package db import ( "fmt" "testing" "time" ) func TestDeleteUserDataFull_DeletesAllData(t *testing.T) { db, err := InitDB(":memory:", LibsqlConfig{}) if err != nil { t.Fatalf("Failed to init database: %v", err) } defer db.Close() // Create test user testUser := &User{ DID: "did:plc:test123", Handle: "test.bsky.social", PDSEndpoint: "https://bsky.social", LastSeen: time.Now(), } if err := UpsertUser(db, testUser); err != nil { t.Fatalf("Failed to create user: %v", err) } // Create manifest _, err = db.Exec(` INSERT INTO manifests (manifest_key, did, repository, digest, hold_endpoint, schema_version, media_type, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `, ManifestKey(testUser.DID, "myapp", "sha256:abc123"), testUser.DID, "myapp", "sha256:abc123", "did:web:hold.example.com", 2, "application/vnd.oci.image.manifest.v1+json", time.Now()) if err != nil { t.Fatalf("Failed to create manifest: %v", err) } // Create tag _, err = db.Exec(` INSERT INTO tags (did, repository, tag, digest, created_at) VALUES (?, ?, ?, ?, ?) `, testUser.DID, "myapp", "latest", "sha256:abc123", time.Now()) if err != nil { t.Fatalf("Failed to create tag: %v", err) } // Create hold membership data (non-cascading) _, err = db.Exec(` INSERT INTO hold_crew_approvals (hold_did, user_did, approved_at, expires_at) VALUES (?, ?, ?, ?) `, "did:web:hold.example.com", testUser.DID, time.Now(), time.Now().Add(24*time.Hour)) if err != nil { t.Fatalf("Failed to create crew approval: %v", err) } _, err = db.Exec(` INSERT INTO hold_crew_members (hold_did, member_did, rkey, permissions) VALUES (?, ?, ?, ?) `, "did:web:hold.example.com", testUser.DID, "member1", `["blob:read","blob:write"]`) if err != nil { t.Fatalf("Failed to create crew member: %v", err) } // Create OAuth store oauthStore := NewOAuthStore(db) // Delete all user data err = DeleteUserDataFull(db, oauthStore, testUser.DID) if err != nil { t.Fatalf("DeleteUserDataFull failed: %v", err) } // Verify user was deleted var count int err = db.QueryRow("SELECT COUNT(*) FROM users WHERE did = ?", testUser.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query users: %v", err) } if count != 0 { t.Error("Expected user to be deleted") } // Verify manifests were cascade deleted err = db.QueryRow("SELECT COUNT(*) FROM manifests WHERE did = ?", testUser.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query manifests: %v", err) } if count != 0 { t.Error("Expected manifests to be cascade deleted") } // Verify tags were cascade deleted err = db.QueryRow("SELECT COUNT(*) FROM tags WHERE did = ?", testUser.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query tags: %v", err) } if count != 0 { t.Error("Expected tags to be cascade deleted") } // Verify hold membership data was deleted err = db.QueryRow("SELECT COUNT(*) FROM hold_crew_approvals WHERE user_did = ?", testUser.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query crew approvals: %v", err) } if count != 0 { t.Error("Expected crew approvals to be deleted") } err = db.QueryRow("SELECT COUNT(*) FROM hold_crew_members WHERE member_did = ?", testUser.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query crew members: %v", err) } if count != 0 { t.Error("Expected crew members to be deleted") } } func TestDeleteUserDataFull_DoesNotAffectOtherUsers(t *testing.T) { db, err := InitDB(":memory:", LibsqlConfig{}) if err != nil { t.Fatalf("Failed to init database: %v", err) } defer db.Close() // Create two users user1 := &User{ DID: "did:plc:user1", Handle: "user1.bsky.social", PDSEndpoint: "https://bsky.social", LastSeen: time.Now(), } user2 := &User{ DID: "did:plc:user2", Handle: "user2.bsky.social", PDSEndpoint: "https://bsky.social", LastSeen: time.Now(), } if err := UpsertUser(db, user1); err != nil { t.Fatalf("Failed to create user1: %v", err) } if err := UpsertUser(db, user2); err != nil { t.Fatalf("Failed to create user2: %v", err) } // Create manifests for both users for _, user := range []*User{user1, user2} { _, err = db.Exec(` INSERT INTO manifests (manifest_key, did, repository, digest, hold_endpoint, schema_version, media_type, created_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?) `, ManifestKey(user.DID, "myapp", "sha256:"+user.DID), user.DID, "myapp", "sha256:"+user.DID, "did:web:hold.example.com", 2, "application/vnd.oci.image.manifest.v1+json", time.Now()) if err != nil { t.Fatalf("Failed to create manifest for %s: %v", user.Handle, err) } } // Create hold membership data for both users for i, user := range []*User{user1, user2} { _, err = db.Exec(` INSERT INTO hold_crew_members (hold_did, member_did, rkey, permissions) VALUES (?, ?, ?, ?) `, "did:web:hold.example.com", user.DID, fmt.Sprintf("member%d", i+1), `["blob:read"]`) if err != nil { t.Fatalf("Failed to create crew member for %s: %v", user.Handle, err) } } oauthStore := NewOAuthStore(db) // Delete only user1's data err = DeleteUserDataFull(db, oauthStore, user1.DID) if err != nil { t.Fatalf("DeleteUserDataFull failed: %v", err) } // Verify user1 was deleted var count int err = db.QueryRow("SELECT COUNT(*) FROM users WHERE did = ?", user1.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query users: %v", err) } if count != 0 { t.Error("Expected user1 to be deleted") } // Verify user2 still exists err = db.QueryRow("SELECT COUNT(*) FROM users WHERE did = ?", user2.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query users: %v", err) } if count != 1 { t.Error("Expected user2 to still exist") } // Verify user2's manifests still exist err = db.QueryRow("SELECT COUNT(*) FROM manifests WHERE did = ?", user2.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query manifests: %v", err) } if count != 1 { t.Error("Expected user2's manifest to still exist") } // Verify user2's crew membership still exists err = db.QueryRow("SELECT COUNT(*) FROM hold_crew_members WHERE member_did = ?", user2.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query crew members: %v", err) } if count != 1 { t.Error("Expected user2's crew membership to still exist") } } func TestDeleteUserDataFull_HandlesNonExistentUser(t *testing.T) { db, err := InitDB(":memory:", LibsqlConfig{}) if err != nil { t.Fatalf("Failed to init database: %v", err) } defer db.Close() oauthStore := NewOAuthStore(db) // Try to delete non-existent user - should not error err = DeleteUserDataFull(db, oauthStore, "did:plc:nonexistent") if err != nil { t.Errorf("Expected no error for non-existent user, got: %v", err) } } func TestDeleteUserDataFull_WithNilOAuthStore(t *testing.T) { db, err := InitDB(":memory:", LibsqlConfig{}) if err != nil { t.Fatalf("Failed to init database: %v", err) } defer db.Close() testUser := &User{ DID: "did:plc:test123", Handle: "test.bsky.social", PDSEndpoint: "https://bsky.social", LastSeen: time.Now(), } if err := UpsertUser(db, testUser); err != nil { t.Fatalf("Failed to create user: %v", err) } // Delete with nil OAuth store - should still work err = DeleteUserDataFull(db, nil, testUser.DID) if err != nil { t.Errorf("Expected no error with nil OAuth store, got: %v", err) } // Verify user was deleted var count int err = db.QueryRow("SELECT COUNT(*) FROM users WHERE did = ?", testUser.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query users: %v", err) } if count != 0 { t.Error("Expected user to be deleted") } } func TestDeleteUserDataFull_DeletesDenials(t *testing.T) { db, err := InitDB(":memory:", LibsqlConfig{}) if err != nil { t.Fatalf("Failed to init database: %v", err) } defer db.Close() testUser := &User{ DID: "did:plc:test123", Handle: "test.bsky.social", PDSEndpoint: "https://bsky.social", LastSeen: time.Now(), } if err := UpsertUser(db, testUser); err != nil { t.Fatalf("Failed to create user: %v", err) } // Create denial record _, err = db.Exec(` INSERT INTO hold_crew_denials (hold_did, user_did, denial_count, next_retry_at, last_denied_at) VALUES (?, ?, ?, ?, ?) `, "did:web:hold.example.com", testUser.DID, 1, time.Now().Add(24*time.Hour), time.Now()) if err != nil { t.Fatalf("Failed to create crew denial: %v", err) } oauthStore := NewOAuthStore(db) err = DeleteUserDataFull(db, oauthStore, testUser.DID) if err != nil { t.Fatalf("DeleteUserDataFull failed: %v", err) } // Verify denial was deleted var count int err = db.QueryRow("SELECT COUNT(*) FROM hold_crew_denials WHERE user_did = ?", testUser.DID).Scan(&count) if err != nil { t.Fatalf("Failed to query crew denials: %v", err) } if count != 0 { t.Error("Expected crew denials to be deleted") } }