From e63838db12b54e713a85d699fd2654978e6785df Mon Sep 17 00:00:00 2001 From: Bretton Date: Wed, 15 Oct 2025 21:33:20 -0700 Subject: [PATCH] test(communities): update existing tests for V2.0 architecture MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Update all existing community tests to align with V2.0 changes: - Replace password hash fields with encrypted password fields - Remove DID generator mocks and dependencies - Update test data structures for PDS-managed keys - Fix assertions for new community provisioning flow Modified Test Files: - community_consumer_test.go: Update Jetstream consumer tests - community_credentials_test.go: Update credential validation tests - community_e2e_test.go: Update end-to-end workflow tests - community_repo_test.go: Update repository layer tests - user_test.go: Add helper functions for test DIDs - community_service_test.go: Update service layer unit tests Breaking Changes: - Communities no longer have Coves-generated DIDs - Password field is now encrypted, not hashed - Service constructors simplified (no DID generator) All tests pass with new V2.0 architecture. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- tests/integration/community_consumer_test.go | 23 ++---- .../integration/community_credentials_test.go | 37 +++------- tests/integration/community_e2e_test.go | 30 ++++---- tests/integration/community_repo_test.go | 72 +++++-------------- tests/integration/user_test.go | 8 +++ tests/unit/community_service_test.go | 5 +- 6 files changed, 58 insertions(+), 117 deletions(-) diff --git a/tests/integration/community_consumer_test.go b/tests/integration/community_consumer_test.go index 9c4c998..e1f2c7f 100644 --- a/tests/integration/community_consumer_test.go +++ b/tests/integration/community_consumer_test.go @@ -1,7 +1,6 @@ package integration import ( - "Coves/internal/atproto/did" "Coves/internal/atproto/jetstream" "Coves/internal/core/communities" "Coves/internal/db/postgres" @@ -21,15 +20,11 @@ func TestCommunityConsumer_HandleCommunityProfile(t *testing.T) { repo := postgres.NewCommunityRepository(db) consumer := jetstream.NewCommunityEventConsumer(repo) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("creates community from firehose event", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) // Simulate a Jetstream commit event event := &jetstream.JetstreamEvent{ @@ -85,11 +80,8 @@ func TestCommunityConsumer_HandleCommunityProfile(t *testing.T) { }) t.Run("updates existing community", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) handle := fmt.Sprintf("!update-test-%s@coves.local", uniqueSuffix) // Create initial community @@ -169,11 +161,8 @@ func TestCommunityConsumer_HandleCommunityProfile(t *testing.T) { }) t.Run("deletes community", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) // Create community to delete community := &communities.Community{ @@ -227,16 +216,12 @@ func TestCommunityConsumer_HandleSubscription(t *testing.T) { repo := postgres.NewCommunityRepository(db) consumer := jetstream.NewCommunityEventConsumer(repo) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("creates subscription from event", func(t *testing.T) { // Create a community first - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, diff --git a/tests/integration/community_credentials_test.go b/tests/integration/community_credentials_test.go index 175322f..fa39c03 100644 --- a/tests/integration/community_credentials_test.go +++ b/tests/integration/community_credentials_test.go @@ -1,7 +1,6 @@ package integration import ( - "Coves/internal/atproto/did" "Coves/internal/core/communities" "Coves/internal/db/postgres" "context" @@ -20,15 +19,11 @@ func TestCommunityRepository_CredentialPersistence(t *testing.T) { }() repo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("persists PDS credentials on create", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, @@ -40,7 +35,7 @@ func TestCommunityRepository_CredentialPersistence(t *testing.T) { Visibility: "public", // V2: PDS credentials PDSEmail: "community-test@communities.coves.local", - PDSPasswordHash: "$2a$10$abcdefghijklmnopqrstuv", // Mock bcrypt hash + PDSPassword: "cleartext-password-encrypted-by-repo", // V2: Cleartext (encrypted by repository) PDSAccessToken: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.test.token", PDSRefreshToken: "refresh_token_xyz123", PDSURL: "http://localhost:2583", @@ -66,8 +61,8 @@ func TestCommunityRepository_CredentialPersistence(t *testing.T) { if retrieved.PDSEmail != community.PDSEmail { t.Errorf("Expected PDSEmail %s, got %s", community.PDSEmail, retrieved.PDSEmail) } - if retrieved.PDSPasswordHash != community.PDSPasswordHash { - t.Errorf("Expected PDSPasswordHash to be persisted") + if retrieved.PDSPassword != community.PDSPassword { + t.Errorf("Expected PDSPassword to be persisted and encrypted/decrypted") } if retrieved.PDSAccessToken != community.PDSAccessToken { t.Errorf("Expected PDSAccessToken to be persisted and decrypted correctly") @@ -81,11 +76,8 @@ func TestCommunityRepository_CredentialPersistence(t *testing.T) { }) t.Run("handles empty credentials gracefully", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) // Community without PDS credentials (e.g., from Jetstream consumer) community := &communities.Community{ @@ -138,15 +130,11 @@ func TestCommunityRepository_EncryptedCredentials(t *testing.T) { }() repo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("credentials are encrypted in database", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) accessToken := "sensitive_access_token_xyz123" refreshToken := "sensitive_refresh_token_abc456" @@ -160,7 +148,7 @@ func TestCommunityRepository_EncryptedCredentials(t *testing.T) { HostedByDID: "did:web:coves.local", Visibility: "public", PDSEmail: "encrypted@communities.coves.local", - PDSPasswordHash: "$2a$10$encrypted", + PDSPassword: "cleartext-password-for-encryption", // V2: Cleartext (encrypted by repository) PDSAccessToken: accessToken, PDSRefreshToken: refreshToken, PDSURL: "http://localhost:2583", @@ -214,11 +202,8 @@ func TestCommunityRepository_EncryptedCredentials(t *testing.T) { }) t.Run("encryption handles special characters", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) // Token with special characters specialToken := "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2NvdmVzLnNvY2lhbCIsInN1YiI6ImRpZDpwbGM6YWJjMTIzIiwiaWF0IjoxNzA5MjQwMDAwfQ.special/chars+here==" @@ -262,15 +247,11 @@ func TestCommunityRepository_V2OwnershipModel(t *testing.T) { }() repo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("V2 communities are self-owned", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, diff --git a/tests/integration/community_e2e_test.go b/tests/integration/community_e2e_test.go index c099613..1be8d02 100644 --- a/tests/integration/community_e2e_test.go +++ b/tests/integration/community_e2e_test.go @@ -2,7 +2,6 @@ package integration import ( "Coves/internal/api/routes" - "Coves/internal/atproto/did" "Coves/internal/atproto/identity" "Coves/internal/atproto/jetstream" "Coves/internal/core/communities" @@ -86,7 +85,6 @@ func TestCommunity_E2E(t *testing.T) { // Setup dependencies communityRepo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") // Get instance credentials instanceHandle := os.Getenv("PDS_INSTANCE_HANDLE") @@ -108,7 +106,7 @@ func TestCommunity_E2E(t *testing.T) { t.Logf("✅ Authenticated - Instance DID: %s", instanceDID) - // V2: Extract instance domain for community provisioning + // V2.0: Extract instance domain for community provisioning var instanceDomain string if strings.HasPrefix(instanceDID, "did:web:") { instanceDomain = strings.TrimPrefix(instanceDID, "did:web:") @@ -117,16 +115,24 @@ func TestCommunity_E2E(t *testing.T) { instanceDomain = "coves.social" } - // V2: Create user service for PDS account provisioning + // V2.0: Create user service with REAL identity resolution using local PLC + plcURL := os.Getenv("PLC_DIRECTORY_URL") + if plcURL == "" { + plcURL = "http://localhost:3002" // Local PLC directory + } userRepo := postgres.NewUserRepository(db) - identityResolver := &communityTestIdentityResolver{} // Simple mock for test - userService := users.NewUserService(userRepo, identityResolver, pdsURL) - - // V2: Initialize PDS account provisioner - provisioner := communities.NewPDSAccountProvisioner(userService, instanceDomain, pdsURL) - - // Create service and consumer - communityService := communities.NewCommunityService(communityRepo, didGen, pdsURL, instanceDID, instanceDomain, provisioner) + identityConfig := identity.DefaultConfig() + identityConfig.PLCURL = plcURL // Use local PLC for identity resolution + identityResolver := identity.NewResolver(db, identityConfig) + _ = users.NewUserService(userRepo, identityResolver, pdsURL) // Keep for potential future use + t.Logf("✅ Identity resolver configured with local PLC: %s", plcURL) + + // V2.0: Initialize PDS account provisioner (simplified - no DID generator needed!) + // PDS handles all DID generation and registration automatically + provisioner := communities.NewPDSAccountProvisioner(instanceDomain, pdsURL) + + // Create service (no longer needs didGen directly - provisioner owns it) + communityService := communities.NewCommunityService(communityRepo, pdsURL, instanceDID, instanceDomain, provisioner) if svc, ok := communityService.(interface{ SetPDSAccessToken(string) }); ok { svc.SetPDSAccessToken(accessToken) } diff --git a/tests/integration/community_repo_test.go b/tests/integration/community_repo_test.go index 7ce6925..a90c3b0 100644 --- a/tests/integration/community_repo_test.go +++ b/tests/integration/community_repo_test.go @@ -1,7 +1,6 @@ package integration import ( - "Coves/internal/atproto/did" "Coves/internal/core/communities" "Coves/internal/db/postgres" "context" @@ -19,16 +18,12 @@ func TestCommunityRepository_Create(t *testing.T) { }() repo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("creates community successfully", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } - // Generate unique handle using timestamp to avoid collisions + // Generate unique handle and DID using timestamp to avoid collisions uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, Handle: fmt.Sprintf("!test-gaming-%s@coves.local", uniqueSuffix), @@ -58,11 +53,8 @@ func TestCommunityRepository_Create(t *testing.T) { }) t.Run("returns error for duplicate DID", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, Handle: fmt.Sprintf("!duplicate-test-%s@coves.local", uniqueSuffix), @@ -81,7 +73,7 @@ func TestCommunityRepository_Create(t *testing.T) { } // Try to create again with same DID - if _, err = repo.Create(ctx, community); err != communities.ErrCommunityAlreadyExists { + if _, err := repo.Create(ctx, community); err != communities.ErrCommunityAlreadyExists { t.Errorf("Expected ErrCommunityAlreadyExists, got: %v", err) } }) @@ -91,10 +83,7 @@ func TestCommunityRepository_Create(t *testing.T) { handle := fmt.Sprintf("!unique-handle-%s@coves.local", uniqueSuffix) // First community - did1, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate first community DID: %v", err) - } + did1 := generateTestDID(uniqueSuffix + "1") community1 := &communities.Community{ DID: did1, Handle: handle, @@ -112,10 +101,7 @@ func TestCommunityRepository_Create(t *testing.T) { } // Second community with different DID but same handle - did2, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate second community DID: %v", err) - } + did2 := generateTestDID(uniqueSuffix + "2") community2 := &communities.Community{ DID: did2, Handle: handle, // Same handle! @@ -128,7 +114,7 @@ func TestCommunityRepository_Create(t *testing.T) { UpdatedAt: time.Now(), } - if _, err = repo.Create(ctx, community2); err != communities.ErrHandleTaken { + if _, err := repo.Create(ctx, community2); err != communities.ErrHandleTaken { t.Errorf("Expected ErrHandleTaken, got: %v", err) } }) @@ -143,15 +129,11 @@ func TestCommunityRepository_GetByDID(t *testing.T) { }() repo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("retrieves existing community", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, Handle: fmt.Sprintf("!getbyid-test-%s@coves.local", uniqueSuffix), @@ -188,10 +170,8 @@ func TestCommunityRepository_GetByDID(t *testing.T) { }) t.Run("returns error for non-existent community", func(t *testing.T) { - fakeDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate fake DID: %v", err) - } + uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + fakeDID := generateTestDID(uniqueSuffix) if _, err := repo.GetByDID(ctx, fakeDID); err != communities.ErrCommunityNotFound { t.Errorf("Expected ErrCommunityNotFound, got: %v", err) } @@ -207,15 +187,11 @@ func TestCommunityRepository_GetByHandle(t *testing.T) { }() repo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("retrieves community by handle", func(t *testing.T) { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) handle := fmt.Sprintf("!handle-lookup-%s@coves.local", uniqueSuffix) community := &communities.Community{ @@ -257,15 +233,11 @@ func TestCommunityRepository_Subscriptions(t *testing.T) { }() repo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() // Create a community for subscription tests - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, Handle: fmt.Sprintf("!subscription-test-%s@coves.local", uniqueSuffix), @@ -311,7 +283,7 @@ func TestCommunityRepository_Subscriptions(t *testing.T) { } // Try to subscribe again - _, err = repo.Subscribe(ctx, sub) + _, err := repo.Subscribe(ctx, sub) if err != communities.ErrSubscriptionAlreadyExists { t.Errorf("Expected ErrSubscriptionAlreadyExists, got: %v", err) } @@ -352,17 +324,14 @@ func TestCommunityRepository_List(t *testing.T) { }() repo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("lists communities with pagination", func(t *testing.T) { // Create multiple communities baseSuffix := time.Now().UnixNano() for i := 0; i < 5; i++ { - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } + uniqueSuffix := fmt.Sprintf("%d%d", baseSuffix, i) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, Handle: fmt.Sprintf("!list-test-%d-%d@coves.local", baseSuffix, i), @@ -402,11 +371,8 @@ func TestCommunityRepository_List(t *testing.T) { t.Run("filters by visibility", func(t *testing.T) { // Create an unlisted community - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, Handle: fmt.Sprintf("!unlisted-test-%s@coves.local", uniqueSuffix), @@ -453,16 +419,12 @@ func TestCommunityRepository_Search(t *testing.T) { }() repo := postgres.NewCommunityRepository(db) - didGen := did.NewGenerator(true, "https://plc.directory") ctx := context.Background() t.Run("searches communities by name", func(t *testing.T) { // Create a community with searchable name - communityDID, err := didGen.GenerateCommunityDID() - if err != nil { - t.Fatalf("Failed to generate community DID: %v", err) - } uniqueSuffix := fmt.Sprintf("%d", time.Now().UnixNano()) + communityDID := generateTestDID(uniqueSuffix) community := &communities.Community{ DID: communityDID, Handle: fmt.Sprintf("!golang-search-%s@coves.local", uniqueSuffix), diff --git a/tests/integration/user_test.go b/tests/integration/user_test.go index eab6f46..3527889 100644 --- a/tests/integration/user_test.go +++ b/tests/integration/user_test.go @@ -70,6 +70,14 @@ func setupTestDB(t *testing.T) *sql.DB { return db } +// generateTestDID generates a unique test DID for integration tests +// V2.0: No longer uses DID generator - just creates valid did:plc strings +func generateTestDID(suffix string) string { + // Use a deterministic base + suffix for reproducible test DIDs + // Format matches did:plc but doesn't need PLC registration for unit/repo tests + return fmt.Sprintf("did:plc:test%s", suffix) +} + func TestUserCreationAndRetrieval(t *testing.T) { db := setupTestDB(t) defer func() { diff --git a/tests/unit/community_service_test.go b/tests/unit/community_service_test.go index 6bea700..ebf05b2 100644 --- a/tests/unit/community_service_test.go +++ b/tests/unit/community_service_test.go @@ -1,7 +1,6 @@ package unit import ( - "Coves/internal/atproto/did" "Coves/internal/core/communities" "context" "fmt" @@ -163,7 +162,7 @@ func TestCommunityService_PDSTimeouts(t *testing.T) { defer slowPDS.Close() _ = newMockCommunityRepo() - _ = did.NewGenerator(true, "https://plc.directory") + // V2.0: DID generator no longer needed - PDS generates DIDs // Note: We can't easily test the actual service without mocking more dependencies // This test verifies the concept - in practice, a 15s operation should NOT timeout @@ -249,7 +248,7 @@ func TestCommunityService_CredentialPersistence(t *testing.T) { CreatedByDID: "did:plc:creator", HostedByDID: "did:web:coves.social", PDSEmail: "community-test@communities.coves.social", - PDSPasswordHash: "$2a$10$hash", + PDSPassword: "cleartext-password-will-be-encrypted", // V2: Cleartext (encrypted by repository) PDSAccessToken: "test_access_token", PDSRefreshToken: "test_refresh_token", PDSURL: "http://localhost:2583", -- 2.51.2