blob: b763892cadfddf75b018e10bf4be7e33ce447984 [file] [log] [blame]
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright 2019 (c) basysKom GmbH <opensource@basyskom.com> (Author: Frank Meerkötter)
*/
#include <open62541/server.h>
#include <open62541/server_config_default.h>
#include <open62541/types.h>
#include "server/ua_server_internal.h"
#include "server/ua_services.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include "check.h"
static UA_Server *server = NULL;
static UA_StatusCode
methodCallback(UA_Server *serverArg,
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)
{
return UA_STATUSCODE_GOOD;
}
static void setup(void) {
server = UA_Server_new();
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
UA_MethodAttributes noFpAttr = UA_MethodAttributes_default;
noFpAttr.description = UA_LOCALIZEDTEXT("en-US","No function pointer attached");
noFpAttr.displayName = UA_LOCALIZEDTEXT("en-US","No function pointer attached");
noFpAttr.executable = true;
noFpAttr.userExecutable = true;
UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "nofunctionpointer"),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
UA_QUALIFIEDNAME(1, "No function pointer"),
noFpAttr, NULL, // no callback
0, NULL, 0, NULL, NULL, NULL);
UA_MethodAttributes nonExecAttr = UA_MethodAttributes_default;
nonExecAttr.description = UA_LOCALIZEDTEXT("en-US","Not executable");
nonExecAttr.displayName = UA_LOCALIZEDTEXT("en-US","Not executable");
nonExecAttr.executable = false;
nonExecAttr.userExecutable = true;
UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "nonexec"),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
UA_QUALIFIEDNAME(1, "Not executable"),
nonExecAttr, &methodCallback,
0, NULL, 0, NULL, NULL, NULL);
}
static void teardown(void) {
UA_Server_delete(server);
}
START_TEST(callUnknownMethod) {
const UA_UInt32 UA_NS0ID_UNKNOWN_METHOD = 60000;
UA_CallMethodRequest callMethodRequest;
UA_CallMethodRequest_init(&callMethodRequest);
callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_UNKNOWN_METHOD);
UA_CallMethodResult result;
UA_CallMethodResult_init(&result);
result = UA_Server_call(server, &callMethodRequest);
ck_assert_int_eq(result.statusCode, UA_STATUSCODE_BADNODEIDUNKNOWN);
} END_TEST
START_TEST(callKnownMethodOnUnknownObject) {
const UA_UInt32 UA_NS0ID_UNKNOWN_OBJECT = 60000;
UA_CallMethodRequest callMethodRequest;
UA_CallMethodRequest_init(&callMethodRequest);
callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_REQUESTSERVERSTATECHANGE);
callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_UNKNOWN_OBJECT);
UA_CallMethodResult result;
UA_CallMethodResult_init(&result);
result = UA_Server_call(server, &callMethodRequest);
ck_assert_int_eq(result.statusCode, UA_STATUSCODE_BADNODEIDUNKNOWN);
} END_TEST
START_TEST(callMethodAndObjectExistsButMethodHasWrongNodeClass) {
UA_CallMethodRequest callMethodRequest;
UA_CallMethodRequest_init(&callMethodRequest);
callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS); // not a method
callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
UA_CallMethodResult result;
UA_CallMethodResult_init(&result);
result = UA_Server_call(server, &callMethodRequest);
ck_assert_int_eq(result.statusCode, UA_STATUSCODE_BADNODECLASSINVALID);
} END_TEST
START_TEST(callMethodOnUnrelatedObject) {
/* Minimal nodeset does not add any method nodes we may call here */
#ifdef UA_GENERATED_NAMESPACE_ZERO
UA_CallMethodRequest callMethodRequest;
UA_CallMethodRequest_init(&callMethodRequest);
callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS);
callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); // not connected via hasComponent
UA_CallMethodResult result;
UA_CallMethodResult_init(&result);
result = UA_Server_call(server, &callMethodRequest);
ck_assert_int_eq(result.statusCode, UA_STATUSCODE_BADMETHODINVALID);
#endif
} END_TEST
START_TEST(callMethodAndObjectExistsButNoFunctionPointerAttached) {
UA_CallMethodRequest callMethodRequest;
UA_CallMethodRequest_init(&callMethodRequest);
callMethodRequest.methodId = UA_NODEID_STRING(1, "nofunctionpointer");
callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_CallMethodResult result;
UA_CallMethodResult_init(&result);
result = UA_Server_call(server, &callMethodRequest);
ck_assert_int_eq(result.statusCode, UA_STATUSCODE_BADINTERNALERROR);
} END_TEST
START_TEST(callMethodNonExecutable) {
UA_CallMethodRequest callMethodRequest;
UA_CallMethodRequest_init(&callMethodRequest);
callMethodRequest.methodId = UA_NODEID_STRING(1, "nonexec");
callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_CallMethodResult result;
UA_CallMethodResult_init(&result);
result = UA_Server_call(server, &callMethodRequest);
ck_assert_int_eq(result.statusCode, UA_STATUSCODE_BADNOTEXECUTABLE);
} END_TEST
START_TEST(callMethodWithMissingArguments) {
/* Minimal nodeset does not add any method nodes we may call here */
#ifdef UA_GENERATED_NAMESPACE_ZERO
UA_CallMethodRequest callMethodRequest;
UA_CallMethodRequest_init(&callMethodRequest);
callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS);
callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
UA_CallMethodResult result;
UA_CallMethodResult_init(&result);
result = UA_Server_call(server, &callMethodRequest);
ck_assert_int_eq(result.statusCode, UA_STATUSCODE_BADARGUMENTSMISSING);
#endif
} END_TEST
START_TEST(callMethodWithTooManyArguments) {
/* Minimal nodeset does not add any method nodes we may call here */
#ifdef UA_GENERATED_NAMESPACE_ZERO
UA_Variant inputArguments[2];
UA_Variant_init(&inputArguments[0]);
UA_Variant_init(&inputArguments[1]);
UA_CallMethodRequest callMethodRequest;
UA_CallMethodRequest_init(&callMethodRequest);
callMethodRequest.inputArgumentsSize = 2; // 1 would be correct
callMethodRequest.inputArguments = (UA_Variant*)&inputArguments;
callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS);
callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
UA_CallMethodResult result;
UA_CallMethodResult_init(&result);
result = UA_Server_call(server, &callMethodRequest);
ck_assert_int_eq(result.statusCode, UA_STATUSCODE_BADTOOMANYARGUMENTS);
#endif
} END_TEST
START_TEST(callMethodWithWronglyTypedArguments) {
/* Minimal nodeset does not add any method nodes we may call here */
#ifdef UA_GENERATED_NAMESPACE_ZERO
UA_Variant inputArgument;
UA_Variant_init(&inputArgument);
UA_Double wrongType = 1.0;
UA_Variant_setScalar(&inputArgument, &wrongType, &UA_TYPES[UA_TYPES_DOUBLE]); // UA_UInt32 would be correct
UA_CallMethodRequest callMethodRequest;
UA_CallMethodRequest_init(&callMethodRequest);
callMethodRequest.inputArgumentsSize = 1;
callMethodRequest.inputArguments = &inputArgument;
callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS);
callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
UA_CallMethodResult result;
UA_CallMethodResult_init(&result);
result = UA_Server_call(server, &callMethodRequest);
ck_assert_int_gt(result.inputArgumentResultsSize, 0);
ck_assert_int_eq(result.inputArgumentResults[0], UA_STATUSCODE_BADTYPEMISMATCH);
ck_assert_int_eq(result.statusCode, UA_STATUSCODE_BADINVALIDARGUMENT);
UA_Array_delete(result.inputArgumentResults, result.inputArgumentResultsSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
#endif
} END_TEST
int main(void) {
Suite *s = suite_create("services_call");
TCase *tc_call = tcase_create("call - error branches");
tcase_add_checked_fixture(tc_call, setup, teardown);
tcase_add_test(tc_call, callUnknownMethod);
tcase_add_test(tc_call, callKnownMethodOnUnknownObject);
tcase_add_test(tc_call, callMethodAndObjectExistsButMethodHasWrongNodeClass);
tcase_add_test(tc_call, callMethodAndObjectExistsButNoFunctionPointerAttached);
tcase_add_test(tc_call, callMethodNonExecutable);
tcase_add_test(tc_call, callMethodOnUnrelatedObject);
tcase_add_test(tc_call, callMethodWithMissingArguments);
tcase_add_test(tc_call, callMethodWithTooManyArguments);
tcase_add_test(tc_call, callMethodWithWronglyTypedArguments);
suite_add_tcase(s, tc_call);
SRunner *sr = srunner_create(s);
srunner_set_fork_status(sr, CK_NOFORK);
srunner_run_all(sr, CK_NORMAL);
int number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}