diff --git a/src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/Adapters/OpcUaDataConnection.cs b/src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/Adapters/OpcUaDataConnection.cs index 2510db86..665b2919 100644 --- a/src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/Adapters/OpcUaDataConnection.cs +++ b/src/ZB.MOM.WW.ScadaBridge.DataConnectionLayer/Adapters/OpcUaDataConnection.cs @@ -17,7 +17,7 @@ namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Adapters; /// - Read/Write → Read/Write service calls /// - Quality → OPC UA StatusCode mapping /// -public class OpcUaDataConnection : IDataConnection +public class OpcUaDataConnection : IDataConnection, IBrowsableDataConnection { private readonly IOpcUaClientFactory _clientFactory; private readonly ILogger _logger; @@ -274,6 +274,12 @@ public class OpcUaDataConnection : IDataConnection return results; } + /// + public Task BrowseChildrenAsync( + string? parentNodeId, + CancellationToken cancellationToken = default) + => _client!.BrowseChildrenAsync(parentNodeId, cancellationToken); + /// public async Task WriteBatchAndWaitAsync( IDictionary values, string flagPath, object? flagValue, diff --git a/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/Adapters/OpcUaDataConnectionBrowseTests.cs b/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/Adapters/OpcUaDataConnectionBrowseTests.cs new file mode 100644 index 00000000..0d0e06fd --- /dev/null +++ b/tests/ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests/Adapters/OpcUaDataConnectionBrowseTests.cs @@ -0,0 +1,41 @@ +using Microsoft.Extensions.Logging.Abstractions; +using NSubstitute; +using ZB.MOM.WW.ScadaBridge.Commons.Interfaces.Protocol; +using ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Adapters; + +namespace ZB.MOM.WW.ScadaBridge.DataConnectionLayer.Tests.Adapters; + +/// +/// Task 9 (opcua-tag-browser): implements +/// as a one-line forwarder onto the +/// underlying . This guards that wiring — the +/// adapter must not add its own browse semantics; all browse behaviour lives +/// in the client (and is covered by RealOpcUaClient's own tests). +/// +public class OpcUaDataConnectionBrowseTests +{ + [Fact] + public async Task BrowseChildrenAsync_ForwardsToUnderlyingClient() + { + var client = Substitute.For(); + var factory = Substitute.For(); + factory.Create().Returns(client); + client.IsConnected.Returns(true); + + var expected = new BrowseChildrenResult( + new[] { new BrowseNode("ns=2;s=X", "X", BrowseNodeClass.Variable, false) }, + Truncated: false); + client.BrowseChildrenAsync("ns=2;s=Parent", Arg.Any()) + .Returns(expected); + + var adapter = new OpcUaDataConnection(factory, NullLogger.Instance); + // ConnectAsync installs the IOpcUaClient instance on the adapter; the + // forwarder dereferences that field directly. + await adapter.ConnectAsync(new Dictionary()); + + var actual = await adapter.BrowseChildrenAsync("ns=2;s=Parent"); + + Assert.Same(expected, actual); + await client.Received(1).BrowseChildrenAsync("ns=2;s=Parent", Arg.Any()); + } +}