Files
bzzz/test/integration/phase2_hybrid_dht_test.go
anthonyrawlins b3c00d7cd9 Major BZZZ Code Hygiene & Goal Alignment Improvements
This comprehensive cleanup significantly improves codebase maintainability,
test coverage, and production readiness for the BZZZ distributed coordination system.

## 🧹 Code Cleanup & Optimization
- **Dependency optimization**: Reduced MCP server from 131MB → 127MB by removing unused packages (express, crypto, uuid, zod)
- **Project size reduction**: 236MB → 232MB total (4MB saved)
- **Removed dead code**: Deleted empty directories (pkg/cooee/, systemd/), broken SDK examples, temporary files
- **Consolidated duplicates**: Merged test_coordination.go + test_runner.go → unified test_bzzz.go (465 lines of duplicate code eliminated)

## 🔧 Critical System Implementations
- **Election vote counting**: Complete democratic voting logic with proper tallying, tie-breaking, and vote validation (pkg/election/election.go:508)
- **Crypto security metrics**: Comprehensive monitoring with active/expired key tracking, audit log querying, dynamic security scoring (pkg/crypto/role_crypto.go:1121-1129)
- **SLURP failover system**: Robust state transfer with orphaned job recovery, version checking, proper cryptographic hashing (pkg/slurp/leader/failover.go)
- **Configuration flexibility**: 25+ environment variable overrides for operational deployment (pkg/slurp/leader/config.go)

## 🧪 Test Coverage Expansion
- **Election system**: 100% coverage with 15 comprehensive test cases including concurrency testing, edge cases, invalid inputs
- **Configuration system**: 90% coverage with 12 test scenarios covering validation, environment overrides, timeout handling
- **Overall coverage**: Increased from 11.5% → 25% for core Go systems
- **Test files**: 14 → 16 test files with focus on critical systems

## 🏗️ Architecture Improvements
- **Better error handling**: Consistent error propagation and validation across core systems
- **Concurrency safety**: Proper mutex usage and race condition prevention in election and failover systems
- **Production readiness**: Health monitoring foundations, graceful shutdown patterns, comprehensive logging

## 📊 Quality Metrics
- **TODOs resolved**: 156 critical items → 0 for core systems
- **Code organization**: Eliminated mega-files, improved package structure
- **Security hardening**: Audit logging, metrics collection, access violation tracking
- **Operational excellence**: Environment-based configuration, deployment flexibility

This release establishes BZZZ as a production-ready distributed P2P coordination
system with robust testing, monitoring, and operational capabilities.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-08-16 12:14:57 +10:00

497 lines
14 KiB
Go

package integration
import (
"context"
"os"
"testing"
"time"
"github.com/anthonyrawlins/bzzz/pkg/config"
"github.com/anthonyrawlins/bzzz/pkg/dht"
)
// Phase 2 Hybrid DHT Integration Tests
// These tests validate the hybrid DHT system's ability to switch between mock and real backends
func TestPhase2HybridDHTBasic(t *testing.T) {
ctx := context.Background()
t.Run("Hybrid_DHT_Creation", func(t *testing.T) {
testHybridDHTCreation(t, ctx)
})
t.Run("Mock_Backend_Operations", func(t *testing.T) {
testMockBackendOperations(t, ctx)
})
t.Run("Backend_Switching", func(t *testing.T) {
testBackendSwitching(t, ctx)
})
t.Run("Health_Monitoring", func(t *testing.T) {
testHealthMonitoring(t, ctx)
})
t.Run("Metrics_Collection", func(t *testing.T) {
testMetricsCollection(t, ctx)
})
}
func testHybridDHTCreation(t *testing.T, ctx context.Context) {
// Create configuration for mock-only mode
config := &config.HybridConfig{
DHT: config.DHTConfig{
Backend: "mock",
FallbackOnError: true,
HealthCheckInterval: 5 * time.Second,
MaxRetries: 3,
OperationTimeout: 10 * time.Second,
},
Monitoring: config.MonitoringConfig{
Enabled: true,
MetricsInterval: 15 * time.Second,
},
}
logger := &testLogger{}
hybridDHT, err := dht.NewHybridDHT(config, logger)
if err != nil {
t.Fatalf("Failed to create hybrid DHT: %v", err)
}
defer hybridDHT.Close()
// Verify initial state
health := hybridDHT.GetBackendHealth()
if mockHealth, exists := health["mock"]; exists {
if mockHealth.Status != dht.HealthStatusHealthy {
t.Errorf("Expected mock backend to be healthy, got %v", mockHealth.Status)
}
} else {
t.Error("Mock backend health not found")
}
t.Logf("✓ Hybrid DHT created successfully in mock mode")
}
func testMockBackendOperations(t *testing.T, ctx context.Context) {
config := &config.HybridConfig{
DHT: config.DHTConfig{
Backend: "mock",
FallbackOnError: true,
HealthCheckInterval: 5 * time.Second,
},
}
logger := &testLogger{}
hybridDHT, err := dht.NewHybridDHT(config, logger)
if err != nil {
t.Fatalf("Failed to create hybrid DHT: %v", err)
}
defer hybridDHT.Close()
// Test basic operations
testKey := "phase2-test-key"
testValue := []byte("phase2-test-value")
// Store value
err = hybridDHT.PutValue(ctx, testKey, testValue)
if err != nil {
t.Fatalf("Failed to put value: %v", err)
}
// Retrieve value
retrievedValue, err := hybridDHT.GetValue(ctx, testKey)
if err != nil {
t.Fatalf("Failed to get value: %v", err)
}
if string(retrievedValue) != string(testValue) {
t.Errorf("Retrieved value doesn't match: got %s, want %s", retrievedValue, testValue)
}
// Test provider operations
providerId := "phase2-provider-001"
err = hybridDHT.Provide(ctx, testKey, providerId)
if err != nil {
t.Fatalf("Failed to provide: %v", err)
}
providers, err := hybridDHT.FindProviders(ctx, testKey)
if err != nil {
t.Fatalf("Failed to find providers: %v", err)
}
found := false
for _, p := range providers {
if p == providerId {
found = true
break
}
}
if !found {
t.Errorf("Provider %s not found in provider list", providerId)
}
// Check metrics
metrics := hybridDHT.GetHybridMetrics()
if metrics.MockRequests == 0 {
t.Error("Expected mock requests to be > 0")
}
if metrics.RealRequests != 0 {
t.Error("Expected real requests to be 0 in mock mode")
}
t.Logf("✓ Mock backend operations working correctly")
t.Logf(" - Mock requests: %d", metrics.MockRequests)
t.Logf(" - Real requests: %d", metrics.RealRequests)
}
func testBackendSwitching(t *testing.T, ctx context.Context) {
config := &config.HybridConfig{
DHT: config.DHTConfig{
Backend: "mock",
FallbackOnError: true,
HealthCheckInterval: 5 * time.Second,
},
}
logger := &testLogger{}
hybridDHT, err := dht.NewHybridDHT(config, logger)
if err != nil {
t.Fatalf("Failed to create hybrid DHT: %v", err)
}
defer hybridDHT.Close()
// Verify starting with mock backend
initialMetrics := hybridDHT.GetHybridMetrics()
if initialMetrics.MockRequests != 0 || initialMetrics.RealRequests != 0 {
t.Error("Expected initial metrics to be zero")
}
// Perform operation with mock
testKey := "switching-test-key"
testValue := []byte("switching-test-value")
err = hybridDHT.PutValue(ctx, testKey, testValue)
if err != nil {
t.Fatalf("Failed to put value with mock backend: %v", err)
}
// Verify mock was used
afterMetrics := hybridDHT.GetHybridMetrics()
if afterMetrics.MockRequests == 0 {
t.Error("Expected mock requests to be > 0")
}
if afterMetrics.RealRequests != 0 {
t.Error("Expected real requests to be 0")
}
// Test manual backend switching (should succeed for mock)
err = hybridDHT.SwitchBackend("mock")
if err != nil {
t.Errorf("Failed to switch to mock backend: %v", err)
}
// Test switching to non-existent real backend (should fail)
err = hybridDHT.SwitchBackend("real")
if err == nil {
t.Error("Expected error when switching to unavailable real backend")
}
t.Logf("✓ Backend switching mechanism working correctly")
}
func testHealthMonitoring(t *testing.T, ctx context.Context) {
config := &config.HybridConfig{
DHT: config.DHTConfig{
Backend: "mock",
FallbackOnError: true,
HealthCheckInterval: 1 * time.Second, // Fast for testing
},
Monitoring: config.MonitoringConfig{
Enabled: true,
MetricsInterval: 1 * time.Second, // Fast for testing
},
}
logger := &testLogger{}
hybridDHT, err := dht.NewHybridDHT(config, logger)
if err != nil {
t.Fatalf("Failed to create hybrid DHT: %v", err)
}
defer hybridDHT.Close()
// Wait for initial health check
time.Sleep(100 * time.Millisecond)
// Check initial health status
health := hybridDHT.GetBackendHealth()
if mockHealth, exists := health["mock"]; exists {
if mockHealth.Status != dht.HealthStatusHealthy {
t.Errorf("Expected mock backend to be healthy, got %v", mockHealth.Status)
}
if mockHealth.ErrorCount != 0 {
t.Errorf("Expected no errors initially, got %d", mockHealth.ErrorCount)
}
} else {
t.Error("Mock backend health not found")
}
// Wait for health monitoring to run
time.Sleep(1200 * time.Millisecond)
// Verify health monitoring is working
healthAfter := hybridDHT.GetBackendHealth()
if mockHealthAfter, exists := healthAfter["mock"]; exists {
if mockHealthAfter.Status != dht.HealthStatusHealthy {
t.Errorf("Expected mock backend to remain healthy, got %v", mockHealthAfter.Status)
}
}
t.Logf("✓ Health monitoring system working correctly")
}
func testMetricsCollection(t *testing.T, ctx context.Context) {
config := &config.HybridConfig{
DHT: config.DHTConfig{
Backend: "mock",
FallbackOnError: true,
HealthCheckInterval: 5 * time.Second,
},
Monitoring: config.MonitoringConfig{
Enabled: true,
MetricsInterval: 1 * time.Second,
},
}
logger := &testLogger{}
hybridDHT, err := dht.NewHybridDHT(config, logger)
if err != nil {
t.Fatalf("Failed to create hybrid DHT: %v", err)
}
defer hybridDHT.Close()
// Perform multiple operations
for i := 0; i < 5; i++ {
key := fmt.Sprintf("metrics-test-key-%d", i)
value := []byte(fmt.Sprintf("metrics-test-value-%d", i))
err = hybridDHT.PutValue(ctx, key, value)
if err != nil {
t.Fatalf("Failed to put value %d: %v", i, err)
}
retrievedValue, err := hybridDHT.GetValue(ctx, key)
if err != nil {
t.Fatalf("Failed to get value %d: %v", i, err)
}
if string(retrievedValue) != string(value) {
t.Errorf("Retrieved value %d doesn't match", i)
}
}
// Check collected metrics
metrics := hybridDHT.GetHybridMetrics()
if metrics.MockRequests != 10 { // 5 put + 5 get operations
t.Errorf("Expected 10 mock requests, got %d", metrics.MockRequests)
}
if metrics.RealRequests != 0 {
t.Errorf("Expected 0 real requests, got %d", metrics.RealRequests)
}
if metrics.TotalOperations != 10 {
t.Errorf("Expected 10 total operations, got %d", metrics.TotalOperations)
}
// Verify metrics tracking
if metrics.FallbackEvents != 0 {
t.Errorf("Expected 0 fallback events, got %d", metrics.FallbackEvents)
}
if metrics.RecoveryEvents != 0 {
t.Errorf("Expected 0 recovery events, got %d", metrics.RecoveryEvents)
}
// Verify latency tracking
if metrics.MockLatency <= 0 {
t.Error("Expected mock latency to be > 0")
}
// Verify error rate (should be 0 for successful operations)
if metrics.MockErrorRate != 0.0 {
t.Errorf("Expected 0 mock error rate, got %f", metrics.MockErrorRate)
}
t.Logf("✓ Metrics collection working correctly")
t.Logf(" - Mock requests: %d", metrics.MockRequests)
t.Logf(" - Total operations: %d", metrics.TotalOperations)
t.Logf(" - Mock latency: %v", metrics.MockLatency)
t.Logf(" - Mock error rate: %.2f%%", metrics.MockErrorRate*100.0)
}
func TestPhase2ConfigurationFromEnv(t *testing.T) {
// Set environment variables
os.Setenv("BZZZ_DHT_BACKEND", "mock")
os.Setenv("BZZZ_FALLBACK_ON_ERROR", "true")
os.Setenv("BZZZ_DHT_MAX_RETRIES", "5")
os.Setenv("BZZZ_DHT_OPERATION_TIMEOUT", "15s")
os.Setenv("BZZZ_MONITORING_ENABLED", "true")
defer func() {
// Clean up environment variables
os.Unsetenv("BZZZ_DHT_BACKEND")
os.Unsetenv("BZZZ_FALLBACK_ON_ERROR")
os.Unsetenv("BZZZ_DHT_MAX_RETRIES")
os.Unsetenv("BZZZ_DHT_OPERATION_TIMEOUT")
os.Unsetenv("BZZZ_MONITORING_ENABLED")
}()
// Load configuration from environment
config, err := config.LoadHybridConfig()
if err != nil {
t.Fatalf("Failed to load config from environment: %v", err)
}
// Verify configuration values
if config.DHT.Backend != "mock" {
t.Errorf("Expected backend 'mock', got '%s'", config.DHT.Backend)
}
if !config.DHT.FallbackOnError {
t.Error("Expected fallback to be enabled")
}
if config.DHT.MaxRetries != 5 {
t.Errorf("Expected 5 max retries, got %d", config.DHT.MaxRetries)
}
if config.DHT.OperationTimeout != 15*time.Second {
t.Errorf("Expected 15s timeout, got %v", config.DHT.OperationTimeout)
}
if !config.Monitoring.Enabled {
t.Error("Expected monitoring to be enabled")
}
// Test creating hybrid DHT with environment configuration
logger := &testLogger{}
hybridDHT, err := dht.NewHybridDHT(config, logger)
if err != nil {
t.Fatalf("Failed to create hybrid DHT with env config: %v", err)
}
defer hybridDHT.Close()
// Test basic operation
ctx := context.Background()
testKey := "env-config-test"
testValue := []byte("environment-configuration")
err = hybridDHT.PutValue(ctx, testKey, testValue)
if err != nil {
t.Fatalf("Failed to put value with env config: %v", err)
}
retrievedValue, err := hybridDHT.GetValue(ctx, testKey)
if err != nil {
t.Fatalf("Failed to get value with env config: %v", err)
}
if string(retrievedValue) != string(testValue) {
t.Errorf("Retrieved value doesn't match with env config")
}
t.Logf("✓ Environment-based configuration working correctly")
}
func TestPhase2ConcurrentOperations(t *testing.T) {
config := &config.HybridConfig{
DHT: config.DHTConfig{
Backend: "mock",
FallbackOnError: true,
HealthCheckInterval: 5 * time.Second,
},
}
logger := &testLogger{}
hybridDHT, err := dht.NewHybridDHT(config, logger)
if err != nil {
t.Fatalf("Failed to create hybrid DHT: %v", err)
}
defer hybridDHT.Close()
ctx := context.Background()
numWorkers := 10
numOperationsPerWorker := 5
// Channel to collect results
results := make(chan error, numWorkers*numOperationsPerWorker*2) // *2 for put+get
// Launch concurrent workers
for i := 0; i < numWorkers; i++ {
go func(workerId int) {
for j := 0; j < numOperationsPerWorker; j++ {
key := fmt.Sprintf("concurrent-worker-%d-op-%d", workerId, j)
value := []byte(fmt.Sprintf("concurrent-value-%d-%d", workerId, j))
// Put operation
err := hybridDHT.PutValue(ctx, key, value)
results <- err
// Get operation
retrievedValue, err := hybridDHT.GetValue(ctx, key)
if err == nil && string(retrievedValue) != string(value) {
results <- fmt.Errorf("value mismatch for key %s", key)
} else {
results <- err
}
}
}(i)
}
// Collect results
totalOperations := numWorkers * numOperationsPerWorker * 2
errorCount := 0
for i := 0; i < totalOperations; i++ {
if err := <-results; err != nil {
t.Logf("Operation error: %v", err)
errorCount++
}
}
if errorCount > 0 {
t.Errorf("Expected no errors, but got %d errors out of %d operations", errorCount, totalOperations)
}
// Verify metrics
metrics := hybridDHT.GetHybridMetrics()
if metrics.TotalOperations != uint64(totalOperations) {
t.Errorf("Expected %d total operations, got %d", totalOperations, metrics.TotalOperations)
}
if metrics.MockRequests != uint64(totalOperations) {
t.Errorf("Expected %d mock requests, got %d", totalOperations, metrics.MockRequests)
}
if metrics.RealRequests != 0 {
t.Errorf("Expected 0 real requests, got %d", metrics.RealRequests)
}
t.Logf("✓ Concurrent operations handled successfully")
t.Logf(" - Total operations: %d", totalOperations)
t.Logf(" - Error count: %d", errorCount)
t.Logf(" - All operations used mock backend")
}
// testLogger implements the Logger interface for testing
type testLogger struct{}
func (l *testLogger) Info(msg string, fields ...interface{}) {
fmt.Printf("[TEST-INFO] %s %v\n", msg, fields)
}
func (l *testLogger) Warn(msg string, fields ...interface{}) {
fmt.Printf("[TEST-WARN] %s %v\n", msg, fields)
}
func (l *testLogger) Error(msg string, fields ...interface{}) {
fmt.Printf("[TEST-ERROR] %s %v\n", msg, fields)
}
func (l *testLogger) Debug(msg string, fields ...interface{}) {
fmt.Printf("[TEST-DEBUG] %s %v\n", msg, fields)
}