diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Heidenhain.Tests/HeidenhainDriverTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Heidenhain.Tests/HeidenhainDriverTests.cs index 4ef3030e4..c69b67a22 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Heidenhain.Tests/HeidenhainDriverTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Heidenhain.Tests/HeidenhainDriverTests.cs @@ -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);