From 62d31434ddbadff18580826576e1169f539e23f0 Mon Sep 17 00:00:00 2001 From: bndw Date: Fri, 13 Feb 2026 17:48:36 -0800 Subject: feat: add gRPC handler with event validation and publishing Handler implementation: - EventStore interface (consumer-side) - Server with PublishEvent, QueryEvents, CountEvents, PublishBatch - pb.Event <-> nostr.Event conversion helpers - Signature and ID validation using existing nostr package - Canonical JSON generation for storage 9 tests passing --- internal/handler/grpc/convert_test.go | 143 ++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 internal/handler/grpc/convert_test.go (limited to 'internal/handler/grpc/convert_test.go') diff --git a/internal/handler/grpc/convert_test.go b/internal/handler/grpc/convert_test.go new file mode 100644 index 0000000..6da2d89 --- /dev/null +++ b/internal/handler/grpc/convert_test.go @@ -0,0 +1,143 @@ +package grpc + +import ( + "testing" + + pb "northwest.io/nostr-grpc/api/nostr/v1" + "northwest.io/nostr-grpc/internal/nostr" +) + +func TestNostrToPB(t *testing.T) { + nostrEvent := &nostr.Event{ + ID: "abc123", + PubKey: "pubkey123", + CreatedAt: 1234567890, + Kind: 1, + Tags: nostr.Tags{{"e", "event1"}, {"p", "pubkey1"}}, + Content: "Hello, Nostr!", + Sig: "sig123", + } + + pbEvent := NostrToPB(nostrEvent) + + if pbEvent.Id != nostrEvent.ID { + t.Errorf("ID mismatch: expected %s, got %s", nostrEvent.ID, pbEvent.Id) + } + if pbEvent.Pubkey != nostrEvent.PubKey { + t.Errorf("Pubkey mismatch: expected %s, got %s", nostrEvent.PubKey, pbEvent.Pubkey) + } + if pbEvent.CreatedAt != nostrEvent.CreatedAt { + t.Errorf("CreatedAt mismatch: expected %d, got %d", nostrEvent.CreatedAt, pbEvent.CreatedAt) + } + if pbEvent.Kind != int32(nostrEvent.Kind) { + t.Errorf("Kind mismatch: expected %d, got %d", nostrEvent.Kind, pbEvent.Kind) + } + if pbEvent.Content != nostrEvent.Content { + t.Errorf("Content mismatch: expected %s, got %s", nostrEvent.Content, pbEvent.Content) + } + if pbEvent.Sig != nostrEvent.Sig { + t.Errorf("Sig mismatch: expected %s, got %s", nostrEvent.Sig, pbEvent.Sig) + } + + if len(pbEvent.Tags) != len(nostrEvent.Tags) { + t.Fatalf("Tags length mismatch: expected %d, got %d", len(nostrEvent.Tags), len(pbEvent.Tags)) + } + + for i, tag := range pbEvent.Tags { + if len(tag.Values) != len(nostrEvent.Tags[i]) { + t.Errorf("Tag[%d] values length mismatch", i) + continue + } + for j, val := range tag.Values { + if val != nostrEvent.Tags[i][j] { + t.Errorf("Tag[%d][%d] mismatch: expected %s, got %s", i, j, nostrEvent.Tags[i][j], val) + } + } + } +} + +func TestPBToNostr(t *testing.T) { + pbEvent := &pb.Event{ + Id: "abc123", + Pubkey: "pubkey123", + CreatedAt: 1234567890, + Kind: 1, + Tags: []*pb.Tag{{Values: []string{"e", "event1"}}, {Values: []string{"p", "pubkey1"}}}, + Content: "Hello, Nostr!", + Sig: "sig123", + } + + nostrEvent := PBToNostr(pbEvent) + + if nostrEvent.ID != pbEvent.Id { + t.Errorf("ID mismatch: expected %s, got %s", pbEvent.Id, nostrEvent.ID) + } + if nostrEvent.PubKey != pbEvent.Pubkey { + t.Errorf("Pubkey mismatch: expected %s, got %s", pbEvent.Pubkey, nostrEvent.PubKey) + } + if nostrEvent.CreatedAt != pbEvent.CreatedAt { + t.Errorf("CreatedAt mismatch: expected %d, got %d", pbEvent.CreatedAt, nostrEvent.CreatedAt) + } + if nostrEvent.Kind != int(pbEvent.Kind) { + t.Errorf("Kind mismatch: expected %d, got %d", pbEvent.Kind, nostrEvent.Kind) + } + if nostrEvent.Content != pbEvent.Content { + t.Errorf("Content mismatch: expected %s, got %s", pbEvent.Content, nostrEvent.Content) + } + if nostrEvent.Sig != pbEvent.Sig { + t.Errorf("Sig mismatch: expected %s, got %s", pbEvent.Sig, nostrEvent.Sig) + } + + if len(nostrEvent.Tags) != len(pbEvent.Tags) { + t.Fatalf("Tags length mismatch: expected %d, got %d", len(pbEvent.Tags), len(nostrEvent.Tags)) + } + + for i, tag := range nostrEvent.Tags { + if len(tag) != len(pbEvent.Tags[i].Values) { + t.Errorf("Tag[%d] values length mismatch", i) + continue + } + for j, val := range tag { + if val != pbEvent.Tags[i].Values[j] { + t.Errorf("Tag[%d][%d] mismatch: expected %s, got %s", i, j, pbEvent.Tags[i].Values[j], val) + } + } + } +} + +func TestRoundTrip(t *testing.T) { + original := &nostr.Event{ + ID: "roundtrip123", + PubKey: "pubkey_roundtrip", + CreatedAt: 9876543210, + Kind: 7, + Tags: nostr.Tags{{"e", "evt"}, {"p", "pk", "relay"}}, + Content: "Round trip test", + Sig: "signature", + } + + pb := NostrToPB(original) + backToNostr := PBToNostr(pb) + + if backToNostr.ID != original.ID { + t.Errorf("Round trip ID mismatch") + } + if backToNostr.PubKey != original.PubKey { + t.Errorf("Round trip PubKey mismatch") + } + if backToNostr.CreatedAt != original.CreatedAt { + t.Errorf("Round trip CreatedAt mismatch") + } + if backToNostr.Kind != original.Kind { + t.Errorf("Round trip Kind mismatch") + } + if backToNostr.Content != original.Content { + t.Errorf("Round trip Content mismatch") + } + if backToNostr.Sig != original.Sig { + t.Errorf("Round trip Sig mismatch") + } + if len(backToNostr.Tags) != len(original.Tags) { + t.Fatalf("Round trip Tags length mismatch") + } +} -- cgit v1.2.3