check_client_subscriptions.c 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880
  1. /* This Source Code Form is subject to the terms of the Mozilla Public
  2. * License, v. 2.0. If a copy of the MPL was not distributed with this
  3. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  4. #include <open62541/client.h>
  5. #include <open62541/client_config_default.h>
  6. #include <open62541/server.h>
  7. #include <open62541/server_config_default.h>
  8. #include "client/ua_client_internal.h"
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include "check.h"
  12. #include "testing_clock.h"
  13. #include "testing_networklayers.h"
  14. #include "thread_wrapper.h"
  15. UA_Server *server;
  16. UA_Boolean running;
  17. UA_ServerNetworkLayer nl;
  18. THREAD_HANDLE server_thread;
  19. THREAD_CALLBACK(serverloop) {
  20. while(running)
  21. UA_Server_run_iterate(server, true);
  22. return 0;
  23. }
  24. static void setup(void) {
  25. running = true;
  26. server = UA_Server_new();
  27. UA_ServerConfig *config = UA_Server_getConfig(server);
  28. UA_ServerConfig_setDefault(config);
  29. config->maxPublishReqPerSession = 5;
  30. UA_Server_run_startup(server);
  31. THREAD_CREATE(server_thread, serverloop);
  32. }
  33. static void teardown(void) {
  34. running = false;
  35. THREAD_JOIN(server_thread);
  36. UA_Server_run_shutdown(server);
  37. UA_Server_delete(server);
  38. }
  39. #ifdef UA_ENABLE_SUBSCRIPTIONS
  40. UA_Boolean notificationReceived = false;
  41. UA_UInt32 countNotificationReceived = 0;
  42. UA_Double publishingInterval = 500.0;
  43. static void
  44. dataChangeHandler(UA_Client *client, UA_UInt32 subId, void *subContext,
  45. UA_UInt32 monId, void *monContext, UA_DataValue *value) {
  46. notificationReceived = true;
  47. countNotificationReceived++;
  48. }
  49. static void
  50. createSubscriptionCallback(UA_Client *client, void *userdata, UA_UInt32 requestId,
  51. void *r) {
  52. UA_CreateSubscriptionResponse_copy((const UA_CreateSubscriptionResponse *)r,
  53. (UA_CreateSubscriptionResponse *)userdata);
  54. }
  55. static void
  56. modifySubscriptionCallback(UA_Client *client, void *userdata, UA_UInt32 requestId,
  57. void *r) {
  58. UA_ModifySubscriptionResponse_copy((const UA_ModifySubscriptionResponse *)r,
  59. (UA_ModifySubscriptionResponse *)userdata);
  60. }
  61. static void
  62. createDataChangesCallback(UA_Client *client, void *userdata, UA_UInt32 requestId,
  63. void *r) {
  64. UA_CreateMonitoredItemsResponse_copy((const UA_CreateMonitoredItemsResponse *)r,
  65. (UA_CreateMonitoredItemsResponse *)userdata);
  66. }
  67. static void
  68. deleteMonitoredItemsCallback(UA_Client *client, void *userdata, UA_UInt32 requestId,
  69. void *r) {
  70. UA_DeleteMonitoredItemsResponse_copy((const UA_DeleteMonitoredItemsResponse *)r,
  71. (UA_DeleteMonitoredItemsResponse *)userdata);
  72. }
  73. static void
  74. deleteSubscriptionsCallback(UA_Client *client, void *userdata, UA_UInt32 requestId,
  75. void *r) {
  76. UA_DeleteSubscriptionsResponse_copy((const UA_DeleteSubscriptionsResponse *)r,
  77. (UA_DeleteSubscriptionsResponse *)userdata);
  78. }
  79. START_TEST(Client_subscription) {
  80. UA_Client *client = UA_Client_new();
  81. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  82. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  83. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  84. UA_Client_recv = client->connection.recv;
  85. client->connection.recv = UA_Client_recvTesting;
  86. UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
  87. UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
  88. NULL, NULL, NULL);
  89. ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  90. UA_UInt32 subId = response.subscriptionId;
  91. // a valid UA_Client_Subscriptions_modify
  92. UA_ModifySubscriptionRequest modifySubscriptionRequest;
  93. UA_ModifySubscriptionRequest_init(&modifySubscriptionRequest);
  94. modifySubscriptionRequest.subscriptionId = response.subscriptionId;
  95. modifySubscriptionRequest.requestedPublishingInterval = response.revisedPublishingInterval;
  96. modifySubscriptionRequest.requestedLifetimeCount = response.revisedLifetimeCount;
  97. modifySubscriptionRequest.requestedMaxKeepAliveCount = response.revisedMaxKeepAliveCount;
  98. UA_ModifySubscriptionResponse modifySubscriptionResponse = UA_Client_Subscriptions_modify(client,modifySubscriptionRequest);
  99. ck_assert_int_eq(modifySubscriptionResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  100. // an invalid UA_Client_Subscriptions_modify
  101. modifySubscriptionRequest.subscriptionId = 99999; // invalid
  102. modifySubscriptionResponse = UA_Client_Subscriptions_modify(client,modifySubscriptionRequest);
  103. ck_assert_int_eq(modifySubscriptionResponse.responseHeader.serviceResult, UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID);
  104. /* monitor the server state */
  105. UA_MonitoredItemCreateRequest monRequest =
  106. UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
  107. UA_MonitoredItemCreateResult monResponse =
  108. UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
  109. UA_TIMESTAMPSTORETURN_BOTH,
  110. monRequest, NULL, dataChangeHandler, NULL);
  111. ck_assert_uint_eq(monResponse.statusCode, UA_STATUSCODE_GOOD);
  112. UA_UInt32 monId = monResponse.monitoredItemId;
  113. UA_fakeSleep((UA_UInt32)publishingInterval + 1);
  114. notificationReceived = false;
  115. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  116. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  117. ck_assert_uint_eq(notificationReceived, true);
  118. retval = UA_Client_MonitoredItems_deleteSingle(client, subId, monId);
  119. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  120. retval = UA_Client_Subscriptions_deleteSingle(client, subId);
  121. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  122. UA_Client_disconnect(client);
  123. UA_Client_delete(client);
  124. }
  125. END_TEST
  126. START_TEST(Client_subscription_async) {
  127. UA_Client *client = UA_Client_new();
  128. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  129. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  130. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  131. UA_Client_recv = client->connection.recv;
  132. client->connection.recv = UA_Client_recvTesting;
  133. UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
  134. UA_UInt32 requestId = 0;
  135. UA_CreateSubscriptionResponse response;
  136. retval = UA_Client_Subscriptions_create_async(client, request, NULL, NULL, NULL,
  137. createSubscriptionCallback, &response,
  138. &requestId);
  139. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  140. UA_realSleep(50); // wait until response is
  141. UA_Client_run_iterate(client, 0);
  142. ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  143. UA_UInt32 subId = response.subscriptionId;
  144. UA_ModifySubscriptionRequest modifySubscriptionRequest;
  145. UA_ModifySubscriptionRequest_init(&modifySubscriptionRequest);
  146. modifySubscriptionRequest.subscriptionId = response.subscriptionId;
  147. modifySubscriptionRequest.requestedPublishingInterval =
  148. response.revisedPublishingInterval;
  149. modifySubscriptionRequest.requestedLifetimeCount = response.revisedLifetimeCount;
  150. modifySubscriptionRequest.requestedMaxKeepAliveCount =
  151. response.revisedMaxKeepAliveCount;
  152. UA_ModifySubscriptionResponse modifySubscriptionResponse;
  153. retval = UA_Client_Subscriptions_modify_async(
  154. client, modifySubscriptionRequest, modifySubscriptionCallback,
  155. &modifySubscriptionResponse, &requestId);
  156. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  157. UA_realSleep(50); // need to wait until response is at the client
  158. retval = UA_Client_run_iterate(client, 0);
  159. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  160. ck_assert_int_eq(modifySubscriptionResponse.responseHeader.serviceResult,
  161. UA_STATUSCODE_GOOD);
  162. /* monitor the server state */
  163. UA_MonitoredItemCreateRequest singleMonRequest =
  164. UA_MonitoredItemCreateRequest_default(
  165. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
  166. void *contexts = NULL;
  167. UA_Client_DataChangeNotificationCallback notifications = dataChangeHandler;
  168. UA_Client_DeleteMonitoredItemCallback deleteCallbacks = NULL;
  169. UA_CreateMonitoredItemsRequest monRequest;
  170. UA_CreateMonitoredItemsRequest_init(&monRequest);
  171. monRequest.subscriptionId = subId;
  172. monRequest.itemsToCreate = &singleMonRequest;
  173. monRequest.itemsToCreateSize = 1;
  174. UA_CreateMonitoredItemsResponse monResponse;
  175. retval = UA_Client_MonitoredItems_createDataChanges_async(
  176. client, monRequest, &contexts, &notifications, &deleteCallbacks,
  177. createDataChangesCallback, &monResponse, &requestId);
  178. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  179. UA_realSleep(50); // need to wait until response is at the client
  180. retval = UA_Client_run_iterate(client, 0);
  181. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  182. ck_assert_uint_eq(monResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  183. ck_assert_uint_eq(monResponse.resultsSize, 1);
  184. ck_assert_uint_eq(monResponse.results[0].statusCode, UA_STATUSCODE_GOOD);
  185. UA_UInt32 monId = monResponse.results[0].monitoredItemId;
  186. UA_fakeSleep((UA_UInt32)publishingInterval + 1);
  187. notificationReceived = false;
  188. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  189. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  190. ck_assert_uint_eq(notificationReceived, true);
  191. UA_DeleteMonitoredItemsRequest monDeleteRequest;
  192. UA_DeleteMonitoredItemsRequest_init(&monDeleteRequest);
  193. monDeleteRequest.subscriptionId = subId;
  194. monDeleteRequest.monitoredItemIds = &monId;
  195. monDeleteRequest.monitoredItemIdsSize = 1;
  196. UA_DeleteMonitoredItemsResponse monDeleteResponse;
  197. retval = UA_Client_MonitoredItems_delete_async(client, monDeleteRequest,
  198. deleteMonitoredItemsCallback,
  199. &monDeleteResponse, &requestId);
  200. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  201. UA_realSleep(50); // need to wait until response is at the client
  202. retval = UA_Client_run_iterate(client, 0);
  203. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  204. ck_assert_uint_eq(monDeleteResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  205. ck_assert_uint_eq(monDeleteResponse.resultsSize, 1);
  206. ck_assert_uint_eq(monDeleteResponse.results[0], UA_STATUSCODE_GOOD);
  207. UA_DeleteSubscriptionsRequest subDeleteRequest;
  208. UA_DeleteSubscriptionsRequest_init(&subDeleteRequest);
  209. subDeleteRequest.subscriptionIds = &monId;
  210. subDeleteRequest.subscriptionIdsSize = 1;
  211. UA_DeleteSubscriptionsResponse subDeleteResponse;
  212. printf("will delete\n");
  213. retval = UA_Client_Subscriptions_delete_async(client, subDeleteRequest,
  214. deleteSubscriptionsCallback,
  215. &subDeleteResponse, &requestId);
  216. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  217. UA_realSleep(50); // need to wait until response is at the client
  218. retval = UA_Client_run_iterate(client, 0);
  219. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  220. ck_assert_uint_eq(subDeleteResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  221. ck_assert_uint_eq(subDeleteResponse.resultsSize, 1);
  222. ck_assert_uint_eq(subDeleteResponse.results[0], UA_STATUSCODE_GOOD);
  223. UA_CreateSubscriptionResponse_deleteMembers(&response);
  224. UA_ModifySubscriptionResponse_deleteMembers(&modifySubscriptionResponse);
  225. UA_CreateMonitoredItemsResponse_deleteMembers(&monResponse);
  226. UA_DeleteMonitoredItemsResponse_deleteMembers(&monDeleteResponse);
  227. UA_DeleteSubscriptionsResponse_deleteMembers(&subDeleteResponse);
  228. UA_Client_disconnect(client);
  229. UA_Client_delete(client);
  230. }
  231. END_TEST
  232. START_TEST(Client_subscription_createDataChanges) {
  233. UA_Client *client = UA_Client_new();
  234. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  235. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  236. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  237. UA_Client_recv = client->connection.recv;
  238. client->connection.recv = UA_Client_recvTesting;
  239. UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
  240. UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
  241. NULL, NULL, NULL);
  242. ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  243. UA_UInt32 subId = response.subscriptionId;
  244. UA_MonitoredItemCreateRequest items[3];
  245. UA_UInt32 newMonitoredItemIds[3];
  246. UA_Client_DataChangeNotificationCallback callbacks[3];
  247. UA_Client_DeleteMonitoredItemCallback deleteCallbacks[3];
  248. void *contexts[3];
  249. /* monitor the server state */
  250. items[0] = UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
  251. callbacks[0] = dataChangeHandler;
  252. contexts[0] = NULL;
  253. deleteCallbacks[0] = NULL;
  254. /* monitor invalid node */
  255. items[1] = UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, 999999));
  256. callbacks[1] = dataChangeHandler;
  257. contexts[1] = NULL;
  258. deleteCallbacks[1] = NULL;
  259. /* monitor current time */
  260. items[2] = UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME));
  261. callbacks[2] = dataChangeHandler;
  262. contexts[2] = NULL;
  263. deleteCallbacks[2] = NULL;
  264. UA_CreateMonitoredItemsRequest createRequest;
  265. UA_CreateMonitoredItemsRequest_init(&createRequest);
  266. createRequest.subscriptionId = subId;
  267. createRequest.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
  268. createRequest.itemsToCreate = items;
  269. createRequest.itemsToCreateSize = 3;
  270. UA_CreateMonitoredItemsResponse createResponse =
  271. UA_Client_MonitoredItems_createDataChanges(client, createRequest, contexts,
  272. callbacks, deleteCallbacks);
  273. ck_assert_uint_eq(createResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  274. ck_assert_uint_eq(createResponse.resultsSize, 3);
  275. ck_assert_uint_eq(createResponse.results[0].statusCode, UA_STATUSCODE_GOOD);
  276. newMonitoredItemIds[0] = createResponse.results[0].monitoredItemId;
  277. ck_assert_uint_eq(createResponse.results[1].statusCode, UA_STATUSCODE_BADNODEIDUNKNOWN);
  278. newMonitoredItemIds[1] = createResponse.results[1].monitoredItemId;
  279. ck_assert_uint_eq(newMonitoredItemIds[1], 0);
  280. ck_assert_uint_eq(createResponse.results[2].statusCode, UA_STATUSCODE_GOOD);
  281. newMonitoredItemIds[2] = createResponse.results[2].monitoredItemId;
  282. ck_assert_uint_eq(createResponse.results[2].statusCode, UA_STATUSCODE_GOOD);
  283. UA_CreateMonitoredItemsResponse_deleteMembers(&createResponse);
  284. UA_fakeSleep((UA_UInt32)publishingInterval + 1);
  285. notificationReceived = false;
  286. countNotificationReceived = 0;
  287. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  288. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  289. ck_assert_uint_eq(notificationReceived, true);
  290. ck_assert_uint_eq(countNotificationReceived, 2);
  291. notificationReceived = false;
  292. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  293. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  294. ck_assert_uint_eq(notificationReceived, true);
  295. ck_assert_uint_eq(countNotificationReceived, 3);
  296. UA_DeleteMonitoredItemsRequest deleteRequest;
  297. UA_DeleteMonitoredItemsRequest_init(&deleteRequest);
  298. deleteRequest.subscriptionId = subId;
  299. deleteRequest.monitoredItemIds = newMonitoredItemIds;
  300. deleteRequest.monitoredItemIdsSize = 3;
  301. UA_DeleteMonitoredItemsResponse deleteResponse =
  302. UA_Client_MonitoredItems_delete(client, deleteRequest);
  303. ck_assert_uint_eq(deleteResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  304. ck_assert_uint_eq(deleteResponse.resultsSize, 3);
  305. ck_assert_uint_eq(deleteResponse.results[0], UA_STATUSCODE_GOOD);
  306. ck_assert_uint_eq(deleteResponse.results[1], UA_STATUSCODE_BADMONITOREDITEMIDINVALID);
  307. ck_assert_uint_eq(deleteResponse.results[2], UA_STATUSCODE_GOOD);
  308. UA_DeleteMonitoredItemsResponse_deleteMembers(&deleteResponse);
  309. retval = UA_Client_Subscriptions_deleteSingle(client, subId);
  310. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  311. UA_Client_disconnect(client);
  312. UA_Client_delete(client);
  313. }
  314. END_TEST
  315. START_TEST(Client_subscription_createDataChanges_async) {
  316. UA_UInt32 reqId = 0;
  317. UA_Client *client = UA_Client_new();
  318. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  319. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  320. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  321. UA_Client_recv = client->connection.recv;
  322. client->connection.recv = UA_Client_recvTesting;
  323. // Async subscription creation is tested in Client_subscription_async
  324. // simplify test case using synchronous here
  325. UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
  326. UA_CreateSubscriptionResponse response =
  327. UA_Client_Subscriptions_create(client, request, NULL, NULL, NULL);
  328. ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  329. UA_UInt32 subId = response.subscriptionId;
  330. UA_MonitoredItemCreateRequest items[3];
  331. UA_UInt32 newMonitoredItemIds[3];
  332. UA_Client_DataChangeNotificationCallback callbacks[3];
  333. UA_Client_DeleteMonitoredItemCallback deleteCallbacks[3];
  334. void *contexts[3];
  335. /* monitor the server state */
  336. items[0] = UA_MonitoredItemCreateRequest_default(
  337. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
  338. callbacks[0] = dataChangeHandler;
  339. contexts[0] = NULL;
  340. deleteCallbacks[0] = NULL;
  341. /* monitor invalid node */
  342. items[1] = UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, 999999));
  343. callbacks[1] = dataChangeHandler;
  344. contexts[1] = NULL;
  345. deleteCallbacks[1] = NULL;
  346. /* monitor current time */
  347. items[2] = UA_MonitoredItemCreateRequest_default(
  348. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME));
  349. callbacks[2] = dataChangeHandler;
  350. contexts[2] = NULL;
  351. deleteCallbacks[2] = NULL;
  352. UA_CreateMonitoredItemsRequest createRequest;
  353. UA_CreateMonitoredItemsRequest_init(&createRequest);
  354. createRequest.subscriptionId = subId;
  355. createRequest.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
  356. createRequest.itemsToCreate = items;
  357. createRequest.itemsToCreateSize = 3;
  358. UA_CreateMonitoredItemsResponse createResponse;
  359. retval = UA_Client_MonitoredItems_createDataChanges_async(
  360. client, createRequest, contexts, callbacks, deleteCallbacks,
  361. createDataChangesCallback, &createResponse, &reqId);
  362. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  363. UA_realSleep(50);
  364. retval = UA_Client_run_iterate(client, 0);
  365. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  366. ck_assert_uint_eq(createResponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  367. ck_assert_uint_eq(createResponse.resultsSize, 3);
  368. ck_assert_uint_eq(createResponse.results[0].statusCode, UA_STATUSCODE_GOOD);
  369. newMonitoredItemIds[0] = createResponse.results[0].monitoredItemId;
  370. ck_assert_uint_eq(createResponse.results[1].statusCode,
  371. UA_STATUSCODE_BADNODEIDUNKNOWN);
  372. newMonitoredItemIds[1] = createResponse.results[1].monitoredItemId;
  373. ck_assert_uint_eq(newMonitoredItemIds[1], 0);
  374. ck_assert_uint_eq(createResponse.results[2].statusCode, UA_STATUSCODE_GOOD);
  375. newMonitoredItemIds[2] = createResponse.results[2].monitoredItemId;
  376. ck_assert_uint_eq(createResponse.results[2].statusCode, UA_STATUSCODE_GOOD);
  377. UA_CreateMonitoredItemsResponse_deleteMembers(&createResponse);
  378. UA_fakeSleep((UA_UInt32)publishingInterval + 1);
  379. notificationReceived = false;
  380. countNotificationReceived = 0;
  381. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  382. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  383. ck_assert_uint_eq(notificationReceived, true);
  384. ck_assert_uint_eq(countNotificationReceived, 2);
  385. notificationReceived = false;
  386. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  387. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  388. ck_assert_uint_eq(notificationReceived, true);
  389. ck_assert_uint_eq(countNotificationReceived, 3);
  390. {
  391. UA_DeleteMonitoredItemsRequest deleteRequest;
  392. UA_DeleteMonitoredItemsRequest_init(&deleteRequest);
  393. deleteRequest.subscriptionId = subId;
  394. deleteRequest.monitoredItemIds = newMonitoredItemIds;
  395. deleteRequest.monitoredItemIdsSize = 3;
  396. UA_DeleteMonitoredItemsResponse deleteResponse;
  397. retval = UA_Client_MonitoredItems_delete_async(
  398. client, deleteRequest, deleteMonitoredItemsCallback, &deleteResponse, &reqId);
  399. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  400. UA_realSleep(50); // need to wait until response is at the client
  401. retval = UA_Client_run_iterate(client, 0);
  402. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  403. ck_assert_uint_eq(deleteResponse.responseHeader.serviceResult,
  404. UA_STATUSCODE_GOOD);
  405. ck_assert_uint_eq(deleteResponse.resultsSize, 3);
  406. ck_assert_uint_eq(deleteResponse.results[0], UA_STATUSCODE_GOOD);
  407. ck_assert_uint_eq(deleteResponse.results[1],
  408. UA_STATUSCODE_BADMONITOREDITEMIDINVALID);
  409. ck_assert_uint_eq(deleteResponse.results[2], UA_STATUSCODE_GOOD);
  410. UA_DeleteMonitoredItemsResponse_deleteMembers(&deleteResponse);
  411. }
  412. // Async subscription deletion is tested in Client_subscription_async
  413. // simplify test case using synchronous here
  414. retval = UA_Client_Subscriptions_deleteSingle(client, subId);
  415. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  416. UA_Client_disconnect(client);
  417. UA_Client_delete(client);
  418. }
  419. END_TEST
  420. START_TEST(Client_subscription_keepAlive) {
  421. UA_Client *client = UA_Client_new();
  422. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  423. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  424. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  425. UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
  426. request.requestedMaxKeepAliveCount = 1;
  427. UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
  428. NULL, NULL, NULL);
  429. ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  430. UA_UInt32 subId = response.subscriptionId;
  431. /* monitor the server state */
  432. UA_MonitoredItemCreateRequest monRequest =
  433. UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
  434. UA_MonitoredItemCreateResult monResponse =
  435. UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
  436. UA_TIMESTAMPSTORETURN_BOTH,
  437. monRequest, NULL, dataChangeHandler, NULL);
  438. ck_assert_uint_eq(monResponse.statusCode, UA_STATUSCODE_GOOD);
  439. UA_UInt32 monId = monResponse.monitoredItemId;
  440. /* Ensure that the subscription is late */
  441. UA_fakeSleep((UA_UInt32)(publishingInterval + 1));
  442. /* Manually send a publish request */
  443. UA_PublishRequest pr;
  444. UA_PublishRequest_init(&pr);
  445. pr.subscriptionAcknowledgementsSize = 0;
  446. UA_PublishResponse presponse;
  447. UA_PublishResponse_init(&presponse);
  448. __UA_Client_Service(client, &pr, &UA_TYPES[UA_TYPES_PUBLISHREQUEST],
  449. &presponse, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
  450. ck_assert_uint_eq(presponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  451. ck_assert_uint_eq(presponse.notificationMessage.notificationDataSize, 1);
  452. UA_PublishResponse_deleteMembers(&presponse);
  453. UA_PublishRequest_deleteMembers(&pr);
  454. UA_fakeSleep((UA_UInt32)(publishingInterval + 1));
  455. UA_PublishRequest_init(&pr);
  456. pr.subscriptionAcknowledgementsSize = 0;
  457. UA_PublishResponse_init(&presponse);
  458. __UA_Client_Service(client, &pr, &UA_TYPES[UA_TYPES_PUBLISHREQUEST],
  459. &presponse, &UA_TYPES[UA_TYPES_PUBLISHRESPONSE]);
  460. ck_assert_uint_eq(presponse.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  461. ck_assert_uint_eq(presponse.notificationMessage.notificationDataSize, 0);
  462. UA_PublishResponse_deleteMembers(&presponse);
  463. UA_PublishRequest_deleteMembers(&pr);
  464. retval = UA_Client_MonitoredItems_deleteSingle(client, subId, monId);
  465. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  466. retval = UA_Client_Subscriptions_deleteSingle(client, subId);
  467. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  468. UA_Client_disconnect(client);
  469. UA_Client_delete(client);
  470. }
  471. END_TEST
  472. START_TEST(Client_subscription_connectionClose) {
  473. UA_Client *client = UA_Client_new();
  474. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  475. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  476. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  477. UA_Client_recv = client->connection.recv;
  478. client->connection.recv = UA_Client_recvTesting;
  479. UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
  480. UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
  481. NULL, NULL, NULL);
  482. ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  483. /* monitor the server state */
  484. UA_MonitoredItemCreateRequest monRequest =
  485. UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
  486. UA_MonitoredItemCreateResult monResponse =
  487. UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
  488. UA_TIMESTAMPSTORETURN_BOTH,
  489. monRequest, NULL, dataChangeHandler, NULL);
  490. ck_assert_uint_eq(monResponse.statusCode, UA_STATUSCODE_GOOD);
  491. UA_fakeSleep((UA_UInt32)publishingInterval + 1);
  492. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 60));
  493. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  494. /* Simulate BADCONNECTIONCLOSE */
  495. UA_Client_recvTesting_result = UA_STATUSCODE_BADCONNECTIONCLOSED;
  496. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 60));
  497. ck_assert_uint_eq(retval, UA_STATUSCODE_BADCONNECTIONCLOSED);
  498. UA_Client_disconnect(client);
  499. UA_Client_delete(client);
  500. }
  501. END_TEST
  502. START_TEST(Client_subscription_without_notification) {
  503. UA_Client *client = UA_Client_new();
  504. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  505. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  506. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  507. UA_Client_recv = client->connection.recv;
  508. client->connection.recv = UA_Client_recvTesting;
  509. UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
  510. request.requestedMaxKeepAliveCount = 1;
  511. UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
  512. NULL, NULL, NULL);
  513. ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  514. UA_UInt32 subId = response.subscriptionId;
  515. /* monitor the server state */
  516. UA_MonitoredItemCreateRequest monRequest =
  517. UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
  518. monRequest.requestedParameters.samplingInterval = 99999999.0;
  519. UA_MonitoredItemCreateResult monResponse =
  520. UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
  521. UA_TIMESTAMPSTORETURN_BOTH,
  522. monRequest, NULL, dataChangeHandler, NULL);
  523. UA_UInt32 monId = monResponse.monitoredItemId;
  524. ck_assert_uint_eq(monResponse.statusCode, UA_STATUSCODE_GOOD);
  525. UA_fakeSleep((UA_UInt32)publishingInterval + 1);
  526. notificationReceived = false;
  527. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  528. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  529. ck_assert_uint_eq(notificationReceived, true);
  530. notificationReceived = false;
  531. retval = UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  532. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  533. ck_assert_uint_eq(notificationReceived, false);
  534. retval = UA_Client_MonitoredItems_deleteSingle(client, subId, monId);
  535. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  536. retval = UA_Client_Subscriptions_deleteSingle(client, subId);
  537. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  538. UA_Client_disconnect(client);
  539. UA_Client_delete(client);
  540. }
  541. END_TEST
  542. static UA_ClientState callbackClientState;
  543. static void
  544. stateCallback (UA_Client *client, UA_ClientState clientState){
  545. callbackClientState = clientState;
  546. if (clientState == UA_CLIENTSTATE_SESSION){
  547. /* A new session was created. We need to create the subscription. */
  548. UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
  549. request.requestedMaxKeepAliveCount = 1;
  550. UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
  551. NULL, NULL, NULL);
  552. ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  553. UA_UInt32 subId = response.subscriptionId;
  554. ck_assert_uint_ne(subId, 0);
  555. /* Add a MonitoredItem */
  556. UA_MonitoredItemCreateRequest monRequest =
  557. UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME));
  558. UA_MonitoredItemCreateResult monResponse =
  559. UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
  560. UA_TIMESTAMPSTORETURN_BOTH,
  561. monRequest, NULL, dataChangeHandler, NULL);
  562. ck_assert_uint_eq(monResponse.statusCode, UA_STATUSCODE_GOOD);
  563. UA_UInt32 monId = monResponse.monitoredItemId;
  564. ck_assert_uint_ne(monId, 0);
  565. }
  566. }
  567. static UA_Boolean inactivityCallbackCalled = false;
  568. static void
  569. subscriptionInactivityCallback (UA_Client *client, UA_UInt32 subId, void *subContext) {
  570. inactivityCallbackCalled = true;
  571. }
  572. START_TEST(Client_subscription_async_sub) {
  573. UA_Client *client = UA_Client_new();
  574. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  575. /* Set stateCallback */
  576. UA_ClientConfig *cc = UA_Client_getConfig(client);
  577. cc->stateCallback = stateCallback;
  578. cc->subscriptionInactivityCallback = subscriptionInactivityCallback;
  579. inactivityCallbackCalled = false;
  580. /* Activate background publish request */
  581. cc->outStandingPublishRequests = 10;
  582. ck_assert_uint_eq(callbackClientState, UA_CLIENTSTATE_DISCONNECTED);
  583. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  584. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  585. ck_assert_uint_eq(callbackClientState, UA_CLIENTSTATE_SESSION);
  586. UA_Client_recv = client->connection.recv;
  587. client->connection.recv = UA_Client_recvTesting;
  588. UA_fakeSleep((UA_UInt32)publishingInterval + 1);
  589. countNotificationReceived = 0;
  590. notificationReceived = false;
  591. UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  592. ck_assert_uint_eq(notificationReceived, true);
  593. ck_assert_uint_eq(countNotificationReceived, 1);
  594. notificationReceived = false;
  595. UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  596. ck_assert_uint_eq(notificationReceived, true);
  597. ck_assert_uint_eq(countNotificationReceived, 2);
  598. notificationReceived = false;
  599. UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  600. ck_assert_uint_eq(notificationReceived, true);
  601. ck_assert_uint_eq(countNotificationReceived, 3);
  602. notificationReceived = false;
  603. UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  604. ck_assert_uint_eq(notificationReceived, true);
  605. ck_assert_uint_eq(countNotificationReceived, 4);
  606. notificationReceived = false;
  607. UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  608. ck_assert_uint_eq(notificationReceived, true);
  609. ck_assert_uint_eq(countNotificationReceived, 5);
  610. ck_assert_uint_lt(client->config.outStandingPublishRequests, 10);
  611. notificationReceived = false;
  612. /* Simulate network cable unplugged (no response from server) */
  613. UA_Client_recvTesting_result = UA_STATUSCODE_GOODNONCRITICALTIMEOUT;
  614. UA_Client_run_iterate(client, (UA_UInt16)(publishingInterval + 1));
  615. ck_assert_uint_eq(notificationReceived, false);
  616. ck_assert_uint_eq(callbackClientState, UA_CLIENTSTATE_SESSION);
  617. /* Simulate network cable unplugged (no response from server) */
  618. ck_assert_uint_eq(inactivityCallbackCalled, false);
  619. UA_Client_recvTesting_result = UA_STATUSCODE_GOODNONCRITICALTIMEOUT;
  620. UA_Client_run_iterate(client, (UA_UInt16)cc->timeout);
  621. ck_assert_uint_eq(inactivityCallbackCalled, true);
  622. ck_assert_uint_eq(callbackClientState, UA_CLIENTSTATE_SESSION);
  623. UA_Client_delete(client);
  624. }
  625. END_TEST
  626. #ifdef UA_ENABLE_METHODCALLS
  627. START_TEST(Client_methodcall) {
  628. UA_Client *client = UA_Client_new();
  629. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  630. UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  631. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  632. UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
  633. UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
  634. NULL, NULL, NULL);
  635. ck_assert_uint_eq(response.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
  636. /* monitor the server state */
  637. UA_MonitoredItemCreateRequest monRequest =
  638. UA_MonitoredItemCreateRequest_default(UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_STATE));
  639. UA_MonitoredItemCreateResult monResponse =
  640. UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
  641. UA_TIMESTAMPSTORETURN_BOTH,
  642. monRequest, NULL, NULL, NULL);
  643. ck_assert_uint_eq(monResponse.statusCode, UA_STATUSCODE_GOOD);
  644. /* Minimal nodeset does not contain any method we can call here */
  645. #ifdef UA_GENERATED_NAMESPACE_ZERO
  646. UA_UInt32 monId = monResponse.monitoredItemId;
  647. UA_UInt32 subId = response.subscriptionId;
  648. /* call a method to get monitored item id */
  649. UA_Variant input;
  650. UA_Variant_init(&input);
  651. UA_Variant_setScalarCopy(&input, &subId, &UA_TYPES[UA_TYPES_UINT32]);
  652. size_t outputSize;
  653. UA_Variant *output;
  654. retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
  655. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), 1, &input, &outputSize, &output);
  656. ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
  657. ck_assert_uint_eq(outputSize, 2);
  658. ck_assert_uint_eq(output[0].arrayLength, 1);
  659. ck_assert_uint_eq(*((UA_UInt32*)output[0].data), monId);
  660. UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
  661. UA_Variant_deleteMembers(&input);
  662. /* call with invalid subscription id */
  663. UA_Variant_init(&input);
  664. subId = 0;
  665. UA_Variant_setScalarCopy(&input, &subId, &UA_TYPES[UA_TYPES_UINT32]);
  666. retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
  667. UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), 1, &input, &outputSize, &output);
  668. ck_assert_uint_eq(retval, UA_STATUSCODE_BADSUBSCRIPTIONIDINVALID);
  669. UA_Variant_deleteMembers(&input);
  670. #endif
  671. UA_Client_disconnect(client);
  672. UA_Client_delete(client);
  673. }
  674. END_TEST
  675. #endif /* UA_ENABLE_METHODCALLS */
  676. #endif /* UA_ENABLE_SUBSCRIPTIONS */
  677. static Suite* testSuite_Client(void) {
  678. Suite *s = suite_create("Client Subscription");
  679. #ifdef UA_ENABLE_SUBSCRIPTIONS
  680. TCase *tc_client = tcase_create("Client Subscription Basic");
  681. tcase_add_checked_fixture(tc_client, setup, teardown);
  682. tcase_add_test(tc_client, Client_subscription);
  683. tcase_add_test(tc_client, Client_subscription_async);
  684. tcase_add_test(tc_client, Client_subscription_connectionClose);
  685. tcase_add_test(tc_client, Client_subscription_createDataChanges);
  686. tcase_add_test(tc_client, Client_subscription_createDataChanges_async);
  687. tcase_add_test(tc_client, Client_subscription_keepAlive);
  688. tcase_add_test(tc_client, Client_subscription_without_notification);
  689. tcase_add_test(tc_client, Client_subscription_async_sub);
  690. suite_add_tcase(s,tc_client);
  691. #endif /* UA_ENABLE_SUBSCRIPTIONS */
  692. #if defined(UA_ENABLE_SUBSCRIPTIONS) && defined(UA_ENABLE_METHODCALLS)
  693. TCase *tc_client2 = tcase_create("Client Subscription + Method Call of GetMonitoredItmes");
  694. tcase_add_checked_fixture(tc_client2, setup, teardown);
  695. tcase_add_test(tc_client2, Client_methodcall);
  696. suite_add_tcase(s,tc_client2);
  697. #endif
  698. return s;
  699. }
  700. int main(void) {
  701. Suite *s = testSuite_Client();
  702. SRunner *sr = srunner_create(s);
  703. srunner_set_fork_status(sr, CK_NOFORK);
  704. srunner_run_all(sr,CK_NORMAL);
  705. int number_failed = srunner_ntests_failed(sr);
  706. srunner_free(sr);
  707. return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  708. }