You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
302 lines
8.7 KiB
302 lines
8.7 KiB
package neo4j |
|
|
|
import ( |
|
"context" |
|
"testing" |
|
) |
|
|
|
// TestMigrationV2_CleanupBinaryEncodedValues tests that migration v2 properly |
|
// cleans up binary-encoded pubkeys and event IDs |
|
func TestMigrationV2_CleanupBinaryEncodedValues(t *testing.T) { |
|
if testDB == nil { |
|
t.Skip("Neo4j not available") |
|
} |
|
|
|
// Clean up before test |
|
cleanTestDatabase() |
|
|
|
ctx := context.Background() |
|
|
|
// Create some valid NostrUser nodes (should NOT be deleted) |
|
validPubkeys := []string{ |
|
"0000000000000000000000000000000000000000000000000000000000000001", |
|
"abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789", |
|
} |
|
for _, pk := range validPubkeys { |
|
setupInvalidNostrUser(t, pk) // Using setupInvalidNostrUser to create directly |
|
} |
|
|
|
// Create some invalid NostrUser nodes (should be deleted) |
|
invalidPubkeys := []string{ |
|
"binary\x00garbage\x00data", // Binary garbage |
|
"ABCDEF", // Too short |
|
"GGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGGG", // Non-hex chars |
|
string(append(make([]byte, 32), 0)), // 33-byte binary format |
|
} |
|
for _, pk := range invalidPubkeys { |
|
setupInvalidNostrUser(t, pk) |
|
} |
|
|
|
// Verify invalid nodes exist before migration |
|
invalidCountBefore := countInvalidNostrUsers(t) |
|
if invalidCountBefore != 4 { |
|
t.Errorf("Expected 4 invalid NostrUsers before migration, got %d", invalidCountBefore) |
|
} |
|
|
|
totalBefore := countNodes(t, "NostrUser") |
|
if totalBefore != 6 { |
|
t.Errorf("Expected 6 total NostrUsers before migration, got %d", totalBefore) |
|
} |
|
|
|
// Run the migration |
|
err := migrateBinaryToHex(ctx, testDB) |
|
if err != nil { |
|
t.Fatalf("Migration failed: %v", err) |
|
} |
|
|
|
// Verify invalid nodes were deleted |
|
invalidCountAfter := countInvalidNostrUsers(t) |
|
if invalidCountAfter != 0 { |
|
t.Errorf("Expected 0 invalid NostrUsers after migration, got %d", invalidCountAfter) |
|
} |
|
|
|
// Verify valid nodes were NOT deleted |
|
totalAfter := countNodes(t, "NostrUser") |
|
if totalAfter != 2 { |
|
t.Errorf("Expected 2 valid NostrUsers after migration, got %d", totalAfter) |
|
} |
|
} |
|
|
|
// TestMigrationV2_CleanupInvalidEvents tests that migration v2 properly |
|
// cleans up Event nodes with invalid pubkeys or IDs |
|
func TestMigrationV2_CleanupInvalidEvents(t *testing.T) { |
|
if testDB == nil { |
|
t.Skip("Neo4j not available") |
|
} |
|
|
|
// Clean up before test |
|
cleanTestDatabase() |
|
|
|
ctx := context.Background() |
|
|
|
// Create valid events |
|
validEventID := "1111111111111111111111111111111111111111111111111111111111111111" |
|
validPubkey := "0000000000000000000000000000000000000000000000000000000000000001" |
|
setupTestEvent(t, validEventID, validPubkey, 1, "[]") |
|
|
|
// Create invalid events directly |
|
setupInvalidEvent(t, "invalid_id", validPubkey) // Invalid ID |
|
setupInvalidEvent(t, validEventID+"2", "invalid_pubkey") // Invalid pubkey (different ID to avoid duplicate) |
|
setupInvalidEvent(t, "TOOSHORT", "binary\x00garbage") // Both invalid |
|
|
|
// Count events before migration |
|
eventsBefore := countNodes(t, "Event") |
|
if eventsBefore != 4 { |
|
t.Errorf("Expected 4 Events before migration, got %d", eventsBefore) |
|
} |
|
|
|
// Run the migration |
|
err := migrateBinaryToHex(ctx, testDB) |
|
if err != nil { |
|
t.Fatalf("Migration failed: %v", err) |
|
} |
|
|
|
// Verify only valid event remains |
|
eventsAfter := countNodes(t, "Event") |
|
if eventsAfter != 1 { |
|
t.Errorf("Expected 1 valid Event after migration, got %d", eventsAfter) |
|
} |
|
} |
|
|
|
// TestMigrationV2_CleanupInvalidTags tests that migration v2 properly |
|
// cleans up Tag nodes (e/p type) with invalid values |
|
func TestMigrationV2_CleanupInvalidTags(t *testing.T) { |
|
if testDB == nil { |
|
t.Skip("Neo4j not available") |
|
} |
|
|
|
// Clean up before test |
|
cleanTestDatabase() |
|
|
|
ctx := context.Background() |
|
|
|
// Create valid tags |
|
validHex := "abcdef0123456789abcdef0123456789abcdef0123456789abcdef0123456789" |
|
setupInvalidTag(t, "e", validHex) // Valid e-tag |
|
setupInvalidTag(t, "p", validHex) // Valid p-tag |
|
setupInvalidTag(t, "t", "topic") // Non e/p tag (should not be affected) |
|
|
|
// Create invalid e/p tags |
|
setupInvalidTag(t, "e", "binary\x00garbage") // Invalid e-tag |
|
setupInvalidTag(t, "p", "TOOSHORT") // Invalid p-tag (too short) |
|
setupInvalidTag(t, "e", string(append(make([]byte, 32), 0))) // Binary encoded |
|
|
|
// Count tags before migration |
|
tagsBefore := countNodes(t, "Tag") |
|
if tagsBefore != 6 { |
|
t.Errorf("Expected 6 Tags before migration, got %d", tagsBefore) |
|
} |
|
|
|
invalidBefore := countInvalidTags(t) |
|
if invalidBefore != 3 { |
|
t.Errorf("Expected 3 invalid e/p Tags before migration, got %d", invalidBefore) |
|
} |
|
|
|
// Run the migration |
|
err := migrateBinaryToHex(ctx, testDB) |
|
if err != nil { |
|
t.Fatalf("Migration failed: %v", err) |
|
} |
|
|
|
// Verify invalid tags were deleted |
|
invalidAfter := countInvalidTags(t) |
|
if invalidAfter != 0 { |
|
t.Errorf("Expected 0 invalid e/p Tags after migration, got %d", invalidAfter) |
|
} |
|
|
|
// Verify valid tags remain (2 e/p valid + 1 t-tag) |
|
tagsAfter := countNodes(t, "Tag") |
|
if tagsAfter != 3 { |
|
t.Errorf("Expected 3 Tags after migration, got %d", tagsAfter) |
|
} |
|
} |
|
|
|
// TestMigrationV2_Idempotent tests that migration v2 can be run multiple times safely |
|
func TestMigrationV2_Idempotent(t *testing.T) { |
|
if testDB == nil { |
|
t.Skip("Neo4j not available") |
|
} |
|
|
|
// Clean up before test |
|
cleanTestDatabase() |
|
|
|
ctx := context.Background() |
|
|
|
// Create only valid data |
|
validPubkey := "0000000000000000000000000000000000000000000000000000000000000001" |
|
validEventID := "1111111111111111111111111111111111111111111111111111111111111111" |
|
setupTestEvent(t, validEventID, validPubkey, 1, "[]") |
|
|
|
countBefore := countNodes(t, "Event") |
|
|
|
// Run migration first time |
|
err := migrateBinaryToHex(ctx, testDB) |
|
if err != nil { |
|
t.Fatalf("First migration run failed: %v", err) |
|
} |
|
|
|
countAfterFirst := countNodes(t, "Event") |
|
if countAfterFirst != countBefore { |
|
t.Errorf("First migration changed valid event count: before=%d, after=%d", countBefore, countAfterFirst) |
|
} |
|
|
|
// Run migration second time |
|
err = migrateBinaryToHex(ctx, testDB) |
|
if err != nil { |
|
t.Fatalf("Second migration run failed: %v", err) |
|
} |
|
|
|
countAfterSecond := countNodes(t, "Event") |
|
if countAfterSecond != countBefore { |
|
t.Errorf("Second migration changed valid event count: before=%d, after=%d", countBefore, countAfterSecond) |
|
} |
|
} |
|
|
|
// TestMigrationV2_NoDataDoesNotFail tests that migration v2 succeeds with empty database |
|
func TestMigrationV2_NoDataDoesNotFail(t *testing.T) { |
|
if testDB == nil { |
|
t.Skip("Neo4j not available") |
|
} |
|
|
|
// Clean up completely |
|
cleanTestDatabase() |
|
|
|
ctx := context.Background() |
|
|
|
// Run migration on empty database - should not fail |
|
err := migrateBinaryToHex(ctx, testDB) |
|
if err != nil { |
|
t.Fatalf("Migration on empty database failed: %v", err) |
|
} |
|
} |
|
|
|
// TestMigrationMarking tests that migrations are properly tracked |
|
func TestMigrationMarking(t *testing.T) { |
|
if testDB == nil { |
|
t.Skip("Neo4j not available") |
|
} |
|
|
|
// Clean up before test |
|
cleanTestDatabase() |
|
|
|
ctx := context.Background() |
|
|
|
// Verify migration v2 has not been applied |
|
if testDB.migrationApplied(ctx, "v2") { |
|
t.Error("Migration v2 should not be applied before test") |
|
} |
|
|
|
// Mark migration as complete |
|
err := testDB.markMigrationComplete(ctx, "v2", "Test migration") |
|
if err != nil { |
|
t.Fatalf("Failed to mark migration complete: %v", err) |
|
} |
|
|
|
// Verify migration is now marked as applied |
|
if !testDB.migrationApplied(ctx, "v2") { |
|
t.Error("Migration v2 should be applied after marking") |
|
} |
|
|
|
// Clean up |
|
cleanTestDatabase() |
|
} |
|
|
|
// TestMigrationV1_AuthorToNostrUserMerge tests the author migration |
|
func TestMigrationV1_AuthorToNostrUserMerge(t *testing.T) { |
|
if testDB == nil { |
|
t.Skip("Neo4j not available") |
|
} |
|
|
|
// Clean up before test |
|
cleanTestDatabase() |
|
|
|
ctx := context.Background() |
|
|
|
// Create some Author nodes (legacy format) |
|
authorPubkeys := []string{ |
|
"0000000000000000000000000000000000000000000000000000000000000001", |
|
"0000000000000000000000000000000000000000000000000000000000000002", |
|
} |
|
|
|
for _, pk := range authorPubkeys { |
|
cypher := `CREATE (a:Author {pubkey: $pubkey})` |
|
_, err := testDB.ExecuteWrite(ctx, cypher, map[string]any{"pubkey": pk}) |
|
if err != nil { |
|
t.Fatalf("Failed to create Author node: %v", err) |
|
} |
|
} |
|
|
|
// Verify Author nodes exist |
|
authorCount := countNodes(t, "Author") |
|
if authorCount != 2 { |
|
t.Errorf("Expected 2 Author nodes, got %d", authorCount) |
|
} |
|
|
|
// Run migration |
|
err := migrateAuthorToNostrUser(ctx, testDB) |
|
if err != nil { |
|
t.Fatalf("Migration failed: %v", err) |
|
} |
|
|
|
// Verify NostrUser nodes were created |
|
nostrUserCount := countNodes(t, "NostrUser") |
|
if nostrUserCount != 2 { |
|
t.Errorf("Expected 2 NostrUser nodes after migration, got %d", nostrUserCount) |
|
} |
|
|
|
// Verify Author nodes were deleted (they should have no relationships after migration) |
|
authorCountAfter := countNodes(t, "Author") |
|
if authorCountAfter != 0 { |
|
t.Errorf("Expected 0 Author nodes after migration, got %d", authorCountAfter) |
|
} |
|
}
|
|
|