tinyrelayfile
tinyrelay/internal/configport/configport_test.go/

internal/configport/configport_test.go raw
1package configport
2
3import (
4 "context"
5 "strings"
6 "testing"
7
8 "github.com/FelineStateMachine/tinyrelay/internal/community"
9 "github.com/FelineStateMachine/tinyrelay/internal/policy"
10 "github.com/FelineStateMachine/tinyrelay/internal/storage"
11)
12
13func TestParsePlanOmittedAndEmptySections(t *testing.T) {
14 ctx := context.Background()
15 st, err := storage.Open(ctx, t.TempDir()+"/relay.db")
16 if err != nil {
17 t.Fatal(err)
18 }
19 defer st.Close()
20 owner := strings.Repeat("a", 64)
21 c, err := community.New(ctx, st, owner)
22 if err != nil {
23 t.Fatal(err)
24 }
25 cur := policy.Defaults(owner)
26 svc := New(ConfigStore{Store: st, Community: c, Policy: func() policy.Policy { return cur }})
27 doc, err := Parse([]byte(`{"format":"bind.ws/relay-config/2","policy":{"reads":"members"}}`))
28 if err != nil {
29 t.Fatal(err)
30 }
31 plan, err := svc.Plan(ctx, doc)
32 if err != nil {
33 t.Fatal(err)
34 }
35 if len(plan.Policy) == 0 {
36 t.Fatal("expected policy diff")
37 }
38 if len(plan.Members) != 0 {
39 t.Fatal("omitted members changed plan")
40 }
41 doc, err = Parse([]byte(`{"format":"bind.ws/relay-config/2","members":[]}`))
42 if err != nil {
43 t.Fatal(err)
44 }
45 plan, err = svc.Plan(ctx, doc)
46 if err != nil {
47 t.Fatal(err)
48 }
49 if !plan.MembersCleared {
50 t.Fatal("empty members must clear")
51 }
52}
53
54func TestApplyDryRunAndEconomyMigrationWarning(t *testing.T) {
55 ctx := context.Background()
56 st, err := storage.Open(ctx, t.TempDir()+"/relay.db")
57 if err != nil {
58 t.Fatal(err)
59 }
60 defer st.Close()
61 owner := strings.Repeat("a", 64)
62 _, err = community.New(ctx, st, owner)
63 if err != nil {
64 t.Fatal(err)
65 }
66 cur := policy.Defaults(owner)
67 changed := false
68 svc := New(ConfigStore{Store: st, Policy: func() policy.Policy { return cur }, OnApplied: func(policy.Policy) { changed = true }})
69 doc, err := Parse([]byte(`{"format":"bind.ws/relay-config/2","policy":{"fuel":10,"reads":"auth"}}`))
70 if err != nil {
71 t.Fatal(err)
72 }
73 if len(doc.Warnings) == 0 {
74 t.Fatal("expected removed economy warning")
75 }
76 if _, err := svc.Apply(ctx, doc, true); err != nil {
77 t.Fatal(err)
78 }
79 if changed {
80 t.Fatal("dry run mutated policy")
81 }
82}
83
84func TestApplyAtomicAcrossPolicyMetadataAndJobs(t *testing.T) {
85 ctx := context.Background()
86 st, err := storage.Open(ctx, t.TempDir()+"/relay.db")
87 if err != nil {
88 t.Fatal(err)
89 }
90 defer st.Close()
91 owner := strings.Repeat("a", 64)
92 _, err = community.New(ctx, st, owner)
93 if err != nil {
94 t.Fatal(err)
95 }
96 cur := policy.Defaults(owner)
97 if err := st.PutSetting(ctx, "policy", cur); err != nil {
98 t.Fatal(err)
99 }
100 svc := New(ConfigStore{Store: st, Policy: func() policy.Policy { return cur }})
101 if _, err := st.DB().Exec(`INSERT INTO config_jobs(id,recipe) VALUES('old','{"source":"old"}')`); err != nil {
102 t.Fatal(err)
103 }
104 if _, err := st.DB().Exec(`INSERT INTO community_members(pubkey,name,note,role,created_at) VALUES(?,?,?,?,?)`, strings.Repeat("b", 64), "old", "", "member", 1); err != nil {
105 t.Fatal(err)
106 }
107 doc, err := Parse([]byte(`{"format":"bind.ws/relay-config/2","policy":{"reads":"auth"},"members":[{"pubkey":"cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc","role":"member"}],"kinds":{"allow":[1],"block":[1]},"jobs":[{"id":"new","source":"new"}]}`))
108 if err != nil {
109 t.Fatal(err)
110 }
111 if _, err := svc.Apply(ctx, doc, false); err == nil {
112 t.Fatal("expected duplicate kind rule failure")
113 }
114 var got policy.Policy
115 if err := st.GetSetting(ctx, "policy", &got); err != nil {
116 t.Fatal(err)
117 }
118 if got.Reads != cur.Reads {
119 t.Fatalf("policy committed despite rollback: %q", got.Reads)
120 }
121 var jobs, members int
122 if err := st.DB().QueryRow(`SELECT count(*) FROM config_jobs WHERE id='old'`).Scan(&jobs); err != nil {
123 t.Fatal(err)
124 }
125 if err := st.DB().QueryRow(`SELECT count(*) FROM community_members WHERE pubkey=?`, strings.Repeat("b", 64)).Scan(&members); err != nil {
126 t.Fatal(err)
127 }
128 if jobs != 1 || members != 1 {
129 t.Fatalf("metadata committed despite rollback: jobs=%d members=%d", jobs, members)
130 }
131}
132
133func TestApplyJobsFeedsReplicationQueue(t *testing.T) {
134 ctx := context.Background()
135 st, err := storage.Open(ctx, t.TempDir()+"/relay.db")
136 if err != nil {
137 t.Fatal(err)
138 }
139 defer st.Close()
140 owner := strings.Repeat("a", 64)
141 if _, err := community.New(ctx, st, owner); err != nil {
142 t.Fatal(err)
143 }
144 cur := policy.Defaults(owner)
145 svc := New(ConfigStore{Store: st, Community: nil, Policy: func() policy.Policy { return cur }})
146 doc, err := Parse([]byte(`{"format":"bind.ws/relay-config/2","jobs":[{"id":"pull-1","kind":"pull","relays":["wss://relay.example"]}]}`))
147 if err != nil {
148 t.Fatal(err)
149 }
150 if _, err := svc.Apply(ctx, doc, false); err != nil {
151 t.Fatal(err)
152 }
153 var payload string
154 if err := st.DB().QueryRow(`SELECT payload FROM replication_jobs WHERE id='pull-1'`).Scan(&payload); err != nil {
155 t.Fatal(err)
156 }
157 if !strings.Contains(payload, `"kind":"pull"`) {
158 t.Fatalf("replication payload: %s", payload)
159 }
160}

About

ownerc01503e8035f
visibilitypublic
headd730679639bf

Maintainers

  • c01503e8035f owner
  • ba1b5beed5b5 agent hermes

Clone

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

Refs