test(heidenhain): wait for the whole outage-invalidation pass before asserting on it (pre-existing race)
Comms_loss_invalidates_every_remote_value_and_recovery_republishes_identical_values failed
1/40 on base 5bbe1e3c (and 1/29 on this branch): "Capabilities/Identity should be
CommunicationLost but was Supported". RetireAll -> Invalidate publishes every tag in authored
order under one lock, capability LAST, and the recorder sees each publish as it happens; the
test asserted the capability the instant the five value tags read BadNoCommunication, i.e.
before the pass's final publish. Now the wait includes the capability's CommunicationLost
(a presence the pass must produce) and additionally asserts no value went Good again during
the outage.
Second latent race fixed in the same test: Degraded holds through Backoff AND Connecting, but
the host status is Stopped only in Backoff (Unknown while a reconnect attempt is in flight),
so the test now waits for Degraded && Stopped instead of sampling whichever phase it hit.
After the fix: 79/80 filtered runs passed and 10/10 full-suite runs; the one non-pass was a vstest
"failed to connect to testhost after 90 s" host-startup timeout (the test never ran), not a test result.
This commit is contained in:
@@ -151,13 +151,26 @@ public sealed class HeidenhainDriverTests
|
||||
|
||||
sim.GoOffline();
|
||||
// EVERY remote leaf — fast status, slow identity/alarms and custom PLC — goes Bad at once.
|
||||
await WaitUntil(() => tags.Take(5).All(t => rec.Last(t.RawPath)?.StatusCode == HeidenhainStatus.BadNoCommunication));
|
||||
rec.Last(tags[5].RawPath)!.Value.ShouldBe("CommunicationLost");
|
||||
// The invalidation is ONE pass over the device's tags (in authored order, capability last), delivered to this
|
||||
// thread's recorder as it runs — so wait for the WHOLE pass to land (the capability's CommunicationLost is
|
||||
// its last publication) before asserting on any of it. Asserting the capability the instant the five value
|
||||
// tags read Bad raced the pass's final publish (1/40 on 5bbe1e3c: "Supported").
|
||||
await WaitUntil(() => tags.Take(5).All(t => rec.Last(t.RawPath)?.StatusCode == HeidenhainStatus.BadNoCommunication)
|
||||
&& rec.Last(tags[5].RawPath)?.Value is "CommunicationLost");
|
||||
rec.Last(tags[5].RawPath)!.StatusCode.ShouldBe(HeidenhainStatus.Good);
|
||||
// ...and it is one pass: no remote value published Good again after its outage invalidation.
|
||||
foreach (var t in tags.Take(5))
|
||||
{
|
||||
var seq = rec.For(t.RawPath).Select(s => s.StatusCode).ToList();
|
||||
seq.Skip(seq.LastIndexOf(HeidenhainStatus.BadNoCommunication)).ShouldAllBe(s => s == HeidenhainStatus.BadNoCommunication);
|
||||
}
|
||||
|
||||
(await d.ReadAsync([tags[2].RawPath], Ct))[0].StatusCode.ShouldBe(HeidenhainStatus.BadNoCommunication);
|
||||
await WaitUntil(() => d.GetHealth().State == DriverState.Degraded);
|
||||
// Degraded holds through every reconnect attempt (Backoff AND Connecting carry the last error), but the host
|
||||
// status reads Stopped only in Backoff and Unknown while a reconnect attempt is in flight — so wait for the
|
||||
// Backoff phase rather than sample whichever phase the loop happens to be in.
|
||||
await WaitUntil(() => d.GetHealth().State == DriverState.Degraded && d.GetHostStatuses().Single().State == HostState.Stopped);
|
||||
d.GetHealth().LastError.ShouldNotBeNullOrEmpty();
|
||||
d.GetHostStatuses().Single().State.ShouldBe(HostState.Stopped);
|
||||
hostEvents.ShouldContain(e => e.NewState == HostState.Stopped);
|
||||
var frozen = d.GetHealth().LastSuccessfulRead;
|
||||
await Task.Delay(500, Ct);
|
||||
|
||||
Reference in New Issue
Block a user