fix(adminui): Test Connect honours the configured probe timeout; drain its clear timer (R04 L2, G1-F5, F-FU2)
DriverTestConnectButton always sent a fixed 10 s, and the Galaxy/OpcUaClient probes run under min(caller, configured), so ProbeTimeoutSeconds - documented on every driver as the Test Connect timeout - could shorten a probe but never lengthen it (Galaxy's 30 s default was silently 10 s). TestConnectBudget reads the root ProbeTimeoutSeconds from the merged config at click time, clamped to the actor's [1, 60] s, falling back to TimeoutSeconds. DeviceModal (the only host) needs no change. The Galaxy/OpcUaClient form hints are reworded. The 30 s result-clear timer moves from System.Timers.Timer + an async void Elapsed lambda to System.Threading.Timer, drained in DisposeAsync, with a generation so a superseded fire cannot clear a newer result. Refs #745 Claude-Session: https://claude.ai/code/session_01Ub9hGmYLQvn9XETzw7CMsT
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
using Shouldly;
|
||||
using Xunit;
|
||||
using ZB.MOM.WW.OtOpcUa.AdminUI.Components.Shared.Drivers;
|
||||
|
||||
namespace ZB.MOM.WW.OtOpcUa.AdminUI.Tests.Drivers;
|
||||
|
||||
/// <summary>
|
||||
/// G1-F5 / F-FU2: Test Connect honours the driver's configured <c>ProbeTimeoutSeconds</c> (so it can
|
||||
/// lengthen the budget, not only shorten it), aligned across Galaxy and OpcUaClient, and the button
|
||||
/// drains its clear timer (R04 L2).
|
||||
/// </summary>
|
||||
[Trait("Category", "Unit")]
|
||||
public sealed class TestConnectBudgetTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData("{\"ProbeTimeoutSeconds\":30}", 30)] // Galaxy default — was silently 10 s
|
||||
[InlineData("{\"probeTimeoutSeconds\":15}", 15)] // OpcUaClient default, camelCase
|
||||
[InlineData("{\"ProbeTimeoutSeconds\":\"25\"}", 25)]
|
||||
[InlineData("{\"ProbeTimeoutSeconds\":2.5}", 3)]
|
||||
[InlineData("{\"ProbeTimeoutSeconds\":600}", 60)] // clamped to the actor's max
|
||||
public void A_configured_timeout_is_the_budget(string json, int expected)
|
||||
=> TestConnectBudget.Resolve(json).ShouldBe(expected);
|
||||
|
||||
[Theory]
|
||||
[InlineData(null)]
|
||||
[InlineData("")]
|
||||
[InlineData("{}")]
|
||||
[InlineData("{\"ProbeTimeoutSeconds\":0}")]
|
||||
[InlineData("{\"ProbeTimeoutSeconds\":-5}")]
|
||||
[InlineData("{\"ProbeTimeoutSeconds\":null}")]
|
||||
[InlineData("not json")]
|
||||
[InlineData("[1,2]")]
|
||||
[InlineData("{\"Nested\":{\"ProbeTimeoutSeconds\":40}}")] // only the root key counts
|
||||
public void No_valid_configured_timeout_falls_back(string? json)
|
||||
=> TestConnectBudget.Resolve(json, fallbackSeconds: 10).ShouldBe(10);
|
||||
|
||||
[Fact]
|
||||
public void The_fallback_is_clamped_too()
|
||||
{
|
||||
TestConnectBudget.Resolve("{}", fallbackSeconds: 0).ShouldBe(TestConnectBudget.MinSeconds);
|
||||
TestConnectBudget.Resolve("{}", fallbackSeconds: 999).ShouldBe(TestConnectBudget.MaxSeconds);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Button_resolves_its_budget_from_the_config_and_drains_a_threading_timer()
|
||||
{
|
||||
var src = AdminUiSource.Read("Components", "Shared", "Drivers", "DriverTestConnectButton.razor");
|
||||
|
||||
src.ShouldContain("TestConnectBudget.Resolve(json, TimeoutSeconds)");
|
||||
src.ShouldContain("@implements IAsyncDisposable");
|
||||
src.ShouldContain("System.Threading.Timer");
|
||||
src.ShouldNotContain("System.Timers.Timer");
|
||||
src.ShouldNotContain("async (_, _)");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user