fix(dcl): async OPC UA endpoint discovery bounded by OperationTimeoutMs/verify budget; adapter connect never runs on the actor thread (review 2026-10-21 02/P2)
This commit is contained in:
+36
@@ -126,4 +126,40 @@ public class DataConnectionHousekeepingTests : TestKit
|
||||
&& message.Contains("established", StringComparison.OrdinalIgnoreCase)),
|
||||
TimeSpan.FromSeconds(5));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 02/P2: an adapter whose connect does synchronous work before its first yielding await
|
||||
/// (OPC UA discovery used to) must not park the actor's dispatcher thread — the actor keeps
|
||||
/// answering while the connect is in progress.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task AdapterConnect_NeverRunsOnTheActorThread()
|
||||
{
|
||||
const string name = "connect-off-actor-thread";
|
||||
var adapter = Substitute.For<IDataConnection>();
|
||||
using var release = new ManualResetEventSlim(false);
|
||||
adapter.ConnectAsync(Arg.Any<IDictionary<string, string>>(), Arg.Any<CancellationToken>())
|
||||
.Returns(_ =>
|
||||
{
|
||||
release.Wait(TimeSpan.FromSeconds(10)); // synchronous I/O before any await
|
||||
return Task.CompletedTask;
|
||||
});
|
||||
adapter.Status.Returns(ConnectionHealth.Connecting);
|
||||
|
||||
var actor = Sys.ActorOf(Props.Create(() => new DataConnectionActor(
|
||||
name, adapter, Options(), _health, _factory, "OpcUa")), name);
|
||||
AwaitCondition(() => adapter.ReceivedCalls().Any(c => c.GetMethodInfo().Name == nameof(IDataConnection.ConnectAsync)),
|
||||
TimeSpan.FromSeconds(5));
|
||||
|
||||
try
|
||||
{
|
||||
var report = await actor.Ask<DataConnectionHealthReport>(
|
||||
new DataConnectionActor.GetHealthReport(), TimeSpan.FromSeconds(2));
|
||||
Assert.Equal(name, report.ConnectionName);
|
||||
}
|
||||
finally
|
||||
{
|
||||
release.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user