server(alarms): honor ExcludeAttributes GR-only contract; warn on empty config-only watch-list
This commit is contained in:
@@ -208,6 +208,76 @@ public sealed class AlarmWatchListResolverTests
|
||||
Assert.Equal("StandaloneTag", result[1].SourceObjectReference);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fix 1: ExcludeAttributes must be ignored when UseGalaxyRepository is false.
|
||||
/// A config-only include must survive even when the same path appears in ExcludeAttributes.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ResolveAsync_ExcludeIgnored_WhenGalaxyRepositoryDisabled()
|
||||
{
|
||||
// Repo is never consulted; only IncludeAttributes matters.
|
||||
StubGalaxyRepository repo = new([]);
|
||||
|
||||
AlarmWatchListResolver resolver = CreateResolver(repo);
|
||||
|
||||
IReadOnlyList<AlarmSubtagTarget> result = await resolver.ResolveAsync(Options(
|
||||
useGalaxyRepository: false,
|
||||
include: ["Tank01.Level.HiHi"],
|
||||
exclude: ["Tank01.Level.HiHi"]));
|
||||
|
||||
// ExcludeAttributes is ignored when GR is off — the include must be present.
|
||||
AlarmSubtagTarget target = Assert.Single(result);
|
||||
Assert.Equal("Galaxy!Tank01.Level.HiHi", target.AlarmFullReference);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fix 1 (GR-on path): ExcludeAttributes still prunes GR rows when
|
||||
/// UseGalaxyRepository is true.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ResolveAsync_ExcludeApplied_WhenGalaxyRepositoryEnabled()
|
||||
{
|
||||
StubGalaxyRepository repo = new(
|
||||
[
|
||||
new GalaxyAlarmAttributeRow { FullTagReference = "Tank01.Level.HiHi", SourceObjectReference = "Tank01" },
|
||||
new GalaxyAlarmAttributeRow { FullTagReference = "Tank02.Level.HiHi", SourceObjectReference = "Tank02" },
|
||||
]);
|
||||
|
||||
AlarmWatchListResolver resolver = CreateResolver(repo);
|
||||
|
||||
IReadOnlyList<AlarmSubtagTarget> result = await resolver.ResolveAsync(Options(
|
||||
useGalaxyRepository: true,
|
||||
exclude: ["Tank02.Level.HiHi"]));
|
||||
|
||||
// Tank02 was excluded; only Tank01 remains.
|
||||
AlarmSubtagTarget target = Assert.Single(result);
|
||||
Assert.Contains("Tank01", target.ActiveSubtag, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fix 1: A whitespace-only ExcludeAttributes entry must be skipped and must
|
||||
/// not accidentally exclude any real reference.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task ResolveAsync_WhitespaceOnlyExcludeEntry_IsSkipped()
|
||||
{
|
||||
StubGalaxyRepository repo = new(
|
||||
[
|
||||
new GalaxyAlarmAttributeRow { FullTagReference = "Tank01.Level.HiHi", SourceObjectReference = "Tank01" },
|
||||
]);
|
||||
|
||||
AlarmWatchListResolver resolver = CreateResolver(repo);
|
||||
|
||||
// The exclude array contains a whitespace-only string — should be a no-op.
|
||||
IReadOnlyList<AlarmSubtagTarget> result = await resolver.ResolveAsync(Options(
|
||||
useGalaxyRepository: true,
|
||||
exclude: [" "]));
|
||||
|
||||
// Tank01 must not have been wrongly excluded.
|
||||
AlarmSubtagTarget target = Assert.Single(result);
|
||||
Assert.Contains("Tank01", target.ActiveSubtag, StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
/// <summary>In-memory <see cref="IGalaxyRepository"/> returning a fixed alarm rowset.</summary>
|
||||
private sealed class StubGalaxyRepository(List<GalaxyAlarmAttributeRow> rows) : IGalaxyRepository
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user