using ZB.MOM.WW.ScadaBridge.Commons.Observability;
namespace ZB.MOM.WW.ScadaBridge.Host.Tests;
///
/// Infrastructure-free guards for : the meter name is the
/// stable value registered with OTel, and the emit helpers are safe to call (they are no-op
/// until follow-on tasks wire real emit points and a listener attaches).
///
public class ScadaBridgeTelemetryTests
{
[Fact]
public void MeterName_IsStableValue()
{
Assert.Equal("ZB.MOM.WW.ScadaBridge", ScadaBridgeTelemetry.MeterName);
}
///
/// Register row 32 class: SetQueueDepthProvider writes the SAME process-global
/// slot QueueDepthGaugeCollection (StoreAndForward.Tests) exists to serialize
/// access to — this test was mutating it with no clear and no [Collection],
/// leaving a stray () => 5 provider registered in the process for the rest of
/// this assembly's run. Since the meter/instrument state is a single static field on
/// ScadaBridgeTelemetry (Commons), the leak is scoped to whatever process this
/// assembly's test host runs in — it cannot reach StoreAndForward.Tests (a separate
/// assembly with its own test-host process), but it IS visible within Host.Tests, whose
/// MetricsEndpointTests boots a real in-process host (WebApplicationFactory
/// shares this AppDomain, not a child process) and scrapes /metrics, which
/// enumerates every registered gauge including this one.
///
/// Honesty note on what was and wasn't proven: a search of this assembly (and the whole
/// test tree) found no test today that asserts on the VALUE of
/// scadabridge.store_and_forward.queue.depth from Host.Tests or any other
/// same-process reader — MetricsEndpointTests only asserts the endpoint returns
/// Prometheus-shaped text, not this series' content, and the only test that DOES assert
/// on the value (QueueDepthGaugeTests) lives in StoreAndForward.Tests, a distinct
/// test-host process the leak cannot reach. So there is no currently-reproducible flake
/// to demonstrate here (no fork of this test with the leak left in has an assertion to
/// break) — the defect is a landmine for a FUTURE same-process reader, not a live one.
/// The fix (compare-and-clear in finally) closes the landmine regardless; a
/// [Collection] is intentionally not added since no second same-process reader of
/// this slot exists to serialize against as of this writing — re-run this search before
/// removing the guard below if that changes.
///
[Fact]
public void EmitHelpers_DoNotThrow()
{
Func queueDepthProvider = () => 5;
var ex = Record.Exception(() =>
{
ScadaBridgeTelemetry.RecordDeploymentApplied();
ScadaBridgeTelemetry.RecordInboundApiRequest("X");
ScadaBridgeTelemetry.SiteStreamSubscriberOpened();
ScadaBridgeTelemetry.SiteStreamSubscriberClosed();
ScadaBridgeTelemetry.LiveAlarmAggregatorStarted();
ScadaBridgeTelemetry.LiveAlarmAggregatorStopped();
ScadaBridgeTelemetry.RecordLiveAlarmStreamReconnect();
ScadaBridgeTelemetry.SetQueueDepthProvider(queueDepthProvider);
});
try
{
Assert.Null(ex);
}
finally
{
// Compare-and-clear: only removes OUR delegate from the process-global slot, so
// a legitimate concurrent registrant (a real StoreAndForwardService started
// elsewhere in this process) is never stomped — mirrors
// ScadaBridgeTelemetry.ClearQueueDepthProvider's own doc'd contract.
ScadaBridgeTelemetry.ClearQueueDepthProvider(queueDepthProvider);
}
}
}