worker(alarms): exact-match ack resolution (no substring false-match) + ack-by-guid tests
This commit is contained in:
@@ -147,9 +147,9 @@ public sealed class SubtagAlarmConsumer : IMxAccessAlarmConsumer
|
||||
/// subtag; the operator-identity arguments are not surfaced through the
|
||||
/// subtag write.
|
||||
/// </summary>
|
||||
/// <param name="alarmName">The alarm name (object-rooted tag name or any reference fragment).</param>
|
||||
/// <param name="providerName">The provider name (unused for matching).</param>
|
||||
/// <param name="groupName">The group name (unused for matching).</param>
|
||||
/// <param name="alarmName">The alarm name (object-rooted tag name as the dispatcher derives it).</param>
|
||||
/// <param name="providerName">The provider name used to recompose the full reference for lookup.</param>
|
||||
/// <param name="groupName">The group name used to recompose the full reference for lookup.</param>
|
||||
/// <param name="ackComment">The acknowledgment comment.</param>
|
||||
/// <param name="ackOperatorName">The operator name (unused in subtag mode).</param>
|
||||
/// <param name="ackOperatorNode">The operator node (unused in subtag mode).</param>
|
||||
@@ -171,7 +171,7 @@ public sealed class SubtagAlarmConsumer : IMxAccessAlarmConsumer
|
||||
throw new ObjectDisposedException(nameof(SubtagAlarmConsumer));
|
||||
}
|
||||
|
||||
AlarmSubtagTarget? target = ResolveTargetByName(alarmName);
|
||||
AlarmSubtagTarget? target = ResolveTargetByName(alarmName, providerName, groupName);
|
||||
if (target is null)
|
||||
{
|
||||
return -1;
|
||||
@@ -278,27 +278,21 @@ public sealed class SubtagAlarmConsumer : IMxAccessAlarmConsumer
|
||||
record.AlarmGuid = SyntheticAlarmGuid.ForReference(reference);
|
||||
}
|
||||
|
||||
private AlarmSubtagTarget? ResolveTargetByName(string? alarmName)
|
||||
private AlarmSubtagTarget? ResolveTargetByName(string? alarmName, string? providerName, string? groupName)
|
||||
{
|
||||
if (string.IsNullOrEmpty(alarmName))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// Match a target whose full reference contains the supplied name. The
|
||||
// dispatcher derives (name, provider, group) from the composed
|
||||
// reference, so the object-rooted tag name is always a substring of the
|
||||
// target's AlarmFullReference.
|
||||
foreach (AlarmSubtagTarget target in targetsByReference.Values)
|
||||
{
|
||||
string reference = target.AlarmFullReference ?? string.Empty;
|
||||
if (reference.IndexOf(alarmName!, StringComparison.OrdinalIgnoreCase) >= 0)
|
||||
{
|
||||
return target;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
// Recompose the full reference from the same (provider, group, name)
|
||||
// tuple the dispatcher derived, then do an exact OrdinalIgnoreCase
|
||||
// lookup in targetsByReference. This avoids the false-positive that a
|
||||
// substring scan would produce when one alarm name is a prefix of
|
||||
// another (e.g. "Level.Hi" matching "Level.HiHi").
|
||||
string composed = AlarmRecordTransitionMapper.ComposeFullReference(providerName, groupName, alarmName);
|
||||
targetsByReference.TryGetValue(composed, out AlarmSubtagTarget? target);
|
||||
return target;
|
||||
}
|
||||
|
||||
private int WriteAckComment(AlarmSubtagTarget target, string ackComment)
|
||||
|
||||
Reference in New Issue
Block a user