diff options
author | Jannis Voelker <jannis.voelker@basyskom.com> | 2017-11-27 15:33:37 +0100 |
---|---|---|
committer | Frank Meerkoetter <frank.meerkoetter@basyskom.com> | 2017-12-14 13:28:00 +0000 |
commit | 4a4b01633618736cb0d851a5719b64e5b6640a0d (patch) | |
tree | b1912db19b50152fb986ce0fc74ab661b02ee1e9 /tests | |
parent | 28f2c5d6bc152948a3ce7f22e55db9afcaba1d3c (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.cpp | 54 | ||||
-rw-r--r-- | tests/open62541-testserver/main.cpp | 1 | ||||
-rw-r--r-- | tests/open62541-testserver/open62541-testserver.pro | 2 | ||||
-rw-r--r-- | tests/open62541-testserver/testserver.cpp | 74 | ||||
-rw-r--r-- | tests/open62541-testserver/testserver.h | 8 |
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}; |