From ced4eef80cebb05345a21f5afc09e5ebbdb61b44 Mon Sep 17 00:00:00 2001 From: Bretton Date: Wed, 29 Jul 2026 04:52:38 -0700 Subject: [PATCH] test(integration): migrate batch 1 (29 files) to testkit.DB per-test clones Phase 3 task 7. aggregator_e2e through concurrent_scenarios: 115 setup sites (103 setupTestDB calls + 12 hand-rolled sql.Open/goose blocks) become testkit.DB(t) clones; 19 unscoped DELETE FROM statements and one per-file cleanup fn deleted rather than ported; two tests turned out to need no database at all. Isolation verified by running a previously PK-colliding pair concurrently. make ci green 3399/0 at 142s. Co-Authored-By: Claude Fable 5 --- loop_state.md | 16 ++- tests/integration/aggregator_e2e_test.go | 16 +-- .../aggregator_registration_test.go | 28 ++--- tests/integration/aggregator_test.go | 64 ++--------- .../author_avatar_hydration_test.go | 4 +- tests/integration/author_posts_e2e_test.go | 36 ++----- tests/integration/blob_upload_e2e_test.go | 18 +--- .../block_handle_resolution_test.go | 15 +-- tests/integration/bluesky_post_test.go | 4 +- tests/integration/comment_consumer_test.go | 82 ++------------ tests/integration/comment_e2e_test.go | 101 ++---------------- tests/integration/comment_query_test.go | 93 +++------------- tests/integration/comment_vote_test.go | 15 +-- tests/integration/comment_write_test.go | 46 ++------ .../integration/community_avatar_e2e_test.go | 63 +---------- tests/integration/community_blocking_test.go | 30 +----- tests/integration/community_consumer_test.go | 29 +---- .../integration/community_credentials_test.go | 22 +--- tests/integration/community_e2e_test.go | 40 +------ .../community_get_viewer_state_test.go | 8 +- .../community_hostedby_security_test.go | 22 +--- .../community_identifier_resolution_test.go | 29 +---- .../community_list_viewer_state_test.go | 8 +- .../community_provisioning_test.go | 43 ++------ tests/integration/community_repo_test.go | 45 ++------ .../community_service_integration_test.go | 22 +--- .../community_suggestion_e2e_test.go | 18 +--- .../integration/community_update_e2e_test.go | 23 +--- .../community_v2_validation_test.go | 15 +-- .../integration/concurrent_scenarios_test.go | 29 +---- 30 files changed, 156 insertions(+), 828 deletions(-) diff --git a/loop_state.md b/loop_state.md index fdb374e..bb41b54 100644 --- a/loop_state.md +++ b/loop_state.md @@ -43,7 +43,7 @@ Stop the loop when every task is done, or on any blocked task. | 4 | testkit pds.go (absorb 4 factories, createPDSAccount×2, XRPC clients), firehose.go (generic cursor-gated), appview.go; fix 5 handle-collision sites | 1 ⛩ | S | done | (see git log) | PHASE 1 COMPLETE. Worker found ALL 10 legacy subscribeToJetstream copies broken (gorilla corrupt-after-deadline → every "30s wait" gave up at ~5s — explains historical flakes). 5 factories not 4 (comments missed by helpers.go); old generateTID never emitted valid TIDs (now wraps indigo TIDClock); dep rule is TRANSITIVE (atproto/pds imports core/blobs → reimplemented). FULL PANEL (Codex+CR+SFH+TA+security): security CLEAN; ~28-item batch applied — same-time_us dedupe set, deadline-bounded dials, all-read-errors-recover, discard counting (clock-skew diagnosis), overflow=failure, lock-free blocking I/O, Event.Raw()/Into() (unblocks consumer migrations), XRPC-shaped 404 classification, PendingIfUnavailable, ConsumerHealth + WithConsumerHealth, option-pattern unification, testkit.Main(m, Require*...). CR false-positive on ParallelBudget wiring (discarded). testkit 117 tests -race -shuffle green; make ci GREEN 3429/14 | | 5 | Kill the lies: delete 6 debt tests; lexicon validator stops generating defs-only subtests (retire 8 allowlist entries); move 2 ratelimit files to internal/api/middleware (T0); fold tests/unit into internal/core/communities | 2 | M | done | (see git log) | ALLOWLIST → 0 ENTRIES; make ci GREEN 3399/3399, 0 skips. Lexicon fix is a coverage GAIN (43 defs-only fragment resolutions previously asserted nothing + two-way naming consistency). tests/unit was 100% FAKE (servers never dialed, literals asserted against themselves, t.Log theater) — deleted wholesale, nothing to port; communities now at honest zero (task 17). 3 tautology "tests" deleted rather than moved. Audit 911→897 | | 6 | Split multi-tier files by test func (manifest in commit msg); add build tags in place; retarget Makefile to tags; delete -short/testing.Short(); delete test-all | 2 ⛩ | S | done | (see git log) | PHASE 2 COMPLETE. 76 files `integration`, 3 `e2e`; 2 jetstream files split; 161 Short guards deleted (162nd was a doc comment); test-all + 4 dead targets gone. Honesty test: untagged suite green under --network none FIRST TRY (36 pkgs). make test = 11s no-Docker. Review (Codex needs-work / Opus safe-as-is): 8 fixes — GATE INTEGRITY closed (exit codes captured + mismatch rule; OOM-137-with-green-report now fails — was a silent pass since the harness was born; proved via truth table), -parallel 1 pinned on e2e (serial T2), readiness probe now hits the HOST endpoint tests dial, shared-DB migrate restored via testkit.MigrateSharedDatabase (advisory-locked, in testdbprepare), DSN redacted via url.Redacted, pure testkit files untagged (TestMain split into tagged harness_test.go + untagged harness_support_test.go), T0 socket-free (failingTransport). make ci GREEN 3399/0 skips 2m4s; audit 573 | -| 7 | Migrate setupTestDB call sites → testkit.DB(t), batch 1 (~25 files) + delete their DELETE FROMs/cleanups | 3 | M | pending | | mechanical; gates are the reviewer | +| 7 | Migrate setupTestDB call sites → testkit.DB(t), batch 1 (~25 files) + delete their DELETE FROMs/cleanups | 3 | M | done | (see git log) | 29 files (aggregator_e2e..concurrent_scenarios incl. 4 hand-rolled setup clones), 115 sites → testkit.DB(t) (2 needed NO db at all — migration doubles as unused-DB detector), 19 DELETE FROMs + 1 cleanup fn deleted, diff +142/−828. Isolation PROVEN: concurrent -count=2 on a hardcoded-PK pair green; 0 leaked clones. make ci GREEN 3399/0 @142s (+18s vs baseline: ~150ms/test = FORCE-drop + 2 lock RTs — task 9 pays it back). Audit 573→561. NO order-dependency failures surfaced | | 8 | Migrate remaining call sites; delete all 3 setupTestDB defs + per-file cleanup fns | 3 | M | pending | | | | 9 | Global-state audit (t.Setenv/os.Setenv/logger/http-default → testkit injection); enable t.Parallel on proven-safe; connection budgets; `-race` clean; drop -p 1 | 3 ⛩ | S | pending | | wall-clock vs task-1 baseline recorded here | | 10 | Contract-manifest CI check (WantedCollections ↔ //coves:ingestion-contract markers) + T2 skeleton (serial runner via compose runner; make test-e2e; test-e2e-dev escape hatch) | 4 ⛩ | S | pending | | build BEFORE first contract so every contract lands against it | @@ -173,3 +173,17 @@ Stop the loop when every task is done, or on any blocked task. make test-integration's readiness gate is test-db-prepare's real connection to the published port — compose-up conflicts are tolerated by design because the connection probe is the decider. +- **From task 7 (for task 8 + tasks 10-16)**: BOUNDARY — task 8 takes + discover_test.go onward + oauth_token_verification + user_journey_e2e + + user_profile_avatar_e2e; 104 setupTestDB sites remain; cleanup fns still + live (cleanupTestDB, cleanupUserBlockTestDB, + cleanupUserBlockEnforcementTestData, CleanupOAuthTestData) + all 3 + setupTestDB defs; 8 files still goose.Up the shared DB (all task-8 set). + Per-call setup helpers returning routers are safe only if no test holds + TWO at once (each call = its own clone — check before migrating such + helpers). community_repo_test.go ~:497 has a big commented-out Search + test (dead code, delete some day, not mechanically). NO tests/integration + file dials a running AppView (all in-process httptest routers) — the + shared-DB-vs-clone desync hazard is confined to tests/e2e; tasks 10-16 + must keep it that way (T2 contracts observe via the REAL AppView's + endpoints and never mix testkit.DB clones with container-side writes). diff --git a/tests/integration/aggregator_e2e_test.go b/tests/integration/aggregator_e2e_test.go index b838c84..5d71240 100644 --- a/tests/integration/aggregator_e2e_test.go +++ b/tests/integration/aggregator_e2e_test.go @@ -12,6 +12,7 @@ import ( "Coves/internal/core/posts" "Coves/internal/core/users" "Coves/internal/db/postgres" + "Coves/tests/testkit" "bytes" "context" "encoding/json" @@ -50,12 +51,7 @@ func TestAggregator_E2E_WithJetstream(t *testing.T) { if resp != nil { _ = resp.Body.Close() } - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) // Setup repositories aggregatorRepo := postgres.NewAggregatorRepository(db) @@ -84,14 +80,6 @@ func TestAggregator_E2E_WithJetstream(t *testing.T) { ctx := context.Background() - // Cleanup test data (aggregators and communities will be created via real PDS in test parts) - _, _ = db.Exec("DELETE FROM aggregator_posts WHERE aggregator_did LIKE 'did:plc:%'") - _, _ = db.Exec("DELETE FROM aggregator_authorizations WHERE aggregator_did LIKE 'did:plc:%'") - _, _ = db.Exec("DELETE FROM aggregators WHERE did LIKE 'did:plc:%'") - _, _ = db.Exec("DELETE FROM posts WHERE community_did LIKE 'did:plc:%'") - _, _ = db.Exec("DELETE FROM communities WHERE did LIKE 'did:plc:%'") - _, _ = db.Exec("DELETE FROM users WHERE did LIKE 'did:plc:%'") - // ==================================================================================== // Part 1: Service Declaration via Real PDS // ==================================================================================== diff --git a/tests/integration/aggregator_registration_test.go b/tests/integration/aggregator_registration_test.go index e81579d..f05dd36 100644 --- a/tests/integration/aggregator_registration_test.go +++ b/tests/integration/aggregator_registration_test.go @@ -7,6 +7,7 @@ import ( "Coves/internal/atproto/identity" "Coves/internal/core/users" "Coves/internal/db/postgres" + "Coves/tests/testkit" "bytes" "context" "crypto/tls" @@ -66,8 +67,7 @@ func (m *mockAggregatorIdentityResolver) Purge(ctx context.Context, identifier s func TestAggregatorRegistration_Success(t *testing.T) { // Setup test database - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) testDID := "did:plc:test123" testHandle := "aggregator.bsky.social" @@ -154,8 +154,7 @@ func TestAggregatorRegistration_Success(t *testing.T) { func TestAggregatorRegistration_DomainVerificationFailed(t *testing.T) { // Setup test database - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) // Setup test server that returns wrong DID wellKnownServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -217,8 +216,7 @@ func TestAggregatorRegistration_DomainVerificationFailed(t *testing.T) { } func TestAggregatorRegistration_InvalidDID(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) tests := []struct { name string @@ -275,8 +273,7 @@ func TestAggregatorRegistration_InvalidDID(t *testing.T) { } func TestAggregatorRegistration_AlreadyRegistered(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) // Pre-create user with same DID existingDID := "did:plc:existing123" @@ -355,8 +352,7 @@ func TestAggregatorRegistration_AlreadyRegistered(t *testing.T) { } func TestAggregatorRegistration_WellKnownNotAccessible(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) // Setup test server that returns 404 for .well-known wellKnownServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -413,8 +409,7 @@ func TestAggregatorRegistration_WellKnownNotAccessible(t *testing.T) { } func TestAggregatorRegistration_WellKnownTooLarge(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) testDID := "did:plc:toolarge" @@ -474,8 +469,7 @@ func TestAggregatorRegistration_WellKnownTooLarge(t *testing.T) { } func TestAggregatorRegistration_DIDResolutionFailed(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) testDID := "did:plc:nonexistent" @@ -546,8 +540,7 @@ func TestAggregatorRegistration_DIDResolutionFailed(t *testing.T) { } func TestAggregatorRegistration_LargeWellKnownResponse(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) testDID := "did:plc:largedos123" @@ -638,8 +631,7 @@ func TestAggregatorRegistration_E2E_WithRealInfrastructure(t *testing.T) { // This is a TRUE E2E test that validates the full registration flow // with real .well-known server and real identity resolution - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) testDID := "did:plc:e2etest123" testHandle := "e2ebot.bsky.social" diff --git a/tests/integration/aggregator_test.go b/tests/integration/aggregator_test.go index 7ebc1a3..9d2f6d2 100644 --- a/tests/integration/aggregator_test.go +++ b/tests/integration/aggregator_test.go @@ -6,6 +6,7 @@ import ( "Coves/internal/core/aggregators" "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "encoding/json" "fmt" @@ -15,12 +16,7 @@ import ( // TestAggregatorRepository_Create tests basic aggregator creation func TestAggregatorRepository_Create(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewAggregatorRepository(db) ctx := context.Background() @@ -121,12 +117,7 @@ func TestAggregatorRepository_Create(t *testing.T) { // TestAggregatorRepository_IsAggregator tests the fast existence check func TestAggregatorRepository_IsAggregator(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewAggregatorRepository(db) ctx := context.Background() @@ -172,12 +163,7 @@ func TestAggregatorRepository_IsAggregator(t *testing.T) { // TestAggregatorAuthorization_Create tests authorization creation func TestAggregatorAuthorization_Create(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) aggRepo := postgres.NewAggregatorRepository(db) commRepo := postgres.NewCommunityRepository(db) @@ -331,12 +317,7 @@ func TestAggregatorAuthorization_Create(t *testing.T) { // TestAggregatorAuthorization_IsAuthorized tests fast authorization check func TestAggregatorAuthorization_IsAuthorized(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) aggRepo := postgres.NewAggregatorRepository(db) commRepo := postgres.NewCommunityRepository(db) @@ -469,12 +450,7 @@ func TestAggregatorAuthorization_IsAuthorized(t *testing.T) { // TestAggregatorService_PostCreationIntegration tests the full post creation flow with aggregators func TestAggregatorService_PostCreationIntegration(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) aggRepo := postgres.NewAggregatorRepository(db) commRepo := postgres.NewCommunityRepository(db) @@ -568,12 +544,7 @@ func TestAggregatorService_PostCreationIntegration(t *testing.T) { // TestAggregatorService_RateLimiting tests rate limit enforcement func TestAggregatorService_RateLimiting(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) aggRepo := postgres.NewAggregatorRepository(db) commRepo := postgres.NewCommunityRepository(db) @@ -659,12 +630,7 @@ func TestAggregatorService_RateLimiting(t *testing.T) { // TestAggregatorPostService_Integration tests the posts service integration func TestAggregatorPostService_Integration(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) aggRepo := postgres.NewAggregatorRepository(db) aggService := aggregators.NewAggregatorService(aggRepo, nil) @@ -710,12 +676,7 @@ func TestAggregatorPostService_Integration(t *testing.T) { // TestAggregatorTriggers tests database triggers for auto-updating stats func TestAggregatorTriggers(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) aggRepo := postgres.NewAggregatorRepository(db) commRepo := postgres.NewCommunityRepository(db) @@ -824,12 +785,7 @@ func TestAggregatorTriggers(t *testing.T) { // TestAggregatorAuthorization_DisabledAtField tests that disabledAt is properly stored and retrieved func TestAggregatorAuthorization_DisabledAtField(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) aggRepo := postgres.NewAggregatorRepository(db) commRepo := postgres.NewCommunityRepository(db) diff --git a/tests/integration/author_avatar_hydration_test.go b/tests/integration/author_avatar_hydration_test.go index ced9076..b5b9f33 100644 --- a/tests/integration/author_avatar_hydration_test.go +++ b/tests/integration/author_avatar_hydration_test.go @@ -6,6 +6,7 @@ import ( "Coves/internal/core/communityFeeds" "Coves/internal/core/posts" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "fmt" "net/url" @@ -24,8 +25,7 @@ import ( // Regression test for the bug where feeds and post views only hydrated the // community avatar and author cards were always bare even for fully indexed users. func TestAuthorProfileHydration(t *testing.T) { - db := setupTestDB(t) - t.Cleanup(func() { _ = db.Close() }) + db := testkit.DB(t) ctx := context.Background() testID := uniqueTestID() diff --git a/tests/integration/author_posts_e2e_test.go b/tests/integration/author_posts_e2e_test.go index f88887d..81df57b 100644 --- a/tests/integration/author_posts_e2e_test.go +++ b/tests/integration/author_posts_e2e_test.go @@ -11,20 +11,18 @@ import ( "Coves/internal/core/users" "Coves/internal/core/votes" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" - "database/sql" "encoding/json" "fmt" "io" "net/http" "net/http/httptest" - "os" "testing" "time" "github.com/go-chi/chi/v5" _ "github.com/lib/pq" - "github.com/pressly/goose/v3" ) // getPostTitleFromView extracts title from PostView.Record. @@ -48,25 +46,7 @@ func getPostTitleFromView(t *testing.T, pv *posts.PostView) string { // TestGetAuthorPosts_E2E_Success tests the full author posts flow with real PDS // Flow: Create user on PDS → Create posts → Query via XRPC → Verify response func TestGetAuthorPosts_E2E_Success(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - // Run migrations - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) // Check if PDS is running pdsURL := getTestPDSURL() @@ -289,8 +269,7 @@ func TestGetAuthorPosts_E2E_Success(t *testing.T) { // TestGetAuthorPosts_FilterLogic tests the different filter options func TestGetAuthorPosts_FilterLogic(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) ctx := context.Background() @@ -424,8 +403,7 @@ func TestGetAuthorPosts_FilterLogic(t *testing.T) { // TestGetAuthorPosts_ServiceErrors tests error handling in the service layer func TestGetAuthorPosts_ServiceErrors(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) ctx := context.Background() @@ -538,8 +516,7 @@ func TestGetAuthorPosts_ServiceErrors(t *testing.T) { // TestGetAuthorPosts_WithJetstreamIndexing tests the full flow including Jetstream indexing func TestGetAuthorPosts_WithJetstreamIndexing(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) ctx := context.Background() pdsURL := getTestPDSURL() @@ -647,8 +624,7 @@ func TestGetAuthorPosts_WithJetstreamIndexing(t *testing.T) { // TestGetAuthorPosts_CommunityFilter tests filtering posts by community func TestGetAuthorPosts_CommunityFilter(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) ctx := context.Background() diff --git a/tests/integration/blob_upload_e2e_test.go b/tests/integration/blob_upload_e2e_test.go index 91f2870..a618e4f 100644 --- a/tests/integration/blob_upload_e2e_test.go +++ b/tests/integration/blob_upload_e2e_test.go @@ -10,6 +10,7 @@ import ( "Coves/internal/core/posts" "Coves/internal/core/users" "Coves/internal/db/postgres" + "Coves/tests/testkit" "bytes" "context" "encoding/json" @@ -51,12 +52,7 @@ func TestBlobUpload_E2E_PostWithImages(t *testing.T) { t.Skipf("PDS health check failed at %s: status %d", pdsURL, healthResp.StatusCode) } - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() @@ -366,12 +362,7 @@ func TestBlobUpload_E2E_CommentWithImage(t *testing.T) { t.Skipf("PDS health check failed at %s: status %d", pdsURL, healthResp.StatusCode) } - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() @@ -519,8 +510,7 @@ func TestBlobUpload_PDS_MockServer(t *testing.T) { // TestBlobUpload_Validation tests blob upload validation func TestBlobUpload_Validation(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) communityRepo := postgres.NewCommunityRepository(db) blobService := blobs.NewBlobService(getTestPDSURL()) diff --git a/tests/integration/block_handle_resolution_test.go b/tests/integration/block_handle_resolution_test.go index 7cf8094..1c69cf8 100644 --- a/tests/integration/block_handle_resolution_test.go +++ b/tests/integration/block_handle_resolution_test.go @@ -6,6 +6,7 @@ import ( "Coves/internal/api/handlers/community" "Coves/internal/api/middleware" "Coves/internal/core/communities" + "Coves/tests/testkit" "bytes" "context" "encoding/json" @@ -34,12 +35,7 @@ func createTestOAuthSessionForBlock(did string) *oauth.ClientSessionData { // TestBlockHandler_HandleResolution tests that the block handler accepts handles // in addition to DIDs and resolves them correctly func TestBlockHandler_HandleResolution(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() @@ -272,12 +268,7 @@ func TestBlockHandler_HandleResolution(t *testing.T) { // TestUnblockHandler_HandleResolution tests that the unblock handler accepts handles func TestUnblockHandler_HandleResolution(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() diff --git a/tests/integration/bluesky_post_test.go b/tests/integration/bluesky_post_test.go index d3c9c46..73afd7f 100644 --- a/tests/integration/bluesky_post_test.go +++ b/tests/integration/bluesky_post_test.go @@ -3,6 +3,7 @@ package integration import ( + "Coves/tests/testkit" "context" "fmt" "net/http" @@ -23,8 +24,7 @@ func TestBlueskyPostCrossPosting_E2E_LivePDS(t *testing.T) { } _ = healthResp.Body.Close() - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) ctx := context.Background() diff --git a/tests/integration/comment_consumer_test.go b/tests/integration/comment_consumer_test.go index 8305312..867ddff 100644 --- a/tests/integration/comment_consumer_test.go +++ b/tests/integration/comment_consumer_test.go @@ -6,6 +6,7 @@ import ( "Coves/internal/atproto/jetstream" "Coves/internal/core/comments" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "fmt" "testing" @@ -13,12 +14,7 @@ import ( ) func TestCommentConsumer_CreateComment(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -171,12 +167,7 @@ func TestCommentConsumer_CreateComment(t *testing.T) { } func TestCommentConsumer_Threading(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -327,12 +318,7 @@ func TestCommentConsumer_Threading(t *testing.T) { } func TestCommentConsumer_UpdateComment(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -453,12 +439,7 @@ func TestCommentConsumer_UpdateComment(t *testing.T) { } func TestCommentConsumer_DeleteComment(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -631,12 +612,7 @@ func TestCommentConsumer_DeleteComment(t *testing.T) { } func TestCommentConsumer_SecurityValidation(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -884,22 +860,11 @@ func TestCommentConsumer_SecurityValidation(t *testing.T) { } func TestCommentRepository_Queries(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) - // Clean up any existing test data from previous runs - _, err := db.ExecContext(ctx, "DELETE FROM comments WHERE commenter_did LIKE 'did:plc:%'") - if err != nil { - t.Fatalf("Failed to clean up test comments: %v", err) - } - testUser := createTestUser(t, db, "query.test", "did:plc:query123") testCommunity, err := createFeedTestCommunity(db, ctx, "querycommunity", "owner6.test") if err != nil { @@ -1053,12 +1018,7 @@ func TestCommentRepository_Queries(t *testing.T) { // TestCommentConsumer_OutOfOrderReconciliation tests that parent counts are // correctly reconciled when child comments arrive before their parent func TestCommentConsumer_OutOfOrderReconciliation(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -1072,12 +1032,6 @@ func TestCommentConsumer_OutOfOrderReconciliation(t *testing.T) { postURI := createTestPost(t, db, testCommunity, testUser.DID, "OOO Test Post", 0, time.Now()) t.Run("Child arrives before parent - count reconciled", func(t *testing.T) { - // Clean up comments to ensure isolation from other tests - _, cleanErr := db.ExecContext(ctx, "DELETE FROM comments") - if cleanErr != nil { - t.Fatalf("Failed to clean up comments: %v", cleanErr) - } - // Scenario: User A creates comment C1 on post // User B creates reply C2 to C1 // Jetstream delivers C2 before C1 (different repos) @@ -1207,12 +1161,6 @@ func TestCommentConsumer_OutOfOrderReconciliation(t *testing.T) { }) t.Run("Multiple children arrive before parent", func(t *testing.T) { - // Clean up comments from previous subtest to ensure isolation - _, cleanErr := db.ExecContext(ctx, "DELETE FROM comments") - if cleanErr != nil { - t.Fatalf("Failed to clean up comments: %v", cleanErr) - } - parentRkey := generateTID() parentURI := fmt.Sprintf("at://%s/social.coves.community.comment/%s", testUser.DID, parentRkey) @@ -1323,12 +1271,7 @@ func TestCommentConsumer_OutOfOrderReconciliation(t *testing.T) { // TestCommentConsumer_Resurrection tests that soft-deleted comments can be recreated // In atProto, deleted records' rkeys become available for reuse func TestCommentConsumer_Resurrection(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -1628,12 +1571,7 @@ func TestCommentConsumer_Resurrection(t *testing.T) { // TestCommentConsumer_ThreadingImmutability tests that UPDATE events cannot change threading refs func TestCommentConsumer_ThreadingImmutability(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) diff --git a/tests/integration/comment_e2e_test.go b/tests/integration/comment_e2e_test.go index b750741..7fe75a2 100644 --- a/tests/integration/comment_e2e_test.go +++ b/tests/integration/comment_e2e_test.go @@ -8,14 +8,13 @@ import ( "Coves/internal/atproto/utils" "Coves/internal/core/comments" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" - "database/sql" "encoding/json" "fmt" "io" "net" "net/http" - "os" "strings" "testing" "time" @@ -24,31 +23,12 @@ import ( "github.com/bluesky-social/indigo/atproto/syntax" "github.com/gorilla/websocket" _ "github.com/lib/pq" - "github.com/pressly/goose/v3" ) // TestCommentE2E_CreateWithJetstream tests the full comment creation flow with real Jetstream // Flow: Client → Service → PDS Write → Jetstream Firehose → Consumer → AppView func TestCommentE2E_CreateWithJetstream(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - // Run migrations - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) // Check if PDS is running pdsURL := getTestPDSURL() @@ -242,25 +222,7 @@ func TestCommentE2E_CreateWithJetstream(t *testing.T) { // TestCommentE2E_UpdateWithJetstream tests comment update with real Jetstream indexing func TestCommentE2E_UpdateWithJetstream(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - // Run migrations - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) // Check if PDS is running pdsURL := getTestPDSURL() @@ -472,24 +434,7 @@ func TestCommentE2E_UpdateWithJetstream(t *testing.T) { // TestCommentE2E_DeleteWithJetstream tests comment deletion with real Jetstream indexing func TestCommentE2E_DeleteWithJetstream(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) pdsURL := getTestPDSURL() healthResp, err := http.Get(pdsURL + "/xrpc/_health") @@ -881,24 +826,7 @@ func subscribeToJetstreamForCommentDelete( // TestCommentE2E_Authorization tests that users cannot modify other users' comments func TestCommentE2E_Authorization(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) pdsURL := getTestPDSURL() healthResp, err := http.Get(pdsURL + "/xrpc/_health") @@ -1069,24 +997,7 @@ func TestCommentE2E_Authorization(t *testing.T) { // TestCommentE2E_ValidationErrors tests that validation errors are properly returned func TestCommentE2E_ValidationErrors(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) pdsURL := getTestPDSURL() healthResp, err := http.Get(pdsURL + "/xrpc/_health") diff --git a/tests/integration/comment_query_test.go b/tests/integration/comment_query_test.go index ea09a82..9182aad 100644 --- a/tests/integration/comment_query_test.go +++ b/tests/integration/comment_query_test.go @@ -7,6 +7,7 @@ import ( "Coves/internal/atproto/jetstream" "Coves/internal/core/comments" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "database/sql" "encoding/json" @@ -23,12 +24,7 @@ import ( // TestCommentQuery_BasicFetch tests fetching top-level comments with default params func TestCommentQuery_BasicFetch(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "basicfetch.test", "did:plc:basicfetch123") @@ -83,12 +79,7 @@ func TestCommentQuery_BasicFetch(t *testing.T) { // TestCommentQuery_NestedReplies tests fetching comments with nested reply structure func TestCommentQuery_NestedReplies(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "nested.test", "did:plc:nested123") @@ -173,12 +164,7 @@ func TestCommentQuery_NestedReplies(t *testing.T) { // TestCommentQuery_DepthLimit tests depth limiting works correctly func TestCommentQuery_DepthLimit(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "depth.test", "did:plc:depth123") @@ -257,12 +243,7 @@ func TestCommentQuery_DepthLimit(t *testing.T) { // TestCommentQuery_HotSorting tests hot sorting with Lemmy algorithm func TestCommentQuery_HotSorting(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "hot.test", "did:plc:hot123") @@ -308,12 +289,7 @@ func TestCommentQuery_HotSorting(t *testing.T) { // TestCommentQuery_TopSorting tests top sorting with score-based ordering func TestCommentQuery_TopSorting(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "top.test", "did:plc:top123") @@ -371,12 +347,7 @@ func TestCommentQuery_TopSorting(t *testing.T) { // TestCommentQuery_NewSorting tests chronological sorting func TestCommentQuery_NewSorting(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "new.test", "did:plc:new123") @@ -410,12 +381,7 @@ func TestCommentQuery_NewSorting(t *testing.T) { // TestCommentQuery_Pagination tests cursor-based pagination func TestCommentQuery_Pagination(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "page.test", "did:plc:page123") @@ -484,12 +450,7 @@ func TestCommentQuery_Pagination(t *testing.T) { // TestCommentQuery_EmptyThread tests fetching comments from a post with no comments func TestCommentQuery_EmptyThread(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "empty.test", "did:plc:empty123") @@ -520,12 +481,7 @@ func TestCommentQuery_EmptyThread(t *testing.T) { // TestCommentQuery_DeletedComments tests that soft-deleted comments are excluded func TestCommentQuery_DeletedComments(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -645,12 +601,7 @@ func TestCommentQuery_DeletedComments(t *testing.T) { // TestCommentQuery_InvalidInputs tests error handling for invalid inputs func TestCommentQuery_InvalidInputs(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() service := setupCommentService(db) @@ -745,12 +696,7 @@ func TestCommentQuery_InvalidInputs(t *testing.T) { // TestCommentQuery_HTTPHandler tests the HTTP handler end-to-end func TestCommentQuery_HTTPHandler(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "http.test", "did:plc:http123") @@ -804,12 +750,7 @@ func TestCommentQuery_HTTPHandler(t *testing.T) { // TestCommentQuery_ParentRkeySubtree tests fetching a comment subtree via parentRkey // Backs the comment-permalink page and "continue this thread" for deep threads func TestCommentQuery_ParentRkeySubtree(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "subtree.test", "did:plc:subtree123") @@ -1117,7 +1058,6 @@ func TestCommentQuery_ParentRkeySubtree(t *testing.T) { fmt.Sprintf("at://%s/social.coves.actor.block/subtreeblock", blockerDID), "bafysubtreeblockcid") require.NoError(t, err, "Failed to record viewer block") - defer func() { _, _ = db.Exec("DELETE FROM user_blocks WHERE blocker_did = $1", blockerDID) }() blockedReq := &comments.GetCommentsRequest{ PostURI: postURI, @@ -1205,12 +1145,7 @@ func TestCommentQuery_ParentRkeySubtree(t *testing.T) { // TestCommentQuery_ParentRkeyHTTPHandler tests the real XRPC handler with parentRkey func TestCommentQuery_ParentRkeyHTTPHandler(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() testUser := createTestUser(t, db, "subtreehttp.test", "did:plc:subtreehttp123") diff --git a/tests/integration/comment_vote_test.go b/tests/integration/comment_vote_test.go index bffe46d..2054ffd 100644 --- a/tests/integration/comment_vote_test.go +++ b/tests/integration/comment_vote_test.go @@ -7,6 +7,7 @@ import ( "Coves/internal/core/comments" "Coves/internal/core/users" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "fmt" "testing" @@ -15,12 +16,7 @@ import ( // TestCommentVote_CreateAndUpdate tests voting on comments and vote count updates func TestCommentVote_CreateAndUpdate(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -325,12 +321,7 @@ func TestCommentVote_CreateAndUpdate(t *testing.T) { // TestCommentVote_ViewerState tests viewer vote state in comment query responses func TestCommentVote_ViewerState(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) diff --git a/tests/integration/comment_write_test.go b/tests/integration/comment_write_test.go index 5a88cb4..450ec56 100644 --- a/tests/integration/comment_write_test.go +++ b/tests/integration/comment_write_test.go @@ -8,14 +8,13 @@ import ( "Coves/internal/atproto/utils" "Coves/internal/core/comments" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" - "database/sql" "encoding/json" "errors" "fmt" "io" "net/http" - "os" "strings" "testing" "time" @@ -23,35 +22,12 @@ import ( oauthlib "github.com/bluesky-social/indigo/atproto/auth/oauth" "github.com/bluesky-social/indigo/atproto/syntax" _ "github.com/lib/pq" - "github.com/pressly/goose/v3" ) // TestCommentWrite_CreateTopLevelComment tests creating a comment on a post via E2E flow func TestCommentWrite_CreateTopLevelComment(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { - if closeErr := db.Close(); closeErr != nil { - t.Logf("Failed to close database: %v", closeErr) - } - }() - - // Run migrations - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) // Check if PDS is running pdsURL := getTestPDSURL() @@ -279,8 +255,7 @@ func TestCommentWrite_CreateTopLevelComment(t *testing.T) { // TestCommentWrite_CreateNestedReply tests creating a reply to another comment func TestCommentWrite_CreateNestedReply(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) ctx := context.Background() pdsURL := getTestPDSURL() @@ -426,8 +401,7 @@ func TestCommentWrite_CreateNestedReply(t *testing.T) { // TestCommentWrite_UpdateComment tests updating an existing comment func TestCommentWrite_UpdateComment(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) ctx := context.Background() pdsURL := getTestPDSURL() @@ -543,8 +517,7 @@ func TestCommentWrite_UpdateComment(t *testing.T) { // TestCommentWrite_DeleteComment tests deleting a comment func TestCommentWrite_DeleteComment(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) ctx := context.Background() pdsURL := getTestPDSURL() @@ -648,9 +621,6 @@ func TestCommentWrite_DeleteComment(t *testing.T) { // TestCommentWrite_CannotUpdateOthersComment tests authorization for updates func TestCommentWrite_CannotUpdateOthersComment(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() - ctx := context.Background() pdsURL := getTestPDSURL() @@ -724,9 +694,6 @@ func TestCommentWrite_CannotUpdateOthersComment(t *testing.T) { // TestCommentWrite_CannotDeleteOthersComment tests authorization for deletes func TestCommentWrite_CannotDeleteOthersComment(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() - ctx := context.Background() pdsURL := getTestPDSURL() @@ -806,8 +773,7 @@ func parseTestDID(did string) (syntax.DID, error) { // CID validation correctly detects concurrent modifications. // This verifies the optimistic locking mechanism that prevents lost updates. func TestCommentWrite_ConcurrentModificationDetection(t *testing.T) { - db := setupTestDB(t) - defer func() { _ = db.Close() }() + db := testkit.DB(t) ctx := context.Background() pdsURL := getTestPDSURL() diff --git a/tests/integration/community_avatar_e2e_test.go b/tests/integration/community_avatar_e2e_test.go index 11327a9..669ab8c 100644 --- a/tests/integration/community_avatar_e2e_test.go +++ b/tests/integration/community_avatar_e2e_test.go @@ -8,9 +8,9 @@ import ( "Coves/internal/core/blobs" "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "bytes" "context" - "database/sql" "errors" "fmt" "image" @@ -25,7 +25,6 @@ import ( "github.com/gorilla/websocket" _ "github.com/lib/pq" - "github.com/pressly/goose/v3" ) // createTestPNGImage creates a simple PNG image for testing @@ -48,25 +47,7 @@ func createTestPNGImage(width, height int, c color.Color) []byte { // TestCommunityAvatarE2E_CreateWithAvatar tests creating a community with an avatar // Flow: CreateCommunity(avatar) → PDS uploadBlob + putRecord → Jetstream → Consumer → AppView func TestCommunityAvatarE2E_CreateWithAvatar(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - // Run migrations - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) // Check if PDS is running pdsURL := os.Getenv("PDS_URL") @@ -294,25 +275,7 @@ func TestCommunityAvatarE2E_CreateWithAvatar(t *testing.T) { // TestCommunityAvatarE2E_UpdateWithAvatar tests updating a community's avatar // Flow: UpdateCommunity(avatar) → PDS uploadBlob + putRecord → Jetstream → Consumer → AppView func TestCommunityAvatarE2E_UpdateWithAvatar(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - // Run migrations - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) // Check if PDS is running pdsURL := os.Getenv("PDS_URL") @@ -668,25 +631,7 @@ func TestCommunityAvatarE2E_UpdateWithAvatar(t *testing.T) { // TestCommunityAvatarE2E_UpdateWithBanner tests updating a community's banner // Flow: UpdateCommunity(banner) → PDS uploadBlob + putRecord → Jetstream → Consumer → AppView func TestCommunityAvatarE2E_UpdateWithBanner(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - // Run migrations - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) // Check if PDS is running pdsURL := os.Getenv("PDS_URL") diff --git a/tests/integration/community_blocking_test.go b/tests/integration/community_blocking_test.go index 9deb5c2..a976fdf 100644 --- a/tests/integration/community_blocking_test.go +++ b/tests/integration/community_blocking_test.go @@ -5,6 +5,7 @@ package integration import ( "Coves/internal/atproto/jetstream" "Coves/internal/core/communities" + "Coves/tests/testkit" "context" "database/sql" "fmt" @@ -17,8 +18,7 @@ import ( // TestCommunityBlocking_Indexing tests Jetstream indexing of block events func TestCommunityBlocking_Indexing(t *testing.T) { ctx := context.Background() - db := setupTestDB(t) - defer cleanupBlockingTestDB(t, db) + db := testkit.DB(t) repo := createBlockingTestCommunityRepo(t, db) // Skip verification in tests @@ -205,8 +205,7 @@ func TestCommunityBlocking_Indexing(t *testing.T) { // TestCommunityBlocking_ListBlocked tests listing blocked communities func TestCommunityBlocking_ListBlocked(t *testing.T) { ctx := context.Background() - db := setupTestDB(t) - defer cleanupBlockingTestDB(t, db) + db := testkit.DB(t) repo := createBlockingTestCommunityRepo(t, db) userDID := "did:plc:test-user-list" @@ -282,8 +281,7 @@ func TestCommunityBlocking_ListBlocked(t *testing.T) { // TestCommunityBlocking_IsBlocked tests the fast block check func TestCommunityBlocking_IsBlocked(t *testing.T) { ctx := context.Background() - db := setupTestDB(t) - defer cleanupBlockingTestDB(t, db) + db := testkit.DB(t) repo := createBlockingTestCommunityRepo(t, db) @@ -346,8 +344,7 @@ func TestCommunityBlocking_IsBlocked(t *testing.T) { // TestCommunityBlocking_GetBlock tests block retrieval func TestCommunityBlocking_GetBlock(t *testing.T) { ctx := context.Background() - db := setupTestDB(t) - defer cleanupBlockingTestDB(t, db) + db := testkit.DB(t) repo := createBlockingTestCommunityRepo(t, db) @@ -440,20 +437,3 @@ func createBlockingTestCommunity(t *testing.T, repo communities.Repository, name return created } - -func cleanupBlockingTestDB(t *testing.T, db *sql.DB) { - // Clean up test data - _, err := db.Exec("DELETE FROM community_blocks WHERE user_did LIKE 'did:plc:test-%'") - if err != nil { - t.Logf("Warning: Failed to clean up blocks: %v", err) - } - - _, err = db.Exec("DELETE FROM communities WHERE did LIKE 'did:plc:test-community-%'") - if err != nil { - t.Logf("Warning: Failed to clean up communities: %v", err) - } - - if closeErr := db.Close(); closeErr != nil { - t.Logf("Failed to close database: %v", closeErr) - } -} diff --git a/tests/integration/community_consumer_test.go b/tests/integration/community_consumer_test.go index 4f17d4f..c03e2ff 100644 --- a/tests/integration/community_consumer_test.go +++ b/tests/integration/community_consumer_test.go @@ -7,6 +7,7 @@ import ( "Coves/internal/atproto/jetstream" "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "errors" "fmt" @@ -15,12 +16,7 @@ import ( ) func TestCommunityConsumer_HandleCommunityProfile(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -226,12 +222,7 @@ func TestCommunityConsumer_HandleCommunityProfile(t *testing.T) { } func TestCommunityConsumer_HandleSubscription(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -316,12 +307,7 @@ func TestCommunityConsumer_HandleSubscription(t *testing.T) { } func TestCommunityConsumer_IgnoresNonCommunityEvents(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) // Use mock resolver (though these tests don't create communities, so it won't be called) @@ -406,12 +392,7 @@ func (m *mockIdentityResolver) Resolve(ctx context.Context, did string) (*identi } func TestCommunityConsumer_PLCHandleResolution(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() diff --git a/tests/integration/community_credentials_test.go b/tests/integration/community_credentials_test.go index 6f11466..7ab56bc 100644 --- a/tests/integration/community_credentials_test.go +++ b/tests/integration/community_credentials_test.go @@ -5,6 +5,7 @@ package integration import ( "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "fmt" "testing" @@ -13,12 +14,7 @@ import ( // TestCommunityRepository_CredentialPersistence tests that PDS credentials are properly persisted func TestCommunityRepository_CredentialPersistence(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -124,12 +120,7 @@ func TestCommunityRepository_CredentialPersistence(t *testing.T) { // TestCommunityRepository_EncryptedCredentials tests encryption at rest func TestCommunityRepository_EncryptedCredentials(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -241,12 +232,7 @@ func TestCommunityRepository_EncryptedCredentials(t *testing.T) { // TestCommunityRepository_V2OwnershipModel tests that communities are self-owned func TestCommunityRepository_V2OwnershipModel(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() diff --git a/tests/integration/community_e2e_test.go b/tests/integration/community_e2e_test.go index d250297..4dce3b7 100644 --- a/tests/integration/community_e2e_test.go +++ b/tests/integration/community_e2e_test.go @@ -13,7 +13,6 @@ import ( "Coves/tests/testkit" "bytes" "context" - "database/sql" "encoding/json" "fmt" "io" @@ -30,7 +29,6 @@ import ( "github.com/go-chi/chi/v5" "github.com/gorilla/websocket" _ "github.com/lib/pq" - "github.com/pressly/goose/v3" ) // TestCommunity_E2E is a TRUE end-to-end test covering the complete flow: @@ -45,43 +43,7 @@ import ( // - Complete data flow from HTTP write to HTTP read via real infrastructure func TestCommunity_E2E(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { - if closeErr := db.Close(); closeErr != nil { - t.Logf("Failed to close database: %v", closeErr) - } - }() - - // Run migrations - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } - - // Clean up test data from previous runs (order matters due to FK constraints) - // Delete subscriptions first (references communities and users) - if _, cleanErr := db.Exec("DELETE FROM community_subscriptions"); cleanErr != nil { - t.Logf("Warning: Failed to clean up subscriptions: %v", cleanErr) - } - // Delete posts (references communities) - if _, cleanErr := db.Exec("DELETE FROM posts"); cleanErr != nil { - t.Logf("Warning: Failed to clean up posts: %v", cleanErr) - } - // Delete communities - if _, cleanErr := db.Exec("DELETE FROM communities"); cleanErr != nil { - t.Logf("Warning: Failed to clean up communities: %v", cleanErr) - } + db := testkit.DB(t) // Check if PDS is running pdsURL := os.Getenv("PDS_URL") diff --git a/tests/integration/community_get_viewer_state_test.go b/tests/integration/community_get_viewer_state_test.go index 3eb3910..9538cb7 100644 --- a/tests/integration/community_get_viewer_state_test.go +++ b/tests/integration/community_get_viewer_state_test.go @@ -7,6 +7,7 @@ import ( "Coves/internal/api/middleware" "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "encoding/json" "fmt" @@ -33,12 +34,7 @@ func (m *getViewerMockService) GetCommunity(ctx context.Context, identifier stri // social.coves.community.get lexicon promise ("viewer state will be // included if authenticated"). func TestCommunityGet_ViewerState(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() diff --git a/tests/integration/community_hostedby_security_test.go b/tests/integration/community_hostedby_security_test.go index b786e96..ba4d63b 100644 --- a/tests/integration/community_hostedby_security_test.go +++ b/tests/integration/community_hostedby_security_test.go @@ -5,6 +5,7 @@ package integration import ( "Coves/internal/atproto/jetstream" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "fmt" "net/http" @@ -16,12 +17,7 @@ import ( // TestHostedByVerification_DomainMatching tests that hostedBy domain must match handle domain func TestHostedByVerification_DomainMatching(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -241,12 +237,7 @@ func TestHostedByVerification_DomainMatching(t *testing.T) { // TestBidirectionalDIDVerification tests the full bidirectional verification with mock HTTP server // This test verifies that the DID document must claim the handle in alsoKnownAs field func TestBidirectionalDIDVerification(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -395,12 +386,7 @@ func TestBidirectionalDIDVerification(t *testing.T) { // TestExtractDomainFromHandle tests the domain extraction logic for various handle formats func TestExtractDomainFromHandle(t *testing.T) { // This is an internal function test - we'll test it through the consumer - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() diff --git a/tests/integration/community_identifier_resolution_test.go b/tests/integration/community_identifier_resolution_test.go index 6c0cce6..2b98734 100644 --- a/tests/integration/community_identifier_resolution_test.go +++ b/tests/integration/community_identifier_resolution_test.go @@ -5,6 +5,7 @@ package integration import ( "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "fmt" "os" @@ -17,12 +18,7 @@ import ( // TestCommunityIdentifierResolution tests all formats accepted by ResolveCommunityIdentifier func TestCommunityIdentifierResolution(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -213,12 +209,7 @@ func TestCommunityIdentifierResolution(t *testing.T) { // TestResolveScopedIdentifier_InputValidation tests input sanitization func TestResolveScopedIdentifier_InputValidation(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -388,12 +379,7 @@ func TestGetDisplayHandle(t *testing.T) { // TestIdentifierResolution_ErrorContext verifies error messages include identifier context func TestIdentifierResolution_ErrorContext(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -451,12 +437,7 @@ func TestIdentifierResolution_ErrorContext(t *testing.T) { // TestGetCommunity_IdentifierResolution tests all formats accepted by GetCommunity // This is distinct from ResolveCommunityIdentifier - GetCommunity returns the full Community object func TestGetCommunity_IdentifierResolution(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() diff --git a/tests/integration/community_list_viewer_state_test.go b/tests/integration/community_list_viewer_state_test.go index 1db9d61..27ac840 100644 --- a/tests/integration/community_list_viewer_state_test.go +++ b/tests/integration/community_list_viewer_state_test.go @@ -7,6 +7,7 @@ import ( "Coves/internal/api/middleware" "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "encoding/json" "fmt" @@ -22,12 +23,7 @@ import ( // TestCommunityList_ViewerState tests that the list communities endpoint // correctly populates viewer.subscribed field for authenticated users func TestCommunityList_ViewerState(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() diff --git a/tests/integration/community_provisioning_test.go b/tests/integration/community_provisioning_test.go index ffe48c5..dc817f7 100644 --- a/tests/integration/community_provisioning_test.go +++ b/tests/integration/community_provisioning_test.go @@ -5,6 +5,7 @@ package integration import ( "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "fmt" "strings" @@ -15,12 +16,7 @@ import ( // TestCommunityRepository_PasswordEncryption verifies P0 fix: // Password must be encrypted (not hashed) so we can recover it for session renewal func TestCommunityRepository_PasswordEncryption(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -139,12 +135,7 @@ func TestCommunityRepository_PasswordEncryption(t *testing.T) { // TestCommunityService_NameValidation verifies P1 fix: // Community names must respect DNS label limits (63 chars max) func TestCommunityService_NameValidation(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) provisioner := communities.NewPDSAccountProvisioner("test.local", "http://localhost:3001") @@ -307,12 +298,7 @@ func TestCommunityService_NameValidation(t *testing.T) { // TestPasswordSecurity verifies password generation security properties // Critical for P0: Passwords must be unpredictable and have sufficient entropy func TestPasswordSecurity(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -388,12 +374,7 @@ func TestPasswordSecurity(t *testing.T) { t.Run("password has sufficient length", func(t *testing.T) { // The implementation uses 32-character passwords // We can verify this indirectly through the database - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) @@ -446,12 +427,7 @@ func TestPasswordSecurity(t *testing.T) { // TestConcurrentProvisioning verifies thread-safety during community creation // Critical: Prevents race conditions that could create duplicate communities func TestConcurrentProvisioning(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -703,12 +679,7 @@ func TestPDSNetworkFailures(t *testing.T) { // TestTokenValidation verifies that PDS-returned tokens meet requirements // Critical for P0: Tokens must be valid JWTs that can be used for authentication func TestTokenValidation(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() diff --git a/tests/integration/community_repo_test.go b/tests/integration/community_repo_test.go index 3fc2793..7e116b6 100644 --- a/tests/integration/community_repo_test.go +++ b/tests/integration/community_repo_test.go @@ -5,6 +5,7 @@ package integration import ( "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "fmt" "testing" @@ -12,12 +13,7 @@ import ( ) func TestCommunityRepository_Create(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -123,12 +119,7 @@ func TestCommunityRepository_Create(t *testing.T) { } func TestCommunityRepository_GetByDID(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -181,12 +172,7 @@ func TestCommunityRepository_GetByDID(t *testing.T) { } func TestCommunityRepository_GetByHandle(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -227,12 +213,7 @@ func TestCommunityRepository_GetByHandle(t *testing.T) { } func TestCommunityRepository_Subscriptions(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -321,12 +302,7 @@ func TestCommunityRepository_Subscriptions(t *testing.T) { } func TestCommunityRepository_List(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -412,12 +388,7 @@ func TestCommunityRepository_List(t *testing.T) { } func TestCommunityRepository_GetSubscribedCommunityDIDs(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) ctx := context.Background() @@ -530,7 +501,7 @@ func TestCommunityRepository_GetSubscribedCommunityDIDs(t *testing.T) { // TODO: Implement search functionality before re-enabling this test // func TestCommunityRepository_Search(t *testing.T) { -// db := setupTestDB(t) +// db := testkit.DB(t) // defer func() { // if err := db.Close(); err != nil { // t.Logf("Failed to close database: %v", err) diff --git a/tests/integration/community_service_integration_test.go b/tests/integration/community_service_integration_test.go index 2ac4af2..7d340e9 100644 --- a/tests/integration/community_service_integration_test.go +++ b/tests/integration/community_service_integration_test.go @@ -5,6 +5,7 @@ package integration import ( "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "bytes" "context" "encoding/json" @@ -41,12 +42,7 @@ func TestCommunityService_CreateWithRealPDS(t *testing.T) { }() // Setup test database - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() repo := postgres.NewCommunityRepository(db) @@ -291,12 +287,7 @@ func TestCommunityService_UpdateWithRealPDS(t *testing.T) { }() // Setup test database - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() repo := postgres.NewCommunityRepository(db) @@ -482,12 +473,7 @@ func TestPasswordAuthentication(t *testing.T) { }() // Setup test database - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() repo := postgres.NewCommunityRepository(db) diff --git a/tests/integration/community_suggestion_e2e_test.go b/tests/integration/community_suggestion_e2e_test.go index ace7568..7be16b5 100644 --- a/tests/integration/community_suggestion_e2e_test.go +++ b/tests/integration/community_suggestion_e2e_test.go @@ -6,6 +6,7 @@ import ( "Coves/internal/api/routes" "Coves/internal/core/communitysuggestions" "Coves/internal/db/postgres" + "Coves/tests/testkit" "bytes" "encoding/json" "fmt" @@ -205,22 +206,7 @@ func updateStatusRequest(t *testing.T, router http.Handler, token string, sugges func setupSuggestionTestRouter(t *testing.T, adminDIDs []string) (http.Handler, *E2EOAuthMiddleware) { t.Helper() - db := setupTestDB(t) - - // Clean up suggestion-specific tables at the start to avoid dirty state from previous runs - if _, err := db.Exec("DELETE FROM suggestion_votes"); err != nil { - t.Logf("Warning: Failed to clean up suggestion_votes: %v", err) - } - if _, err := db.Exec("DELETE FROM community_suggestions"); err != nil { - t.Logf("Warning: Failed to clean up community_suggestions: %v", err) - } - - t.Cleanup(func() { - // Clean up at end too to leave DB clean - _, _ = db.Exec("DELETE FROM suggestion_votes") - _, _ = db.Exec("DELETE FROM community_suggestions") - _ = db.Close() - }) + db := testkit.DB(t) // Wire up real repository and service repo := postgres.NewCommunitySuggestionRepository(db) diff --git a/tests/integration/community_update_e2e_test.go b/tests/integration/community_update_e2e_test.go index 4bc8f36..448013b 100644 --- a/tests/integration/community_update_e2e_test.go +++ b/tests/integration/community_update_e2e_test.go @@ -8,8 +8,8 @@ import ( "Coves/internal/core/blobs" "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" - "database/sql" "errors" "fmt" "io" @@ -22,7 +22,6 @@ import ( "github.com/gorilla/websocket" _ "github.com/lib/pq" - "github.com/pressly/goose/v3" ) // TestCommunityUpdateE2E_WithJetstream tests the FULL community update flow with REAL Jetstream @@ -30,25 +29,7 @@ import ( // // This is a TRUE E2E test - no simulated Jetstream events! func TestCommunityUpdateE2E_WithJetstream(t *testing.T) { - // Setup test database - dbURL := os.Getenv("TEST_DATABASE_URL") - if dbURL == "" { - dbURL = "postgres://test_user:test_password@localhost:5434/coves_test?sslmode=disable" - } - - db, err := sql.Open("postgres", dbURL) - if err != nil { - t.Fatalf("Failed to connect to test database: %v", err) - } - defer func() { _ = db.Close() }() - - // Run migrations - if dialectErr := goose.SetDialect("postgres"); dialectErr != nil { - t.Fatalf("Failed to set goose dialect: %v", dialectErr) - } - if migrateErr := goose.Up(db, "../../internal/db/migrations"); migrateErr != nil { - t.Fatalf("Failed to run migrations: %v", migrateErr) - } + db := testkit.DB(t) // Check if PDS is running pdsURL := os.Getenv("PDS_URL") diff --git a/tests/integration/community_v2_validation_test.go b/tests/integration/community_v2_validation_test.go index 5f9248a..cb09eac 100644 --- a/tests/integration/community_v2_validation_test.go +++ b/tests/integration/community_v2_validation_test.go @@ -6,6 +6,7 @@ import ( "Coves/internal/atproto/jetstream" "Coves/internal/core/communities" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "errors" "fmt" @@ -15,12 +16,7 @@ import ( // TestCommunityConsumer_V2RKeyValidation tests that only V2 communities (rkey="self") are accepted func TestCommunityConsumer_V2RKeyValidation(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) // Skip verification in tests @@ -250,12 +246,7 @@ func TestCommunityConsumer_V2RKeyValidation(t *testing.T) { // TestCommunityConsumer_HandleField tests the V2 handle field func TestCommunityConsumer_HandleField(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) repo := postgres.NewCommunityRepository(db) // Skip verification in tests diff --git a/tests/integration/concurrent_scenarios_test.go b/tests/integration/concurrent_scenarios_test.go index 82ede8d..6c3709c 100644 --- a/tests/integration/concurrent_scenarios_test.go +++ b/tests/integration/concurrent_scenarios_test.go @@ -8,6 +8,7 @@ import ( "Coves/internal/core/communities" "Coves/internal/core/users" "Coves/internal/db/postgres" + "Coves/tests/testkit" "context" "fmt" "sync" @@ -18,12 +19,7 @@ import ( // TestConcurrentVoting_MultipleUsersOnSamePost tests race conditions when multiple users // vote on the same post simultaneously func TestConcurrentVoting_MultipleUsersOnSamePost(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() voteRepo := postgres.NewVoteRepository(db) @@ -325,12 +321,7 @@ func TestConcurrentVoting_MultipleUsersOnSamePost(t *testing.T) { // TestConcurrentCommenting_MultipleUsersOnSamePost tests race conditions when multiple users // comment on the same post simultaneously func TestConcurrentCommenting_MultipleUsersOnSamePost(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() commentRepo := postgres.NewCommentRepository(db) @@ -583,12 +574,7 @@ func TestConcurrentCommenting_MultipleUsersOnSamePost(t *testing.T) { // TestConcurrentCommunityCreation tests race conditions when multiple goroutines // try to create communities with the same handle func TestConcurrentCommunityCreation_DuplicateHandle(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() repo := postgres.NewCommunityRepository(db) @@ -718,12 +704,7 @@ func TestConcurrentCommunityCreation_DuplicateHandle(t *testing.T) { // TestConcurrentSubscription tests race conditions when multiple users subscribe // to the same community simultaneously func TestConcurrentSubscription_RaceConditions(t *testing.T) { - db := setupTestDB(t) - defer func() { - if err := db.Close(); err != nil { - t.Logf("Failed to close database: %v", err) - } - }() + db := testkit.DB(t) ctx := context.Background() communityRepo := postgres.NewCommunityRepository(db) -- 2.51.2