6951faa08f
NativeAlarmModel: IsAlarm=false now removes the alarm key; advisory Warnings, driver gating, order-safe Edit. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe
107 lines
4.2 KiB
C#
107 lines
4.2 KiB
C#
using System.Text.Json.Nodes;
|
|
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.AdminUI.Uns.TagEditors;
|
|
using ZB.MOM.WW.OtOpcUa.Core.Abstractions;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Uns;
|
|
|
|
/// <summary>Gitea #642 — the shared NativeAlarmEditor's pure-model behaviour: remove-on-off, composition
|
|
/// with the per-driver editors' models, validation parity with the deploy gate, driver-type gating.</summary>
|
|
public sealed class NativeAlarmEditorModelTests
|
|
{
|
|
[Fact]
|
|
public void ToJson_with_IsAlarm_false_removes_the_alarm_key_and_keeps_the_rest()
|
|
{
|
|
var m = NativeAlarmModel.FromJson("""{"FullName":"X.Y","alarm":{"alarmType":"LimitAlarm","severity":300,"extra":1}}""");
|
|
m.IsAlarm = false;
|
|
|
|
var o = JsonNode.Parse(m.ToJson())!.AsObject();
|
|
o.ContainsKey("alarm").ShouldBeFalse();
|
|
o["FullName"]!.GetValue<string>().ShouldBe("X.Y");
|
|
}
|
|
|
|
[Fact]
|
|
public void Toggle_off_then_on_again_starts_from_defaults()
|
|
{
|
|
var off = NativeAlarmModel.Edit("""{"alarm":{"severity":300}}""", m => m.IsAlarm = false);
|
|
var on = NativeAlarmModel.Edit(off, m => m.IsAlarm = true);
|
|
var back = NativeAlarmModel.FromJson(on);
|
|
back.IsAlarm.ShouldBeTrue();
|
|
back.Severity.ShouldBe(500);
|
|
back.AlarmType.ShouldBe("AlarmCondition");
|
|
}
|
|
|
|
[Fact]
|
|
public void Edit_preserves_unknown_keys_at_both_levels()
|
|
{
|
|
var json = NativeAlarmModel.Edit("""{"FullName":"A","zz":1,"alarm":{"alarmType":"OffNormalAlarm","custom":"k"}}""",
|
|
m => m.Severity = 900);
|
|
var o = JsonNode.Parse(json)!.AsObject();
|
|
o["zz"]!.GetValue<int>().ShouldBe(1);
|
|
o["alarm"]!["custom"]!.GetValue<string>().ShouldBe("k");
|
|
o["alarm"]!["severity"]!.GetValue<int>().ShouldBe(900);
|
|
}
|
|
|
|
[Fact]
|
|
public void Alarm_and_mtconnect_driver_editor_compose_in_either_order()
|
|
{
|
|
const string start = """{"fullName":"Xact"}""";
|
|
|
|
// alarm first, then driver editor (driver model re-parses the alarm-bearing JSON)
|
|
var a1 = NativeAlarmModel.Edit(start, m => { m.IsAlarm = true; m.Severity = 800; });
|
|
var d1 = MTConnectTagConfigModel.FromJson(a1);
|
|
d1.FullName = "Yact";
|
|
var r1 = d1.ToJson();
|
|
|
|
// driver editor first, then alarm
|
|
var d2 = MTConnectTagConfigModel.FromJson(start);
|
|
d2.FullName = "Yact";
|
|
var r2 = NativeAlarmModel.Edit(d2.ToJson(), m => { m.IsAlarm = true; m.Severity = 800; });
|
|
|
|
foreach (var r in new[] { r1, r2 })
|
|
{
|
|
var o = JsonNode.Parse(r)!.AsObject();
|
|
o["fullName"]!.GetValue<string>().ShouldBe("Yact");
|
|
o["alarm"]!["severity"]!.GetValue<int>().ShouldBe(800);
|
|
}
|
|
}
|
|
|
|
[Theory]
|
|
[InlineData("Modbus")]
|
|
[InlineData("S7")]
|
|
[InlineData("AbCip")]
|
|
[InlineData("AbLegacy")]
|
|
[InlineData("TwinCAT")]
|
|
[InlineData("FOCAS")]
|
|
[InlineData("OpcUaClient")]
|
|
[InlineData("Sql")]
|
|
[InlineData("Mqtt")]
|
|
[InlineData("MTConnect")]
|
|
public void Every_typed_driver_model_preserves_an_alarm_object(string driverType)
|
|
{
|
|
const string json = """{"alarm":{"alarmType":"LimitAlarm","severity":123}}""";
|
|
var round = TagConfigRoundTrip.Through(driverType, json);
|
|
NativeAlarmModel.FromJson(round).Severity.ShouldBe(123);
|
|
}
|
|
|
|
[Fact]
|
|
public void Validate_is_not_stricter_than_the_deploy_gate()
|
|
{
|
|
// The gate/parser accepts any severity (clamped 1..1000 at publish) and any alarmType string.
|
|
var m = NativeAlarmModel.FromJson("""{"alarm":{"alarmType":"Whatever","severity":5000}}""");
|
|
m.Validate().ShouldBeNull();
|
|
m.Warnings().ShouldNotBeEmpty(); // advisory only
|
|
}
|
|
|
|
[Fact]
|
|
public void SupportsNativeAlarms_covers_exactly_the_IAlarmSource_drivers()
|
|
{
|
|
foreach (var t in new[] { DriverTypeNames.MTConnect, DriverTypeNames.AbCip, DriverTypeNames.FOCAS,
|
|
DriverTypeNames.OpcUaClient, DriverTypeNames.Galaxy })
|
|
NativeAlarmModel.SupportsNativeAlarms(t).ShouldBeTrue(t);
|
|
foreach (var t in new[] { DriverTypeNames.Modbus, DriverTypeNames.S7, DriverTypeNames.Mqtt, null })
|
|
NativeAlarmModel.SupportsNativeAlarms(t).ShouldBeFalse(t);
|
|
}
|
|
}
|