feat(scripted-alarms): materialise real Part 9 AlarmConditionState nodes (T14)
This commit is contained in:
@@ -311,6 +311,38 @@ public sealed class Phase7ApplierTests
|
||||
sink.VariableCalls.ShouldContain(("eq-1/load-pct", "eq-1", "load-pct", "Float64"));
|
||||
}
|
||||
|
||||
/// <summary>T14 — MaterialiseScriptedAlarms materialises one condition per ENABLED alarm (keyed by
|
||||
/// ScriptedAlarmId, parented to its EquipmentId, carrying Name/AlarmType/Severity) and SKIPS
|
||||
/// disabled alarms.</summary>
|
||||
[Fact]
|
||||
public void MaterialiseScriptedAlarms_materialises_enabled_and_skips_disabled()
|
||||
{
|
||||
var sink = new RecordingSink();
|
||||
var applier = new Phase7Applier(sink, NullLogger<Phase7Applier>.Instance);
|
||||
|
||||
var composition = new Phase7CompositionResult(
|
||||
Array.Empty<EquipmentNode>(), Array.Empty<DriverInstancePlan>(), Array.Empty<ScriptedAlarmPlan>())
|
||||
{
|
||||
EquipmentScriptedAlarms = new[]
|
||||
{
|
||||
new EquipmentScriptedAlarmPlan(
|
||||
ScriptedAlarmId: "alm-1", EquipmentId: "eq-1", Name: "HighTemp", AlarmType: "OffNormalAlarm",
|
||||
Severity: 700, MessageTemplate: "Temp high", PredicateScriptId: "scr-1", PredicateSource: "return true;",
|
||||
DependencyRefs: Array.Empty<string>(), HistorizeToAveva: false, Retain: true, Enabled: true),
|
||||
new EquipmentScriptedAlarmPlan(
|
||||
ScriptedAlarmId: "alm-2", EquipmentId: "eq-2", Name: "LowFlow", AlarmType: "AlarmCondition",
|
||||
Severity: 300, MessageTemplate: "Flow low", PredicateScriptId: "scr-2", PredicateSource: "return false;",
|
||||
DependencyRefs: Array.Empty<string>(), HistorizeToAveva: false, Retain: true, Enabled: false),
|
||||
},
|
||||
};
|
||||
|
||||
applier.MaterialiseScriptedAlarms(composition);
|
||||
|
||||
// Only the enabled alarm is materialised; the disabled one is skipped entirely.
|
||||
sink.AlarmConditionCalls.ShouldHaveSingleItem()
|
||||
.ShouldBe(("alm-1", "eq-1", "HighTemp", "OffNormalAlarm", 700));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that added equipment tags in an otherwise-empty plan trigger an
|
||||
/// address-space rebuild (parity with the Galaxy-tag path — the planner now diffs equipment
|
||||
/// tags, so a tags-only deploy is no longer a silent no-op).</summary>
|
||||
@@ -419,6 +451,8 @@ public sealed class Phase7ApplierTests
|
||||
public ConcurrentQueue<(string NodeId, string? Parent, string DisplayName)> FolderQueue { get; } = new();
|
||||
/// <summary>Gets the queue of variable creation calls.</summary>
|
||||
public ConcurrentQueue<(string NodeId, string? Parent, string DisplayName, string DataType)> VariableQueue { get; } = new();
|
||||
/// <summary>Gets the queue of alarm-condition materialise calls.</summary>
|
||||
public ConcurrentQueue<(string AlarmNodeId, string EquipmentNodeId, string DisplayName, string AlarmType, int Severity)> AlarmConditionQueue { get; } = new();
|
||||
/// <summary>Gets the number of rebuild calls made on this sink.</summary>
|
||||
public int RebuildCalls;
|
||||
|
||||
@@ -428,6 +462,8 @@ public sealed class Phase7ApplierTests
|
||||
public List<(string NodeId, string? Parent, string DisplayName)> FolderCalls => FolderQueue.ToList();
|
||||
/// <summary>Gets the list of recorded variable creation calls.</summary>
|
||||
public List<(string NodeId, string? Parent, string DisplayName, string DataType)> VariableCalls => VariableQueue.ToList();
|
||||
/// <summary>Gets the list of recorded alarm-condition materialise calls.</summary>
|
||||
public List<(string AlarmNodeId, string EquipmentNodeId, string DisplayName, string AlarmType, int Severity)> AlarmConditionCalls => AlarmConditionQueue.ToList();
|
||||
|
||||
/// <summary>Records a value write (no-op in this recording sink).</summary>
|
||||
/// <param name="nodeId">The node ID.</param>
|
||||
@@ -442,6 +478,14 @@ public sealed class Phase7ApplierTests
|
||||
/// <param name="sourceTimestampUtc">The source timestamp in UTC.</param>
|
||||
public void WriteAlarmState(string alarmNodeId, bool active, bool acknowledged, DateTime sourceTimestampUtc)
|
||||
=> AlarmQueue.Enqueue((alarmNodeId, active, acknowledged));
|
||||
/// <summary>Records an alarm-condition materialise call.</summary>
|
||||
/// <param name="alarmNodeId">The alarm node ID (== ScriptedAlarmId).</param>
|
||||
/// <param name="equipmentNodeId">The equipment folder node ID.</param>
|
||||
/// <param name="displayName">The condition display name.</param>
|
||||
/// <param name="alarmType">The domain alarm type.</param>
|
||||
/// <param name="severity">The domain severity.</param>
|
||||
public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity)
|
||||
=> AlarmConditionQueue.Enqueue((alarmNodeId, equipmentNodeId, displayName, alarmType, severity));
|
||||
/// <summary>Records a folder creation call.</summary>
|
||||
/// <param name="folderNodeId">The folder node ID.</param>
|
||||
/// <param name="parentNodeId">The parent folder node ID, if any.</param>
|
||||
@@ -482,6 +526,13 @@ public sealed class Phase7ApplierTests
|
||||
{
|
||||
if (_throwOnAlarmWrite) throw new InvalidOperationException("simulated sink fault");
|
||||
}
|
||||
/// <summary>No-op alarm-condition materialise call.</summary>
|
||||
/// <param name="alarmNodeId">The alarm node ID.</param>
|
||||
/// <param name="equipmentNodeId">The equipment folder node ID.</param>
|
||||
/// <param name="displayName">The condition display name.</param>
|
||||
/// <param name="alarmType">The domain alarm type.</param>
|
||||
/// <param name="severity">The domain severity.</param>
|
||||
public void MaterialiseAlarmCondition(string alarmNodeId, string equipmentNodeId, string displayName, string alarmType, int severity) { }
|
||||
/// <summary>No-op folder creation call.</summary>
|
||||
/// <param name="folderNodeId">The folder node ID.</param>
|
||||
/// <param name="parentNodeId">The parent folder node ID, if any.</param>
|
||||
|
||||
Reference in New Issue
Block a user