test(alarms): alarmmgr observation probe — log wnwrap transitions over 35s
This commit is contained in:
@@ -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));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user