/// <summary> /// Worker function to browse the full address space of a server. /// </summary> /// <param name="services">The service interface.</param> /// <param name="operationLimits">The operation limits.</param> public static ReferenceDescriptionCollection BrowseFullAddressSpaceWorker( IServerTestServices services, RequestHeader requestHeader, OperationLimits operationLimits = null, BrowseDescription browseDescription = null) { operationLimits = operationLimits ?? new OperationLimits(); requestHeader.Timestamp = DateTime.UtcNow; // Browse template var startingNode = Objects.RootFolder; var browseTemplate = browseDescription ?? new BrowseDescription { NodeId = startingNode, BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences, IncludeSubtypes = true, NodeClassMask = 0, ResultMask = (uint)BrowseResultMask.All }; var browseDescriptionCollection = ServerFixtureUtils.CreateBrowseDescriptionCollectionFromNodeId( new NodeIdCollection(new NodeId[] { Objects.RootFolder }), browseTemplate); // Browse ResponseHeader response = null; uint requestedMaxReferencesPerNode = operationLimits.MaxNodesPerBrowse; bool verifyMaxNodesPerBrowse = operationLimits.MaxNodesPerBrowse > 0; var referenceDescriptions = new ReferenceDescriptionCollection(); // Test if server responds with BadNothingToDo { var sre = Assert.Throws <ServiceResultException>(() => _ = services.Browse(requestHeader, null, 0, browseDescriptionCollection.Take(0).ToArray(), out var results, out var infos)); Assert.AreEqual(StatusCodes.BadNothingToDo, sre.StatusCode); } while (browseDescriptionCollection.Any()) { BrowseResultCollection allResults = new BrowseResultCollection(); if (verifyMaxNodesPerBrowse && browseDescriptionCollection.Count > operationLimits.MaxNodesPerBrowse) { verifyMaxNodesPerBrowse = false; // Test if server responds with BadTooManyOperations var sre = Assert.Throws <ServiceResultException>(() => _ = services.Browse(requestHeader, null, 0, browseDescriptionCollection, out var results, out var infos)); Assert.AreEqual(StatusCodes.BadTooManyOperations, sre.StatusCode); // Test if server responds with BadTooManyOperations var tempBrowsePath = browseDescriptionCollection.Take((int)operationLimits.MaxNodesPerBrowse + 1).ToArray(); sre = Assert.Throws <ServiceResultException>(() => _ = services.Browse(requestHeader, null, 0, tempBrowsePath, out var results, out var infos)); Assert.AreEqual(StatusCodes.BadTooManyOperations, sre.StatusCode); } bool repeatBrowse; var maxNodesPerBrowse = operationLimits.MaxNodesPerBrowse; BrowseResultCollection browseResultCollection = new BrowseResultCollection(); DiagnosticInfoCollection diagnosticsInfoCollection; do { var browseCollection = (maxNodesPerBrowse == 0) ? browseDescriptionCollection : browseDescriptionCollection.Take((int)maxNodesPerBrowse).ToArray(); repeatBrowse = false; try { requestHeader.Timestamp = DateTime.UtcNow; response = services.Browse(requestHeader, null, requestedMaxReferencesPerNode, browseCollection, out browseResultCollection, out diagnosticsInfoCollection); ServerFixtureUtils.ValidateResponse(response); ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticsInfoCollection, browseCollection); allResults.AddRange(browseResultCollection); } catch (ServiceResultException sre) { if (sre.StatusCode == StatusCodes.BadEncodingLimitsExceeded || sre.StatusCode == StatusCodes.BadResponseTooLarge) { // try to address by overriding operation limit maxNodesPerBrowse = maxNodesPerBrowse == 0 ? (uint)browseCollection.Count / 2 : maxNodesPerBrowse / 2; repeatBrowse = true; } else { throw; } } } while (repeatBrowse); if (maxNodesPerBrowse == 0) { browseDescriptionCollection.Clear(); } else { browseDescriptionCollection = browseDescriptionCollection.Skip((int)maxNodesPerBrowse).ToArray(); } // Browse next var continuationPoints = ServerFixtureUtils.PrepareBrowseNext(browseResultCollection); while (continuationPoints.Any()) { requestHeader.Timestamp = DateTime.UtcNow; response = services.BrowseNext(requestHeader, false, continuationPoints, out var browseNextResultCollection, out diagnosticsInfoCollection); ServerFixtureUtils.ValidateResponse(response); ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticsInfoCollection, continuationPoints); allResults.AddRange(browseNextResultCollection); continuationPoints = ServerFixtureUtils.PrepareBrowseNext(browseNextResultCollection); } // Build browse request for next level var browseTable = new NodeIdCollection(); foreach (var result in allResults) { referenceDescriptions.AddRange(result.References); foreach (var reference in result.References) { browseTable.Add(ExpandedNodeId.ToNodeId(reference.NodeId, null)); } } browseDescriptionCollection = ServerFixtureUtils.CreateBrowseDescriptionCollectionFromNodeId(browseTable, browseTemplate); } referenceDescriptions.Sort((x, y) => (x.NodeId.CompareTo(y.NodeId))); TestContext.Out.WriteLine("Found {0} references on server.", referenceDescriptions.Count); foreach (var reference in referenceDescriptions) { TestContext.Out.WriteLine("NodeId {0} {1} {2}", reference.NodeId, reference.NodeClass, reference.BrowseName); } return(referenceDescriptions); }
public async Task BrowseAsync() { // Browse template var startingNode = Objects.RootFolder; var browseTemplate = new BrowseDescription { NodeId = startingNode, BrowseDirection = BrowseDirection.Forward, ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences, IncludeSubtypes = true, NodeClassMask = 0, ResultMask = (uint)BrowseResultMask.All }; var requestHeader = new RequestHeader(); var referenceDescriptions = new ReferenceDescriptionCollection(); var browseDescriptionCollection = ServerFixtureUtils.CreateBrowseDescriptionCollectionFromNodeId( new NodeIdCollection(new NodeId[] { Objects.RootFolder }), browseTemplate); while (browseDescriptionCollection.Any()) { TestContext.Out.WriteLine("Browse {0} Nodes...", browseDescriptionCollection.Count); BrowseResultCollection allResults = new BrowseResultCollection(); var response = await Session.BrowseAsync( requestHeader, null, 5, browseDescriptionCollection, CancellationToken.None).ConfigureAwait(false); BrowseResultCollection results = response.Results; DiagnosticInfoCollection diagnosticInfos = response.DiagnosticInfos; allResults.AddRange(results); var continuationPoints = ServerFixtureUtils.PrepareBrowseNext(results); while (continuationPoints.Any()) { TestContext.Out.WriteLine("BrowseNext {0} Nodes...", continuationPoints.Count); var nextResponse = await Session.BrowseNextAsync(requestHeader, false, continuationPoints, CancellationToken.None); BrowseResultCollection browseNextResultCollection = nextResponse.Results; diagnosticInfos = nextResponse.DiagnosticInfos; ServerFixtureUtils.ValidateResponse(response.ResponseHeader); ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, continuationPoints); allResults.AddRange(browseNextResultCollection); continuationPoints = ServerFixtureUtils.PrepareBrowseNext(browseNextResultCollection); } // Build browse request for next level var browseTable = new NodeIdCollection(); foreach (var result in allResults) { referenceDescriptions.AddRange(result.References); foreach (var reference in result.References) { browseTable.Add(ExpandedNodeId.ToNodeId(reference.NodeId, Session.NamespaceUris)); } } browseDescriptionCollection = ServerFixtureUtils.CreateBrowseDescriptionCollectionFromNodeId(browseTable, browseTemplate); } referenceDescriptions.Sort((x, y) => (x.NodeId.CompareTo(y.NodeId))); // read values var nodesToRead = new ReadValueIdCollection(referenceDescriptions.Select(r => new ReadValueId() { NodeId = ExpandedNodeId.ToNodeId(r.NodeId, Session.NamespaceUris), AttributeId = Attributes.Value })); // test reads TestContext.Out.WriteLine("Test Read Nodes..."); var readResponse = await Session.ReadAsync(requestHeader, 0, TimestampsToReturn.Neither, nodesToRead, CancellationToken.None).ConfigureAwait(false); // test register nodes TestContext.Out.WriteLine("Test Register Nodes..."); var nodesToRegister = new NodeIdCollection(nodesToRead.Select(n => n.NodeId)); var registerResponse = await Session.RegisterNodesAsync(requestHeader, nodesToRegister, CancellationToken.None).ConfigureAwait(false); var unregisterResponse = await Session.UnregisterNodesAsync(requestHeader, registerResponse.RegisteredNodeIds, CancellationToken.None).ConfigureAwait(false); // test writes var nodesToWrite = new WriteValueCollection(); int ii = 0; foreach (var result in readResponse.Results) { if (StatusCode.IsGood(result.StatusCode)) { var writeValue = new WriteValue() { AttributeId = Attributes.Value, NodeId = nodesToRead[ii].NodeId, Value = new DataValue(result.WrappedValue) }; nodesToWrite.Add(writeValue); } ii++; } TestContext.Out.WriteLine("Test Writes..."); var writeResponse = await Session.WriteAsync(requestHeader, nodesToWrite, CancellationToken.None).ConfigureAwait(false); TestContext.Out.WriteLine("Found {0} references on server.", referenceDescriptions.Count); ii = 0; foreach (var reference in referenceDescriptions) { TestContext.Out.WriteLine("NodeId {0} {1} {2} {3}", reference.NodeId, reference.NodeClass, reference.BrowseName, readResponse.Results[ii++].WrappedValue); } }