Files
next.orly.dev/pkg/spider/spider_test.go
mleku a4fc3d8d9b
Some checks failed
Go / build (push) Has been cancelled
Go / release (push) Has been cancelled
Implement spider functionality for event synchronization
- Introduced a new `spider` package to manage connections to admin relays and synchronize events for followed pubkeys.
- Added configuration options for spider mode in the application settings, allowing for different operational modes (e.g., follows).
- Implemented callback mechanisms to dynamically retrieve admin relays and follow lists.
- Enhanced the main application to initialize and manage the spider, including starting and stopping its operation.
- Added tests to validate spider creation, callbacks, and operational behavior.
- Bumped version to v0.17.14.
2025-10-22 22:24:21 +01:00

245 lines
5.6 KiB
Go

package spider
import (
"context"
"os"
"testing"
"time"
"next.orly.dev/pkg/database"
)
func TestSpiderCreation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Create a temporary database for testing
tempDir, err := os.MkdirTemp("", "spider-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
db, err := database.New(ctx, cancel, tempDir, "error")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer db.Close()
// Test spider creation
spider, err := New(ctx, db, nil, "follows")
if err != nil {
t.Fatalf("Failed to create spider: %v", err)
}
if spider == nil {
t.Fatal("Spider is nil")
}
// Test that spider is not running initially
spider.mu.RLock()
running := spider.running
spider.mu.RUnlock()
if running {
t.Error("Spider should not be running initially")
}
}
func TestSpiderCallbacks(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Create a temporary database for testing
tempDir, err := os.MkdirTemp("", "spider-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
db, err := database.New(ctx, cancel, tempDir, "error")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer db.Close()
spider, err := New(ctx, db, nil, "follows")
if err != nil {
t.Fatalf("Failed to create spider: %v", err)
}
// Test callback setup
testRelays := []string{"wss://relay1.example.com", "wss://relay2.example.com"}
testPubkeys := [][]byte{{1, 2, 3}, {4, 5, 6}}
spider.SetCallbacks(
func() []string { return testRelays },
func() [][]byte { return testPubkeys },
)
// Verify callbacks are set
spider.mu.RLock()
hasCallbacks := spider.getAdminRelays != nil && spider.getFollowList != nil
spider.mu.RUnlock()
if !hasCallbacks {
t.Error("Callbacks should be set")
}
// Test that start fails without callbacks being set first
spider2, err := New(ctx, db, nil, "follows")
if err != nil {
t.Fatalf("Failed to create second spider: %v", err)
}
err = spider2.Start()
if err == nil {
t.Error("Start should fail when callbacks are not set")
}
}
func TestSpiderModeValidation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Create a temporary database for testing
tempDir, err := os.MkdirTemp("", "spider-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
db, err := database.New(ctx, cancel, tempDir, "error")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer db.Close()
// Test valid mode
spider, err := New(ctx, db, nil, "follows")
if err != nil {
t.Fatalf("Failed to create spider with valid mode: %v", err)
}
if spider == nil {
t.Fatal("Spider should not be nil for valid mode")
}
// Test invalid mode
_, err = New(ctx, db, nil, "invalid")
if err == nil {
t.Error("Should fail with invalid mode")
}
// Test none mode (should succeed but be a no-op)
spider2, err := New(ctx, db, nil, "none")
if err != nil {
t.Errorf("Should succeed with 'none' mode: %v", err)
}
if spider2 == nil {
t.Error("Spider should not be nil for 'none' mode")
}
// Test that 'none' mode doesn't require callbacks
err = spider2.Start()
if err != nil {
t.Errorf("'none' mode should start without callbacks: %v", err)
}
}
func TestSpiderBatching(t *testing.T) {
// Test batch creation logic
followList := make([][]byte, 50) // 50 pubkeys
for i := range followList {
followList[i] = make([]byte, 32)
for j := range followList[i] {
followList[i][j] = byte(i)
}
}
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
rc := &RelayConnection{
url: "wss://test.relay.com",
ctx: ctx,
}
batches := rc.createBatches(followList)
// Should create 3 batches: 20, 20, 10
expectedBatches := 3
if len(batches) != expectedBatches {
t.Errorf("Expected %d batches, got %d", expectedBatches, len(batches))
}
// Check batch sizes
if len(batches[0]) != BatchSize {
t.Errorf("First batch should have %d pubkeys, got %d", BatchSize, len(batches[0]))
}
if len(batches[1]) != BatchSize {
t.Errorf("Second batch should have %d pubkeys, got %d", BatchSize, len(batches[1]))
}
if len(batches[2]) != 10 {
t.Errorf("Third batch should have 10 pubkeys, got %d", len(batches[2]))
}
}
func TestSpiderStartStop(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
// Create a temporary database for testing
tempDir, err := os.MkdirTemp("", "spider-test-*")
if err != nil {
t.Fatalf("Failed to create temp dir: %v", err)
}
defer os.RemoveAll(tempDir)
db, err := database.New(ctx, cancel, tempDir, "error")
if err != nil {
t.Fatalf("Failed to create test database: %v", err)
}
defer db.Close()
spider, err := New(ctx, db, nil, "follows")
if err != nil {
t.Fatalf("Failed to create spider: %v", err)
}
// Set up callbacks
spider.SetCallbacks(
func() []string { return []string{"wss://test.relay.com"} },
func() [][]byte { return [][]byte{{1, 2, 3}} },
)
// Test start
err = spider.Start()
if err != nil {
t.Fatalf("Failed to start spider: %v", err)
}
// Verify spider is running
spider.mu.RLock()
running := spider.running
spider.mu.RUnlock()
if !running {
t.Error("Spider should be running after start")
}
// Test stop
spider.Stop()
// Give it a moment to stop
time.Sleep(100 * time.Millisecond)
// Verify spider is stopped
spider.mu.RLock()
running = spider.running
spider.mu.RUnlock()
if running {
t.Error("Spider should not be running after stop")
}
}