package ontology import ( "testing" ) func kinds(v ...string) *[]string { s := append([]string{}, v...) return &s } // monitoringTree mirrors the real shape of seeds/ontology.yaml: a declaration // on an abstract type that concrete subtypes inherit, an explicit none on a // topological type, a probeable type outside the infrastructure layer, and an // undeclared infrastructure type (the ontology gap this is meant to catch). func monitoringTree() *TypeTree { return &TypeTree{ Types: map[string]TypeInfo{ "entity": {IsAbstract: true, Layer: "meta"}, "compute-entity": {Parent: "entity", IsAbstract: true, Layer: "infrastructure"}, "machine": {Parent: "compute-entity", IsAbstract: true, Layer: "infrastructure", Monitoring: kinds("ping", "resource")}, "proxmox-host": {Parent: "machine", Layer: "infrastructure"}, "workstation": {Parent: "machine", Layer: "infrastructure"}, "service": {Parent: "entity", Layer: "infrastructure", Monitoring: kinds("http", "process")}, "site": {Parent: "entity", Layer: "infrastructure", Monitoring: kinds()}, "vlan": {Parent: "entity", Layer: "infrastructure"}, // undeclared: a gap "agent": {Parent: "entity", Layer: "governance", Monitoring: kinds("http")}, "signal": {Parent: "entity", Layer: "cognition"}, "document": {Parent: "entity", Layer: "governance"}, }, } } func TestMonitoringResolvesThroughHierarchy(t *testing.T) { tree := monitoringTree() cases := []struct { typ string wantKinds []string wantDecl bool wantSource string desc string }{ {"machine", []string{"ping", "resource"}, true, "machine", "declared on itself"}, {"proxmox-host", []string{"ping", "resource"}, true, "machine", "inherited from abstract parent"}, {"workstation", []string{"ping", "resource"}, true, "machine", "inherited by a sibling too"}, {"service", []string{"http", "process"}, true, "service", "declared on itself"}, {"site", nil, true, "site", "explicitly none — not a gap"}, {"agent", []string{"http"}, true, "agent", "explicit declaration beats the layer default"}, {"signal", nil, true, "", "cognition layer is implicitly none"}, {"document", nil, true, "", "governance layer is implicitly none"}, {"vlan", nil, false, "", "undeclared infrastructure type is a genuine gap"}, {"nonexistent", nil, false, "", "unknown type resolves to undeclared"}, } for _, c := range cases { got := tree.Monitoring(c.typ) if got.Declared != c.wantDecl { t.Errorf("%s (%s): Declared = %v, want %v", c.typ, c.desc, got.Declared, c.wantDecl) } if got.Source != c.wantSource { t.Errorf("%s (%s): Source = %q, want %q", c.typ, c.desc, got.Source, c.wantSource) } if len(got.Kinds) != len(c.wantKinds) { t.Errorf("%s (%s): Kinds = %v, want %v", c.typ, c.desc, got.Kinds, c.wantKinds) continue } for i, k := range c.wantKinds { if got.Kinds[i] != k { t.Errorf("%s (%s): Kinds[%d] = %q, want %q", c.typ, c.desc, i, got.Kinds[i], k) } } } } // The distinction between these two is what keeps coverageSweep from raising // permanent, unresolvable signals against entities that are working as intended. func TestMonitoringNoneIsNotTheSameAsUndeclared(t *testing.T) { tree := monitoringTree() site := tree.Monitoring("site") if !site.None() { t.Error("site declared `monitoring: none`, expected None() to report true") } vlan := tree.Monitoring("vlan") if vlan.None() { t.Error("vlan declared nothing at all — None() must not claim it opted out") } if vlan.Declared { t.Error("vlan is an undeclared infrastructure type; it should read as a gap") } } func TestMonitoringWants(t *testing.T) { tree := monitoringTree() svc := tree.Monitoring("service") if !svc.Wants("http") { t.Error("service should want an http check") } if svc.Wants("resource") { t.Error("service should not want a resource check") } if tree.Monitoring("site").Wants("http") { t.Error("an explicitly unmonitorable type wants nothing") } } func TestMonitoringSurvivesParentCycle(t *testing.T) { // The ingest rejects cycles; this guards the walker regardless. tree := &TypeTree{Types: map[string]TypeInfo{ "a": {Parent: "b", Layer: "infrastructure"}, "b": {Parent: "a", Layer: "infrastructure"}, }} got := tree.Monitoring("a") if got.Declared { t.Errorf("cyclic chain declared nothing, got %+v", got) } }