fix(transport): transport template NativeAlarmSources — imports no longer amputate native alarm mirrors nor dangle instance overrides
New TemplateNativeAlarmSourceDto + init-only TemplateDto.NativeAlarmSources (empty default, additive — IsInherited placeholders carried for the collision detector). Exported in ToBundleContent, consumed in FromBundleContent + BuildTemplate, and a new SyncTemplateNativeAlarmSourcesAsync runs the Overwrite add/update/delete child sync with per-change audit rows. ArtifactDiff.CompareTemplate now DiffChildren over native sources so Preview reports a NativeAlarmSources field change. Proven by an end-to-end flatten test: an instance native-alarm-source override that dangled pre-fix now resolves against the re-imported template source. Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
@@ -202,6 +202,46 @@ public sealed class EntitySerializerTests
|
||||
Assert.True(Assert.Single(rtBasic.Scripts).LockedInDerived);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Roundtrip_template_preserves_NativeAlarmSources()
|
||||
{
|
||||
var basic = new Template("Basic") { Id = 1 };
|
||||
basic.NativeAlarmSources.Add(new TemplateNativeAlarmSource("Boiler")
|
||||
{
|
||||
Id = 1,
|
||||
TemplateId = 1,
|
||||
Description = "boiler alarms",
|
||||
ConnectionName = "OpcUaPrimary",
|
||||
SourceReference = "ns=3;s=Boiler.Alarm",
|
||||
ConditionFilter = "severity>500",
|
||||
IsLocked = true,
|
||||
IsInherited = false,
|
||||
LockedInDerived = true,
|
||||
});
|
||||
|
||||
var aggregate = MakeEmptyAggregate() with { Templates = new[] { basic } };
|
||||
|
||||
var sut = new EntitySerializer();
|
||||
var dto = sut.ToBundleContent(aggregate);
|
||||
|
||||
var dtoSrc = Assert.Single(Assert.Single(dto.Templates).NativeAlarmSources);
|
||||
Assert.Equal("Boiler", dtoSrc.Name);
|
||||
Assert.Equal("OpcUaPrimary", dtoSrc.ConnectionName);
|
||||
Assert.Equal("ns=3;s=Boiler.Alarm", dtoSrc.SourceReference);
|
||||
Assert.Equal("severity>500", dtoSrc.ConditionFilter);
|
||||
Assert.True(dtoSrc.IsLocked);
|
||||
Assert.True(dtoSrc.LockedInDerived);
|
||||
|
||||
var rtSrc = Assert.Single(Assert.Single(sut.FromBundleContent(dto).Templates).NativeAlarmSources);
|
||||
Assert.Equal("Boiler", rtSrc.Name);
|
||||
Assert.Equal("boiler alarms", rtSrc.Description);
|
||||
Assert.Equal("OpcUaPrimary", rtSrc.ConnectionName);
|
||||
Assert.Equal("ns=3;s=Boiler.Alarm", rtSrc.SourceReference);
|
||||
Assert.Equal("severity>500", rtSrc.ConditionFilter);
|
||||
Assert.True(rtSrc.IsLocked);
|
||||
Assert.True(rtSrc.LockedInDerived);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void OldForm_bundle_json_without_LockedInDerived_deserializes_to_false()
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user