wasmdb_test.go raw

   1  //go:build js && wasm
   2  
   3  package wasmdb
   4  
   5  import (
   6  	"bytes"
   7  	"context"
   8  	"testing"
   9  	"time"
  10  
  11  	"next.orly.dev/pkg/nostr/encoders/event"
  12  	"next.orly.dev/pkg/nostr/encoders/filter"
  13  	"next.orly.dev/pkg/nostr/encoders/kind"
  14  	"next.orly.dev/pkg/nostr/encoders/tag"
  15  	"next.orly.dev/pkg/database/indexes/types"
  16  )
  17  
  18  // TestDatabaseOpen tests that we can open an IndexedDB database
  19  func TestDatabaseOpen(t *testing.T) {
  20  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  21  	defer cancel()
  22  
  23  	// Create a new database instance
  24  	db, err := New(ctx, cancel, "/tmp/test", "info")
  25  	if err != nil {
  26  		t.Fatalf("Failed to create database: %v", err)
  27  	}
  28  	defer db.Close()
  29  
  30  	// Wait for the database to be ready
  31  	select {
  32  	case <-db.Ready():
  33  		t.Log("Database ready")
  34  	case <-ctx.Done():
  35  		t.Fatal("Timeout waiting for database to be ready")
  36  	}
  37  
  38  	t.Log("Database opened successfully")
  39  }
  40  
  41  // TestDatabaseMetaStorage tests storing and retrieving metadata
  42  func TestDatabaseMetaStorage(t *testing.T) {
  43  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  44  	defer cancel()
  45  
  46  	db, err := New(ctx, cancel, "/tmp/test", "info")
  47  	if err != nil {
  48  		t.Fatalf("Failed to create database: %v", err)
  49  	}
  50  	defer db.Close()
  51  
  52  	<-db.Ready()
  53  
  54  	// Test SetMarker and GetMarker
  55  	testKey := "test_key"
  56  	testValue := []byte("test_value_12345")
  57  
  58  	err = db.SetMarker(testKey, testValue)
  59  	if err != nil {
  60  		t.Fatalf("Failed to set marker: %v", err)
  61  	}
  62  
  63  	retrieved, err := db.GetMarker(testKey)
  64  	if err != nil {
  65  		t.Fatalf("Failed to get marker: %v", err)
  66  	}
  67  
  68  	if string(retrieved) != string(testValue) {
  69  		t.Errorf("Retrieved value %q doesn't match expected %q", retrieved, testValue)
  70  	}
  71  
  72  	// Test HasMarker
  73  	if !db.HasMarker(testKey) {
  74  		t.Error("HasMarker returned false for existing key")
  75  	}
  76  
  77  	if db.HasMarker("nonexistent_key") {
  78  		t.Error("HasMarker returned true for nonexistent key")
  79  	}
  80  
  81  	// Test DeleteMarker
  82  	err = db.DeleteMarker(testKey)
  83  	if err != nil {
  84  		t.Fatalf("Failed to delete marker: %v", err)
  85  	}
  86  
  87  	if db.HasMarker(testKey) {
  88  		t.Error("HasMarker returned true after deletion")
  89  	}
  90  }
  91  
  92  // TestDatabaseSerialCounters tests the serial number generation
  93  func TestDatabaseSerialCounters(t *testing.T) {
  94  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
  95  	defer cancel()
  96  
  97  	db, err := New(ctx, cancel, "/tmp/test", "info")
  98  	if err != nil {
  99  		t.Fatalf("Failed to create database: %v", err)
 100  	}
 101  	defer db.Close()
 102  
 103  	<-db.Ready()
 104  
 105  	// Generate some serials and verify they're incrementing
 106  	serial1, err := db.nextEventSerial()
 107  	if err != nil {
 108  		t.Fatalf("Failed to get first serial: %v", err)
 109  	}
 110  
 111  	serial2, err := db.nextEventSerial()
 112  	if err != nil {
 113  		t.Fatalf("Failed to get second serial: %v", err)
 114  	}
 115  
 116  	if serial2 != serial1+1 {
 117  		t.Errorf("Serials not incrementing: got %d and %d", serial1, serial2)
 118  	}
 119  
 120  	t.Logf("Generated serials: %d, %d", serial1, serial2)
 121  }
 122  
 123  // TestDatabaseRelayIdentity tests relay identity key management
 124  func TestDatabaseRelayIdentity(t *testing.T) {
 125  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 126  	defer cancel()
 127  
 128  	db, err := New(ctx, cancel, "/tmp/test", "info")
 129  	if err != nil {
 130  		t.Fatalf("Failed to create database: %v", err)
 131  	}
 132  	defer db.Close()
 133  
 134  	<-db.Ready()
 135  
 136  	// First call should create a new identity
 137  	skb, err := db.GetOrCreateRelayIdentitySecret()
 138  	if err != nil {
 139  		t.Fatalf("Failed to get/create relay identity: %v", err)
 140  	}
 141  
 142  	if len(skb) != 32 {
 143  		t.Errorf("Expected 32-byte secret key, got %d bytes", len(skb))
 144  	}
 145  
 146  	// Second call should return the same key
 147  	skb2, err := db.GetOrCreateRelayIdentitySecret()
 148  	if err != nil {
 149  		t.Fatalf("Failed to get relay identity second time: %v", err)
 150  	}
 151  
 152  	if string(skb) != string(skb2) {
 153  		t.Error("GetOrCreateRelayIdentitySecret returned different keys on second call")
 154  	}
 155  
 156  	t.Logf("Relay identity key: %x", skb[:8])
 157  }
 158  
 159  // TestDatabaseWipe tests the wipe functionality
 160  func TestDatabaseWipe(t *testing.T) {
 161  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 162  	defer cancel()
 163  
 164  	db, err := New(ctx, cancel, "/tmp/test", "info")
 165  	if err != nil {
 166  		t.Fatalf("Failed to create database: %v", err)
 167  	}
 168  	defer db.Close()
 169  
 170  	<-db.Ready()
 171  
 172  	// Store some data
 173  	err = db.SetMarker("wipe_test_key", []byte("wipe_test_value"))
 174  	if err != nil {
 175  		t.Fatalf("Failed to set marker: %v", err)
 176  	}
 177  
 178  	// Wipe the database
 179  	err = db.Wipe()
 180  	if err != nil {
 181  		t.Fatalf("Failed to wipe database: %v", err)
 182  	}
 183  
 184  	// Verify data is gone
 185  	if db.HasMarker("wipe_test_key") {
 186  		t.Error("Marker still exists after wipe")
 187  	}
 188  
 189  	t.Log("Database wipe successful")
 190  }
 191  
 192  // createTestEvent creates a test event with fake ID and signature (for storage testing only)
 193  func createTestEvent(kind uint16, content string, pubkey []byte) *event.E {
 194  	ev := event.New()
 195  	ev.Kind = kind
 196  	ev.Content = []byte(content)
 197  	ev.CreatedAt = time.Now().Unix()
 198  	ev.Tags = tag.NewS()
 199  
 200  	// Use provided pubkey or generate a fake one
 201  	if len(pubkey) == 32 {
 202  		ev.Pubkey = pubkey
 203  	} else {
 204  		ev.Pubkey = make([]byte, 32)
 205  		for i := range ev.Pubkey {
 206  			ev.Pubkey[i] = byte(i)
 207  		}
 208  	}
 209  
 210  	// Generate a fake ID (normally would be SHA256 of serialized event)
 211  	ev.ID = make([]byte, 32)
 212  	for i := range ev.ID {
 213  		ev.ID[i] = byte(i + 100)
 214  	}
 215  
 216  	// Generate a fake signature (won't verify, but storage doesn't need to verify)
 217  	ev.Sig = make([]byte, 64)
 218  	for i := range ev.Sig {
 219  		ev.Sig[i] = byte(i + 200)
 220  	}
 221  
 222  	return ev
 223  }
 224  
 225  // TestSaveAndFetchEvent tests saving and fetching events
 226  func TestSaveAndFetchEvent(t *testing.T) {
 227  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 228  	defer cancel()
 229  
 230  	// Wipe the database to start fresh
 231  	db, err := New(ctx, cancel, "/tmp/test", "debug")
 232  	if err != nil {
 233  		t.Fatalf("Failed to create database: %v", err)
 234  	}
 235  	defer db.Close()
 236  
 237  	<-db.Ready()
 238  
 239  	// Wipe to ensure clean state
 240  	if err := db.Wipe(); err != nil {
 241  		t.Fatalf("Failed to wipe database: %v", err)
 242  	}
 243  
 244  	// Create a test event
 245  	ev := createTestEvent(1, "Hello, Nostr!", nil)
 246  	t.Logf("Created event with ID: %x", ev.ID[:8])
 247  
 248  	// Save the event
 249  	replaced, err := db.SaveEvent(ctx, ev)
 250  	if err != nil {
 251  		t.Fatalf("Failed to save event: %v", err)
 252  	}
 253  	if replaced {
 254  		t.Error("Expected replaced to be false for new event")
 255  	}
 256  
 257  	t.Log("Event saved successfully")
 258  
 259  	// Look up the serial by ID
 260  	ser, err := db.GetSerialById(ev.ID)
 261  	if err != nil {
 262  		t.Fatalf("Failed to get serial by ID: %v", err)
 263  	}
 264  	if ser == nil {
 265  		t.Fatal("Got nil serial")
 266  	}
 267  	t.Logf("Event serial: %d", ser.Get())
 268  
 269  	// Fetch the event by serial
 270  	fetchedEv, err := db.FetchEventBySerial(ser)
 271  	if err != nil {
 272  		t.Fatalf("Failed to fetch event by serial: %v", err)
 273  	}
 274  	if fetchedEv == nil {
 275  		t.Fatal("Fetched event is nil")
 276  	}
 277  
 278  	// Verify the event content matches
 279  	if !bytes.Equal(fetchedEv.ID, ev.ID) {
 280  		t.Errorf("Event ID mismatch: got %x, want %x", fetchedEv.ID[:8], ev.ID[:8])
 281  	}
 282  	if !bytes.Equal(fetchedEv.Content, ev.Content) {
 283  		t.Errorf("Event content mismatch: got %q, want %q", fetchedEv.Content, ev.Content)
 284  	}
 285  	if fetchedEv.Kind != ev.Kind {
 286  		t.Errorf("Event kind mismatch: got %d, want %d", fetchedEv.Kind, ev.Kind)
 287  	}
 288  
 289  	t.Log("Event fetched and verified successfully")
 290  }
 291  
 292  // TestSaveEventDuplicate tests that saving a duplicate event returns an error
 293  func TestSaveEventDuplicate(t *testing.T) {
 294  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 295  	defer cancel()
 296  
 297  	db, err := New(ctx, cancel, "/tmp/test", "info")
 298  	if err != nil {
 299  		t.Fatalf("Failed to create database: %v", err)
 300  	}
 301  	defer db.Close()
 302  
 303  	<-db.Ready()
 304  
 305  	// Wipe to ensure clean state
 306  	if err := db.Wipe(); err != nil {
 307  		t.Fatalf("Failed to wipe database: %v", err)
 308  	}
 309  
 310  	// Create and save a test event
 311  	ev := createTestEvent(1, "Duplicate test", nil)
 312  
 313  	_, err = db.SaveEvent(ctx, ev)
 314  	if err != nil {
 315  		t.Fatalf("Failed to save first event: %v", err)
 316  	}
 317  
 318  	// Try to save the same event again
 319  	_, err = db.SaveEvent(ctx, ev)
 320  	if err == nil {
 321  		t.Error("Expected error when saving duplicate event, got nil")
 322  	} else {
 323  		t.Logf("Got expected error for duplicate: %v", err)
 324  	}
 325  }
 326  
 327  // TestSaveEventWithTags tests saving an event with tags
 328  func TestSaveEventWithTags(t *testing.T) {
 329  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 330  	defer cancel()
 331  
 332  	db, err := New(ctx, cancel, "/tmp/test", "info")
 333  	if err != nil {
 334  		t.Fatalf("Failed to create database: %v", err)
 335  	}
 336  	defer db.Close()
 337  
 338  	<-db.Ready()
 339  
 340  	// Wipe to ensure clean state
 341  	if err := db.Wipe(); err != nil {
 342  		t.Fatalf("Failed to wipe database: %v", err)
 343  	}
 344  
 345  	// Create an event with tags
 346  	ev := createTestEvent(1, "Event with tags", nil)
 347  
 348  	// Make the ID unique
 349  	ev.ID[0] = 0x42
 350  
 351  	// Add some tags
 352  	ev.Tags = tag.NewS(
 353  		tag.NewFromAny("t", "nostr"),
 354  		tag.NewFromAny("t", "test"),
 355  	)
 356  
 357  	// Save the event
 358  	_, err = db.SaveEvent(ctx, ev)
 359  	if err != nil {
 360  		t.Fatalf("Failed to save event with tags: %v", err)
 361  	}
 362  
 363  	// Fetch it back
 364  	ser, err := db.GetSerialById(ev.ID)
 365  	if err != nil {
 366  		t.Fatalf("Failed to get serial: %v", err)
 367  	}
 368  
 369  	fetchedEv, err := db.FetchEventBySerial(ser)
 370  	if err != nil {
 371  		t.Fatalf("Failed to fetch event: %v", err)
 372  	}
 373  
 374  	// Verify tags
 375  	if fetchedEv.Tags == nil || fetchedEv.Tags.Len() != 2 {
 376  		t.Errorf("Expected 2 tags, got %v", fetchedEv.Tags)
 377  	}
 378  
 379  	t.Log("Event with tags saved and fetched successfully")
 380  }
 381  
 382  // TestFetchEventsBySerials tests batch fetching of events
 383  func TestFetchEventsBySerials(t *testing.T) {
 384  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 385  	defer cancel()
 386  
 387  	db, err := New(ctx, cancel, "/tmp/test", "info")
 388  	if err != nil {
 389  		t.Fatalf("Failed to create database: %v", err)
 390  	}
 391  	defer db.Close()
 392  
 393  	<-db.Ready()
 394  
 395  	// Wipe to ensure clean state
 396  	if err := db.Wipe(); err != nil {
 397  		t.Fatalf("Failed to wipe database: %v", err)
 398  	}
 399  
 400  	// Create and save multiple events
 401  	var serials []*types.Uint40
 402  	for i := 0; i < 3; i++ {
 403  		ev := createTestEvent(1, "Batch test event", nil)
 404  		ev.ID[0] = byte(0x50 + i) // Make IDs unique
 405  
 406  		_, err := db.SaveEvent(ctx, ev)
 407  		if err != nil {
 408  			t.Fatalf("Failed to save event %d: %v", i, err)
 409  		}
 410  
 411  		ser, err := db.GetSerialById(ev.ID)
 412  		if err != nil {
 413  			t.Fatalf("Failed to get serial for event %d: %v", i, err)
 414  		}
 415  		serials = append(serials, ser)
 416  	}
 417  
 418  	// Batch fetch
 419  	events, err := db.FetchEventsBySerials(serials)
 420  	if err != nil {
 421  		t.Fatalf("Failed to batch fetch events: %v", err)
 422  	}
 423  
 424  	if len(events) != 3 {
 425  		t.Errorf("Expected 3 events, got %d", len(events))
 426  	}
 427  
 428  	t.Logf("Successfully batch fetched %d events", len(events))
 429  }
 430  
 431  // TestGetFullIdPubkeyBySerial tests getting event metadata by serial
 432  func TestGetFullIdPubkeyBySerial(t *testing.T) {
 433  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 434  	defer cancel()
 435  
 436  	db, err := New(ctx, cancel, "/tmp/test", "debug")
 437  	if err != nil {
 438  		t.Fatalf("Failed to create database: %v", err)
 439  	}
 440  	defer db.Close()
 441  
 442  	<-db.Ready()
 443  
 444  	// Wipe to ensure clean state
 445  	if err := db.Wipe(); err != nil {
 446  		t.Fatalf("Failed to wipe database: %v", err)
 447  	}
 448  
 449  	// Create and save an event
 450  	ev := createTestEvent(1, "Metadata test", nil)
 451  	ev.ID[0] = 0x99 // Make ID unique
 452  
 453  	_, err = db.SaveEvent(ctx, ev)
 454  	if err != nil {
 455  		t.Fatalf("Failed to save event: %v", err)
 456  	}
 457  
 458  	ser, err := db.GetSerialById(ev.ID)
 459  	if err != nil {
 460  		t.Fatalf("Failed to get serial: %v", err)
 461  	}
 462  
 463  	// Get full ID/pubkey/timestamp metadata
 464  	fidpk, err := db.GetFullIdPubkeyBySerial(ser)
 465  	if err != nil {
 466  		t.Fatalf("Failed to get full id pubkey: %v", err)
 467  	}
 468  	if fidpk == nil {
 469  		t.Fatal("Got nil fidpk")
 470  	}
 471  
 472  	// Verify the ID matches
 473  	if !bytes.Equal(fidpk.Id, ev.ID) {
 474  		t.Errorf("ID mismatch: got %x, want %x", fidpk.Id[:8], ev.ID[:8])
 475  	}
 476  
 477  	t.Logf("Got metadata: ID=%x, Pub=%x, Ts=%d, Ser=%d",
 478  		fidpk.Id[:8], fidpk.Pub[:4], fidpk.Ts, fidpk.Ser)
 479  }
 480  
 481  // TestQueryEventsByKind tests querying events by kind
 482  func TestQueryEventsByKind(t *testing.T) {
 483  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 484  	defer cancel()
 485  
 486  	db, err := New(ctx, cancel, "/tmp/test", "info")
 487  	if err != nil {
 488  		t.Fatalf("Failed to create database: %v", err)
 489  	}
 490  	defer db.Close()
 491  
 492  	<-db.Ready()
 493  
 494  	// Wipe to ensure clean state
 495  	if err := db.Wipe(); err != nil {
 496  		t.Fatalf("Failed to wipe database: %v", err)
 497  	}
 498  
 499  	// Create events of different kinds
 500  	ev1 := createTestEvent(1, "Kind 1 event", nil)
 501  	ev1.ID[0] = 0xA1
 502  	ev2 := createTestEvent(1, "Another kind 1", nil)
 503  	ev2.ID[0] = 0xA2
 504  	ev3 := createTestEvent(7, "Kind 7 event", nil)
 505  	ev3.ID[0] = 0xA3
 506  
 507  	// Save events
 508  	for _, ev := range []*event.E{ev1, ev2, ev3} {
 509  		if _, err := db.SaveEvent(ctx, ev); err != nil {
 510  			t.Fatalf("Failed to save event: %v", err)
 511  		}
 512  	}
 513  
 514  	// Query for kind 1
 515  	f := &filter.F{
 516  		Kinds: kind.NewS(kind.New(1)),
 517  	}
 518  
 519  	evs, err := db.QueryEvents(ctx, f)
 520  	if err != nil {
 521  		t.Fatalf("Failed to query events: %v", err)
 522  	}
 523  
 524  	if len(evs) != 2 {
 525  		t.Errorf("Expected 2 events of kind 1, got %d", len(evs))
 526  	}
 527  
 528  	t.Logf("Query by kind 1 returned %d events", len(evs))
 529  }
 530  
 531  // TestQueryEventsByAuthor tests querying events by author pubkey
 532  func TestQueryEventsByAuthor(t *testing.T) {
 533  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 534  	defer cancel()
 535  
 536  	db, err := New(ctx, cancel, "/tmp/test", "info")
 537  	if err != nil {
 538  		t.Fatalf("Failed to create database: %v", err)
 539  	}
 540  	defer db.Close()
 541  
 542  	<-db.Ready()
 543  
 544  	// Wipe to ensure clean state
 545  	if err := db.Wipe(); err != nil {
 546  		t.Fatalf("Failed to wipe database: %v", err)
 547  	}
 548  
 549  	// Create events from different authors
 550  	author1 := make([]byte, 32)
 551  	for i := range author1 {
 552  		author1[i] = 0x11
 553  	}
 554  	author2 := make([]byte, 32)
 555  	for i := range author2 {
 556  		author2[i] = 0x22
 557  	}
 558  
 559  	ev1 := createTestEvent(1, "From author 1", author1)
 560  	ev1.ID[0] = 0xB1
 561  	ev2 := createTestEvent(1, "Also from author 1", author1)
 562  	ev2.ID[0] = 0xB2
 563  	ev3 := createTestEvent(1, "From author 2", author2)
 564  	ev3.ID[0] = 0xB3
 565  
 566  	// Save events
 567  	for _, ev := range []*event.E{ev1, ev2, ev3} {
 568  		if _, err := db.SaveEvent(ctx, ev); err != nil {
 569  			t.Fatalf("Failed to save event: %v", err)
 570  		}
 571  	}
 572  
 573  	// Query for author1
 574  	f := &filter.F{
 575  		Authors: tag.NewFromBytesSlice(author1),
 576  	}
 577  
 578  	evs, err := db.QueryEvents(ctx, f)
 579  	if err != nil {
 580  		t.Fatalf("Failed to query events: %v", err)
 581  	}
 582  
 583  	if len(evs) != 2 {
 584  		t.Errorf("Expected 2 events from author1, got %d", len(evs))
 585  	}
 586  
 587  	t.Logf("Query by author returned %d events", len(evs))
 588  }
 589  
 590  // TestCountEvents tests the event counting functionality
 591  func TestCountEvents(t *testing.T) {
 592  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 593  	defer cancel()
 594  
 595  	db, err := New(ctx, cancel, "/tmp/test", "info")
 596  	if err != nil {
 597  		t.Fatalf("Failed to create database: %v", err)
 598  	}
 599  	defer db.Close()
 600  
 601  	<-db.Ready()
 602  
 603  	// Wipe to ensure clean state
 604  	if err := db.Wipe(); err != nil {
 605  		t.Fatalf("Failed to wipe database: %v", err)
 606  	}
 607  
 608  	// Create multiple events
 609  	for i := 0; i < 5; i++ {
 610  		ev := createTestEvent(1, "Count test event", nil)
 611  		ev.ID[0] = byte(0xC0 + i)
 612  		if _, err := db.SaveEvent(ctx, ev); err != nil {
 613  			t.Fatalf("Failed to save event: %v", err)
 614  		}
 615  	}
 616  
 617  	// Count all kind 1 events
 618  	f := &filter.F{
 619  		Kinds: kind.NewS(kind.New(1)),
 620  	}
 621  
 622  	count, approx, err := db.CountEvents(ctx, f)
 623  	if err != nil {
 624  		t.Fatalf("Failed to count events: %v", err)
 625  	}
 626  
 627  	if count != 5 {
 628  		t.Errorf("Expected count of 5, got %d", count)
 629  	}
 630  	if approx {
 631  		t.Log("Count is approximate")
 632  	}
 633  
 634  	t.Logf("CountEvents returned %d", count)
 635  }
 636  
 637  // TestQueryEventsWithLimit tests applying a limit to query results
 638  func TestQueryEventsWithLimit(t *testing.T) {
 639  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 640  	defer cancel()
 641  
 642  	db, err := New(ctx, cancel, "/tmp/test", "info")
 643  	if err != nil {
 644  		t.Fatalf("Failed to create database: %v", err)
 645  	}
 646  	defer db.Close()
 647  
 648  	<-db.Ready()
 649  
 650  	// Wipe to ensure clean state
 651  	if err := db.Wipe(); err != nil {
 652  		t.Fatalf("Failed to wipe database: %v", err)
 653  	}
 654  
 655  	// Create 10 events
 656  	for i := 0; i < 10; i++ {
 657  		ev := createTestEvent(1, "Limit test event", nil)
 658  		ev.ID[0] = byte(0xD0 + i)
 659  		if _, err := db.SaveEvent(ctx, ev); err != nil {
 660  			t.Fatalf("Failed to save event: %v", err)
 661  		}
 662  	}
 663  
 664  	// Query with limit of 3
 665  	limit := uint(3)
 666  	f := &filter.F{
 667  		Kinds: kind.NewS(kind.New(1)),
 668  		Limit: &limit,
 669  	}
 670  
 671  	evs, err := db.QueryEvents(ctx, f)
 672  	if err != nil {
 673  		t.Fatalf("Failed to query events: %v", err)
 674  	}
 675  
 676  	if len(evs) != 3 {
 677  		t.Errorf("Expected 3 events with limit, got %d", len(evs))
 678  	}
 679  
 680  	t.Logf("Query with limit returned %d events", len(evs))
 681  }
 682  
 683  // TestQueryEventsByTag tests querying events by tag
 684  func TestQueryEventsByTag(t *testing.T) {
 685  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 686  	defer cancel()
 687  
 688  	db, err := New(ctx, cancel, "/tmp/test", "info")
 689  	if err != nil {
 690  		t.Fatalf("Failed to create database: %v", err)
 691  	}
 692  	defer db.Close()
 693  
 694  	<-db.Ready()
 695  
 696  	// Wipe to ensure clean state
 697  	if err := db.Wipe(); err != nil {
 698  		t.Fatalf("Failed to wipe database: %v", err)
 699  	}
 700  
 701  	// Create events with different tags
 702  	ev1 := createTestEvent(1, "Has bitcoin tag", nil)
 703  	ev1.ID[0] = 0xE1
 704  	ev1.Tags = tag.NewS(
 705  		tag.NewFromAny("t", "bitcoin"),
 706  	)
 707  
 708  	ev2 := createTestEvent(1, "Has nostr tag", nil)
 709  	ev2.ID[0] = 0xE2
 710  	ev2.Tags = tag.NewS(
 711  		tag.NewFromAny("t", "nostr"),
 712  	)
 713  
 714  	ev3 := createTestEvent(1, "Has bitcoin and nostr tags", nil)
 715  	ev3.ID[0] = 0xE3
 716  	ev3.Tags = tag.NewS(
 717  		tag.NewFromAny("t", "bitcoin"),
 718  		tag.NewFromAny("t", "nostr"),
 719  	)
 720  
 721  	// Save events
 722  	for _, ev := range []*event.E{ev1, ev2, ev3} {
 723  		if _, err := db.SaveEvent(ctx, ev); err != nil {
 724  			t.Fatalf("Failed to save event: %v", err)
 725  		}
 726  	}
 727  
 728  	// Query for bitcoin tag
 729  	f := &filter.F{
 730  		Tags: tag.NewS(
 731  			tag.NewFromAny("#t", "bitcoin"),
 732  		),
 733  	}
 734  
 735  	evs, err := db.QueryEvents(ctx, f)
 736  	if err != nil {
 737  		t.Fatalf("Failed to query events: %v", err)
 738  	}
 739  
 740  	if len(evs) != 2 {
 741  		t.Errorf("Expected 2 events with bitcoin tag, got %d", len(evs))
 742  	}
 743  
 744  	t.Logf("Query by tag returned %d events", len(evs))
 745  }
 746  
 747  // TestQueryForSerials tests the QueryForSerials method
 748  func TestQueryForSerials(t *testing.T) {
 749  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 750  	defer cancel()
 751  
 752  	db, err := New(ctx, cancel, "/tmp/test", "info")
 753  	if err != nil {
 754  		t.Fatalf("Failed to create database: %v", err)
 755  	}
 756  	defer db.Close()
 757  
 758  	<-db.Ready()
 759  
 760  	// Wipe to ensure clean state
 761  	if err := db.Wipe(); err != nil {
 762  		t.Fatalf("Failed to wipe database: %v", err)
 763  	}
 764  
 765  	// Create and save events
 766  	for i := 0; i < 3; i++ {
 767  		ev := createTestEvent(1, "Serial test", nil)
 768  		ev.ID[0] = byte(0xF0 + i)
 769  		if _, err := db.SaveEvent(ctx, ev); err != nil {
 770  			t.Fatalf("Failed to save event: %v", err)
 771  		}
 772  	}
 773  
 774  	// Query for serials
 775  	f := &filter.F{
 776  		Kinds: kind.NewS(kind.New(1)),
 777  	}
 778  
 779  	sers, err := db.QueryForSerials(ctx, f)
 780  	if err != nil {
 781  		t.Fatalf("Failed to query for serials: %v", err)
 782  	}
 783  
 784  	if len(sers) != 3 {
 785  		t.Errorf("Expected 3 serials, got %d", len(sers))
 786  	}
 787  
 788  	t.Logf("QueryForSerials returned %d serials", len(sers))
 789  }
 790  
 791  // TestDeleteEvent tests deleting an event by ID
 792  func TestDeleteEvent(t *testing.T) {
 793  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 794  	defer cancel()
 795  
 796  	db, err := New(ctx, cancel, "/tmp/test", "info")
 797  	if err != nil {
 798  		t.Fatalf("Failed to create database: %v", err)
 799  	}
 800  	defer db.Close()
 801  
 802  	<-db.Ready()
 803  
 804  	// Wipe to ensure clean state
 805  	if err := db.Wipe(); err != nil {
 806  		t.Fatalf("Failed to wipe database: %v", err)
 807  	}
 808  
 809  	// Create and save an event
 810  	ev := createTestEvent(1, "Event to delete", nil)
 811  	ev.ID[0] = 0xDE
 812  
 813  	if _, err := db.SaveEvent(ctx, ev); err != nil {
 814  		t.Fatalf("Failed to save event: %v", err)
 815  	}
 816  
 817  	// Verify it exists
 818  	ser, err := db.GetSerialById(ev.ID)
 819  	if err != nil {
 820  		t.Fatalf("Failed to get serial: %v", err)
 821  	}
 822  	if ser == nil {
 823  		t.Fatal("Serial should not be nil after save")
 824  	}
 825  
 826  	// Delete the event
 827  	if err := db.DeleteEvent(ctx, ev.ID); err != nil {
 828  		t.Fatalf("Failed to delete event: %v", err)
 829  	}
 830  
 831  	// Verify it no longer exists
 832  	ser, err = db.GetSerialById(ev.ID)
 833  	if err == nil && ser != nil {
 834  		t.Error("Event should not exist after deletion")
 835  	}
 836  
 837  	t.Log("Event deleted successfully")
 838  }
 839  
 840  // TestDeleteEventBySerial tests deleting an event by serial number
 841  func TestDeleteEventBySerial(t *testing.T) {
 842  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 843  	defer cancel()
 844  
 845  	db, err := New(ctx, cancel, "/tmp/test", "info")
 846  	if err != nil {
 847  		t.Fatalf("Failed to create database: %v", err)
 848  	}
 849  	defer db.Close()
 850  
 851  	<-db.Ready()
 852  
 853  	// Wipe to ensure clean state
 854  	if err := db.Wipe(); err != nil {
 855  		t.Fatalf("Failed to wipe database: %v", err)
 856  	}
 857  
 858  	// Create and save an event
 859  	ev := createTestEvent(1, "Event to delete by serial", nil)
 860  	ev.ID[0] = 0xDF
 861  
 862  	if _, err := db.SaveEvent(ctx, ev); err != nil {
 863  		t.Fatalf("Failed to save event: %v", err)
 864  	}
 865  
 866  	// Get the serial
 867  	ser, err := db.GetSerialById(ev.ID)
 868  	if err != nil {
 869  		t.Fatalf("Failed to get serial: %v", err)
 870  	}
 871  
 872  	// Fetch the event
 873  	fetchedEv, err := db.FetchEventBySerial(ser)
 874  	if err != nil {
 875  		t.Fatalf("Failed to fetch event: %v", err)
 876  	}
 877  
 878  	// Delete by serial
 879  	if err := db.DeleteEventBySerial(ctx, ser, fetchedEv); err != nil {
 880  		t.Fatalf("Failed to delete event by serial: %v", err)
 881  	}
 882  
 883  	// Verify event is gone
 884  	fetchedEv, err = db.FetchEventBySerial(ser)
 885  	if err == nil && fetchedEv != nil {
 886  		t.Error("Event should not exist after deletion by serial")
 887  	}
 888  
 889  	t.Log("Event deleted by serial successfully")
 890  }
 891  
 892  // TestCheckForDeleted tests that deleted events are properly detected
 893  func TestCheckForDeleted(t *testing.T) {
 894  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 895  	defer cancel()
 896  
 897  	db, err := New(ctx, cancel, "/tmp/test", "info")
 898  	if err != nil {
 899  		t.Fatalf("Failed to create database: %v", err)
 900  	}
 901  	defer db.Close()
 902  
 903  	<-db.Ready()
 904  
 905  	// Wipe to ensure clean state
 906  	if err := db.Wipe(); err != nil {
 907  		t.Fatalf("Failed to wipe database: %v", err)
 908  	}
 909  
 910  	// Create a regular event
 911  	ev := createTestEvent(1, "Event that will be deleted", nil)
 912  	ev.ID[0] = 0xDD
 913  	ev.CreatedAt = time.Now().Unix() - 100 // 100 seconds ago
 914  
 915  	if _, err := db.SaveEvent(ctx, ev); err != nil {
 916  		t.Fatalf("Failed to save event: %v", err)
 917  	}
 918  
 919  	// Create a kind 5 deletion event referencing it
 920  	// Use binary format for the e-tag value since GetIndexesForEvent hashes the raw value,
 921  	// and NormalizeTagValueForHash converts hex to binary before hashing in filters
 922  	deleteEv := createTestEvent(5, "", ev.Pubkey)
 923  	deleteEv.ID[0] = 0xD5
 924  	deleteEv.CreatedAt = time.Now().Unix() // Now
 925  
 926  	// Store the e-tag with binary value in the format matching JSON unmarshal
 927  	// The nostr library stores e/p tag values as 33 bytes (32 bytes + null terminator)
 928  	eTagValue := make([]byte, 33)
 929  	copy(eTagValue[:32], ev.ID)
 930  	eTagValue[32] = 0 // null terminator to match nostr library's binary format
 931  	deleteEv.Tags = tag.NewS(
 932  		tag.NewFromAny("e", string(eTagValue)),
 933  	)
 934  
 935  	if _, err := db.SaveEvent(ctx, deleteEv); err != nil {
 936  		t.Fatalf("Failed to save delete event: %v", err)
 937  	}
 938  
 939  	// Check if the original event is marked as deleted
 940  	err = db.CheckForDeleted(ev, nil)
 941  	if err == nil {
 942  		t.Error("Expected error indicating event was deleted")
 943  	} else {
 944  		t.Logf("CheckForDeleted correctly detected deletion: %v", err)
 945  	}
 946  }
 947  
 948  // ============================================================================
 949  // NIP-43 Membership Tests
 950  // ============================================================================
 951  
 952  // TestNIP43AddAndRemoveMember tests adding and removing NIP-43 members
 953  func TestNIP43AddAndRemoveMember(t *testing.T) {
 954  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
 955  	defer cancel()
 956  
 957  	db, err := New(ctx, cancel, "/tmp/test", "info")
 958  	if err != nil {
 959  		t.Fatalf("Failed to create database: %v", err)
 960  	}
 961  	defer db.Close()
 962  
 963  	<-db.Ready()
 964  
 965  	// Wipe to ensure clean state
 966  	if err := db.Wipe(); err != nil {
 967  		t.Fatalf("Failed to wipe database: %v", err)
 968  	}
 969  
 970  	// Create a test pubkey
 971  	pubkey := make([]byte, 32)
 972  	for i := range pubkey {
 973  		pubkey[i] = byte(i + 1)
 974  	}
 975  
 976  	// Initially should not be a member
 977  	isMember, err := db.IsNIP43Member(pubkey)
 978  	if err != nil {
 979  		t.Fatalf("Failed to check member status: %v", err)
 980  	}
 981  	if isMember {
 982  		t.Error("Expected non-member initially")
 983  	}
 984  
 985  	// Add member with invite code
 986  	inviteCode := "TEST-INVITE-123"
 987  	if err := db.AddNIP43Member(pubkey, inviteCode); err != nil {
 988  		t.Fatalf("Failed to add NIP-43 member: %v", err)
 989  	}
 990  
 991  	// Should now be a member
 992  	isMember, err = db.IsNIP43Member(pubkey)
 993  	if err != nil {
 994  		t.Fatalf("Failed to check member status: %v", err)
 995  	}
 996  	if !isMember {
 997  		t.Error("Expected to be a member after adding")
 998  	}
 999  
1000  	// Get membership details
1001  	membership, err := db.GetNIP43Membership(pubkey)
1002  	if err != nil {
1003  		t.Fatalf("Failed to get membership: %v", err)
1004  	}
1005  	if membership.InviteCode != inviteCode {
1006  		t.Errorf("Invite code mismatch: got %s, want %s", membership.InviteCode, inviteCode)
1007  	}
1008  	if !bytes.Equal(membership.Pubkey, pubkey) {
1009  		t.Error("Pubkey mismatch in membership")
1010  	}
1011  
1012  	// Remove member
1013  	if err := db.RemoveNIP43Member(pubkey); err != nil {
1014  		t.Fatalf("Failed to remove member: %v", err)
1015  	}
1016  
1017  	// Should no longer be a member
1018  	isMember, err = db.IsNIP43Member(pubkey)
1019  	if err != nil {
1020  		t.Fatalf("Failed to check member status: %v", err)
1021  	}
1022  	if isMember {
1023  		t.Error("Expected non-member after removal")
1024  	}
1025  
1026  	t.Log("NIP-43 add/remove member test passed")
1027  }
1028  
1029  // TestNIP43GetAllMembers tests retrieving all members
1030  func TestNIP43GetAllMembers(t *testing.T) {
1031  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1032  	defer cancel()
1033  
1034  	db, err := New(ctx, cancel, "/tmp/test", "info")
1035  	if err != nil {
1036  		t.Fatalf("Failed to create database: %v", err)
1037  	}
1038  	defer db.Close()
1039  
1040  	<-db.Ready()
1041  
1042  	// Wipe to ensure clean state
1043  	if err := db.Wipe(); err != nil {
1044  		t.Fatalf("Failed to wipe database: %v", err)
1045  	}
1046  
1047  	// Add multiple members
1048  	pubkeys := make([][]byte, 3)
1049  	for i := 0; i < 3; i++ {
1050  		pubkeys[i] = make([]byte, 32)
1051  		for j := range pubkeys[i] {
1052  			pubkeys[i][j] = byte((i+1)*10 + j)
1053  		}
1054  		if err := db.AddNIP43Member(pubkeys[i], "invite"+string(rune('A'+i))); err != nil {
1055  			t.Fatalf("Failed to add member %d: %v", i, err)
1056  		}
1057  	}
1058  
1059  	// Get all members
1060  	members, err := db.GetAllNIP43Members()
1061  	if err != nil {
1062  		t.Fatalf("Failed to get all members: %v", err)
1063  	}
1064  
1065  	if len(members) != 3 {
1066  		t.Errorf("Expected 3 members, got %d", len(members))
1067  	}
1068  
1069  	t.Logf("Retrieved %d NIP-43 members", len(members))
1070  }
1071  
1072  // TestNIP43InviteCode tests invite code functionality
1073  func TestNIP43InviteCode(t *testing.T) {
1074  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1075  	defer cancel()
1076  
1077  	db, err := New(ctx, cancel, "/tmp/test", "info")
1078  	if err != nil {
1079  		t.Fatalf("Failed to create database: %v", err)
1080  	}
1081  	defer db.Close()
1082  
1083  	<-db.Ready()
1084  
1085  	// Wipe to ensure clean state
1086  	if err := db.Wipe(); err != nil {
1087  		t.Fatalf("Failed to wipe database: %v", err)
1088  	}
1089  
1090  	// Store a valid invite code (expires in 24 hours)
1091  	validCode := "VALID-CODE-ABC"
1092  	expiresAt := time.Now().Add(24 * time.Hour)
1093  	if err := db.StoreInviteCode(validCode, expiresAt); err != nil {
1094  		t.Fatalf("Failed to store invite code: %v", err)
1095  	}
1096  
1097  	// Validate the code
1098  	valid, err := db.ValidateInviteCode(validCode)
1099  	if err != nil {
1100  		t.Fatalf("Failed to validate invite code: %v", err)
1101  	}
1102  	if !valid {
1103  		t.Error("Expected valid invite code to be valid")
1104  	}
1105  
1106  	// Check non-existent code
1107  	valid, err = db.ValidateInviteCode("NONEXISTENT")
1108  	if err != nil {
1109  		t.Fatalf("Unexpected error: %v", err)
1110  	}
1111  	if valid {
1112  		t.Error("Expected non-existent code to be invalid")
1113  	}
1114  
1115  	// Delete the code
1116  	if err := db.DeleteInviteCode(validCode); err != nil {
1117  		t.Fatalf("Failed to delete invite code: %v", err)
1118  	}
1119  
1120  	// Should now be invalid
1121  	valid, err = db.ValidateInviteCode(validCode)
1122  	if err != nil {
1123  		t.Fatalf("Unexpected error: %v", err)
1124  	}
1125  	if valid {
1126  		t.Error("Expected deleted code to be invalid")
1127  	}
1128  
1129  	t.Log("NIP-43 invite code test passed")
1130  }
1131  
1132  // TestNIP43ExpiredInviteCode tests that expired invite codes are invalid
1133  func TestNIP43ExpiredInviteCode(t *testing.T) {
1134  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1135  	defer cancel()
1136  
1137  	db, err := New(ctx, cancel, "/tmp/test", "info")
1138  	if err != nil {
1139  		t.Fatalf("Failed to create database: %v", err)
1140  	}
1141  	defer db.Close()
1142  
1143  	<-db.Ready()
1144  
1145  	// Wipe to ensure clean state
1146  	if err := db.Wipe(); err != nil {
1147  		t.Fatalf("Failed to wipe database: %v", err)
1148  	}
1149  
1150  	// Store an expired invite code (expired 1 hour ago)
1151  	expiredCode := "EXPIRED-CODE-XYZ"
1152  	expiresAt := time.Now().Add(-1 * time.Hour)
1153  	if err := db.StoreInviteCode(expiredCode, expiresAt); err != nil {
1154  		t.Fatalf("Failed to store invite code: %v", err)
1155  	}
1156  
1157  	// Validate the expired code
1158  	valid, err := db.ValidateInviteCode(expiredCode)
1159  	if err != nil {
1160  		t.Fatalf("Unexpected error: %v", err)
1161  	}
1162  	if valid {
1163  		t.Error("Expected expired invite code to be invalid")
1164  	}
1165  
1166  	t.Log("Expired invite code correctly detected as invalid")
1167  }
1168  
1169  // TestNIP43InvalidPubkeyLength tests that invalid pubkey lengths are rejected
1170  func TestNIP43InvalidPubkeyLength(t *testing.T) {
1171  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1172  	defer cancel()
1173  
1174  	db, err := New(ctx, cancel, "/tmp/test", "info")
1175  	if err != nil {
1176  		t.Fatalf("Failed to create database: %v", err)
1177  	}
1178  	defer db.Close()
1179  
1180  	<-db.Ready()
1181  
1182  	// Try to add a member with invalid pubkey length
1183  	shortPubkey := make([]byte, 16) // Should be 32
1184  	err = db.AddNIP43Member(shortPubkey, "test")
1185  	if err == nil {
1186  		t.Error("Expected error for invalid pubkey length")
1187  	}
1188  
1189  	t.Logf("Correctly rejected invalid pubkey length: %v", err)
1190  }
1191  
1192  // ============================================================================
1193  // Subscription Management Tests
1194  // ============================================================================
1195  
1196  // TestSubscriptionExtend tests extending subscriptions
1197  func TestSubscriptionExtend(t *testing.T) {
1198  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1199  	defer cancel()
1200  
1201  	db, err := New(ctx, cancel, "/tmp/test", "info")
1202  	if err != nil {
1203  		t.Fatalf("Failed to create database: %v", err)
1204  	}
1205  	defer db.Close()
1206  
1207  	<-db.Ready()
1208  
1209  	// Wipe to ensure clean state
1210  	if err := db.Wipe(); err != nil {
1211  		t.Fatalf("Failed to wipe database: %v", err)
1212  	}
1213  
1214  	pubkey := make([]byte, 32)
1215  	for i := range pubkey {
1216  		pubkey[i] = byte(i + 50)
1217  	}
1218  
1219  	// Initially no subscription
1220  	sub, err := db.GetSubscription(pubkey)
1221  	if err != nil {
1222  		t.Fatalf("Failed to get subscription: %v", err)
1223  	}
1224  	if sub != nil {
1225  		t.Error("Expected nil subscription initially")
1226  	}
1227  
1228  	// Extend subscription by 30 days
1229  	if err := db.ExtendSubscription(pubkey, 30); err != nil {
1230  		t.Fatalf("Failed to extend subscription: %v", err)
1231  	}
1232  
1233  	// Should now have a subscription
1234  	sub, err = db.GetSubscription(pubkey)
1235  	if err != nil {
1236  		t.Fatalf("Failed to get subscription: %v", err)
1237  	}
1238  	if sub == nil {
1239  		t.Fatal("Expected subscription after extension")
1240  	}
1241  
1242  	// Verify paid until is in the future
1243  	if sub.PaidUntil.Before(time.Now()) {
1244  		t.Error("PaidUntil should be in the future")
1245  	}
1246  
1247  	// Extend again
1248  	if err := db.ExtendSubscription(pubkey, 15); err != nil {
1249  		t.Fatalf("Failed to extend subscription again: %v", err)
1250  	}
1251  
1252  	sub2, err := db.GetSubscription(pubkey)
1253  	if err != nil {
1254  		t.Fatalf("Failed to get subscription: %v", err)
1255  	}
1256  
1257  	// Second extension should add to first
1258  	if !sub2.PaidUntil.After(sub.PaidUntil) {
1259  		t.Error("Expected PaidUntil to increase after second extension")
1260  	}
1261  
1262  	t.Log("Subscription extension test passed")
1263  }
1264  
1265  // TestSubscriptionActive tests checking if subscription is active
1266  func TestSubscriptionActive(t *testing.T) {
1267  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1268  	defer cancel()
1269  
1270  	db, err := New(ctx, cancel, "/tmp/test", "info")
1271  	if err != nil {
1272  		t.Fatalf("Failed to create database: %v", err)
1273  	}
1274  	defer db.Close()
1275  
1276  	<-db.Ready()
1277  
1278  	// Wipe to ensure clean state
1279  	if err := db.Wipe(); err != nil {
1280  		t.Fatalf("Failed to wipe database: %v", err)
1281  	}
1282  
1283  	pubkey := make([]byte, 32)
1284  	for i := range pubkey {
1285  		pubkey[i] = byte(i + 60)
1286  	}
1287  
1288  	// First check creates a trial subscription
1289  	active, err := db.IsSubscriptionActive(pubkey)
1290  	if err != nil {
1291  		t.Fatalf("Failed to check subscription: %v", err)
1292  	}
1293  	if !active {
1294  		t.Error("Expected new user to have active trial subscription")
1295  	}
1296  
1297  	// Second check should still be active
1298  	active, err = db.IsSubscriptionActive(pubkey)
1299  	if err != nil {
1300  		t.Fatalf("Failed to check subscription: %v", err)
1301  	}
1302  	if !active {
1303  		t.Error("Expected subscription to remain active")
1304  	}
1305  
1306  	t.Log("Subscription active check passed")
1307  }
1308  
1309  // TestBlossomSubscription tests blossom storage subscription
1310  func TestBlossomSubscription(t *testing.T) {
1311  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1312  	defer cancel()
1313  
1314  	db, err := New(ctx, cancel, "/tmp/test", "info")
1315  	if err != nil {
1316  		t.Fatalf("Failed to create database: %v", err)
1317  	}
1318  	defer db.Close()
1319  
1320  	<-db.Ready()
1321  
1322  	// Wipe to ensure clean state
1323  	if err := db.Wipe(); err != nil {
1324  		t.Fatalf("Failed to wipe database: %v", err)
1325  	}
1326  
1327  	pubkey := make([]byte, 32)
1328  	for i := range pubkey {
1329  		pubkey[i] = byte(i + 70)
1330  	}
1331  
1332  	// Initially no quota
1333  	quota, err := db.GetBlossomStorageQuota(pubkey)
1334  	if err != nil {
1335  		t.Fatalf("Failed to get quota: %v", err)
1336  	}
1337  	if quota != 0 {
1338  		t.Error("Expected zero quota initially")
1339  	}
1340  
1341  	// Add blossom subscription
1342  	if err := db.ExtendBlossomSubscription(pubkey, "premium", 1024, 30); err != nil {
1343  		t.Fatalf("Failed to extend blossom subscription: %v", err)
1344  	}
1345  
1346  	// Check quota
1347  	quota, err = db.GetBlossomStorageQuota(pubkey)
1348  	if err != nil {
1349  		t.Fatalf("Failed to get quota: %v", err)
1350  	}
1351  	if quota != 1024 {
1352  		t.Errorf("Expected quota of 1024, got %d", quota)
1353  	}
1354  
1355  	// Check subscription details
1356  	sub, err := db.GetSubscription(pubkey)
1357  	if err != nil {
1358  		t.Fatalf("Failed to get subscription: %v", err)
1359  	}
1360  	if sub.BlossomLevel != "premium" {
1361  		t.Errorf("Expected premium level, got %s", sub.BlossomLevel)
1362  	}
1363  
1364  	t.Log("Blossom subscription test passed")
1365  }
1366  
1367  // TestPaymentHistory tests recording and retrieving payment history
1368  func TestPaymentHistory(t *testing.T) {
1369  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1370  	defer cancel()
1371  
1372  	db, err := New(ctx, cancel, "/tmp/test", "info")
1373  	if err != nil {
1374  		t.Fatalf("Failed to create database: %v", err)
1375  	}
1376  	defer db.Close()
1377  
1378  	<-db.Ready()
1379  
1380  	// Wipe to ensure clean state
1381  	if err := db.Wipe(); err != nil {
1382  		t.Fatalf("Failed to wipe database: %v", err)
1383  	}
1384  
1385  	pubkey := make([]byte, 32)
1386  	for i := range pubkey {
1387  		pubkey[i] = byte(i + 80)
1388  	}
1389  
1390  	// Initially no payment history
1391  	payments, err := db.GetPaymentHistory(pubkey)
1392  	if err != nil {
1393  		t.Fatalf("Failed to get payment history: %v", err)
1394  	}
1395  	if len(payments) != 0 {
1396  		t.Error("Expected empty payment history initially")
1397  	}
1398  
1399  	// Record a payment
1400  	if err := db.RecordPayment(pubkey, 10000, "lnbc100...", "preimage123"); err != nil {
1401  		t.Fatalf("Failed to record payment: %v", err)
1402  	}
1403  
1404  	// Small delay to ensure different timestamps
1405  	time.Sleep(10 * time.Millisecond)
1406  
1407  	// Record another payment
1408  	if err := db.RecordPayment(pubkey, 20000, "lnbc200...", "preimage456"); err != nil {
1409  		t.Fatalf("Failed to record payment: %v", err)
1410  	}
1411  
1412  	// Check payment history
1413  	payments, err = db.GetPaymentHistory(pubkey)
1414  	if err != nil {
1415  		t.Fatalf("Failed to get payment history: %v", err)
1416  	}
1417  	if len(payments) != 2 {
1418  		t.Errorf("Expected 2 payments, got %d", len(payments))
1419  	}
1420  
1421  	t.Logf("Retrieved %d payments from history", len(payments))
1422  }
1423  
1424  // TestIsFirstTimeUser tests first-time user detection
1425  func TestIsFirstTimeUser(t *testing.T) {
1426  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1427  	defer cancel()
1428  
1429  	db, err := New(ctx, cancel, "/tmp/test", "info")
1430  	if err != nil {
1431  		t.Fatalf("Failed to create database: %v", err)
1432  	}
1433  	defer db.Close()
1434  
1435  	<-db.Ready()
1436  
1437  	// Wipe to ensure clean state
1438  	if err := db.Wipe(); err != nil {
1439  		t.Fatalf("Failed to wipe database: %v", err)
1440  	}
1441  
1442  	pubkey := make([]byte, 32)
1443  	for i := range pubkey {
1444  		pubkey[i] = byte(i + 90)
1445  	}
1446  
1447  	// First check should be true
1448  	isFirst, err := db.IsFirstTimeUser(pubkey)
1449  	if err != nil {
1450  		t.Fatalf("Failed to check first time user: %v", err)
1451  	}
1452  	if !isFirst {
1453  		t.Error("Expected true for first check")
1454  	}
1455  
1456  	// Second check should be false
1457  	isFirst, err = db.IsFirstTimeUser(pubkey)
1458  	if err != nil {
1459  		t.Fatalf("Failed to check first time user: %v", err)
1460  	}
1461  	if isFirst {
1462  		t.Error("Expected false for second check")
1463  	}
1464  
1465  	t.Log("First time user detection test passed")
1466  }
1467  
1468  // TestSubscriptionInvalidDays tests that invalid day counts are rejected
1469  func TestSubscriptionInvalidDays(t *testing.T) {
1470  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1471  	defer cancel()
1472  
1473  	db, err := New(ctx, cancel, "/tmp/test", "info")
1474  	if err != nil {
1475  		t.Fatalf("Failed to create database: %v", err)
1476  	}
1477  	defer db.Close()
1478  
1479  	<-db.Ready()
1480  
1481  	pubkey := make([]byte, 32)
1482  
1483  	// Try to extend with 0 days
1484  	err = db.ExtendSubscription(pubkey, 0)
1485  	if err == nil {
1486  		t.Error("Expected error for 0 days")
1487  	}
1488  
1489  	// Try to extend with negative days
1490  	err = db.ExtendSubscription(pubkey, -5)
1491  	if err == nil {
1492  		t.Error("Expected error for negative days")
1493  	}
1494  
1495  	t.Log("Invalid days correctly rejected")
1496  }
1497  
1498  // ============================================================================
1499  // Import/Export Tests
1500  // ============================================================================
1501  
1502  // TestImportExport tests basic import/export functionality
1503  func TestImportExport(t *testing.T) {
1504  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1505  	defer cancel()
1506  
1507  	db, err := New(ctx, cancel, "/tmp/test", "info")
1508  	if err != nil {
1509  		t.Fatalf("Failed to create database: %v", err)
1510  	}
1511  	defer db.Close()
1512  
1513  	<-db.Ready()
1514  
1515  	// Wipe to ensure clean state
1516  	if err := db.Wipe(); err != nil {
1517  		t.Fatalf("Failed to wipe database: %v", err)
1518  	}
1519  
1520  	// Create and save some events
1521  	for i := 0; i < 3; i++ {
1522  		ev := createTestEvent(1, "Export test event", nil)
1523  		ev.ID[0] = byte(0xAA + i)
1524  		if _, err := db.SaveEvent(ctx, ev); err != nil {
1525  			t.Fatalf("Failed to save event: %v", err)
1526  		}
1527  	}
1528  
1529  	// Export to buffer
1530  	var exportBuf bytes.Buffer
1531  	db.Export(ctx, &exportBuf)
1532  
1533  	exportData := exportBuf.String()
1534  	if len(exportData) == 0 {
1535  		t.Error("Expected non-empty export data")
1536  	}
1537  
1538  	// Count lines (should be 3 JSONL lines)
1539  	lines := bytes.Count(exportBuf.Bytes(), []byte("\n"))
1540  	if lines != 3 {
1541  		t.Errorf("Expected 3 export lines, got %d", lines)
1542  	}
1543  
1544  	t.Logf("Exported %d events to %d bytes", lines, len(exportData))
1545  }
1546  
1547  // TestImportFromReader tests importing events from JSONL reader
1548  func TestImportFromReader(t *testing.T) {
1549  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1550  	defer cancel()
1551  
1552  	db, err := New(ctx, cancel, "/tmp/test", "info")
1553  	if err != nil {
1554  		t.Fatalf("Failed to create database: %v", err)
1555  	}
1556  	defer db.Close()
1557  
1558  	<-db.Ready()
1559  
1560  	// Wipe to ensure clean state
1561  	if err := db.Wipe(); err != nil {
1562  		t.Fatalf("Failed to wipe database: %v", err)
1563  	}
1564  
1565  	// Create JSONL import data
1566  	// Note: These are simplified test events - real events would have valid signatures
1567  	jsonl := `{"id":"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","pubkey":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","created_at":1700000000,"kind":1,"tags":[],"content":"Test event 1","sig":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc"}
1568  {"id":"dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd","pubkey":"bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb","created_at":1700000001,"kind":1,"tags":[],"content":"Test event 2","sig":"eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee"}
1569  `
1570  
1571  	reader := bytes.NewReader([]byte(jsonl))
1572  	err = db.ImportEventsFromReader(ctx, reader)
1573  	if err != nil {
1574  		t.Fatalf("Failed to import events: %v", err)
1575  	}
1576  
1577  	t.Log("Import from reader test completed")
1578  }
1579  
1580  // TestImportExportRoundTrip tests full round-trip import/export
1581  func TestImportExportRoundTrip(t *testing.T) {
1582  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1583  	defer cancel()
1584  
1585  	// Create first database
1586  	db1, err := New(ctx, cancel, "/tmp/test", "info")
1587  	if err != nil {
1588  		t.Fatalf("Failed to create database 1: %v", err)
1589  	}
1590  	defer db1.Close()
1591  
1592  	<-db1.Ready()
1593  
1594  	// Wipe to ensure clean state
1595  	if err := db1.Wipe(); err != nil {
1596  		t.Fatalf("Failed to wipe database: %v", err)
1597  	}
1598  
1599  	// Create events with specific content for verification
1600  	// Using kinds 1, 7, 10, 20, 30 to avoid kind 3 which requires p tags
1601  	kinds := []uint16{1, 7, 10, 20, 30}
1602  	originalEvents := make([]*event.E, 5)
1603  	for i := 0; i < 5; i++ {
1604  		ev := createTestEvent(kinds[i], "Round trip content "+string(rune('A'+i)), nil)
1605  		ev.ID[0] = byte(0xBB + i)
1606  		originalEvents[i] = ev
1607  		if _, err := db1.SaveEvent(ctx, ev); err != nil {
1608  			t.Fatalf("Failed to save event: %v", err)
1609  		}
1610  	}
1611  
1612  	// Export from db1
1613  	var exportBuf bytes.Buffer
1614  	db1.Export(ctx, &exportBuf)
1615  
1616  	// Wipe db1 (simulating a fresh database)
1617  	if err := db1.Wipe(); err != nil {
1618  		t.Fatalf("Failed to wipe database: %v", err)
1619  	}
1620  
1621  	// Import back
1622  	db1.Import(&exportBuf)
1623  
1624  	// Query all events
1625  	f := &filter.F{}
1626  	evs, err := db1.QueryEvents(ctx, f)
1627  	if err != nil {
1628  		t.Fatalf("Failed to query events: %v", err)
1629  	}
1630  
1631  	if len(evs) < 5 {
1632  		t.Errorf("Expected at least 5 events after round trip, got %d", len(evs))
1633  	}
1634  
1635  	t.Logf("Round trip test: %d events survived", len(evs))
1636  }
1637  
1638  // TestGetSerialsByPubkey tests retrieving serials by pubkey
1639  func TestGetSerialsByPubkey(t *testing.T) {
1640  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1641  	defer cancel()
1642  
1643  	db, err := New(ctx, cancel, "/tmp/test", "info")
1644  	if err != nil {
1645  		t.Fatalf("Failed to create database: %v", err)
1646  	}
1647  	defer db.Close()
1648  
1649  	<-db.Ready()
1650  
1651  	// Wipe to ensure clean state
1652  	if err := db.Wipe(); err != nil {
1653  		t.Fatalf("Failed to wipe database: %v", err)
1654  	}
1655  
1656  	// Create a specific author
1657  	author := make([]byte, 32)
1658  	for i := range author {
1659  		author[i] = 0xCC
1660  	}
1661  
1662  	// Create events from this author
1663  	for i := 0; i < 3; i++ {
1664  		ev := createTestEvent(1, "Author test", author)
1665  		ev.ID[0] = byte(0xCC + i)
1666  		if _, err := db.SaveEvent(ctx, ev); err != nil {
1667  			t.Fatalf("Failed to save event: %v", err)
1668  		}
1669  	}
1670  
1671  	// Get serials by pubkey
1672  	serials, err := db.GetSerialsByPubkey(author)
1673  	if err != nil {
1674  		t.Fatalf("Failed to get serials by pubkey: %v", err)
1675  	}
1676  
1677  	if len(serials) != 3 {
1678  		t.Errorf("Expected 3 serials, got %d", len(serials))
1679  	}
1680  
1681  	t.Logf("GetSerialsByPubkey returned %d serials", len(serials))
1682  }
1683  
1684  // TestExportByPubkey tests exporting events filtered by pubkey
1685  func TestExportByPubkey(t *testing.T) {
1686  	ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
1687  	defer cancel()
1688  
1689  	db, err := New(ctx, cancel, "/tmp/test", "info")
1690  	if err != nil {
1691  		t.Fatalf("Failed to create database: %v", err)
1692  	}
1693  	defer db.Close()
1694  
1695  	<-db.Ready()
1696  
1697  	// Wipe to ensure clean state
1698  	if err := db.Wipe(); err != nil {
1699  		t.Fatalf("Failed to wipe database: %v", err)
1700  	}
1701  
1702  	// Create two different authors
1703  	author1 := make([]byte, 32)
1704  	for i := range author1 {
1705  		author1[i] = 0xDD
1706  	}
1707  	author2 := make([]byte, 32)
1708  	for i := range author2 {
1709  		author2[i] = 0xEE
1710  	}
1711  
1712  	// Create events from both authors
1713  	for i := 0; i < 2; i++ {
1714  		ev := createTestEvent(1, "Author 1 content", author1)
1715  		ev.ID[0] = byte(0xD0 + i)
1716  		if _, err := db.SaveEvent(ctx, ev); err != nil {
1717  			t.Fatalf("Failed to save event: %v", err)
1718  		}
1719  	}
1720  	for i := 0; i < 3; i++ {
1721  		ev := createTestEvent(1, "Author 2 content", author2)
1722  		ev.ID[0] = byte(0xE0 + i)
1723  		if _, err := db.SaveEvent(ctx, ev); err != nil {
1724  			t.Fatalf("Failed to save event: %v", err)
1725  		}
1726  	}
1727  
1728  	// Export only author1's events
1729  	var exportBuf bytes.Buffer
1730  	db.Export(ctx, &exportBuf, author1)
1731  
1732  	lines := bytes.Count(exportBuf.Bytes(), []byte("\n"))
1733  	if lines != 2 {
1734  		t.Errorf("Expected 2 export lines for author1, got %d", lines)
1735  	}
1736  
1737  	t.Logf("Exported %d events for specific pubkey", lines)
1738  }
1739  
1740