package httpapi // Integration tests for Phase 3 endpoints: checks, classifications, // executions, approvals, patterns, skills, policy, and knowledge search. // Guarded by OIKOS_TEST_DATABASE_URL; run via `make test-db` or with env set. import ( "encoding/json" "net/http/httptest" "strings" "testing" ) func TestPhase3ListChecks(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/checks", nil) if rec.Code != 200 { t.Fatalf("list checks status %d: %v", rec.Code, body) } } func TestPhase3ListApprovals(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/approvals", nil) if rec.Code != 200 { t.Fatalf("list approvals status %d: %v", rec.Code, body) } } func TestPhase3ListRiskClasses(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/risk-classes", nil) if rec.Code != 200 { t.Fatalf("list risk classes status %d: %v", rec.Code, body) } items, _ := body["items"].([]any) if len(items) < 2 { t.Errorf("expected 2+ risk classes, got %d", len(items)) } } func TestPhase3ListAutonomySettings(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/autonomy-settings", nil) if rec.Code != 200 { t.Fatalf("get autonomy settings status %d: %v", rec.Code, body) } _ = body } func TestPhase3ListPatterns(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/patterns", nil) if rec.Code != 200 { t.Fatalf("list patterns status %d: %v", rec.Code, body) } } func TestPhase3ListSkills(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/skills", nil) if rec.Code != 200 { t.Fatalf("list skills status %d: %v", rec.Code, body) } } func TestPhase3ListExecutions(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/executions", nil) if rec.Code != 200 { t.Fatalf("list executions status %d: %v", rec.Code, body) } } func TestPhase3ListClassifications(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/classifications", nil) if rec.Code != 200 { t.Fatalf("list classifications status %d: %v", rec.Code, body) } } func TestPhase3QueryMetrics(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/metrics?entity_id=00000000-0000-0000-0000-000000000001&metric=health", nil) if rec.Code != 200 { t.Fatalf("query metrics status %d: %v", rec.Code, body) } } func TestPhase3JSONRoundTrip(t *testing.T) { sigData := map[string]any{ "id": "sig-123", "kind": "down", "severity": "critical", "state": "raised", "occurrence_count": 1, } b, _ := json.Marshal(sigData) var back map[string]any if err := json.Unmarshal(b, &back); err != nil { t.Fatalf("signal round-trip: %v", err) } if back["kind"] != "down" { t.Errorf("kind = %v, want down", back["kind"]) } } // ─── Phase 4 tests ──────────────────────────────────────────────────── func TestPhase4AgentActivity(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/agent-activity", nil) if rec.Code != 200 { t.Fatalf("agent-activity status %d: %v", rec.Code, body) } } func TestPhase4CreateExecution(t *testing.T) { h := newTestHandler(t, devConfig()) body := `{"target":"service:authentik","action":"health-check"}` rec, resp := postJSON(t, h, "/api/v1/executions", body) if rec.Code != 201 { t.Fatalf("create execution status %d: %v", rec.Code, resp) } if resp["action"] != "health-check" { t.Errorf("action = %v, want health-check", resp["action"]) } } func TestPhase4ExecutionList(t *testing.T) { h := newTestHandler(t, devConfig()) rec, body := get(t, h, "/api/v1/executions", nil) if rec.Code != 200 { t.Fatalf("list executions status %d: %v", rec.Code, body) } items, _ := body["items"].([]any) t.Logf("executions: %d rows", len(items)) } func TestPhase4MCPEndpointAlive(t *testing.T) { h := newTestHandler(t, devConfig()) body := `{"jsonrpc":"2.0","method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"test-oikos","version":"1.0"}},"id":1}` req := httptest.NewRequest("POST", "/mcp", strings.NewReader(body)) req.Header.Set("Content-Type", "application/json") req.Header.Set("Accept", "application/json, text/event-stream") req.Header.Set("Authorization", "Bearer "+testAuthToken) rec := httptest.NewRecorder() h.ServeHTTP(rec, req) if rec.Code != 200 { t.Fatalf("mcp initialize status %d: %s", rec.Code, rec.Body.String()) } sid := rec.Header().Get("Mcp-Session-Id") if sid == "" { t.Error("no Mcp-Session-Id header") } t.Logf("session: %s", sid) }