private static void CreateMonitoredItem(
            IServerTestServices services, RequestHeader requestHeader,
            uint subscriptionId, NodeId nodeId)
        {
            uint queueSize     = 5;
            var  itemsToCreate = new MonitoredItemCreateRequestCollection {
                // add item
                new MonitoredItemCreateRequest {
                    ItemToMonitor = new ReadValueId {
                        AttributeId = Attributes.Value,
                        NodeId      = nodeId
                    },
                    MonitoringMode      = MonitoringMode.Reporting,
                    RequestedParameters = new MonitoringParameters {
                        ClientHandle     = 1u,
                        SamplingInterval = -1,
                        Filter           = null,
                        DiscardOldest    = true,
                        QueueSize        = queueSize
                    }
                }
            };
            var response = services.CreateMonitoredItems(requestHeader, subscriptionId, TimestampsToReturn.Neither, itemsToCreate,
                                                         out MonitoredItemCreateResultCollection itemCreateResults, out DiagnosticInfoCollection diagnosticInfos);

            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, itemsToCreate);
        }
Example #2
0
        private CallMethodRequestCollection ResendDataCall(StatusCode expectedStatus, UInt32Collection subscriptionIds)
        {
            // Find the ResendData method
            var nodesToCall = new CallMethodRequestCollection();

            foreach (var subscriptionId in subscriptionIds)
            {
                nodesToCall.Add(new CallMethodRequest()
                {
                    ObjectId       = ObjectIds.Server,
                    MethodId       = MethodIds.Server_ResendData,
                    InputArguments = new VariantCollection()
                    {
                        new Variant(subscriptionId)
                    }
                });
            }

            //call ResendData method with subscription ids
            m_requestHeader.Timestamp = DateTime.UtcNow;
            var response = m_server.Call(m_requestHeader,
                                         nodesToCall,
                                         out var results,
                                         out var diagnosticInfos);

            Assert.AreEqual(expectedStatus, results[0].StatusCode.Code);
            ServerFixtureUtils.ValidateResponse(response);

            return(nodesToCall);
        }
Example #3
0
        /// <summary>
        /// Start server fixture on random or fixed port.
        /// </summary>
        public async Task <T> StartAsync(TextWriter writer, int port = 0)
        {
            Random m_random           = new Random();
            bool   retryStartServer   = false;
            int    testPort           = port;
            int    serverStartRetries = 1;

            if (port <= 0)
            {
                testPort           = ServerFixtureUtils.GetNextFreeIPPort();
                serverStartRetries = 25;
            }

            do
            {
                try
                {
                    await InternalStartServerAsync(writer, testPort).ConfigureAwait(false);
                }
                catch (ServiceResultException sre)
                {
                    if (serverStartRetries <= 0 ||
                        sre.StatusCode != StatusCodes.BadNoCommunication)
                    {
                        throw;
                    }
                    serverStartRetries--;
                    testPort         = m_random.Next(ServerFixtureUtils.MinTestPort, ServerFixtureUtils.MaxTestPort);
                    retryStartServer = true;
                }
                await Task.Delay(m_random.Next(100, 1000)).ConfigureAwait(false);
            } while (retryStartServer);

            return(Server);
        }
        /// <summary>
        /// Worker method to translate the browse path.
        /// </summary>
        public static BrowsePathResultCollection TranslateBrowsePathWorker(
            IServerTestServices services,
            ReferenceDescriptionCollection referenceDescriptions,
            RequestHeader requestHeader,
            OperationLimits operationLimits)
        {
            // Browse template
            var startingNode = Objects.RootFolder;

            requestHeader.Timestamp = DateTime.UtcNow;

            // TranslateBrowsePath
            bool verifyMaxNodesPerBrowse = operationLimits.MaxNodesPerTranslateBrowsePathsToNodeIds > 0;
            var  browsePaths             = new BrowsePathCollection(
                referenceDescriptions.Select(r => new BrowsePath()
            {
                RelativePath = new RelativePath(r.BrowseName), StartingNode = startingNode
            })
                );
            BrowsePathResultCollection allBrowsePaths = new BrowsePathResultCollection();

            while (browsePaths.Any())
            {
                if (verifyMaxNodesPerBrowse &&
                    browsePaths.Count > operationLimits.MaxNodesPerTranslateBrowsePathsToNodeIds)
                {
                    verifyMaxNodesPerBrowse = false;
                    // Test if server responds with BadTooManyOperations
                    var sre = Assert.Throws <ServiceResultException>(() =>
                                                                     _ = services.TranslateBrowsePathsToNodeIds(requestHeader, browsePaths, out var results, out var infos));
                    Assert.AreEqual(StatusCodes.BadTooManyOperations, sre.StatusCode);
                }
                var browsePathSnippet = (operationLimits.MaxNodesPerTranslateBrowsePathsToNodeIds > 0) ?
                                        browsePaths.Take((int)operationLimits.MaxNodesPerTranslateBrowsePathsToNodeIds).ToArray() :
                                        browsePaths;
                ResponseHeader response = services.TranslateBrowsePathsToNodeIds(requestHeader, browsePathSnippet, out var browsePathResults, out var diagnosticInfos);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, browsePathSnippet);
                allBrowsePaths.AddRange(browsePathResults);
                foreach (var result in browsePathResults)
                {
                    if (result.Targets?.Count > 0)
                    {
                        TestContext.Out.WriteLine("BrowsePath {0}", result.Targets[0].ToString());
                    }
                }

                if (operationLimits.MaxNodesPerTranslateBrowsePathsToNodeIds == 0)
                {
                    browsePaths.Clear();
                }
                else
                {
                    browsePaths = browsePaths.Skip((int)operationLimits.MaxNodesPerTranslateBrowsePathsToNodeIds).ToArray();
                }
            }
            return(allBrowsePaths);
        }
        /// <summary>
        /// Worker method to test Transfer of subscriptions to new session.
        /// </summary>
        public static void TransferSubscriptionTest(
            IServerTestServices services,
            RequestHeader requestHeader,
            UInt32Collection subscriptionIds,
            bool sendInitialData,
            bool expectAccessDenied)
        {
            Assert.AreEqual(1, subscriptionIds.Count);

            requestHeader.Timestamp = DateTime.UtcNow;
            var response = services.TransferSubscriptions(requestHeader, subscriptionIds, sendInitialData,
                                                          out TransferResultCollection transferResults, out DiagnosticInfoCollection diagnosticInfos);

            Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
            Assert.AreEqual(subscriptionIds.Count, transferResults.Count);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptionIds);

            foreach (var transferResult in transferResults)
            {
                TestContext.Out.WriteLine("TransferResult: {0}", transferResult.StatusCode);
                if (expectAccessDenied)
                {
                    Assert.AreEqual(StatusCodes.BadUserAccessDenied, transferResult.StatusCode.Code);
                }
                else
                {
                    Assert.IsTrue(StatusCode.IsGood(transferResult.StatusCode));
                    Assert.AreEqual(1, transferResult.AvailableSequenceNumbers.Count);
                }
            }

            if (expectAccessDenied)
            {
                return;
            }

            requestHeader.Timestamp = DateTime.UtcNow;
            var acknoledgements = new SubscriptionAcknowledgementCollection();

            response = services.Publish(requestHeader, acknoledgements,
                                        out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                        out bool moreNotifications, out NotificationMessage notificationMessage,
                                        out StatusCodeCollection _, out diagnosticInfos);
            Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
            Assert.AreEqual(subscriptionIds[0], publishedId);
            Assert.AreEqual(sendInitialData ? 1 : 0, notificationMessage.NotificationData.Count);
            //Assert.AreEqual(0, availableSequenceNumbers.Count);

            requestHeader.Timestamp = DateTime.UtcNow;
            response = services.DeleteSubscriptions(requestHeader, subscriptionIds, out StatusCodeCollection statusResults, out diagnosticInfos);
            Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
        }
Example #6
0
        /// <summary>
        /// Read Values of NodeIds, determine types, write back new random values.
        /// </summary>
        /// <param name="testSet">The nodeIds to modify.</param>
        private void UpdateValues(NodeId[] testSet)
        {
            // Read values
            var requestHeader = m_requestHeader;
            var nodesToRead   = new ReadValueIdCollection();

            foreach (NodeId nodeId in testSet)
            {
                nodesToRead.Add(new ReadValueId()
                {
                    NodeId = nodeId, AttributeId = Attributes.Value
                });
            }
            var response = m_server.Read(requestHeader, kMaxAge, TimestampsToReturn.Neither, nodesToRead,
                                         out var readDataValues, out var diagnosticInfos);

            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, readDataValues);
            Assert.AreEqual(testSet.Length, readDataValues.Count);

            var modifiedValues = new DataValueCollection();

            foreach (var dataValue in readDataValues)
            {
                var typeInfo = TypeInfo.Construct(dataValue.Value);
                Assert.IsNotNull(typeInfo);
                var value = m_generator.GetRandom(typeInfo.BuiltInType);
                modifiedValues.Add(new DataValue()
                {
                    WrappedValue = new Variant(value)
                });
            }

            int ii           = 0;
            var nodesToWrite = new WriteValueCollection();

            foreach (NodeId nodeId in testSet)
            {
                nodesToWrite.Add(new WriteValue()
                {
                    NodeId = nodeId, AttributeId = Attributes.Value, Value = modifiedValues[ii]
                });
                ii++;
            }

            // Write Nodes
            requestHeader.Timestamp = DateTime.UtcNow;
            response = m_server.Write(requestHeader, nodesToWrite,
                                      out var writeDataValues, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, writeDataValues);
        }
        /// <summary>
        /// Worker method to test TransferSubscriptions of a server.
        /// </summary>
        public static UInt32Collection CreateSubscriptionForTransfer(
            IServerTestServices services,
            RequestHeader requestHeader,
            NodeId[] testNodes,
            uint queueSize       = DefaultMonitoredItemsQueueSize,
            int samplingInterval = DefaultMonitoredItemsSamplingInterval)
        {
            // start time

            requestHeader.Timestamp = DateTime.UtcNow;
            uint subscriptionId = CreateSubscription(services, requestHeader);
            uint clientHandle   = 1;

            foreach (NodeId testNode in testNodes)
            {
                CreateMonitoredItem(services, requestHeader, subscriptionId, testNode, clientHandle++, queueSize, samplingInterval);
            }

            var subscriptionIds = new UInt32Collection();

            subscriptionIds.Add(subscriptionId);

            // enable publishing
            var response = services.SetPublishingMode(requestHeader, true, subscriptionIds,
                                                      out var statuses, out var diagnosticInfos);

            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptionIds);

            // wait some time to settle
            Thread.Sleep(1000);

            // publish request
            var acknoledgements = new SubscriptionAcknowledgementCollection();

            response = services.Publish(requestHeader, acknoledgements,
                                        out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                        out bool moreNotifications, out NotificationMessage notificationMessage,
                                        out StatusCodeCollection _, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
            Assert.AreEqual(subscriptionId, publishedId);

            // static node, do not acknoledge
            Assert.AreEqual(1, availableSequenceNumbers.Count);

            return(subscriptionIds);
        }
Example #8
0
        public void Write()
        {
            // Write
            var requestHeader = m_requestHeader;

            requestHeader.Timestamp = DateTime.UtcNow;
            var nodesToWrite = new WriteValueCollection();
            var nodeId       = new NodeId("Scalar_Simulation_Int32", 2);

            nodesToWrite.Add(new WriteValue()
            {
                NodeId = nodeId, AttributeId = Attributes.Value, Value = new DataValue(1234)
            });
            var response = m_server.Write(requestHeader, nodesToWrite,
                                          out var dataValues, out var diagnosticInfos);

            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, dataValues);
        }
        /// <summary>
        /// Worker method to verify the SubscriptionTransferred message of a server.
        /// </summary>
        public static void VerifySubscriptionTransferred(
            IServerTestServices services,
            RequestHeader requestHeader,
            UInt32Collection subscriptionIds,
            bool deleteSubscriptions)
        {
            // start time
            requestHeader.Timestamp = DateTime.UtcNow;

            // wait some time to settle
            Thread.Sleep(100);

            // publish request
            var acknoledgements = new SubscriptionAcknowledgementCollection();
            var response        = services.Publish(requestHeader, acknoledgements,
                                                   out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                                   out bool moreNotifications, out NotificationMessage notificationMessage,
                                                   out StatusCodeCollection _, out var diagnosticInfos);

            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
            Assert.IsFalse(moreNotifications);
            Assert.IsTrue(subscriptionIds.Contains(publishedId));
            Assert.AreEqual(1, notificationMessage.NotificationData.Count);
            var statusMessage = notificationMessage.NotificationData[0].ToString();

            Assert.IsTrue(statusMessage.Contains("GoodSubscriptionTransferred"));

            // static node, do not acknoledge
            if (availableSequenceNumbers != null)
            {
                Assert.AreEqual(0, availableSequenceNumbers.Count);
            }

            if (deleteSubscriptions)
            {
                response = services.DeleteSubscriptions(requestHeader, subscriptionIds, out var _, out diagnosticInfos);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptionIds);
            }
        }
Example #10
0
        public void ReadAllNodes()
        {
            var serverTestServices = new ServerTestServices(m_server);

            if (m_operationLimits == null)
            {
                GetOperationLimits();
            }
            if (m_referenceDescriptions == null)
            {
                m_referenceDescriptions = CommonTestWorkers.BrowseFullAddressSpaceWorker(serverTestServices, m_requestHeader, m_operationLimits);
            }

            // Read all variables
            var requestHeader = m_requestHeader;

            foreach (var reference in m_referenceDescriptions)
            {
                requestHeader.Timestamp = DateTime.UtcNow;
                var nodesToRead = new ReadValueIdCollection();
                var nodeId      = ExpandedNodeId.ToNodeId(reference.NodeId, m_server.CurrentInstance.NamespaceUris);
                foreach (var attributeId in ServerFixtureUtils.AttributesIds.Keys)
                {
                    nodesToRead.Add(new ReadValueId()
                    {
                        NodeId = nodeId, AttributeId = attributeId
                    });
                }
                TestContext.Out.WriteLine("NodeId {0} {1}", reference.NodeId, reference.BrowseName);
                var response = m_server.Read(requestHeader, MaxAge, TimestampsToReturn.Both, nodesToRead,
                                             out var dataValues, out var diagnosticInfos);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, dataValues);

                foreach (var dataValue in dataValues)
                {
                    TestContext.Out.WriteLine(" {0}", dataValue.ToString());
                }
            }
        }
        private static uint CreateSubscription(IServerTestServices services, RequestHeader requestHeader)
        {
            // start time
            requestHeader.Timestamp = DateTime.UtcNow;

            // create subscription
            double publishingInterval        = 1000.0;
            uint   lifetimeCount             = 60;
            uint   maxKeepAliveCount         = 2;
            uint   maxNotificationPerPublish = 0;
            byte   priority = 128;
            bool   enabled  = false;

            var response = services.CreateSubscription(requestHeader,
                                                       publishingInterval, lifetimeCount, maxKeepAliveCount,
                                                       maxNotificationPerPublish, enabled, priority,
                                                       out uint id, out double revisedPublishingInterval, out uint revisedLifetimeCount, out uint revisedMaxKeepAliveCount);

            ServerFixtureUtils.ValidateResponse(response);

            return(id);
        }
Example #12
0
        public void Read()
        {
            // Read
            var requestHeader = m_requestHeader;

            requestHeader.Timestamp = DateTime.UtcNow;
            var nodesToRead = new ReadValueIdCollection();
            var nodeId      = new NodeId("Scalar_Simulation_Int32", 2);

            foreach (var attributeId in ServerFixtureUtils.AttributesIds.Keys)
            {
                nodesToRead.Add(new ReadValueId()
                {
                    NodeId = nodeId, AttributeId = attributeId
                });
            }
            var response = m_server.Read(requestHeader, MaxAge, TimestampsToReturn.Neither, nodesToRead,
                                         out var dataValues, out var diagnosticInfos);

            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, dataValues);
        }
Example #13
0
        public void ResendData(bool updateValues, uint queueSize)
        {
            var serverTestServices = new ServerTestServices(m_server);
            // save old security context, test fixture can only work with one session
            var securityContext = SecureChannelContext.Current;

            try
            {
                var namespaceUris = m_server.CurrentInstance.NamespaceUris;
                NodeIdCollection testSetCollection = CommonTestWorkers.NodeIdTestSetStatic.Select(n => ExpandedNodeId.ToNodeId(n, namespaceUris)).ToArray();
                testSetCollection.AddRange(CommonTestWorkers.NodeIdTestDataSetStatic.Select(n => ExpandedNodeId.ToNodeId(n, namespaceUris)).ToArray());
                NodeId[] testSet = testSetCollection.ToArray();

                //Re-use method CreateSubscriptionForTransfer to create a subscription
                var subscriptionIds = CommonTestWorkers.CreateSubscriptionForTransfer(serverTestServices, m_requestHeader, testSet, queueSize, 0);

                RequestHeader resendDataRequestHeader   = m_server.CreateAndActivateSession("ResendData");
                var           resendDataSecurityContext = SecureChannelContext.Current;

                SecureChannelContext.Current = securityContext;
                // After the ResendData call there will be data to publish again
                var nodesToCall = ResendDataCall(StatusCodes.Good, subscriptionIds);

                Thread.Sleep(1000);

                // Make sure publish queue becomes empty by consuming it
                Assert.AreEqual(1, subscriptionIds.Count);

                // Issue a Publish request
                m_requestHeader.Timestamp = DateTime.UtcNow;
                var acknoledgements = new SubscriptionAcknowledgementCollection();
                var response        = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                                 out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                                                 out bool moreNotifications, out NotificationMessage notificationMessage,
                                                                 out StatusCodeCollection _, out DiagnosticInfoCollection diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(1, notificationMessage.NotificationData.Count);

                // Validate nothing to publish a few times
                const int timesToCallPublish = 3;
                for (int i = 0; i < timesToCallPublish; i++)
                {
                    m_requestHeader.Timestamp = DateTime.UtcNow;
                    response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                          out publishedId, out availableSequenceNumbers,
                                                          out moreNotifications, out notificationMessage,
                                                          out StatusCodeCollection _, out diagnosticInfos);

                    Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                    ServerFixtureUtils.ValidateResponse(response);
                    ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                    Assert.AreEqual(subscriptionIds[0], publishedId);
                    Assert.AreEqual(0, notificationMessage.NotificationData.Count);
                }

                // Validate ResendData method call returns error from different session contexts

                // call ResendData method from different session context
                SecureChannelContext.Current      = resendDataSecurityContext;
                resendDataRequestHeader.Timestamp = DateTime.UtcNow;
                response = m_server.Call(resendDataRequestHeader,
                                         nodesToCall,
                                         out var results,
                                         out diagnosticInfos);

                SecureChannelContext.Current = securityContext;

                Assert.AreEqual(StatusCodes.BadUserAccessDenied, results[0].StatusCode.Code);
                ServerFixtureUtils.ValidateResponse(response);

                // Still nothing to publish since previous ResendData call did not execute
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(0, notificationMessage.NotificationData.Count);

                if (updateValues)
                {
                    UpdateValues(testSet);

                    // fill queues, but only a single value per resend publish shall be returned
                    for (int i = 1; i < queueSize; i++)
                    {
                        UpdateValues(testSet);
                    }
                }

                // call ResendData method from the same session context
                ResendDataCall(StatusCodes.Good, subscriptionIds);

                // Data should be available for publishing now
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(1, notificationMessage.NotificationData.Count);
                var items = notificationMessage.NotificationData.FirstOrDefault();
                Assert.IsTrue(items.Body is Opc.Ua.DataChangeNotification);
                var monitoredItemsCollection = ((Opc.Ua.DataChangeNotification)items.Body).MonitoredItems;
                Assert.AreEqual(testSet.Length, monitoredItemsCollection.Count);

                Thread.Sleep(1000);

                if (updateValues && queueSize > 1)
                {
                    // remaining queue Data should be sent in this publish
                    m_requestHeader.Timestamp = DateTime.UtcNow;
                    response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                          out publishedId, out availableSequenceNumbers,
                                                          out moreNotifications, out notificationMessage,
                                                          out StatusCodeCollection _, out diagnosticInfos);

                    Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                    ServerFixtureUtils.ValidateResponse(response);
                    ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                    Assert.AreEqual(subscriptionIds[0], publishedId);
                    Assert.AreEqual(1, notificationMessage.NotificationData.Count);
                    items = notificationMessage.NotificationData.FirstOrDefault();
                    Assert.IsTrue(items.Body is Opc.Ua.DataChangeNotification);
                    monitoredItemsCollection = ((Opc.Ua.DataChangeNotification)items.Body).MonitoredItems;
                    Assert.AreEqual(testSet.Length * (queueSize - 1), monitoredItemsCollection.Count, testSet.Length);
                }

                // Call ResendData method with invalid subscription Id
                ResendDataCall(StatusCodes.BadSubscriptionIdInvalid, new UInt32Collection()
                {
                    subscriptionIds.Last() + 20
                });

                // Nothing to publish since previous ResendData call did not execute
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(0, notificationMessage.NotificationData.Count);

                resendDataRequestHeader.Timestamp = DateTime.UtcNow;
                SecureChannelContext.Current      = resendDataSecurityContext;
                m_server.CloseSession(resendDataRequestHeader);
            }
            finally
            {
                //restore security context, that close connection can work
                SecureChannelContext.Current = securityContext;
            }
        }
        /// <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 void ResendData()
        {
            var serverTestServices = new ServerTestServices(m_server);
            // save old security context, test fixture can only work with one session
            var securityContext = SecureChannelContext.Current;

            try
            {
                var      namespaceUris = m_server.CurrentInstance.NamespaceUris;
                NodeId[] testSet       = CommonTestWorkers.NodeIdTestSetStatic.Select(n => ExpandedNodeId.ToNodeId(n, namespaceUris)).ToArray();
                //Re-use method CreateSubscriptionForTransfer to create a subscription
                CommonTestWorkers.CreateSubscriptionForTransfer(serverTestServices, m_requestHeader,
                                                                testSet, out var subscriptionIds);

                RequestHeader resendDataRequestHeader   = m_server.CreateAndActivateSession("ResendData");
                var           resendDataSecurityContext = SecureChannelContext.Current;

                // After the ResendData call there will be data to publish again
                MethodState methodStateInstance = (MethodState)m_server.CurrentInstance.
                                                  DiagnosticsNodeManager.FindPredefinedNode(MethodIds.Server_ResendData, typeof(MethodState));
                var nodesToCall = new CallMethodRequestCollection();
                nodesToCall.Add(new CallMethodRequest()
                {
                    ObjectId       = ObjectIds.Server,
                    MethodId       = MethodIds.Server_ResendData,
                    InputArguments = new VariantCollection()
                    {
                        new Variant(subscriptionIds.Last())
                    }
                });

                //call ResendData method from the same session context
                m_requestHeader.Timestamp = DateTime.UtcNow;
                var response = m_server.Call(m_requestHeader,
                                             nodesToCall,
                                             out var results,
                                             out var diagnosticInfos);

                Assert.IsTrue(StatusCode.IsGood(results[0].StatusCode));
                ServerFixtureUtils.ValidateResponse(response);

                Thread.Sleep(1000);

                // Make sure publish queue becomes empty by consuming it
                Assert.AreEqual(1, subscriptionIds.Count);
                // Issue a Publish request
                m_requestHeader.Timestamp = DateTime.UtcNow;
                var acknoledgements = new SubscriptionAcknowledgementCollection();
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out uint publishedId, out UInt32Collection availableSequenceNumbers,
                                                      out bool moreNotifications, out NotificationMessage notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(1, notificationMessage.NotificationData.Count);

                // Validate nothing to publish a few times
                const int timesToCallPublish = 3;
                for (int i = 0; i < timesToCallPublish; i++)
                {
                    m_requestHeader.Timestamp = DateTime.UtcNow;
                    response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                          out publishedId, out availableSequenceNumbers,
                                                          out moreNotifications, out notificationMessage,
                                                          out StatusCodeCollection _, out diagnosticInfos);

                    Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                    ServerFixtureUtils.ValidateResponse(response);
                    ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                    Assert.AreEqual(subscriptionIds[0], publishedId);
                    Assert.AreEqual(0, notificationMessage.NotificationData.Count);
                }

                // Validate ResendData method call from same and different session contexts

                // call ResendData method from different session context
                resendDataRequestHeader.Timestamp = DateTime.UtcNow;
                response = m_server.Call(resendDataRequestHeader,
                                         nodesToCall,
                                         out results,
                                         out diagnosticInfos);

                Assert.AreEqual(StatusCodes.BadUserAccessDenied, results[0].StatusCode.Code);
                ServerFixtureUtils.ValidateResponse(response);

                // Still nothing to publish since previous ResendData call did not execute
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(0, notificationMessage.NotificationData.Count);

                //call ResendData method from the same session context
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = m_server.Call(m_requestHeader,
                                         nodesToCall,
                                         out results,
                                         out diagnosticInfos);

                Assert.IsTrue(StatusCode.IsGood(results[0].StatusCode));
                ServerFixtureUtils.ValidateResponse(response);

                // Data should be available for publishing now
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(1, notificationMessage.NotificationData.Count);

                // Call ResendData method with invalid subscription Id
                nodesToCall = new CallMethodRequestCollection();
                nodesToCall.Add(new CallMethodRequest()
                {
                    ObjectId       = ObjectIds.Server,
                    MethodId       = MethodIds.Server_ResendData,
                    InputArguments = new VariantCollection()
                    {
                        new Variant(subscriptionIds.Last() + 20)
                    }
                });
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = m_server.Call(m_requestHeader,
                                         nodesToCall,
                                         out results,
                                         out diagnosticInfos);

                Assert.AreEqual(StatusCodes.BadSubscriptionIdInvalid, results[0].StatusCode.Code);
                ServerFixtureUtils.ValidateResponse(response);

                // Nothing to publish since previous ResendData call did not execute
                m_requestHeader.Timestamp = DateTime.UtcNow;
                response = serverTestServices.Publish(m_requestHeader, acknoledgements,
                                                      out publishedId, out availableSequenceNumbers,
                                                      out moreNotifications, out notificationMessage,
                                                      out StatusCodeCollection _, out diagnosticInfos);

                Assert.AreEqual(StatusCodes.Good, response.ServiceResult.Code);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(subscriptionIds[0], publishedId);
                Assert.AreEqual(0, notificationMessage.NotificationData.Count);

                resendDataRequestHeader.Timestamp = DateTime.UtcNow;
                SecureChannelContext.Current      = resendDataSecurityContext;
                m_server.CloseSession(resendDataRequestHeader);
            }
            finally
            {
                //restore security context, that close connection can work
                SecureChannelContext.Current = securityContext;
            }
        }
Example #16
0
        public void GetOperationLimits()
        {
            var readIdCollection = new ReadValueIdCollection()
            {
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerRead
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryReadData
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryReadEvents
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerWrite
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryUpdateData
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerHistoryUpdateEvents
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerBrowse
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxMonitoredItemsPerCall
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerNodeManagement
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerRegisterNodes
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerTranslateBrowsePathsToNodeIds
                },
                new ReadValueId()
                {
                    AttributeId = Attributes.Value, NodeId = VariableIds.Server_ServerCapabilities_OperationLimits_MaxNodesPerMethodCall
                }
            };

            var requestHeader = m_requestHeader;

            requestHeader.Timestamp = DateTime.UtcNow;
            var response = m_server.Read(requestHeader, MaxAge, TimestampsToReturn.Neither, readIdCollection, out var results, out var diagnosticInfos);

            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, results);

            Assert.NotNull(results);
            Assert.AreEqual(readIdCollection.Count, results.Count);

            m_operationLimits = new OperationLimits()
            {
                MaxNodesPerRead                          = (uint)results[0].Value,
                MaxNodesPerHistoryReadData               = (uint)results[1].Value,
                MaxNodesPerHistoryReadEvents             = (uint)results[2].Value,
                MaxNodesPerWrite                         = (uint)results[3].Value,
                MaxNodesPerHistoryUpdateData             = (uint)results[4].Value,
                MaxNodesPerHistoryUpdateEvents           = (uint)results[5].Value,
                MaxNodesPerBrowse                        = (uint)results[6].Value,
                MaxMonitoredItemsPerCall                 = (uint)results[7].Value,
                MaxNodesPerNodeManagement                = (uint)results[8].Value,
                MaxNodesPerRegisterNodes                 = (uint)results[9].Value,
                MaxNodesPerTranslateBrowsePathsToNodeIds = (uint)results[10].Value,
                MaxNodesPerMethodCall                    = (uint)results[11].Value
            };
        }
        /// <summary>
        /// Worker method to test subscriptions of a server.
        /// </summary>
        /// <param name="services"></param>
        /// <param name="requestHeader"></param>
        public static void SubscriptionTest(
            IServerTestServices services,
            RequestHeader requestHeader)
        {
            // start time
            requestHeader.Timestamp = DateTime.UtcNow;

            // create subscription
            double publishingInterval        = 1000.0;
            uint   lifetimeCount             = 60;
            uint   maxKeepAliveCount         = 2;
            uint   maxNotificationPerPublish = 0;
            byte   priority  = 128;
            bool   enabled   = false;
            uint   queueSize = 5;

            var response = services.CreateSubscription(requestHeader,
                                                       publishingInterval, lifetimeCount, maxKeepAliveCount,
                                                       maxNotificationPerPublish, enabled, priority,
                                                       out uint id, out double revisedPublishingInterval, out uint revisedLifetimeCount, out uint revisedMaxKeepAliveCount);

            Assert.AreEqual(publishingInterval, revisedPublishingInterval);
            Assert.AreEqual(lifetimeCount, revisedLifetimeCount);
            Assert.AreEqual(maxKeepAliveCount, revisedMaxKeepAliveCount);
            ServerFixtureUtils.ValidateResponse(response);

            MonitoredItemCreateRequestCollection itemsToCreate = new MonitoredItemCreateRequestCollection();
            // check badnothingtodo
            var sre = Assert.Throws <ServiceResultException>(() =>
                                                             services.CreateMonitoredItems(requestHeader, id, TimestampsToReturn.Neither, itemsToCreate,
                                                                                           out MonitoredItemCreateResultCollection mockResults, out DiagnosticInfoCollection mockInfos));

            Assert.AreEqual(StatusCodes.BadNothingToDo, sre.StatusCode);

            // add item
            uint handleCounter = 1;

            itemsToCreate.Add(new MonitoredItemCreateRequest()
            {
                ItemToMonitor = new ReadValueId()
                {
                    AttributeId = Attributes.Value,
                    NodeId      = VariableIds.Server_ServerStatus_CurrentTime
                },
                MonitoringMode      = MonitoringMode.Reporting,
                RequestedParameters = new MonitoringParameters()
                {
                    ClientHandle     = ++handleCounter,
                    SamplingInterval = -1,
                    Filter           = null,
                    DiscardOldest    = true,
                    QueueSize        = queueSize
                }
            });
            response = services.CreateMonitoredItems(requestHeader, id, TimestampsToReturn.Neither, itemsToCreate,
                                                     out MonitoredItemCreateResultCollection itemCreateResults, out DiagnosticInfoCollection diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, itemsToCreate);

            // modify subscription
            response = services.ModifySubscription(requestHeader, id,
                                                   publishingInterval, lifetimeCount, maxKeepAliveCount,
                                                   maxNotificationPerPublish, priority,
                                                   out revisedPublishingInterval, out revisedLifetimeCount, out revisedMaxKeepAliveCount);
            Assert.AreEqual(publishingInterval, revisedPublishingInterval);
            Assert.AreEqual(lifetimeCount, revisedLifetimeCount);
            Assert.AreEqual(maxKeepAliveCount, revisedMaxKeepAliveCount);
            ServerFixtureUtils.ValidateResponse(response);

            // modify monitored item, just timestamps to return
            var itemsToModify = new MonitoredItemModifyRequestCollection();

            foreach (var itemCreated in itemCreateResults)
            {
                itemsToModify.Add(
                    new MonitoredItemModifyRequest()
                {
                    MonitoredItemId = itemCreated.MonitoredItemId
                });
            }
            ;
            response = services.ModifyMonitoredItems(requestHeader, id, TimestampsToReturn.Both, itemsToModify,
                                                     out MonitoredItemModifyResultCollection modifyResults, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, itemsToModify);

            // publish request
            var acknoledgements = new SubscriptionAcknowledgementCollection();

            response = services.Publish(requestHeader, acknoledgements,
                                        out uint subscriptionId, out UInt32Collection availableSequenceNumbers,
                                        out bool moreNotifications, out NotificationMessage notificationMessage,
                                        out StatusCodeCollection statuses, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
            Assert.AreEqual(id, subscriptionId);
            Assert.AreEqual(0, availableSequenceNumbers.Count);

            // enable publishing
            enabled = true;
            var subscriptions = new UInt32Collection()
            {
                id
            };

            response = services.SetPublishingMode(requestHeader, enabled, subscriptions,
                                                  out statuses, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptions);

            // wait some time to fill queue
            int loopCounter = (int)queueSize;

            Thread.Sleep(loopCounter * 1000);

            acknoledgements = new SubscriptionAcknowledgementCollection();
            do
            {
                // get publish responses
                response = services.Publish(requestHeader, acknoledgements,
                                            out subscriptionId, out availableSequenceNumbers,
                                            out moreNotifications, out notificationMessage,
                                            out statuses, out diagnosticInfos);
                ServerFixtureUtils.ValidateResponse(response);
                ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, acknoledgements);
                Assert.AreEqual(id, subscriptionId);

                var dataChangeNotification = notificationMessage.NotificationData[0].Body as DataChangeNotification;
                TestContext.Out.WriteLine("Notification: {0} {1} {2}",
                                          notificationMessage.SequenceNumber,
                                          dataChangeNotification?.MonitoredItems[0].Value.ToString(),
                                          notificationMessage.PublishTime);

                acknoledgements.Clear();
                acknoledgements.Add(new SubscriptionAcknowledgement()
                {
                    SubscriptionId = id,
                    SequenceNumber = notificationMessage.SequenceNumber
                });
            } while (acknoledgements.Count > 0 && --loopCounter > 0);

            // republish
            response = services.Republish(requestHeader, subscriptionId, notificationMessage.SequenceNumber, out notificationMessage);
            ServerFixtureUtils.ValidateResponse(response);

            // disable publishing
            enabled  = false;
            response = services.SetPublishingMode(requestHeader, enabled, subscriptions,
                                                  out statuses, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptions);

            // delete subscription
            response = services.DeleteSubscriptions(requestHeader, subscriptions, out statuses, out diagnosticInfos);
            ServerFixtureUtils.ValidateResponse(response);
            ServerFixtureUtils.ValidateDiagnosticInfos(diagnosticInfos, subscriptions);
        }