test(alarms): alarmmgr observation probe — log wnwrap transitions over 35s

This commit is contained in:
Joseph Doherty
2026-06-14 01:41:21 -04:00
parent 64db828d71
commit 1502e3f51d
@@ -0,0 +1,131 @@
// AlarmmgrObserveProbe.cs
//
// Independent oracle for whether the dev-rig alarms actually toggle. Subscribes
// via the native alarmmgr route (WnWrapAlarmConsumer / wwAlarmConsumerClass),
// polls for ~35s, and logs every alarm transition it observes (Raise / Clear /
// Ack). If TestMachine_001.TestAlarm001 is being flipped on a ~10s cadence this
// will show alternating Raise/Clear; if nothing toggles it shows only the
// initial active snapshot. Runs only with MXGATEWAY_RUN_LIVE_MXACCESS_TESTS=1.
//
// net48/x86: no init-only props, records, or index/range operators.
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading;
using WNWRAPCONSUMERLib;
using ZB.MOM.WW.MxGateway.Worker.MxAccess;
using ZB.MOM.WW.MxGateway.Worker.Tests.TestSupport;
using Xunit.Abstractions;
namespace ZB.MOM.WW.MxGateway.Worker.Tests.Probes;
/// <summary>
/// Observation probe that reports alarm transitions seen through the native
/// alarmmgr (wnwrap) consumer, to verify whether the rig's alarms toggle.
/// </summary>
public sealed class AlarmmgrObserveProbe
{
private static readonly string SubscriptionExpression =
string.Format(@"\\{0}\Galaxy!DEV", Environment.MachineName);
private readonly ITestOutputHelper output;
private readonly ConcurrentQueue<string> log = new ConcurrentQueue<string>();
private readonly Stopwatch elapsed = Stopwatch.StartNew();
/// <summary>Initializes a new instance of the AlarmmgrObserveProbe class.</summary>
/// <param name="output">Test output helper for logging.</param>
public AlarmmgrObserveProbe(ITestOutputHelper output)
{
this.output = output;
}
/// <summary>
/// Subscribes via the alarmmgr consumer and logs every transition seen
/// over a ~35s window plus the final active-alarm snapshot.
/// </summary>
[LiveMxAccessFact]
public void Observe_AlarmTransitions_ViaAlarmmgr()
{
Exception? threadException = null;
ManualResetEventSlim done = new ManualResetEventSlim(false);
Thread thread = new Thread(() =>
{
try { Run(); }
catch (Exception ex) { threadException = ex; }
finally { done.Set(); }
});
thread.IsBackground = false;
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
done.Wait();
thread.Join();
List<string> lines = new List<string>();
string? line;
while (log.TryDequeue(out line))
{
output.WriteLine(line);
lines.Add(line);
}
string logPath = Environment.GetEnvironmentVariable("PROBE_LOG")
?? System.IO.Path.Combine(System.IO.Path.GetTempPath(), "alarmmgr-observe.log");
try { System.IO.File.WriteAllLines(logPath, lines); }
catch (Exception writeEx) { output.WriteLine("log write failed: " + writeEx.Message); }
if (threadException != null)
{
throw threadException;
}
}
private void Run()
{
Log("=== alarmmgr (wnwrap) observation ===");
Log("Subscription: " + SubscriptionExpression);
using WnWrapAlarmConsumer consumer = new WnWrapAlarmConsumer(
new wwAlarmConsumerClass(), maxAlarmsPerFetch: 1024);
int transitionCount = 0;
consumer.AlarmTransitionEmitted += (_, e) =>
{
Interlocked.Increment(ref transitionCount);
Log(string.Format(
"transition: Tag='{0}' State={1} Prev={2} Group='{3}' Provider='{4}'",
e.Record.TagName, e.Record.State, e.PreviousState,
e.Record.Group, e.Record.ProviderName));
};
consumer.Subscribe(SubscriptionExpression);
Log("Subscribed. Polling every 1s for 35s ...");
DateTime deadline = DateTime.UtcNow + TimeSpan.FromSeconds(35);
int polls = 0;
while (DateTime.UtcNow < deadline)
{
consumer.PollOnce();
polls++;
Thread.Sleep(1000);
}
Log(string.Format("Polling done. polls={0} transitions={1}", polls, transitionCount));
IReadOnlyList<MxAlarmSnapshotRecord> snapshot = consumer.SnapshotActiveAlarms();
Log(string.Format("Final active-alarm snapshot count={0}:", snapshot.Count));
foreach (MxAlarmSnapshotRecord r in snapshot)
{
Log(string.Format(" active: Tag='{0}' State={1} Group='{2}'",
r.TagName, r.State, r.Group));
}
Log("=== observation complete ===");
}
private void Log(string line)
{
log.Enqueue(string.Format("[t={0:F1}s] {1}", elapsed.Elapsed.TotalSeconds, line));
}
}