refactor(backend): update test files for PoolProxy and per-test transactions
Migrate all test files from SetupTestDB/db.DB pattern to per-test transactions: - Replace SetupTestDB(t) with SetupTestTx(t) for context + transaction - Replace db.DB.Query/QueryRow/Exec with tx.Query/QueryRow/Exec - Replace context.Background() with context from SetupTestTx - Replace defer rows.Close() pattern with explicit rows.Close() - Add testdb.SeedBaseline(pool) to all TestMain functions - Wire db.Conn = db.NewPoolProxy(pool) in all TestMain functions Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
+23
-31
@@ -18,19 +18,9 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"crussell/db"
|
||||
"crussell/testutils/testtx"
|
||||
)
|
||||
|
||||
// requiresDB skips the test if the database is not available (e.g. running
|
||||
// tests standalone without test DB setup). DB-backed JTI revocation tests
|
||||
// need a connection to the revoked_jtis table.
|
||||
func requiresDB(t *testing.T) {
|
||||
t.Helper()
|
||||
if db.DB == nil {
|
||||
t.Skip("skipping: no database connection")
|
||||
}
|
||||
}
|
||||
|
||||
// =============================================================================
|
||||
// generateJTI Tests
|
||||
// =============================================================================
|
||||
@@ -139,12 +129,13 @@ func TestGenerateToken_JTIInClaims(t *testing.T) {
|
||||
// TestVerifyToken_ReturnsJTI creates a token, verifies it, and checks the
|
||||
// returned user_id, role, and JTI match the expected values.
|
||||
func TestVerifyToken_ReturnsJTI(t *testing.T) {
|
||||
ctx, _ := testtx.SetupTestTx(t)
|
||||
token, jti, err := GenerateToken("user-003", "verified_email")
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken() failed: %v", err)
|
||||
}
|
||||
|
||||
userID, role, returnedJTI, err := VerifyToken(token, context.Background())
|
||||
userID, role, returnedJTI, err := VerifyToken(token, ctx)
|
||||
if err != nil {
|
||||
t.Fatalf("VerifyToken() failed: %v", err)
|
||||
}
|
||||
@@ -163,15 +154,15 @@ func TestVerifyToken_ReturnsJTI(t *testing.T) {
|
||||
// TestVerifyToken_RevokedJTI creates a token, revokes its JTI, and verifies
|
||||
// that VerifyToken returns an error containing "token revoked".
|
||||
func TestVerifyToken_RevokedJTI(t *testing.T) {
|
||||
requiresDB(t)
|
||||
ctx, _ := testtx.SetupTestTx(t)
|
||||
token, jti, err := GenerateToken("user-004", "verified_email")
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken() failed: %v", err)
|
||||
}
|
||||
|
||||
RevokeJTI(jti, time.Now().Add(30*24*time.Hour))
|
||||
RevokeJTI(ctx, jti, time.Now().Add(30*24*time.Hour))
|
||||
|
||||
_, _, _, err = VerifyToken(token, context.Background())
|
||||
_, _, _, err = VerifyToken(token, ctx)
|
||||
if err == nil {
|
||||
t.Fatal("expected error for revoked JTI, got nil")
|
||||
}
|
||||
@@ -209,19 +200,19 @@ func TestVerifyToken_MissingJTI(t *testing.T) {
|
||||
// TestRevokeJTI_AddsToSet verifies that calling RevokeJTI adds the JTI to the
|
||||
// revoked set, and IsJTIRevoked returns true for it.
|
||||
func TestRevokeJTI_AddsToSet(t *testing.T) {
|
||||
requiresDB(t)
|
||||
ctx, _ := testtx.SetupTestTx(t)
|
||||
_, jti, err := GenerateToken("user-006", "verified_email")
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken() failed: %v", err)
|
||||
}
|
||||
|
||||
if IsJTIRevoked(jti) {
|
||||
if IsJTIRevoked(ctx, jti) {
|
||||
t.Fatal("JTI should not be revoked before calling RevokeJTI")
|
||||
}
|
||||
|
||||
RevokeJTI(jti, time.Now().Add(30*24*time.Hour))
|
||||
RevokeJTI(ctx, jti, time.Now().Add(30*24*time.Hour))
|
||||
|
||||
if !IsJTIRevoked(jti) {
|
||||
if !IsJTIRevoked(ctx, jti) {
|
||||
t.Error("expected IsJTIRevoked to return true after RevokeJTI")
|
||||
}
|
||||
}
|
||||
@@ -229,7 +220,8 @@ func TestRevokeJTI_AddsToSet(t *testing.T) {
|
||||
// TestIsJTIRevoked_NonExistent verifies that checking a non-existent JTI
|
||||
// returns false.
|
||||
func TestIsJTIRevoked_NonExistent(t *testing.T) {
|
||||
if IsJTIRevoked("nonexistent-jti-12345") {
|
||||
ctx, _ := testtx.SetupTestTx(t)
|
||||
if IsJTIRevoked(ctx, "nonexistent-jti-12345") {
|
||||
t.Error("expected IsJTIRevoked to return false for non-existent JTI")
|
||||
}
|
||||
}
|
||||
@@ -241,29 +233,29 @@ func TestIsJTIRevoked_NonExistent(t *testing.T) {
|
||||
// TestCleanupRevokedJTIs_RemovesExpired adds a JTI with a past expiry time,
|
||||
// runs CleanupRevokedJTIs, and verifies the JTI is removed from the set.
|
||||
func TestCleanupRevokedJTIs_RemovesExpired(t *testing.T) {
|
||||
requiresDB(t)
|
||||
ctx, tx := testtx.SetupTestTx(t)
|
||||
_, jti, err := GenerateToken("user-007", "verified_email")
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken() failed: %v", err)
|
||||
}
|
||||
|
||||
// Add with future expiry so IsJTIRevoked sees it
|
||||
RevokeJTI(jti, time.Now().Add(1*time.Hour))
|
||||
RevokeJTI(ctx, jti, time.Now().Add(1*time.Hour))
|
||||
|
||||
if !IsJTIRevoked(jti) {
|
||||
if !IsJTIRevoked(ctx, jti) {
|
||||
t.Fatal("JTI should be in revoked set after RevokeJTI")
|
||||
}
|
||||
|
||||
// Directly update the DB to set expiry in the past
|
||||
_, err = db.DB.Exec(context.Background(),
|
||||
_, err = tx.Exec(ctx,
|
||||
"UPDATE revoked_jtis SET expires_at = NOW() - INTERVAL '1 hour' WHERE jti = $1", jti)
|
||||
if err != nil {
|
||||
t.Fatalf("failed to expire JTI: %v", err)
|
||||
}
|
||||
|
||||
CleanupRevokedJTIs()
|
||||
CleanupRevokedJTIs(ctx)
|
||||
|
||||
if IsJTIRevoked(jti) {
|
||||
if IsJTIRevoked(ctx, jti) {
|
||||
t.Error("expected expired JTI to be removed after cleanup")
|
||||
}
|
||||
}
|
||||
@@ -271,22 +263,22 @@ func TestCleanupRevokedJTIs_RemovesExpired(t *testing.T) {
|
||||
// TestCleanupRevokedJTIs_KeepsValid adds a JTI with a future expiry time,
|
||||
// runs CleanupRevokedJTIs, and verifies the JTI is still in the set.
|
||||
func TestCleanupRevokedJTIs_KeepsValid(t *testing.T) {
|
||||
requiresDB(t)
|
||||
ctx, _ := testtx.SetupTestTx(t)
|
||||
_, jti, err := GenerateToken("user-008", "verified_email")
|
||||
if err != nil {
|
||||
t.Fatalf("GenerateToken() failed: %v", err)
|
||||
}
|
||||
|
||||
// Add with future expiry
|
||||
RevokeJTI(jti, time.Now().Add(30*24*time.Hour))
|
||||
RevokeJTI(ctx, jti, time.Now().Add(30*24*time.Hour))
|
||||
|
||||
if !IsJTIRevoked(jti) {
|
||||
if !IsJTIRevoked(ctx, jti) {
|
||||
t.Fatal("JTI should be in revoked set before cleanup")
|
||||
}
|
||||
|
||||
CleanupRevokedJTIs()
|
||||
CleanupRevokedJTIs(ctx)
|
||||
|
||||
if !IsJTIRevoked(jti) {
|
||||
if !IsJTIRevoked(ctx, jti) {
|
||||
t.Error("expected valid (future expiry) JTI to remain after cleanup")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ func TestMain(m *testing.M) {
|
||||
InitJWT("test-secret-key-for-jwt-test")
|
||||
|
||||
pool := testdb.CreateTestDatabase("crussell_test_auth")
|
||||
db.DB = pool
|
||||
db.Conn = db.NewPoolProxy(pool)
|
||||
|
||||
code := m.Run()
|
||||
testdb.DestroyTestDatabase(pool, "crussell_test_auth")
|
||||
|
||||
Reference in New Issue
Block a user