Files
Pulse/internal/api/docker_agents_additional_test.go
2026-01-25 21:08:44 +00:00

257 lines
7.4 KiB
Go

package api
import (
"bytes"
"encoding/json"
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
"github.com/rcourtman/pulse-go-rewrite/internal/config"
"github.com/rcourtman/pulse-go-rewrite/internal/monitoring"
"github.com/rcourtman/pulse-go-rewrite/internal/websocket"
agentsdocker "github.com/rcourtman/pulse-go-rewrite/pkg/agents/docker"
)
func newDockerAgentHandlers(t *testing.T, cfg *config.Config) (*DockerAgentHandlers, *monitoring.Monitor) {
t.Helper()
if cfg == nil {
cfg = &config.Config{DataPath: t.TempDir()}
}
if cfg.DataPath == "" {
cfg.DataPath = t.TempDir()
}
monitor, err := monitoring.New(cfg)
if err != nil {
t.Fatalf("monitoring.New: %v", err)
}
t.Cleanup(func() { monitor.Stop() })
hub := websocket.NewHub(nil)
handler := NewDockerAgentHandlers(nil, monitor, hub, cfg)
return handler, monitor
}
func seedDockerHost(t *testing.T, monitor *monitoring.Monitor) string {
t.Helper()
report := agentsdocker.Report{
Agent: agentsdocker.AgentInfo{
ID: "agent-1",
Version: "1.0.0",
IntervalSeconds: 30,
},
Host: agentsdocker.HostInfo{
Hostname: "docker-host",
Name: "Docker Host",
MachineID: "machine-1",
DockerVersion: "26.0.0",
TotalCPU: 4,
TotalMemoryBytes: 8 << 30,
UptimeSeconds: 120,
},
Timestamp: time.Now().UTC(),
}
host, err := monitor.ApplyDockerReport(report, nil)
if err != nil {
t.Fatalf("ApplyDockerReport: %v", err)
}
if host.ID == "" {
t.Fatalf("expected host ID to be set")
}
return host.ID
}
func TestDockerAgentHandlers_HandleReport(t *testing.T) {
handler, _ := newDockerAgentHandlers(t, nil)
report := agentsdocker.Report{
Agent: agentsdocker.AgentInfo{
ID: "agent-2",
Version: "1.0.0",
IntervalSeconds: 30,
},
Host: agentsdocker.HostInfo{
Hostname: "docker-host-2",
Name: "Docker Host 2",
MachineID: "machine-2",
DockerVersion: "26.0.0",
TotalCPU: 4,
TotalMemoryBytes: 4 << 30,
UptimeSeconds: 60,
},
Timestamp: time.Now().UTC(),
}
body, _ := json.Marshal(report)
req := httptest.NewRequest(http.MethodPost, "/api/agents/docker/report", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.HandleReport(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body.String())
}
var resp map[string]interface{}
if err := json.Unmarshal(rec.Body.Bytes(), &resp); err != nil {
t.Fatalf("decode response: %v", err)
}
if resp["success"] != true {
t.Fatalf("success = %v, want true", resp["success"])
}
if resp["hostId"] == "" {
t.Fatalf("expected hostId in response")
}
}
func TestDockerAgentHandlers_HandleCommandAck(t *testing.T) {
handler, monitor := newDockerAgentHandlers(t, nil)
hostID := seedDockerHost(t, monitor)
cmdStatus, err := monitor.QueueDockerHostStop(hostID)
if err != nil {
t.Fatalf("QueueDockerHostStop: %v", err)
}
reqBody := map[string]string{
"hostId": hostID,
"status": "completed",
}
body, _ := json.Marshal(reqBody)
path := "/api/agents/docker/commands/" + cmdStatus.ID + "/ack"
req := httptest.NewRequest(http.MethodPost, path, bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.HandleCommandAck(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body.String())
}
}
func TestDockerAgentHandlers_HandleDockerHostActions(t *testing.T) {
handler, monitor := newDockerAgentHandlers(t, nil)
hostID := seedDockerHost(t, monitor)
req := httptest.NewRequest(http.MethodPost, "/api/agents/docker/hosts/"+hostID+"/allow-reenroll", nil)
rec := httptest.NewRecorder()
handler.HandleDockerHostActions(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body.String())
}
}
func TestDockerAgentHandlers_HandleDeleteHost(t *testing.T) {
handler, monitor := newDockerAgentHandlers(t, nil)
hostID := seedDockerHost(t, monitor)
req := httptest.NewRequest(http.MethodDelete, "/api/agents/docker/hosts/"+hostID+"?force=true", nil)
rec := httptest.NewRecorder()
handler.HandleDeleteHost(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body.String())
}
}
func TestDockerAgentHandlers_HandleUnhideHost(t *testing.T) {
handler, monitor := newDockerAgentHandlers(t, nil)
hostID := seedDockerHost(t, monitor)
req := httptest.NewRequest(http.MethodPut, "/api/agents/docker/hosts/"+hostID+"/unhide", nil)
rec := httptest.NewRecorder()
handler.HandleUnhideHost(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body.String())
}
}
func TestDockerAgentHandlers_HandleMarkPendingUninstall(t *testing.T) {
handler, monitor := newDockerAgentHandlers(t, nil)
hostID := seedDockerHost(t, monitor)
req := httptest.NewRequest(http.MethodPut, "/api/agents/docker/hosts/"+hostID+"/pending-uninstall", nil)
rec := httptest.NewRecorder()
handler.HandleMarkPendingUninstall(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body.String())
}
}
func TestDockerAgentHandlers_HandleSetCustomDisplayName(t *testing.T) {
handler, monitor := newDockerAgentHandlers(t, nil)
hostID := seedDockerHost(t, monitor)
body := []byte(`{"displayName":"My Docker Host"}`)
req := httptest.NewRequest(http.MethodPut, "/api/agents/docker/hosts/"+hostID+"/display-name", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.HandleSetCustomDisplayName(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body.String())
}
}
func TestDockerAgentHandlers_HandleContainerUpdate(t *testing.T) {
handler, monitor := newDockerAgentHandlers(t, &config.Config{DataPath: t.TempDir()})
hostID := seedDockerHost(t, monitor)
reqBody := map[string]string{
"hostId": hostID,
"containerId": "container-1",
"containerName": "nginx",
}
body, _ := json.Marshal(reqBody)
req := httptest.NewRequest(http.MethodPost, "/api/agents/docker/containers/container-1/update", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.HandleContainerUpdate(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body.String())
}
}
func TestDockerAgentHandlers_HandleContainerUpdate_Disabled(t *testing.T) {
cfg := &config.Config{DataPath: t.TempDir(), DisableDockerUpdateActions: true}
handler, monitor := newDockerAgentHandlers(t, cfg)
hostID := seedDockerHost(t, monitor)
reqBody := map[string]string{
"hostId": hostID,
"containerId": "container-2",
"containerName": "redis",
}
body, _ := json.Marshal(reqBody)
req := httptest.NewRequest(http.MethodPost, "/api/agents/docker/containers/container-2/update", bytes.NewReader(body))
rec := httptest.NewRecorder()
handler.HandleContainerUpdate(rec, req)
if rec.Code != http.StatusForbidden {
t.Fatalf("status = %d, want 403", rec.Code)
}
}
func TestDockerAgentHandlers_HandleCheckUpdates(t *testing.T) {
handler, monitor := newDockerAgentHandlers(t, nil)
hostID := seedDockerHost(t, monitor)
req := httptest.NewRequest(http.MethodPost, "/api/agents/docker/hosts/"+hostID+"/check-updates", nil)
rec := httptest.NewRecorder()
handler.HandleCheckUpdates(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status = %d, want 200: %s", rec.Code, rec.Body.String())
}
if !strings.Contains(rec.Body.String(), "Check for updates") {
t.Fatalf("expected check updates message")
}
}