check_server_historical_data.c 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056
  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 <open62541/client.h>
  8. #include <open62541/client_config_default.h>
  9. #include <open62541/client_highlevel.h>
  10. #include <open62541/plugin/historydata/history_data_backend.h>
  11. #include <open62541/plugin/historydata/history_data_backend_memory.h>
  12. #include <open62541/plugin/historydata/history_data_gathering_default.h>
  13. #include <open62541/plugin/historydata/history_database_default.h>
  14. #include <open62541/plugin/historydatabase.h>
  15. #include <open62541/server.h>
  16. #include <open62541/server_config_default.h>
  17. #include "client/ua_client_internal.h"
  18. #include "server/ua_server_internal.h"
  19. #include "ua_network_tcp.h"
  20. #include <check.h>
  21. #include "testing_clock.h"
  22. #include "testing_networklayers.h"
  23. #include "thread_wrapper.h"
  24. #ifdef UA_ENABLE_HISTORIZING
  25. #include "historical_read_test_data.h"
  26. #include "randomindextest_backend.h"
  27. #endif
  28. #include <stddef.h>
  29. static UA_Server *server;
  30. static UA_ServerConfig *config;
  31. #ifdef UA_ENABLE_HISTORIZING
  32. static UA_HistoryDataGathering *gathering;
  33. #endif
  34. static UA_Boolean running;
  35. static THREAD_HANDLE server_thread;
  36. static MUTEX_HANDLE serverMutex;
  37. static UA_Client *client;
  38. static UA_NodeId parentNodeId;
  39. static UA_NodeId parentReferenceNodeId;
  40. static UA_NodeId outNodeId;
  41. static UA_DateTime *testDataSorted;
  42. static void serverMutexLock(void) {
  43. if (!(MUTEX_LOCK(serverMutex))) {
  44. fprintf(stderr, "Mutex cannot be locked.\n");
  45. exit(1);
  46. }
  47. }
  48. static void serverMutexUnlock(void) {
  49. if (!(MUTEX_UNLOCK(serverMutex))) {
  50. fprintf(stderr, "Mutex cannot be unlocked.\n");
  51. exit(1);
  52. }
  53. }
  54. THREAD_CALLBACK(serverloop)
  55. {
  56. while(running) {
  57. serverMutexLock();
  58. UA_Server_run_iterate(server, false);
  59. serverMutexUnlock();
  60. }
  61. return 0;
  62. }
  63. static void
  64. setup(void)
  65. {
  66. if (!(MUTEX_INIT(serverMutex))) {
  67. fprintf(stderr, "Server mutex was not created correctly.\n");
  68. exit(1);
  69. }
  70. running = true;
  71. config = UA_ServerConfig_new_default();
  72. #ifdef UA_ENABLE_HISTORIZING
  73. gathering = (UA_HistoryDataGathering*)UA_calloc(1, sizeof(UA_HistoryDataGathering));
  74. *gathering = UA_HistoryDataGathering_Default(1);
  75. config->historyDatabase = UA_HistoryDatabase_default(*gathering);
  76. #endif
  77. server = UA_Server_new(config);
  78. UA_StatusCode retval = UA_Server_run_startup(server);
  79. if (retval != UA_STATUSCODE_GOOD)
  80. {
  81. fprintf(stderr, "Error while calling Server_run_startup. %s\n", UA_StatusCode_name(retval));
  82. exit(1);
  83. }
  84. THREAD_CREATE(server_thread, serverloop);
  85. /* Define the attribute of the uint32 variable node */
  86. UA_VariableAttributes attr = UA_VariableAttributes_default;
  87. UA_UInt32 myUint32 = 40;
  88. UA_Variant_setScalar(&attr.value, &myUint32, &UA_TYPES[UA_TYPES_UINT32]);
  89. attr.description = UA_LOCALIZEDTEXT("en-US","the answer");
  90. attr.displayName = UA_LOCALIZEDTEXT("en-US","the answer");
  91. attr.dataType = UA_TYPES[UA_TYPES_UINT32].typeId;
  92. attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD | UA_ACCESSLEVELMASK_HISTORYWRITE;
  93. attr.historizing = true;
  94. /* Add the variable node to the information model */
  95. UA_NodeId uint32NodeId = UA_NODEID_STRING(1, "the.answer");
  96. UA_QualifiedName uint32Name = UA_QUALIFIEDNAME(1, "the answer");
  97. parentNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
  98. parentReferenceNodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
  99. UA_NodeId_init(&outNodeId);
  100. retval = UA_Server_addVariableNode(server,
  101. uint32NodeId,
  102. parentNodeId,
  103. parentReferenceNodeId,
  104. uint32Name,
  105. UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
  106. attr,
  107. NULL,
  108. &outNodeId);
  109. if (retval != UA_STATUSCODE_GOOD)
  110. {
  111. fprintf(stderr, "Error adding variable node. %s\n", UA_StatusCode_name(retval));
  112. exit(1);
  113. }
  114. client = UA_Client_new();
  115. UA_ClientConfig_setDefault(UA_Client_getConfig(client));
  116. retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
  117. if (retval != UA_STATUSCODE_GOOD)
  118. {
  119. fprintf(stderr, "Client can not connect to opc.tcp://localhost:4840. %s\n", UA_StatusCode_name(retval));
  120. exit(1);
  121. }
  122. UA_Client_recv = client->connection.recv;
  123. client->connection.recv = UA_Client_recvTesting;
  124. }
  125. static void
  126. teardown(void)
  127. {
  128. /* cleanup */
  129. UA_Client_disconnect(client);
  130. UA_Client_delete(client);
  131. running = false;
  132. THREAD_JOIN(server_thread);
  133. UA_NodeId_deleteMembers(&parentNodeId);
  134. UA_NodeId_deleteMembers(&parentReferenceNodeId);
  135. UA_NodeId_deleteMembers(&outNodeId);
  136. UA_Server_run_shutdown(server);
  137. UA_Server_delete(server);
  138. UA_ServerConfig_delete(config);
  139. #ifdef UA_ENABLE_HISTORIZING
  140. UA_free(gathering);
  141. #endif
  142. if (!MUTEX_DESTROY(serverMutex)) {
  143. fprintf(stderr, "Server mutex was not destroyed correctly.\n");
  144. exit(1);
  145. }
  146. }
  147. #ifdef UA_ENABLE_HISTORIZING
  148. #include <stdio.h>
  149. #include "ua_session.h"
  150. static UA_StatusCode
  151. setUInt32(UA_Client *thisClient, UA_NodeId node, UA_UInt32 value)
  152. {
  153. UA_Variant variant;
  154. UA_Variant_setScalar(&variant, &value, &UA_TYPES[UA_TYPES_UINT32]);
  155. return UA_Client_writeValueAttribute(thisClient, node, &variant);
  156. }
  157. static UA_DateTime* sortDateTimes(UA_DateTime *data) {
  158. size_t count = 0;
  159. while(data[count++]);
  160. UA_DateTime* ret;
  161. if (UA_Array_copy(data, count, (void**)&ret, &UA_TYPES[UA_TYPES_DATETIME]) != UA_STATUSCODE_GOOD)
  162. return NULL;
  163. --count;
  164. // sort it
  165. for (size_t i = 1; i < count; i++) {
  166. for (size_t j = 0; j < count - i; j++) {
  167. if (ret[j] > ret[j+1]) {
  168. UA_DateTime tmp = ret[j];
  169. ret[j] = ret[j+1];
  170. ret[j+1] = tmp;
  171. }
  172. }
  173. }
  174. return ret;
  175. }
  176. static void
  177. printTimestamp(UA_DateTime timestamp)
  178. {
  179. if (timestamp == TIMESTAMP_FIRST) {
  180. fprintf(stderr, "FIRST,");
  181. } else if (timestamp == TIMESTAMP_LAST) {
  182. fprintf(stderr, "LAST,");
  183. } else {
  184. fprintf(stderr, "%3lld,", timestamp / UA_DATETIME_SEC);
  185. }
  186. }
  187. static void
  188. printResult(UA_DataValue * value)
  189. {
  190. if (value->status != UA_STATUSCODE_GOOD)
  191. fprintf(stderr, "%s:", UA_StatusCode_name(value->status));
  192. printTimestamp(value->sourceTimestamp);
  193. }
  194. static UA_Boolean
  195. resultIsEqual(const UA_DataValue * result, const testTuple * tuple, size_t index)
  196. {
  197. switch (tuple->result[index]) {
  198. case TIMESTAMP_FIRST:
  199. if (result->status != UA_STATUSCODE_BADBOUNDNOTFOUND
  200. || !UA_Variant_isEmpty(&result->value))
  201. return false;
  202. /* we do not test timestamp if TIMESTAMP_UNSPECIFIED is given for start.
  203. * See OPC UA Part 11, Version 1.03, Page 5-6, Table 1, Mark b for details.*/
  204. if (tuple->start != TIMESTAMP_UNSPECIFIED
  205. && tuple->start != result->sourceTimestamp)
  206. return false;
  207. break;
  208. case TIMESTAMP_LAST:
  209. if (result->status != UA_STATUSCODE_BADBOUNDNOTFOUND
  210. || !UA_Variant_isEmpty(&result->value))
  211. return false;
  212. /* we do not test timestamp if TIMESTAMP_UNSPECIFIED is given for end.
  213. * See OPC UA Part 11, Version 1.03, Page 5-6, Table 1, Mark a for details.*/
  214. if (tuple->end != TIMESTAMP_UNSPECIFIED
  215. && tuple->end != result->sourceTimestamp)
  216. return false;
  217. break;
  218. default:
  219. if (result->sourceTimestamp != tuple->result[index]
  220. || result->value.type != &UA_TYPES[UA_TYPES_INT64]
  221. || *((UA_Int64*)result->value.data) != tuple->result[index])
  222. return false;
  223. }
  224. return true;
  225. }
  226. static UA_Boolean
  227. fillHistoricalDataBackend(UA_HistoryDataBackend backend)
  228. {
  229. int i = 0;
  230. UA_DateTime currentDateTime = testData[i];
  231. fprintf(stderr, "Adding to historical data backend: ");
  232. while (currentDateTime) {
  233. fprintf(stderr, "%lld, ", currentDateTime / UA_DATETIME_SEC);
  234. UA_DataValue value;
  235. UA_DataValue_init(&value);
  236. value.hasValue = true;
  237. UA_Int64 d = currentDateTime;
  238. UA_Variant_setScalarCopy(&value.value, &d, &UA_TYPES[UA_TYPES_INT64]);
  239. value.hasSourceTimestamp = true;
  240. value.sourceTimestamp = currentDateTime;
  241. value.hasServerTimestamp = true;
  242. value.serverTimestamp = currentDateTime;
  243. value.hasStatus = true;
  244. value.status = UA_STATUSCODE_GOOD;
  245. if (backend.serverSetHistoryData(server, backend.context, NULL, NULL, &outNodeId, UA_FALSE, &value) != UA_STATUSCODE_GOOD) {
  246. fprintf(stderr, "\n");
  247. return false;
  248. }
  249. UA_DataValue_deleteMembers(&value);
  250. currentDateTime = testData[++i];
  251. }
  252. fprintf(stderr, "\n");
  253. return true;
  254. }
  255. void
  256. Service_HistoryRead(UA_Server *server, UA_Session *session,
  257. const UA_HistoryReadRequest *request,
  258. UA_HistoryReadResponse *response);
  259. static void
  260. requestHistory(UA_DateTime start,
  261. UA_DateTime end,
  262. UA_HistoryReadResponse * response,
  263. UA_UInt32 numValuesPerNode,
  264. UA_Boolean returnBounds,
  265. UA_ByteString *continuationPoint)
  266. {
  267. UA_ReadRawModifiedDetails *details = UA_ReadRawModifiedDetails_new();
  268. details->startTime = start;
  269. details->endTime = end;
  270. details->isReadModified = false;
  271. details->numValuesPerNode = numValuesPerNode;
  272. details->returnBounds = returnBounds;
  273. UA_HistoryReadValueId *valueId = UA_HistoryReadValueId_new();
  274. UA_NodeId_copy(&outNodeId, &valueId->nodeId);
  275. if (continuationPoint)
  276. UA_ByteString_copy(continuationPoint, &valueId->continuationPoint);
  277. UA_HistoryReadRequest request;
  278. UA_HistoryReadRequest_init(&request);
  279. request.historyReadDetails.encoding = UA_EXTENSIONOBJECT_DECODED;
  280. request.historyReadDetails.content.decoded.type = &UA_TYPES[UA_TYPES_READRAWMODIFIEDDETAILS];
  281. request.historyReadDetails.content.decoded.data = details;
  282. request.timestampsToReturn = UA_TIMESTAMPSTORETURN_BOTH;
  283. request.nodesToReadSize = 1;
  284. request.nodesToRead = valueId;
  285. Service_HistoryRead(server, &server->adminSession, &request, response);
  286. UA_HistoryReadRequest_deleteMembers(&request);
  287. }
  288. static UA_UInt32
  289. testHistoricalDataBackend(size_t maxResponseSize)
  290. {
  291. const UA_HistorizingNodeIdSettings* setting = gathering->getHistorizingSetting(server, gathering->context, &outNodeId);
  292. UA_HistorizingNodeIdSettings newSetting = *setting;
  293. newSetting.maxHistoryDataResponseSize = maxResponseSize;
  294. gathering->updateNodeIdSetting(server, gathering->context, &outNodeId, newSetting);
  295. UA_UInt32 retval = 0;
  296. size_t i = 0;
  297. testTuple *current = &testRequests[i];
  298. fprintf(stderr, "Testing with maxResponseSize of %lu\n", maxResponseSize);
  299. fprintf(stderr, "Start | End | numValuesPerNode | returnBounds |ContPoint| {Expected}{Result} Result\n");
  300. fprintf(stderr, "------+------+------------------+--------------+---------+----------------\n");
  301. size_t j;
  302. while (current->start || current->end) {
  303. j = 0;
  304. if (current->start == TIMESTAMP_UNSPECIFIED) {
  305. fprintf(stderr, "UNSPEC|");
  306. } else {
  307. fprintf(stderr, " %3lld |", current->start / UA_DATETIME_SEC);
  308. }
  309. if (current->end == TIMESTAMP_UNSPECIFIED) {
  310. fprintf(stderr, "UNSPEC|");
  311. } else {
  312. fprintf(stderr, " %3lld |", current->end / UA_DATETIME_SEC);
  313. }
  314. fprintf(stderr, " %2u | %s | %s | {", current->numValuesPerNode, (current->returnBounds ? "Yes" : " No"), (current->returnContinuationPoint ? "Yes" : " No"));
  315. while (current->result[j]) {
  316. printTimestamp(current->result[j]);
  317. ++j;
  318. }
  319. fprintf(stderr, "}");
  320. UA_DataValue *result = NULL;
  321. size_t resultSize = 0;
  322. UA_ByteString continuous;
  323. UA_ByteString_init(&continuous);
  324. UA_Boolean readOk = true;
  325. size_t reseivedValues = 0;
  326. fprintf(stderr, "{");
  327. size_t counter = 0;
  328. do {
  329. UA_HistoryReadResponse response;
  330. UA_HistoryReadResponse_init(&response);
  331. UA_UInt32 numValuesPerNode = current->numValuesPerNode;
  332. if (numValuesPerNode > 0 && numValuesPerNode + (UA_UInt32)reseivedValues > current->numValuesPerNode)
  333. numValuesPerNode = current->numValuesPerNode - (UA_UInt32)reseivedValues;
  334. requestHistory(current->start,
  335. current->end,
  336. &response,
  337. numValuesPerNode,
  338. current->returnBounds,
  339. &continuous);
  340. ++counter;
  341. if(response.resultsSize != 1) {
  342. fprintf(stderr, "ResultError:Size %lu %s", response.resultsSize, UA_StatusCode_name(response.responseHeader.serviceResult));
  343. readOk = false;
  344. UA_HistoryReadResponse_deleteMembers(&response);
  345. break;
  346. }
  347. UA_StatusCode stat = response.results[0].statusCode;
  348. if (stat == UA_STATUSCODE_BADBOUNDNOTSUPPORTED && current->returnBounds) {
  349. fprintf(stderr, "%s", UA_StatusCode_name(stat));
  350. UA_HistoryReadResponse_deleteMembers(&response);
  351. break;
  352. }
  353. if(response.results[0].historyData.encoding != UA_EXTENSIONOBJECT_DECODED
  354. || response.results[0].historyData.content.decoded.type != &UA_TYPES[UA_TYPES_HISTORYDATA]) {
  355. fprintf(stderr, "ResultError:HistoryData");
  356. readOk = false;
  357. UA_HistoryReadResponse_deleteMembers(&response);
  358. break;
  359. }
  360. UA_HistoryData * data = (UA_HistoryData *)response.results[0].historyData.content.decoded.data;
  361. resultSize = data->dataValuesSize;
  362. result = data->dataValues;
  363. if (resultSize == 0 && continuous.length > 0) {
  364. fprintf(stderr, "continuousResultEmpty");
  365. readOk = false;
  366. UA_HistoryReadResponse_deleteMembers(&response);
  367. break;
  368. }
  369. if (resultSize > maxResponseSize) {
  370. fprintf(stderr, "resultToBig");
  371. readOk = false;
  372. UA_HistoryReadResponse_deleteMembers(&response);
  373. break;
  374. }
  375. if (stat != UA_STATUSCODE_GOOD) {
  376. fprintf(stderr, "%s", UA_StatusCode_name(stat));
  377. } else {
  378. for (size_t k = 0; k < resultSize; ++k)
  379. printResult(&result[k]);
  380. }
  381. if (stat == UA_STATUSCODE_GOOD && j >= resultSize + reseivedValues) {
  382. for (size_t l = 0; l < resultSize; ++l) {
  383. /* See OPC UA Part 11, Version 1.03, Page 5-6, Table 1, Mark a for details.*/
  384. if (current->result[l + reseivedValues] == TIMESTAMP_LAST && current->end == TIMESTAMP_UNSPECIFIED) {
  385. // This test will work on not continous read, only
  386. if (reseivedValues == 0 && !(l > 0 && result[l].sourceTimestamp == result[l-1].sourceTimestamp + UA_DATETIME_SEC))
  387. readOk = false;
  388. }
  389. /* See OPC UA Part 11, Version 1.03, Page 5-6, Table 1, Mark b for details.*/
  390. if (current->result[l + reseivedValues] == TIMESTAMP_FIRST && current->start == TIMESTAMP_UNSPECIFIED) {
  391. // This test will work on not continous read, only
  392. if (reseivedValues == 0 && !(l > 0 && result[l].sourceTimestamp == result[l-1].sourceTimestamp - UA_DATETIME_SEC))
  393. readOk = false;
  394. }
  395. if (!resultIsEqual(&result[l], current, l + reseivedValues))
  396. readOk = false;
  397. }
  398. if (response.results[0].continuationPoint.length > 0)
  399. fprintf(stderr, "C,");
  400. reseivedValues += resultSize;
  401. if (reseivedValues == j) {
  402. if (current->returnContinuationPoint && response.results[0].continuationPoint.length == 0) {
  403. readOk = false;
  404. fprintf(stderr, "missingContinuationPoint");
  405. }
  406. if (!current->returnContinuationPoint && response.results[0].continuationPoint.length > 0) {
  407. readOk = false;
  408. fprintf(stderr, "unexpectedContinuationPoint");
  409. }
  410. UA_HistoryReadResponse_deleteMembers(&response);
  411. break;
  412. }
  413. UA_ByteString_deleteMembers(&continuous);
  414. UA_ByteString_copy(&response.results[0].continuationPoint, &continuous);
  415. } else {
  416. readOk = false;
  417. UA_HistoryReadResponse_deleteMembers(&response);
  418. break;
  419. }
  420. UA_HistoryReadResponse_deleteMembers(&response);
  421. } while (continuous.length > 0);
  422. if (j != reseivedValues) {
  423. readOk = false;
  424. }
  425. UA_ByteString_deleteMembers(&continuous);
  426. if (!readOk) {
  427. fprintf(stderr, "} Fail (%lu requests)\n", counter);
  428. ++retval;
  429. } else {
  430. fprintf(stderr, "} OK (%lu requests)\n", counter);
  431. }
  432. current = &testRequests[++i];
  433. }
  434. return retval;
  435. }
  436. void
  437. Service_HistoryUpdate(UA_Server *server, UA_Session *session,
  438. const UA_HistoryUpdateRequest *request,
  439. UA_HistoryUpdateResponse *response);
  440. static UA_StatusCode
  441. deleteHistory(UA_DateTime start,
  442. UA_DateTime end)
  443. {
  444. UA_DeleteRawModifiedDetails *details = UA_DeleteRawModifiedDetails_new();
  445. details->startTime = start;
  446. details->endTime = end;
  447. details->isDeleteModified = false;
  448. UA_NodeId_copy(&outNodeId, &details->nodeId);
  449. UA_HistoryUpdateRequest request;
  450. UA_HistoryUpdateRequest_init(&request);
  451. request.historyUpdateDetailsSize = 1;
  452. request.historyUpdateDetails = UA_ExtensionObject_new();
  453. UA_ExtensionObject_init(request.historyUpdateDetails);
  454. request.historyUpdateDetails[0].encoding = UA_EXTENSIONOBJECT_DECODED;
  455. request.historyUpdateDetails[0].content.decoded.type = &UA_TYPES[UA_TYPES_DELETERAWMODIFIEDDETAILS];
  456. request.historyUpdateDetails[0].content.decoded.data = details;
  457. UA_HistoryUpdateResponse response;
  458. UA_HistoryUpdateResponse_init(&response);
  459. Service_HistoryUpdate(server, &server->adminSession, &request, &response);
  460. UA_HistoryUpdateRequest_deleteMembers(&request);
  461. UA_StatusCode ret = UA_STATUSCODE_GOOD;
  462. if (response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  463. ret = response.responseHeader.serviceResult;
  464. else if (response.resultsSize != 1)
  465. ret = UA_STATUSCODE_BADUNEXPECTEDERROR;
  466. else if (response.results[0].statusCode != UA_STATUSCODE_GOOD)
  467. ret = response.results[0].statusCode;
  468. else if (response.results[0].operationResultsSize != 0)
  469. ret = UA_STATUSCODE_BADUNEXPECTEDERROR;
  470. UA_HistoryUpdateResponse_deleteMembers(&response);
  471. return ret;
  472. }
  473. static UA_StatusCode
  474. updateHistory(UA_PerformUpdateType updateType, UA_DateTime *updateData, UA_StatusCode ** operationResults, size_t *operationResultsSize)
  475. {
  476. UA_UpdateDataDetails *details = UA_UpdateDataDetails_new();
  477. details->performInsertReplace = updateType;
  478. UA_NodeId_copy(&outNodeId, &details->nodeId);
  479. int updateDataSize = -1;
  480. while(updateData[++updateDataSize]);
  481. fprintf(stderr, "updateHistory for %d values.\n", updateDataSize);
  482. details->updateValuesSize = (size_t)updateDataSize;
  483. details->updateValues = (UA_DataValue*)UA_Array_new(details->updateValuesSize, &UA_TYPES[UA_TYPES_DATAVALUE]);
  484. for (size_t i = 0; i < details->updateValuesSize; ++i) {
  485. UA_DataValue_init(&details->updateValues[i]);
  486. details->updateValues[i].hasValue = true;
  487. UA_Int64 d = updateType;
  488. UA_Variant_setScalarCopy(&details->updateValues[i].value, &d, &UA_TYPES[UA_TYPES_INT64]);
  489. details->updateValues[i].hasSourceTimestamp = true;
  490. details->updateValues[i].sourceTimestamp = updateData[i];
  491. details->updateValues[i].hasServerTimestamp = true;
  492. details->updateValues[i].serverTimestamp = updateData[i];
  493. details->updateValues[i].hasStatus = true;
  494. details->updateValues[i].status = UA_STATUSCODE_GOOD;
  495. }
  496. UA_HistoryUpdateRequest request;
  497. UA_HistoryUpdateRequest_init(&request);
  498. request.historyUpdateDetailsSize = 1;
  499. request.historyUpdateDetails = UA_ExtensionObject_new();
  500. UA_ExtensionObject_init(request.historyUpdateDetails);
  501. request.historyUpdateDetails[0].encoding = UA_EXTENSIONOBJECT_DECODED;
  502. request.historyUpdateDetails[0].content.decoded.type = &UA_TYPES[UA_TYPES_UPDATEDATADETAILS];
  503. request.historyUpdateDetails[0].content.decoded.data = details;
  504. UA_HistoryUpdateResponse response;
  505. UA_HistoryUpdateResponse_init(&response);
  506. Service_HistoryUpdate(server, &server->adminSession, &request, &response);
  507. UA_HistoryUpdateRequest_deleteMembers(&request);
  508. UA_StatusCode ret = UA_STATUSCODE_GOOD;
  509. if (response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
  510. ret = response.responseHeader.serviceResult;
  511. else if (response.resultsSize != 1)
  512. ret = UA_STATUSCODE_BADUNEXPECTEDERROR;
  513. else if (response.results[0].statusCode != UA_STATUSCODE_GOOD)
  514. ret = response.results[0].statusCode;
  515. else if (response.results[0].operationResultsSize != (size_t)updateDataSize)
  516. ret = UA_STATUSCODE_BADUNEXPECTEDERROR;
  517. else {
  518. if (operationResults) {
  519. *operationResultsSize = response.results[0].operationResultsSize;
  520. ret = UA_Array_copy(response.results[0].operationResults, *operationResultsSize, (void**)operationResults, &UA_TYPES[UA_TYPES_STATUSCODE]);
  521. } else {
  522. for (size_t i = 0; i < response.results[0].operationResultsSize; ++i) {
  523. if (response.results[0].operationResults[i] != UA_STATUSCODE_GOOD) {
  524. ret = response.results[0].operationResults[i];
  525. break;
  526. }
  527. }
  528. }
  529. }
  530. UA_HistoryUpdateResponse_deleteMembers(&response);
  531. return ret;
  532. }
  533. static void
  534. testResult(UA_DateTime *resultData, UA_HistoryData * historyData) {
  535. // request
  536. UA_HistoryReadResponse localResponse;
  537. UA_HistoryReadResponse_init(&localResponse);
  538. requestHistory(TIMESTAMP_FIRST, TIMESTAMP_LAST, &localResponse, 0, false, NULL);
  539. // test the response
  540. ck_assert_str_eq(UA_StatusCode_name(localResponse.responseHeader.serviceResult), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  541. ck_assert_uint_eq(localResponse.resultsSize, 1);
  542. ck_assert_str_eq(UA_StatusCode_name(localResponse.results[0].statusCode), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  543. ck_assert_uint_eq(localResponse.results[0].historyData.encoding, UA_EXTENSIONOBJECT_DECODED);
  544. ck_assert(localResponse.results[0].historyData.content.decoded.type == &UA_TYPES[UA_TYPES_HISTORYDATA]);
  545. UA_HistoryData * data = (UA_HistoryData *)localResponse.results[0].historyData.content.decoded.data;
  546. if (historyData)
  547. UA_HistoryData_copy(data, historyData);
  548. for (size_t j = 0; j < data->dataValuesSize; ++j) {
  549. ck_assert(resultData[j] != 0);
  550. ck_assert_uint_eq(data->dataValues[j].hasSourceTimestamp, true);
  551. ck_assert_uint_eq(data->dataValues[j].sourceTimestamp, resultData[j]);
  552. }
  553. UA_HistoryReadResponse_deleteMembers(&localResponse);
  554. }
  555. START_TEST(Server_HistorizingUpdateDelete)
  556. {
  557. UA_HistoryDataBackend backend = UA_HistoryDataBackend_Memory(1, 1);
  558. UA_HistorizingNodeIdSettings setting;
  559. setting.historizingBackend = backend;
  560. setting.maxHistoryDataResponseSize = 1000;
  561. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_USER;
  562. serverMutexLock();
  563. UA_StatusCode ret = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  564. serverMutexUnlock();
  565. ck_assert_str_eq(UA_StatusCode_name(ret), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  566. // fill backend
  567. ck_assert_uint_eq(fillHistoricalDataBackend(backend), true);
  568. // delete some values
  569. ck_assert_str_eq(UA_StatusCode_name(deleteHistory(DELETE_START_TIME, DELETE_STOP_TIME)),
  570. UA_StatusCode_name(UA_STATUSCODE_GOOD));
  571. testResult(testDataAfterDelete, NULL);
  572. UA_HistoryDataBackend_Memory_deleteMembers(&setting.historizingBackend);
  573. }
  574. END_TEST
  575. START_TEST(Server_HistorizingUpdateInsert)
  576. {
  577. UA_HistoryDataBackend backend = UA_HistoryDataBackend_Memory(1, 1);
  578. UA_HistorizingNodeIdSettings setting;
  579. setting.historizingBackend = backend;
  580. setting.maxHistoryDataResponseSize = 1000;
  581. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_USER;
  582. serverMutexLock();
  583. UA_StatusCode ret = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  584. serverMutexUnlock();
  585. ck_assert_str_eq(UA_StatusCode_name(ret), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  586. // fill backend with insert
  587. ck_assert_str_eq(UA_StatusCode_name(updateHistory(UA_PERFORMUPDATETYPE_INSERT, testData, NULL, NULL))
  588. , UA_StatusCode_name(UA_STATUSCODE_GOOD));
  589. UA_HistoryData data;
  590. UA_HistoryData_init(&data);
  591. testResult(testDataSorted, &data);
  592. for (size_t i = 0; i < data.dataValuesSize; ++i) {
  593. ck_assert_uint_eq(data.dataValues[i].hasValue, true);
  594. ck_assert(data.dataValues[i].value.type == &UA_TYPES[UA_TYPES_INT64]);
  595. ck_assert_uint_eq(*((UA_Int64*)data.dataValues[i].value.data), UA_PERFORMUPDATETYPE_INSERT);
  596. }
  597. UA_HistoryData_deleteMembers(&data);
  598. UA_HistoryDataBackend_Memory_deleteMembers(&setting.historizingBackend);
  599. }
  600. END_TEST
  601. START_TEST(Server_HistorizingUpdateReplace)
  602. {
  603. UA_HistoryDataBackend backend = UA_HistoryDataBackend_Memory(1, 1);
  604. UA_HistorizingNodeIdSettings setting;
  605. setting.historizingBackend = backend;
  606. setting.maxHistoryDataResponseSize = 1000;
  607. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_USER;
  608. serverMutexLock();
  609. UA_StatusCode ret = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  610. serverMutexUnlock();
  611. ck_assert_str_eq(UA_StatusCode_name(ret), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  612. // fill backend with insert
  613. ck_assert_str_eq(UA_StatusCode_name(updateHistory(UA_PERFORMUPDATETYPE_INSERT, testData, NULL, NULL))
  614. , UA_StatusCode_name(UA_STATUSCODE_GOOD));
  615. // replace all
  616. ck_assert_str_eq(UA_StatusCode_name(updateHistory(UA_PERFORMUPDATETYPE_REPLACE, testData, NULL, NULL))
  617. , UA_StatusCode_name(UA_STATUSCODE_GOOD));
  618. UA_HistoryData data;
  619. UA_HistoryData_init(&data);
  620. testResult(testDataSorted, &data);
  621. for (size_t i = 0; i < data.dataValuesSize; ++i) {
  622. ck_assert_uint_eq(data.dataValues[i].hasValue, true);
  623. ck_assert(data.dataValues[i].value.type == &UA_TYPES[UA_TYPES_INT64]);
  624. ck_assert_uint_eq(*((UA_Int64*)data.dataValues[i].value.data), UA_PERFORMUPDATETYPE_REPLACE);
  625. }
  626. UA_HistoryData_deleteMembers(&data);
  627. UA_HistoryDataBackend_Memory_deleteMembers(&setting.historizingBackend);
  628. }
  629. END_TEST
  630. START_TEST(Server_HistorizingUpdateUpdate)
  631. {
  632. UA_HistoryDataBackend backend = UA_HistoryDataBackend_Memory(1, 1);
  633. UA_HistorizingNodeIdSettings setting;
  634. setting.historizingBackend = backend;
  635. setting.maxHistoryDataResponseSize = 1000;
  636. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_USER;
  637. serverMutexLock();
  638. UA_StatusCode ret = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  639. serverMutexUnlock();
  640. ck_assert_str_eq(UA_StatusCode_name(ret), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  641. // fill backend with insert
  642. ck_assert_str_eq(UA_StatusCode_name(updateHistory(UA_PERFORMUPDATETYPE_INSERT, testData, NULL, NULL))
  643. , UA_StatusCode_name(UA_STATUSCODE_GOOD));
  644. testResult(testDataSorted, NULL);
  645. // delete some values
  646. ck_assert_str_eq(UA_StatusCode_name(deleteHistory(DELETE_START_TIME, DELETE_STOP_TIME)),
  647. UA_StatusCode_name(UA_STATUSCODE_GOOD));
  648. testResult(testDataAfterDelete, NULL);
  649. // update all and insert some
  650. UA_StatusCode *result;
  651. size_t resultSize = 0;
  652. ck_assert_str_eq(UA_StatusCode_name(updateHistory(UA_PERFORMUPDATETYPE_UPDATE, testDataSorted, &result, &resultSize))
  653. , UA_StatusCode_name(UA_STATUSCODE_GOOD));
  654. for (size_t i = 0; i < resultSize; ++i) {
  655. ck_assert_str_eq(UA_StatusCode_name(result[i]), UA_StatusCode_name(testDataUpdateResult[i]));
  656. }
  657. UA_Array_delete(result, resultSize, &UA_TYPES[UA_TYPES_STATUSCODE]);
  658. UA_HistoryData data;
  659. UA_HistoryData_init(&data);
  660. testResult(testDataSorted, &data);
  661. for (size_t i = 0; i < data.dataValuesSize; ++i) {
  662. ck_assert_uint_eq(data.dataValues[i].hasValue, true);
  663. ck_assert(data.dataValues[i].value.type == &UA_TYPES[UA_TYPES_INT64]);
  664. ck_assert_uint_eq(*((UA_Int64*)data.dataValues[i].value.data), UA_PERFORMUPDATETYPE_UPDATE);
  665. }
  666. UA_HistoryData_deleteMembers(&data);
  667. UA_HistoryDataBackend_Memory_deleteMembers(&setting.historizingBackend);
  668. }
  669. END_TEST
  670. START_TEST(Server_HistorizingStrategyUser)
  671. {
  672. // set a data backend
  673. UA_HistorizingNodeIdSettings setting;
  674. setting.historizingBackend = UA_HistoryDataBackend_Memory(3, 100);
  675. setting.maxHistoryDataResponseSize = 100;
  676. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_USER;
  677. UA_StatusCode retval = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  678. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  679. // fill the data
  680. UA_DateTime start = UA_DateTime_now();
  681. UA_DateTime end = start + (10 * UA_DATETIME_SEC);
  682. for (UA_UInt32 i = 0; i < 10; ++i) {
  683. UA_DataValue value;
  684. UA_DataValue_init(&value);
  685. value.hasValue = true;
  686. value.hasStatus = true;
  687. value.status = UA_STATUSCODE_GOOD;
  688. UA_Variant_setScalarCopy(&value.value, &i, &UA_TYPES[UA_TYPES_UINT32]);
  689. value.hasSourceTimestamp = true;
  690. value.sourceTimestamp = start + (i * UA_DATETIME_SEC);
  691. value.hasServerTimestamp = true;
  692. value.serverTimestamp = value.sourceTimestamp;
  693. retval = setting.historizingBackend.serverSetHistoryData(server,
  694. setting.historizingBackend.context,
  695. NULL,
  696. NULL,
  697. &outNodeId,
  698. UA_FALSE,
  699. &value);
  700. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  701. UA_DataValue_deleteMembers(&value);
  702. }
  703. // request
  704. UA_HistoryReadResponse response;
  705. UA_HistoryReadResponse_init(&response);
  706. requestHistory(start, end, &response, 0, false, NULL);
  707. // test the response
  708. ck_assert_str_eq(UA_StatusCode_name(response.responseHeader.serviceResult), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  709. ck_assert_uint_eq(response.resultsSize, 1);
  710. for (size_t i = 0; i < response.resultsSize; ++i) {
  711. ck_assert_str_eq(UA_StatusCode_name(response.results[i].statusCode), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  712. ck_assert_uint_eq(response.results[i].historyData.encoding, UA_EXTENSIONOBJECT_DECODED);
  713. ck_assert(response.results[i].historyData.content.decoded.type == &UA_TYPES[UA_TYPES_HISTORYDATA]);
  714. UA_HistoryData * data = (UA_HistoryData *)response.results[i].historyData.content.decoded.data;
  715. ck_assert_uint_eq(data->dataValuesSize, 10);
  716. for (size_t j = 0; j < data->dataValuesSize; ++j) {
  717. ck_assert_uint_eq(data->dataValues[j].hasSourceTimestamp, true);
  718. ck_assert_uint_eq(data->dataValues[j].sourceTimestamp, start + (j * UA_DATETIME_SEC));
  719. ck_assert_uint_eq(data->dataValues[j].hasStatus, true);
  720. ck_assert_str_eq(UA_StatusCode_name(data->dataValues[j].status), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  721. ck_assert_uint_eq(data->dataValues[j].hasValue, true);
  722. ck_assert(data->dataValues[j].value.type == &UA_TYPES[UA_TYPES_UINT32]);
  723. UA_UInt32 * value = (UA_UInt32 *)data->dataValues[j].value.data;
  724. ck_assert_uint_eq(*value, j);
  725. }
  726. }
  727. UA_HistoryReadResponse_deleteMembers(&response);
  728. UA_HistoryDataBackend_Memory_deleteMembers(&setting.historizingBackend);
  729. }
  730. END_TEST
  731. START_TEST(Server_HistorizingStrategyPoll)
  732. {
  733. // init to a defined value
  734. UA_StatusCode retval = setUInt32(client, outNodeId, 43);
  735. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  736. // set a data backend
  737. UA_HistorizingNodeIdSettings setting;
  738. setting.historizingBackend = UA_HistoryDataBackend_Memory(3, 100);
  739. setting.maxHistoryDataResponseSize = 100;
  740. setting.pollingInterval = 100;
  741. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_POLL;
  742. serverMutexLock();
  743. retval = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  744. serverMutexUnlock();
  745. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  746. // fill the data
  747. UA_DateTime start = UA_DateTime_now();
  748. serverMutexLock();
  749. retval = gathering->startPoll(server, gathering->context, &outNodeId);
  750. serverMutexUnlock();
  751. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  752. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  753. for (size_t k = 0; k < 10; ++k) {
  754. UA_fakeSleep(50);
  755. UA_realSleep(50);
  756. if (k == 5) {
  757. serverMutexLock();
  758. gathering->stopPoll(server, gathering->context, &outNodeId);
  759. serverMutexUnlock();
  760. }
  761. setUInt32(client, outNodeId, (unsigned int)k);
  762. }
  763. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  764. UA_DateTime end = UA_DateTime_now();
  765. // request
  766. UA_HistoryReadResponse response;
  767. UA_HistoryReadResponse_init(&response);
  768. requestHistory(start, end, &response, 0, false, NULL);
  769. // test the response
  770. ck_assert_str_eq(UA_StatusCode_name(response.responseHeader.serviceResult), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  771. ck_assert_uint_eq(response.resultsSize, 1);
  772. for (size_t i = 0; i < response.resultsSize; ++i) {
  773. ck_assert_str_eq(UA_StatusCode_name(response.results[i].statusCode), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  774. ck_assert_uint_eq(response.results[i].historyData.encoding, UA_EXTENSIONOBJECT_DECODED);
  775. ck_assert(response.results[i].historyData.content.decoded.type == &UA_TYPES[UA_TYPES_HISTORYDATA]);
  776. UA_HistoryData * data = (UA_HistoryData *)response.results[i].historyData.content.decoded.data;
  777. ck_assert(data->dataValuesSize > 1);
  778. for (size_t j = 0; j < data->dataValuesSize; ++j) {
  779. ck_assert_uint_eq(data->dataValues[j].hasSourceTimestamp, true);
  780. ck_assert(data->dataValues[j].sourceTimestamp >= start);
  781. ck_assert(data->dataValues[j].sourceTimestamp < end);
  782. ck_assert_uint_eq(data->dataValues[j].hasValue, true);
  783. ck_assert(data->dataValues[j].value.type == &UA_TYPES[UA_TYPES_UINT32]);
  784. UA_UInt32 * value = (UA_UInt32 *)data->dataValues[j].value.data;
  785. // first need to be 43
  786. if (j == 0) {
  787. ck_assert(*value == 43);
  788. } else {
  789. ck_assert(*value < 5);
  790. }
  791. }
  792. }
  793. UA_HistoryReadResponse_deleteMembers(&response);
  794. UA_HistoryDataBackend_Memory_deleteMembers(&setting.historizingBackend);
  795. }
  796. END_TEST
  797. START_TEST(Server_HistorizingStrategyValueSet)
  798. {
  799. // init to a defined value
  800. UA_StatusCode retval = setUInt32(client, outNodeId, 43);
  801. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  802. // set a data backend
  803. UA_HistorizingNodeIdSettings setting;
  804. setting.historizingBackend = UA_HistoryDataBackend_Memory(3, 100);
  805. setting.maxHistoryDataResponseSize = 100;
  806. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_VALUESET;
  807. serverMutexLock();
  808. retval = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  809. serverMutexUnlock();
  810. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  811. // fill the data
  812. UA_fakeSleep(100);
  813. UA_DateTime start = UA_DateTime_now();
  814. UA_fakeSleep(100);
  815. for (UA_UInt32 i = 0; i < 10; ++i) {
  816. retval = setUInt32(client, outNodeId, i);
  817. ck_assert_str_eq(UA_StatusCode_name(retval), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  818. UA_fakeSleep(100);
  819. }
  820. UA_DateTime end = UA_DateTime_now();
  821. // request
  822. UA_HistoryReadResponse response;
  823. UA_HistoryReadResponse_init(&response);
  824. requestHistory(start, end, &response, 0, false, NULL);
  825. // test the response
  826. ck_assert_str_eq(UA_StatusCode_name(response.responseHeader.serviceResult), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  827. ck_assert_uint_eq(response.resultsSize, 1);
  828. for (size_t i = 0; i < response.resultsSize; ++i) {
  829. ck_assert_str_eq(UA_StatusCode_name(response.results[i].statusCode), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  830. ck_assert_uint_eq(response.results[i].historyData.encoding, UA_EXTENSIONOBJECT_DECODED);
  831. ck_assert(response.results[i].historyData.content.decoded.type == &UA_TYPES[UA_TYPES_HISTORYDATA]);
  832. UA_HistoryData * data = (UA_HistoryData *)response.results[i].historyData.content.decoded.data;
  833. ck_assert(data->dataValuesSize > 0);
  834. for (size_t j = 0; j < data->dataValuesSize; ++j) {
  835. ck_assert(data->dataValues[j].sourceTimestamp >= start && data->dataValues[j].sourceTimestamp < end);
  836. ck_assert_uint_eq(data->dataValues[j].hasSourceTimestamp, true);
  837. ck_assert_str_eq(UA_StatusCode_name(data->dataValues[j].status), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  838. ck_assert_uint_eq(data->dataValues[j].hasValue, true);
  839. ck_assert(data->dataValues[j].value.type == &UA_TYPES[UA_TYPES_UINT32]);
  840. UA_UInt32 * value = (UA_UInt32 *)data->dataValues[j].value.data;
  841. ck_assert_uint_eq(*value, j);
  842. }
  843. }
  844. UA_HistoryReadResponse_deleteMembers(&response);
  845. UA_HistoryDataBackend_Memory_deleteMembers(&setting.historizingBackend);
  846. }
  847. END_TEST
  848. START_TEST(Server_HistorizingBackendMemory)
  849. {
  850. UA_HistoryDataBackend backend = UA_HistoryDataBackend_Memory(1, 1);
  851. UA_HistorizingNodeIdSettings setting;
  852. setting.historizingBackend = backend;
  853. setting.maxHistoryDataResponseSize = 1000;
  854. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_USER;
  855. serverMutexLock();
  856. UA_StatusCode ret = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  857. serverMutexUnlock();
  858. ck_assert_str_eq(UA_StatusCode_name(ret), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  859. // empty backend should not crash
  860. UA_UInt32 retval = testHistoricalDataBackend(100);
  861. fprintf(stderr, "%d tests expected failed.\n", retval);
  862. // fill backend
  863. ck_assert_uint_eq(fillHistoricalDataBackend(backend), true);
  864. // read all in one
  865. retval = testHistoricalDataBackend(100);
  866. fprintf(stderr, "%d tests failed.\n", retval);
  867. ck_assert_uint_eq(retval, 0);
  868. // read continuous one at one request
  869. retval = testHistoricalDataBackend(1);
  870. fprintf(stderr, "%d tests failed.\n", retval);
  871. ck_assert_uint_eq(retval, 0);
  872. // read continuous two at one request
  873. retval = testHistoricalDataBackend(2);
  874. fprintf(stderr, "%d tests failed.\n", retval);
  875. ck_assert_uint_eq(retval, 0);
  876. UA_HistoryDataBackend_Memory_deleteMembers(&setting.historizingBackend);
  877. }
  878. END_TEST
  879. START_TEST(Server_HistorizingRandomIndexBackend)
  880. {
  881. UA_HistoryDataBackend backend = UA_HistoryDataBackend_randomindextest(testData);
  882. UA_HistorizingNodeIdSettings setting;
  883. setting.historizingBackend = backend;
  884. setting.maxHistoryDataResponseSize = 1000;
  885. setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_USER;
  886. serverMutexLock();
  887. UA_StatusCode ret = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
  888. serverMutexUnlock();
  889. ck_assert_str_eq(UA_StatusCode_name(ret), UA_StatusCode_name(UA_STATUSCODE_GOOD));
  890. // read all in one
  891. UA_UInt32 retval = testHistoricalDataBackend(100);
  892. fprintf(stderr, "%d tests failed.\n", retval);
  893. ck_assert_uint_eq(retval, 0);
  894. // read continuous one at one request
  895. retval = testHistoricalDataBackend(1);
  896. fprintf(stderr, "%d tests failed.\n", retval);
  897. ck_assert_uint_eq(retval, 0);
  898. // read continuous two at one request
  899. retval = testHistoricalDataBackend(2);
  900. fprintf(stderr, "%d tests failed.\n", retval);
  901. ck_assert_uint_eq(retval, 0);
  902. UA_HistoryDataBackend_randomindextest_deleteMembers(&backend);
  903. }
  904. END_TEST
  905. #endif /*UA_ENABLE_HISTORIZING*/
  906. static Suite* testSuite_Client(void)
  907. {
  908. Suite *s = suite_create("Server Historical Data");
  909. TCase *tc_server = tcase_create("Server Historical Data Basic");
  910. tcase_add_checked_fixture(tc_server, setup, teardown);
  911. #ifdef UA_ENABLE_HISTORIZING
  912. tcase_add_test(tc_server, Server_HistorizingStrategyPoll);
  913. tcase_add_test(tc_server, Server_HistorizingStrategyUser);
  914. tcase_add_test(tc_server, Server_HistorizingStrategyValueSet);
  915. tcase_add_test(tc_server, Server_HistorizingBackendMemory);
  916. tcase_add_test(tc_server, Server_HistorizingRandomIndexBackend);
  917. tcase_add_test(tc_server, Server_HistorizingUpdateDelete);
  918. tcase_add_test(tc_server, Server_HistorizingUpdateInsert);
  919. tcase_add_test(tc_server, Server_HistorizingUpdateReplace);
  920. tcase_add_test(tc_server, Server_HistorizingUpdateUpdate);
  921. #endif /* UA_ENABLE_HISTORIZING */
  922. suite_add_tcase(s, tc_server);
  923. return s;
  924. }
  925. int main(void)
  926. {
  927. #ifdef UA_ENABLE_HISTORIZING
  928. testDataSorted = sortDateTimes(testData);
  929. #endif /* UA_ENABLE_HISTORIZING */
  930. Suite *s = testSuite_Client();
  931. SRunner *sr = srunner_create(s);
  932. srunner_set_fork_status(sr, CK_NOFORK);
  933. srunner_run_all(sr,CK_NORMAL);
  934. int number_failed = srunner_ntests_failed(sr);
  935. srunner_free(sr);
  936. #ifdef UA_ENABLE_HISTORIZING
  937. UA_free(testDataSorted);
  938. #endif /* UA_ENABLE_HISTORIZING */
  939. return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
  940. }