test(adminui): close Phase 6 review test-gaps + Enterprise-delete warning
This commit is contained in:
+79
@@ -345,6 +345,85 @@ public sealed class DeploymentArtifactAliasParityTests
|
||||
composed.EquipmentTags.Single(t => t.TagId == "tag-modbus").Writable.ShouldBeTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The native-alarm <c>historizeToAveva</c> opt-out (bool?, the per-condition durable-AVEVA-write
|
||||
/// gate) is parsed by BOTH equipment-tag producers' <c>ExtractTagAlarm</c> and MUST stay byte-parity:
|
||||
/// for the SAME tag TagConfig carrying <c>alarm.historizeToAveva: true</c> (and <c>: false</c>), the
|
||||
/// live-edit composer (<see cref="Phase7Composer.Compose"/>) and the artifact decoder
|
||||
/// (<see cref="DeploymentArtifact.ParseComposition(System.ReadOnlySpan{byte})"/>) must derive the
|
||||
/// identical <c>EquipmentTagAlarmInfo.HistorizeToAveva</c>. The galaxy-tag parity test above already
|
||||
/// covers the absent ⇒ null case; this pins the explicit-bool branch on both sides.
|
||||
/// </summary>
|
||||
[Theory]
|
||||
[InlineData(true)]
|
||||
[InlineData(false)]
|
||||
public void Composer_and_artifact_agree_on_alarm_historizeToAveva(bool historizeToAveva)
|
||||
{
|
||||
var ns = new Namespace
|
||||
{
|
||||
NamespaceId = "ns-eq",
|
||||
ClusterId = "c1",
|
||||
Kind = NamespaceKind.Equipment,
|
||||
NamespaceUri = "urn:eq",
|
||||
};
|
||||
var driver = new DriverInstance
|
||||
{
|
||||
DriverInstanceId = "drv-modbus",
|
||||
ClusterId = "c1",
|
||||
NamespaceId = "ns-eq",
|
||||
Name = "Modbus1",
|
||||
DriverType = "Modbus",
|
||||
DriverConfig = "{}",
|
||||
};
|
||||
var area = new UnsArea { UnsAreaId = "area-1", ClusterId = "c1", Name = "filling" };
|
||||
var line = new UnsLine { UnsLineId = "line-1", UnsAreaId = "area-1", Name = "line-1" };
|
||||
var equip = new Equipment
|
||||
{
|
||||
EquipmentId = "eq-1",
|
||||
DriverInstanceId = "drv-modbus",
|
||||
UnsLineId = "line-1",
|
||||
Name = "FillingPump",
|
||||
MachineCode = "FILLINGPUMP",
|
||||
};
|
||||
var alarmJson = historizeToAveva ? "true" : "false";
|
||||
var alarmTag = new Tag
|
||||
{
|
||||
TagId = "tag-alarm",
|
||||
DriverInstanceId = "drv-modbus",
|
||||
EquipmentId = "eq-1",
|
||||
FolderPath = null,
|
||||
Name = "Temp",
|
||||
DataType = "Float",
|
||||
AccessLevel = TagAccessLevel.Read,
|
||||
TagConfig = $"{{\"FullName\":\"40001\",\"alarm\":{{\"alarmType\":\"OffNormalAlarm\",\"severity\":700,\"historizeToAveva\":{alarmJson}}}}}",
|
||||
};
|
||||
|
||||
// ---- Side 1: the live-edit composer ----
|
||||
var composed = Phase7Composer.Compose(
|
||||
new[] { area }, new[] { line }, new[] { equip }, new[] { driver },
|
||||
Array.Empty<ScriptedAlarm>(), new[] { alarmTag }, new[] { ns });
|
||||
|
||||
// ---- Side 2: serialise the SAME draft to the artifact blob shape, then decode it ----
|
||||
var blob = JsonSerializer.SerializeToUtf8Bytes(new
|
||||
{
|
||||
Namespaces = new[] { new { ns.NamespaceId, ns.ClusterId, Kind = (int)ns.Kind } },
|
||||
DriverInstances = new[]
|
||||
{
|
||||
new { driver.DriverInstanceId, driver.DriverType, driver.DriverConfig, driver.NamespaceId, driver.ClusterId },
|
||||
},
|
||||
Tags = new[] { ToSnapshot(alarmTag) },
|
||||
});
|
||||
|
||||
var decoded = DeploymentArtifact.ParseComposition(blob);
|
||||
|
||||
// ---- Byte-parity: HistorizeToAveva matches between producers and equals the seeded bool. ----
|
||||
var decodedAlarm = decoded.EquipmentTags.ShouldHaveSingleItem().Alarm.ShouldNotBeNull();
|
||||
var composedAlarm = composed.EquipmentTags.ShouldHaveSingleItem().Alarm.ShouldNotBeNull();
|
||||
decodedAlarm.HistorizeToAveva.ShouldBe(historizeToAveva);
|
||||
composedAlarm.HistorizeToAveva.ShouldBe(historizeToAveva);
|
||||
decodedAlarm.ShouldBe(composedAlarm); // EquipmentTagAlarmInfo is a positional record ⇒ value equality
|
||||
}
|
||||
|
||||
/// <summary>The full Pascal-case snapshot a <see cref="Tag"/> EF entity serialises to in the
|
||||
/// artifact (matches ConfigComposer): the equipment-tag decoder reads exactly these fields.</summary>
|
||||
private static object ToSnapshot(Tag t) => new
|
||||
|
||||
Reference in New Issue
Block a user