summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorJannis Voelker <jannis.voelker@basyskom.com>2023-09-21 12:40:33 +0200
committerJannis Voelker <jannis.voelker@basyskom.com>2023-09-22 11:16:11 +0200
commitaf7534c2bb7b8759c87e885a445a4bf4c90692e0 (patch)
treee9f7b8d0ede47de91c7b0537ca7201ed7c5cc4e4 /tests
parent60a98da7dc9e5445bbca62c8a167ef90f71d85e2 (diff)
Extend test coverage
- Reduce number of references per node in the test server to force continuation points - Test adding and removing all node classes Change-Id: I37abf70a22319152522af29929b5c7236a38c564 Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qopcuaclient/tst_client.cpp715
-rw-r--r--tests/open62541-testserver/testserver.cpp2
2 files changed, 712 insertions, 5 deletions
diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp
index 897ad2d..fdfa317 100644
--- a/tests/auto/qopcuaclient/tst_client.cpp
+++ b/tests/auto/qopcuaclient/tst_client.cpp
@@ -449,6 +449,8 @@ private slots:
void initTestCase();
void cleanupTestCase();
+ void loadInvalidPlugin();
+
// connect & disconnect
defineDataMethod(connectToInvalid_data)
void connectToInvalid();
@@ -471,6 +473,8 @@ private slots:
defineDataMethod(compareNodeIds_data)
void compareNodeIds();
+ defineDataMethod(getNodeForIdTypes_data)
+ void getNodeForIdTypes();
defineDataMethod(readNS0OmitNode_data)
void readNS0OmitNode();
defineDataMethod(readInvalidNode_data)
@@ -510,6 +514,18 @@ private slots:
void addAndRemoveObjectNode();
defineDataMethod(addAndRemoveVariableNode_data)
void addAndRemoveVariableNode();
+ defineDataMethod(addAndRemoveMethodNode_data)
+ void addAndRemoveMethodNode();
+ defineDataMethod(addAndRemoveObjectTypeNode_data)
+ void addAndRemoveObjectTypeNode();
+ defineDataMethod(addAndRemoveVariableTypeNode_data)
+ void addAndRemoveVariableTypeNode();
+ defineDataMethod(addAndRemoveReferenceTypeNode_data)
+ void addAndRemoveReferenceTypeNode();
+ defineDataMethod(addAndRemoveDataTypeNode_data)
+ void addAndRemoveDataTypeNode();
+ defineDataMethod(addAndRemoveViewNode_data)
+ void addAndRemoveViewNode();
defineDataMethod(addAndRemoveReference_data)
void addAndRemoveReference();
@@ -566,6 +582,8 @@ private slots:
void checkAttributeUpdated();
defineDataMethod(checkValueAttributeUpdated_data);
void checkValueAttributeUpdated();
+ defineDataMethod(checkMonitoringInvalidRequests_data);
+ void checkMonitoringInvalidRequests();
defineDataMethod(stringCharset_data)
void stringCharset();
@@ -974,6 +992,46 @@ void Tst_QOpcUaClient::compareNodeIds()
}
}
+void Tst_QOpcUaClient::getNodeForIdTypes()
+{
+ QFETCH(QOpcUaClient*, opcuaClient);
+
+ QScopedPointer<QOpcUaNode> node(opcuaClient->node("ns=1;i=42"));
+ QVERIFY(node == nullptr);
+
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ node.reset(opcuaClient->node("ns=1;i=42"));
+ QVERIFY(node != nullptr);
+
+ node.reset(opcuaClient->node("ns=1;i="));
+ QVERIFY(node == nullptr);
+
+ node.reset(opcuaClient->node("ns=1;s=TestString"));
+ QVERIFY(node != nullptr);
+
+ node.reset(opcuaClient->node("ns=1;s="));
+ QVERIFY(node == nullptr);
+
+ node.reset(opcuaClient->node("ns=1;g=4365723d-39fb-4139-bbea-bbfe8202b0f9"));
+ QVERIFY(node != nullptr);
+
+ node.reset(opcuaClient->node("ns=1;g=xxxxxxxxx"));
+ QVERIFY(node == nullptr);
+
+ node.reset(opcuaClient->node("ns=1;b=VGVzdElkZW50aWZpZXI="));
+ QVERIFY(node != nullptr);
+
+ node.reset(opcuaClient->node("ns=1;b="));
+ QVERIFY(node == nullptr);
+
+ node.reset(opcuaClient->node("ns=1;q=42"));
+ QVERIFY(node == nullptr);
+
+ node.reset(opcuaClient->node("xxxxxxxxxxxxx"));
+ QVERIFY(node == nullptr);
+}
+
void Tst_QOpcUaClient::readNS0OmitNode()
{
QFETCH(QOpcUaClient*, opcuaClient);
@@ -1078,6 +1136,22 @@ void Tst_QOpcUaClient::writeMultipleAttributes()
QCOMPARE(writeSpy.at(1).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::Value), QOpcUa::UaStatusCode::Good);
QCOMPARE(node->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaQualifiedName>(), QOpcUaQualifiedName(2, QStringLiteral("TestString")));
+
+ writeSpy.clear();
+ node->writeAttributes({});
+
+ writeSpy.wait(signalSpyTimeout);
+ QCOMPARE(writeSpy.size(), 1);
+ QCOMPARE(writeSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::BadNothingToDo);
+
+ node.reset(opcuaClient->node("ns=42;s=idonotexist"));
+ QVERIFY(node != nullptr);
+ QSignalSpy writeSpy2(node.data(), &QOpcUaNode::attributeWritten);
+ node->writeAttributes(map, QOpcUa::Types::QualifiedName);
+ writeSpy2.wait(signalSpyTimeout);
+ QCOMPARE(writeSpy2.size(), 2);
+ QCOMPARE(writeSpy2.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::BadNodeIdUnknown);
+ QCOMPARE(writeSpy2.at(1).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::BadNodeIdUnknown);
}
void Tst_QOpcUaClient::readEmptyArrayVariable()
@@ -1382,6 +1456,9 @@ void Tst_QOpcUaClient::addAndRemoveObjectNode()
attributes.setDisplayName(displayName);
attributes.setDescription(description);
+ attributes.setEventNotifier(QOpcUa::EventNotifierBit::SubscribeToEvents);
+ attributes.setWriteMask(QOpcUa::WriteMaskBit::DisplayName);
+ attributes.setUserWriteMask(QOpcUa::WriteMaskBit::DisplayName);
QOpcUaAddNodeItem nodeInfo;
nodeInfo.setParentNodeId(parent);
@@ -1405,7 +1482,9 @@ void Tst_QOpcUaClient::addAndRemoveObjectNode()
QVERIFY(newNode != nullptr);
QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
- newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName | QOpcUa::NodeAttribute::Description);
+ newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName |
+ QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::EventNotifier |
+ QOpcUa::NodeAttribute::WriteMask | QOpcUa::NodeAttribute::UserWriteMask);
readSpy.wait(signalSpyTimeout);
QCOMPARE(readSpy.size(), 1);
@@ -1413,10 +1492,19 @@ void Tst_QOpcUaClient::addAndRemoveObjectNode()
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::BrowseName), QOpcUa::UaStatusCode::Good);
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::DisplayName), QOpcUa::UaStatusCode::Good);
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::EventNotifier), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::WriteMask), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::UserWriteMask), QOpcUa::UaStatusCode::Good);
QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::EventNotifier).value<quint8>(),
+ static_cast<quint8>(QOpcUa::EventNotifierBit::SubscribeToEvents));
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::WriteMask).value<quint8>(),
+ static_cast<quint8>(QOpcUa::WriteMaskBit::DisplayName));
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::UserWriteMask).value<quint8>(),
+ static_cast<quint8>(QOpcUa::WriteMaskBit::DisplayName));
QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
opcuaClient->deleteNode(requestedNewId.nodeId(), true);
@@ -1459,9 +1547,12 @@ void Tst_QOpcUaClient::addAndRemoveVariableNode()
attributes.setDisplayName(displayName);
attributes.setDescription(description);
- attributes.setValue(23.0, QOpcUa::Types::Double);
+ attributes.setValue(QOpcUaMultiDimensionalArray({1,2,3,4}, {2,2}), QOpcUa::Types::Double);
attributes.setDataTypeId(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::Double));
- attributes.setValueRank(-2); // Scalar or array
+ attributes.setValueRank(2); // Two-dimensional array
+ attributes.setArrayDimensions({ 2, 2 });
+ attributes.setMinimumSamplingInterval(23.0);
+ attributes.setHistorizing(true);
attributes.setAccessLevel(QOpcUa::AccessLevelBit::CurrentRead);
attributes.setUserAccessLevel(QOpcUa::AccessLevelBit::CurrentRead);
@@ -1488,7 +1579,10 @@ void Tst_QOpcUaClient::addAndRemoveVariableNode()
QVERIFY(newNode != nullptr);
QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
- newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName | QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::Value);
+ newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName |
+ QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::Value |
+ QOpcUa::NodeAttribute::ValueRank | QOpcUa::NodeAttribute::ArrayDimensions |
+ QOpcUa::NodeAttribute::MinimumSamplingInterval | QOpcUa::NodeAttribute::Historizing);
readSpy.wait(signalSpyTimeout);
QCOMPARE(readSpy.size(), 1);
@@ -1497,11 +1591,537 @@ void Tst_QOpcUaClient::addAndRemoveVariableNode()
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::DisplayName), QOpcUa::UaStatusCode::Good);
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Value), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::ValueRank), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::ArrayDimensions), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::MinimumSamplingInterval), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Historizing), QOpcUa::UaStatusCode::Good);
+
+
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaMultiDimensionalArray>().valueArray(), QVariantList({1, 2, 3, 4}));
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::ValueRank), 2);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::ArrayDimensions).toList(), QVariantList({ 2, 2 }));
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::MinimumSamplingInterval).toDouble(), 23.0);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Historizing), true);
+
+ QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
+ opcuaClient->deleteNode(requestedNewId.nodeId(), true);
+ removeNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(removeNodeSpy.size(), 1);
+ QCOMPARE(removeNodeSpy.at(0).at(0), requestedNewId.nodeId());
+ QCOMPARE(removeNodeSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> node(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(node != nullptr);
+
+ QSignalSpy unsuccessfulReadSpy(node.data(), &QOpcUaNode::attributeRead);
+
+ node->readAttributes(QOpcUa::NodeAttribute::NodeId);
+ unsuccessfulReadSpy.wait(signalSpyTimeout);
+ QCOMPARE(unsuccessfulReadSpy.size(), 1);
+ QVERIFY(unsuccessfulReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>() & QOpcUa::NodeAttribute::NodeId);
+ QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::NodeId), QOpcUa::UaStatusCode::BadNodeIdUnknown);
+}
+
+void Tst_QOpcUaClient::addAndRemoveMethodNode()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QSignalSpy addNodeSpy(opcuaClient, &QOpcUaClient::addNodeFinished);
+
+ QOpcUaExpandedNodeId parent;
+ parent.setNodeId(QStringLiteral("ns=3;s=TestFolder"));
+ QOpcUaExpandedNodeId requestedNewId;
+ requestedNewId.setNodeId(QStringLiteral("ns=3;s=DynamicMethodNode_%1").arg(opcuaClient->backend()));
+ const quint16 namespaceIndex = 3;
+ QOpcUaQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicMethodNode_%1").arg(opcuaClient->backend()));
+
+ QOpcUaNodeCreationAttributes attributes;
+
+ QOpcUaLocalizedText displayName("en", browseName.name());
+ QOpcUaLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
+
+ attributes.setDisplayName(displayName);
+ attributes.setDescription(description);
+ attributes.setExecutable(true);
+ attributes.setUserExecutable(true);
+
+ QOpcUaAddNodeItem nodeInfo;
+ nodeInfo.setParentNodeId(parent);
+ nodeInfo.setReferenceTypeId(QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId::Organizes));
+ nodeInfo.setRequestedNewNodeId(requestedNewId);
+ nodeInfo.setBrowseName(browseName);
+ nodeInfo.setNodeClass(QOpcUa::NodeClass::Method);
+ nodeInfo.setNodeAttributes(attributes);
+
+ opcuaClient->addNode(nodeInfo);
+
+ addNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(addNodeSpy.size(), 1);
+
+ QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUaExpandedNodeId>().nodeId(), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(1), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> newNode(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(newNode != nullptr);
+
+ QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
+ newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName |
+ QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::Executable |
+ QOpcUa::NodeAttribute::UserExecutable);
+ readSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(readSpy.size(), 1);
+
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::BrowseName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::DisplayName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Executable), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::UserExecutable), QOpcUa::UaStatusCode::Good);
+
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Executable), true);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::UserExecutable), true);
+
+ QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
+ opcuaClient->deleteNode(requestedNewId.nodeId(), true);
+ removeNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(removeNodeSpy.size(), 1);
+ QCOMPARE(removeNodeSpy.at(0).at(0), requestedNewId.nodeId());
+ QCOMPARE(removeNodeSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> node(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(node != nullptr);
+
+ QSignalSpy unsuccessfulReadSpy(node.data(), &QOpcUaNode::attributeRead);
+
+ node->readAttributes(QOpcUa::NodeAttribute::NodeId);
+ unsuccessfulReadSpy.wait(signalSpyTimeout);
+ QCOMPARE(unsuccessfulReadSpy.size(), 1);
+ QVERIFY(unsuccessfulReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>() & QOpcUa::NodeAttribute::NodeId);
+ QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::NodeId), QOpcUa::UaStatusCode::BadNodeIdUnknown);
+}
+
+void Tst_QOpcUaClient::addAndRemoveObjectTypeNode()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QSignalSpy addNodeSpy(opcuaClient, &QOpcUaClient::addNodeFinished);
+
+ QOpcUaExpandedNodeId parent;
+ parent.setNodeId(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::BaseObjectType));
+ QOpcUaExpandedNodeId requestedNewId;
+ requestedNewId.setNodeId(QStringLiteral("ns=3;s=DynamicObjectTypeNode_%1").arg(opcuaClient->backend()));
+ const quint16 namespaceIndex = 3;
+ QOpcUaQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicObjectTypeNode_%1").arg(opcuaClient->backend()));
+
+ QOpcUaNodeCreationAttributes attributes;
+
+ QOpcUaLocalizedText displayName("en", browseName.name());
+ QOpcUaLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
+
+ attributes.setDisplayName(displayName);
+ attributes.setDescription(description);
+ attributes.setIsAbstract(true);
+
+ QOpcUaAddNodeItem nodeInfo;
+ nodeInfo.setParentNodeId(parent);
+ nodeInfo.setReferenceTypeId(QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId::HasSubtype));
+ nodeInfo.setRequestedNewNodeId(requestedNewId);
+ nodeInfo.setBrowseName(browseName);
+ nodeInfo.setNodeClass(QOpcUa::NodeClass::ObjectType);
+ nodeInfo.setNodeAttributes(attributes);
+
+ opcuaClient->addNode(nodeInfo);
+
+ addNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(addNodeSpy.size(), 1);
+
+ QCOMPARE(addNodeSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUaExpandedNodeId>().nodeId(), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(1), requestedNewId.nodeId());
+
+ QScopedPointer<QOpcUaNode> newNode(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(newNode != nullptr);
+
+ QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
+ newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName |
+ QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::IsAbstract);
+ readSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(readSpy.size(), 1);
+
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::BrowseName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::DisplayName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::IsAbstract), QOpcUa::UaStatusCode::Good);
QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
- QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Value).toDouble(), 23.0);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::IsAbstract), true);
+
+ QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
+ opcuaClient->deleteNode(requestedNewId.nodeId(), true);
+ removeNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(removeNodeSpy.size(), 1);
+ QCOMPARE(removeNodeSpy.at(0).at(0), requestedNewId.nodeId());
+ QCOMPARE(removeNodeSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> node(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(node != nullptr);
+
+ QSignalSpy unsuccessfulReadSpy(node.data(), &QOpcUaNode::attributeRead);
+
+ node->readAttributes(QOpcUa::NodeAttribute::NodeId);
+ unsuccessfulReadSpy.wait(signalSpyTimeout);
+ QCOMPARE(unsuccessfulReadSpy.size(), 1);
+ QVERIFY(unsuccessfulReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>() & QOpcUa::NodeAttribute::NodeId);
+ QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::NodeId), QOpcUa::UaStatusCode::BadNodeIdUnknown);
+}
+
+void Tst_QOpcUaClient::addAndRemoveVariableTypeNode()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QSignalSpy addNodeSpy(opcuaClient, &QOpcUaClient::addNodeFinished);
+
+ QOpcUaExpandedNodeId parent;
+ parent.setNodeId(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::BaseVariableType));
+ QOpcUaExpandedNodeId requestedNewId;
+ requestedNewId.setNodeId(QStringLiteral("ns=3;s=DynamicVariableTypeNode_%1").arg(opcuaClient->backend()));
+ const quint16 namespaceIndex = 3;
+ QOpcUaQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicVariableTypeNode_%1").arg(opcuaClient->backend()));
+
+ QOpcUaNodeCreationAttributes attributes;
+
+ QOpcUaLocalizedText displayName("en", browseName.name());
+ QOpcUaLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
+
+ attributes.setDisplayName(displayName);
+ attributes.setDescription(description);
+ attributes.setValue(QOpcUaMultiDimensionalArray({1,2,3,4}, {2,2}), QOpcUa::Types::Double);
+ attributes.setDataTypeId(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::Double));
+ attributes.setValueRank(2); // Two-dimensional array
+ attributes.setArrayDimensions({ 2, 2 });
+ attributes.setIsAbstract(true);
+
+ attributes.setAccessLevel(QOpcUa::AccessLevelBit::CurrentRead);
+ attributes.setUserAccessLevel(QOpcUa::AccessLevelBit::CurrentRead);
+
+ QOpcUaAddNodeItem nodeInfo;
+ nodeInfo.setParentNodeId(parent);
+ nodeInfo.setReferenceTypeId(QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId::HasSubtype));
+ nodeInfo.setRequestedNewNodeId(requestedNewId);
+ nodeInfo.setBrowseName(browseName);
+ nodeInfo.setNodeClass(QOpcUa::NodeClass::VariableType);
+ nodeInfo.setNodeAttributes(attributes);
+
+ opcuaClient->addNode(nodeInfo);
+
+ addNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(addNodeSpy.size(), 1);
+
+ QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUaExpandedNodeId>().nodeId(), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(1), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> newNode(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(newNode != nullptr);
+
+ QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
+ newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName |
+ QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::Value |
+ QOpcUa::NodeAttribute::ValueRank | QOpcUa::NodeAttribute::ArrayDimensions |
+ QOpcUa::NodeAttribute::IsAbstract);
+ readSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(readSpy.size(), 1);
+
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::BrowseName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::DisplayName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Value), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::ValueRank), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::ArrayDimensions), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::IsAbstract), QOpcUa::UaStatusCode::Good);
+
+
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Value).value<QOpcUaMultiDimensionalArray>().valueArray(), QVariantList({1, 2, 3, 4}));
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::ValueRank), 2);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::ArrayDimensions).toList(), QVariantList({ 2, 2 }));
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::IsAbstract), true);
+
+ QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
+ opcuaClient->deleteNode(requestedNewId.nodeId(), true);
+ removeNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(removeNodeSpy.size(), 1);
+ QCOMPARE(removeNodeSpy.at(0).at(0), requestedNewId.nodeId());
+ QCOMPARE(removeNodeSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> node(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(node != nullptr);
+
+ QSignalSpy unsuccessfulReadSpy(node.data(), &QOpcUaNode::attributeRead);
+
+ node->readAttributes(QOpcUa::NodeAttribute::NodeId);
+ unsuccessfulReadSpy.wait(signalSpyTimeout);
+ QCOMPARE(unsuccessfulReadSpy.size(), 1);
+ QVERIFY(unsuccessfulReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>() & QOpcUa::NodeAttribute::NodeId);
+ QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::NodeId), QOpcUa::UaStatusCode::BadNodeIdUnknown);
+}
+
+void Tst_QOpcUaClient::addAndRemoveReferenceTypeNode()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QSignalSpy addNodeSpy(opcuaClient, &QOpcUaClient::addNodeFinished);
+
+ QOpcUaExpandedNodeId parent;
+ parent.setNodeId(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::Organizes));
+ QOpcUaExpandedNodeId requestedNewId;
+ requestedNewId.setNodeId(QStringLiteral("ns=3;s=DynamicReferenceTypeNode_%1").arg(opcuaClient->backend()));
+ const quint16 namespaceIndex = 3;
+ QOpcUaQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicReferenceTypeNode_%1").arg(opcuaClient->backend()));
+
+ QOpcUaNodeCreationAttributes attributes;
+
+ QOpcUaLocalizedText displayName("en", browseName.name());
+ QOpcUaLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
+
+ attributes.setDisplayName(displayName);
+ attributes.setDescription(description);
+ attributes.setIsAbstract(true);
+ attributes.setSymmetric(true);
+ attributes.setInverseName({ "en", "Inverse name"});
+
+ QOpcUaAddNodeItem nodeInfo;
+ nodeInfo.setParentNodeId(parent);
+ nodeInfo.setReferenceTypeId(QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId::HasSubtype));
+ nodeInfo.setRequestedNewNodeId(requestedNewId);
+ nodeInfo.setBrowseName(browseName);
+ nodeInfo.setNodeClass(QOpcUa::NodeClass::ReferenceType);
+ nodeInfo.setNodeAttributes(attributes);
+
+ opcuaClient->addNode(nodeInfo);
+
+ addNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(addNodeSpy.size(), 1);
+
+ QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUaExpandedNodeId>().nodeId(), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(1), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> newNode(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(newNode != nullptr);
+
+ QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
+ newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName |
+ QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::IsAbstract |
+ QOpcUa::NodeAttribute::Symmetric | QOpcUa::NodeAttribute::InverseName);
+ readSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(readSpy.size(), 1);
+
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::BrowseName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::DisplayName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::IsAbstract), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Symmetric), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::InverseName), QOpcUa::UaStatusCode::Good);
+
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::IsAbstract), true);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Symmetric), true);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::InverseName), QOpcUaLocalizedText("en", "Inverse name"));
+
+ QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
+ opcuaClient->deleteNode(requestedNewId.nodeId(), true);
+ removeNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(removeNodeSpy.size(), 1);
+ QCOMPARE(removeNodeSpy.at(0).at(0), requestedNewId.nodeId());
+ QCOMPARE(removeNodeSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> node(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(node != nullptr);
+
+ QSignalSpy unsuccessfulReadSpy(node.data(), &QOpcUaNode::attributeRead);
+
+ node->readAttributes(QOpcUa::NodeAttribute::NodeId);
+ unsuccessfulReadSpy.wait(signalSpyTimeout);
+ QCOMPARE(unsuccessfulReadSpy.size(), 1);
+ QVERIFY(unsuccessfulReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>() & QOpcUa::NodeAttribute::NodeId);
+ QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::NodeId), QOpcUa::UaStatusCode::BadNodeIdUnknown);
+}
+
+void Tst_QOpcUaClient::addAndRemoveDataTypeNode()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QSignalSpy addNodeSpy(opcuaClient, &QOpcUaClient::addNodeFinished);
+
+ QOpcUaExpandedNodeId parent;
+ parent.setNodeId(QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::BaseDataType));
+ QOpcUaExpandedNodeId requestedNewId;
+ requestedNewId.setNodeId(QStringLiteral("ns=3;s=DynamicDataTypeNode_%1").arg(opcuaClient->backend()));
+ const quint16 namespaceIndex = 3;
+ QOpcUaQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicDataTypeNode_%1").arg(opcuaClient->backend()));
+
+ QOpcUaNodeCreationAttributes attributes;
+
+ QOpcUaLocalizedText displayName("en", browseName.name());
+ QOpcUaLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
+
+ attributes.setDisplayName(displayName);
+ attributes.setDescription(description);
+ attributes.setIsAbstract(true);
+
+ QOpcUaAddNodeItem nodeInfo;
+ nodeInfo.setParentNodeId(parent);
+ nodeInfo.setReferenceTypeId(QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId::HasSubtype));
+ nodeInfo.setRequestedNewNodeId(requestedNewId);
+ nodeInfo.setBrowseName(browseName);
+ nodeInfo.setNodeClass(QOpcUa::NodeClass::DataType);
+ nodeInfo.setNodeAttributes(attributes);
+
+ opcuaClient->addNode(nodeInfo);
+
+ addNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(addNodeSpy.size(), 1);
+
+ QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUaExpandedNodeId>().nodeId(), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(1), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> newNode(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(newNode != nullptr);
+
+ QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
+ newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName |
+ QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::IsAbstract);
+ readSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(readSpy.size(), 1);
+
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::BrowseName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::DisplayName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::IsAbstract), QOpcUa::UaStatusCode::Good);
+
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::IsAbstract), true);
+
+ QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
+ opcuaClient->deleteNode(requestedNewId.nodeId(), true);
+ removeNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(removeNodeSpy.size(), 1);
+ QCOMPARE(removeNodeSpy.at(0).at(0), requestedNewId.nodeId());
+ QCOMPARE(removeNodeSpy.at(0).at(1).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> node(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(node != nullptr);
+
+ QSignalSpy unsuccessfulReadSpy(node.data(), &QOpcUaNode::attributeRead);
+
+ node->readAttributes(QOpcUa::NodeAttribute::NodeId);
+ unsuccessfulReadSpy.wait(signalSpyTimeout);
+ QCOMPARE(unsuccessfulReadSpy.size(), 1);
+ QVERIFY(unsuccessfulReadSpy.at(0).at(0).value<QOpcUa::NodeAttributes>() & QOpcUa::NodeAttribute::NodeId);
+ QCOMPARE(node->attributeError(QOpcUa::NodeAttribute::NodeId), QOpcUa::UaStatusCode::BadNodeIdUnknown);
+}
+
+void Tst_QOpcUaClient::addAndRemoveViewNode()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QSignalSpy addNodeSpy(opcuaClient, &QOpcUaClient::addNodeFinished);
+
+ QOpcUaExpandedNodeId parent;
+ parent.setNodeId(QStringLiteral("ns=3;s=TestFolder"));
+ QOpcUaExpandedNodeId requestedNewId;
+ requestedNewId.setNodeId(QStringLiteral("ns=3;s=DynamicViewNode_%1").arg(opcuaClient->backend()));
+ const quint16 namespaceIndex = 3;
+ QOpcUaQualifiedName browseName(namespaceIndex, QStringLiteral("DynamicViewNode_%1").arg(opcuaClient->backend()));
+
+ QOpcUaNodeCreationAttributes attributes;
+
+ QOpcUaLocalizedText displayName("en", browseName.name());
+ QOpcUaLocalizedText description("en", QStringLiteral("Node added at runtime by %1").arg(opcuaClient->backend()));
+
+ attributes.setDisplayName(displayName);
+ attributes.setDescription(description);
+ attributes.setContainsNoLoops(true);
+ attributes.setEventNotifier(QOpcUa::EventNotifierBit::SubscribeToEvents);
+
+ QOpcUaAddNodeItem nodeInfo;
+ nodeInfo.setParentNodeId(parent);
+ nodeInfo.setReferenceTypeId(QOpcUa::nodeIdFromReferenceType(QOpcUa::ReferenceTypeId::Organizes));
+ nodeInfo.setRequestedNewNodeId(requestedNewId);
+ nodeInfo.setBrowseName(browseName);
+ nodeInfo.setNodeClass(QOpcUa::NodeClass::View);
+ nodeInfo.setNodeAttributes(attributes);
+
+ opcuaClient->addNode(nodeInfo);
+
+ addNodeSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(addNodeSpy.size(), 1);
+
+ QCOMPARE(addNodeSpy.at(0).at(0).value<QOpcUaExpandedNodeId>().nodeId(), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(1), requestedNewId.nodeId());
+ QCOMPARE(addNodeSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
+
+ QScopedPointer<QOpcUaNode> newNode(opcuaClient->node(requestedNewId.nodeId()));
+ QVERIFY(newNode != nullptr);
+
+ QSignalSpy readSpy(newNode.data(), &QOpcUaNode::attributeRead);
+ newNode->readAttributes(QOpcUa::NodeAttribute::BrowseName | QOpcUa::NodeAttribute::DisplayName |
+ QOpcUa::NodeAttribute::Description | QOpcUa::NodeAttribute::ContainsNoLoops |
+ QOpcUa::NodeAttribute::EventNotifier);
+ readSpy.wait(signalSpyTimeout);
+
+ QCOMPARE(readSpy.size(), 1);
+
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::BrowseName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::DisplayName), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::Description), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::ContainsNoLoops), QOpcUa::UaStatusCode::Good);
+ QCOMPARE(newNode->attributeError(QOpcUa::NodeAttribute::EventNotifier), QOpcUa::UaStatusCode::Good);
+
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::BrowseName).value<QOpcUaQualifiedName>(), browseName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::DisplayName).value<QOpcUaLocalizedText>(), displayName);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::Description).value<QOpcUaLocalizedText>(), description);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::ContainsNoLoops), true);
+ QCOMPARE(newNode->attribute(QOpcUa::NodeAttribute::EventNotifier), true);
QSignalSpy removeNodeSpy(opcuaClient, &QOpcUaClient::deleteNodeFinished);
opcuaClient->deleteNode(requestedNewId.nodeId(), true);
@@ -1610,6 +2230,21 @@ void Tst_QOpcUaClient::addAndRemoveReference()
for (auto item : results)
QVERIFY(item.targetNodeId().nodeId() != target.nodeId());
}
+
+ // Check error paths
+ addReferenceSpy.clear();
+ refInfo.setTargetNodeId(QOpcUaExpandedNodeId("ns=42;i=1234"));
+ opcuaClient->addReference(refInfo);
+ addReferenceSpy.wait(signalSpyTimeout);
+ QCOMPARE(addReferenceSpy.size(), 1);
+ QCOMPARE(addReferenceSpy.at(0).at(4), QOpcUa::UaStatusCode::BadTargetNodeIdInvalid);
+
+ deleteReferenceSpy.clear();
+ refDelInfo.setTargetNodeId(QOpcUaExpandedNodeId("ns=42;i=1234"));
+ opcuaClient->deleteReference(refDelInfo);
+ deleteReferenceSpy.wait(signalSpyTimeout);
+ QCOMPARE(deleteReferenceSpy.size(), 1);
+ QCOMPARE(addReferenceSpy.at(0).at(4), QOpcUa::UaStatusCode::BadTargetNodeIdInvalid);
}
void Tst_QOpcUaClient::dataChangeSubscription()
@@ -3712,6 +4347,38 @@ void Tst_QOpcUaClient::checkValueAttributeUpdated()
QCOMPARE(spy.at(2).at(0), 23.0);
}
+void Tst_QOpcUaClient::checkMonitoringInvalidRequests()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QScopedPointer<QOpcUaNode> node(opcuaClient->node("ns=3;s=TestNode.ReadWrite"));
+
+ QSignalSpy enableMonitoringSpy(node.get(), &QOpcUaNode::enableMonitoringFinished);
+
+ // Explicit subscription id without existing subscription
+ QOpcUaMonitoringParameters param(200);
+ param.setSubscriptionId(42);
+ node->enableMonitoring(QOpcUa::NodeAttribute::Value, param);
+ enableMonitoringSpy.wait(signalSpyTimeout);
+ QCOMPARE(enableMonitoringSpy.size(), 1);
+ QCOMPARE(enableMonitoringSpy.at(0).at(1), QOpcUa::UaStatusCode::BadSubscriptionIdInvalid);
+
+ // Attempt to modify a monitoring that doesn't exist
+ QSignalSpy monitoringChangedSpy(node.get(), &QOpcUaNode::monitoringStatusChanged);
+ node->modifyMonitoring(QOpcUa::NodeAttribute::Value, QOpcUaMonitoringParameters::Parameter::QueueSize, 23);
+ monitoringChangedSpy.wait(signalSpyTimeout);
+ QCOMPARE(monitoringChangedSpy.size(), 1);
+ qDebug() << monitoringChangedSpy;
+ QCOMPARE(monitoringChangedSpy.at(0).at(2), QOpcUa::UaStatusCode::BadMonitoredItemIdInvalid);
+
+ QSignalSpy disableMonitoringSpy(node.get(), &QOpcUaNode::disableMonitoringFinished);
+ node->disableMonitoring(QOpcUa::NodeAttribute::Value);
+ disableMonitoringSpy.wait(signalSpyTimeout);
+ QCOMPARE(disableMonitoringSpy.size(), 1);
+ QCOMPARE(disableMonitoringSpy.at(0).at(1), QOpcUa::UaStatusCode::BadMonitoredItemIdInvalid);
+}
+
void Tst_QOpcUaClient::stringCharset()
{
QFETCH(QOpcUaClient *, opcuaClient);
@@ -3996,6 +4663,22 @@ void Tst_QOpcUaClient::checkExpandedIdConversion()
result = opcuaClient->resolveExpandedNodeId(id, &ok);
QVERIFY(ok == false);
QCOMPARE(result, QString());
+
+ // Resolving id on different server is expected to fail
+ ok = false;
+ id.setNodeId("ns=0;s=TestNode.ReadWrite");
+ id.setNamespaceUri(QStringLiteral("Test Namespace"));
+ id.setServerIndex(42);
+ result = opcuaClient->resolveExpandedNodeId(id, &ok);
+ QVERIFY(ok == false);
+
+ // Invalid node id is expected to fail
+ ok = false;
+ id.setNodeId("xxxxxxxxxxx");
+ id.setServerIndex(0);
+ id.setNamespaceUri(QStringLiteral("Test Namespace"));
+ result = opcuaClient->resolveExpandedNodeId(id, &ok);
+ QVERIFY(ok == false);
}
void Tst_QOpcUaClient::checkExpandedIdConversionNoOk()
@@ -4039,6 +4722,20 @@ void Tst_QOpcUaClient::checkExpandedIdConversionNoOk()
id.setNodeId("ns=0,s=TestNode.ReadWrite");
result = opcuaClient->resolveExpandedNodeId(id);
QCOMPARE(result, QString());
+
+ // Resolving id on different server is expected to fail
+ id.setNodeId("ns=0;s=TestNode.ReadWrite");
+ id.setNamespaceUri(QStringLiteral("Test Namespace"));
+ id.setServerIndex(42);
+ result = opcuaClient->resolveExpandedNodeId(id);
+ QCOMPARE(result, QString());
+
+ // Invalid node id is expected to fail
+ id.setNodeId("xxxxxxxxxxx");
+ id.setNamespaceUri(QStringLiteral("Test Namespace"));
+ id.setServerIndex(0);
+ result = opcuaClient->resolveExpandedNodeId(id);
+ QCOMPARE(result, QString());
}
void Tst_QOpcUaClient::createQualifiedName()
@@ -4119,6 +4816,7 @@ void Tst_QOpcUaClient::resolveBrowsePath()
QCOMPARE(results.at(0).remainingPathIndex(), (std::numeric_limits<quint32>::max)());
QCOMPARE(results.at(0).targetId().nodeId(), QOpcUa::namespace0Id(QOpcUa::NodeIds::Namespace0::BaseDataType));
QVERIFY(results.at(0).targetId().namespaceUri().isEmpty());
+ QCOMPARE(results.at(0).isFullyResolved(), true);
QCOMPARE(results.at(0).targetId().serverIndex(), 0U);
QCOMPARE(spy.at(0).at(1).value<QList<QOpcUaRelativePathElement>>(), path);
QCOMPARE(spy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::Good);
@@ -5254,6 +5952,13 @@ void Tst_QOpcUaClient::cleanupTestCase()
}
}
+void Tst_QOpcUaClient::loadInvalidPlugin()
+{
+ QOpcUaProvider provider;
+ QScopedPointer<QOpcUaClient> client(provider.createClient("doesnotexist"));
+ QCOMPARE(client, nullptr);
+}
+
int main(int argc, char *argv[])
{
populateDataTypeDefinitionTestData();
diff --git a/tests/open62541-testserver/testserver.cpp b/tests/open62541-testserver/testserver.cpp
index cc01bcf..933772b 100644
--- a/tests/open62541-testserver/testserver.cpp
+++ b/tests/open62541-testserver/testserver.cpp
@@ -240,6 +240,8 @@ bool TestServer::init()
success = createInsecureServerConfig(m_config);
#endif
+ m_config->maxReferencesPerNode = 10;
+
m_gathering = UA_HistoryDataGathering_Default(1);
m_config->historyDatabase = UA_HistoryDatabase_default(m_gathering);