TestPreMigrationSessionStillUsable simulates a session row created before migration 040 — populated id/user_id/expires_at, NULL on the columns added by 040 except for public_id (backfilled by the migration's UPDATE). It must continue to authenticate, enumerate, and revoke without requiring the user
(t *testing.T)
| 809 | // It must continue to authenticate, enumerate, and revoke without |
| 810 | // requiring the user to re-login. |
| 811 | func TestPreMigrationSessionStillUsable(t *testing.T) { |
| 812 | s := openTestDB(t) |
| 813 | ctx := context.Background() |
| 814 | |
| 815 | u, _ := s.CreateUser(ctx, "legacy@test.com", []byte("h"), []byte("s"), "owner", 3, 65536, 4) |
| 816 | |
| 817 | // Forge a row that looks like one minted by the pre-040 server: just |
| 818 | // id/user_id/expires_at/created_at, no idle_ttl, no last_used_at, but |
| 819 | // with the backfilled public_id the migration would have written. |
| 820 | rawToken := "av_sess_legacy_test_token_value_with_padding_to_64_chars_xxxxxxx" |
| 821 | tokenHash := hashSessionToken(rawToken) |
| 822 | expiresAt := time.Now().Add(time.Hour).UTC().Format(time.DateTime) |
| 823 | _, err := s.db.ExecContext(ctx, |
| 824 | `INSERT INTO sessions (id, user_id, expires_at, created_at, public_id) |
| 825 | VALUES (?, ?, ?, datetime('now'), ?)`, |
| 826 | tokenHash, u.ID, expiresAt, "legacypub01", |
| 827 | ) |
| 828 | if err != nil { |
| 829 | t.Fatalf("forging legacy session row: %v", err) |
| 830 | } |
| 831 | |
| 832 | got, err := s.GetSession(ctx, rawToken) |
| 833 | if err != nil { |
| 834 | t.Fatalf("GetSession on legacy row: %v", err) |
| 835 | } |
| 836 | if got.IdleTTL != 0 { |
| 837 | t.Fatalf("legacy row IdleTTL should be 0 (idle disabled), got %v", got.IdleTTL) |
| 838 | } |
| 839 | if got.LastUsedAt != nil { |
| 840 | t.Fatalf("legacy row LastUsedAt should be nil, got %v", got.LastUsedAt) |
| 841 | } |
| 842 | if got.IsExpired(time.Now()) { |
| 843 | t.Fatal("legacy row inside its absolute TTL must not be expired") |
| 844 | } |
| 845 | |
| 846 | rows, err := s.ListUserSessions(ctx, u.ID) |
| 847 | if err != nil { |
| 848 | t.Fatalf("ListUserSessions: %v", err) |
| 849 | } |
| 850 | if len(rows) != 1 || rows[0].PublicID != "legacypub01" { |
| 851 | t.Fatalf("expected legacy row in list with public_id 'legacypub01', got %+v", rows) |
| 852 | } |
| 853 | |
| 854 | // Touch a legacy session: should populate last_used_at without |
| 855 | // retroactively enabling the idle check. |
| 856 | if err := s.TouchSession(ctx, rawToken, "127.0.0.1", "test"); err != nil { |
| 857 | t.Fatalf("TouchSession: %v", err) |
| 858 | } |
| 859 | got, _ = s.GetSession(ctx, rawToken) |
| 860 | if got.LastUsedAt == nil { |
| 861 | t.Fatal("touch should populate last_used_at on legacy row") |
| 862 | } |
| 863 | if got.IdleTTL != 0 { |
| 864 | t.Fatal("touch must not retroactively enable idle expiry on legacy row") |
| 865 | } |
| 866 | |
| 867 | // Revoke by the backfilled public_id works. |
| 868 | if err := s.RevokeUserSession(ctx, u.ID, "legacypub01"); err != nil { |
nothing calls this directly
no test coverage detected