using System.Diagnostics.Metrics; using System.Linq; using FluentAssertions; using StellaOps.Findings.Ledger.Observability; using Xunit; namespace StellaOps.Findings.Ledger.Tests.Observability; public class LedgerMetricsTests { [Fact] public void RecordProjectionApply_emits_histogram_and_counter_with_tags() { var histogramValues = new List<(double Value, KeyValuePair[] Tags)>(); var counterValues = new List<(long Value, KeyValuePair[] Tags)>(); using var listener = new MeterListener { InstrumentPublished = (instrument, l) => { if (instrument.Meter.Name == "StellaOps.Findings.Ledger") { l.EnableMeasurementEvents(instrument); } } }; listener.SetMeasurementEventCallback((instrument, measurement, tags, state) => { if (instrument.Name is "ledger_projection_apply_seconds" or "ledger_projection_lag_seconds") { histogramValues.Add((measurement, tags.ToArray())); } }); listener.SetMeasurementEventCallback((instrument, measurement, tags, state) => { if (instrument.Name == "ledger_projection_events_total") { counterValues.Add((measurement, tags.ToArray())); } }); listener.Start(); LedgerMetrics.RecordProjectionApply( TimeSpan.FromMilliseconds(40), 1.2, "tenant-x", "finding.status.changed", "v1.0", "affected"); histogramValues.Should().NotBeEmpty(); counterValues.Should().NotBeEmpty(); var tags = histogramValues.First().Tags.ToDictionary(kv => kv.Key, kv => kv.Value?.ToString()); tags["tenant"].Should().Be("tenant-x"); tags["event_type"].Should().Be("finding.status.changed"); tags["policy_version"].Should().Be("v1.0"); tags["evaluation_status"].Should().Be("affected"); } }