summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorJannis Voelker <jannis.voelker@basyskom.com>2017-11-27 15:33:37 +0100
committerFrank Meerkoetter <frank.meerkoetter@basyskom.com>2017-12-14 13:28:00 +0000
commit4a4b01633618736cb0d851a5719b64e5b6640a0d (patch)
treeb1912db19b50152fb986ce0fc74ab661b02ee1e9 /tests
parent28f2c5d6bc152948a3ce7f22e55db9afcaba1d3c (diff)
Add an async API for method calls
Methods are called using callMethod() on the object node. Results are emitted as methodCallFinished signal. Change-Id: I555cccba3fa006f2fe24fe0e5ed512d4603fa9a7 Reviewed-by: Frank Meerkoetter <frank.meerkoetter@basyskom.com>
Diffstat (limited to 'tests')
-rw-r--r--tests/auto/qopcuaclient/tst_client.cpp54
-rw-r--r--tests/open62541-testserver/main.cpp1
-rw-r--r--tests/open62541-testserver/open62541-testserver.pro2
-rw-r--r--tests/open62541-testserver/testserver.cpp74
-rw-r--r--tests/open62541-testserver/testserver.h8
5 files changed, 133 insertions, 6 deletions
diff --git a/tests/auto/qopcuaclient/tst_client.cpp b/tests/auto/qopcuaclient/tst_client.cpp
index ad5e7eb..a977cd3 100644
--- a/tests/auto/qopcuaclient/tst_client.cpp
+++ b/tests/auto/qopcuaclient/tst_client.cpp
@@ -175,6 +175,8 @@ private slots:
void dataChangeSubscriptionInvalidNode();
defineDataMethod(methodCall_data)
void methodCall();
+ defineDataMethod(methodCallInvalid_data)
+ void methodCallInvalid();
defineDataMethod(readRange_data)
void readRange();
defineDataMethod(readEui_data)
@@ -714,7 +716,6 @@ void Tst_QOpcUaClient::methodCall()
QFETCH(QOpcUaClient *, opcuaClient);
OpcuaConnector connector(opcuaClient, m_endpoint);
- QSKIP("Method calls are not implemented in open62541-based testserver");
QVector<QOpcUa::TypedVariant> args;
QVector<QVariant> ret;
for (int i = 0; i < 2; i++)
@@ -723,13 +724,54 @@ void Tst_QOpcUaClient::methodCall()
QScopedPointer<QOpcUaNode> node(opcuaClient->node("ns=3;s=TestFolder"));
QVERIFY(node != 0);
- bool success = node->call("ns=0;s=IDoNotExist", &args, &ret);
- QVERIFY(success == false);
+ QSignalSpy methodSpy(node.data(), &QOpcUaNode::methodCallFinished);
- success = node->call("ns=3;s=Test.Method.Multiply", &args, &ret);
+ bool success = node->callMethod("ns=3;s=Test.Method.Multiply", args);
QVERIFY(success == true);
- QVERIFY(ret.size() == 1);
- QVERIFY(ret[0].type() == QVariant::Double && ret[0].value<double>() == 16);
+
+ methodSpy.wait();
+
+ QCOMPARE(methodSpy.size(), 1);
+ QCOMPARE(methodSpy.at(0).at(0), QStringLiteral("ns=3;s=Test.Method.Multiply"));
+ QCOMPARE(methodSpy.at(0).at(1), double(16));
+ QCOMPARE(QOpcUa::isSuccessStatus(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>()), true);
+}
+
+void Tst_QOpcUaClient::methodCallInvalid()
+{
+ QFETCH(QOpcUaClient *, opcuaClient);
+ OpcuaConnector connector(opcuaClient, m_endpoint);
+
+ QVector<QOpcUa::TypedVariant> args;
+ QVector<QVariant> ret;
+ for (int i = 0; i < 3; i++)
+ args.push_back(QOpcUa::TypedVariant(double(4), QOpcUa::Double));
+
+ QScopedPointer<QOpcUaNode> node(opcuaClient->node("ns=3;s=TestFolder"));
+ QVERIFY(node != 0);
+
+ QSignalSpy methodSpy(node.data(), &QOpcUaNode::methodCallFinished);
+
+ bool success = node->callMethod("ns=3;s=Test.Method.Divide", args); // Does not exist
+ QVERIFY(success == true);
+ methodSpy.wait();
+ QCOMPARE(methodSpy.size(), 1);
+ QCOMPARE(QOpcUa::errorCategory(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>()), QOpcUa::ErrorCategory::NodeError);
+
+ methodSpy.clear();
+ success = node->callMethod("ns=3;s=Test.Method.Multiply", args); // One excess argument
+ QVERIFY(success == true);
+ methodSpy.wait();
+ QCOMPARE(methodSpy.size(), 1);
+ QCOMPARE(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::BadInvalidArgument);
+
+ methodSpy.clear();
+ args.resize(1);
+ success = node->callMethod("ns=3;s=Test.Method.Multiply", args); // One argument missing
+ QVERIFY(success == true);
+ methodSpy.wait();
+ QCOMPARE(methodSpy.size(), 1);
+ QCOMPARE(methodSpy.at(0).at(2).value<QOpcUa::UaStatusCode>(), QOpcUa::UaStatusCode::BadArgumentsMissing);
}
void Tst_QOpcUaClient::readRange()
diff --git a/tests/open62541-testserver/main.cpp b/tests/open62541-testserver/main.cpp
index 9821784..0f48af2 100644
--- a/tests/open62541-testserver/main.cpp
+++ b/tests/open62541-testserver/main.cpp
@@ -144,6 +144,7 @@ int main(int argc, char **argv)
});
tickTimer.start();
+ server.addMethod(testFolder, "ns=3;s=Test.Method.Multiply", "MultiplyDoubles");
return app.exec();
}
diff --git a/tests/open62541-testserver/open62541-testserver.pro b/tests/open62541-testserver/open62541-testserver.pro
index 1c39962..50501a1 100644
--- a/tests/open62541-testserver/open62541-testserver.pro
+++ b/tests/open62541-testserver/open62541-testserver.pro
@@ -8,6 +8,8 @@ DEPENDPATH += INCLUDEPATH
CONFIG += c++11 console
+QT += opcua
+
QMAKE_USE_PRIVATE += open62541
win32: DESTDIR = ./
diff --git a/tests/open62541-testserver/testserver.cpp b/tests/open62541-testserver/testserver.cpp
index 1c5d96d..58d135f 100644
--- a/tests/open62541-testserver/testserver.cpp
+++ b/tests/open62541-testserver/testserver.cpp
@@ -36,6 +36,7 @@
#include "testserver.h"
#include "qopen62541utils.h"
+#include <QtOpcUa/qopcuatype.h>
#include <QtCore/QDebug>
#include <QtCore/QLoggingCategory>
@@ -495,6 +496,79 @@ UA_NodeId TestServer::addVariable<UA_StatusCode, UA_StatusCode, UA_TYPES_STATUSC
return resultId;
}
+UA_StatusCode TestServer::multiplyMethod(UA_Server *server, const UA_NodeId *sessionId, void *sessionHandle, const UA_NodeId *methodId, void *methodContext, const UA_NodeId *objectId, void *objectContext, size_t inputSize, const UA_Variant *input, size_t outputSize, UA_Variant *output)
+{
+ Q_UNUSED(server);
+ Q_UNUSED(sessionId);
+ Q_UNUSED(sessionHandle);
+ Q_UNUSED(methodId);
+ Q_UNUSED(methodContext);
+ Q_UNUSED(objectId);
+ Q_UNUSED(objectContext);
+
+ if (inputSize < 2)
+ return QOpcUa::UaStatusCode::BadArgumentsMissing;
+ if (inputSize > 2)
+ return QOpcUa::UaStatusCode::BadTooManyArguments;
+ if (outputSize != 1)
+ return QOpcUa::UaStatusCode::BadInvalidArgument;
+
+ double arg1 = *static_cast<double *>(input[0].data);
+ double arg2 = *static_cast<double *>(input[1].data);
+
+ double temp = arg1 * arg2;
+ UA_Variant_setScalarCopy(output, &temp, &UA_TYPES[UA_TYPES_DOUBLE]);
+
+ return UA_STATUSCODE_GOOD;
+}
+
+UA_NodeId TestServer::addMethod(const UA_NodeId &folder, const QString &variableNode, const QString &description)
+{
+ UA_NodeId methodNodeId = Open62541Utils::nodeIdFromQString(variableNode);
+
+ UA_Argument inputArguments[2];
+ UA_Argument_init(&inputArguments[0]);
+ UA_Argument_init(&inputArguments[1]);
+
+ inputArguments[0].description = UA_LOCALIZEDTEXT_ALLOC("en", "First value");
+ inputArguments[0].name = UA_STRING_ALLOC("The first double");
+ inputArguments[0].dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
+ inputArguments[0].valueRank = -1;
+
+ inputArguments[1].description = UA_LOCALIZEDTEXT_ALLOC("en", "Second value");
+ inputArguments[1].name = UA_STRING_ALLOC("The second double");
+ inputArguments[1].dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
+ inputArguments[1].valueRank = -1;
+
+ UA_Argument outputArgument;
+ UA_Argument_init(&outputArgument);
+
+ outputArgument.description = UA_LOCALIZEDTEXT_ALLOC("en", "The product of the two arguments");
+ outputArgument.name = UA_STRING_ALLOC("The product of the two arguments");
+ outputArgument.dataType = UA_TYPES[UA_TYPES_DOUBLE].typeId;
+ outputArgument.valueRank = -1;
+
+ UA_MethodAttributes attr = UA_MethodAttributes_default;
+
+ attr.description = UA_LOCALIZEDTEXT_ALLOC("en_US", description.toUtf8().constData());
+ attr.displayName = UA_LOCALIZEDTEXT_ALLOC("en_US", variableNode.toUtf8().constData());
+ attr.executable = true;
+
+ UA_NodeId resultId;
+ UA_StatusCode result = UA_Server_addMethodNode(m_server, methodNodeId, folder,
+ UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+ UA_QUALIFIEDNAME_ALLOC(methodNodeId.namespaceIndex, "multiplyArguments"),
+ attr, &multiplyMethod,
+ 2, inputArguments,
+ 1, &outputArgument,
+ NULL, &resultId);
+ if (result != UA_STATUSCODE_GOOD) {
+ qWarning() << "Could not add variable:" << result;
+ return UA_NODEID_NULL;
+ }
+ return resultId;
+}
+
template UA_NodeId TestServer::addVariable<UA_Double, double, UA_TYPES_DOUBLE>(const UA_NodeId &, const QString &, const QString &, double);
template UA_NodeId TestServer::addVariable<UA_Boolean, bool, UA_TYPES_BOOLEAN>(const UA_NodeId &, const QString &, const QString &, bool);
template UA_NodeId TestServer::addVariable<UA_Byte, uchar, UA_TYPES_BYTE>(const UA_NodeId &, const QString &, const QString &, uchar);
diff --git a/tests/open62541-testserver/testserver.h b/tests/open62541-testserver/testserver.h
index 44d19a3..2043848 100644
--- a/tests/open62541-testserver/testserver.h
+++ b/tests/open62541-testserver/testserver.h
@@ -59,6 +59,14 @@ public:
template <typename UA_TYPE_VALUE, typename QTYPE, int UA_TYPE_IDENTIFIER>
UA_NodeId addVariable(const UA_NodeId &folder, const QString &variableNode, const QString &description, QTYPE value);
+ UA_NodeId addMethod(const UA_NodeId &folder, const QString &variableNode, const QString &description);
+
+ static UA_StatusCode multiplyMethod(UA_Server *server, const UA_NodeId *sessionId, void *sessionHandle,
+ const UA_NodeId *methodId, void *methodContext,
+ const UA_NodeId *objectId, void *objectContext,
+ size_t inputSize, const UA_Variant *input,
+ size_t outputSize, UA_Variant *output);
+
UA_ServerConfig *m_config{nullptr};
UA_Server *m_server{nullptr};
QAtomicInt m_running{false};