Add tests for previously uncovered State methods: - SetConnectionHealth / RemoveConnectionHealth - UpdatePBSBackups - UpdatePMGBackups Improves internal/models coverage from 67.0% to 71.9%.
359 lines
9.3 KiB
Go
359 lines
9.3 KiB
Go
package models
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestUpsertHost(t *testing.T) {
|
|
state := NewState()
|
|
|
|
// Test insert new host
|
|
host1 := Host{
|
|
ID: "host-1",
|
|
Hostname: "server-1",
|
|
Status: "online",
|
|
}
|
|
state.UpsertHost(host1)
|
|
|
|
hosts := state.GetHosts()
|
|
if len(hosts) != 1 {
|
|
t.Fatalf("Expected 1 host, got %d", len(hosts))
|
|
}
|
|
if hosts[0].ID != "host-1" {
|
|
t.Errorf("Expected host ID 'host-1', got %q", hosts[0].ID)
|
|
}
|
|
|
|
// Test update existing host
|
|
host1Updated := Host{
|
|
ID: "host-1",
|
|
Hostname: "server-1",
|
|
Status: "offline",
|
|
}
|
|
state.UpsertHost(host1Updated)
|
|
|
|
hosts = state.GetHosts()
|
|
if len(hosts) != 1 {
|
|
t.Fatalf("Expected 1 host after update, got %d", len(hosts))
|
|
}
|
|
if hosts[0].Status != "offline" {
|
|
t.Errorf("Expected status 'offline', got %q", hosts[0].Status)
|
|
}
|
|
|
|
// Test multiple hosts and sorting
|
|
state.UpsertHost(Host{ID: "host-2", Hostname: "alpha-server"})
|
|
state.UpsertHost(Host{ID: "host-3", Hostname: "zulu-server"})
|
|
|
|
hosts = state.GetHosts()
|
|
if len(hosts) != 3 {
|
|
t.Fatalf("Expected 3 hosts, got %d", len(hosts))
|
|
}
|
|
|
|
// Hosts should be sorted by hostname
|
|
if hosts[0].Hostname != "alpha-server" {
|
|
t.Errorf("First host should be 'alpha-server', got %q", hosts[0].Hostname)
|
|
}
|
|
}
|
|
|
|
func TestGetHosts_Copy(t *testing.T) {
|
|
state := NewState()
|
|
|
|
state.UpsertHost(Host{ID: "host-1", Hostname: "server-1"})
|
|
|
|
hosts1 := state.GetHosts()
|
|
hosts2 := state.GetHosts()
|
|
|
|
// Modify one slice
|
|
if len(hosts1) > 0 {
|
|
hosts1[0].Hostname = "modified"
|
|
}
|
|
|
|
// Other slice should be unchanged
|
|
if len(hosts2) > 0 && hosts2[0].Hostname == "modified" {
|
|
t.Error("GetHosts should return a copy, not the same slice")
|
|
}
|
|
|
|
// Original state should be unchanged
|
|
hosts3 := state.GetHosts()
|
|
if hosts3[0].Hostname == "modified" {
|
|
t.Error("State should be unchanged by modifications to returned slice")
|
|
}
|
|
}
|
|
|
|
func TestRemoveHost(t *testing.T) {
|
|
state := NewState()
|
|
|
|
// Insert hosts
|
|
state.UpsertHost(Host{ID: "host-1", Hostname: "server1"})
|
|
state.UpsertHost(Host{ID: "host-2", Hostname: "server2"})
|
|
|
|
// Remove existing host
|
|
removed, ok := state.RemoveHost("host-1")
|
|
if !ok {
|
|
t.Error("Expected RemoveHost to return true for existing host")
|
|
}
|
|
if removed.ID != "host-1" {
|
|
t.Errorf("Expected removed host ID 'host-1', got %q", removed.ID)
|
|
}
|
|
|
|
hosts := state.GetHosts()
|
|
if len(hosts) != 1 {
|
|
t.Fatalf("Expected 1 host after removal, got %d", len(hosts))
|
|
}
|
|
if hosts[0].ID != "host-2" {
|
|
t.Errorf("Remaining host should be 'host-2', got %q", hosts[0].ID)
|
|
}
|
|
|
|
// Remove non-existing host
|
|
removed, ok = state.RemoveHost("non-existent")
|
|
if ok {
|
|
t.Error("Expected RemoveHost to return false for non-existent host")
|
|
}
|
|
if removed.ID != "" {
|
|
t.Errorf("Expected empty Host for non-existent removal, got ID %q", removed.ID)
|
|
}
|
|
}
|
|
|
|
func TestSetHostStatus(t *testing.T) {
|
|
state := NewState()
|
|
|
|
// Test with no hosts
|
|
changed := state.SetHostStatus("host-1", "online")
|
|
if changed {
|
|
t.Error("SetHostStatus should return false when host doesn't exist")
|
|
}
|
|
|
|
// Add host and set status
|
|
state.UpsertHost(Host{ID: "host-1", Hostname: "server1", Status: "offline"})
|
|
|
|
changed = state.SetHostStatus("host-1", "online")
|
|
if !changed {
|
|
t.Error("SetHostStatus should return true when host exists")
|
|
}
|
|
|
|
hosts := state.GetHosts()
|
|
if hosts[0].Status != "online" {
|
|
t.Errorf("Expected status 'online', got %q", hosts[0].Status)
|
|
}
|
|
|
|
// Set same status (no change)
|
|
changed = state.SetHostStatus("host-1", "online")
|
|
if !changed {
|
|
t.Error("SetHostStatus should return true even when status unchanged")
|
|
}
|
|
}
|
|
|
|
func TestTouchHost(t *testing.T) {
|
|
state := NewState()
|
|
|
|
now := time.Now()
|
|
|
|
// Test with non-existent host
|
|
ok := state.TouchHost("host-1", now)
|
|
if ok {
|
|
t.Error("TouchHost should return false for non-existent host")
|
|
}
|
|
|
|
// Add host and touch it
|
|
state.UpsertHost(Host{ID: "host-1", Hostname: "server1"})
|
|
|
|
later := now.Add(time.Hour)
|
|
ok = state.TouchHost("host-1", later)
|
|
if !ok {
|
|
t.Error("TouchHost should return true for existing host")
|
|
}
|
|
|
|
hosts := state.GetHosts()
|
|
if !hosts[0].LastSeen.Equal(later) {
|
|
t.Errorf("LastSeen should be updated to %v, got %v", later, hosts[0].LastSeen)
|
|
}
|
|
}
|
|
|
|
func TestUpdateRecentlyResolved(t *testing.T) {
|
|
state := NewState()
|
|
|
|
now := time.Now()
|
|
alerts := []ResolvedAlert{
|
|
{
|
|
Alert: Alert{
|
|
ID: "alert-1",
|
|
Type: "cpu_high",
|
|
Level: "warning",
|
|
ResourceName: "server-1",
|
|
Message: "High CPU usage",
|
|
},
|
|
ResolvedTime: now,
|
|
},
|
|
{
|
|
Alert: Alert{
|
|
ID: "alert-2",
|
|
Type: "disk_low",
|
|
Level: "critical",
|
|
ResourceName: "server-2",
|
|
Message: "Low disk space",
|
|
},
|
|
ResolvedTime: now.Add(-time.Hour),
|
|
},
|
|
}
|
|
|
|
state.UpdateRecentlyResolved(alerts)
|
|
|
|
// The method updates internal state - verify via snapshot or other means
|
|
// Since RecentlyResolvedAlerts might be accessed differently, just verify no panic
|
|
// and method executes correctly
|
|
}
|
|
|
|
func TestSetConnectionHealth(t *testing.T) {
|
|
state := NewState()
|
|
|
|
// Set connection healthy
|
|
state.SetConnectionHealth("pve-cluster-1", true)
|
|
|
|
snapshot := state.GetSnapshot()
|
|
if healthy, ok := snapshot.ConnectionHealth["pve-cluster-1"]; !ok || !healthy {
|
|
t.Error("Expected connection to be healthy")
|
|
}
|
|
|
|
// Set connection unhealthy
|
|
state.SetConnectionHealth("pve-cluster-1", false)
|
|
|
|
snapshot = state.GetSnapshot()
|
|
if healthy, ok := snapshot.ConnectionHealth["pve-cluster-1"]; !ok || healthy {
|
|
t.Error("Expected connection to be unhealthy")
|
|
}
|
|
|
|
// Multiple connections
|
|
state.SetConnectionHealth("pve-cluster-2", true)
|
|
state.SetConnectionHealth("pbs-instance-1", true)
|
|
|
|
snapshot = state.GetSnapshot()
|
|
if len(snapshot.ConnectionHealth) != 3 {
|
|
t.Errorf("Expected 3 connection health entries, got %d", len(snapshot.ConnectionHealth))
|
|
}
|
|
}
|
|
|
|
func TestRemoveConnectionHealth(t *testing.T) {
|
|
state := NewState()
|
|
|
|
// Set up connection health entries
|
|
state.SetConnectionHealth("pve-cluster-1", true)
|
|
state.SetConnectionHealth("pve-cluster-2", false)
|
|
|
|
// Remove one
|
|
state.RemoveConnectionHealth("pve-cluster-1")
|
|
|
|
snapshot := state.GetSnapshot()
|
|
if _, ok := snapshot.ConnectionHealth["pve-cluster-1"]; ok {
|
|
t.Error("Expected pve-cluster-1 to be removed")
|
|
}
|
|
if _, ok := snapshot.ConnectionHealth["pve-cluster-2"]; !ok {
|
|
t.Error("Expected pve-cluster-2 to still exist")
|
|
}
|
|
|
|
// Remove non-existent (should not panic)
|
|
state.RemoveConnectionHealth("non-existent")
|
|
|
|
// Remove remaining
|
|
state.RemoveConnectionHealth("pve-cluster-2")
|
|
snapshot = state.GetSnapshot()
|
|
if len(snapshot.ConnectionHealth) != 0 {
|
|
t.Errorf("Expected empty connection health map, got %d entries", len(snapshot.ConnectionHealth))
|
|
}
|
|
}
|
|
|
|
func TestUpdatePBSBackups(t *testing.T) {
|
|
state := NewState()
|
|
|
|
now := time.Now()
|
|
|
|
// Add backups from first instance
|
|
backups1 := []PBSBackup{
|
|
{ID: "backup-1", Instance: "pbs-1", BackupTime: now},
|
|
{ID: "backup-2", Instance: "pbs-1", BackupTime: now.Add(-time.Hour)},
|
|
}
|
|
state.UpdatePBSBackups("pbs-1", backups1)
|
|
|
|
snapshot := state.GetSnapshot()
|
|
if len(snapshot.PBSBackups) != 2 {
|
|
t.Fatalf("Expected 2 backups, got %d", len(snapshot.PBSBackups))
|
|
}
|
|
|
|
// Add backups from second instance
|
|
backups2 := []PBSBackup{
|
|
{ID: "backup-3", Instance: "pbs-2", BackupTime: now.Add(-30 * time.Minute)},
|
|
}
|
|
state.UpdatePBSBackups("pbs-2", backups2)
|
|
|
|
snapshot = state.GetSnapshot()
|
|
if len(snapshot.PBSBackups) != 3 {
|
|
t.Fatalf("Expected 3 backups, got %d", len(snapshot.PBSBackups))
|
|
}
|
|
|
|
// Update first instance (should replace its backups)
|
|
backups1Updated := []PBSBackup{
|
|
{ID: "backup-4", Instance: "pbs-1", BackupTime: now.Add(time.Hour)},
|
|
}
|
|
state.UpdatePBSBackups("pbs-1", backups1Updated)
|
|
|
|
snapshot = state.GetSnapshot()
|
|
if len(snapshot.PBSBackups) != 2 {
|
|
t.Fatalf("Expected 2 backups after update, got %d", len(snapshot.PBSBackups))
|
|
}
|
|
|
|
// Verify pbs-1 backups were replaced
|
|
hasOldBackup := false
|
|
for _, b := range snapshot.PBSBackups {
|
|
if b.ID == "backup-1" || b.ID == "backup-2" {
|
|
hasOldBackup = true
|
|
break
|
|
}
|
|
}
|
|
if hasOldBackup {
|
|
t.Error("Old pbs-1 backups should have been replaced")
|
|
}
|
|
}
|
|
|
|
func TestUpdatePMGBackups(t *testing.T) {
|
|
state := NewState()
|
|
|
|
now := time.Now()
|
|
|
|
// Add backups from first instance
|
|
backups1 := []PMGBackup{
|
|
{Filename: "backup-1.conf", Instance: "pmg-1", BackupTime: now},
|
|
{Filename: "backup-2.conf", Instance: "pmg-1", BackupTime: now.Add(-time.Hour)},
|
|
}
|
|
state.UpdatePMGBackups("pmg-1", backups1)
|
|
|
|
snapshot := state.GetSnapshot()
|
|
if len(snapshot.PMGBackups) != 2 {
|
|
t.Fatalf("Expected 2 backups, got %d", len(snapshot.PMGBackups))
|
|
}
|
|
|
|
// Backups should be sorted by time (newest first)
|
|
if snapshot.PMGBackups[0].BackupTime.Before(snapshot.PMGBackups[1].BackupTime) {
|
|
t.Error("Backups should be sorted by time descending")
|
|
}
|
|
|
|
// Add backups from second instance
|
|
backups2 := []PMGBackup{
|
|
{Filename: "backup-3.conf", Instance: "pmg-2", BackupTime: now.Add(-30 * time.Minute)},
|
|
}
|
|
state.UpdatePMGBackups("pmg-2", backups2)
|
|
|
|
snapshot = state.GetSnapshot()
|
|
if len(snapshot.PMGBackups) != 3 {
|
|
t.Fatalf("Expected 3 backups, got %d", len(snapshot.PMGBackups))
|
|
}
|
|
|
|
// Update first instance with empty (should remove its backups)
|
|
state.UpdatePMGBackups("pmg-1", []PMGBackup{})
|
|
|
|
snapshot = state.GetSnapshot()
|
|
if len(snapshot.PMGBackups) != 1 {
|
|
t.Fatalf("Expected 1 backup after clearing pmg-1, got %d", len(snapshot.PMGBackups))
|
|
}
|
|
if snapshot.PMGBackups[0].Instance != "pmg-2" {
|
|
t.Error("Remaining backup should be from pmg-2")
|
|
}
|
|
}
|