147 lines
5.4 KiB
Go
147 lines
5.4 KiB
Go
package main
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestAgentEnrollmentTokenIsSingleUse(t *testing.T) {
|
|
store, err := openStore(":memory:")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer store.Close()
|
|
token, err := store.CreateAgentEnrollmentToken()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
credentials, err := store.EnrollAgent(agentEnrollmentRequest{Token: token, Name: "docker-01", Hostname: "vm105", VMID: 105})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if credentials.ID == "" || credentials.Secret == "" {
|
|
t.Fatal("credentials were not generated")
|
|
}
|
|
if _, err = store.EnrollAgent(agentEnrollmentRequest{Token: token, Hostname: "duplicate"}); err == nil {
|
|
t.Fatal("token was accepted twice")
|
|
}
|
|
}
|
|
|
|
func TestCurrentAgentUpdateManifestMatchesExecutable(t *testing.T) {
|
|
manifest, path, err := currentAgentUpdate()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if manifest.URL != "/api/agent/binary" || len(manifest.SHA256) != 64 {
|
|
t.Fatalf("unexpected manifest: %#v", manifest)
|
|
}
|
|
if _, err = os.Stat(path); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func TestAgentOnlyInstallsNewerVersion(t *testing.T) {
|
|
if !newerAgentVersion("v0.14.0", "v0.13.0") {
|
|
t.Fatal("new version was not detected")
|
|
}
|
|
if newerAgentVersion("v0.12.0", "v0.13.0") {
|
|
t.Fatal("downgrade was allowed")
|
|
}
|
|
if newerAgentVersion("v0.13.0", "v0.13.0") {
|
|
t.Fatal("same version was offered")
|
|
}
|
|
}
|
|
|
|
func TestParseAgentIssues(t *testing.T) {
|
|
issues := parseAgentIssues(`{"MESSAGE":"disk error","_SYSTEMD_UNIT":"worker.service","__REALTIME_TIMESTAMP":"1722960000000000"}` + "\n" + `{"MESSAGE":"network error","__REALTIME_TIMESTAMP":"1722960001000000"}`)
|
|
if len(issues) != 2 || issues[0].Unit != "worker.service" || issues[1].Unit != "system" || issues[0].Time != 1722960000 {
|
|
t.Fatalf("unexpected issues: %#v", issues)
|
|
}
|
|
}
|
|
|
|
func TestClassifyAgentService(t *testing.T) {
|
|
cases := []struct{ path, pkg, priority, want string }{{"/lib/systemd/system/cron.service", "cron", "important", "system"}, {"/lib/systemd/system/jellyfin.service", "jellyfin", "optional", "added"}, {"/etc/systemd/system/my.service", "", "", "local"}, {"/run/systemd/system/transient.service", "", "", "runtime"}}
|
|
for _, tc := range cases {
|
|
if got := classifyAgentService(tc.path, tc.pkg, tc.priority); got != tc.want {
|
|
t.Errorf("%s: got %s want %s", tc.path, got, tc.want)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestAgentServiceDiagnosticsHelpers(t *testing.T) {
|
|
if got := compactSystemdExec(`{ path=/usr/bin/example ; argv[]=/usr/bin/example --serve ; }`); got != "/usr/bin/example" {
|
|
t.Fatalf("unexpected executable: %q", got)
|
|
}
|
|
fields := limitedFields("a b c d", 2)
|
|
if len(fields) != 2 || fields[0] != "a" || fields[1] != "b" {
|
|
t.Fatalf("unexpected limited fields: %#v", fields)
|
|
}
|
|
ports := appendUniqueInt([]int{80}, 80)
|
|
ports = appendUniqueInt(ports, 443)
|
|
if len(ports) != 2 || ports[1] != 443 {
|
|
t.Fatalf("unexpected ports: %#v", ports)
|
|
}
|
|
}
|
|
|
|
func TestAgentReportAuthenticationAndOfflineState(t *testing.T) {
|
|
store, err := openStore(":memory:")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer store.Close()
|
|
token, _ := store.CreateAgentEnrollmentToken()
|
|
credentials, _ := store.EnrollAgent(agentEnrollmentRequest{Token: token, Name: "docker", Hostname: "vm", VMID: 101})
|
|
report := AgentReport{Hostname: "vm", Version: "test", DockerAvailable: true, Containers: []AgentContainer{{ID: "abc", Name: "web", State: "running"}}}
|
|
if err = store.SaveAgentReport(credentials.ID, "wrong", "127.0.0.1", report); err == nil {
|
|
t.Fatal("invalid secret accepted")
|
|
}
|
|
if err = store.SaveAgentReport(credentials.ID, credentials.Secret, "127.0.0.1", report); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
agents, err := store.Agents()
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(agents) != 1 || !agents[0].Online || len(agents[0].Report.Containers) != 1 {
|
|
t.Fatalf("unexpected agents: %#v", agents)
|
|
}
|
|
_, _ = store.db.Exec(`UPDATE agents SET last_seen=? WHERE id=?`, time.Now().Add(-time.Minute).Unix(), credentials.ID)
|
|
agents, _ = store.Agents()
|
|
if agents[0].Online {
|
|
t.Fatal("stale agent is online")
|
|
}
|
|
}
|
|
|
|
func TestAgentProblemsBecomeMaintenanceAwareAlerts(t *testing.T) {
|
|
metrics := dashboardMetrics{Agents: []ManagedAgent{{ID: "node", Name: "app", VMID: 105, Online: true, Report: AgentReport{
|
|
Services: []AgentService{{Name: "postgres.service", State: "failed", SubState: "failed"}},
|
|
Containers: []AgentContainer{{ID: "dead", Name: "web", State: "exited", Status: "Exited (1)"}}, DockerAvailable: true,
|
|
}}}}
|
|
alerts := evaluateAlerts(metrics, defaultThresholds())
|
|
window := MaintenanceWindow{Active: true, VMIDs: []int{105}}
|
|
active, planned := splitMaintenanceAlerts(alerts, window)
|
|
if len(planned) != 2 || len(active) != 0 {
|
|
t.Fatalf("active=%d planned=%d alerts=%#v", len(active), len(planned), alerts)
|
|
}
|
|
}
|
|
|
|
func TestAgentDiagnosticsBecomeAlerts(t *testing.T) {
|
|
metrics := dashboardMetrics{Agents: []ManagedAgent{{ID: "node", Name: "app", VMID: 105, Online: true, Report: AgentReport{
|
|
Services: []AgentService{{Name: "web.service", State: "active", Flapping: true, Restarts: 8, StartedAt: time.Now().Unix()}},
|
|
Filesystems: []AgentFilesystem{{Mountpoint: "/data", TotalBytes: 1000, UsedBytes: 950, UsedPercent: 95}},
|
|
}}}}
|
|
alerts := evaluateAlerts(metrics, defaultThresholds())
|
|
wanted := map[string]bool{"agent-flapping-node-web.service-105": false, "agent-filesystem-node-/data-105": false}
|
|
for _, alert := range alerts {
|
|
if _, ok := wanted[alert.ID]; ok {
|
|
wanted[alert.ID] = true
|
|
}
|
|
}
|
|
for id, found := range wanted {
|
|
if !found {
|
|
t.Fatalf("missing alert %s in %#v", id, alerts)
|
|
}
|
|
}
|
|
}
|