package database import ( "context" "testing" "github.com/dgraph-io/badger/v4" "next.orly.dev/pkg/database/indexes" "next.orly.dev/pkg/database/indexes/types" "git.mleku.dev/mleku/nostr/encoders/event" "git.mleku.dev/mleku/nostr/encoders/hex" "git.mleku.dev/mleku/nostr/encoders/tag" ) func TestPubkeySerialAssignment(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() db, err := New(ctx, cancel, t.TempDir(), "info") if err != nil { t.Fatalf("Failed to create database: %v", err) } defer db.Close() // Create a test pubkey pubkey1 := make([]byte, 32) for i := range pubkey1 { pubkey1[i] = byte(i) } // Get or create serial for the first time t.Logf("First call: GetOrCreatePubkeySerial for pubkey %s", hex.Enc(pubkey1)) ser1, err := db.GetOrCreatePubkeySerial(pubkey1) if err != nil { t.Fatalf("Failed to get or create pubkey serial: %v", err) } if ser1 == nil { t.Fatal("Serial should not be nil") } t.Logf("First call returned serial: %d", ser1.Get()) // Debug: List all keys in database var keyCount int db.View(func(txn *badger.Txn) error { it := txn.NewIterator(badger.DefaultIteratorOptions) defer it.Close() for it.Rewind(); it.Valid(); it.Next() { key := it.Item().KeyCopy(nil) t.Logf("Found key: %s (len=%d)", hex.Enc(key), len(key)) keyCount++ if keyCount > 20 { break // Limit output } } return nil }) t.Logf("Total keys found (first 20): %d", keyCount) // Debug: what prefix should we be looking for? pubHash := new(types.PubHash) pubHash.FromPubkey(pubkey1) expectedPrefix := []byte(indexes.PubkeySerialPrefix) t.Logf("Expected PubkeySerial prefix: %s = %s", string(expectedPrefix), hex.Enc(expectedPrefix)) // Try direct lookup t.Logf("Direct lookup: GetPubkeySerial for same pubkey") serDirect, err := db.GetPubkeySerial(pubkey1) if err != nil { t.Logf("Direct lookup failed: %v", err) } else { t.Logf("Direct lookup returned serial: %d", serDirect.Get()) } // Get the same pubkey again - should return the same serial t.Logf("Second call: GetOrCreatePubkeySerial for same pubkey") ser2, err := db.GetOrCreatePubkeySerial(pubkey1) if err != nil { t.Fatalf("Failed to get existing pubkey serial: %v", err) } t.Logf("Second call returned serial: %d", ser2.Get()) if ser1.Get() != ser2.Get() { t.Errorf("Expected same serial, got %d and %d", ser1.Get(), ser2.Get()) } // Create a different pubkey pubkey2 := make([]byte, 32) for i := range pubkey2 { pubkey2[i] = byte(i + 100) } ser3, err := db.GetOrCreatePubkeySerial(pubkey2) if err != nil { t.Fatalf("Failed to get or create second pubkey serial: %v", err) } if ser3.Get() == ser1.Get() { t.Error("Different pubkeys should have different serials") } // Test reverse lookup: serial -> pubkey retrievedPubkey1, err := db.GetPubkeyBySerial(ser1) if err != nil { t.Fatalf("Failed to get pubkey by serial: %v", err) } if hex.Enc(retrievedPubkey1) != hex.Enc(pubkey1) { t.Errorf("Retrieved pubkey doesn't match. Expected %s, got %s", hex.Enc(pubkey1), hex.Enc(retrievedPubkey1)) } } func TestEventPubkeyGraph(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() db, err := New(ctx, cancel, t.TempDir(), "info") if err != nil { t.Fatalf("Failed to create database: %v", err) } defer db.Close() // Create test event with author and p-tags authorPubkey, _ := hex.Dec("0000000000000000000000000000000000000000000000000000000000000001") pTagPubkey1, _ := hex.Dec("0000000000000000000000000000000000000000000000000000000000000002") pTagPubkey2, _ := hex.Dec("0000000000000000000000000000000000000000000000000000000000000003") eventID := make([]byte, 32) eventID[0] = 1 eventSig := make([]byte, 64) eventSig[0] = 1 ev := &event.E{ ID: eventID, Pubkey: authorPubkey, CreatedAt: 1234567890, Kind: 1, // text note Content: []byte("Test event with p-tags"), Sig: eventSig, Tags: tag.NewS( tag.NewFromAny("p", hex.Enc(pTagPubkey1)), tag.NewFromAny("p", hex.Enc(pTagPubkey2)), tag.NewFromAny("e", "someeventid"), ), } // Save the event - this should create pubkey serials and graph edges _, err = db.SaveEvent(ctx, ev) if err != nil { t.Fatalf("Failed to save event: %v", err) } // Verify that pubkey serials were created authorSerial, err := db.GetPubkeySerial(authorPubkey) if err != nil { t.Fatalf("Failed to get author pubkey serial: %v", err) } if authorSerial == nil { t.Fatal("Author serial should not be nil") } pTag1Serial, err := db.GetPubkeySerial(pTagPubkey1) if err != nil { t.Fatalf("Failed to get p-tag1 pubkey serial: %v", err) } if pTag1Serial == nil { t.Fatal("P-tag1 serial should not be nil") } pTag2Serial, err := db.GetPubkeySerial(pTagPubkey2) if err != nil { t.Fatalf("Failed to get p-tag2 pubkey serial: %v", err) } if pTag2Serial == nil { t.Fatal("P-tag2 serial should not be nil") } // Verify all three pubkeys have different serials if authorSerial.Get() == pTag1Serial.Get() || authorSerial.Get() == pTag2Serial.Get() || pTag1Serial.Get() == pTag2Serial.Get() { t.Error("All pubkey serials should be unique") } t.Logf("Event saved successfully with graph edges:") t.Logf(" Author serial: %d", authorSerial.Get()) t.Logf(" P-tag1 serial: %d", pTag1Serial.Get()) t.Logf(" P-tag2 serial: %d", pTag2Serial.Get()) } func TestMultipleEventsWithSamePubkeys(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() db, err := New(ctx, cancel, t.TempDir(), "info") if err != nil { t.Fatalf("Failed to create database: %v", err) } defer db.Close() // Create two events from the same author mentioning the same person authorPubkey, _ := hex.Dec("0000000000000000000000000000000000000000000000000000000000000001") pTagPubkey, _ := hex.Dec("0000000000000000000000000000000000000000000000000000000000000002") eventID1 := make([]byte, 32) eventID1[0] = 1 eventSig1 := make([]byte, 64) eventSig1[0] = 1 ev1 := &event.E{ ID: eventID1, Pubkey: authorPubkey, CreatedAt: 1234567890, Kind: 1, Content: []byte("First event"), Sig: eventSig1, Tags: tag.NewS( tag.NewFromAny("p", hex.Enc(pTagPubkey)), ), } eventID2 := make([]byte, 32) eventID2[0] = 2 eventSig2 := make([]byte, 64) eventSig2[0] = 2 ev2 := &event.E{ ID: eventID2, Pubkey: authorPubkey, CreatedAt: 1234567891, Kind: 1, Content: []byte("Second event"), Sig: eventSig2, Tags: tag.NewS( tag.NewFromAny("p", hex.Enc(pTagPubkey)), ), } // Save both events _, err = db.SaveEvent(ctx, ev1) if err != nil { t.Fatalf("Failed to save event 1: %v", err) } _, err = db.SaveEvent(ctx, ev2) if err != nil { t.Fatalf("Failed to save event 2: %v", err) } // Verify the same pubkeys got the same serials authorSerial1, _ := db.GetPubkeySerial(authorPubkey) pTagSerial1, _ := db.GetPubkeySerial(pTagPubkey) if authorSerial1 == nil || pTagSerial1 == nil { t.Fatal("Pubkey serials should exist after saving events") } t.Logf("Both events share the same pubkey serials:") t.Logf(" Author serial: %d", authorSerial1.Get()) t.Logf(" P-tag serial: %d", pTagSerial1.Get()) } func TestPubkeySerialEdgeCases(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() db, err := New(ctx, cancel, t.TempDir(), "info") if err != nil { t.Fatalf("Failed to create database: %v", err) } defer db.Close() // Test with invalid pubkey length invalidPubkey := make([]byte, 16) // Wrong length _, err = db.GetOrCreatePubkeySerial(invalidPubkey) if err == nil { t.Error("Should reject pubkey with invalid length") } // Test GetPubkeySerial for non-existent pubkey nonExistentPubkey := make([]byte, 32) for i := range nonExistentPubkey { nonExistentPubkey[i] = 0xFF } _, err = db.GetPubkeySerial(nonExistentPubkey) if err == nil { t.Error("Should return error for non-existent pubkey serial") } } func TestGraphEdgeDirections(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) defer cancel() db, err := New(ctx, cancel, t.TempDir(), "info") if err != nil { t.Fatalf("Failed to create database: %v", err) } defer db.Close() // Create test event with author and p-tags authorPubkey, _ := hex.Dec("0000000000000000000000000000000000000000000000000000000000000001") pTagPubkey, _ := hex.Dec("0000000000000000000000000000000000000000000000000000000000000002") eventID := make([]byte, 32) eventID[0] = 1 eventSig := make([]byte, 64) eventSig[0] = 1 ev := &event.E{ ID: eventID, Pubkey: authorPubkey, CreatedAt: 1234567890, Kind: 1, // text note Content: []byte("Test event"), Sig: eventSig, Tags: tag.NewS( tag.NewFromAny("p", hex.Enc(pTagPubkey)), ), } // Save the event _, err = db.SaveEvent(ctx, ev) if err != nil { t.Fatalf("Failed to save event: %v", err) } // Verify graph edges with correct direction bytes // Look for PubkeyEventGraph keys and check direction byte var foundAuthorEdge, foundPTagEdge bool db.View(func(txn *badger.Txn) error { it := txn.NewIterator(badger.DefaultIteratorOptions) defer it.Close() prefix := []byte(indexes.PubkeyEventGraphPrefix) for it.Seek(prefix); it.ValidForPrefix(prefix); it.Next() { key := it.Item().KeyCopy(nil) // Key format: peg(3)|pubkey_serial(5)|kind(2)|direction(1)|event_serial(5) = 16 bytes if len(key) == 16 { direction := key[10] // Byte at position 10 is the direction t.Logf("Found PubkeyEventGraph edge: key=%s, direction=%d", hex.Enc(key), direction) if direction == types.EdgeDirectionAuthor { foundAuthorEdge = true t.Logf(" ✓ Found author edge (direction=0)") } else if direction == types.EdgeDirectionPTagIn { foundPTagEdge = true t.Logf(" ✓ Found p-tag inbound edge (direction=2)") } } } return nil }) if !foundAuthorEdge { t.Error("Did not find author edge with direction=0") } if !foundPTagEdge { t.Error("Did not find p-tag inbound edge with direction=2") } t.Logf("Graph edges correctly stored with direction bytes:") t.Logf(" Author edge: %v (direction=0)", foundAuthorEdge) t.Logf(" P-tag inbound edge: %v (direction=2)", foundPTagEdge) }