94 lines
2.7 KiB
Go
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")
|
|
}
|
|
}
|