From 553a869d4fd8829dd8a4feeb596c2acd19b077c7 Mon Sep 17 00:00:00 2001 From: Suciu Mircea Adrian Date: Thu, 11 Apr 2024 09:23:32 +0300 Subject: [PATCH] Added KeyFrameCount and DeltaFrame tests (#2579) Added tests which include PubSub KeyFrameCount and DeltaFrames. --- .../Encoding/MessagesHelper.cs | 1139 ++++++++++------- .../WriterGroupPublishedStateTests.cs | 296 +++++ .../Transport/MqttPubSubConnectionTests.cs | 341 ++++- 3 files changed, 1290 insertions(+), 486 deletions(-) create mode 100644 Tests/Opc.Ua.PubSub.Tests/PublishedData/WriterGroupPublishedStateTests.cs diff --git a/Tests/Opc.Ua.PubSub.Tests/Encoding/MessagesHelper.cs b/Tests/Opc.Ua.PubSub.Tests/Encoding/MessagesHelper.cs index bf11e5fdc9..db823bfba8 100644 --- a/Tests/Opc.Ua.PubSub.Tests/Encoding/MessagesHelper.cs +++ b/Tests/Opc.Ua.PubSub.Tests/Encoding/MessagesHelper.cs @@ -28,11 +28,13 @@ * ======================================================================*/ using System; -using System.Collections.Generic; -using System.ComponentModel; using System.Linq; +using System.Collections.Generic; using System.Xml; using Opc.Ua.PubSub.Encoding; +using System.ComponentModel; +using System.Threading; +using Opc.Ua.PubSub.PublishedData; namespace Opc.Ua.PubSub.Tests.Encoding { @@ -179,7 +181,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding UInt32 dataSetMessageContentMask, DataSetFieldContentMask dataSetFieldContentMask, DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData, - double metaDataUpdateTime = 0) + double metaDataUpdateTime = 0, uint keyFrameCount = 1) { // Define a PubSub connection with PublisherId @@ -242,7 +244,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding dataSetWriter.Enabled = true; dataSetWriter.DataSetFieldContentMask = (uint)dataSetFieldContentMask; dataSetWriter.DataSetName = dataSetMetaData.Name; - dataSetWriter.KeyFrameCount = 1; + dataSetWriter.KeyFrameCount = keyFrameCount; DataSetWriterMessageDataType dataSetWriterMessage = null; switch (transportProfileUri) @@ -341,7 +343,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding JsonDataSetMessageContentMask jsonDataSetMessageContentMask, DataSetFieldContentMask dataSetFieldContentMask, DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData, - double metaDataUpdateTime = 0) + double metaDataUpdateTime = 0, uint keyFrameCount = 1) { return CreatePublisherConfiguration( transportProfileUri, addressUrl, @@ -349,7 +351,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding (UInt32)jsonNetworkMessageContentMask, (UInt32)jsonDataSetMessageContentMask, dataSetFieldContentMask, - dataSetMetaDataArray, nameSpaceIndexForData, metaDataUpdateTime); + dataSetMetaDataArray, nameSpaceIndexForData, metaDataUpdateTime, keyFrameCount); } /// @@ -375,7 +377,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding UadpNetworkMessageContentMask uadpNetworkMessageContentMask, UadpDataSetMessageContentMask uadpDataSetMessageContentMask, DataSetFieldContentMask dataSetFieldContentMask, - DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData) + DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData, uint keyFrameCount = 1) { PubSubConfigurationDataType udpPublisherConfiguration = MessagesHelper.CreatePublisherConfiguration( udpTransportProfileUri, @@ -383,7 +385,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding uadpNetworkMessageContentMask: uadpNetworkMessageContentMask, uadpDataSetMessageContentMask: uadpDataSetMessageContentMask, dataSetFieldContentMask: dataSetFieldContentMask, - dataSetMetaDataArray: dataSetMetaDataArray, nameSpaceIndexForData: nameSpaceIndexForData); + dataSetMetaDataArray: dataSetMetaDataArray, nameSpaceIndexForData: nameSpaceIndexForData, keyFrameCount: keyFrameCount); PubSubConfigurationDataType mqttPublisherConfiguration = MessagesHelper.CreatePublisherConfiguration( mqttTransportProfileUri, @@ -391,13 +393,13 @@ namespace Opc.Ua.PubSub.Tests.Encoding uadpNetworkMessageContentMask: uadpNetworkMessageContentMask, uadpDataSetMessageContentMask: uadpDataSetMessageContentMask, dataSetFieldContentMask: dataSetFieldContentMask, - dataSetMetaDataArray: dataSetMetaDataArray, nameSpaceIndexForData: nameSpaceIndexForData); + dataSetMetaDataArray: dataSetMetaDataArray, nameSpaceIndexForData: nameSpaceIndexForData, keyFrameCount: keyFrameCount); // add the udp connection too if (udpPublisherConfiguration.Connections != null && udpPublisherConfiguration.Connections.Count > 0) { - mqttPublisherConfiguration.Connections.Add(udpPublisherConfiguration.Connections[0]); + mqttPublisherConfiguration.Connections.Add(udpPublisherConfiguration.Connections.First()); } return mqttPublisherConfiguration; @@ -436,7 +438,9 @@ namespace Opc.Ua.PubSub.Tests.Encoding { foreach (var writerGroup in pubSubConnection.WriterGroups) { - if (ExtensionObject.ToEncodeable(writerGroup.TransportSettings) is BrokerWriterGroupTransportDataType brokerTransportSettings) + BrokerWriterGroupTransportDataType brokerTransportSettings = ExtensionObject.ToEncodeable(writerGroup.TransportSettings) + as BrokerWriterGroupTransportDataType; + if (brokerTransportSettings != null) { brokerTransportSettings.QueueName = topic; } @@ -466,7 +470,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding UadpDataSetMessageContentMask uadpDataSetMessageContentMask, DataSetFieldContentMask dataSetFieldContentMask, DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData, - double metaDataUpdateTime = 0) + double metaDataUpdateTime = 0, uint keyFrameCount = 1) { return CreatePublisherConfiguration( transportProfileUri, addressUrl, @@ -474,7 +478,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding (UInt32)uadpNetworkMessageContentMask, (UInt32)uadpDataSetMessageContentMask, dataSetFieldContentMask, - dataSetMetaDataArray, nameSpaceIndexForData, metaDataUpdateTime); + dataSetMetaDataArray, nameSpaceIndexForData, metaDataUpdateTime, keyFrameCount); } /// @@ -496,7 +500,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding DataSetFieldContentMask dataSetFieldContentMask, DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData, - double metaDataUpdateTime = 0) + double metaDataUpdateTime = 0, uint keyFrameCount = 1) { string writerGroupName = $"WriterGroup {writerGroupId}"; string brokerMetaData = "$Metadata"; @@ -548,7 +552,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding dataSetWriter.Enabled = true; dataSetWriter.DataSetFieldContentMask = (uint)dataSetFieldContentMask; dataSetWriter.DataSetName = dataSetMetaData.Name; - dataSetWriter.KeyFrameCount = 1; + dataSetWriter.KeyFrameCount = keyFrameCount; DataSetWriterMessageDataType dataSetWriterMessage = null; switch (transportProfileUri) @@ -694,7 +698,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding public static DataSetWriterDataType CreateDataSetWriter(ushort dataSetWriterId, string dataSetName, DataSetFieldContentMask dataSetFieldContentMask, - DataSetWriterMessageDataType messageSettings) + DataSetWriterMessageDataType messageSettings, uint keyFrameCount = 1) { // Define DataSetWriter 'dataSetName' DataSetWriterDataType dataSetWriter = new DataSetWriterDataType(); @@ -703,7 +707,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding dataSetWriter.Enabled = true; dataSetWriter.DataSetFieldContentMask = (uint)dataSetFieldContentMask; dataSetWriter.DataSetName = dataSetName; - dataSetWriter.KeyFrameCount = 1; + dataSetWriter.KeyFrameCount = keyFrameCount; dataSetWriter.MessageSettings = new ExtensionObject(messageSettings); @@ -733,7 +737,8 @@ namespace Opc.Ua.PubSub.Tests.Encoding foreach (var field in publishedDataSet.DataSetMetaData.Fields) { publishedDataSetSimpleSource.PublishedData.Add( - new PublishedVariableDataType() { + new PublishedVariableDataType() + { PublishedVariable = new NodeId(field.Name, namespaceIndex), AttributeId = Attributes.Value, }); @@ -798,19 +803,18 @@ namespace Opc.Ua.PubSub.Tests.Encoding DataSetMetaDataType dataSetMetaData, DataSetFieldContentMask dataSetFieldContentMask, DataSetReaderMessageDataType messageSettings, - DataSetReaderTransportDataType transportSettings) + DataSetReaderTransportDataType transportSettings, uint keyFrameCount = 1) { // Define DataSetReader 'dataSetName' DataSetReaderDataType dataSetReader = new DataSetReaderDataType(); dataSetReader.Name = $"Reader {writerGroupId}{dataSetWriterId}"; dataSetReader.PublisherId = publisherId; dataSetReader.WriterGroupId = writerGroupId; - //dataSetReader.DataSetWriterId = 0; dataSetReader.DataSetWriterId = dataSetWriterId; dataSetReader.Enabled = true; dataSetReader.DataSetFieldContentMask = (uint)dataSetFieldContentMask; //dataSetReader.DataSetName = dataSetName; - dataSetReader.KeyFrameCount = 1; + dataSetReader.KeyFrameCount = keyFrameCount; dataSetReader.DataSetMetaData = dataSetMetaData; dataSetReader.MessageSettings = new ExtensionObject(messageSettings); @@ -839,7 +843,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding JsonNetworkMessageContentMask jsonNetworkMessageContentMask, JsonDataSetMessageContentMask jsonDataSetMessageContentMask, DataSetFieldContentMask dataSetFieldContentMask, - DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData) + DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData, uint keyFrameCount = 1) { return CreateSubscriberConfiguration( transportProfileUri, addressUrl, @@ -847,7 +851,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding (UInt32)jsonNetworkMessageContentMask, (UInt32)jsonDataSetMessageContentMask, dataSetFieldContentMask, - dataSetMetaDataArray, nameSpaceIndexForData); + dataSetMetaDataArray, nameSpaceIndexForData, keyFrameCount); } /// @@ -870,7 +874,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding UInt32 networkMessageContentMask, UInt32 dataSetMessageContentMask, DataSetFieldContentMask dataSetFieldContentMask, - DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData) + DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData, uint keyFrameCount = 1) { // Define a PubSub connection with PublisherId PubSubConnectionDataType pubSubConnection1 = CreatePubSubConnection(transportProfileUri, addressUrl, publisherId, PubSubType.Subscriber); @@ -904,7 +908,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding } dataSetReader.Enabled = true; dataSetReader.DataSetFieldContentMask = (uint)dataSetFieldContentMask; - dataSetReader.KeyFrameCount = 1; + dataSetReader.KeyFrameCount = keyFrameCount; dataSetReader.DataSetMetaData = dataSetMetaData; DataSetReaderMessageDataType dataSetReaderMessageSettings = null; @@ -925,6 +929,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding }; dataSetReaderTransportSettings = new BrokerDataSetReaderTransportDataType() { QueueName = brokerQueueName, + MetaDataQueueName = $"{brokerQueueName}/{brokerMetaData}", }; break; case Profiles.PubSubMqttJsonTransport: @@ -993,7 +998,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding UadpNetworkMessageContentMask uadpNetworkMessageContentMask, UadpDataSetMessageContentMask uadpDataSetMessageContentMask, DataSetFieldContentMask dataSetFieldContentMask, - DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData) + DataSetMetaDataType[] dataSetMetaDataArray, ushort nameSpaceIndexForData, uint keyFrameCount = 1) { return CreateSubscriberConfiguration( transportProfileUri, addressUrl, @@ -1001,7 +1006,7 @@ namespace Opc.Ua.PubSub.Tests.Encoding (UInt32)uadpNetworkMessageContentMask, (UInt32)uadpDataSetMessageContentMask, dataSetFieldContentMask, - dataSetMetaDataArray, nameSpaceIndexForData); + dataSetMetaDataArray, nameSpaceIndexForData, keyFrameCount); } /// @@ -1094,7 +1099,9 @@ namespace Opc.Ua.PubSub.Tests.Encoding { foreach (var dataSetReader in readerGroup.DataSetReaders) { - if (ExtensionObject.ToEncodeable(dataSetReader.TransportSettings) is BrokerDataSetReaderTransportDataType brokerTransportSettings) + BrokerDataSetReaderTransportDataType brokerTransportSettings = ExtensionObject.ToEncodeable(dataSetReader.TransportSettings) + as BrokerDataSetReaderTransportDataType; + if (brokerTransportSettings != null) { brokerTransportSettings.QueueName = topic; } @@ -1120,7 +1127,8 @@ namespace Opc.Ua.PubSub.Tests.Encoding metaData.DataSetClassId = Uuid.Empty; metaData.Name = dataSetName; metaData.Fields = fieldMetaDatas; - metaData.ConfigurationVersion = new ConfigurationVersionDataType() { + metaData.ConfigurationVersion = new ConfigurationVersionDataType() + { MajorVersion = majorVersion, MinorVersion = minorVersion, }; @@ -1133,6 +1141,25 @@ namespace Opc.Ua.PubSub.Tests.Encoding #region Get UaDataNetwork type messages + /// + /// Get Uadp | Json type entry + /// + /// + /// + /// + public static List GetUaDataNetworkMessages(IList networkMessages) where T : UaNetworkMessage + { + if(typeof(T) == typeof(UadpNetworkMessage)) + { + return GetUadpUaDataNetworkMessages(networkMessages.Cast().ToList()) as List; + } + if (typeof(T) == typeof(JsonNetworkMessage)) + { + return GetJsonUaDataNetworkMessages(networkMessages.Cast().ToList()) as List; + } + return null; + } + /// /// Get Json ua-data entry /// @@ -1147,6 +1174,20 @@ namespace Opc.Ua.PubSub.Tests.Encoding return null; } + /// + /// Get Uadp DatasetMessage type entry + /// + /// + /// + public static List GetUadpUaDataNetworkMessages(IList networkMessages) + { + if (networkMessages != null) + { + return networkMessages.Where(x => x.UADPNetworkMessageType == UADPNetworkMessageType.DataSetMessage).ToList(); + } + return null; + } + /// /// Get Json ua-metadata entries /// @@ -1191,185 +1232,186 @@ namespace Opc.Ua.PubSub.Tests.Encoding dataSetMetaData.DataSetClassId = new Uuid(Guid.NewGuid()); dataSetMetaData.Name = dataSetName; dataSetMetaData.Fields = new FieldMetaDataCollection() + { + new FieldMetaData() { - new FieldMetaData() - { - Name = "BoolToggleMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Boolean, - DataType = DataTypeIds.Boolean, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "SByteMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.SByte, - DataType = DataTypeIds.SByte, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "ByteMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Byte, - DataType = DataTypeIds.Byte, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "Int16Matrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Int16, - DataType = DataTypeIds.Int16, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "UInt16Matrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.UInt16, - DataType = DataTypeIds.UInt16, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "Int32Matrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Int32, - DataType = DataTypeIds.Int32, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "UInt32Matrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.UInt32, - DataType = DataTypeIds.UInt32, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "Int64Matrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Int64, - DataType = DataTypeIds.UInt64, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "UInt64Matrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.UInt64, - DataType = DataTypeIds.UInt64, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "FloatMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Float, - DataType = DataTypeIds.Float, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "DoubleMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Double, - DataType = DataTypeIds.Double, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "StringMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.String, - DataType = DataTypeIds.String, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "DateTimeMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.DateTime, - DataType = DataTypeIds.DateTime, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "GuidMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Guid, - DataType = DataTypeIds.Guid, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "ByteStringMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.ByteString, - DataType = DataTypeIds.ByteString, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "XmlElementMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.XmlElement, - DataType = DataTypeIds.XmlElement, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "NodeIdMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.NodeId, - DataType = DataTypeIds.NodeId, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "ExpandedNodeIdMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.ExpandedNodeId, - DataType = DataTypeIds.ExpandedNodeId, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "StatusCodeMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.StatusCode, - DataType = DataTypeIds.StatusCode, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "QualifiedNameMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.QualifiedName, - DataType = DataTypeIds.QualifiedName, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "LocalizedTextMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.LocalizedText, - DataType = DataTypeIds.LocalizedText, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "DiagnosticInfoMatrix", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.DiagnosticInfo, - DataType = DataTypeIds.DiagnosticInfo, - ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null - }, - }; - dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() { + Name = "BoolToggleMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Boolean, + DataType = DataTypeIds.Boolean, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "SByteMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.SByte, + DataType = DataTypeIds.SByte, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "ByteMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Byte, + DataType = DataTypeIds.Byte, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "Int16Matrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Int16, + DataType = DataTypeIds.Int16, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "UInt16Matrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.UInt16, + DataType = DataTypeIds.UInt16, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "Int32Matrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Int32, + DataType = DataTypeIds.Int32, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "UInt32Matrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.UInt32, + DataType = DataTypeIds.UInt32, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "Int64Matrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Int64, + DataType = DataTypeIds.UInt64, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "UInt64Matrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.UInt64, + DataType = DataTypeIds.UInt64, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "FloatMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Float, + DataType = DataTypeIds.Float, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "DoubleMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Double, + DataType = DataTypeIds.Double, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "StringMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.String, + DataType = DataTypeIds.String, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "DateTimeMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.DateTime, + DataType = DataTypeIds.DateTime, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "GuidMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Guid, + DataType = DataTypeIds.Guid, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "ByteStringMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.ByteString, + DataType = DataTypeIds.ByteString, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "XmlElementMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.XmlElement, + DataType = DataTypeIds.XmlElement, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "NodeIdMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.NodeId, + DataType = DataTypeIds.NodeId, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "ExpandedNodeIdMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.ExpandedNodeId, + DataType = DataTypeIds.ExpandedNodeId, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "StatusCodeMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.StatusCode, + DataType = DataTypeIds.StatusCode, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "QualifiedNameMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.QualifiedName, + DataType = DataTypeIds.QualifiedName, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "LocalizedTextMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.LocalizedText, + DataType = DataTypeIds.LocalizedText, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "DiagnosticInfoMatrix", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.DiagnosticInfo, + DataType = DataTypeIds.DiagnosticInfo, + ValueRank = ValueRanks.TwoDimensions, Description = LocalizedText.Null + }, + }; + dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() + { MinorVersion = 1, MajorVersion = 1 }; @@ -1389,185 +1431,186 @@ namespace Opc.Ua.PubSub.Tests.Encoding dataSetMetaData.DataSetClassId = new Uuid(Guid.NewGuid()); dataSetMetaData.Name = dataSetName; dataSetMetaData.Fields = new FieldMetaDataCollection() + { + new FieldMetaData() { - new FieldMetaData() - { - Name = "BoolToggleArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Boolean, - DataType = DataTypeIds.Boolean, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "SByteArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.SByte, - DataType = DataTypeIds.SByte, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "ByteArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Byte, - DataType = DataTypeIds.Byte, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "Int16Array", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Int16, - DataType = DataTypeIds.Int16, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "UInt16Array", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.UInt16, - DataType = DataTypeIds.UInt16, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "Int32Array", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Int32, - DataType = DataTypeIds.Int32, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "UInt32Array", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.UInt32, - DataType = DataTypeIds.UInt32, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "Int64Array", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Int64, - DataType = DataTypeIds.UInt64, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "UInt64Array", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.UInt64, - DataType = DataTypeIds.UInt64, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "FloatArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Float, - DataType = DataTypeIds.Float, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "DoubleArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Double, - DataType = DataTypeIds.Double, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "StringArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.String, - DataType = DataTypeIds.String, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "DateTimeArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.DateTime, - DataType = DataTypeIds.DateTime, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "GuidArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Guid, - DataType = DataTypeIds.Guid, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "ByteStringArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.ByteString, - DataType = DataTypeIds.ByteString, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "XmlElementArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.XmlElement, - DataType = DataTypeIds.XmlElement, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "NodeIdArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.NodeId, - DataType = DataTypeIds.NodeId, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "ExpandedNodeIdArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.ExpandedNodeId, - DataType = DataTypeIds.ExpandedNodeId, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "StatusCodeArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.StatusCode, - DataType = DataTypeIds.StatusCode, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "QualifiedNameArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.QualifiedName, - DataType = DataTypeIds.QualifiedName, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "LocalizedTextArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.LocalizedText, - DataType = DataTypeIds.LocalizedText, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "DiagnosticInfoArray", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.DiagnosticInfo, - DataType = DataTypeIds.DiagnosticInfo, - ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null - }, - }; - dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() { + Name = "BoolToggleArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Boolean, + DataType = DataTypeIds.Boolean, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "SByteArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.SByte, + DataType = DataTypeIds.SByte, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "ByteArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Byte, + DataType = DataTypeIds.Byte, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "Int16Array", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Int16, + DataType = DataTypeIds.Int16, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "UInt16Array", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.UInt16, + DataType = DataTypeIds.UInt16, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "Int32Array", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Int32, + DataType = DataTypeIds.Int32, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "UInt32Array", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.UInt32, + DataType = DataTypeIds.UInt32, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "Int64Array", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Int64, + DataType = DataTypeIds.UInt64, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "UInt64Array", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.UInt64, + DataType = DataTypeIds.UInt64, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "FloatArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Float, + DataType = DataTypeIds.Float, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "DoubleArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Double, + DataType = DataTypeIds.Double, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "StringArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.String, + DataType = DataTypeIds.String, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "DateTimeArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.DateTime, + DataType = DataTypeIds.DateTime, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "GuidArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Guid, + DataType = DataTypeIds.Guid, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "ByteStringArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.ByteString, + DataType = DataTypeIds.ByteString, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "XmlElementArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.XmlElement, + DataType = DataTypeIds.XmlElement, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "NodeIdArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.NodeId, + DataType = DataTypeIds.NodeId, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "ExpandedNodeIdArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.ExpandedNodeId, + DataType = DataTypeIds.ExpandedNodeId, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "StatusCodeArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.StatusCode, + DataType = DataTypeIds.StatusCode, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "QualifiedNameArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.QualifiedName, + DataType = DataTypeIds.QualifiedName, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "LocalizedTextArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.LocalizedText, + DataType = DataTypeIds.LocalizedText, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "DiagnosticInfoArray", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.DiagnosticInfo, + DataType = DataTypeIds.DiagnosticInfo, + ValueRank = ValueRanks.OneDimension, Description = LocalizedText.Null + }, + }; + dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() + { MinorVersion = 1, MajorVersion = 1 }; @@ -1587,36 +1630,37 @@ namespace Opc.Ua.PubSub.Tests.Encoding dataSetMetaData.DataSetClassId = new Uuid(Guid.NewGuid()); dataSetMetaData.Name = dataSetName; dataSetMetaData.Fields = new FieldMetaDataCollection() + { + new FieldMetaData() { - new FieldMetaData() - { - Name = "BoolToggle", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Boolean, - DataType = DataTypeIds.Boolean, - ValueRank = ValueRanks.Scalar, - Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "Byte", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Byte, - DataType = DataTypeIds.Byte, - ValueRank = ValueRanks.Scalar, - Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "SByte", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.SByte, - DataType = DataTypeIds.SByte, - ValueRank = ValueRanks.Scalar, - Description = LocalizedText.Null - }, - }; - dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() { + Name = "BoolToggle", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Boolean, + DataType = DataTypeIds.Boolean, + ValueRank = ValueRanks.Scalar, + Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "Byte", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Byte, + DataType = DataTypeIds.Byte, + ValueRank = ValueRanks.Scalar, + Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "SByte", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.SByte, + DataType = DataTypeIds.SByte, + ValueRank = ValueRanks.Scalar, + Description = LocalizedText.Null + }, + }; + dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() + { MinorVersion = 1, MajorVersion = 1 }; @@ -1636,36 +1680,37 @@ namespace Opc.Ua.PubSub.Tests.Encoding dataSetMetaData.DataSetClassId = new Uuid(Guid.NewGuid()); dataSetMetaData.Name = dataSetName; dataSetMetaData.Fields = new FieldMetaDataCollection() + { + new FieldMetaData() { - new FieldMetaData() - { - Name = "UInt16", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.UInt16, - DataType = DataTypeIds.UInt16, - ValueRank = ValueRanks.Scalar, - Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "UInt32", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.UInt32, - DataType = DataTypeIds.UInt32, - ValueRank = ValueRanks.Scalar, - Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "UInt64", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.UInt64, - DataType = DataTypeIds.UInt64, - ValueRank = ValueRanks.Scalar, - Description = LocalizedText.Null - } - }; - dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() { + Name = "UInt16", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.UInt16, + DataType = DataTypeIds.UInt16, + ValueRank = ValueRanks.Scalar, + Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "UInt32", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.UInt32, + DataType = DataTypeIds.UInt32, + ValueRank = ValueRanks.Scalar, + Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "UInt64", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.UInt64, + DataType = DataTypeIds.UInt64, + ValueRank = ValueRanks.Scalar, + Description = LocalizedText.Null + } + }; + dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() + { MinorVersion = 1, MajorVersion = 1 }; @@ -1685,36 +1730,37 @@ namespace Opc.Ua.PubSub.Tests.Encoding dataSetMetaData.DataSetClassId = new Uuid(Guid.NewGuid()); dataSetMetaData.Name = dataSetName; dataSetMetaData.Fields = new FieldMetaDataCollection() + { + new FieldMetaData() { - new FieldMetaData() - { - Name = "Int16", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Int16, - DataType = DataTypeIds.Int16, - ValueRank = ValueRanks.Scalar, - Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "Int32", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Int32, - DataType = DataTypeIds.Int32, - ValueRank = ValueRanks.Scalar, - Description = LocalizedText.Null - }, - new FieldMetaData() - { - Name = "Int64", - DataSetFieldId = new Uuid(Guid.NewGuid()), - BuiltInType = (byte)BuiltInType.Int64, - DataType = DataTypeIds.Int64, - ValueRank = ValueRanks.Scalar, - Description = LocalizedText.Null - } - }; - dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() { + Name = "Int16", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Int16, + DataType = DataTypeIds.Int16, + ValueRank = ValueRanks.Scalar, + Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "Int32", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Int32, + DataType = DataTypeIds.Int32, + ValueRank = ValueRanks.Scalar, + Description = LocalizedText.Null + }, + new FieldMetaData() + { + Name = "Int64", + DataSetFieldId = new Uuid(Guid.NewGuid()), + BuiltInType = (byte)BuiltInType.Int64, + DataType = DataTypeIds.Int64, + ValueRank = ValueRanks.Scalar, + Description = LocalizedText.Null + } + }; + dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() + { MinorVersion = 1, MajorVersion = 1 }; @@ -2487,7 +2533,8 @@ namespace Opc.Ua.PubSub.Tests.Encoding }, }; - dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() { + dataSetMetaData.ConfigurationVersion = new ConfigurationVersionDataType() + { MinorVersion = 1, MajorVersion = 1 }; @@ -2498,13 +2545,13 @@ namespace Opc.Ua.PubSub.Tests.Encoding #endregion Create datasets metadata /// - /// Load publishing data + /// Load initial publishing data /// /// public static void LoadData(UaPubSubApplication pubSubApplication, UInt16 namespaceIndexAllTypes) { - #region DataSet AllTypes - // DataSet 'AllTypes' fill with primitive data + #region DataSet data + // DataSet fill with primitive data DataValue boolToggle = new DataValue(new Variant(false)); pubSubApplication.DataStore.WritePublishedDataItem(new NodeId("BoolToggle", namespaceIndexAllTypes), Attributes.Value, boolToggle); DataValue byteValue = new DataValue(new Variant((byte)10)); @@ -2713,6 +2760,146 @@ namespace Opc.Ua.PubSub.Tests.Encoding #endregion } + /// + /// Get datastore data for specified datasets + /// + /// + /// + /// + /// + public static Dictionary GetDataStoreData(UaPubSubApplication pubSubApplication, UaNetworkMessage uaDataNetworkMessage, UInt16 namespaceIndexAllTypes) + { + Dictionary dataSetsData = new Dictionary(); + + foreach (UaDataSetMessage datasetMessage in uaDataNetworkMessage.DataSetMessages) + { + foreach (Field field in datasetMessage.DataSet.Fields) + { + NodeId fieldNodeId = new NodeId(field.FieldMetaData.Name, namespaceIndexAllTypes); + DataValue fieldDataValue = pubSubApplication.DataStore.ReadPublishedDataItem(fieldNodeId, Attributes.Value); + if (fieldDataValue != null) + { + if (!dataSetsData.ContainsKey(fieldNodeId)) + { + dataSetsData.Add(fieldNodeId, fieldDataValue); + } + } + } + } + + return dataSetsData; + } + + /// + /// Get snapshot data + /// + /// + /// + /// + public static Dictionary GetSnapshotData(UaPubSubApplication pubSubApplication, UInt16 namespaceIndexAllTypes) + { + Dictionary snapshotData = new Dictionary(); + + NodeId boolNodeId = new NodeId("BoolToggle", namespaceIndexAllTypes); + DataValue boolToggle = pubSubApplication.DataStore.ReadPublishedDataItem(boolNodeId, Attributes.Value); + snapshotData.Add(boolNodeId, (DataValue)boolToggle.MemberwiseClone()); + NodeId byteNodeId = new NodeId("Byte", namespaceIndexAllTypes); + DataValue byteValue = pubSubApplication.DataStore.ReadPublishedDataItem(byteNodeId, Attributes.Value); + snapshotData.Add(byteNodeId, (DataValue)byteValue.MemberwiseClone()); + NodeId int16NodeId = new NodeId("Int16", namespaceIndexAllTypes); + DataValue int16Value = pubSubApplication.DataStore.ReadPublishedDataItem(int16NodeId, Attributes.Value); + snapshotData.Add(int16NodeId,(DataValue)int16Value.MemberwiseClone()); + NodeId int32NodeId = new NodeId("Int32", namespaceIndexAllTypes); + DataValue int32Value = pubSubApplication.DataStore.ReadPublishedDataItem(int32NodeId, Attributes.Value); + snapshotData.Add(int32NodeId, (DataValue)int32Value.MemberwiseClone()); + NodeId uint16NodeId = new NodeId("UInt16", namespaceIndexAllTypes); + DataValue uInt16Value = pubSubApplication.DataStore.ReadPublishedDataItem(uint16NodeId, Attributes.Value); + snapshotData.Add(uint16NodeId, (DataValue)uInt16Value.MemberwiseClone()); + NodeId uint32NodeId = new NodeId("UInt32", namespaceIndexAllTypes); + DataValue uInt32Value = pubSubApplication.DataStore.ReadPublishedDataItem(uint32NodeId, Attributes.Value); + snapshotData.Add(uint32NodeId, (DataValue)uInt32Value.MemberwiseClone()); + NodeId doubleNodeId = new NodeId("Double", namespaceIndexAllTypes); + DataValue doubleValue = pubSubApplication.DataStore.ReadPublishedDataItem(doubleNodeId, Attributes.Value); + snapshotData.Add(doubleNodeId, (DataValue)doubleValue.MemberwiseClone()); + NodeId dateTimeNodeId = new NodeId("DateTime", namespaceIndexAllTypes); + DataValue dateTimeValue = pubSubApplication.DataStore.ReadPublishedDataItem(dateTimeNodeId, Attributes.Value); + snapshotData.Add(dateTimeNodeId,(DataValue)dateTimeValue.MemberwiseClone()); + + return snapshotData; + } + + /// + /// Update snapshot publishing data + /// + /// + /// + public static void UpdateSnapshotData(UaPubSubApplication pubSubApplication, UInt16 namespaceIndexAllTypes) + { + #region Update DataSet values + // DataSet update with primitive data + DataValue boolToggle = pubSubApplication.DataStore.ReadPublishedDataItem(new NodeId("BoolToggle", namespaceIndexAllTypes), Attributes.Value); + if (boolToggle.Value is bool) + { + bool boolVal = Convert.ToBoolean(boolToggle.Value); + boolToggle.Value = !boolVal; + pubSubApplication.DataStore.WritePublishedDataItem(new NodeId("BoolToggle", namespaceIndexAllTypes), Attributes.Value, boolToggle); + } + DataValue byteValue = pubSubApplication.DataStore.ReadPublishedDataItem(new NodeId("Byte", namespaceIndexAllTypes), Attributes.Value); + if (byteValue.Value is byte) + { + byte byteVal = Convert.ToByte(byteValue.Value); + byteValue.Value = ++byteVal; + pubSubApplication.DataStore.WritePublishedDataItem(new NodeId("Byte", namespaceIndexAllTypes), Attributes.Value, byteValue); + } + DataValue int16Value = pubSubApplication.DataStore.ReadPublishedDataItem(new NodeId("Int16", namespaceIndexAllTypes), Attributes.Value); + if (int16Value.Value is Int16) + { + Int16 int16Val = Convert.ToInt16(int16Value.Value); + int intIdentifier = int16Val; + Interlocked.CompareExchange(ref intIdentifier, 0, Int16.MaxValue); + int16Value.Value = (Int16)Interlocked.Increment(ref intIdentifier); + pubSubApplication.DataStore.WritePublishedDataItem(new NodeId("Int16", namespaceIndexAllTypes), Attributes.Value, int16Value); + } + DataValue int32Value = pubSubApplication.DataStore.ReadPublishedDataItem(new NodeId("Int32", namespaceIndexAllTypes), Attributes.Value); + if (int32Value.Value is Int32) + { + Int32 int32Val = Convert.ToInt32(int16Value.Value); + int intIdentifier = int32Val; + Interlocked.CompareExchange(ref intIdentifier, 0, Int32.MaxValue); + int32Value.Value = (Int32)Interlocked.Increment(ref intIdentifier); + pubSubApplication.DataStore.WritePublishedDataItem(new NodeId("Int32", namespaceIndexAllTypes), Attributes.Value, int32Value); + } + DataValue uInt16Value = pubSubApplication.DataStore.ReadPublishedDataItem(new NodeId("UInt16", namespaceIndexAllTypes), Attributes.Value); + if (uInt16Value.Value is UInt16) + { + UInt16 uInt16Val = Convert.ToUInt16(uInt16Value.Value); + int intIdentifier = uInt16Val; + Interlocked.CompareExchange(ref intIdentifier, 0, UInt16.MaxValue); + uInt16Value.Value = (UInt16)Interlocked.Increment(ref intIdentifier); + pubSubApplication.DataStore.WritePublishedDataItem(new NodeId("UInt16", namespaceIndexAllTypes), Attributes.Value, uInt16Value); + } + DataValue uInt32Value = pubSubApplication.DataStore.ReadPublishedDataItem(new NodeId("UInt32", namespaceIndexAllTypes), Attributes.Value); + if (uInt32Value.Value is UInt32) + { + UInt32 uInt32Val = Convert.ToUInt32(uInt32Value.Value); + long longIdentifier = uInt32Val; + Interlocked.CompareExchange(ref longIdentifier, 0, UInt32.MaxValue); + uInt32Value.Value = (UInt32)Interlocked.Increment(ref longIdentifier); + pubSubApplication.DataStore.WritePublishedDataItem(new NodeId("UInt32", namespaceIndexAllTypes), Attributes.Value, uInt32Value); + } + DataValue doubleValue = pubSubApplication.DataStore.ReadPublishedDataItem(new NodeId("Double", namespaceIndexAllTypes), Attributes.Value); + if (doubleValue.Value is double) + { + double doubleVal = Convert.ToDouble(doubleValue.Value); + Interlocked.CompareExchange(ref doubleVal, 0, double.MaxValue); + doubleValue.Value = ++doubleVal; + pubSubApplication.DataStore.WritePublishedDataItem(new NodeId("Double", namespaceIndexAllTypes), Attributes.Value, doubleValue); + } + DataValue dateTimeValue = new DataValue(new Variant(DateTime.UtcNow)); + pubSubApplication.DataStore.WritePublishedDataItem(new NodeId("DateTime", namespaceIndexAllTypes), Attributes.Value, dateTimeValue); + #endregion + } + /// /// Convert a value type to nullable object /// diff --git a/Tests/Opc.Ua.PubSub.Tests/PublishedData/WriterGroupPublishedStateTests.cs b/Tests/Opc.Ua.PubSub.Tests/PublishedData/WriterGroupPublishedStateTests.cs new file mode 100644 index 0000000000..bf99839ef5 --- /dev/null +++ b/Tests/Opc.Ua.PubSub.Tests/PublishedData/WriterGroupPublishedStateTests.cs @@ -0,0 +1,296 @@ +/* ======================================================================== + * Copyright (c) 2005-2021 The OPC Foundation, Inc. All rights reserved. + * + * OPC Foundation MIT License 1.00 + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + * + * The complete license agreement can be found here: + * http://opcfoundation.org/License/MIT/1.00/ + * ======================================================================*/ + +using System; +using System.Collections.Generic; +using System.Linq; +using NUnit.Framework; +using Opc.Ua.PubSub.Encoding; +using Opc.Ua.PubSub.Tests.Encoding; +using Opc.Ua.PubSub.PublishedData; +using System.Reflection; + +namespace Opc.Ua.PubSub.Tests.PublishedData +{ + public class WriterGroupPublishedStateTests + { + + /// + /// PubSub message type mapping + /// + public enum PubSubMessageType + { + Uadp, + Json + } + + private const UInt16 NamespaceIndexAllTypes = 3; + + private const string UdpUrlFormat = "{0}://{1}:4840"; + private const string MqttUrlFormat = "{0}://{1}:1883"; + //private const string MqttsUrlFormat = "{0}://{1}:8883"; + + [Test(Description = "Publish Uadp | Json DataSetMessages with KeyFrameCount and delta frames")] + public void PublishDataSetMessages( + [Values(PubSubMessageType.Uadp, PubSubMessageType.Json)] + PubSubMessageType pubSubMessageType, + [Values(1, 2, 3, 4)] Int32 keyFrameCount) + { + //Arrange + object publisherId = 1; + UInt16 writerGroupId = 1; + + string addressUrl = "http://localhost:1883"; + + DataSetFieldContentMask dataSetFieldContentMask = DataSetFieldContentMask.None; + + DataSetMetaDataType[] dataSetMetaDataArray = new DataSetMetaDataType[] + { + MessagesHelper.CreateDataSetMetaData1("DataSet1"), + MessagesHelper.CreateDataSetMetaData2("DataSet2"), + MessagesHelper.CreateDataSetMetaData2("DataSet3"), + }; + + PubSubConfigurationDataType publisherConfiguration = null; + + if (pubSubMessageType == PubSubMessageType.Uadp) + { + UadpNetworkMessageContentMask uadpNetworkMessageContentMask = UadpNetworkMessageContentMask.PublisherId + | UadpNetworkMessageContentMask.WriterGroupId + | UadpNetworkMessageContentMask.PayloadHeader; + UadpDataSetMessageContentMask uadpDataSetMessageContentMask = UadpDataSetMessageContentMask.None; + + publisherConfiguration = MessagesHelper.CreatePublisherConfiguration( + Profiles.PubSubMqttUadpTransport, + addressUrl, publisherId: publisherId, writerGroupId: writerGroupId, + uadpNetworkMessageContentMask: uadpNetworkMessageContentMask, + uadpDataSetMessageContentMask: uadpDataSetMessageContentMask, + dataSetFieldContentMask: dataSetFieldContentMask, + dataSetMetaDataArray: dataSetMetaDataArray, nameSpaceIndexForData: NamespaceIndexAllTypes, + keyFrameCount: Convert.ToUInt32(keyFrameCount)); + } + + if (pubSubMessageType == PubSubMessageType.Json) + { + JsonNetworkMessageContentMask jsonNetworkMessageContentMask = JsonNetworkMessageContentMask.NetworkMessageHeader + | JsonNetworkMessageContentMask.PublisherId + | JsonNetworkMessageContentMask.DataSetMessageHeader; + JsonDataSetMessageContentMask jsonDataSetMessageContentMask = JsonDataSetMessageContentMask.DataSetWriterId; + + publisherConfiguration = MessagesHelper.CreatePublisherConfiguration( + Profiles.PubSubMqttJsonTransport, + addressUrl, publisherId: publisherId, writerGroupId: writerGroupId, + jsonNetworkMessageContentMask: jsonNetworkMessageContentMask, + jsonDataSetMessageContentMask: jsonDataSetMessageContentMask, + dataSetFieldContentMask: dataSetFieldContentMask, + dataSetMetaDataArray: dataSetMetaDataArray, nameSpaceIndexForData: NamespaceIndexAllTypes, + keyFrameCount: Convert.ToUInt32(keyFrameCount)); + } + + Assert.IsNotNull(publisherConfiguration, "publisherConfiguration should not be null"); + + // Create publisher application for multiple datasets + UaPubSubApplication publisherApplication = UaPubSubApplication.Create(publisherConfiguration); + MessagesHelper.LoadData(publisherApplication, NamespaceIndexAllTypes); + + IUaPubSubConnection publisherConnection = publisherApplication.PubSubConnections.First(); + Assert.IsNotNull(publisherConnection, "Publisher first connection should not be null"); + + Assert.IsNotNull(publisherConfiguration.Connections.First(), "publisherConfiguration first connection should not be null"); + Assert.IsNotNull(publisherConfiguration.Connections.First().WriterGroups.First(), "publisherConfiguration first writer group of first connection should not be null"); + + WriterGroupPublishState writerGroupPublishState = new WriterGroupPublishState(); + var networkMessages = publisherConnection.CreateNetworkMessages(publisherConfiguration.Connections.First().WriterGroups.First(), writerGroupPublishState); + Assert.IsNotNull(networkMessages, "connection.CreateNetworkMessages shall not return null"); + Assert.GreaterOrEqual(networkMessages.Count, 1, "connection.CreateNetworkMessages shall have at least one network message"); + + object uaNetworkMessagesList = null; + List uaNetworkMessages = null; + if (pubSubMessageType == PubSubMessageType.Uadp) + { + uaNetworkMessagesList = MessagesHelper.GetUaDataNetworkMessages(networkMessages.Cast().ToList()); + Assert.IsNotNull(uaNetworkMessagesList, "uaNetworkMessagesList should not be null"); + uaNetworkMessages = ((IEnumerable)uaNetworkMessagesList).Cast().ToList(); + } + if (pubSubMessageType == PubSubMessageType.Json) + { + uaNetworkMessagesList = MessagesHelper.GetUaDataNetworkMessages(networkMessages.Cast().ToList()); + uaNetworkMessages = ((IEnumerable)uaNetworkMessagesList).Cast().ToList(); + } + Assert.IsNotNull(uaNetworkMessages, "uaNetworkMessages should not be null. Data entry is missing from configuration!?"); + + // get datastore data + Dictionary dataStoreData = new Dictionary(); + foreach (UaNetworkMessage uaDataNetworkMessage in uaNetworkMessages) + { + Dictionary dataSetsData = MessagesHelper.GetDataStoreData(publisherApplication, uaDataNetworkMessage, NamespaceIndexAllTypes); + foreach (NodeId nodeId in dataSetsData.Keys) + { + if (!dataStoreData.ContainsKey(nodeId)) + { + dataStoreData.Add(nodeId, dataSetsData[nodeId]); + } + } + } + Assert.IsNotEmpty(dataStoreData, "datastore entries should be greater than 0"); + + // check if received data is valid + foreach (UaNetworkMessage uaDataNetworkMessage in uaNetworkMessages) + { + ValidateDataSetMessageData(uaDataNetworkMessage, dataStoreData); + } + + for (int keyCount = 0; keyCount < keyFrameCount - 1; keyCount++) + { + // change the values and get one more time the dataset(s) data + MessagesHelper.UpdateSnapshotData(publisherApplication, NamespaceIndexAllTypes); + networkMessages = publisherConnection.CreateNetworkMessages(publisherConfiguration.Connections.First().WriterGroups.First(), writerGroupPublishState); + Assert.IsNotNull(networkMessages, "connection.CreateNetworkMessages shall not be null"); + Assert.GreaterOrEqual(networkMessages.Count, 1, "connection.CreateNetworkMessages should have at least one network message"); + + if (pubSubMessageType == PubSubMessageType.Uadp) + { + uaNetworkMessagesList = MessagesHelper.GetUaDataNetworkMessages(networkMessages.Cast().ToList()); + Assert.IsNotNull(uaNetworkMessagesList, "uaNetworkMessagesList shall not be null"); + uaNetworkMessages = ((IEnumerable)uaNetworkMessagesList).Cast().ToList(); + } + if (pubSubMessageType == PubSubMessageType.Json) + { + uaNetworkMessagesList = MessagesHelper.GetUaDataNetworkMessages(networkMessages.Cast().ToList()); + uaNetworkMessages = ((IEnumerable)uaNetworkMessagesList).Cast().ToList(); + } + Assert.IsNotNull(uaNetworkMessages, "uaNetworkMessages should not be null. Data entry is missing from configuration!?"); + + // check if delta received data is valid + Dictionary snapshotData = MessagesHelper.GetSnapshotData(publisherApplication, NamespaceIndexAllTypes); + foreach (UaNetworkMessage uaDataNetworkMessage in uaNetworkMessages) + { + ValidateDataSetMessageData(uaDataNetworkMessage, keyFrameCount == 1 ? dataStoreData : snapshotData, keyFrameCount, writerGroupPublishState); + } + } + + // check one more time if delta received data is valid + Dictionary snapshotDataCopy = MessagesHelper.GetSnapshotData(publisherApplication, NamespaceIndexAllTypes); + foreach (UaNetworkMessage uaDataNetworkMessage in uaNetworkMessages) + { + ValidateDataSetMessageData(uaDataNetworkMessage, keyFrameCount == 1 ? dataStoreData : snapshotDataCopy, keyFrameCount, writerGroupPublishState); + } + } + + #region Private methods + + /// + /// Validate dataset message data + /// + /// + /// + private void ValidateDataSetMessageData(UaNetworkMessage uaDataNetworkMessage, Dictionary dataStoreData, + Int32 keyFrameCount = 1, WriterGroupPublishState writerGroupPublishState = null) + { + IEnumerable writerGroupDataSetStates = null; + if (writerGroupPublishState != null) + { + var dataSetStates = writerGroupPublishState.GetType() + .GetField("m_dataSetStates", BindingFlags.Instance | BindingFlags.NonPublic) + .GetValue(writerGroupPublishState); + + var dataSetStatesValues = dataSetStates.GetType() + .GetProperty("Values", BindingFlags.Instance | BindingFlags.Public) + .GetValue(dataSetStates); + + writerGroupDataSetStates = ((IEnumerable)dataSetStatesValues).Cast(); + } + + foreach (UaDataSetMessage datasetMessage in uaDataNetworkMessage.DataSetMessages) + { + if (datasetMessage.DataSet.IsDeltaFrame) + { + Assert.Greater(keyFrameCount, 1, "keyFrameCount > 1 if dataset is delta!"); + Assert.IsNotNull(writerGroupPublishState, "WriterGroupPublishState should not be null"); + Assert.IsNotNull(writerGroupDataSetStates, "writerGroupDataSetStates that contains last saved detaset should not be null"); + + DataSet lastDataSetFound = null; + foreach (object dataSetState in writerGroupDataSetStates) + { + var writerGroupLastDataSet = dataSetState.GetType() + .GetField("LastDataSet", BindingFlags.Instance | BindingFlags.Public) + .GetValue(dataSetState); + if (writerGroupLastDataSet != null) + { + string dataSetName = writerGroupLastDataSet.GetType() + .GetProperty("Name", BindingFlags.Instance | BindingFlags.Public) + .GetValue(writerGroupLastDataSet) as string; + if (!string.IsNullOrEmpty(dataSetName) && + datasetMessage.DataSet.Name == dataSetName) + { + lastDataSetFound = writerGroupLastDataSet as DataSet; + } + } + } + Assert.IsNotNull(lastDataSetFound, "lastDataSetFound dataset should not be null"); + + int fieldIndex = 0; + foreach (Field field in datasetMessage.DataSet.Fields) + { + // ghost field should still be hold it in the state.LastDataSet + Field lastDataSetField = lastDataSetFound.Fields[fieldIndex++]; + Assert.IsNotNull(lastDataSetField, "lastDataSetField should not be null even if the partial field is missing due to delta"); + // for delta frames dataset might contains partial filled data + if (field == null) + { + continue; + } + NodeId targetNodeId = new NodeId(field.FieldMetaData.Name, NamespaceIndexAllTypes); + Assert.IsTrue(dataStoreData.ContainsKey(targetNodeId), "field name: '{0}' should be exists in partial received dataset", field.FieldMetaData.Name); + Assert.IsNotNull(dataStoreData[targetNodeId], "field: '{0}' should not be null", field.FieldMetaData.Name); + Assert.AreEqual(field.Value.Value, dataStoreData[targetNodeId].Value, "field: '{0}' value: {1} should be equal to datastore value: {2}", + field.FieldMetaData.Name, field.Value, dataStoreData[targetNodeId].Value); + Assert.AreEqual(lastDataSetField.Value.Value, dataStoreData[targetNodeId].Value, "lastDataSetField: '{0}' value: {1} should be equal to datastore value: {2}", + lastDataSetField.FieldMetaData.Name, lastDataSetField.Value, dataStoreData[targetNodeId].Value); + } + } + else + { + Assert.AreEqual(keyFrameCount, 1, "keyFrameCount = 1 if dataset is not delta!"); + foreach (Field field in datasetMessage.DataSet.Fields) + { + Assert.IsNotNull(field, "field {0}: should not be null if dataset is not delta!", field.FieldMetaData.Name); + NodeId targetNodeId = new NodeId(field.FieldMetaData.Name, NamespaceIndexAllTypes); + Assert.IsTrue(dataStoreData.ContainsKey(targetNodeId), "field name: {0} should be exists in partial received dataset", field.FieldMetaData.Name); + Assert.IsNotNull(dataStoreData[targetNodeId], "field {0}: should not be null", field.FieldMetaData.Name); + Assert.AreEqual(field.Value.Value, dataStoreData[targetNodeId].Value, "field: '{0}' value: {1} should be equal to datastore value: {2}", + field.FieldMetaData.Name, field.Value, dataStoreData[targetNodeId].Value); + } + } + } + } + + #endregion Private methods + } +} diff --git a/Tests/Opc.Ua.PubSub.Tests/Transport/MqttPubSubConnectionTests.cs b/Tests/Opc.Ua.PubSub.Tests/Transport/MqttPubSubConnectionTests.cs index ef466f7d4f..1373a1e503 100644 --- a/Tests/Opc.Ua.PubSub.Tests/Transport/MqttPubSubConnectionTests.cs +++ b/Tests/Opc.Ua.PubSub.Tests/Transport/MqttPubSubConnectionTests.cs @@ -37,6 +37,7 @@ using Opc.Ua.PubSub.Encoding; using Opc.Ua.PubSub.Transport; using Opc.Ua.PubSub.Tests.Encoding; using System.Collections.Generic; +using Opc.Ua.PubSub.PublishedData; namespace Opc.Ua.PubSub.Tests.Transport { @@ -46,10 +47,19 @@ namespace Opc.Ua.PubSub.Tests.Transport private const UInt16 kNamespaceIndexAllTypes = 3; private ManualResetEvent m_uaDataShutdownEvent; + private ManualResetEvent m_uaDeltaDataShutdownEvent; private ManualResetEvent m_uaMetaDataShutdownEvent; private ManualResetEvent m_uaConfigurationUpdateEvent; + private bool m_isDeltaFrame; + private Dictionary m_snapshotData; private const int kEstimatedPublishingTime = 60000; + private const string DefaultBrokerProcessName = "mosquitto"; + + private const string UdpUrlFormat = "{0}://{1}:4840"; + private const string MqttUrlFormat = "{0}://{1}:1883"; + private const string MqttsUrlFormat = "{0}://{1}:8883"; + [OneTimeSetUp()] public void MyTestInitialize() { @@ -63,12 +73,12 @@ namespace Opc.Ua.PubSub.Tests.Transport public void ValidateMqttLocalPubSubConnectionWithUadp( [Values((byte)1, (UInt16)1, (UInt32)1, (UInt64)1, "abc")] object publisherId) { - RestartMosquitto("mosquitto"); + RestartMosquitto(); //Arrange UInt16 writerGroupId = 1; - string mqttLocalBrokerUrl = "mqtt://localhost:1883"; + string mqttLocalBrokerUrl = string.Format(MqttUrlFormat, Utils.UriSchemeMqtt, "localhost"); ITransportProtocolConfiguration mqttConfiguration = new MqttClientProtocolConfiguration(version: EnumMqttProtocolVersion.V500); @@ -149,6 +159,7 @@ namespace Opc.Ua.PubSub.Tests.Transport // it will signal if the uadp message was received from local ip m_uaDataShutdownEvent = new ManualResetEvent(false); + m_isDeltaFrame = false; subscriberApplication.DataReceived += UaPubSubApplication_DataReceived; subscriberConnection.Start(); @@ -159,6 +170,142 @@ namespace Opc.Ua.PubSub.Tests.Transport { Assert.Fail("The UADP message was not received"); } + + subscriberConnection.Stop(); + publisherConnection.Stop(); + + } + + [Test(Description = "Validate mqtt local pub/sub connection with uadp data.")] +#if !CUSTOM_TESTS + [Ignore("A mosquitto tool should be installed local in order to run correctly.")] +#endif + public void ValidateMqttLocalPubSubConnectionWithDeltaUadp( + [Values((byte)1, (UInt16)1, (UInt32)1, (UInt64)1, "abc")] object publisherId, + [Values(1, 2, 3, 4)] Int32 keyFrameCount) + { + RestartMosquitto(); + + //Arrange + UInt16 writerGroupId = 1; + + string mqttLocalBrokerUrl = string.Format(MqttUrlFormat, Utils.UriSchemeMqtt, "localhost"); + + ITransportProtocolConfiguration mqttConfiguration = new MqttClientProtocolConfiguration(version: EnumMqttProtocolVersion.V500); + + UadpNetworkMessageContentMask uadpNetworkMessageContentMask = UadpNetworkMessageContentMask.PublisherId + | UadpNetworkMessageContentMask.WriterGroupId + | UadpNetworkMessageContentMask.PayloadHeader; + UadpDataSetMessageContentMask uadpDataSetMessageContentMask = UadpDataSetMessageContentMask.None; + + DataSetFieldContentMask dataSetFieldContentMask = DataSetFieldContentMask.None; + + DataSetMetaDataType[] dataSetMetaDataArray = new DataSetMetaDataType[] + { + MessagesHelper.CreateDataSetMetaData1("DataSet1"), + MessagesHelper.CreateDataSetMetaData2("DataSet2"), + }; + + PubSubConfigurationDataType publisherConfiguration = MessagesHelper.CreatePublisherConfiguration( + Profiles.PubSubMqttUadpTransport, + mqttLocalBrokerUrl, publisherId: publisherId, writerGroupId: writerGroupId, + uadpNetworkMessageContentMask: uadpNetworkMessageContentMask, + uadpDataSetMessageContentMask: uadpDataSetMessageContentMask, + dataSetFieldContentMask: dataSetFieldContentMask, + dataSetMetaDataArray: dataSetMetaDataArray, nameSpaceIndexForData: kNamespaceIndexAllTypes, + keyFrameCount: Convert.ToUInt32(keyFrameCount)); + Assert.IsNotNull(publisherConfiguration, "publisherConfiguration should not be null"); + + // Configure the mqtt publisher configuration with the MQTTbroker + PubSubConnectionDataType mqttPublisherConnection = MessagesHelper.GetConnection(publisherConfiguration, publisherId); + Assert.IsNotNull(mqttPublisherConnection, "The MQTT publisher connection is invalid."); + mqttPublisherConnection.ConnectionProperties = mqttConfiguration.ConnectionProperties; + Assert.IsNotNull(mqttPublisherConnection.ConnectionProperties, "The MQTT publisher connection properties are not valid."); + + // Create publisher application for multiple datasets + UaPubSubApplication publisherApplication = UaPubSubApplication.Create(publisherConfiguration); + MessagesHelper.LoadData(publisherApplication, kNamespaceIndexAllTypes); + + IUaPubSubConnection publisherConnection = publisherApplication.PubSubConnections.First(); + Assert.IsNotNull(publisherConnection, "Publisher first connection should not be null"); + + Assert.IsNotNull(publisherConfiguration.Connections.First(), "publisherConfiguration first connection should not be null"); + Assert.IsNotNull(publisherConfiguration.Connections.First().WriterGroups.First(), "publisherConfiguration first writer group of first connection should not be null"); + + var networkMessages = publisherConnection.CreateNetworkMessages(publisherConfiguration.Connections.First().WriterGroups.First(), new WriterGroupPublishState()); + Assert.IsNotNull(networkMessages, "connection.CreateNetworkMessages shall not return null"); + Assert.GreaterOrEqual(networkMessages.Count, 1, "connection.CreateNetworkMessages shall have at least one network message"); + + UadpNetworkMessage uaNetworkMessage = networkMessages[0] as UadpNetworkMessage; + Assert.IsNotNull(uaNetworkMessage, "networkMessageEncode should not be null"); + + bool hasDataSetWriterId = (uadpNetworkMessageContentMask & UadpNetworkMessageContentMask.PayloadHeader) != 0; + + PubSubConfigurationDataType subscriberConfiguration = MessagesHelper.CreateSubscriberConfiguration( + Profiles.PubSubMqttUadpTransport, + mqttLocalBrokerUrl, publisherId: publisherId, writerGroupId: writerGroupId, setDataSetWriterId: hasDataSetWriterId, + uadpNetworkMessageContentMask: uadpNetworkMessageContentMask, + uadpDataSetMessageContentMask: uadpDataSetMessageContentMask, + dataSetFieldContentMask: dataSetFieldContentMask, + dataSetMetaDataArray: dataSetMetaDataArray, + nameSpaceIndexForData: kNamespaceIndexAllTypes, keyFrameCount: Convert.ToUInt32(keyFrameCount)); + Assert.IsNotNull(subscriberConfiguration, "subscriberConfiguration should not be null"); + + // Create subscriber application for multiple datasets + UaPubSubApplication subscriberApplication = UaPubSubApplication.Create(subscriberConfiguration); + Assert.IsNotNull(subscriberApplication, "subscriberApplication should not be null"); + Assert.IsNotNull(subscriberApplication.PubSubConnections.First(), "subscriberConfiguration first connection should not be null"); + + // Configure the mqtt subscriber configuration with the MQTTbroker + PubSubConnectionDataType mqttSubcriberConnection = MessagesHelper.GetConnection(subscriberConfiguration, publisherId); + Assert.IsNotNull(mqttSubcriberConnection, "The MQTT subscriber connection is invalid."); + mqttSubcriberConnection.ConnectionProperties = mqttConfiguration.ConnectionProperties; + Assert.IsNotNull(mqttSubcriberConnection.ConnectionProperties, "The MQTT subscriber connection properties are not valid."); + + var dataSetReaders = subscriberApplication.PubSubConnections.First().GetOperationalDataSetReaders(); + Assert.IsNotNull(dataSetReaders, "dataSetReaders should not be null"); + IUaPubSubConnection subscriberConnection = subscriberApplication.PubSubConnections.First(); + Assert.IsNotNull(subscriberConnection, "Subscriber first connection should not be null"); + + //Act + // it will signal if the uadp message was received from local ip + m_uaDataShutdownEvent = new ManualResetEvent(false); + // it will signal if the mqtt with delta frame message was received from local ip + m_uaDeltaDataShutdownEvent = new ManualResetEvent(false); + + m_isDeltaFrame = keyFrameCount > 1; + subscriberApplication.DataReceived += UaPubSubApplication_DataReceived; + subscriberConnection.Start(); + + publisherConnection.Start(); + + //Assert + m_snapshotData = MessagesHelper.GetSnapshotData(publisherApplication, kNamespaceIndexAllTypes); + if (!m_uaDataShutdownEvent.WaitOne(kEstimatedPublishingTime)) + { + Assert.Fail("The UADP message was not received"); + } + if (keyFrameCount > 1) + { + MessagesHelper.UpdateSnapshotData(publisherApplication, kNamespaceIndexAllTypes); + if (!m_uaDeltaDataShutdownEvent.WaitOne(kEstimatedPublishingTime)) + { + Assert.Fail("The UADP delta message was not received"); + } + } + if (keyFrameCount > 2) + { + for (int keyCount = 0; keyCount < keyFrameCount - 1; keyCount++) + { + m_uaDeltaDataShutdownEvent.Reset(); + m_snapshotData = MessagesHelper.GetSnapshotData(publisherApplication, kNamespaceIndexAllTypes); + MessagesHelper.UpdateSnapshotData(publisherApplication, kNamespaceIndexAllTypes); + if (!m_uaDeltaDataShutdownEvent.WaitOne(kEstimatedPublishingTime)) + { + Assert.Fail("The UADP delta message was not received"); + } + } + } subscriberConnection.Stop(); publisherConnection.Stop(); @@ -173,12 +320,12 @@ namespace Opc.Ua.PubSub.Tests.Transport [Values((byte)1, (UInt16)1, (UInt32)1, (UInt64)1, "abc")] object publisherId, [Values(0, 10000)] double metaDataUpdateTime) { - RestartMosquitto("mosquitto"); + RestartMosquitto(); //Arrange UInt16 writerGroupId = 1; - string mqttLocalBrokerUrl = "mqtt://localhost:1883"; + string mqttLocalBrokerUrl = string.Format(MqttUrlFormat, Utils.UriSchemeMqtt, "localhost"); ITransportProtocolConfiguration mqttConfiguration = new MqttClientProtocolConfiguration(version: EnumMqttProtocolVersion.V500); @@ -204,7 +351,7 @@ namespace Opc.Ua.PubSub.Tests.Transport jsonDataSetMessageContentMask: jsonDataSetMessageContentMask, dataSetFieldContentMask: dataSetFieldContentMask, dataSetMetaDataArray: dataSetMetaDataArray, nameSpaceIndexForData: kNamespaceIndexAllTypes, - metaDataUpdateTime); + metaDataUpdateTime: metaDataUpdateTime); Assert.IsNotNull(publisherConfiguration, "publisherConfiguration should not be null"); // Configure the mqtt publisher configuration with the MQTTbroker @@ -269,6 +416,7 @@ namespace Opc.Ua.PubSub.Tests.Transport // it will signal if the changed configuration message was received on local ip m_uaConfigurationUpdateEvent = new ManualResetEvent(false); + m_isDeltaFrame = false; subscriberApplication.DataReceived += UaPubSubApplication_DataReceived; subscriberApplication.MetaDataReceived += UaPubSubApplication_MetaDataReceived; subscriberApplication.ConfigurationUpdating += UaPubSubApplication_ConfigurationUpdating; @@ -290,6 +438,146 @@ namespace Opc.Ua.PubSub.Tests.Transport publisherConnection.Stop(); } + [Test(Description = "Validate mqtt local pub/sub connection with json data.")] +#if !CUSTOM_TESTS + [Ignore("A mosquitto tool should be installed local in order to run correctly.")] +#endif + public void ValidateMqttLocalPubSubConnectionWithDeltaJson( + [Values((byte)1, (UInt16)1, (UInt32)1, (UInt64)1, "abc")] object publisherId, + [Values(2, 3, 4)] Int32 keyFrameCount) + { + RestartMosquitto(); + + //Arrange + UInt16 writerGroupId = 1; + + string mqttLocalBrokerUrl = string.Format(MqttUrlFormat, Utils.UriSchemeMqtt, "localhost"); + + ITransportProtocolConfiguration mqttConfiguration = new MqttClientProtocolConfiguration(version: EnumMqttProtocolVersion.V500); + + JsonNetworkMessageContentMask jsonNetworkMessageContentMask = JsonNetworkMessageContentMask.NetworkMessageHeader + | JsonNetworkMessageContentMask.PublisherId + | JsonNetworkMessageContentMask.DataSetMessageHeader; + JsonDataSetMessageContentMask jsonDataSetMessageContentMask = JsonDataSetMessageContentMask.None; + + DataSetFieldContentMask dataSetFieldContentMask = DataSetFieldContentMask.None; + + DataSetMetaDataType[] dataSetMetaDataArray = new DataSetMetaDataType[] + { + MessagesHelper.CreateDataSetMetaData1("DataSet1"), + MessagesHelper.CreateDataSetMetaData2("DataSet2"), + }; + + PubSubConfigurationDataType publisherConfiguration = MessagesHelper.CreatePublisherConfiguration( + Profiles.PubSubMqttJsonTransport, + mqttLocalBrokerUrl, publisherId: publisherId, writerGroupId: writerGroupId, + jsonNetworkMessageContentMask: jsonNetworkMessageContentMask, + jsonDataSetMessageContentMask: jsonDataSetMessageContentMask, + dataSetFieldContentMask: dataSetFieldContentMask, + dataSetMetaDataArray: dataSetMetaDataArray, nameSpaceIndexForData: kNamespaceIndexAllTypes, + metaDataUpdateTime: 1000, keyFrameCount: Convert.ToUInt32(keyFrameCount)); + Assert.IsNotNull(publisherConfiguration, "publisherConfiguration should not be null"); + + // Configure the mqtt publisher configuration with the MQTTbroker + PubSubConnectionDataType mqttPublisherConnection = MessagesHelper.GetConnection(publisherConfiguration, publisherId); + Assert.IsNotNull(mqttPublisherConnection, "The MQTT publisher connection is invalid."); + mqttPublisherConnection.ConnectionProperties = mqttConfiguration.ConnectionProperties; + Assert.IsNotNull(mqttPublisherConnection.ConnectionProperties, "The MQTT publisher connection properties are not valid."); + + // Create publisher application for multiple datasets + UaPubSubApplication publisherApplication = UaPubSubApplication.Create(publisherConfiguration); + MessagesHelper.LoadData(publisherApplication, kNamespaceIndexAllTypes); + + IUaPubSubConnection publisherConnection = publisherApplication.PubSubConnections.First(); + Assert.IsNotNull(publisherConnection, "Publisher first connection should not be null"); + + Assert.IsNotNull(publisherConfiguration.Connections.First(), "publisherConfiguration first connection should not be null"); + Assert.IsNotNull(publisherConfiguration.Connections.First().WriterGroups.First(), "publisherConfiguration first writer group of first connection should not be null"); + + var networkMessages = publisherConnection.CreateNetworkMessages(publisherConfiguration.Connections.First().WriterGroups.First(), new WriterGroupPublishState()); + Assert.IsNotNull(networkMessages, "connection.CreateNetworkMessages shall not return null"); + Assert.GreaterOrEqual(networkMessages.Count, 1, "connection.CreateNetworkMessages shall have at least one network message"); + + List uaNetworkMessages = MessagesHelper.GetJsonUaDataNetworkMessages(networkMessages.Cast().ToList()); + Assert.IsNotNull(uaNetworkMessages, "Json ua-data entries are missing from configuration!"); + + List uaMetaDataNetworkMessages = MessagesHelper.GetJsonUaMetaDataNetworkMessages(networkMessages.Cast().ToList()); + Assert.IsNotNull(uaMetaDataNetworkMessages, "Json ua-metadata entries are missing from configuration!"); + + bool hasDataSetWriterId = (jsonNetworkMessageContentMask & JsonNetworkMessageContentMask.DataSetMessageHeader) != 0 + && (jsonDataSetMessageContentMask & JsonDataSetMessageContentMask.DataSetWriterId) != 0; + + PubSubConfigurationDataType subscriberConfiguration = MessagesHelper.CreateSubscriberConfiguration( + Profiles.PubSubMqttJsonTransport, + mqttLocalBrokerUrl, publisherId: publisherId, writerGroupId: writerGroupId, setDataSetWriterId: hasDataSetWriterId, + jsonNetworkMessageContentMask: jsonNetworkMessageContentMask, + jsonDataSetMessageContentMask: jsonDataSetMessageContentMask, + dataSetFieldContentMask: dataSetFieldContentMask, + dataSetMetaDataArray: dataSetMetaDataArray, + nameSpaceIndexForData: kNamespaceIndexAllTypes, keyFrameCount: Convert.ToUInt32(keyFrameCount)); + Assert.IsNotNull(subscriberConfiguration, "subscriberConfiguration should not be null"); + + // Create subscriber application for multiple datasets + UaPubSubApplication subscriberApplication = UaPubSubApplication.Create(subscriberConfiguration); + Assert.IsNotNull(subscriberApplication, "subscriberApplication should not be null"); + Assert.IsNotNull(subscriberApplication.PubSubConnections.First(), "subscriberConfiguration first connection should not be null"); + + // Configure the mqtt subscriber configuration with the MQTTbroker + PubSubConnectionDataType mqttSubcriberConnection = MessagesHelper.GetConnection(subscriberConfiguration, publisherId); + Assert.IsNotNull(mqttSubcriberConnection, "The MQTT subscriber connection is invalid."); + mqttSubcriberConnection.ConnectionProperties = mqttConfiguration.ConnectionProperties; + Assert.IsNotNull(mqttSubcriberConnection.ConnectionProperties, "The MQTT subscriber connection properties are not valid."); + + var dataSetReaders = subscriberApplication.PubSubConnections.First().GetOperationalDataSetReaders(); + Assert.IsNotNull(dataSetReaders, "dataSetReaders should not be null"); + IUaPubSubConnection subscriberConnection = subscriberApplication.PubSubConnections.First(); + Assert.IsNotNull(subscriberConnection, "Subscriber first connection should not be null"); + + //Act + // it will signal if the mqtt message was received from local ip + m_uaDataShutdownEvent = new ManualResetEvent(false); + // it will signal if the mqtt with delta frame message was received from local ip + m_uaDeltaDataShutdownEvent = new ManualResetEvent(false); + + m_isDeltaFrame = keyFrameCount > 1; + subscriberApplication.DataReceived += UaPubSubApplication_DataReceived; + subscriberConnection.Start(); + + publisherConnection.Start(); + + //Assert + m_snapshotData = MessagesHelper.GetSnapshotData(publisherApplication, kNamespaceIndexAllTypes); + Assert.IsNotNull(m_snapshotData, "snapshot data should not be null"); + if (!m_uaDataShutdownEvent.WaitOne(kEstimatedPublishingTime)) + { + Assert.Fail("The JSON message was not received"); + } + if (keyFrameCount > 1) + { + MessagesHelper.UpdateSnapshotData(publisherApplication, kNamespaceIndexAllTypes); + if (!m_uaDeltaDataShutdownEvent.WaitOne(kEstimatedPublishingTime)) + { + Assert.Fail("The JSON delta message was not received"); + } + } + if (keyFrameCount > 2) + { + for (int keyCount = 0; keyCount < keyFrameCount - 1; keyCount++) + { + m_uaDeltaDataShutdownEvent.Reset(); + m_snapshotData = MessagesHelper.GetSnapshotData(publisherApplication, kNamespaceIndexAllTypes); + MessagesHelper.UpdateSnapshotData(publisherApplication, kNamespaceIndexAllTypes); + if (!m_uaDeltaDataShutdownEvent.WaitOne(kEstimatedPublishingTime)) + { + Assert.Fail("The JSON delta message was not received"); + } + } + } + + subscriberConnection.Stop(); + publisherConnection.Stop(); + } + #region Private methods /// @@ -299,7 +587,37 @@ namespace Opc.Ua.PubSub.Tests.Transport /// private void UaPubSubApplication_DataReceived(object sender, SubscribedDataEventArgs e) { - m_uaDataShutdownEvent.Set(); + if (m_isDeltaFrame) + { + bool hasChanged = false; + foreach (UaDataSetMessage dataSetMessage in e.NetworkMessage.DataSetMessages) + { + foreach(Field field in dataSetMessage.DataSet.Fields) + { + if (m_snapshotData.Keys.Contains(field.TargetNodeId)) + { + // check if the published value changed + DataValue snapshotValue = m_snapshotData[field.TargetNodeId]; + if(!field.Value.Equals(snapshotValue)) + { + hasChanged = true; + } + } + } + } + if(!hasChanged) + { + m_uaDataShutdownEvent.Set(); + } + else + { + m_uaDeltaDataShutdownEvent.Set(); + } + } + else + { + m_uaDataShutdownEvent.Set(); + } } /// @@ -327,11 +645,11 @@ namespace Opc.Ua.PubSub.Tests.Transport /// /// /// - private void RestartMosquitto(string processName, string arguments = "") + private void RestartMosquitto(string arguments = "") { try { - Process[] processes = Process.GetProcessesByName(processName); + Process[] processes = Process.GetProcessesByName(DefaultBrokerProcessName); if (processes.Length > 0) { Process mosquittoProcess = processes[0]; @@ -340,10 +658,13 @@ namespace Opc.Ua.PubSub.Tests.Transport using (Process process = new Process()) { + string programFilesPath = Environment.Is64BitOperatingSystem ? + Environment.GetEnvironmentVariable("ProgramW6432") : + Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86); + ProcessStartInfo startInfo = new ProcessStartInfo( - Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), - Path.Combine(processName, $"{processName}.exe"))); + Path.Combine(programFilesPath, Path.Combine(DefaultBrokerProcessName, $"{DefaultBrokerProcessName}.exe"))); startInfo.WindowStyle = ProcessWindowStyle.Hidden; //startInfo.CreateNoWindow = true; //startInfo.RedirectStandardOutput = true;