package storage import ( "context" "testing" pb "northwest.io/muxstr/api/nostr/v1" ) func setupTestEvents(t *testing.T, store *Storage) { ctx := context.Background() events := []*EventData{ { Event: &pb.Event{ Id: "aaaa1111", Pubkey: "pubkey1", CreatedAt: 1000, Kind: 1, Tags: []*pb.Tag{{Values: []string{"e", "event123"}}}, Content: "test event 1", Sig: "sig1", }, CanonicalJSON: []byte(`[0,"pubkey1",1000,1,[["e","event123"]],"test event 1"]`), }, { Event: &pb.Event{ Id: "bbbb2222", Pubkey: "pubkey2", CreatedAt: 2000, Kind: 1, Tags: []*pb.Tag{{Values: []string{"p", "pubkey1"}}}, Content: "test event 2", Sig: "sig2", }, CanonicalJSON: []byte(`[0,"pubkey2",2000,1,[["p","pubkey1"]],"test event 2"]`), }, { Event: &pb.Event{ Id: "cccc3333", Pubkey: "pubkey1", CreatedAt: 3000, Kind: 3, Tags: []*pb.Tag{}, Content: "test event 3", Sig: "sig3", }, CanonicalJSON: []byte(`[0,"pubkey1",3000,3,[],"test event 3"]`), }, { Event: &pb.Event{ Id: "dddd4444", Pubkey: "pubkey3", CreatedAt: 4000, Kind: 1, Tags: []*pb.Tag{ {Values: []string{"e", "event123"}}, {Values: []string{"p", "pubkey2"}}, }, Content: "test event 4", Sig: "sig4", }, CanonicalJSON: []byte(`[0,"pubkey3",4000,1,[["e","event123"],["p","pubkey2"]],"test event 4"]`), }, } for _, data := range events { if err := store.StoreEvent(ctx, data); err != nil { t.Fatalf("failed to store event %s: %v", data.Event.Id, err) } } } func TestQueryEventsByID(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{ {Ids: []string{"aaaa1111"}}, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 1 { t.Fatalf("expected 1 event, got %d", len(events)) } if events[0].Id != "aaaa1111" { t.Errorf("expected ID aaaa1111, got %s", events[0].Id) } } func TestQueryEventsByIDPrefix(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{ {Ids: []string{"aaaa"}}, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 1 { t.Fatalf("expected 1 event, got %d", len(events)) } if events[0].Id != "aaaa1111" { t.Errorf("expected ID aaaa1111, got %s", events[0].Id) } } func TestQueryEventsByAuthor(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{ {Authors: []string{"pubkey1"}}, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 2 { t.Fatalf("expected 2 events, got %d", len(events)) } for _, event := range events { if event.Pubkey != "pubkey1" { t.Errorf("expected pubkey pubkey1, got %s", event.Pubkey) } } } func TestQueryEventsByKind(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{ {Kinds: []int32{1}}, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 3 { t.Fatalf("expected 3 events, got %d", len(events)) } for _, event := range events { if event.Kind != 1 { t.Errorf("expected kind 1, got %d", event.Kind) } } } func TestQueryEventsByETag(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{ {ETags: []string{"event123"}}, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 2 { t.Fatalf("expected 2 events, got %d", len(events)) } } func TestQueryEventsByPTag(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{ {PTags: []string{"pubkey1"}}, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 1 { t.Fatalf("expected 1 event, got %d", len(events)) } if events[0].Id != "bbbb2222" { t.Errorf("expected ID bbbb2222, got %s", events[0].Id) } } func TestQueryEventsSince(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() since := int64(2500) filters := []*pb.Filter{ {Since: &since}, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 2 { t.Fatalf("expected 2 events, got %d", len(events)) } for _, event := range events { if event.CreatedAt < since { t.Errorf("event %s has timestamp %d, expected >= %d", event.Id, event.CreatedAt, since) } } } func TestQueryEventsUntil(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() until := int64(2500) filters := []*pb.Filter{ {Until: &until}, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 2 { t.Fatalf("expected 2 events, got %d", len(events)) } for _, event := range events { if event.CreatedAt > until { t.Errorf("event %s has timestamp %d, expected <= %d", event.Id, event.CreatedAt, until) } } } func TestQueryEventsWithLimit(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{{}} opts := &QueryOptions{Limit: 2} events, err := store.QueryEvents(ctx, filters, opts) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 2 { t.Fatalf("expected 2 events due to limit, got %d", len(events)) } } func TestQueryEventsWithCanonical(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{ {Ids: []string{"aaaa1111"}}, } opts := &QueryOptions{IncludeCanonical: true} events, err := store.QueryEvents(ctx, filters, opts) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 1 { t.Fatalf("expected 1 event, got %d", len(events)) } if len(events[0].CanonicalJson) == 0 { t.Error("expected canonical JSON to be populated") } } func TestQueryMultipleFilters(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{ {Ids: []string{"aaaa1111"}}, {Kinds: []int32{3}}, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 2 { t.Fatalf("expected 2 events (UNION), got %d", len(events)) } } func TestQueryEventsOrdering(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() filters := []*pb.Filter{{}} events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } for i := 1; i < len(events); i++ { if events[i].CreatedAt > events[i-1].CreatedAt { t.Errorf("events not ordered by created_at DESC: %d > %d", events[i].CreatedAt, events[i-1].CreatedAt) } } } func TestQueryEventsComplex(t *testing.T) { store, err := New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() setupTestEvents(t, store) ctx := context.Background() since := int64(1500) filters := []*pb.Filter{ { Authors: []string{"pubkey1"}, Kinds: []int32{1, 3}, Since: &since, }, } events, err := store.QueryEvents(ctx, filters, nil) if err != nil { t.Fatalf("query failed: %v", err) } if len(events) != 1 { t.Fatalf("expected 1 event, got %d", len(events)) } if events[0].Id != "cccc3333" { t.Errorf("expected event cccc3333, got %s", events[0].Id) } }