check_server_asyncop.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. /* This work is licensed under a Creative Commons CCZero 1.0 Universal License.
  2. * See http://creativecommons.org/publicdomain/zero/1.0/ for more information. */
  3. /* This example is just to see how fast we can process messages. The server does
  4. not open a TCP port. */
  5. #include <open62541/server_config_default.h>
  6. #include <open62541/server.h>
  7. #include <open62541/client.h>
  8. #include <open62541/client_config_default.h>
  9. #include <open62541/client_highlevel_async.h>
  10. #include <open62541/plugin/log_stdout.h>
  11. #include "testing_clock.h"
  12. #include "thread_wrapper.h"
  13. #include <check.h>
  14. UA_Boolean running;
  15. THREAD_HANDLE server_thread;
  16. static UA_Server *server;
  17. static size_t clientCounter;
  18. static UA_StatusCode
  19. methodCallback(UA_Server *serverArg,
  20. const UA_NodeId *sessionId, void *sessionHandle,
  21. const UA_NodeId *methodId, void *methodContext,
  22. const UA_NodeId *objectId, void *objectContext,
  23. size_t inputSize, const UA_Variant *input,
  24. size_t outputSize, UA_Variant *output) {
  25. return UA_STATUSCODE_GOOD;
  26. }
  27. static void
  28. clientReceiveCallback(UA_Client *client, void *userdata,
  29. UA_UInt32 requestId, UA_CallResponse *cr) {
  30. UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_CLIENT, "Received call response");
  31. clientCounter++;
  32. }
  33. THREAD_CALLBACK(serverloop) {
  34. while(running)
  35. UA_Server_run_iterate(server, true);
  36. return 0;
  37. }
  38. static void setup(void) {
  39. clientCounter = 0;
  40. running = true;
  41. server = UA_Server_new();
  42. UA_ServerConfig *config = UA_Server_getConfig(server);
  43. UA_ServerConfig_setDefault(config);
  44. config->asyncOperationTimeout = 2000.0; /* 2 seconds */
  45. UA_MethodAttributes methodAttr = UA_MethodAttributes_default;
  46. methodAttr.executable = true;
  47. methodAttr.userExecutable = true;
  48. /* Synchronous Method */
  49. UA_StatusCode res =
  50. UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "method"),
  51. UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
  52. UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
  53. UA_QUALIFIEDNAME(1, "method"),
  54. methodAttr, &methodCallback,
  55. 0, NULL, 0, NULL, NULL, NULL);
  56. ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
  57. /* Asynchronous Method */
  58. res = UA_Server_addMethodNode(server, UA_NODEID_STRING(1, "asyncMethod"),
  59. UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
  60. UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
  61. UA_QUALIFIEDNAME(1, "asyncMethod"),
  62. methodAttr, &methodCallback,
  63. 0, NULL, 0, NULL, NULL, NULL);
  64. ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
  65. res = UA_Server_setMethodNodeAsync(server, UA_NODEID_STRING(1, "asyncMethod"), true);
  66. ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
  67. UA_Server_run_startup(server);
  68. THREAD_CREATE(server_thread, serverloop);
  69. }
  70. static void teardown(void) {
  71. running = false;
  72. THREAD_JOIN(server_thread);
  73. UA_Server_run_shutdown(server);
  74. UA_Server_delete(server);
  75. }
  76. START_TEST(Async_call) {
  77. UA_Client *client = UA_Client_new();
  78. UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
  79. UA_ClientConfig_setDefault(clientConfig);
  80. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  81. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  82. /* Stop the server thread. Iterate manually from now on */
  83. running = false;
  84. THREAD_JOIN(server_thread);
  85. /* Call async method, then the sync method.
  86. * The sync method returns first. */
  87. retval = UA_Client_call_async(client,
  88. UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
  89. UA_NODEID_STRING(1, "asyncMethod"),
  90. 0, NULL, clientReceiveCallback, NULL, NULL);
  91. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  92. retval = UA_Client_call_async(client,
  93. UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
  94. UA_NODEID_STRING(1, "method"),
  95. 0, NULL, clientReceiveCallback, NULL, NULL);
  96. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  97. /* Receive the answer of the sync call */
  98. ck_assert_uint_eq(clientCounter, 0);
  99. UA_Server_run_iterate(server, true);
  100. UA_Client_run_iterate(client, 0);
  101. UA_Server_run_iterate(server, true);
  102. UA_Client_run_iterate(client, 0);
  103. ck_assert_uint_eq(clientCounter, 1);
  104. /* Process the async method call for the server */
  105. UA_AsyncOperationType aot;
  106. const UA_AsyncOperationRequest *request;
  107. void *context;
  108. UA_Boolean haveAsync = UA_Server_getAsyncOperation(server, &aot, &request, &context);
  109. ck_assert_uint_eq(haveAsync, true);
  110. UA_AsyncOperationResponse response;
  111. UA_CallMethodResult_init(&response.callMethodResult);
  112. UA_Server_setAsyncOperationResult(server, &response, context);
  113. /* Iterate and pick up the async response to be sent out */
  114. UA_fakeSleep(1000);
  115. UA_Server_run_iterate(server, true);
  116. UA_fakeSleep(1000);
  117. UA_Server_run_iterate(server, true);
  118. /* Process async responses during 1s */
  119. UA_Client_run_iterate(client, 0);
  120. ck_assert_uint_eq(clientCounter, 2);
  121. running = true;
  122. THREAD_CREATE(server_thread, serverloop);
  123. UA_Client_disconnect(client);
  124. UA_Client_delete(client);
  125. } END_TEST
  126. START_TEST(Async_timeout) {
  127. UA_Client *client = UA_Client_new();
  128. UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
  129. UA_ClientConfig_setDefault(clientConfig);
  130. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  131. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  132. /* Stop the server thread. Iterate manually from now on */
  133. running = false;
  134. THREAD_JOIN(server_thread);
  135. /* Call async method, then the sync method.
  136. * The sync method returns first. */
  137. retval = UA_Client_call_async(client,
  138. UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
  139. UA_NODEID_STRING(1, "asyncMethod"),
  140. 0, NULL, clientReceiveCallback, NULL, NULL);
  141. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  142. /* We expect to receive the timeout not yet*/
  143. UA_Server_run_iterate(server, true);
  144. UA_Client_run_iterate(client, 0);
  145. ck_assert_uint_eq(clientCounter, 0);
  146. UA_fakeSleep(1000 * 1.5);
  147. /* We expect to receive the timeout not yet*/
  148. UA_Server_run_iterate(server, true);
  149. UA_Client_run_iterate(client, 0);
  150. ck_assert_uint_eq(clientCounter, 0);
  151. UA_fakeSleep(1000);
  152. /* We expect to receive the timeout response */
  153. UA_Server_run_iterate(server, true);
  154. UA_Client_run_iterate(client, 0);
  155. ck_assert_uint_eq(clientCounter, 1);
  156. running = true;
  157. THREAD_CREATE(server_thread, serverloop);
  158. UA_Client_disconnect(client);
  159. UA_Client_delete(client);
  160. } END_TEST
  161. /* Force a timeout when the operation is checked out with the worker */
  162. START_TEST(Async_timeout_worker) {
  163. UA_Client *client = UA_Client_new();
  164. UA_ClientConfig *clientConfig = UA_Client_getConfig(client);
  165. UA_ClientConfig_setDefault(clientConfig);
  166. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  167. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  168. /* Stop the server thread. Iterate manually from now on */
  169. running = false;
  170. THREAD_JOIN(server_thread);
  171. /* Call async method, then the sync method.
  172. * The sync method returns first. */
  173. retval = UA_Client_call_async(client,
  174. UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
  175. UA_NODEID_STRING(1, "asyncMethod"),
  176. 0, NULL, clientReceiveCallback, NULL, NULL);
  177. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  178. UA_Server_run_iterate(server, true);
  179. /* Process the async method call for the server */
  180. UA_AsyncOperationType aot;
  181. const UA_AsyncOperationRequest *request;
  182. void *context;
  183. UA_Boolean haveAsync = UA_Server_getAsyncOperation(server, &aot, &request, &context);
  184. ck_assert_uint_eq(haveAsync, true);
  185. UA_AsyncOperationResponse response;
  186. UA_CallMethodResult_init(&response.callMethodResult);
  187. /* Force a timeout */
  188. UA_fakeSleep(2500);
  189. UA_Server_run_iterate(server, true);
  190. UA_Client_run_iterate(client, 0);
  191. ck_assert_uint_eq(clientCounter, 1);
  192. /* Return the late response */
  193. UA_Server_setAsyncOperationResult(server, &response, context);
  194. running = true;
  195. THREAD_CREATE(server_thread, serverloop);
  196. UA_Client_disconnect(client);
  197. UA_Client_delete(client);
  198. } END_TEST
  199. static Suite* method_async_suite(void) {
  200. /* set up unit test for internal data structures */
  201. Suite *s = suite_create("Async Method");
  202. TCase* tc_manager = tcase_create("AsyncMethod");
  203. tcase_add_checked_fixture(tc_manager, setup, teardown);
  204. tcase_add_test(tc_manager, Async_call);
  205. tcase_add_test(tc_manager, Async_timeout);
  206. tcase_add_test(tc_manager, Async_timeout_worker);
  207. suite_add_tcase(s, tc_manager);
  208. return s;
  209. }
  210. int main(void) {
  211. /* Unit tests for internal data structures for async methods */
  212. int number_failed = 0;
  213. Suite *s = method_async_suite();
  214. SRunner *sr = srunner_create(s);
  215. srunner_set_fork_status(sr, CK_NOFORK);
  216. srunner_run_all(sr, CK_NORMAL);
  217. number_failed += srunner_ntests_failed(sr);
  218. srunner_free(sr);
  219. return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  220. }