feat(runtime): wire driver SubscribeBulk pass so tag values stream
v2-ci / build (push) Failing after 51s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
v2-ci / build (push) Failing after 51s
v2-ci / unit-tests (tests/Core/ZB.MOM.WW.OtOpcUa.Cluster.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.ControlPlane.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Runtime.Tests) (push) Has been skipped
v2-ci / unit-tests (tests/Server/ZB.MOM.WW.OtOpcUa.Security.Tests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.Host.IntegrationTests) (push) Has been skipped
v2-ci / integration (tests/Server/ZB.MOM.WW.OtOpcUa.OpcUaServer.IntegrationTests) (push) Has been skipped
Materialised SystemPlatform/Galaxy variables previously stayed BadWaitingForInitialData because nothing told the driver to subscribe (OpcUaPublishActor TODO 'on a future SubscribeBulk pass') and published values were only forwarded to the VirtualTag mux, never the OPC UA sink. DriverHostActor now, after each apply, groups the deployment's galaxy tag MXAccess refs by driver and sends DriverInstanceActor.SetDesiredSubscriptions; the actor retains the set and (re)subscribes on every Connected entry, so values resume after reconnects/redeploys (closes the F8b/#113 gap). Published values are also forwarded to OpcUaPublishActor as AttributeValueUpdate (NodeId == galaxy MxAccessRef) so the materialised variable shows live data. Verified live in docker-dev: galaxy TestMachine_001 tags go Good with a changing TestChangingInt. +1 unit test.
This commit is contained in:
@@ -152,6 +152,36 @@ public sealed class DriverInstanceActorTests : RuntimeActorTestBase
|
||||
parent.ExpectMsg<DriverInstanceActor.AttributeValuePublished>().Quality.ShouldBe(OpcUaQuality.Bad);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Verifies the SubscribeBulk pass: SetDesiredSubscriptions retains the ref set and the actor
|
||||
/// auto-subscribes when it (re)enters Connected — including a re-subscribe after a reconnect,
|
||||
/// closing the F8b/#113 gap that previously left galaxy variables at BadWaitingForInitialData.
|
||||
/// </summary>
|
||||
[Fact]
|
||||
public async Task SetDesiredSubscriptions_auto_subscribes_on_connect_and_resubscribes_after_reconnect()
|
||||
{
|
||||
var driver = new SubscribableStubDriver();
|
||||
var parent = CreateTestProbe();
|
||||
var actor = parent.ChildActorOf(DriverInstanceActor.Props(driver, reconnectInterval: TimeSpan.FromMilliseconds(50)));
|
||||
|
||||
// Desired set arrives BEFORE connect — retained, not yet applied.
|
||||
actor.Tell(new DriverInstanceActor.SetDesiredSubscriptions(
|
||||
new[] { "tag-a", "tag-b" }, TimeSpan.FromMilliseconds(100)));
|
||||
|
||||
// Connecting → Connected triggers the auto-subscribe.
|
||||
actor.Tell(new DriverInstanceActor.InitializeRequested("{}"));
|
||||
AwaitCondition(() => driver.SubscribeCount >= 1, TimeSpan.FromSeconds(2));
|
||||
driver.LastSubscribedRefs.ShouldBe(new[] { "tag-a", "tag-b" });
|
||||
|
||||
// The auto-subscription is live — a data change reaches the parent.
|
||||
driver.FireDataChange("tag-a", value: 7, statusCode: 0u);
|
||||
parent.ExpectMsg<DriverInstanceActor.AttributeValuePublished>(TimeSpan.FromSeconds(2)).Value.ShouldBe(7);
|
||||
|
||||
// Reconnect → the desired set is re-established without any new host message.
|
||||
actor.Tell(new DriverInstanceActor.DisconnectObserved("backend blip"));
|
||||
AwaitCondition(() => driver.SubscribeCount >= 2, TimeSpan.FromSeconds(3));
|
||||
}
|
||||
|
||||
/// <summary>Verifies that subscribing to a non-ISubscribable driver replies with failure.</summary>
|
||||
[Fact]
|
||||
public async Task Subscribe_against_non_ISubscribable_replies_with_failure()
|
||||
@@ -266,13 +296,22 @@ public sealed class DriverInstanceActorTests : RuntimeActorTestBase
|
||||
/// <summary>Gets the number of subscribers to OnDataChange.</summary>
|
||||
public int OnDataChangeSubscriberCount => OnDataChange?.GetInvocationList().Length ?? 0;
|
||||
|
||||
/// <summary>Number of times <see cref="SubscribeAsync"/> was called (re-subscribe asserts).</summary>
|
||||
public int SubscribeCount;
|
||||
/// <summary>The reference set passed to the most recent <see cref="SubscribeAsync"/> call.</summary>
|
||||
public IReadOnlyList<string>? LastSubscribedRefs;
|
||||
|
||||
/// <summary>Subscribes to the specified full references.</summary>
|
||||
/// <param name="fullReferences">The full references to subscribe to.</param>
|
||||
/// <param name="publishingInterval">The publishing interval.</param>
|
||||
/// <param name="cancellationToken">Cancellation token for the operation.</param>
|
||||
public Task<ISubscriptionHandle> SubscribeAsync(
|
||||
IReadOnlyList<string> fullReferences, TimeSpan publishingInterval, CancellationToken cancellationToken)
|
||||
=> Task.FromResult<ISubscriptionHandle>(_handle);
|
||||
{
|
||||
Interlocked.Increment(ref SubscribeCount);
|
||||
LastSubscribedRefs = fullReferences;
|
||||
return Task.FromResult<ISubscriptionHandle>(_handle);
|
||||
}
|
||||
|
||||
/// <summary>Unsubscribes from the specified subscription handle.</summary>
|
||||
/// <param name="handle">The subscription handle.</param>
|
||||
|
||||
Reference in New Issue
Block a user