test(alarms): drivable-alarm discovery scan across candidate alarm tags
This commit is contained in:
@@ -335,6 +335,97 @@ public sealed class AlarmSubtagLiveSmokeTests
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Discovery run: scans candidate alarm attributes for one whose value
|
||||
/// actually responds to an external write (so it can drive a full
|
||||
/// Raise/Clear lifecycle). Logs each candidate's before/after value and
|
||||
/// InAlarm; does not assert. Runs only with
|
||||
/// <c>MXGATEWAY_RUN_LIVE_MXACCESS_TESTS=1</c>. Side effect: flips any
|
||||
/// writable candidate.
|
||||
/// </summary>
|
||||
[LiveMxAccessFact]
|
||||
public void LiveProbe_FindDrivableAlarm()
|
||||
{
|
||||
Exception? threadException = null;
|
||||
ManualResetEventSlim done = new ManualResetEventSlim(false);
|
||||
Thread thread = new Thread(() =>
|
||||
{
|
||||
try { RunFindDrivable(); }
|
||||
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(), "alarm-find-drivable.log");
|
||||
try { System.IO.File.WriteAllLines(logPath, lines); } catch { /* best effort */ }
|
||||
if (threadException != null) { throw threadException; }
|
||||
}
|
||||
|
||||
private void RunFindDrivable()
|
||||
{
|
||||
string[] candidates = new string[]
|
||||
{
|
||||
"TestMachine_001.TestAlarm002",
|
||||
"TestMachine_001.TestAlarm003",
|
||||
"TestMachine_002.TestAlarm001",
|
||||
"TestMachine_003.TestAlarm001",
|
||||
};
|
||||
|
||||
Log("=== Find a drivable alarm ===");
|
||||
MxAccessComObjectFactory factory = new MxAccessComObjectFactory();
|
||||
using LmxSubtagAlarmSource source = new LmxSubtagAlarmSource(factory, clientName: null);
|
||||
|
||||
Dictionary<string, object?> latest =
|
||||
new Dictionary<string, object?>(StringComparer.OrdinalIgnoreCase);
|
||||
source.ValueChanged += (_, c) =>
|
||||
{
|
||||
latest[c.ItemAddress] = c.Value;
|
||||
Log(string.Format("raw: {0} = {1}", c.ItemAddress, c.Value ?? "<null>"));
|
||||
};
|
||||
|
||||
List<string> toAdvise = new List<string>();
|
||||
foreach (string cand in candidates)
|
||||
{
|
||||
toAdvise.Add(cand);
|
||||
toAdvise.Add(cand + ".InAlarm");
|
||||
}
|
||||
source.Advise(toAdvise);
|
||||
Log("Advised candidates. Pumping ...");
|
||||
PumpFor(TimeSpan.FromSeconds(7));
|
||||
|
||||
foreach (string cand in candidates)
|
||||
{
|
||||
object? before;
|
||||
latest.TryGetValue(cand, out before);
|
||||
bool beforeBool = before is bool bb && bb;
|
||||
Log(string.Format("[{0}] before: value={1} InAlarm={2}",
|
||||
cand, before ?? "<none>", latest.ContainsKey(cand + ".InAlarm") ? latest[cand + ".InAlarm"] : "<none>"));
|
||||
|
||||
Log(string.Format("[{0}] writing {1} ...", cand, !beforeBool));
|
||||
try { source.Write(cand, !beforeBool); }
|
||||
catch (Exception ex) { Log(string.Format("[{0}] write threw: {1}", cand, ex.Message)); continue; }
|
||||
|
||||
PumpFor(TimeSpan.FromSeconds(5));
|
||||
object? after;
|
||||
latest.TryGetValue(cand, out after);
|
||||
bool changed = !Equals(before, after);
|
||||
Log(string.Format("[{0}] after: value={1} InAlarm={2} -> {3}",
|
||||
cand, after ?? "<none>",
|
||||
latest.ContainsKey(cand + ".InAlarm") ? latest[cand + ".InAlarm"] : "<none>",
|
||||
changed ? "DRIVABLE (value changed)" : "not drivable (value held)"));
|
||||
}
|
||||
|
||||
Log("=== Find-drivable scan complete ===");
|
||||
}
|
||||
|
||||
private void RunSelfDriven()
|
||||
{
|
||||
// The discrete alarm's source attribute. Writing its boolean value
|
||||
|
||||
Reference in New Issue
Block a user