test(transport): harden T5 native-source coverage — no-change zero-audit + IsInherited/LockedInDerived fidelity
Follow-up from the T5 code review: assert an idempotent Overwrite emits zero TemplateNativeAlarmSource* audit rows, and round-trip IsInherited/LockedInDerived as true through both the serializer and the importer BuildTemplate path. Claude-Session: https://claude.ai/code/session_01MtdgwpEeCUn6cUA5f1LMPj
This commit is contained in:
+40
-4
@@ -103,15 +103,17 @@ public sealed class NativeAlarmSourceImportTests : IDisposable
|
||||
string connection = "OpcUaPrimary",
|
||||
string sourceRef = "ns=3;s=Boiler.Alarm",
|
||||
string? filter = "severity>500",
|
||||
bool locked = false) => new(name)
|
||||
bool locked = false,
|
||||
bool inherited = false,
|
||||
bool lockedInDerived = false) => new(name)
|
||||
{
|
||||
Description = "boiler native alarms",
|
||||
ConnectionName = connection,
|
||||
SourceReference = sourceRef,
|
||||
ConditionFilter = filter,
|
||||
IsLocked = locked,
|
||||
IsInherited = false,
|
||||
LockedInDerived = false,
|
||||
IsInherited = inherited,
|
||||
LockedInDerived = lockedInDerived,
|
||||
};
|
||||
|
||||
[Fact]
|
||||
@@ -121,7 +123,8 @@ public sealed class NativeAlarmSourceImportTests : IDisposable
|
||||
{
|
||||
var ctx = scope.ServiceProvider.GetRequiredService<ScadaBridgeDbContext>();
|
||||
var t = new Template("Pump") { Description = "tpl" };
|
||||
t.NativeAlarmSources.Add(MakeSource(locked: true));
|
||||
// Set every flag non-default so BuildTemplate's fidelity is exercised.
|
||||
t.NativeAlarmSources.Add(MakeSource(locked: true, inherited: true, lockedInDerived: true));
|
||||
ctx.Templates.Add(t);
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
@@ -155,6 +158,39 @@ public sealed class NativeAlarmSourceImportTests : IDisposable
|
||||
Assert.Equal("ns=3;s=Boiler.Alarm", src.SourceReference);
|
||||
Assert.Equal("severity>500", src.ConditionFilter);
|
||||
Assert.True(src.IsLocked);
|
||||
Assert.True(src.IsInherited);
|
||||
Assert.True(src.LockedInDerived);
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task Import_Overwrite_NoChange_EmitsNoNativeSourceAudit()
|
||||
{
|
||||
// An idempotent Overwrite (bundle == target) must produce ZERO
|
||||
// TemplateNativeAlarmSource* audit rows — the "no audit noise" invariant.
|
||||
await using (var scope = _provider.CreateAsyncScope())
|
||||
{
|
||||
var ctx = scope.ServiceProvider.GetRequiredService<ScadaBridgeDbContext>();
|
||||
var t = new Template("Pump") { Description = "same" };
|
||||
t.NativeAlarmSources.Add(MakeSource("Boiler", locked: true, lockedInDerived: true));
|
||||
ctx.Templates.Add(t);
|
||||
await ctx.SaveChangesAsync();
|
||||
}
|
||||
var sessionId = await ExportAllTemplatesAndLoadAsync();
|
||||
|
||||
await using (var scope = _provider.CreateAsyncScope())
|
||||
{
|
||||
var importer = scope.ServiceProvider.GetRequiredService<IBundleImporter>();
|
||||
await importer.ApplyAsync(sessionId,
|
||||
new List<ImportResolution> { new("Template", "Pump", ResolutionAction.Overwrite, null) },
|
||||
user: "bob");
|
||||
}
|
||||
|
||||
await using (var scope = _provider.CreateAsyncScope())
|
||||
{
|
||||
var ctx = scope.ServiceProvider.GetRequiredService<ScadaBridgeDbContext>();
|
||||
Assert.False(await ctx.AuditLogEntries.AnyAsync(a =>
|
||||
a.Action.StartsWith("TemplateNativeAlarmSource")));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -215,7 +215,7 @@ public sealed class EntitySerializerTests
|
||||
SourceReference = "ns=3;s=Boiler.Alarm",
|
||||
ConditionFilter = "severity>500",
|
||||
IsLocked = true,
|
||||
IsInherited = false,
|
||||
IsInherited = true,
|
||||
LockedInDerived = true,
|
||||
});
|
||||
|
||||
@@ -230,6 +230,7 @@ public sealed class EntitySerializerTests
|
||||
Assert.Equal("ns=3;s=Boiler.Alarm", dtoSrc.SourceReference);
|
||||
Assert.Equal("severity>500", dtoSrc.ConditionFilter);
|
||||
Assert.True(dtoSrc.IsLocked);
|
||||
Assert.True(dtoSrc.IsInherited);
|
||||
Assert.True(dtoSrc.LockedInDerived);
|
||||
|
||||
var rtSrc = Assert.Single(Assert.Single(sut.FromBundleContent(dto).Templates).NativeAlarmSources);
|
||||
@@ -239,6 +240,7 @@ public sealed class EntitySerializerTests
|
||||
Assert.Equal("ns=3;s=Boiler.Alarm", rtSrc.SourceReference);
|
||||
Assert.Equal("severity>500", rtSrc.ConditionFilter);
|
||||
Assert.True(rtSrc.IsLocked);
|
||||
Assert.True(rtSrc.IsInherited);
|
||||
Assert.True(rtSrc.LockedInDerived);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user