using System.Diagnostics.Metrics; using StellaOps.AirGap.Importer.Telemetry; namespace StellaOps.AirGap.Importer.Tests; public sealed class OfflineKitMetricsTests : IDisposable { private readonly MeterListener _listener; private readonly List _measurements = []; public OfflineKitMetricsTests() { _listener = new MeterListener(); _listener.InstrumentPublished = (instrument, listener) => { if (instrument.Meter.Name == OfflineKitMetrics.MeterName) { listener.EnableMeasurementEvents(instrument); } }; _listener.SetMeasurementEventCallback((instrument, measurement, tags, state) => { _measurements.Add(new RecordedMeasurement(instrument.Name, measurement, tags.ToArray())); }); _listener.SetMeasurementEventCallback((instrument, measurement, tags, state) => { _measurements.Add(new RecordedMeasurement(instrument.Name, measurement, tags.ToArray())); }); _listener.Start(); } public void Dispose() => _listener.Dispose(); [Fact] public void RecordImport_EmitsCounterWithLabels() { using var metrics = new OfflineKitMetrics(); metrics.RecordImport(status: "success", tenantId: "tenant-a"); Assert.Contains(_measurements, m => m.Name == "offlinekit_import_total" && m.Value is long v && v == 1 && m.HasTag(OfflineKitMetrics.TagNames.Status, "success") && m.HasTag(OfflineKitMetrics.TagNames.TenantId, "tenant-a")); } [Fact] public void RecordAttestationVerifyLatency_EmitsHistogramWithLabels() { using var metrics = new OfflineKitMetrics(); metrics.RecordAttestationVerifyLatency(attestationType: "dsse", seconds: 1.234, success: true); Assert.Contains(_measurements, m => m.Name == "offlinekit_attestation_verify_latency_seconds" && m.Value is double v && Math.Abs(v - 1.234) < 0.000_001 && m.HasTag(OfflineKitMetrics.TagNames.AttestationType, "dsse") && m.HasTag(OfflineKitMetrics.TagNames.Success, "true")); } [Fact] public void RecordRekorSuccess_EmitsCounterWithLabels() { using var metrics = new OfflineKitMetrics(); metrics.RecordRekorSuccess(mode: "offline"); Assert.Contains(_measurements, m => m.Name == "attestor_rekor_success_total" && m.Value is long v && v == 1 && m.HasTag(OfflineKitMetrics.TagNames.Mode, "offline")); } [Fact] public void RecordRekorRetry_EmitsCounterWithLabels() { using var metrics = new OfflineKitMetrics(); metrics.RecordRekorRetry(reason: "stale_snapshot"); Assert.Contains(_measurements, m => m.Name == "attestor_rekor_retry_total" && m.Value is long v && v == 1 && m.HasTag(OfflineKitMetrics.TagNames.Reason, "stale_snapshot")); } [Fact] public void RecordRekorInclusionLatency_EmitsHistogramWithLabels() { using var metrics = new OfflineKitMetrics(); metrics.RecordRekorInclusionLatency(seconds: 0.5, success: false); Assert.Contains(_measurements, m => m.Name == "rekor_inclusion_latency" && m.Value is double v && Math.Abs(v - 0.5) < 0.000_001 && m.HasTag(OfflineKitMetrics.TagNames.Success, "false")); } private sealed record RecordedMeasurement(string Name, object Value, IReadOnlyList> Tags) { public bool HasTag(string key, string expectedValue) => Tags.Any(t => t.Key == key && string.Equals(t.Value?.ToString(), expectedValue, StringComparison.Ordinal)); } }