package arbitrum import ( "context" "fmt" "testing" "time" "github.com/fraktal/mev-beta/internal/logger" ) func TestRPCManagerRoundRobin(t *testing.T) { log := &logger.Logger{} manager := NewRPCManager(log) if len(manager.endpoints) != 0 { t.Errorf("Expected 0 endpoints, got %d", len(manager.endpoints)) } } func TestRPCManagerHealthTracking(t *testing.T) { log := &logger.Logger{} _ = NewRPCManager(log) // Create health tracker health := &RPCEndpointHealth{ URL: "https://test.rpc.io", } // Record success health.RecordSuccess(50 * time.Millisecond) success, failure, consecutive, healthy := health.GetStats() if success != 1 { t.Errorf("Expected 1 success, got %d", success) } if failure != 0 { t.Errorf("Expected 0 failures, got %d", failure) } if !healthy { t.Errorf("Expected healthy=true, got %v", healthy) } if consecutive != 0 { t.Errorf("Expected 0 consecutive failures, got %d", consecutive) } } func TestRPCManagerConsecutiveFailures(t *testing.T) { logger := &logger.Logger{} _ = logger health := &RPCEndpointHealth{ URL: "https://test.rpc.io", } // Record 3 failures for i := 0; i < 3; i++ { health.RecordFailure() } _, failure, consecutive, healthy := health.GetStats() if failure != 3 { t.Errorf("Expected 3 failures, got %d", failure) } if consecutive != 3 { t.Errorf("Expected 3 consecutive failures, got %d", consecutive) } if healthy { t.Errorf("Expected healthy=false after 3 consecutive failures, got %v", healthy) } // Record a success - should reset consecutive failures health.RecordSuccess(100 * time.Millisecond) _, _, consecutive, healthy = health.GetStats() if consecutive != 0 { t.Errorf("Expected 0 consecutive failures after success, got %d", consecutive) } if !healthy { t.Errorf("Expected healthy=true after success, got %v", healthy) } } func TestRPCManagerRotationSelection(t *testing.T) { log := &logger.Logger{} manager := NewRPCManager(log) // Test with nil endpoints - should fail _, _, err := manager.GetNextClient(context.Background()) if err == nil { t.Errorf("Expected error for empty endpoints, got nil") } } func TestRPCEndpointHealthStats(t *testing.T) { log := &logger.Logger{} _ = NewRPCManager(log) // Add some health data health := &RPCEndpointHealth{ URL: "https://test.rpc.io", } // Record multiple operations health.RecordSuccess(45 * time.Millisecond) health.RecordSuccess(55 * time.Millisecond) health.RecordFailure() health.RecordSuccess(50 * time.Millisecond) success, failure, consecutive, healthy := health.GetStats() if success != 3 { t.Errorf("Expected 3 successes, got %d", success) } if failure != 1 { t.Errorf("Expected 1 failure, got %d", failure) } if !healthy { t.Errorf("Expected healthy=true after recovery, got %v", healthy) } if consecutive != 0 { t.Errorf("Expected 0 consecutive failures after recovery, got %d", consecutive) } } func TestRPCManagerStats(t *testing.T) { logger := &logger.Logger{} manager := NewRPCManager(logger) stats := manager.GetStats() if stats["total_endpoints"] != 0 { t.Errorf("Expected 0 endpoints, got %d", stats["total_endpoints"]) } totalRequests, ok := stats["total_requests"] if !ok || totalRequests.(int64) != 0 { t.Errorf("Expected 0 total requests") } } func TestRoundRobinSelection(t *testing.T) { logger := &logger.Logger{} manager := NewRPCManager(logger) manager.SetRotationPolicy(RoundRobin) // Simulate 10 selections for i := 0; i < 10; i++ { idx := manager.selectRoundRobin() if idx < 0 { t.Errorf("Got negative index %d on iteration %d", idx, i) } } } func TestRotationPolicySetting(t *testing.T) { logger := &logger.Logger{} manager := NewRPCManager(logger) manager.SetRotationPolicy(HealthAware) if manager.rotationPolicy != HealthAware { t.Errorf("Expected HealthAware policy, got %s", manager.rotationPolicy) } manager.SetRotationPolicy(LeastFailures) if manager.rotationPolicy != LeastFailures { t.Errorf("Expected LeastFailures policy, got %s", manager.rotationPolicy) } manager.SetRotationPolicy(RoundRobin) if manager.rotationPolicy != RoundRobin { t.Errorf("Expected RoundRobin policy, got %s", manager.rotationPolicy) } } // BenchmarkRoundRobinSelection benchmarks the round-robin selection func BenchmarkRoundRobinSelection(b *testing.B) { logger := &logger.Logger{} manager := NewRPCManager(logger) manager.SetRotationPolicy(RoundRobin) b.ResetTimer() for i := 0; i < b.N; i++ { _ = manager.selectRoundRobin() } } // Example demonstrates basic RPC Manager usage func Example() { logger := &logger.Logger{} manager := NewRPCManager(logger) // Set rotation policy manager.SetRotationPolicy(HealthAware) // Record some operations health1 := &RPCEndpointHealth{URL: "https://rpc1.io"} health1.RecordSuccess(50 * time.Millisecond) health1.RecordSuccess(45 * time.Millisecond) health2 := &RPCEndpointHealth{URL: "https://rpc2.io"} health2.RecordSuccess(100 * time.Millisecond) health2.RecordFailure() fmt.Printf("Endpoint 1: Health tracking initialized\n") fmt.Printf("Endpoint 2: Health tracking initialized\n") // Output: // Endpoint 1: Health tracking initialized // Endpoint 2: Health tracking initialized }