refactor(worker): alarm consumers resolve the AckMsg item instead of acking
IMxAccessAlarmConsumer.ResolveAckTarget/ResolveAckTargetByName replace AcknowledgeByGuid/AcknowledgeByName. wnwrap maps Galaxy-provider alarms to <tag>.AckMsg and drops its inert parallel ack consumer; subtag resolves to the target's AckCommentSubtag and no longer advises or writes it; ISubtagAlarmSource.Write is removed. Does not build alone: AlarmDispatcher moves to the new API in the next commit. Claude-Session: https://claude.ai/code/session_016J6isfcgqy4SB2RK3ZvFvT
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// Validates the subtag-fallback pipeline against a real Galaxy + MXAccess install:
|
||||
// LmxSubtagAlarmSource (own LMXProxyServerClass) ->
|
||||
// SubtagAlarmConsumer (state machine + AcknowledgeByName write) ->
|
||||
// SubtagAlarmConsumer (state machine + ResolveAckTargetByName) + AlarmAckWriter (AckMsg write) ->
|
||||
// synthesized MxAlarmTransitionEvent (Raise / Clear, Degraded=true, SyntheticGuid)
|
||||
//
|
||||
// FIELD NAMES CONFIRMED: InAlarm/Acked/AckMsg/Priority are the confirmed AVEVA
|
||||
@@ -49,8 +49,9 @@ namespace ZB.MOM.WW.MxGateway.Worker.Tests.Probes;
|
||||
/// synthesize <see cref="MxAlarmTransitionEvent"/> records from Galaxy
|
||||
/// alarm subtags using the confirmed AVEVA <c>AlarmExtension</c> field
|
||||
/// names (InAlarm/Acked/AckMsg/Priority), and that
|
||||
/// <see cref="SubtagAlarmConsumer.AcknowledgeByName"/> writes the
|
||||
/// ack-comment subtag (AckMsg) successfully.
|
||||
/// <see cref="SubtagAlarmConsumer.ResolveAckTargetByName"/> resolves the
|
||||
/// ack-comment subtag (AckMsg) that <see cref="AlarmAckWriter"/> then
|
||||
/// writes successfully.
|
||||
///
|
||||
/// Skip-gated; flip <c>Skip=null</c> on the dev rig with an alarm being
|
||||
/// driven (flip script or a manual operator/IDE toggle of the alarm
|
||||
@@ -119,7 +120,7 @@ public sealed class AlarmSubtagLiveSmokeTests
|
||||
/// real <c>LMXProxyServerClass</c>, collects a Raise then a Clear
|
||||
/// transition synthesized by <see cref="SubtagAlarmConsumer"/>, confirms
|
||||
/// the Degraded flag and synthetic GUID are stamped, then
|
||||
/// AcknowledgeByName and verifies the ack-comment write returns 0.
|
||||
/// acknowledges through the resolved ack-comment subtag and verifies the write succeeds.
|
||||
/// </summary>
|
||||
[Fact(Skip = "Live dev-rig smoke test — flip Skip=null with AVEVA + an alarm being driven (flip script or manual operator/IDE toggle of the alarm attribute). Subtag fallback path. Field names confirmed (InAlarm/Acked/AckMsg/Priority); live-validate runtime path resolves without intermediate alarm-condition segment.")]
|
||||
public void SubtagFallback_FullPipelineRoundTrip_SynthesizesRaiseAndAcknowledges()
|
||||
@@ -257,17 +258,9 @@ public sealed class AlarmSubtagLiveSmokeTests
|
||||
Log("InAlarm subtag delivered a value: " + inAlarmResolved);
|
||||
|
||||
// Decisive write: AckMsg. Returns 0 only if the address resolves and is writable.
|
||||
Log("AcknowledgeByName (writes AckMsg subtag) ...");
|
||||
int rc = consumer.AcknowledgeByName(
|
||||
alarmName: AlarmTagName,
|
||||
providerName: Provider,
|
||||
groupName: Group,
|
||||
ackComment: "subtag-resolution-probe",
|
||||
ackOperatorName: Environment.UserName,
|
||||
ackOperatorNode: Environment.MachineName,
|
||||
ackOperatorDomain: Environment.UserDomainName ?? string.Empty,
|
||||
ackOperatorFullName: Environment.UserName);
|
||||
Log(string.Format("AcknowledgeByName(AckMsg write) -> rc={0}", rc));
|
||||
Log("Acknowledge (writes AckMsg subtag via AlarmAckWriter) ...");
|
||||
int rc = AckViaWriter(consumer, "subtag-resolution-probe").NativeStatus;
|
||||
Log(string.Format("Ack (AckMsg write) -> rc={0}", rc));
|
||||
|
||||
DateTime settle = DateTime.UtcNow + TimeSpan.FromSeconds(2);
|
||||
while (DateTime.UtcNow < settle)
|
||||
@@ -392,21 +385,13 @@ public sealed class AlarmSubtagLiveSmokeTests
|
||||
Assert.True(foundInSnapshot,
|
||||
string.Format("Active alarm snapshot must contain '{0}' after a Raise.", AlarmFullReference));
|
||||
|
||||
// 3. AcknowledgeByName — writes the ack-comment subtag.
|
||||
// 3. Resolve the ack-comment subtag and write it as the operator.
|
||||
// The dispatcher derives (alarmName, provider, group) via the same
|
||||
// TryParseReference logic as AlarmsLiveSmokeTests.
|
||||
Log("Calling AcknowledgeByName ...");
|
||||
int rc = consumer.AcknowledgeByName(
|
||||
alarmName: AlarmTagName,
|
||||
providerName: Provider,
|
||||
groupName: Group,
|
||||
ackComment: "subtag-fallback-smoke ack",
|
||||
ackOperatorName: Environment.UserName,
|
||||
ackOperatorNode: Environment.MachineName,
|
||||
ackOperatorDomain: Environment.UserDomainName ?? string.Empty,
|
||||
ackOperatorFullName: Environment.UserName);
|
||||
Log("Acknowledging via AlarmAckWriter ...");
|
||||
int rc = AckViaWriter(consumer, "subtag-fallback-smoke ack").NativeStatus;
|
||||
|
||||
Log(string.Format("AcknowledgeByName -> rc={0}", rc));
|
||||
Log(string.Format("Ack -> rc={0}", rc));
|
||||
Assert.Equal(0, rc);
|
||||
|
||||
// 4. Wait for a Clear or Acknowledge transition to confirm the state
|
||||
@@ -501,6 +486,29 @@ public sealed class AlarmSubtagLiveSmokeTests
|
||||
/// Mirrors the pump pattern documented in
|
||||
/// <c>docs/MxAccessWorkerInstanceDesign.md</c>.
|
||||
/// </summary>
|
||||
/// <summary>
|
||||
/// Resolves the probe alarm's ack item through the consumer and writes it
|
||||
/// with <see cref="AlarmAckWriter"/> as the operator named by
|
||||
/// <c>MXGATEWAY_PROBE_ACK_USER</c>/<c>MXGATEWAY_PROBE_ACK_PASSWORD</c>
|
||||
/// (default: current user, empty password).
|
||||
/// </summary>
|
||||
private static AlarmAckResult AckViaWriter(SubtagAlarmConsumer consumer, string comment)
|
||||
{
|
||||
AlarmAckTarget target = consumer.ResolveAckTargetByName(AlarmTagName, Provider, Group);
|
||||
if (!target.Found)
|
||||
{
|
||||
return AlarmAckResult.FromTarget(target);
|
||||
}
|
||||
|
||||
using AlarmAckWriter writer = new AlarmAckWriter(
|
||||
new MxAccessComObjectFactory(), PumpMessages, TimeSpan.FromSeconds(5), AlarmAckWriter.DefaultClientName);
|
||||
return writer.Acknowledge(target.ItemAddress, comment, new AlarmAckOperator
|
||||
{
|
||||
UserName = Environment.GetEnvironmentVariable("MXGATEWAY_PROBE_ACK_USER") ?? Environment.UserName,
|
||||
Password = Environment.GetEnvironmentVariable("MXGATEWAY_PROBE_ACK_PASSWORD") ?? string.Empty,
|
||||
});
|
||||
}
|
||||
|
||||
private static void PumpMessages()
|
||||
{
|
||||
NativeMethods.MSG msg;
|
||||
|
||||
Reference in New Issue
Block a user