package unit import ( "context" "crypto/tls" "net/http" "os" "strings" "testing" "time" tests "github.com/jfraeys/fetch_ml/tests/fixtures" ) // TestBasicRedisConnection tests basic Redis connectivity func TestBasicRedisConnection(t *testing.T) { t.Parallel() // Enable parallel execution ctx := context.Background() // Use fixtures for Redis operations redisHelper, err := tests.NewRedisHelper("localhost:6379", 12) if err != nil { t.Skipf("Redis not available, skipping test: %v", err) } defer func() { redisHelper.FlushDB() redisHelper.Close() }() // Test basic operations key := "test:key" value := "test_value" // Set if err := redisHelper.GetClient().Set(ctx, key, value, time.Hour).Err(); err != nil { t.Fatalf("Failed to set value: %v", err) } // Get result, err := redisHelper.GetClient().Get(ctx, key).Result() if err != nil { t.Fatalf("Failed to get value: %v", err) } if result != value { t.Errorf("Expected value '%s', got '%s'", value, result) } // Delete if err := redisHelper.GetClient().Del(ctx, key).Err(); err != nil { t.Fatalf("Failed to delete key: %v", err) } // Verify deleted _, err = redisHelper.GetClient().Get(ctx, key).Result() if err == nil { t.Error("Expected error when getting deleted key") } } // TestTaskQueueBasicOperations tests basic task queue functionality func TestTaskQueueBasicOperations(t *testing.T) { t.Parallel() // Enable parallel execution // Use fixtures for Redis operations redisHelper, err := tests.NewRedisHelper("localhost:6379", 11) if err != nil { t.Skipf("Redis not available, skipping test: %v", err) } defer func() { redisHelper.FlushDB() redisHelper.Close() }() // Create task queue taskQueue, err := tests.NewTaskQueue(&tests.Config{ RedisAddr: "localhost:6379", RedisDB: 11, }) if err != nil { t.Fatalf("Failed to create task queue: %v", err) } defer taskQueue.Close() // Test enqueue task, err := taskQueue.EnqueueTask("simple_test", "--epochs 1", 5) if err != nil { t.Fatalf("Failed to enqueue task: %v", err) } if task.ID == "" { t.Error("Task ID should not be empty") } if task.Status != "queued" { t.Errorf("Expected status 'queued', got '%s'", task.Status) } // Test get retrievedTask, err := taskQueue.GetTask(task.ID) if err != nil { t.Fatalf("Failed to get task: %v", err) } if retrievedTask.ID != task.ID { t.Errorf("Expected task ID %s, got %s", task.ID, retrievedTask.ID) } // Test get next nextTask, err := taskQueue.GetNextTask() if err != nil { t.Fatalf("Failed to get next task: %v", err) } if nextTask == nil { t.Fatal("Should have retrieved a task") } if nextTask.ID != task.ID { t.Errorf("Expected task ID %s, got %s", task.ID, nextTask.ID) } // Test update now := time.Now() nextTask.Status = "running" nextTask.StartedAt = &now if err := taskQueue.UpdateTask(nextTask); err != nil { t.Fatalf("Failed to update task: %v", err) } // Verify update updatedTask, err := taskQueue.GetTask(nextTask.ID) if err != nil { t.Fatalf("Failed to get updated task: %v", err) } if updatedTask.Status != "running" { t.Errorf("Expected status 'running', got '%s'", updatedTask.Status) } if updatedTask.StartedAt == nil { t.Error("StartedAt should not be nil") } // Test metrics if err := taskQueue.RecordMetric("simple_test", "accuracy", 0.95); err != nil { t.Fatalf("Failed to record metric: %v", err) } metrics, err := taskQueue.GetMetrics("simple_test") if err != nil { t.Fatalf("Failed to get metrics: %v", err) } if metrics["accuracy"] != "0.95" { t.Errorf("Expected accuracy '0.95', got '%s'", metrics["accuracy"]) } t.Log("Basic task queue operations test completed successfully") } // TestManageScriptHealthCheck tests the manage.sh health check functionality func TestManageScriptHealthCheck(t *testing.T) { t.Parallel() // Enable parallel execution // Use fixtures for manage script operations manageScript := "../../tools/manage.sh" if _, err := os.Stat(manageScript); os.IsNotExist(err) { t.Skipf("manage.sh not found at %s", manageScript) } ms := tests.NewManageScript(manageScript) // Test help command to verify health command exists output, err := ms.Status() if err != nil { t.Fatalf("Failed to run manage.sh status: %v", err) } if !strings.Contains(output, "Redis") { t.Error("manage.sh status should include 'Redis' service status") } t.Log("manage.sh status command verification completed") } // TestAPIHealthEndpoint tests the actual API health endpoint func TestAPIHealthEndpoint(t *testing.T) { t.Parallel() // Enable parallel execution // Create HTTP client with reduced timeout for better performance client := &http.Client{ Timeout: 3 * time.Second, // Reduced from 5 seconds } // Test the health endpoint req, err := http.NewRequest("GET", "https://localhost:9101/health", nil) if err != nil { t.Fatalf("Failed to create request: %v", err) } // Add required headers req.Header.Set("X-API-Key", "password") req.Header.Set("X-Forwarded-For", "127.0.0.1") // Make request (skip TLS verification for self-signed certs) client.Transport = &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, } resp, err := client.Do(req) if err != nil { // API might not be running, which is okay for this test t.Skipf("API not available, skipping health endpoint test: %v", err) return } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { t.Errorf("Expected status 200, got %d", resp.StatusCode) } t.Log("API health endpoint test completed successfully") }