From 159f30dcd0512adc5d0fe49a92b92ff99ce268e5 Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Thu, 8 Oct 2026 01:35:25 -0400 Subject: [PATCH] test(focas): wait for the first full poll, not the bootstrap stamp, before reading (#591) LastFixedPollUtc is stamped by the fixed-tree bootstrap before any axis snapshot is published, so under load Each_duplicate_axis_reads_its_own_position could read inside that window and get BadNodeIdUnknown. The helper now waits for the last axis slot plus the servo/spindle caches. 45/45 green under 14-core yes load. Claude-Session: https://claude.ai/code/session_01Ef2ozxS7QPanGT8uoATbTe --- .../FocasDuplicateSiblingNameTests.cs | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasDuplicateSiblingNameTests.cs b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasDuplicateSiblingNameTests.cs index a2d1c33b..441b03aa 100644 --- a/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasDuplicateSiblingNameTests.cs +++ b/tests/Drivers/ZB.MOM.WW.OtOpcUa.Driver.FOCAS.Tests/FocasDuplicateSiblingNameTests.cs @@ -53,10 +53,24 @@ public sealed class FocasDuplicateSiblingNameTests { var drv = NewDriver(tags); await drv.InitializeAsync("{}", CancellationToken.None); - var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(5); - while (DateTime.UtcNow < deadline && drv.GetDeviceState(Host)?.LastFixedPollUtc is null) - await Task.Delay(25, TestContext.Current.CancellationToken); - drv.GetDeviceState(Host)!.LastFixedPollUtc.ShouldNotBeNull("the fixed-tree loop never completed a poll"); + // LastFixedPollUtc alone is NOT "the first axis pass finished": the bootstrap stamps it + // after the sysinfo probe, before any axis snapshot is published (#591 — under load a + // read slipped into that window and saw BadNodeIdUnknown). Wait for the data itself: + // the last axis slot plus the servo/spindle caches this fake's first tick populates. + var deadline = DateTime.UtcNow + TimeSpan.FromSeconds(30); + var ready = false; + while (!ready && DateTime.UtcNow < deadline) + { + var st = drv.GetDeviceState(Host); + ready = st is not null + && st.LastFixedPollUtc is not null + && st.LastFixedSnapshots.ContainsKey(FocasDriver.FixedTreeReference(Host, "Axes/AA_2/AbsolutePosition")) + && st.LastServoLoads.Count >= 3 + && st.LastSpindleLoads.Count >= 2 + && st.LastSpindleMotorSpeeds.Count >= 2; + if (!ready) await Task.Delay(10, TestContext.Current.CancellationToken); + } + ready.ShouldBeTrue("the fixed-tree loop never completed its first full poll"); return drv; }