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