fix(hosts): a driver that never built a tag table reports NO ANSWER, not zero skips
Found on the docker-dev live gate, not in tests. Two drivers that faulted during initialise (rtu-gate, opcua1) each rendered "0 tags" on /hosts against two authored tags apiece, because a ledger that had never committed returned SkippedTagReport.Empty. A zero report is a positive claim -- "this driver skipped nothing" -- and making it on behalf of a driver that never got as far as looking is exactly the quiet inaccuracy #541 exists to remove. GetSkippedTags() and SkippedTagLedger.Snapshot() now return null until the first committed build, so the column renders the same em-dash it already used for a driver that cannot report at all. Both are 'no answer'; neither is 'nothing skipped'. Knock-on: a FOCAS driver whose only init threw now reports null rather than a zero report, which is strictly more honest than the assertion the test originally made.
This commit is contained in:
@@ -9,17 +9,45 @@ namespace ZB.MOM.WW.OtOpcUa.Core.Abstractions.Tests;
|
||||
/// </summary>
|
||||
public sealed class SkippedTagLedgerTests
|
||||
{
|
||||
/// <summary>
|
||||
/// <b>A ledger that has never built reports NO ANSWER, not a clean bill of health.</b> Caught on
|
||||
/// the docker-dev rig: two drivers that faulted during initialise each rendered "0 tags" on
|
||||
/// <c>/hosts</c> against two authored tags apiece. A zero report is a positive claim — "this driver
|
||||
/// skipped nothing" — and making it on behalf of a driver that never got as far as looking is the
|
||||
/// same species of quiet inaccuracy this capability exists to remove.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void A_fresh_ledger_reports_nothing()
|
||||
{
|
||||
var report = new SkippedTagLedger().Snapshot();
|
||||
public void A_ledger_that_has_never_built_reports_no_answer_rather_than_a_clean_one()
|
||||
=> new SkippedTagLedger().Snapshot().ShouldBeNull();
|
||||
|
||||
report.AuthoredCount.ShouldBe(0);
|
||||
/// <summary>An empty deployment that DID build reports a zero report — distinct from the above.</summary>
|
||||
[Fact]
|
||||
public void A_committed_empty_build_reports_zero_rather_than_no_answer()
|
||||
{
|
||||
var ledger = new SkippedTagLedger();
|
||||
ledger.BeginRebuild(0);
|
||||
ledger.Commit();
|
||||
|
||||
var report = ledger.Snapshot();
|
||||
report.ShouldNotBeNull();
|
||||
report!.AuthoredCount.ShouldBe(0);
|
||||
report.SkippedCount.ShouldBe(0);
|
||||
report.Sample.ShouldBeEmpty();
|
||||
report.HasSkips.ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An in-flight first build is still "no answer" — the staging state must not leak as a report.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public void A_first_build_still_in_progress_reports_no_answer()
|
||||
{
|
||||
var ledger = new SkippedTagLedger();
|
||||
ledger.BeginRebuild(10);
|
||||
ledger.Skip("a", "r");
|
||||
|
||||
ledger.Snapshot().ShouldBeNull();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void A_committed_build_reports_its_skips_with_the_authored_denominator()
|
||||
{
|
||||
@@ -30,7 +58,7 @@ public sealed class SkippedTagLedgerTests
|
||||
ledger.Skip("Line1/Makino/Identity/Version", "invalid Address");
|
||||
ledger.Commit();
|
||||
|
||||
var report = ledger.Snapshot();
|
||||
var report = ledger.Snapshot()!;
|
||||
report.AuthoredCount.ShouldBe(22);
|
||||
report.SkippedCount.ShouldBe(2);
|
||||
report.Sample.Select(s => s.RawPath)
|
||||
@@ -54,7 +82,7 @@ public sealed class SkippedTagLedgerTests
|
||||
ledger.Skip("c", "r");
|
||||
ledger.Commit();
|
||||
|
||||
ledger.Snapshot().SkippedEverything.ShouldBeTrue();
|
||||
ledger.Snapshot()!.SkippedEverything.ShouldBeTrue();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -70,7 +98,7 @@ public sealed class SkippedTagLedgerTests
|
||||
ledger.BeginRebuild(0);
|
||||
ledger.Commit();
|
||||
|
||||
ledger.Snapshot().SkippedEverything.ShouldBeFalse();
|
||||
ledger.Snapshot()!.SkippedEverything.ShouldBeFalse();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -86,7 +114,7 @@ public sealed class SkippedTagLedgerTests
|
||||
for (var i = 0; i < 500; i++) ledger.Skip($"tag-{i}", "TagConfig did not map to a definition");
|
||||
ledger.Commit();
|
||||
|
||||
var report = ledger.Snapshot();
|
||||
var report = ledger.Snapshot()!;
|
||||
report.SkippedCount.ShouldBe(500);
|
||||
report.Sample.Count.ShouldBe(SkippedTagLedger.MaxSample);
|
||||
report.Sample[0].RawPath.ShouldBe("tag-0", "the sample keeps the FIRST skips, in encounter order");
|
||||
@@ -108,13 +136,13 @@ public sealed class SkippedTagLedgerTests
|
||||
ledger.BeginRebuild(10);
|
||||
ledger.Skip("new-1", "r");
|
||||
|
||||
var midRebuild = ledger.Snapshot();
|
||||
var midRebuild = ledger.Snapshot()!;
|
||||
midRebuild.SkippedCount.ShouldBe(1);
|
||||
midRebuild.Sample.Single().RawPath.ShouldBe("old");
|
||||
|
||||
ledger.Skip("new-2", "r");
|
||||
ledger.Commit();
|
||||
ledger.Snapshot().Sample.Select(s => s.RawPath).ShouldBe(["new-1", "new-2"]);
|
||||
ledger.Snapshot()!.Sample.Select(s => s.RawPath).ShouldBe(["new-1", "new-2"]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -133,7 +161,7 @@ public sealed class SkippedTagLedgerTests
|
||||
ledger.Skip("would-have-been-reported", "invalid Address");
|
||||
// …driver throws here; no Commit.
|
||||
|
||||
ledger.Snapshot().Sample.Single().RawPath.ShouldBe("known-bad");
|
||||
ledger.Snapshot()!.Sample.Single().RawPath.ShouldBe("known-bad");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -151,7 +179,7 @@ public sealed class SkippedTagLedgerTests
|
||||
ledger.BeginRebuild(2);
|
||||
ledger.Commit();
|
||||
|
||||
var report = ledger.Snapshot();
|
||||
var report = ledger.Snapshot()!;
|
||||
report.HasSkips.ShouldBeFalse();
|
||||
report.SkippedCount.ShouldBe(0);
|
||||
report.AuthoredCount.ShouldBe(2);
|
||||
@@ -167,7 +195,7 @@ public sealed class SkippedTagLedgerTests
|
||||
var ledger = new SkippedTagLedger();
|
||||
|
||||
Should.NotThrow(() => ledger.Skip("orphan", "r"));
|
||||
ledger.Snapshot().SkippedCount.ShouldBe(0);
|
||||
ledger.Snapshot().ShouldBeNull("a stray Skip must not conjure a report out of nothing");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -197,7 +225,7 @@ public sealed class SkippedTagLedgerTests
|
||||
{
|
||||
while (!writer.IsCompleted && !cts.IsCancellationRequested)
|
||||
{
|
||||
var r = ledger.Snapshot();
|
||||
var r = ledger.Snapshot()!;
|
||||
// Every committed snapshot is internally consistent: the sample never exceeds either the
|
||||
// cap or the true count it is drawn from.
|
||||
r.Sample.Count.ShouldBeLessThanOrEqualTo(SkippedTagLedger.MaxSample);
|
||||
|
||||
Reference in New Issue
Block a user