mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-01 21:10:13 +00:00
New test files: - internal/ai/providers/gemini_test.go: Comprehensive Gemini provider tests - internal/api/ai_intelligence_handlers_test.go: AI intelligence endpoint tests - internal/api/ai_patrol_handlers_test.go: AI patrol endpoint tests - internal/api/license_handlers_test.go: License API handler tests - internal/api/security_oidc_response_test.go: OIDC response formatting tests - internal/config/ai_config_test.go: AI configuration function tests - internal/config/persistence_ai_test.go: AI config persistence tests - internal/config/persistence_extended_test.go: Extended persistence tests - internal/license/persistence_test.go: License persistence tests - internal/license/pubkey_test.go: Public key handling tests - internal/monitoring/host_agent_temps_test.go: Temperature processing tests Enhanced existing files: - internal/api/updates_test.go: Added update handler tests - internal/license/license_test.go: Added Service method tests Coverage improvements: - ai/providers: 57.3% -> 73.0% (+15.7%) - license: 78.3% -> 85.9% (+7.6%) - config: 49.7% -> 53.9% (+4.2%) - monitoring: 49.8% -> 50.8% (+1.0%) - api: 28.4% -> 29.8% (+1.4%)
343 lines
9.9 KiB
Go
343 lines
9.9 KiB
Go
package api
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
|
)
|
|
|
|
// createTestAIHandler creates a test AI handler with minimal setup
|
|
func createTestAIHandler(t *testing.T) *AISettingsHandler {
|
|
t.Helper()
|
|
tmp := t.TempDir()
|
|
cfg := &config.Config{DataPath: tmp}
|
|
persistence := config.NewConfigPersistence(tmp)
|
|
return NewAISettingsHandler(cfg, persistence, nil)
|
|
}
|
|
|
|
// TestHandleGetPatterns tests the patterns endpoint
|
|
func TestHandleGetPatterns_MethodNotAllowed(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/ai/intelligence/patterns", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetPatterns(rec, req)
|
|
|
|
if rec.Code != http.StatusMethodNotAllowed {
|
|
t.Fatalf("expected status %d for POST, got %d", http.StatusMethodNotAllowed, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestHandleGetPatterns_NoPatrolService(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/ai/intelligence/patterns", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetPatterns(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
// Should return empty patterns array with message
|
|
patterns, ok := resp["patterns"].([]interface{})
|
|
if !ok {
|
|
t.Fatal("expected patterns array in response")
|
|
}
|
|
if len(patterns) != 0 {
|
|
t.Fatalf("expected empty patterns, got %d", len(patterns))
|
|
}
|
|
if resp["message"] != "Patrol service not initialized" {
|
|
t.Fatalf("unexpected message: %v", resp["message"])
|
|
}
|
|
}
|
|
|
|
func TestHandleGetPatterns_ResourceIDFilter(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
// Test with resource_id query parameter - should still return gracefully
|
|
req := httptest.NewRequest(http.MethodGet, "/api/ai/intelligence/patterns?resource_id=vm-100", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetPatterns(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
patterns, ok := resp["patterns"].([]interface{})
|
|
if !ok {
|
|
t.Fatal("expected patterns array in response")
|
|
}
|
|
if len(patterns) != 0 {
|
|
t.Fatalf("expected empty patterns for non-initialized service, got %d", len(patterns))
|
|
}
|
|
}
|
|
|
|
// TestHandleGetPredictions tests the predictions endpoint
|
|
func TestHandleGetPredictions_MethodNotAllowed(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/ai/intelligence/predictions", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetPredictions(rec, req)
|
|
|
|
if rec.Code != http.StatusMethodNotAllowed {
|
|
t.Fatalf("expected status %d for POST, got %d", http.StatusMethodNotAllowed, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestHandleGetPredictions_NoPatrolService(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/ai/intelligence/predictions", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetPredictions(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
predictions, ok := resp["predictions"].([]interface{})
|
|
if !ok {
|
|
t.Fatal("expected predictions array in response")
|
|
}
|
|
if len(predictions) != 0 {
|
|
t.Fatalf("expected empty predictions, got %d", len(predictions))
|
|
}
|
|
if resp["message"] != "Patrol service not initialized" {
|
|
t.Fatalf("unexpected message: %v", resp["message"])
|
|
}
|
|
}
|
|
|
|
func TestHandleGetPredictions_ResourceIDFilter(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/ai/intelligence/predictions?resource_id=vm-200", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetPredictions(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
// Verify response is valid JSON with expected structure
|
|
if _, ok := resp["predictions"]; !ok {
|
|
t.Fatal("expected predictions field in response")
|
|
}
|
|
}
|
|
|
|
// TestHandleGetCorrelations tests the correlations endpoint
|
|
func TestHandleGetCorrelations_MethodNotAllowed(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/ai/intelligence/correlations", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetCorrelations(rec, req)
|
|
|
|
if rec.Code != http.StatusMethodNotAllowed {
|
|
t.Fatalf("expected status %d for POST, got %d", http.StatusMethodNotAllowed, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestHandleGetCorrelations_NoPatrolService(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/ai/intelligence/correlations", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetCorrelations(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
correlations, ok := resp["correlations"].([]interface{})
|
|
if !ok {
|
|
t.Fatal("expected correlations array in response")
|
|
}
|
|
if len(correlations) != 0 {
|
|
t.Fatalf("expected empty correlations, got %d", len(correlations))
|
|
}
|
|
if resp["message"] != "Patrol service not initialized" {
|
|
t.Fatalf("unexpected message: %v", resp["message"])
|
|
}
|
|
}
|
|
|
|
func TestHandleGetCorrelations_ResourceIDFilter(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/ai/intelligence/correlations?resource_id=storage-1", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetCorrelations(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
if _, ok := resp["correlations"]; !ok {
|
|
t.Fatal("expected correlations field in response")
|
|
}
|
|
}
|
|
|
|
// TestHandleGetRecentChanges tests the changes endpoint
|
|
func TestHandleGetRecentChanges_MethodNotAllowed(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/ai/intelligence/changes", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetRecentChanges(rec, req)
|
|
|
|
if rec.Code != http.StatusMethodNotAllowed {
|
|
t.Fatalf("expected status %d for POST, got %d", http.StatusMethodNotAllowed, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestHandleGetRecentChanges_NoPatrolService(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/ai/intelligence/changes", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetRecentChanges(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
changes, ok := resp["changes"].([]interface{})
|
|
if !ok {
|
|
t.Fatal("expected changes array in response")
|
|
}
|
|
if len(changes) != 0 {
|
|
t.Fatalf("expected empty changes, got %d", len(changes))
|
|
}
|
|
if resp["message"] != "Patrol service not initialized" {
|
|
t.Fatalf("unexpected message: %v", resp["message"])
|
|
}
|
|
}
|
|
|
|
// TestHandleGetBaselines tests the baselines endpoint
|
|
func TestHandleGetBaselines_MethodNotAllowed(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodPost, "/api/ai/intelligence/baselines", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetBaselines(rec, req)
|
|
|
|
if rec.Code != http.StatusMethodNotAllowed {
|
|
t.Fatalf("expected status %d for POST, got %d", http.StatusMethodNotAllowed, rec.Code)
|
|
}
|
|
}
|
|
|
|
func TestHandleGetBaselines_NoPatrolService(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/ai/intelligence/baselines", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetBaselines(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
baselines, ok := resp["baselines"].([]interface{})
|
|
if !ok {
|
|
t.Fatal("expected baselines array in response")
|
|
}
|
|
if len(baselines) != 0 {
|
|
t.Fatalf("expected empty baselines, got %d", len(baselines))
|
|
}
|
|
if resp["message"] != "Patrol service not initialized" {
|
|
t.Fatalf("unexpected message: %v", resp["message"])
|
|
}
|
|
}
|
|
|
|
func TestHandleGetBaselines_ResourceIDFilter(t *testing.T) {
|
|
t.Parallel()
|
|
handler := createTestAIHandler(t)
|
|
|
|
req := httptest.NewRequest(http.MethodGet, "/api/ai/intelligence/baselines?resource_id=node-1", nil)
|
|
rec := httptest.NewRecorder()
|
|
|
|
handler.HandleGetBaselines(rec, req)
|
|
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("expected status %d, got %d: %s", http.StatusOK, rec.Code, rec.Body.String())
|
|
}
|
|
|
|
var resp map[string]interface{}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
|
|
t.Fatalf("failed to unmarshal response: %v", err)
|
|
}
|
|
|
|
if _, ok := resp["baselines"]; !ok {
|
|
t.Fatal("expected baselines field in response")
|
|
}
|
|
}
|