bridge_test.go raw
1 package bridge
2
3 import (
4 "context"
5 "sync"
6 "testing"
7 "time"
8
9 "next.orly.dev/pkg/nostr/crypto/keys"
10 "github.com/stretchr/testify/assert"
11 "github.com/stretchr/testify/require"
12 )
13
14 // Ensure Bridge wg field is accessible for testing.
15 var _ = (*sync.WaitGroup)(nil)
16
17 func TestBridge_StartStop(t *testing.T) {
18 sk, err := keys.GenerateSecretKey()
19 require.NoError(t, err)
20
21 cfg := &Config{
22 NSEC: keys.GenerateSecretKeyHex(),
23 DataDir: t.TempDir(),
24 }
25 _ = sk // we use GenerateSecretKeyHex for a quick hex key
26
27 b := New(cfg, nil)
28
29 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
30 defer cancel()
31
32 require.NoError(t, b.Start(ctx))
33 assert.NotNil(t, b.Signer())
34 assert.Len(t, b.Signer().Pub(), 32)
35 assert.Equal(t, IdentityFromConfig, b.IdentitySource())
36
37 b.Stop()
38 }
39
40 func TestBridge_StartWithDBGetter(t *testing.T) {
41 sk, err := keys.GenerateSecretKey()
42 require.NoError(t, err)
43
44 cfg := &Config{
45 DataDir: t.TempDir(),
46 }
47
48 dbGetter := func() ([]byte, error) {
49 return sk, nil
50 }
51
52 b := New(cfg, dbGetter)
53
54 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
55 defer cancel()
56
57 require.NoError(t, b.Start(ctx))
58 assert.Equal(t, IdentityFromDB, b.IdentitySource())
59 assert.NotNil(t, b.Signer())
60
61 b.Stop()
62 }
63
64 func TestBridge_StartFileGeneration(t *testing.T) {
65 cfg := &Config{
66 DataDir: t.TempDir(),
67 }
68
69 b := New(cfg, nil)
70
71 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
72 defer cancel()
73
74 require.NoError(t, b.Start(ctx))
75 assert.Equal(t, IdentityFromFile, b.IdentitySource())
76 assert.NotNil(t, b.Signer())
77 assert.Len(t, b.Signer().Pub(), 32)
78
79 b.Stop()
80 }
81
82 func TestBridge_StartWithDomain(t *testing.T) {
83 cfg := &Config{
84 NSEC: keys.GenerateSecretKeyHex(),
85 DataDir: t.TempDir(),
86 Domain: "bridge.example.com",
87 }
88
89 b := New(cfg, nil)
90
91 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
92 defer cancel()
93
94 require.NoError(t, b.Start(ctx))
95 b.Stop()
96 }
97
98 func TestBridge_StopWithoutStart(t *testing.T) {
99 cfg := &Config{
100 DataDir: t.TempDir(),
101 }
102 b := New(cfg, nil)
103 // Should not panic
104 b.Stop()
105 }
106
107 func TestBridge_RelayWatchLoop(t *testing.T) {
108 // relayWatchLoop just blocks on ctx.Done — verify it exits cleanly
109 cfg := &Config{
110 NSEC: keys.GenerateSecretKeyHex(),
111 DataDir: t.TempDir(),
112 }
113 b := New(cfg, nil)
114 b.ctx, b.cancel = context.WithCancel(context.Background())
115 b.wg.Add(1)
116 go b.relayWatchLoop()
117
118 // Cancel should cause relayWatchLoop to exit
119 b.cancel()
120 b.wg.Wait() // will hang if relayWatchLoop doesn't exit
121 }
122
123 func TestIdentitySourceString(t *testing.T) {
124 tests := []struct {
125 source IdentitySource
126 want string
127 }{
128 {IdentityFromConfig, "config"},
129 {IdentityFromDB, "database"},
130 {IdentityFromFile, "file"},
131 {IdentitySource(99), "unknown"},
132 }
133 for _, tt := range tests {
134 got := identitySourceString(tt.source)
135 if got != tt.want {
136 t.Errorf("identitySourceString(%d) = %q, want %q", tt.source, got, tt.want)
137 }
138 }
139 }
140
141 func TestBridge_StartWithRelayURL(t *testing.T) {
142 // Starting with a RelayURL that can't connect should fail
143 cfg := &Config{
144 NSEC: keys.GenerateSecretKeyHex(),
145 DataDir: t.TempDir(),
146 RelayURL: "wss://nonexistent.example.com",
147 }
148
149 b := New(cfg, nil)
150
151 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
152 defer cancel()
153
154 err := b.Start(ctx)
155 if err == nil {
156 b.Stop()
157 t.Fatal("expected error connecting to nonexistent relay")
158 }
159 }
160
161 func TestBridge_StartBadDataDir(t *testing.T) {
162 cfg := &Config{
163 NSEC: keys.GenerateSecretKeyHex(),
164 DataDir: "/dev/null/impossible/path",
165 }
166
167 b := New(cfg, nil)
168
169 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
170 defer cancel()
171
172 err := b.Start(ctx)
173 if err == nil {
174 b.Stop()
175 t.Fatal("expected error for impossible data dir")
176 }
177 }
178
179 func TestBridge_StartInvalidNSEC(t *testing.T) {
180 cfg := &Config{
181 NSEC: "nsecINVALID",
182 DataDir: t.TempDir(),
183 }
184
185 b := New(cfg, nil)
186
187 ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
188 defer cancel()
189
190 err := b.Start(ctx)
191 if err == nil {
192 b.Stop()
193 t.Fatal("expected error from invalid NSEC")
194 }
195 }
196
197 func TestBridge_StopWithRelay(t *testing.T) {
198 // Test Stop when relay is set but not connected (just Close on RelayConn)
199 cfg := &Config{
200 NSEC: keys.GenerateSecretKeyHex(),
201 DataDir: t.TempDir(),
202 }
203
204 b := New(cfg, nil)
205
206 ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
207 defer cancel()
208
209 require.NoError(t, b.Start(ctx))
210
211 // Manually set relay to test Stop path
212 b.relay = NewRelayConn("wss://example.com", nil)
213
214 b.Stop()
215 }
216