package metriccatalog import ( "bytes" "context" "encoding/json" "errors" "strings" "testing" "github.com/itworx/pulse/internal/datasource" ) func TestDefaultContainerMetricsUseUnraidCAdvisorNameLabel(t *testing.T) { catalog, err := DefaultRegistry() if err != nil { t.Fatal(err) } for _, semanticName := range []string{"container.cpu.utilization", "container.memory.used"} { metric, ok := catalog.Find(semanticName) if !ok { t.Fatalf("metric %q missing", semanticName) } if !strings.Contains(metric.QueryTemplate, `name={{container}}`) || strings.Contains(metric.QueryTemplate, `container={{container}}`) { t.Fatalf("metric %q does not target the Unraid cAdvisor name label: %s", semanticName, metric.QueryTemplate) } } } func TestDefaultCatalogValidatesAndHasDeterministicVersion(t *testing.T) { first, err := DefaultRegistry() if err != nil { t.Fatal(err) } second, err := DefaultRegistry() if err != nil { t.Fatal(err) } if first.Version() == "" || first.Version() != second.Version() { t.Fatalf("versions are not deterministic: %q/%q", first.Version(), second.Version()) } if len(first.Metrics()) < 1 || len(first.Bindings()) != len(first.Metrics()) { t.Fatal("catalog metrics/bindings mismatch") } for _, binding := range first.Bindings() { if binding.State != BindingUnsupported || len(binding.MissingCapabilities) == 0 { t.Fatalf("unconfigured binding was not explicit: %+v", binding) } } } func TestCapabilityBindingDistinguishesSupportedAndUnavailable(t *testing.T) { catalog, err := DefaultRegistry() if err != nil { t.Fatal(err) } metric := catalog.Metrics()[0] capability := metric.RequiredCapabilities[0] supported, err := New(Catalog{SchemaVersion: SchemaVersion, Metrics: []Definition{metric}}, datasource.CapabilitySet{{ID: capability, Version: "v1", State: datasource.CapabilityEnabled}}) if err != nil { t.Fatal(err) } if got := supported.Bindings()[0].State; got != BindingSupported { t.Fatalf("state=%q", got) } unavailable, err := New(Catalog{SchemaVersion: SchemaVersion, Metrics: []Definition{metric}}, datasource.CapabilitySet{{ID: capability, Version: "v1", State: datasource.CapabilityUnavailable}}) if err != nil { t.Fatal(err) } if got := unavailable.Bindings()[0].State; got != BindingUnavailable { t.Fatalf("state=%q", got) } } func TestCatalogVersionChangesWhenDefinitionChanges(t *testing.T) { original, err := DefaultRegistry() if err != nil { t.Fatal(err) } metrics := original.Metrics() metrics[0].Description += " changed" changed, err := New(Catalog{SchemaVersion: SchemaVersion, Metrics: metrics}, nil) if err != nil { t.Fatal(err) } if original.Version() == changed.Version() { t.Fatal("catalog version did not change") } } func TestLoadRejectsUnknownFieldsAndHonorsCancellation(t *testing.T) { ctx, cancel := context.WithCancel(context.Background()) cancel() if _, err := Load(ctx, bytes.NewBufferString(`{"schemaVersion":1,"metrics":[]}`), nil); !errors.Is(err, context.Canceled) { t.Fatalf("cancel error=%v", err) } // Plain encoding/json intentionally tolerates unknown fields; only Load is strict. var catalog Catalog if err := json.Unmarshal([]byte(`{"schemaVersion":1,"metrics":[],"unexpected":true}`), &catalog); err != nil { t.Fatalf("direct unmarshal rejected an unknown field: %v", err) } if _, err := Load(context.Background(), bytes.NewBufferString(`{"schemaVersion":1,"metrics":[],"unexpected":true}`), nil); err == nil { t.Fatal("unknown field accepted") } } func TestValidationRejectsUnknownPlaceholderDuplicateAndInvalidLimit(t *testing.T) { base := Definition{SemanticName: "host.cpu.utilization", Version: 1, Description: "cpu", Unit: "percent", ValueKind: "gauge", SourceKind: "prometheus", QueryTemplate: "up{host={{not_allowed}}}", AllowedLabels: []string{"instance"}, CardinalityBudget: 1, Limits: Limits{MaxRangeSeconds: 60, MaxSeries: 1, MaxPoints: 10, TimeoutSeconds: 1}, AllowedVisualizations: []string{"stat"}, FreshnessSeconds: 1} if _, err := New(Catalog{SchemaVersion: SchemaVersion, Metrics: []Definition{base}}, nil); err == nil { t.Fatal("unknown placeholder accepted") } base.QueryTemplate = "up" base.AllowedLabels = []string{"instance", "instance"} if _, err := New(Catalog{SchemaVersion: SchemaVersion, Metrics: []Definition{base}}, nil); err == nil { t.Fatal("duplicate label accepted") } base.AllowedLabels = []string{"instance"} base.Limits.MaxPoints = 9 if _, err := New(Catalog{SchemaVersion: SchemaVersion, Metrics: []Definition{base}}, nil); err == nil { t.Fatal("invalid points accepted") } }