tinyrelayfile
tinyrelay/internal/daemon/notifications_test.go/

internal/daemon/notifications_test.go raw
1package daemon
2
3import (
4 "context"
5 "path/filepath"
6 "testing"
7
8 "github.com/FelineStateMachine/tinyrelay/internal/catalog"
9 "github.com/FelineStateMachine/tinyrelay/internal/event"
10 "github.com/FelineStateMachine/tinyrelay/internal/storage"
11 "github.com/FelineStateMachine/tinyrelay/internal/work"
12)
13
14func TestDeliverNotificationQueuesPrivateLocalAndRecipientWorkAtomically(t *testing.T) {
15 ctx := context.Background()
16 store, err := storage.Open(ctx, filepath.Join(t.TempDir(), "tenant.db"))
17 if err != nil {
18 t.Fatal(err)
19 }
20 defer store.Close()
21 secret, err := event.GenerateKey()
22 if err != nil {
23 t.Fatal(err)
24 }
25 recipient, err := event.PublicKey(secret)
26 if err != nil {
27 t.Fatal(err)
28 }
29 wrap := event.Event{CreatedAt: 10, Kind: event.KIND_WRAP, Tags: [][]string{{"p", recipient}}, Content: "cipher"}
30 if err := event.Sign(&wrap, secret); err != nil {
31 t.Fatal(err)
32 }
33 tenant := &Tenant{store: store, meta: catalog.Tenant{ID: "tenant-1"}, publicURL: "http://relay.example"}
34 if err := tenant.deliverNotification(ctx, wrap, recipient); err != nil {
35 t.Fatal(err)
36 }
37 var count int
38 if err := store.DB().QueryRowContext(ctx, `SELECT count(*) FROM work_intents WHERE event_id=?`, wrap.ID).Scan(&count); err != nil {
39 t.Fatal(err)
40 }
41 if count != 2 {
42 t.Fatalf("queued intents = %d, want local broadcast and recipient delivery", count)
43 }
44 var target string
45 if err := store.DB().QueryRowContext(ctx, `SELECT target FROM work_intents WHERE kind=?`, notificationDelivery).Scan(&target); err != nil {
46 t.Fatal(err)
47 }
48 if target != recipient {
49 t.Fatalf("delivery target = %q, want recipient %q", target, recipient)
50 }
51 if err := store.DB().QueryRowContext(ctx, `SELECT count(*) FROM events WHERE kind=10050`).Scan(&count); err != nil {
52 t.Fatal(err)
53 }
54 if count != 0 {
55 t.Fatal("stored a recipient's kind-10050 list locally")
56 }
57}
58
59func TestNotificationRelayValidation(t *testing.T) {
60 if !validRelayURL("wss://inbox.example") || !validRelayURL("ws://localhost") {
61 t.Fatal("valid relay URL rejected")
62 }
63 if validRelayURL("https://inbox.example") || validRelayURL("relay.example") {
64 t.Fatal("non-relay URL accepted")
65 }
66 if !sameRelay("wss://relay.example/", "wss://relay.example") {
67 t.Fatal("trailing slash not normalized")
68 }
69}
70
71func TestNotificationDeliveryRequiresRecipientInboxList(t *testing.T) {
72 ctx := context.Background()
73 store, err := storage.Open(ctx, filepath.Join(t.TempDir(), "tenant.db"))
74 if err != nil {
75 t.Fatal(err)
76 }
77 defer store.Close()
78 secret, err := event.GenerateKey()
79 if err != nil {
80 t.Fatal(err)
81 }
82 recipient, err := event.PublicKey(secret)
83 if err != nil {
84 t.Fatal(err)
85 }
86 wrap := event.Event{CreatedAt: 10, Kind: event.KIND_WRAP, Tags: [][]string{{"p", recipient}}, Content: "cipher"}
87 if err := event.Sign(&wrap, secret); err != nil {
88 t.Fatal(err)
89 }
90 tenant := &Tenant{store: store}
91 if err := tenant.deliverNotification(ctx, wrap, recipient); err != nil {
92 t.Fatal(err)
93 }
94 handler := tenant.notificationHandlers()[notificationDelivery]
95 err = handler(ctx, work.Intent{Kind: notificationDelivery, EventID: wrap.ID, Target: recipient})
96 if err == nil {
97 t.Fatal("delivery without kind-10050 inbox should remain retryable")
98 }
99}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

  • https://012.run/npub1cq2s86qrtadf36eqq3epm38wmhdynrrcwxf84eldk3f94dkv7ttsrulrz5/tinyrelay.git

Refs