Ctrl K
ComunidadGuías…

server/internal/handlers/admin_systemd_test.go

Rama main · réplica de lectura del repositorio original.

Archivo original ↗Preguntar a KiBot
package handlers_test

import (
	"bytes"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"testing"

	"blackbox/server/internal/handlers"
	"blackbox/server/internal/models"
	"github.com/stretchr/testify/require"
	"gorm.io/gorm"
)

type systemdConfigPayload struct {
	Units []string `json:"units"`
}

func seedNode(t *testing.T, db *gorm.DB, name string) {
	t.Helper()
	require.NoError(t, db.Create(&models.Node{ID: name, Name: name, Capabilities: "[]"}).Error)
}

func TestGetSystemdSettings_ReturnsEmptyMapWhenNoneConfigured(t *testing.T) {
	database := newTestDB(t)
	req := httptest.NewRequest(http.MethodGet, "/api/admin/settings/systemd", nil)
	w := httptest.NewRecorder()
	handlers.GetSystemdSettings(database)(w, req)
	require.Equal(t, http.StatusOK, w.Code)
	var resp map[string][]string
	require.NoError(t, json.NewDecoder(w.Body).Decode(&resp))
	require.Empty(t, resp)
}

func TestUpdateSystemdSettings_UpsertsUnitList(t *testing.T) {
	database := newTestDB(t)
	seedNode(t, database, "node-01")
	body := `{"units":["nginx.service","postgres.service"]}`
	req := httptest.NewRequest(http.MethodPut, "/api/admin/settings/systemd/node-01",
		bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req = withChiParam(req, "node_name", "node-01")
	w := httptest.NewRecorder()
	handlers.UpdateSystemdSettings(database)(w, req)
	require.Equal(t, http.StatusNoContent, w.Code)

	var inst models.DataSourceInstance
	require.NoError(t, database.Where("type = ? AND node_id = ?", "systemd", "node-01").First(&inst).Error)
	var cfg systemdConfigPayload
	require.NoError(t, json.Unmarshal([]byte(inst.Config), &cfg))
	require.Equal(t, []string{"nginx.service", "postgres.service"}, cfg.Units)
}

func TestUpdateSystemdSettings_OverwritesExistingList(t *testing.T) {
	database := newTestDB(t)
	nodeName := "node-01"
	existingCfg, _ := json.Marshal(map[string]any{"units": []string{"old.service"}})
	require.NoError(t, database.Create(&models.DataSourceInstance{
		ID: "sys-test-1", Type: "systemd", Scope: "agent", NodeID: &nodeName,
		Name: "Systemd", Config: string(existingCfg), Enabled: true,
	}).Error)

	body := `{"units":["nginx.service"]}`
	req := httptest.NewRequest(http.MethodPut, "/api/admin/settings/systemd/node-01",
		bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req = withChiParam(req, "node_name", "node-01")
	w := httptest.NewRecorder()
	handlers.UpdateSystemdSettings(database)(w, req)
	require.Equal(t, http.StatusNoContent, w.Code)

	var inst models.DataSourceInstance
	require.NoError(t, database.Where("type = ? AND node_id = ?", "systemd", "node-01").First(&inst).Error)
	var cfg systemdConfigPayload
	require.NoError(t, json.Unmarshal([]byte(inst.Config), &cfg))
	require.Equal(t, []string{"nginx.service"}, cfg.Units)
}

func TestUpdateSystemdSettings_RequiresNodeName(t *testing.T) {
	database := newTestDB(t)
	req := httptest.NewRequest(http.MethodPut, "/api/admin/settings/systemd",
		bytes.NewBufferString(`{"units":["nginx.service"]}`))
	req.Header.Set("Content-Type", "application/json")
	w := httptest.NewRecorder()

	handlers.UpdateSystemdSettings(database)(w, req)

	require.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUpdateSystemdSettings_RejectsInvalidJSON(t *testing.T) {
	database := newTestDB(t)
	req := httptest.NewRequest(http.MethodPut, "/api/admin/settings/systemd/node-01",
		bytes.NewBufferString(`{"units":[}`))
	req.Header.Set("Content-Type", "application/json")
	req = withChiParam(req, "node_name", "node-01")
	w := httptest.NewRecorder()

	handlers.UpdateSystemdSettings(database)(w, req)

	require.Equal(t, http.StatusBadRequest, w.Code)
}

func TestUpdateSystemdSettings_PersistsEmptyUnitList(t *testing.T) {
	database := newTestDB(t)
	seedNode(t, database, "node-01")
	req := httptest.NewRequest(http.MethodPut, "/api/admin/settings/systemd/node-01",
		bytes.NewBufferString(`{"units":[]}`))
	req.Header.Set("Content-Type", "application/json")
	req = withChiParam(req, "node_name", "node-01")
	w := httptest.NewRecorder()

	handlers.UpdateSystemdSettings(database)(w, req)

	require.Equal(t, http.StatusNoContent, w.Code)

	var inst models.DataSourceInstance
	require.NoError(t, database.Where("type = ? AND node_id = ?", "systemd", "node-01").First(&inst).Error)
	var cfg systemdConfigPayload
	require.NoError(t, json.Unmarshal([]byte(inst.Config), &cfg))
	require.Empty(t, cfg.Units)
}

func TestUpdateSystemdSettings_DeduplicatesMixedForms(t *testing.T) {
	database := newTestDB(t)
	seedNode(t, database, "node-01")
	body := `{"units":["nginx","nginx.service","redis.service","redis"]}`
	req := httptest.NewRequest(http.MethodPut, "/api/admin/settings/systemd/node-01",
		bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req = withChiParam(req, "node_name", "node-01")
	w := httptest.NewRecorder()
	handlers.UpdateSystemdSettings(database)(w, req)
	require.Equal(t, http.StatusNoContent, w.Code)

	var inst models.DataSourceInstance
	require.NoError(t, database.Where("type = ? AND node_id = ?", "systemd", "node-01").First(&inst).Error)
	var cfg systemdConfigPayload
	require.NoError(t, json.Unmarshal([]byte(inst.Config), &cfg))
	require.Equal(t, []string{"nginx.service", "redis.service"}, cfg.Units)
}

func TestUpdateSystemdSettings_NormalizesBareName(t *testing.T) {
	database := newTestDB(t)
	seedNode(t, database, "node-01")
	body := `{"units":["nginx","redis.service"]}`
	req := httptest.NewRequest(http.MethodPut, "/api/admin/settings/systemd/node-01",
		bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req = withChiParam(req, "node_name", "node-01")
	w := httptest.NewRecorder()
	handlers.UpdateSystemdSettings(database)(w, req)
	require.Equal(t, http.StatusNoContent, w.Code)

	var inst models.DataSourceInstance
	require.NoError(t, database.Where("type = ? AND node_id = ?", "systemd", "node-01").First(&inst).Error)
	var cfg systemdConfigPayload
	require.NoError(t, json.Unmarshal([]byte(inst.Config), &cfg))
	require.Equal(t, []string{"nginx.service", "redis.service"}, cfg.Units)
}

func TestUpdateSystemdSettings_DottedBareNameGetsSuffix(t *testing.T) {
	database := newTestDB(t)
	seedNode(t, database, "node-01")
	body := `{"units":["dbus-org.freedesktop.resolve1"]}`
	req := httptest.NewRequest(http.MethodPut, "/api/admin/settings/systemd/node-01",
		bytes.NewBufferString(body))
	req.Header.Set("Content-Type", "application/json")
	req = withChiParam(req, "node_name", "node-01")
	w := httptest.NewRecorder()
	handlers.UpdateSystemdSettings(database)(w, req)
	require.Equal(t, http.StatusNoContent, w.Code)

	var inst models.DataSourceInstance
	require.NoError(t, database.Where("type = ? AND node_id = ?", "systemd", "node-01").First(&inst).Error)
	var cfg systemdConfigPayload
	require.NoError(t, json.Unmarshal([]byte(inst.Config), &cfg))
	require.Equal(t, []string{"dbus-org.freedesktop.resolve1.service"}, cfg.Units)
}

func TestGetSystemdSettings_ReturnsAllNodes(t *testing.T) {
	database := newTestDB(t)
	node01 := "node-01"
	node02 := "node-02"
	cfg1, _ := json.Marshal(map[string]any{"units": []string{"nginx.service"}})
	cfg2, _ := json.Marshal(map[string]any{"units": []string{"redis.service"}})
	require.NoError(t, database.Create(&models.DataSourceInstance{
		ID: "sys-n1", Type: "systemd", Scope: "agent", NodeID: &node01,
		Name: "Systemd", Config: string(cfg1), Enabled: true,
	}).Error)
	require.NoError(t, database.Create(&models.DataSourceInstance{
		ID: "sys-n2", Type: "systemd", Scope: "agent", NodeID: &node02,
		Name: "Systemd", Config: string(cfg2), Enabled: true,
	}).Error)

	req := httptest.NewRequest(http.MethodGet, "/api/admin/settings/systemd", nil)
	w := httptest.NewRecorder()
	handlers.GetSystemdSettings(database)(w, req)
	require.Equal(t, http.StatusOK, w.Code)
	var resp map[string][]string
	require.NoError(t, json.NewDecoder(w.Body).Decode(&resp))
	require.Equal(t, []string{"nginx.service"}, resp["node-01"])
	require.Equal(t, []string{"redis.service"}, resp["node-02"])
}