package grpc import ( "context" "fmt" "testing" "time" pb "northwest.io/muxstr/api/nostr/v1" "northwest.io/muxstr/internal/nostr" "northwest.io/muxstr/internal/storage" ) func TestPublishEvent(t *testing.T) { store, err := storage.New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() server := NewServer(store) ctx := context.Background() key, err := nostr.GenerateKey() if err != nil { t.Fatalf("failed to generate key: %v", err) } nostrEvent := &nostr.Event{ PubKey: key.Public(), CreatedAt: time.Now().Unix(), Kind: 1, Tags: nostr.Tags{}, Content: "test event", } if err := key.Sign(nostrEvent); err != nil { t.Fatalf("failed to sign event: %v", err) } pbEvent := NostrToPB(nostrEvent) resp, err := server.PublishEvent(ctx, &pb.PublishEventRequest{Event: pbEvent}) if err != nil { t.Fatalf("PublishEvent failed: %v", err) } if !resp.Accepted { t.Errorf("expected event to be accepted, got: %s", resp.Message) } if resp.Message != "success" { t.Errorf("expected success message, got: %s", resp.Message) } if len(resp.CanonicalJson) == 0 { t.Error("expected canonical JSON to be returned") } } func TestPublishEventDuplicate(t *testing.T) { store, err := storage.New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() server := NewServer(store) ctx := context.Background() key, err := nostr.GenerateKey() if err != nil { t.Fatalf("failed to generate key: %v", err) } nostrEvent := &nostr.Event{ PubKey: key.Public(), CreatedAt: time.Now().Unix(), Kind: 1, Tags: nostr.Tags{}, Content: "duplicate test", } if err := key.Sign(nostrEvent); err != nil { t.Fatalf("failed to sign event: %v", err) } pbEvent := NostrToPB(nostrEvent) resp1, err := server.PublishEvent(ctx, &pb.PublishEventRequest{Event: pbEvent}) if err != nil { t.Fatalf("first PublishEvent failed: %v", err) } if !resp1.Accepted { t.Fatalf("first event should be accepted") } resp2, err := server.PublishEvent(ctx, &pb.PublishEventRequest{Event: pbEvent}) if err != nil { t.Fatalf("second PublishEvent failed: %v", err) } if resp2.Accepted { t.Error("duplicate event should not be accepted") } if resp2.Message != "duplicate: event already exists" { t.Errorf("expected duplicate message, got: %s", resp2.Message) } } func TestPublishEventInvalidSignature(t *testing.T) { store, err := storage.New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() server := NewServer(store) ctx := context.Background() key, err := nostr.GenerateKey() if err != nil { t.Fatalf("failed to generate key: %v", err) } nostrEvent := &nostr.Event{ PubKey: key.Public(), CreatedAt: time.Now().Unix(), Kind: 1, Tags: nostr.Tags{}, Content: "test event", } if err := key.Sign(nostrEvent); err != nil { t.Fatalf("failed to sign event: %v", err) } pbEvent := NostrToPB(nostrEvent) pbEvent.Sig = "invalid_signature" resp, err := server.PublishEvent(ctx, &pb.PublishEventRequest{Event: pbEvent}) if err != nil { t.Fatalf("PublishEvent failed: %v", err) } if resp.Accepted { t.Error("event with invalid signature should not be accepted") } if resp.Message != "invalid signature" { t.Errorf("expected invalid signature message, got: %s", resp.Message) } } func TestPublishEventInvalidID(t *testing.T) { store, err := storage.New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() server := NewServer(store) ctx := context.Background() pbEvent := &pb.Event{ Id: "wrong_id", Pubkey: "pubkey123", CreatedAt: time.Now().Unix(), Kind: 1, Tags: []*pb.Tag{}, Content: "test", Sig: "sig123", } resp, err := server.PublishEvent(ctx, &pb.PublishEventRequest{Event: pbEvent}) if err != nil { t.Fatalf("PublishEvent failed: %v", err) } if resp.Accepted { t.Error("event with invalid ID should not be accepted") } if resp.Message != "invalid event ID" { t.Errorf("expected invalid ID message, got: %s", resp.Message) } } func TestQueryEvents(t *testing.T) { store, err := storage.New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() server := NewServer(store) ctx := context.Background() key, err := nostr.GenerateKey() if err != nil { t.Fatalf("failed to generate key: %v", err) } for i := 0; i < 3; i++ { nostrEvent := &nostr.Event{ PubKey: key.Public(), CreatedAt: time.Now().Unix(), Kind: 1, Tags: nostr.Tags{}, Content: fmt.Sprintf("test event %d", i), } if err := key.Sign(nostrEvent); err != nil { t.Fatalf("failed to sign event: %v", err) } pbEvent := NostrToPB(nostrEvent) if _, err := server.PublishEvent(ctx, &pb.PublishEventRequest{Event: pbEvent}); err != nil { t.Fatalf("failed to publish event: %v", err) } time.Sleep(time.Millisecond) } resp, err := server.QueryEvents(ctx, &pb.QueryRequest{ Filters: []*pb.Filter{ {Authors: []string{key.Public()}}, }, }) if err != nil { t.Fatalf("QueryEvents failed: %v", err) } if len(resp.Events) != 3 { t.Errorf("expected 3 events, got %d", len(resp.Events)) } } func TestPublishBatch(t *testing.T) { store, err := storage.New(":memory:") if err != nil { t.Fatalf("failed to create storage: %v", err) } defer store.Close() server := NewServer(store) ctx := context.Background() key, err := nostr.GenerateKey() if err != nil { t.Fatalf("failed to generate key: %v", err) } var events []*pb.Event for i := 0; i < 3; i++ { nostrEvent := &nostr.Event{ PubKey: key.Public(), CreatedAt: time.Now().Unix(), Kind: 1, Tags: nostr.Tags{}, Content: fmt.Sprintf("batch test %d", i), } if err := key.Sign(nostrEvent); err != nil { t.Fatalf("failed to sign event: %v", err) } events = append(events, NostrToPB(nostrEvent)) time.Sleep(time.Millisecond) } resp, err := server.PublishBatch(ctx, &pb.PublishBatchRequest{Events: events}) if err != nil { t.Fatalf("PublishBatch failed: %v", err) } if len(resp.Results) != 3 { t.Fatalf("expected 3 results, got %d", len(resp.Results)) } for i, result := range resp.Results { if !result.Accepted { t.Errorf("event %d should be accepted, got: %s", i, result.Message) } } }