using System; using System.Collections.Generic; using System.Diagnostics.Metrics; using Microsoft.Extensions.Logging.Abstractions; using StellaOps.Concelier.WebService.Services; using StellaOps.Concelier.WebService.Diagnostics; using Xunit; namespace StellaOps.Concelier.WebService.Tests; public sealed class AdvisoryAiTelemetryTests : IDisposable { private readonly MeterListener _listener; private readonly List<(long Value, KeyValuePair[] Tags)> _guardrailMeasurements = new(); public AdvisoryAiTelemetryTests() { _listener = new MeterListener { InstrumentPublished = (instrument, listener) => { if (instrument.Meter.Name == AdvisoryAiMetrics.MeterName) { listener.EnableMeasurementEvents(instrument); } } }; _listener.SetMeasurementEventCallback((instrument, measurement, tags, state) => { if (instrument.Meter.Name == AdvisoryAiMetrics.MeterName && instrument.Name == "advisory_ai_guardrail_blocks_total") { _guardrailMeasurements.Add((measurement, tags.ToArray())); } }); _listener.Start(); } [Fact] public void TrackChunkResult_RecordsGuardrailCounts_ForCacheHits() { var telemetry = new AdvisoryAiTelemetry(NullLogger.Instance); var guardrailCounts = new Dictionary { { AdvisoryChunkGuardrailReason.BelowMinimumLength, 2 } }; telemetry.TrackChunkResult(new AdvisoryAiChunkRequestTelemetry( Tenant: "tenant-a", AdvisoryKey: "CVE-2099-0001", Result: "ok", Truncated: false, CacheHit: true, ObservationCount: 1, SourceCount: 1, ChunkCount: 1, Duration: TimeSpan.FromMilliseconds(5), GuardrailCounts: guardrailCounts)); var measurement = Assert.Single(_guardrailMeasurements); Assert.Equal(2, measurement.Value); var cacheHitTagFound = false; foreach (var tag in measurement.Tags) { if (tag.Key == "cache" && (string?)tag.Value == "hit") { cacheHitTagFound = true; break; } } Assert.True(cacheHitTagFound, "guardrail measurement should be tagged with cache hit outcome."); } public void Dispose() { _listener.Dispose(); } }