Pulse/internal/api/router_low_coverage_additional_test.go
2026-03-18 16:06:30 +00:00

264 lines
9.4 KiB
Go

package api
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"github.com/rcourtman/pulse-go-rewrite/internal/ai/knowledge"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
"github.com/rcourtman/pulse-go-rewrite/internal/models"
"github.com/rcourtman/pulse-go-rewrite/internal/monitoring"
"github.com/rcourtman/pulse-go-rewrite/pkg/metrics"
)
func TestHandleMetricsStoreStats_MethodNotAllowed(t *testing.T) {
router := &Router{}
req := httptest.NewRequest(http.MethodPost, "/api/metrics/store/stats", nil)
rec := httptest.NewRecorder()
router.handleMetricsStoreStats(rec, req)
if rec.Code != http.StatusMethodNotAllowed {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusMethodNotAllowed)
}
}
func TestHandleMetricsStoreStats_NoMonitor(t *testing.T) {
router := &Router{}
req := httptest.NewRequest(http.MethodGet, "/api/metrics/store/stats", nil)
rec := httptest.NewRecorder()
router.handleMetricsStoreStats(rec, req)
if rec.Code != http.StatusInternalServerError {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusInternalServerError)
}
}
func TestHandleMetricsStoreStats_NoStore(t *testing.T) {
monitor, _, _ := newTestMonitor(t)
router := &Router{monitor: monitor}
req := httptest.NewRequest(http.MethodGet, "/api/metrics/store/stats", nil)
rec := httptest.NewRecorder()
router.handleMetricsStoreStats(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
var payload map[string]interface{}
if err := json.NewDecoder(rec.Body).Decode(&payload); err != nil {
t.Fatalf("decode response: %v", err)
}
if payload["enabled"] != false {
t.Fatalf("expected enabled=false, got %#v", payload["enabled"])
}
}
func TestHandleMetricsStoreStats_WithStore(t *testing.T) {
monitor, _, _ := newTestMonitor(t)
store, err := metrics.NewStore(metrics.DefaultConfig(t.TempDir()))
if err != nil {
t.Fatalf("metrics.NewStore error: %v", err)
}
defer store.Close()
setUnexportedField(t, monitor, "metricsStore", store)
router := &Router{monitor: monitor}
req := httptest.NewRequest(http.MethodGet, "/api/metrics/store/stats", nil)
rec := httptest.NewRecorder()
router.handleMetricsStoreStats(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
var payload map[string]interface{}
if err := json.NewDecoder(rec.Body).Decode(&payload); err != nil {
t.Fatalf("decode response: %v", err)
}
if payload["enabled"] != true {
t.Fatalf("expected enabled=true, got %#v", payload["enabled"])
}
}
func TestHandleDiagnosticsDockerPrepareToken_MethodNotAllowed(t *testing.T) {
router := &Router{}
req := httptest.NewRequest(http.MethodGet, "/api/diagnostics/docker/prepare-token", nil)
rec := httptest.NewRecorder()
router.handleDiagnosticsDockerPrepareToken(rec, req)
if rec.Code != http.StatusMethodNotAllowed {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusMethodNotAllowed)
}
}
func TestHandleDiagnosticsDockerPrepareToken_InvalidJSON(t *testing.T) {
router := &Router{monitor: &monitoring.Monitor{}, config: &config.Config{}}
req := httptest.NewRequest(http.MethodPost, "/api/diagnostics/docker/prepare-token", strings.NewReader("{"))
rec := httptest.NewRecorder()
router.handleDiagnosticsDockerPrepareToken(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusBadRequest)
}
}
func TestHandleDiagnosticsDockerPrepareToken_MissingAgentID(t *testing.T) {
router := &Router{monitor: &monitoring.Monitor{}, config: &config.Config{}}
body := bytes.NewBufferString(`{"agentId":""}`)
req := httptest.NewRequest(http.MethodPost, "/api/diagnostics/docker/prepare-token", body)
rec := httptest.NewRecorder()
router.handleDiagnosticsDockerPrepareToken(rec, req)
if rec.Code != http.StatusBadRequest {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusBadRequest)
}
}
func TestHandleDiagnosticsDockerPrepareToken_AgentNotFound(t *testing.T) {
monitor, _, _ := newTestMonitor(t)
router := &Router{monitor: monitor, config: &config.Config{}}
body := bytes.NewBufferString(`{"agentId":"missing"}`)
req := httptest.NewRequest(http.MethodPost, "/api/diagnostics/docker/prepare-token", body)
rec := httptest.NewRecorder()
router.handleDiagnosticsDockerPrepareToken(rec, req)
if rec.Code != http.StatusNotFound {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusNotFound)
}
}
func TestHandleDiagnosticsDockerPrepareToken_Success(t *testing.T) {
monitor, state, _ := newTestMonitor(t)
state.DockerHosts = []models.DockerHost{{ID: "host-1", DisplayName: "Docker Host"}}
router := &Router{monitor: monitor, config: &config.Config{PublicURL: "https://pulse.example.com"}}
body := bytes.NewBufferString(`{"agentId":"host-1","tokenName":""}`)
req := httptest.NewRequest(http.MethodPost, "/api/diagnostics/docker/prepare-token", body)
rec := httptest.NewRecorder()
router.handleDiagnosticsDockerPrepareToken(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
var payload map[string]interface{}
if err := json.NewDecoder(rec.Body).Decode(&payload); err != nil {
t.Fatalf("decode response: %v", err)
}
if ok, _ := payload["success"].(bool); !ok {
t.Fatalf("expected success true, got %#v", payload["success"])
}
if payload["token"] == "" {
t.Fatalf("expected token in response")
}
agent, _ := payload["agent"].(map[string]interface{})
if agent["id"] != "host-1" {
t.Fatalf("unexpected agent id: %#v", agent["id"])
}
if !strings.Contains(payload["installCommand"].(string), "https://pulse.example.com") {
t.Fatalf("expected install command to include base URL")
}
if !strings.Contains(payload["installCommand"].(string), "--enable-host=false") {
t.Fatalf("expected install command to disable host metrics with the canonical lifecycle flag: %q", payload["installCommand"])
}
if !strings.Contains(payload["installCommand"].(string), "--enable-docker") {
t.Fatalf("expected install command to enable docker metrics: %q", payload["installCommand"])
}
if !strings.Contains(payload["installCommand"].(string), `| { if [ "$(id -u)" -eq 0 ]; then bash -s --`) {
t.Fatalf("expected install command to use lifecycle privilege wrapper: %q", payload["installCommand"])
}
if strings.Contains(payload["installCommand"].(string), "| sudo bash -s -- --url") {
t.Fatalf("expected install command to preserve the governed root-or-sudo wrapper instead of a raw sudo pipe: %q", payload["installCommand"])
}
if !strings.Contains(payload["systemdServiceSnippet"].(string), "--enable-host=false") {
t.Fatalf("expected systemd snippet to disable host metrics: %q", payload["systemdServiceSnippet"])
}
if len(router.config.APITokens) == 0 {
t.Fatalf("expected API token to be recorded")
}
}
func TestHandleDiagnosticsDockerPrepareToken_NormalizesTrailingSlashPublicURL(t *testing.T) {
monitor, state, _ := newTestMonitor(t)
state.DockerHosts = []models.DockerHost{{ID: "host-1", DisplayName: "Docker Host"}}
router := &Router{monitor: monitor, config: &config.Config{PublicURL: "https://pulse.example.com/base///"}}
body := bytes.NewBufferString(`{"agentId":"host-1","tokenName":""}`)
req := httptest.NewRequest(http.MethodPost, "/api/diagnostics/docker/prepare-token", body)
rec := httptest.NewRecorder()
router.handleDiagnosticsDockerPrepareToken(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want %d", rec.Code, http.StatusOK)
}
var payload map[string]interface{}
if err := json.NewDecoder(rec.Body).Decode(&payload); err != nil {
t.Fatalf("decode response: %v", err)
}
installCommand, _ := payload["installCommand"].(string)
if !strings.Contains(installCommand, posixShellQuote("https://pulse.example.com/base/install.sh")) {
t.Fatalf("expected normalized install script URL, got %q", installCommand)
}
if strings.Contains(installCommand, "//install.sh") {
t.Fatalf("expected normalized install script URL without double slash, got %q", installCommand)
}
systemdSnippet, _ := payload["systemdServiceSnippet"].(string)
if !strings.Contains(systemdSnippet, `Environment="PULSE_URL=https://pulse.example.com/base"`) {
t.Fatalf("expected normalized Pulse URL in systemd snippet, got %q", systemdSnippet)
}
if strings.Contains(systemdSnippet, `Environment="PULSE_URL=https://pulse.example.com/base/"`) {
t.Fatalf("expected trailing slash to be trimmed from systemd snippet, got %q", systemdSnippet)
}
if pulseURL, _ := payload["pulseURL"].(string); pulseURL != "https://pulse.example.com/base" {
t.Fatalf("expected normalized pulseURL, got %q", pulseURL)
}
}
func TestKnowledgeStoreProviderWrapper(t *testing.T) {
wrapper := &knowledgeStoreProviderWrapper{}
if err := wrapper.SaveNote("res-1", "note", "service"); err == nil {
t.Fatalf("expected error when store is nil")
}
if got := wrapper.GetKnowledge("res-1", ""); got != nil {
t.Fatalf("expected nil knowledge when store is nil")
}
store, err := knowledge.NewStore(t.TempDir())
if err != nil {
t.Fatalf("knowledge.NewStore error: %v", err)
}
wrapper.store = store
if err := wrapper.SaveNote("res-1", "hello", "service"); err != nil {
t.Fatalf("SaveNote error: %v", err)
}
entries := wrapper.GetKnowledge("res-1", "service")
if len(entries) != 1 {
t.Fatalf("expected 1 entry, got %d", len(entries))
}
if entries[0].Category != "service" || entries[0].Note != "hello" {
t.Fatalf("unexpected entry: %#v", entries[0])
}
all := wrapper.GetKnowledge("res-1", "")
if len(all) != 1 {
t.Fatalf("expected 1 entry from full query, got %d", len(all))
}
}