Files
softbus_OPC/third_party/open62541/tests/server/check_server_asyncop.c
2026-06-09 17:27:24 +08:00

345 lines
12 KiB
C

/* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
* See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
/* This example is just to see how fast we can process messages. The server does
not open a TCP port. */
#include <open62541/server_config_default.h>
#include <open62541/server.h>
#include <open62541/client.h>
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel_async.h>
#include <open62541/plugin/log_stdout.h>
#include "testing_clock.h"
#include "thread_wrapper.h"
#include <check.h>
#include <stdlib.h>
UA_Boolean running;
THREAD_HANDLE server_thread;
static UA_Server *server;
static size_t clientCounter;
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
clientReceiveCallback(UA_Client *client, void *userdata,
UA_UInt32 requestId, UA_CallResponse *cr) {
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "Received call response");
clientCounter++;
}
THREAD_CALLBACK(serverloop) {
while(running)
UA_Server_run_iterate(server, true);
return 0;
}
static void setup(void) {
clientCounter = 0;
running = true;
server = UA_Server_new();
ck_assert(server != NULL);
UA_ServerConfig *config = UA_Server_getConfig(server);
UA_ServerConfig_setDefault(config);
config->asyncOperationTimeout = 2000.0; /* 2 seconds */
UA_MethodAttributes methodAttr = UA_MethodAttributes_default;
methodAttr.executable = true;
methodAttr.userExecutable = true;
/* Synchronous Method */
UA_StatusCode res =
UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "method"),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "method"),
methodAttr, &methodCallback,
0, NULL, 0, NULL, NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
/* Asynchronous Method */
res = UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "asyncMethod"),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "asyncMethod"),
methodAttr, &methodCallback,
0, NULL, 0, NULL, NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
res = UA_Server_setMethodNodeAsync(server, UA_NODEID_STRING(1, "asyncMethod"), true);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
UA_Server_run_startup(server);
THREAD_CREATE(server_thread, serverloop);
}
static void teardown(void) {
running = false;
THREAD_JOIN(server_thread);
UA_Server_run_shutdown(server);
UA_Server_delete(server);
}
START_TEST(Async_call) {
UA_Client *client = UA_Client_new();
UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(clientConfig);
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Stop the server thread. Iterate manually from now on */
running = false;
THREAD_JOIN(server_thread);
/* Call async method, then the sync method.
* The sync method returns first. */
retval = UA_Client_call_async(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_STRING(1, "asyncMethod"),
0, NULL, clientReceiveCallback, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
retval = UA_Client_call_async(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_STRING(1, "method"),
0, NULL, clientReceiveCallback, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Receive the answer of the sync call */
while(clientCounter == 0) {
UA_Server_run_iterate(server, true);
UA_Client_run_iterate(client, 0);
}
ck_assert_uint_eq(clientCounter, 1);
/* Process the async method call for the server */
UA_AsyncOperationType aot;
const UA_AsyncOperationRequest *request;
void *context = NULL;
UA_DateTime timeout = 0;
UA_Boolean haveAsync =
UA_Server_getAsyncOperationNonBlocking(server, &aot, &request, &context, &timeout);
ck_assert_uint_eq(haveAsync, true);
UA_AsyncOperationResponse response;
UA_CallMethodResult_init(&response.callMethodResult);
UA_Server_setAsyncOperationResult(server, &response, context);
/* Iterate and pick up the async response to be sent out */
UA_fakeSleep(1000);
UA_Server_run_iterate(server, true);
UA_fakeSleep(1000);
UA_Server_run_iterate(server, true);
/* Process async responses during 1s */
UA_Client_run_iterate(client, 0);
ck_assert_uint_eq(clientCounter, 2);
running = true;
THREAD_CREATE(server_thread, serverloop);
UA_Client_disconnect(client);
UA_Client_delete(client);
} END_TEST
START_TEST(Async_timeout) {
UA_Client *client = UA_Client_new();
UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(clientConfig);
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Stop the server thread. Iterate manually from now on */
running = false;
THREAD_JOIN(server_thread);
/* Call async method, then the sync method.
* The sync method returns first. */
retval = UA_Client_call_async(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_STRING(1, "asyncMethod"),
0, NULL, clientReceiveCallback, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* We expect to receive the timeout not yet*/
UA_Server_run_iterate(server, true);
UA_Client_run_iterate(client, 0);
ck_assert_uint_eq(clientCounter, 0);
UA_fakeSleep((UA_UInt32)(1000 * 1.5));
/* We expect to receive the timeout not yet*/
UA_Server_run_iterate(server, true);
UA_Client_run_iterate(client, 0);
ck_assert_uint_eq(clientCounter, 0);
UA_fakeSleep(1000);
/* We expect to receive the timeout response */
UA_Server_run_iterate(server, true);
UA_Client_run_iterate(client, 0);
ck_assert_uint_eq(clientCounter, 1);
running = true;
THREAD_CREATE(server_thread, serverloop);
UA_Client_disconnect(client);
UA_Client_delete(client);
} END_TEST
START_TEST(Async_cancel) {
UA_Client *client = UA_Client_new();
UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(clientConfig);
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Call async method, then the sync method.
* The sync method returns first. */
UA_UInt32 reqId = 0;
retval = UA_Client_call_async(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_STRING(1, "asyncMethod"),
0, NULL, clientReceiveCallback, NULL, &reqId);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Cancel the request */
UA_UInt32 cancelCount = 0;
UA_Client_cancelByRequestId(client, reqId, &cancelCount);
ck_assert_uint_eq(cancelCount, 1);
/* We expect to receive the cancelled response */
UA_Client_run_iterate(client, 0);
ck_assert_uint_eq(clientCounter, 1);
UA_Client_disconnect(client);
UA_Client_delete(client);
} END_TEST
START_TEST(Async_cancel_multiple) {
UA_Client *client = UA_Client_new();
UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(clientConfig);
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
UA_CallRequest creq;
UA_CallRequest_init(&creq);
creq.requestHeader.requestHandle = 1337;
UA_CallMethodRequest cmr;
UA_CallMethodRequest_init(&cmr);
cmr.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
cmr.methodId = UA_NODEID_STRING(1, "asyncMethod");
creq.methodsToCall = &cmr;
creq.methodsToCallSize = 1;
__UA_Client_AsyncService(client,
&creq, &UA_TYPES[UA_TYPES_CALLREQUEST],
NULL, &UA_TYPES[UA_TYPES_CALLRESPONSE],
NULL, NULL);
__UA_Client_AsyncService(client,
&creq, &UA_TYPES[UA_TYPES_CALLREQUEST],
NULL, &UA_TYPES[UA_TYPES_CALLRESPONSE],
NULL, NULL);
/* Expect two cancelled requests */
UA_UInt32 cancelCount = 0;
UA_Client_cancelByRequestHandle(client, 1337, &cancelCount);
ck_assert_uint_eq(cancelCount, 2);
UA_Client_run_iterate(client, 0);
UA_Client_disconnect(client);
UA_Client_delete(client);
} END_TEST
/* Force a timeout when the operation is checked out with the worker */
START_TEST(Async_timeout_worker) {
UA_Client *client = UA_Client_new();
UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
UA_ClientConfig_setDefault(clientConfig);
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
/* Stop the server thread. Iterate manually from now on */
running = false;
THREAD_JOIN(server_thread);
/* Call async method, then the sync method.
* The sync method returns first. */
retval = UA_Client_call_async(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_STRING(1, "asyncMethod"),
0, NULL, clientReceiveCallback, NULL, NULL);
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
UA_Server_run_iterate(server, true);
/* Process the async method call for the server */
UA_AsyncOperationType aot;
const UA_AsyncOperationRequest *request;
void *context = NULL;
UA_DateTime timeout = 0;
UA_Boolean haveAsync =
UA_Server_getAsyncOperationNonBlocking(server, &aot, &request, &context, &timeout);
ck_assert_uint_eq(haveAsync, true);
UA_AsyncOperationResponse response;
UA_CallMethodResult_init(&response.callMethodResult);
/* Force a timeout */
UA_fakeSleep(2500);
UA_Server_run_iterate(server, true);
UA_Client_run_iterate(client, 0);
ck_assert_uint_eq(clientCounter, 1);
/* Return the late response */
UA_Server_setAsyncOperationResult(server, &response, context);
running = true;
THREAD_CREATE(server_thread, serverloop);
UA_Client_disconnect(client);
UA_Client_delete(client);
} END_TEST
static Suite* method_async_suite(void) {
/* set up unit test for internal data structures */
Suite *s = suite_create("Async Method");
TCase* tc_manager = tcase_create("AsyncMethod");
tcase_add_checked_fixture(tc_manager, setup, teardown);
tcase_add_test(tc_manager, Async_call);
tcase_add_test(tc_manager, Async_timeout);
tcase_add_test(tc_manager, Async_cancel);
tcase_add_test(tc_manager, Async_cancel_multiple);
tcase_add_test(tc_manager, Async_timeout_worker);
suite_add_tcase(s, tc_manager);
return s;
}
int main(void) {
/* Unit tests for internal data structures for async methods */
int number_failed = 0;
Suite *s = method_async_suite();
SRunner *sr = srunner_create(s);
srunner_set_fork_status(sr, CK_NOFORK);
srunner_run_all(sr, CK_NORMAL);
number_failed += srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}