Pulse/internal/unifiedresources/pbs_pmg_registry_test.go
2026-07-30 17:23:38 +01:00

319 lines
10 KiB
Go

package unifiedresources
import (
"testing"
"time"
"github.com/rcourtman/pulse-go-rewrite/internal/models"
)
func TestIngestSnapshotIncludesPBSAndPMGInstances(t *testing.T) {
now := time.Now().UTC()
snapshot := models.StateSnapshot{
PBSInstances: []models.PBSInstance{
{
ID: "pbs-1",
Name: "pbs-main",
Host: "https://pbs.example.com:8007",
Status: "online",
Version: "3.2.1",
CPU: 22.5,
Memory: 48.0,
MemoryUsed: 8 * 1024 * 1024 * 1024,
MemoryTotal: 16 * 1024 * 1024 * 1024,
Uptime: 86400,
Datastores: []models.PBSDatastore{{
Name: "fast",
Status: "online",
Total: 100,
Used: 96,
}},
BackupJobs: []models.PBSBackupJob{{ID: "job-1"}},
JobHealthEvidence: []models.PBSJobHealthEvidence{{
ID: "sync-remote-a",
Family: "sync",
Store: "fast",
LastRunState: "OK",
LastRunUPID: "UPID:sync:1",
LastRunEndtime: now.Add(-time.Hour).Unix(),
Confidence: "direct-task-match",
EvidenceSource: "pbs-job-config",
EvidenceScope: "configured-job",
Freshness: models.PBSJobHealthFreshness{
ObservedAt: now,
LastRunEndTime: now.Add(-time.Hour),
State: "observed",
},
Posture: "healthy",
}},
ConnectionHealth: "online",
LastSeen: now,
},
},
PMGInstances: []models.PMGInstance{
{
ID: "pmg-1",
Name: "pmg-main",
Host: "https://pmg.example.com:8006",
GuestURL: "https://pmg.example.com/quarantine",
Status: "online",
Version: "8.2",
ConnectionHealth: "connected",
LastSeen: now,
LastUpdated: now,
MailStats: &models.PMGMailStats{
CountTotal: 1900,
BytesIn: 5_000_000,
BytesOut: 4_000_000,
SpamIn: 125,
VirusIn: 4,
JunkIn: 32,
PregreetRejects: 7,
UpdatedAt: now,
},
MailCount: []models.PMGMailCountPoint{{Timestamp: now, Count: 1900, CountIn: 1200, CountOut: 700, Timeframe: "hour", Index: 1}},
Nodes: []models.PMGNodeStatus{
{
Name: "pmg-node-1",
Status: "online",
Uptime: 43200,
QueueStatus: &models.PMGQueueStatus{
Active: 12,
Deferred: 5,
Hold: 2,
Incoming: 3,
Total: 22,
OldestAge: 1800,
UpdatedAt: now,
},
},
},
},
},
}
registry := NewRegistry(NewMemoryStore())
registry.IngestSnapshot(snapshot)
resources := registry.List()
if len(resources) != 3 {
t.Fatalf("expected 3 resources, got %d", len(resources))
}
var pbsResource *Resource
var datastoreResource *Resource
var pmgResource *Resource
for i := range resources {
resource := resources[i]
switch resource.Type {
case ResourceTypePBS:
pbsResource = &resource
case ResourceTypeStorage:
if resource.Storage != nil && resource.Storage.Platform == "pbs" {
datastoreResource = &resource
}
case ResourceTypePMG:
pmgResource = &resource
}
}
if pbsResource == nil {
t.Fatal("expected PBS resource")
}
if !containsDataSource(pbsResource.Sources, SourcePBS) {
t.Fatalf("expected PBS source, got %+v", pbsResource.Sources)
}
if pbsResource.Metrics == nil || pbsResource.Metrics.CPU == nil {
t.Fatalf("expected PBS CPU metrics, got %+v", pbsResource.Metrics)
}
if pbsResource.PBS == nil || pbsResource.PBS.DatastoreCount != 1 {
t.Fatalf("expected PBS payload with datastore count, got %+v", pbsResource.PBS)
}
if pbsResource.PBS.JobHealthEvidenceCount != 1 || len(pbsResource.PBS.JobHealthEvidence) != 1 {
t.Fatalf("expected PBS job health evidence ledger, got %+v", pbsResource.PBS)
}
if got := pbsResource.PBS.JobHealthEvidence[0]; got.Confidence != "direct-task-match" || got.EvidenceSource != "pbs-job-config" || got.EvidenceScope != "configured-job" || got.LastRunState != "OK" {
t.Fatalf("expected direct PBS job evidence with raw fields, got %+v", got)
}
if pbsResource.Status != StatusWarning {
t.Fatalf("expected PBS instance warning status from rolled-up datastore risk, got %q", pbsResource.Status)
}
if pbsResource.PBS.StorageRisk == nil || len(pbsResource.PBS.StorageRisk.Reasons) == 0 {
t.Fatalf("expected PBS instance storage risk payload, got %+v", pbsResource.PBS)
}
if len(pbsResource.Incidents) == 0 || pbsResource.Incidents[0].Code != "capacity_runway_low" {
t.Fatalf("expected rolled-up PBS incidents, got %+v", pbsResource.Incidents)
}
if datastoreResource == nil {
t.Fatal("expected PBS datastore storage resource")
}
if datastoreResource.Storage == nil {
t.Fatalf("expected PBS datastore storage metadata, got %+v", datastoreResource)
}
if datastoreResource.Storage.Platform != "pbs" || datastoreResource.Storage.Topology != "datastore" {
t.Fatalf("expected PBS datastore platform/topology, got %+v", datastoreResource.Storage)
}
if datastoreResource.Status != StatusWarning {
t.Fatalf("expected PBS datastore warning status from derived risk, got %q", datastoreResource.Status)
}
if datastoreResource.Storage.Risk == nil || len(datastoreResource.Storage.Risk.Reasons) == 0 {
t.Fatalf("expected PBS datastore risk payload, got %+v", datastoreResource.Storage)
}
if len(datastoreResource.Incidents) == 0 || datastoreResource.Incidents[0].Code != "capacity_runway_low" {
t.Fatalf("expected PBS datastore incidents, got %+v", datastoreResource.Incidents)
}
if datastoreResource.ParentID == nil || *datastoreResource.ParentID != pbsResource.ID {
t.Fatalf("expected PBS datastore to be parented under PBS instance, got %+v", datastoreResource.ParentID)
}
if pmgResource == nil {
t.Fatal("expected PMG resource")
}
if !containsDataSource(pmgResource.Sources, SourcePMG) {
t.Fatalf("expected PMG source, got %+v", pmgResource.Sources)
}
if pmgResource.Metrics == nil {
t.Fatalf("expected PMG metrics payload, got nil")
}
if pmgResource.PMG == nil || pmgResource.PMG.QueueTotal != 22 {
t.Fatalf("expected PMG payload with queue totals, got %+v", pmgResource.PMG)
}
if pmgResource.PMG.HostURL != "https://pmg.example.com:8006" || pmgResource.PMG.GuestURL != "https://pmg.example.com/quarantine" {
t.Fatalf("expected PMG URL payloads, got %+v", pmgResource.PMG)
}
if len(pmgResource.PMG.Nodes) != 1 || pmgResource.PMG.Nodes[0].QueueStatus == nil || pmgResource.PMG.Nodes[0].QueueStatus.OldestAge != 1800 {
t.Fatalf("expected PMG queue oldest age, got %+v", pmgResource.PMG.Nodes)
}
if pmgResource.PMG.MailStats == nil || pmgResource.PMG.MailStats.CountTotal != 1900 || pmgResource.PMG.MailStats.JunkIn != 32 || pmgResource.PMG.MailStats.PregreetRejects != 7 {
t.Fatalf("expected full PMG mail stats payload, got %+v", pmgResource.PMG.MailStats)
}
if len(pmgResource.PMG.MailCount) != 1 || pmgResource.PMG.MailCount[0].Index != 1 {
t.Fatalf("expected PMG mail count points, got %+v", pmgResource.PMG.MailCount)
}
}
func TestIngestSnapshotAssociatesPBSHostAgentPhysicalDisks(t *testing.T) {
now := time.Now().UTC()
registry := NewRegistry(nil)
registry.IngestSnapshot(models.StateSnapshot{
Hosts: []models.Host{
{
ID: "agent-pbs-1",
Hostname: "pbs-one.local",
MachineID: "machine-pbs-1",
Status: "online",
LastSeen: now,
Sensors: models.HostSensorSummary{
SMART: []models.HostDiskSMART{
{
Device: "/dev/sda",
Model: "Backup Drive",
Serial: "PBS-DISK-1",
Health: "PASSED",
Temperature: 36,
},
},
},
},
},
PBSInstances: []models.PBSInstance{
{
ID: "pbs-1",
Name: "pbs-one",
Host: "https://pbs-one.example:8007",
Status: "online",
LastSeen: now,
},
},
})
var hostResource *Resource
var diskResource *Resource
for _, resource := range registry.List() {
switch resource.Type {
case ResourceTypeAgent:
if resource.Agent != nil && resource.Agent.AgentID == "agent-pbs-1" {
copy := resource
hostResource = &copy
}
case ResourceTypePhysicalDisk:
if resource.PhysicalDisk != nil && resource.PhysicalDisk.Serial == "PBS-DISK-1" {
copy := resource
diskResource = &copy
}
}
}
if hostResource == nil || diskResource == nil {
t.Fatalf("expected correlated PBS host and disk, host=%+v disk=%+v", hostResource, diskResource)
}
if !containsDataSource(hostResource.Sources, SourcePBS) {
t.Fatalf("PBS host sources = %v, want PBS membership", hostResource.Sources)
}
if !containsDataSource(diskResource.Sources, SourceAgent) ||
!containsDataSource(diskResource.Sources, SourcePBS) {
t.Fatalf("PBS disk sources = %v, want agent and PBS", diskResource.Sources)
}
if diskResource.ParentID == nil || *diskResource.ParentID != hostResource.ID {
t.Fatalf(
"PBS disk parent = %v, want agent host %q to retain canonical parent authority",
diskResource.ParentID,
hostResource.ID,
)
}
RefreshCanonicalMetadata(diskResource)
if !containsPlatformScope(diskResource.PlatformScopes, "proxmox-pbs") {
t.Fatalf("PBS disk platform scopes = %v, want proxmox-pbs", diskResource.PlatformScopes)
}
}
func TestIngestSnapshotSkipsAmbiguousPBSHostAgentAssociation(t *testing.T) {
now := time.Now().UTC()
hosts := []models.Host{
{
ID: "agent-pbs-a",
Hostname: "pbs-one.local",
Status: "online",
LastSeen: now,
Sensors: models.HostSensorSummary{
SMART: []models.HostDiskSMART{{Device: "/dev/sda", Serial: "PBS-A"}},
},
},
{
ID: "agent-pbs-b",
Hostname: "pbs-one.example",
Status: "online",
LastSeen: now,
Sensors: models.HostSensorSummary{
SMART: []models.HostDiskSMART{{Device: "/dev/sdb", Serial: "PBS-B"}},
},
},
}
registry := NewRegistry(nil)
registry.IngestSnapshot(models.StateSnapshot{
Hosts: hosts,
PBSInstances: []models.PBSInstance{
{
ID: "pbs-1",
Name: "pbs-one",
Host: "https://pbs-one.example:8007",
Status: "online",
LastSeen: now,
},
},
})
for _, resource := range registry.ListByType(ResourceTypePhysicalDisk) {
if containsDataSource(resource.Sources, SourcePBS) {
t.Fatalf("ambiguous PBS host disk gained PBS source membership: %+v", resource)
}
}
}
func containsPlatformScope(values []string, expected string) bool {
for _, value := range values {
if value == expected {
return true
}
}
return false
}