check_client_historical_data.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334
  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. *
  5. * Copyright 2018 (c) basysKom GmbH <opensource@basyskom.com> (Author: Peter Rustler)
  6. */
  7. #include "ua_types.h"
  8. #include "ua_server.h"
  9. #include "server/ua_server_internal.h"
  10. #include "ua_client.h"
  11. #include "client/ua_client_internal.h"
  12. #include "ua_client_highlevel.h"
  13. #include "ua_config_default.h"
  14. #include "ua_network_tcp.h"
  15. #include "check.h"
  16. #include "testing_clock.h"
  17. #include "testing_networklayers.h"
  18. #include "thread_wrapper.h"
  19. #include "ua_plugin_historydatabase.h"
  20. #include "ua_historydatabase_default.h"
  21. #include "ua_plugin_history_data_gathering.h"
  22. #include "ua_historydatabackend_memory.h"
  23. #include "ua_historydatagathering_default.h"
  24. #ifdef UA_ENABLE_HISTORIZING
  25. #include "historical_read_test_data.h"
  26. #endif
  27. #include <stddef.h>
  28. static UA_Server *server;
  29. static UA_ServerConfig *config;
  30. #ifdef UA_ENABLE_HISTORIZING
  31. static UA_HistoryDataGathering *gathering;
  32. #endif
  33. static UA_Boolean running;
  34. static THREAD_HANDLE server_thread;
  35. static UA_Client *client;
  36. static UA_NodeId parentNodeId;
  37. static UA_NodeId parentReferenceNodeId;
  38. static UA_NodeId outNodeId;
  39. #ifdef UA_ENABLE_HISTORIZING
  40. static UA_HistoryDataBackend serverBackend;
  41. // same size as the test data
  42. static const size_t testDataSize = sizeof(testData) / sizeof(testData[0]);
  43. static UA_DateTime receivedTestData[sizeof(testData) / sizeof(testData[0])];
  44. static size_t receivedTestDataPos;
  45. #endif
  46. THREAD_CALLBACK(serverloop)
  47. {
  48. while(running)
  49. UA_Server_run_iterate(server, true);
  50. return 0;
  51. }
  52. #ifdef UA_ENABLE_HISTORIZING
  53. static UA_Boolean
  54. fillHistoricalDataBackend(UA_HistoryDataBackend backend);
  55. #endif
  56. static void
  57. setup(void)
  58. {
  59. running = true;
  60. config = UA_ServerConfig_new_default();
  61. #ifdef UA_ENABLE_HISTORIZING
  62. receivedTestDataPos = 0;
  63. memset(receivedTestData, 0, sizeof(receivedTestData));
  64. gathering = (UA_HistoryDataGathering*)UA_calloc(1, sizeof(UA_HistoryDataGathering));
  65. *gathering = UA_HistoryDataGathering_Default(1);
  66. config->historyDatabase = UA_HistoryDatabase_default(*gathering);
  67. #endif
  68. server = UA_Server_new(config);
  69. UA_StatusCode retval = UA_Server_run_startup(server);
  70. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  71. THREAD_CREATE(server_thread, serverloop);
  72. /* Define the attribute of the uint32 variable node */
  73. UA_VariableAttributes attr = UA_VariableAttributes_default;
  74. UA_UInt32 myUint32 = 40;
  75. UA_Variant_setScalar(&attr.value, &myUint32, &UA_TYPES[UA_TYPES_UINT32]);
  76. attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
  77. attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
  78. attr.dataType = UA_TYPES[UA_TYPES_UINT32].typeId;
  79. attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD;
  80. attr.historizing = true;
  81. /* Add the variable node to the information model */
  82. UA_NodeId uint32NodeId = UA_NODEID_STRING(1, "the.answer");
  83. UA_QualifiedName uint32Name = UA_QUALIFIEDNAME(1, "the answer");
  84. parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
  85. parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
  86. UA_NodeId_init(&outNodeId);
  87. ck_assert_uint_eq(UA_Server_addVariableNode(server,
  88. uint32NodeId,
  89. parentNodeId,
  90. parentReferenceNodeId,
  91. uint32Name,
  92. UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
  93. attr,
  94. NULL,
  95. &outNodeId)
  96. , UA_STATUSCODE_GOOD);
  97. #ifdef UA_ENABLE_HISTORIZING
  98. UA_HistorizingNodeIdSettings setting;
  99. serverBackend = UA_HistoryDataBackend_Memory(1, 100);
  100. setting.historizingBackend = serverBackend;
  101. setting.maxHistoryDataResponseSize = 100;
  102. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_USER;
  103. retval = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  104. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  105. ck_assert(fillHistoricalDataBackend(setting.historizingBackend));
  106. #endif
  107. client = UA_Client_new();
  108. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  109. retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  110. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  111. UA_Client_recv = client->connection.recv;
  112. client->connection.recv = UA_Client_recvTesting;
  113. }
  114. static void
  115. teardown(void)
  116. {
  117. /* cleanup */
  118. #ifdef UA_ENABLE_HISTORIZING
  119. UA_HistoryDataBackend_Memory_deleteMembers(&serverBackend);
  120. #endif
  121. UA_Client_disconnect(client);
  122. UA_Client_delete(client);
  123. UA_NodeId_deleteMembers(&parentNodeId);
  124. UA_NodeId_deleteMembers(&parentReferenceNodeId);
  125. UA_NodeId_deleteMembers(&outNodeId);
  126. running = false;
  127. THREAD_JOIN(server_thread);
  128. UA_Server_run_shutdown(server);
  129. UA_Server_delete(server);
  130. UA_ServerConfig_delete(config);
  131. #ifdef UA_ENABLE_HISTORIZING
  132. UA_free(gathering);
  133. #endif
  134. }
  135. #ifdef UA_ENABLE_HISTORIZING
  136. #include <stdio.h>
  137. #include "ua_session.h"
  138. static UA_Boolean
  139. fillHistoricalDataBackend(UA_HistoryDataBackend backend)
  140. {
  141. fprintf(stderr, "Adding to historical data backend: ");
  142. for (size_t i = 0; i < testDataSize; ++i) {
  143. fprintf(stderr, "%lld, ", testData[i] / UA_DATETIME_SEC);
  144. UA_DataValue value;
  145. UA_DataValue_init(&value);
  146. value.hasValue = true;
  147. UA_Int64 d = testData[i];
  148. UA_Variant_setScalarCopy(&value.value, &d, &UA_TYPES[UA_TYPES_INT64]);
  149. value.hasSourceTimestamp = true;
  150. value.sourceTimestamp = testData[i];
  151. value.hasServerTimestamp = true;
  152. value.serverTimestamp = testData[i];
  153. value.hasStatus = true;
  154. value.status = UA_STATUSCODE_GOOD;
  155. if (backend.serverSetHistoryData(server, backend.context, NULL, NULL, &outNodeId, UA_FALSE, &value) != UA_STATUSCODE_GOOD) {
  156. fprintf(stderr, "\n");
  157. return false;
  158. }
  159. UA_DataValue_deleteMembers(&value);
  160. }
  161. fprintf(stderr, "\n");
  162. return true;
  163. }
  164. static UA_Boolean checkTestData(UA_Boolean inverse) {
  165. for (size_t i = 0; i < testDataSize; ++i) {
  166. if (testDataSize != receivedTestDataPos)
  167. return false;
  168. if (!inverse && testData[i] != receivedTestData[i])
  169. return false;
  170. if (inverse && testData[i] != receivedTestData[testDataSize-i-1])
  171. return false;
  172. }
  173. return true;
  174. }
  175. static UA_Boolean
  176. receiveCallback(UA_Client *clt,
  177. const UA_NodeId *nodeId,
  178. UA_Boolean moreDataAvailable,
  179. const UA_ExtensionObject *_data,
  180. void *callbackContext) {
  181. UA_HistoryData *data = (UA_HistoryData*)_data->content.decoded.data;
  182. fprintf(stderr, "Received %lu at pos %lu. moreDataAvailable %d\n", data->dataValuesSize, receivedTestDataPos, moreDataAvailable);
  183. if (receivedTestDataPos + data->dataValuesSize > testDataSize)
  184. return false;
  185. for (size_t i = 0; i < data->dataValuesSize; ++i) {
  186. receivedTestData[i+receivedTestDataPos] = *((UA_Int64*)data->dataValues[i].value.data);
  187. }
  188. receivedTestDataPos += data->dataValuesSize;
  189. return true;
  190. }
  191. START_TEST(Client_HistorizingReadRawAll)
  192. {
  193. UA_Client_HistoryRead_raw(client,
  194. &outNodeId,
  195. receiveCallback,
  196. TESTDATA_START_TIME,
  197. TESTDATA_STOP_TIME,
  198. UA_STRING_NULL,
  199. false,
  200. 100,
  201. UA_TIMESTAMPSTORETURN_BOTH,
  202. (void*)false);
  203. ck_assert(checkTestData(false));
  204. }
  205. END_TEST
  206. START_TEST(Client_HistorizingReadRawOne)
  207. {
  208. UA_Client_HistoryRead_raw(client,
  209. &outNodeId,
  210. receiveCallback,
  211. TESTDATA_START_TIME,
  212. TESTDATA_STOP_TIME,
  213. UA_STRING_NULL,
  214. false,
  215. 1,
  216. UA_TIMESTAMPSTORETURN_BOTH,
  217. (void*)false);
  218. ck_assert(checkTestData(false));
  219. }
  220. END_TEST
  221. START_TEST(Client_HistorizingReadRawTwo)
  222. {
  223. UA_Client_HistoryRead_raw(client,
  224. &outNodeId,
  225. receiveCallback,
  226. TESTDATA_START_TIME,
  227. TESTDATA_STOP_TIME,
  228. UA_STRING_NULL,
  229. false,
  230. 2,
  231. UA_TIMESTAMPSTORETURN_BOTH,
  232. (void*)false);
  233. ck_assert(checkTestData(false));
  234. }
  235. END_TEST
  236. START_TEST(Client_HistorizingReadRawAllInv)
  237. {
  238. UA_Client_HistoryRead_raw(client,
  239. &outNodeId,
  240. receiveCallback,
  241. TESTDATA_STOP_TIME,
  242. TESTDATA_START_TIME,
  243. UA_STRING_NULL,
  244. false,
  245. 100,
  246. UA_TIMESTAMPSTORETURN_BOTH,
  247. (void*)true);
  248. ck_assert(checkTestData(true));
  249. }
  250. END_TEST
  251. START_TEST(Client_HistorizingReadRawOneInv)
  252. {
  253. UA_Client_HistoryRead_raw(client,
  254. &outNodeId,
  255. receiveCallback,
  256. TESTDATA_STOP_TIME,
  257. TESTDATA_START_TIME,
  258. UA_STRING_NULL,
  259. false,
  260. 1,
  261. UA_TIMESTAMPSTORETURN_BOTH,
  262. (void*)true);
  263. ck_assert(checkTestData(true));
  264. }
  265. END_TEST
  266. START_TEST(Client_HistorizingReadRawTwoInv)
  267. {
  268. UA_Client_HistoryRead_raw(client,
  269. &outNodeId,
  270. receiveCallback,
  271. TESTDATA_STOP_TIME,
  272. TESTDATA_START_TIME,
  273. UA_STRING_NULL,
  274. false,
  275. 2,
  276. UA_TIMESTAMPSTORETURN_BOTH,
  277. (void*)true);
  278. ck_assert(checkTestData(true));
  279. }
  280. END_TEST
  281. #endif /*UA_ENABLE_HISTORIZING*/
  282. static Suite* testSuite_Client(void)
  283. {
  284. Suite *s = suite_create("Client Historical Data");
  285. TCase *tc_client = tcase_create("Client Historical Data read_raw");
  286. tcase_add_checked_fixture(tc_client, setup, teardown);
  287. #ifdef UA_ENABLE_HISTORIZING
  288. tcase_add_test(tc_client, Client_HistorizingReadRawAll);
  289. tcase_add_test(tc_client, Client_HistorizingReadRawOne);
  290. tcase_add_test(tc_client, Client_HistorizingReadRawTwo);
  291. tcase_add_test(tc_client, Client_HistorizingReadRawAllInv);
  292. tcase_add_test(tc_client, Client_HistorizingReadRawOneInv);
  293. tcase_add_test(tc_client, Client_HistorizingReadRawTwoInv);
  294. #endif /* UA_ENABLE_HISTORIZING */
  295. suite_add_tcase(s, tc_client);
  296. return s;
  297. }
  298. int main(void)
  299. {
  300. Suite *s = testSuite_Client();
  301. SRunner *sr = srunner_create(s);
  302. srunner_set_fork_status(sr, CK_NOFORK);
  303. srunner_run_all(sr,CK_NORMAL);
  304. int number_failed = srunner_ntests_failed(sr);
  305. srunner_free(sr);
  306. return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  307. }