Smail/backend/session/migration_store_test.go
smail f68c367042
Some checks are pending
Security Checks / security (push) Waiting to run
实现三种数据库迁移并完善认证与迁移写入保护
2026-09-06 01:31:29 +08:00

94 lines
2.7 KiB
Go

package session
import (
"context"
"database/sql"
"errors"
"net/http"
"net/http/httptest"
"path/filepath"
"testing"
"time"
"github.com/alexedwards/scs/sqlite3store"
"github.com/alexedwards/scs/v2"
_ "modernc.org/sqlite"
)
func TestMigrationSessionResponseDoesNotWriteLockedDatabase(t *testing.T) {
path := filepath.Join(t.TempDir(), "session.db")
database, err := sql.Open("sqlite", path+"?_pragma=busy_timeout(1)")
if err != nil {
t.Fatal(err)
}
defer database.Close()
if _, err := database.Exec("CREATE TABLE sessions (token TEXT PRIMARY KEY, data BLOB NOT NULL, expiry REAL NOT NULL)"); err != nil {
t.Fatal(err)
}
manager := scs.New()
manager.IdleTimeout = time.Hour
paused := false
store := &migrationStore{Store: sqlite3store.NewWithCleanupInterval(database, 0), codec: manager.Codec, paused: func() bool { return paused }}
manager.Store = store
ctx, err := manager.Load(context.Background(), "")
if err != nil {
t.Fatal(err)
}
manager.Put(ctx, "role", "super_admin")
token, _, err := manager.Commit(ctx)
if err != nil {
t.Fatal(err)
}
var originalExpiry float64
if err := database.QueryRow("SELECT expiry FROM sessions").Scan(&originalExpiry); err != nil {
t.Fatal(err)
}
lockDB, err := sql.Open("sqlite", path)
if err != nil {
t.Fatal(err)
}
defer lockDB.Close()
lock, err := lockDB.Conn(context.Background())
if err != nil {
t.Fatal(err)
}
defer lock.Close()
handler := manager.LoadAndSave(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if manager.GetString(r.Context(), "role") != "super_admin" {
t.Error("identity lost")
}
if !paused {
if _, err := lock.ExecContext(r.Context(), "BEGIN IMMEDIATE"); err != nil {
t.Error(err)
}
paused = true
}
_, _ = w.Write([]byte("ok"))
}))
defer lock.ExecContext(context.Background(), "ROLLBACK")
for range 2 {
recorder := httptest.NewRecorder()
request := httptest.NewRequest(http.MethodGet, "/api/v1/config/status", nil)
request.AddCookie(&http.Cookie{Name: manager.Cookie.Name, Value: token})
handler.ServeHTTP(recorder, request)
if recorder.Code != 200 || recorder.Body.String() != "ok" {
t.Fatalf("session response: %d %s", recorder.Code, recorder.Body.String())
}
}
ctx, err = manager.Load(context.Background(), token)
if err != nil {
t.Fatal(err)
}
manager.Put(ctx, "role", "admin")
if _, _, err := manager.Commit(ctx); !errors.Is(err, errMigrationSessionWrite) {
t.Fatalf("changed session accepted: %v", err)
}
if err := store.Delete(token); !errors.Is(err, errMigrationSessionWrite) {
t.Fatal("deletion accepted")
}
var expiry float64
if err := database.QueryRow("SELECT expiry FROM sessions").Scan(&expiry); err != nil || expiry != originalExpiry {
t.Fatal("session expiry changed while frozen")
}
}