Pre-fix test suite documenting 9 database migration and schema integrity bugs. Tests FAIL where they assert correct post-fix behavior, PASS where they document current buggy state. Tests added: - F-B1-11 P0: main.go swallows migration errors (3 tests) - F-B1-13: Duplicate migration numbers 009/012 (2 tests) - F-B1-1: Migration 024 self-insert into schema_migrations (2 tests) - F-B1-2: Migration 024 references non-existent column (2 tests) - F-B1-3: Migration 018 wrong file suffix (2 tests) - F-B1-4: Migration 018 GRANT to wrong role (1 test) - F-B1-15: 7+ migrations not idempotent (2 tests) - F-B1-5: Missing agent_commands sent_at index (2 tests) - F-B1-6: N+1 query in GetDashboardStats (2 tests) - F-B1-10: No background refresh token cleanup (2 tests) Current state: 10 PASS, 10 FAIL, 0 SKIP. All A-series tests continue to pass (no regressions). See docs/B1_PreFix_Tests.md for full inventory. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
122 lines
4.0 KiB
Go
122 lines
4.0 KiB
Go
package database_test
|
|
|
|
// refresh_token_cleanup_test.go — Pre-fix tests for missing token cleanup.
|
|
//
|
|
// F-B1-10 MEDIUM: No automatic refresh token cleanup exists. The
|
|
// refresh_tokens table grows unbounded. CleanupExpiredTokens() is
|
|
// only callable via the admin endpoint, not by a background job.
|
|
//
|
|
// Run: cd aggregator-server && go test ./internal/database/... -v -run TestRefreshToken
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Test 7.1 — Documents no background cleanup exists (F-B1-10)
|
|
//
|
|
// Category: PASS-NOW (documents the gap)
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func TestNoBackgroundRefreshTokenCleanup(t *testing.T) {
|
|
// Search main.go for any goroutine that cleans up refresh tokens
|
|
mainPath := filepath.Join("..", "..", "cmd", "server", "main.go")
|
|
content, err := os.ReadFile(mainPath)
|
|
if err != nil {
|
|
t.Fatalf("failed to read main.go: %v", err)
|
|
}
|
|
|
|
src := string(content)
|
|
|
|
// Look for patterns indicating background token cleanup
|
|
patterns := []string{
|
|
"CleanupExpiredTokens",
|
|
"cleanup.*refresh",
|
|
"refresh.*cleanup",
|
|
"token.*cleanup",
|
|
"cleanup.*token",
|
|
}
|
|
|
|
foundBackground := false
|
|
for _, p := range patterns {
|
|
if strings.Contains(strings.ToLower(src), strings.ToLower(p)) {
|
|
// Check if it's in a go routine or ticker (background context)
|
|
idx := strings.Index(strings.ToLower(src), strings.ToLower(p))
|
|
// Look backwards 200 chars for "go func" or "ticker" or "goroutine"
|
|
start := idx - 200
|
|
if start < 0 {
|
|
start = 0
|
|
}
|
|
context := src[start:idx]
|
|
if strings.Contains(context, "go func") ||
|
|
strings.Contains(context, "ticker") ||
|
|
strings.Contains(context, "goroutine") ||
|
|
strings.Contains(context, "Ticker") {
|
|
foundBackground = true
|
|
t.Logf("[INFO] [server] [database] background cleanup found near: %s", p)
|
|
}
|
|
}
|
|
}
|
|
|
|
if foundBackground {
|
|
t.Error("[ERROR] [server] [database] F-B1-10 already fixed: " +
|
|
"background refresh token cleanup found in main.go")
|
|
}
|
|
|
|
t.Log("[INFO] [server] [database] F-B1-10 confirmed: no background refresh token cleanup exists")
|
|
t.Log("[INFO] [server] [database] CleanupExpiredTokens() is only reachable via admin endpoint")
|
|
t.Log("[INFO] [server] [database] refresh_tokens table grows unbounded until manually cleaned")
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Test 7.2 — Background cleanup must exist (assert fix)
|
|
//
|
|
// Category: FAIL-NOW / PASS-AFTER-FIX
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func TestBackgroundRefreshTokenCleanupExists(t *testing.T) {
|
|
mainPath := filepath.Join("..", "..", "cmd", "server", "main.go")
|
|
content, err := os.ReadFile(mainPath)
|
|
if err != nil {
|
|
t.Fatalf("failed to read main.go: %v", err)
|
|
}
|
|
|
|
src := strings.ToLower(string(content))
|
|
|
|
// After fix: main.go must contain a background goroutine or ticker
|
|
// that periodically calls token cleanup
|
|
hasCleanupInBackground := false
|
|
|
|
// Check for goroutine patterns near cleanup
|
|
if strings.Contains(src, "cleanupexpiredtokens") ||
|
|
strings.Contains(src, "cleanup_expired_tokens") ||
|
|
strings.Contains(src, "token_cleanup") {
|
|
// Look for "go func" or "ticker" in surrounding context
|
|
for _, marker := range []string{"cleanupexpiredtokens", "cleanup_expired_tokens", "token_cleanup"} {
|
|
idx := strings.Index(src, marker)
|
|
if idx == -1 {
|
|
continue
|
|
}
|
|
start := idx - 300
|
|
if start < 0 {
|
|
start = 0
|
|
}
|
|
context := src[start:idx]
|
|
if strings.Contains(context, "go func") ||
|
|
strings.Contains(context, "ticker") {
|
|
hasCleanupInBackground = true
|
|
}
|
|
}
|
|
}
|
|
|
|
if !hasCleanupInBackground {
|
|
t.Errorf("[ERROR] [server] [database] no background refresh token cleanup found.\n" +
|
|
"F-B1-10: a background goroutine or scheduler entry must periodically\n" +
|
|
"call CleanupExpiredTokens() to prevent unbounded table growth.\n" +
|
|
"After fix: add a ticker-based cleanup in main.go startup.")
|
|
}
|
|
}
|