nip43_test.go raw
1 //go:build integration
2 // +build integration
3
4 package neo4j
5
6 import (
7 "testing"
8 "time"
9
10 "next.orly.dev/pkg/nostr/encoders/hex"
11 "next.orly.dev/pkg/nostr/interfaces/signer/p8k"
12 )
13
14 // All tests in this file use the shared testDB instance from testmain_test.go
15 // to avoid Neo4j authentication rate limiting from too many connections.
16
17 func TestNIP43_AddAndRemoveMember(t *testing.T) {
18 if testDB == nil {
19 t.Skip("Neo4j not available")
20 }
21
22 cleanTestDatabase()
23
24 signer, _ := p8k.New()
25 signer.Generate()
26 pubkey := signer.Pub()
27
28 // Add member
29 inviteCode := "test-invite-123"
30 if err := testDB.AddNIP43Member(pubkey, inviteCode); err != nil {
31 t.Fatalf("Failed to add NIP-43 member: %v", err)
32 }
33
34 // Check membership
35 isMember, err := testDB.IsNIP43Member(pubkey)
36 if err != nil {
37 t.Fatalf("Failed to check membership: %v", err)
38 }
39 if !isMember {
40 t.Fatal("Expected pubkey to be a member")
41 }
42
43 // Get membership details
44 membership, err := testDB.GetNIP43Membership(pubkey)
45 if err != nil {
46 t.Fatalf("Failed to get membership: %v", err)
47 }
48 if membership.InviteCode != inviteCode {
49 t.Fatalf("Invite code mismatch: got %s, expected %s", membership.InviteCode, inviteCode)
50 }
51
52 // Remove member
53 if err := testDB.RemoveNIP43Member(pubkey); err != nil {
54 t.Fatalf("Failed to remove member: %v", err)
55 }
56
57 // Verify no longer a member
58 isMember, _ = testDB.IsNIP43Member(pubkey)
59 if isMember {
60 t.Fatal("Expected pubkey to not be a member after removal")
61 }
62
63 t.Logf("✓ NIP-43 add and remove member works correctly")
64 }
65
66 func TestNIP43_GetAllMembers(t *testing.T) {
67 if testDB == nil {
68 t.Skip("Neo4j not available")
69 }
70
71 cleanTestDatabase()
72
73 // Add multiple members
74 var pubkeys [][]byte
75 for i := 0; i < 3; i++ {
76 signer, _ := p8k.New()
77 signer.Generate()
78 pubkey := signer.Pub()
79 pubkeys = append(pubkeys, pubkey)
80
81 if err := testDB.AddNIP43Member(pubkey, "invite"+string(rune('A'+i))); err != nil {
82 t.Fatalf("Failed to add member %d: %v", i, err)
83 }
84 }
85
86 // Get all members
87 members, err := testDB.GetAllNIP43Members()
88 if err != nil {
89 t.Fatalf("Failed to get all members: %v", err)
90 }
91
92 if len(members) != 3 {
93 t.Fatalf("Expected 3 members, got %d", len(members))
94 }
95
96 // Verify all added pubkeys are in the members list
97 memberMap := make(map[string]bool)
98 for _, m := range members {
99 memberMap[hex.Enc(m)] = true
100 }
101
102 for i, pk := range pubkeys {
103 if !memberMap[hex.Enc(pk)] {
104 t.Fatalf("Member %d not found in list", i)
105 }
106 }
107
108 t.Logf("✓ GetAllNIP43Members returned %d members", len(members))
109 }
110
111 func TestNIP43_InviteCode(t *testing.T) {
112 if testDB == nil {
113 t.Skip("Neo4j not available")
114 }
115
116 cleanTestDatabase()
117
118 // Store valid invite code (expires in 1 hour)
119 validCode := "valid-code-123"
120 expiresAt := time.Now().Add(1 * time.Hour)
121 if err := testDB.StoreInviteCode(validCode, expiresAt); err != nil {
122 t.Fatalf("Failed to store invite code: %v", err)
123 }
124
125 // Validate the code
126 isValid, err := testDB.ValidateInviteCode(validCode)
127 if err != nil {
128 t.Fatalf("Failed to validate invite code: %v", err)
129 }
130 if !isValid {
131 t.Fatal("Expected valid invite code to be valid")
132 }
133
134 // Test non-existent code
135 isValid, err = testDB.ValidateInviteCode("non-existent-code")
136 if err != nil {
137 t.Fatalf("Failed to validate non-existent code: %v", err)
138 }
139 if isValid {
140 t.Fatal("Expected non-existent code to be invalid")
141 }
142
143 // Delete the invite code
144 if err := testDB.DeleteInviteCode(validCode); err != nil {
145 t.Fatalf("Failed to delete invite code: %v", err)
146 }
147
148 // Verify code is no longer valid
149 isValid, _ = testDB.ValidateInviteCode(validCode)
150 if isValid {
151 t.Fatal("Expected deleted code to be invalid")
152 }
153
154 t.Logf("✓ NIP-43 invite code operations work correctly")
155 }
156
157 func TestNIP43_ExpiredInviteCode(t *testing.T) {
158 if testDB == nil {
159 t.Skip("Neo4j not available")
160 }
161
162 cleanTestDatabase()
163
164 // Store expired invite code (expired 1 hour ago)
165 expiredCode := "expired-code-123"
166 expiresAt := time.Now().Add(-1 * time.Hour)
167 if err := testDB.StoreInviteCode(expiredCode, expiresAt); err != nil {
168 t.Fatalf("Failed to store expired invite code: %v", err)
169 }
170
171 // Validate should return false for expired code
172 isValid, err := testDB.ValidateInviteCode(expiredCode)
173 if err != nil {
174 t.Fatalf("Failed to validate expired code: %v", err)
175 }
176 if isValid {
177 t.Fatal("Expected expired code to be invalid")
178 }
179
180 t.Logf("✓ Expired invite code correctly detected as invalid")
181 }
182
183 func TestNIP43_DuplicateMember(t *testing.T) {
184 if testDB == nil {
185 t.Skip("Neo4j not available")
186 }
187
188 cleanTestDatabase()
189
190 signer, _ := p8k.New()
191 signer.Generate()
192 pubkey := signer.Pub()
193
194 // Add member first time
195 if err := testDB.AddNIP43Member(pubkey, "invite1"); err != nil {
196 t.Fatalf("Failed to add member: %v", err)
197 }
198
199 // Add same member again (should not error, just update)
200 if err := testDB.AddNIP43Member(pubkey, "invite2"); err != nil {
201 t.Fatalf("Failed to re-add member: %v", err)
202 }
203
204 // Check membership still exists
205 isMember, _ := testDB.IsNIP43Member(pubkey)
206 if !isMember {
207 t.Fatal("Expected pubkey to still be a member")
208 }
209
210 // Get all members should have only 1 entry
211 members, _ := testDB.GetAllNIP43Members()
212 if len(members) != 1 {
213 t.Fatalf("Expected 1 member, got %d", len(members))
214 }
215
216 t.Logf("✓ Duplicate member handling works correctly")
217 }
218
219 func TestNIP43_MembershipPersistence(t *testing.T) {
220 if testDB == nil {
221 t.Skip("Neo4j not available")
222 }
223
224 cleanTestDatabase()
225
226 signer, _ := p8k.New()
227 signer.Generate()
228 pubkey := signer.Pub()
229
230 // Add member
231 inviteCode := "persistence-test"
232 if err := testDB.AddNIP43Member(pubkey, inviteCode); err != nil {
233 t.Fatalf("Failed to add member: %v", err)
234 }
235
236 // Get membership and verify all fields
237 membership, err := testDB.GetNIP43Membership(pubkey)
238 if err != nil {
239 t.Fatalf("Failed to get membership: %v", err)
240 }
241
242 if membership.InviteCode != inviteCode {
243 t.Fatalf("InviteCode mismatch")
244 }
245
246 if membership.AddedAt.IsZero() {
247 t.Fatal("AddedAt should not be zero")
248 }
249
250 // Verify the pubkey in membership matches
251 if hex.Enc(membership.Pubkey[:]) != hex.Enc(pubkey) {
252 t.Fatal("Pubkey mismatch in membership")
253 }
254
255 t.Logf("✓ NIP-43 membership persistence verified")
256 }
257