1c8a67eece
Both defects were live on both demo boxes: the recipe said namespace "root" while storage.cfg said demo-felhom/demo-hp, and it never named which of two content=backup dir storages holds the local archives. R-106: the namespace came from the listed snapshot, but PBS omits `ns` per item once the list is namespace-scoped, so it was always empty and normalised to "root". It now resolves from the pbs STORAGE (storage.cfg's `namespace`) — the same field vzdump makes PVE read, so the recipe cannot disagree with the backup. R-109: backup_target resolves from the primary tier of cfg.Backup.BackupTiers(), the function the scheduler consults, and carries the mountpoint that separates /mnt/hdd_1 from /var/lib/vz. The resolver reports the tier IN EFFECT (daemon-start config), not agent.json on disk — a target move rewrites the file and deliberately does not restart. Unresolvable is recorded as unresolvable: resolved|unknown plus a distinct reason, never a default, an empty string, or a placeholder. Needs hub v0.83.0 — AssembleDRRecipe allow-lists top-level keys, so backup_target would otherwise be stored intact and dropped before any operator saw it. 9 tests, 4 red-proofs (each mutation asserted to have landed). Suite rc=0, 29 ok.
71 lines
2.6 KiB
Go
71 lines
2.6 KiB
Go
package hub
|
|
|
|
import (
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
|
|
"gitea.dooplex.hu/admin/felhom-agent/internal/capability"
|
|
)
|
|
|
|
func TestHostReport_FieldNamesAndEmptyCollections(t *testing.T) {
|
|
r := &HostReport{
|
|
HostID: "demo-host-01",
|
|
ReportedAt: "2026-06-08T12:00:00Z",
|
|
AgentVersion: "0.3.0",
|
|
Host: HostMetrics{
|
|
Node: "demo-felhom", CPUPercent: 3.2,
|
|
MemoryTotalBytes: 16777216000, MemoryUsedBytes: 4194304000, MemoryPercent: 25.0,
|
|
DiskTotalBytes: 152000000000, DiskUsedBytes: 30000000000, DiskPercent: 19.7,
|
|
LoadAvg: []string{"0.10", "0.20", "0.15"}, UptimeSeconds: 86400,
|
|
CPUTempC: intp(47), // nullable scalar — set here so the "no null" invariant stays meaningful
|
|
},
|
|
Guests: []Guest{{
|
|
VMID: 100, Name: "felhom-cust-acme", Status: "running", ControllerVersion: "",
|
|
Spec: &GuestSpec{Cores: 2, MemoryBytes: 2147483648, DiskBytes: 21474836480},
|
|
}},
|
|
StorageTargets: []StorageTarget{},
|
|
Backups: []Backup{},
|
|
RestoreTests: []RestoreTest{},
|
|
PBSSnapshots: []PBSSnapshot{},
|
|
AuditTail: []AuditEntry{},
|
|
Cloudflared: Cloudflared{Status: "active"},
|
|
Capabilities: []capability.Status{},
|
|
LeafFingerprint: "60b5974d586f5f3c8ec41eb998d0f07406178219c36bf6d3ff377570279d8245",
|
|
}
|
|
// dr_recipe is always set on the real path (Collect); set it here too so the "no null" invariant
|
|
// covers it (empty pbs is omitempty → omitted, never null).
|
|
r.DRRecipe = BuildDRRecipeHostHalf(r.Guests, r.StorageTargets, r.PBSSnapshots, ConfiguredBackupTarget{})
|
|
b, err := json.Marshal(r)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
got := string(b)
|
|
|
|
for _, field := range []string{
|
|
`"host_id":"demo-host-01"`, `"reported_at":`, `"agent_version":"0.3.0"`,
|
|
`"cpu_percent":3.2`, `"memory_total_bytes":16777216000`, `"loadavg":["0.10","0.20","0.15"]`,
|
|
`"disk_percent":19.7`, `"uptime_seconds":86400`, `"cpu_temp_c":47`,
|
|
`"vmid":100`, `"controller_version":""`, `"memory_bytes":2147483648`,
|
|
`"cloudflared":{"status":"active"}`,
|
|
// empty collections must be [] not null
|
|
`"storage_targets":[]`, `"backups":[]`, `"restore_tests":[]`, `"pbs_snapshots":[]`, `"audit_tail":[]`,
|
|
`"capabilities":[]`,
|
|
`"leaf_fingerprint":"60b5974d586f5f3c8ec41eb998d0f07406178219c36bf6d3ff377570279d8245"`,
|
|
} {
|
|
if !strings.Contains(got, field) {
|
|
t.Errorf("report JSON missing %s\n got: %s", field, got)
|
|
}
|
|
}
|
|
if strings.Contains(got, "null") {
|
|
t.Errorf("report JSON must not contain null (empty collections should be []): %s", got)
|
|
}
|
|
}
|
|
|
|
func TestGuest_SpecOmittedWhenUnknown(t *testing.T) {
|
|
b, _ := json.Marshal(Guest{VMID: 9, Name: "g", Status: "unknown"})
|
|
if strings.Contains(string(b), "spec") {
|
|
t.Errorf("unknown guest should omit spec, got %s", b)
|
|
}
|
|
}
|