mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-07 00:37:36 +00:00
175 lines
6 KiB
Go
175 lines
6 KiB
Go
package monitoring
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/alerts"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/config"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/models"
|
|
"github.com/rcourtman/pulse-go-rewrite/internal/unifiedresources"
|
|
)
|
|
|
|
func TestPersistGuestIdentity_Concurrent(t *testing.T) {
|
|
// Setup temporary metadata store
|
|
tmpDir, err := os.MkdirTemp("", "persist_test")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
// metadataFile := filepath.Join(tmpDir, "guest_metadata.json") // Actually NewGuestMetadataStore takes directory not file usually? No, it takes root dir?
|
|
// Let's verify standard usage. "store := NewGuestMetadataStore(tmpDir, nil)"
|
|
// Implementation: func NewGuestMetadataStore(dataPath string, fs FileSystem)
|
|
// Inside it does filepath.Join(dataPath, "guest_metadata.json") ?
|
|
// Let's re-read NewGuestMetadataStore in internal/config/guest_metadata.go via grep or similar if needed.
|
|
// But based on "config.NewGuestMetadataStore(metadataFile)" from my previous code failing, and grep showing "dataPath", it likely takes a Dir or File path.
|
|
// grep output: guestMetadataStore := NewGuestMetadataStore(dataPath, c.fs)
|
|
// Most likely directory.
|
|
|
|
store := config.NewGuestMetadataStore(tmpDir, nil)
|
|
|
|
guestKey := "pve1:node1:100"
|
|
|
|
// Test basic persistence
|
|
persistGuestIdentity(store, guestKey, "VM 100", "qemu")
|
|
|
|
// Wait a bit since persistGuestIdentity is async
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
meta := store.Get(guestKey)
|
|
if meta == nil || meta.LastKnownName != "VM 100" || meta.LastKnownType != "qemu" {
|
|
t.Errorf("Failed to persist guest identity: %+v", meta)
|
|
}
|
|
|
|
// Test persistence with "downgrade" prevention
|
|
// Set type to "oci" manually first
|
|
ociMeta := &config.GuestMetadata{
|
|
ID: guestKey,
|
|
LastKnownName: "VM 100",
|
|
LastKnownType: "oci",
|
|
}
|
|
_ = store.Set(guestKey, ociMeta)
|
|
|
|
// Try to update to "lxc"
|
|
persistGuestIdentity(store, guestKey, "VM 100", "lxc")
|
|
time.Sleep(50 * time.Millisecond)
|
|
|
|
meta = store.Get(guestKey)
|
|
if meta.LastKnownType != "oci" {
|
|
t.Errorf("Should ensure type 'oci' is preserved, got '%s'", meta.LastKnownType)
|
|
}
|
|
|
|
// Test persistence that shouldn't happen (no change) -> coverage of the if check
|
|
// Should not trigger Set()
|
|
persistGuestIdentity(store, guestKey, "VM 100", "oci")
|
|
}
|
|
|
|
func TestEnrichWithPersistedMetadata_Detail(t *testing.T) {
|
|
tmpDir, err := os.MkdirTemp("", "enrich_test")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
store := config.NewGuestMetadataStore(tmpDir, nil)
|
|
|
|
// 1. Add some metadata
|
|
_ = store.Set("pve1:node1:100", &config.GuestMetadata{ID: "pve1:node1:100", LastKnownName: "PersistedVM", LastKnownType: "qemu"})
|
|
_ = store.Set("pve1:node1:101", &config.GuestMetadata{ID: "pve1:node1:101", LastKnownName: "LiveVM", LastKnownType: "qemu"})
|
|
_ = store.Set("invalid:key", &config.GuestMetadata{ID: "invalid:key", LastKnownName: "BadKey", LastKnownType: "qemu"}) // coverage for bad key
|
|
_ = store.Set("pve1:node1:badid", &config.GuestMetadata{ID: "pve1:node1:badid", LastKnownName: "BadID", LastKnownType: "qemu"}) // coverage for atoi error
|
|
|
|
// 2. Setup existing lookup
|
|
lookup := make(map[string][]alerts.GuestLookup)
|
|
// VM 101 is live
|
|
lookup["101"] = []alerts.GuestLookup{
|
|
{Name: "LiveVM", Instance: "pve1", Node: "node1", VMID: 101},
|
|
}
|
|
|
|
// 3. Run enrich
|
|
enrichWithPersistedMetadata(store, lookup)
|
|
|
|
// 4. Verify
|
|
// 100 should be added
|
|
if entries, ok := lookup["100"]; !ok || len(entries) != 1 {
|
|
t.Error("Expected VM 100 to be enriched")
|
|
} else {
|
|
if entries[0].Name != "PersistedVM" {
|
|
t.Errorf("Expected name PersistedVM, got %s", entries[0].Name)
|
|
}
|
|
}
|
|
|
|
// 101 should not be duplicated (it was live)
|
|
if len(lookup["101"]) != 1 {
|
|
t.Error("VM 101 should not be duplicated")
|
|
}
|
|
}
|
|
|
|
func TestBuildGuestLookupsFromReadState_PrefersCanonicalWorkloads(t *testing.T) {
|
|
tmpDir, err := os.MkdirTemp("", "guest_lookup_read_state")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
store := config.NewGuestMetadataStore(tmpDir, nil)
|
|
registry := unifiedresources.NewRegistry(nil)
|
|
registry.IngestSnapshot(models.StateSnapshot{
|
|
VMs: []models.VM{{
|
|
ID: "vm-1",
|
|
Name: "canonical-vm",
|
|
Instance: "pve1",
|
|
Node: "node1",
|
|
VMID: 100,
|
|
Type: "qemu",
|
|
}},
|
|
Containers: []models.Container{{
|
|
ID: "ct-1",
|
|
Name: "canonical-ct",
|
|
Instance: "pve1",
|
|
Node: "node2",
|
|
VMID: 101,
|
|
Type: "oci",
|
|
IsOCI: true,
|
|
}},
|
|
})
|
|
|
|
byKey, byVMID := buildGuestLookupsFromReadState(registry, store)
|
|
|
|
vmKey := alerts.BuildGuestKey("pve1", "node1", 100)
|
|
if got := byKey[vmKey]; got.Name != "canonical-vm" || got.Type != "qemu" {
|
|
t.Fatalf("expected canonical vm lookup, got %+v", got)
|
|
}
|
|
ctKey := alerts.BuildGuestKey("pve1", "node2", 101)
|
|
if got := byKey[ctKey]; got.Name != "canonical-ct" || got.Type != "oci" {
|
|
t.Fatalf("expected canonical container lookup, got %+v", got)
|
|
}
|
|
if len(byVMID["100"]) != 1 || byVMID["100"][0].Name != "canonical-vm" {
|
|
t.Fatalf("expected vmid lookup for VM 100, got %+v", byVMID["100"])
|
|
}
|
|
if len(byVMID["101"]) != 1 || byVMID["101"][0].Name != "canonical-ct" {
|
|
t.Fatalf("expected vmid lookup for container 101, got %+v", byVMID["101"])
|
|
}
|
|
}
|
|
|
|
func TestBuildGuestLookupsFromReadState_UsesPersistedMetadataWhenCanonicalStateEmpty(t *testing.T) {
|
|
tmpDir, err := os.MkdirTemp("", "guest_lookup_persisted")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(tmpDir)
|
|
|
|
store := config.NewGuestMetadataStore(tmpDir, nil)
|
|
_ = store.Set("pve1:node1:100", &config.GuestMetadata{ID: "pve1:node1:100", LastKnownName: "persisted-vm", LastKnownType: "qemu"})
|
|
|
|
byKey, byVMID := buildGuestLookupsFromReadState(unifiedresources.NewRegistry(nil), store)
|
|
|
|
if len(byKey) != 0 {
|
|
t.Fatalf("expected no direct byKey entries without live canonical workloads, got %+v", byKey)
|
|
}
|
|
if len(byVMID["100"]) != 1 || byVMID["100"][0].Name != "persisted-vm" || byVMID["100"][0].Type != "qemu" {
|
|
t.Fatalf("expected persisted metadata fallback, got %+v", byVMID["100"])
|
|
}
|
|
}
|