get-indexes-for-event_test.go raw
1 package database
2
3 import (
4 "bytes"
5 "testing"
6
7 "next.orly.dev/pkg/lol/chk"
8 "github.com/minio/sha256-simd"
9 "next.orly.dev/pkg/database/indexes"
10 types2 "next.orly.dev/pkg/database/indexes/types"
11 "next.orly.dev/pkg/nostr/encoders/event"
12 "next.orly.dev/pkg/nostr/encoders/kind"
13 "next.orly.dev/pkg/nostr/encoders/tag"
14 "next.orly.dev/pkg/utils"
15 )
16
17 func TestGetIndexesForEvent(t *testing.T) {
18 t.Run("BasicEvent", testBasicEvent)
19 t.Run("EventWithTags", testEventWithTags)
20 t.Run("ErrorHandling", testErrorHandling)
21 }
22
23 // Helper function to verify that a specific index is included in the generated
24 // indexes
25 func verifyIndexIncluded(t *testing.T, idxs [][]byte, expectedIdx *indexes.T) {
26 // Marshal the expected index
27 buf := new(bytes.Buffer)
28 err := expectedIdx.MarshalWrite(buf)
29 if chk.E(err) {
30 t.Fatalf("Failed to marshal expected index: %v", err)
31 }
32
33 expectedBytes := buf.Bytes()
34 found := false
35
36 for _, idx := range idxs {
37 if utils.FastEqual(idx, expectedBytes) {
38 found = true
39 break
40 }
41 }
42
43 if !found {
44 t.Errorf("Expected index not found in generated indexes")
45 t.Errorf("Expected: %v", expectedBytes)
46 t.Errorf("Generated indexes: %d indexes", len(idxs))
47 }
48 }
49
50 // Test basic event with minimal fields
51 func testBasicEvent(t *testing.T) {
52 // Create a basic event
53 ev := event.New()
54
55 // Set ID
56 id := make([]byte, sha256.Size)
57 for i := range id {
58 id[i] = byte(i)
59 }
60 ev.ID = id
61
62 // Set Pubkey
63 pubkey := make([]byte, 32)
64 for i := range pubkey {
65 pubkey[i] = byte(i + 1)
66 }
67 ev.Pubkey = pubkey
68
69 // Set CreatedAt
70 ev.CreatedAt = 12345
71
72 // Set Kind
73 ev.Kind = kind.TextNote.K
74
75 // Set Content
76 ev.Content = []byte("Test content")
77
78 // Generate indexes
79 serial := uint64(1)
80 idxs, err := GetIndexesForEvent(ev, serial)
81 if chk.E(err) {
82 t.Fatalf("GetIndexesForEvent failed: %v", err)
83 }
84
85 // Verify the number of indexes (should be 8 for a basic event without tags: 6 base + 2 word indexes from content)
86 if len(idxs) != 8 {
87 t.Fatalf("Expected 8 indexes, got %d", len(idxs))
88 }
89
90 // Create and verify the expected indexes
91
92 // 1. ID index
93 ser := new(types2.Uint40)
94 err = ser.Set(serial)
95 if chk.E(err) {
96 t.Fatalf("Failed to create Uint40: %v", err)
97 }
98
99 idHash := new(types2.IdHash)
100 err = idHash.FromId(ev.ID)
101 if chk.E(err) {
102 t.Fatalf("Failed to create IdHash: %v", err)
103 }
104 idIndex := indexes.IdEnc(idHash, ser)
105 verifyIndexIncluded(t, idxs, idIndex)
106
107 // 2. FullIdPubkey index
108 fullID := new(types2.Id)
109 err = fullID.FromId(ev.ID)
110 if chk.E(err) {
111 t.Fatalf("Failed to create ID: %v", err)
112 }
113
114 pubHash := new(types2.PubHash)
115 err = pubHash.FromPubkey(ev.Pubkey)
116 if chk.E(err) {
117 t.Fatalf("Failed to create PubHash: %v", err)
118 }
119
120 createdAt := new(types2.Uint64)
121 createdAt.Set(uint64(ev.CreatedAt))
122
123 idPubkeyIndex := indexes.FullIdPubkeyEnc(ser, fullID, pubHash, createdAt)
124 verifyIndexIncluded(t, idxs, idPubkeyIndex)
125
126 // 3. CreatedAt index
127 createdAtIndex := indexes.CreatedAtEnc(createdAt, ser)
128 verifyIndexIncluded(t, idxs, createdAtIndex)
129
130 // 4. Pubkey index
131 pubkeyIndex := indexes.PubkeyEnc(pubHash, createdAt, ser)
132 verifyIndexIncluded(t, idxs, pubkeyIndex)
133
134 // 5. Kind index
135 kind := new(types2.Uint16)
136 kind.Set(ev.Kind)
137
138 kindIndex := indexes.KindEnc(kind, createdAt, ser)
139 verifyIndexIncluded(t, idxs, kindIndex)
140
141 // 6. KindPubkey index
142 kindPubkeyIndex := indexes.KindPubkeyEnc(kind, pubHash, createdAt, ser)
143 verifyIndexIncluded(t, idxs, kindPubkeyIndex)
144 }
145
146 // Test event with tags
147 func testEventWithTags(t *testing.T) {
148 // Create an event with tags
149 ev := event.New()
150
151 // Set ID
152 id := make([]byte, sha256.Size)
153 for i := range id {
154 id[i] = byte(i)
155 }
156 ev.ID = id
157
158 // Set Pubkey
159 pubkey := make([]byte, 32)
160 for i := range pubkey {
161 pubkey[i] = byte(i + 1)
162 }
163 ev.Pubkey = pubkey
164
165 // Set CreatedAt
166 ev.CreatedAt = 12345
167
168 // Set Kind
169 ev.Kind = kind.TextNote.K // TextNote kind
170
171 // Set Content
172 ev.Content = []byte("Test content with tags")
173
174 // Add tags
175 ev.Tags = tag.NewS()
176
177 // Add e tag (event reference)
178 eTagKey := "e"
179 eTagValue := "abcdef1234567890"
180 eTag := tag.NewFromAny(eTagKey, eTagValue)
181 *ev.Tags = append(*ev.Tags, eTag)
182
183 // Add p tag (pubkey reference)
184 pTagKey := "p"
185 pTagValue := "0123456789abcdef"
186 pTag := tag.NewFromAny(pTagKey, pTagValue)
187 *ev.Tags = append(*ev.Tags, pTag)
188
189 // Generate indexes
190 serial := uint64(2)
191 idxs, err := GetIndexesForEvent(ev, serial)
192 if chk.E(err) {
193 t.Fatalf("GetIndexesForEvent failed: %v", err)
194 }
195
196 // Verify the number of indexes (should be 19 for an event with 2 tags)
197 // 6 basic indexes + 3 word indexes from content ("test", "content", "tags" — "with" is a stopword)
198 // + 4 indexes per tag (TagPubkey, Tag, TagKind, TagKindPubkey) = 8
199 // + 2 word indexes from tag values ("abcdef1234567890", "0123456789abcdef")
200 if len(idxs) != 19 {
201 t.Fatalf("Expected 19 indexes, got %d", len(idxs))
202 }
203
204 // Create and verify the basic indexes (same as in testBasicEvent)
205 ser := new(types2.Uint40)
206 err = ser.Set(serial)
207 if chk.E(err) {
208 t.Fatalf("Failed to create Uint40: %v", err)
209 }
210
211 idHash := new(types2.IdHash)
212 err = idHash.FromId(ev.ID)
213 if chk.E(err) {
214 t.Fatalf("Failed to create IdHash: %v", err)
215 }
216
217 // Verify one of the tag-related indexes (e tag)
218 pubHash := new(types2.PubHash)
219 err = pubHash.FromPubkey(ev.Pubkey)
220 if chk.E(err) {
221 t.Fatalf("Failed to create PubHash: %v", err)
222 }
223
224 createdAt := new(types2.Uint64)
225 createdAt.Set(uint64(ev.CreatedAt))
226
227 // Create tag key and value for e tag
228 eKey := new(types2.Letter)
229 eKey.Set('e')
230
231 eValueHash := new(types2.Ident)
232 eValueHash.FromIdent([]byte("abcdef1234567890"))
233
234 // Verify TagPubkey index for e tag
235 pubkeyTagIndex := indexes.TagPubkeyEnc(
236 eKey, eValueHash, pubHash, createdAt, ser,
237 )
238 verifyIndexIncluded(t, idxs, pubkeyTagIndex)
239
240 // Verify Tag index for e tag
241 tagIndex := indexes.TagEnc(
242 eKey, eValueHash, createdAt, ser,
243 )
244 verifyIndexIncluded(t, idxs, tagIndex)
245
246 // Verify TagKind index for e tag
247 kind := new(types2.Uint16)
248 kind.Set(ev.Kind)
249
250 kindTagIndex := indexes.TagKindEnc(eKey, eValueHash, kind, createdAt, ser)
251 verifyIndexIncluded(t, idxs, kindTagIndex)
252
253 // Verify TagKindPubkey index for e tag
254 kindPubkeyTagIndex := indexes.TagKindPubkeyEnc(
255 eKey, eValueHash, kind, pubHash, createdAt, ser,
256 )
257 verifyIndexIncluded(t, idxs, kindPubkeyTagIndex)
258 }
259
260 // Test error handling
261 func testErrorHandling(t *testing.T) {
262 // Test with invalid serial number (too large for Uint40)
263 ev := event.New()
264
265 // Set ID
266 id := make([]byte, sha256.Size)
267 for i := range id {
268 id[i] = byte(i)
269 }
270 ev.ID = id
271
272 // Set Pubkey
273 pubkey := make([]byte, 32)
274 for i := range pubkey {
275 pubkey[i] = byte(i + 1)
276 }
277 ev.Pubkey = pubkey
278
279 // Set CreatedAt
280 ev.CreatedAt = 12345
281
282 // Set Kind
283 ev.Kind = kind.TextNote.K
284
285 // Set Content
286 ev.Content = []byte("Test content")
287
288 // Use an invalid serial number (too large for Uint40)
289 invalidSerial := uint64(1) << 40 // 2^40, which is too large for Uint40
290
291 // Generate indexes
292 idxs, err := GetIndexesForEvent(ev, invalidSerial)
293
294 // Verify that an error was returned
295 if err == nil {
296 t.Fatalf("Expected error for invalid serial number, got nil")
297 }
298
299 // Verify that idxs is nil when an error occurs
300 if idxs != nil {
301 t.Fatalf("Expected nil idxs when error occurs, got %v", idxs)
302 }
303
304 // Note: We don't test with nil event as it causes a panic
305 // The function doesn't have nil checks, which is a potential improvement
306 }
307