test(focas): #678.3 wait for motor speeds too; WaitFor fails on timeout (15 s)

This commit is contained in:
Joseph Doherty
2026-10-11 10:43:54 -04:00
parent 42eb96af9e
commit 1e343b0c52
@@ -71,7 +71,7 @@ public sealed class WireBackendTests
await driver.InitializeAsync("{}", ct);
await WaitFor(() =>
driver.GetDeviceState(DeviceHost) is { FixedTreeCache: not null }, TimeSpan.FromSeconds(5));
driver.GetDeviceState(DeviceHost) is { FixedTreeCache: not null }, WaitTimeout);
var state = driver.GetDeviceState(DeviceHost);
state.ShouldNotBeNull();
@@ -82,7 +82,7 @@ public sealed class WireBackendTests
await WaitFor(() =>
state.LastFixedSnapshots.ContainsKey($"{DeviceHost}/Axes/X/AbsolutePosition"),
TimeSpan.FromSeconds(3));
WaitTimeout);
state.LastFixedSnapshots[$"{DeviceHost}/Axes/X/AbsolutePosition"].ShouldBe(123456);
}
}
@@ -136,7 +136,7 @@ public sealed class WireBackendTests
await WaitFor(() =>
driver.GetDeviceState(DeviceHost) is { LastProgramInfo: not null },
TimeSpan.FromSeconds(5));
WaitTimeout);
var snapshots = await driver.ReadAsync(
[$"{DeviceHost}/Program/Name",
@@ -194,7 +194,7 @@ public sealed class WireBackendTests
{
var state = driver.GetDeviceState(DeviceHost);
return state is not null && state.LastTimers.Count == 4;
}, TimeSpan.FromSeconds(5));
}, WaitTimeout);
var snapshots = await driver.ReadAsync(
[$"{DeviceHost}/Timers/PowerOnSeconds",
@@ -265,8 +265,11 @@ public sealed class WireBackendTests
{
var state = driver.GetDeviceState(DeviceHost);
return state?.FixedTreeCache is { Capabilities.SpindleLoad: true, Capabilities.SpindleMotorSpeed: true }
&& state.LastSpindleLoads.Count >= 2;
}, TimeSpan.FromSeconds(5));
&& state.LastSpindleLoads.Count >= 2
// Motor speeds are cached after a SECOND wire round-trip (FocasDriver spindle poll), so the loads
// arriving first does not mean the speeds have — waiting on loads alone raced under load (#678.3).
&& state.LastSpindleMotorSpeeds.Count >= 2;
}, WaitTimeout);
var snapshots = await driver.ReadAsync(
[$"{DeviceHost}/Spindle/S1/Load",
@@ -282,6 +285,10 @@ public sealed class WireBackendTests
}
}
/// <summary>Generous: the sim fixture answers fast, but a loaded CI host (e.g. a concurrent docker build) does not.</summary>
private static readonly TimeSpan WaitTimeout = TimeSpan.FromSeconds(15);
/// <summary>Polls <paramref name="pred"/>; FAILS the test with a clear message on timeout rather than returning silently.</summary>
private static async Task WaitFor(Func<bool> pred, TimeSpan timeout)
{
var deadline = DateTime.UtcNow + timeout;
@@ -290,5 +297,7 @@ public sealed class WireBackendTests
if (pred()) return;
await Task.Delay(50);
}
if (pred()) return;
Assert.Fail($"Condition not met within {timeout.TotalSeconds:0.#}s waiting on the FOCAS wire backend.");
}
}