randomindextest_backend.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  1. #ifndef BACKEND_H
  2. #define BACKEND_H
  3. #include "ua_plugin_history_data_backend.h"
  4. struct tupel {
  5. size_t index;
  6. UA_DataValue value;
  7. };
  8. // null terminated array
  9. struct context_randomindextest {
  10. // null terminated array
  11. struct tupel *tupels;
  12. size_t tupelSize;
  13. };
  14. static size_t
  15. indexByIndex_randomindextest(struct context_randomindextest *context, size_t index)
  16. {
  17. for (size_t i = 0; i < context->tupelSize; ++i) {
  18. if (context->tupels[i].index == index)
  19. return i;
  20. }
  21. return context->tupelSize;
  22. }
  23. // last value should be NULL, all values must be sorted
  24. static struct context_randomindextest*
  25. generateTestContext_randomindextest(const UA_DateTime *data) {
  26. size_t count = 0;
  27. while(data[count++]);
  28. struct context_randomindextest* ret = (struct context_randomindextest*)UA_calloc(1, sizeof(struct context_randomindextest));
  29. ret->tupels = (struct tupel*)UA_calloc(count, sizeof(struct tupel));
  30. ret->tupelSize = count;
  31. UA_DateTime *sortData;
  32. UA_StatusCode retval = UA_Array_copy(data, count, (void**)&sortData, &UA_TYPES[UA_TYPES_DATETIME]);
  33. if (retval != UA_STATUSCODE_GOOD)
  34. return NULL;
  35. for (size_t i = 0; i < count; ++i) {
  36. size_t current = 0;
  37. for (size_t j = 1; j < count-1; ++j){
  38. UA_DateTime currentDate = sortData[current];
  39. UA_DateTime jDate = sortData[j];
  40. if (currentDate > jDate) {
  41. current = j;
  42. }
  43. }
  44. UA_DateTime nextValue = i == count-1 ? 0 : sortData[current];
  45. sortData[current] = LLONG_MAX;
  46. bool unique;
  47. do {
  48. unique = true;
  49. ret->tupels[i].index = UA_UInt32_random();
  50. for (size_t j = 0; j < i; ++j)
  51. if (i != j && ret->tupels[i].index == ret->tupels[j].index)
  52. unique = false;
  53. } while (!unique);
  54. UA_DataValue_init(&ret->tupels[i].value);
  55. ret->tupels[i].value.hasValue = true;
  56. UA_Variant_setScalarCopy(&ret->tupels[i].value.value, &nextValue, &UA_TYPES[UA_TYPES_INT64]);
  57. ret->tupels[i].value.hasStatus = true;
  58. ret->tupels[i].value.status = UA_STATUSCODE_GOOD;
  59. ret->tupels[i].value.hasServerTimestamp = true;
  60. ret->tupels[i].value.serverTimestamp = nextValue;
  61. ret->tupels[i].value.hasSourceTimestamp = true;
  62. ret->tupels[i].value.sourceTimestamp = nextValue;
  63. }
  64. UA_free(sortData);
  65. return ret;
  66. }
  67. static void
  68. deleteMembers_randomindextest(UA_HistoryDataBackend *backend)
  69. {
  70. struct context_randomindextest* context = (struct context_randomindextest*)backend->context;
  71. for (size_t i = 0; i < context->tupelSize; ++i) {
  72. UA_DataValue_deleteMembers(&context->tupels[i].value);
  73. }
  74. UA_free(context->tupels);
  75. UA_free(context);
  76. }
  77. static UA_StatusCode
  78. serverSetHistoryData_randomindextest(UA_Server *server,
  79. void *hdbContext,
  80. const UA_NodeId *sessionId,
  81. void *sessionContext,
  82. const UA_NodeId *nodeId,
  83. UA_Boolean historizing,
  84. const UA_DataValue *value)
  85. {
  86. // we do not add data to the test data
  87. return UA_STATUSCODE_GOOD;
  88. }
  89. static size_t
  90. getEnd_private(struct context_randomindextest* context)
  91. {
  92. return context->tupels[context->tupelSize-1].index;
  93. }
  94. static size_t
  95. getEnd_randomindextest(UA_Server *server,
  96. void *hdbContext,
  97. const UA_NodeId *sessionId,
  98. void *sessionContext,
  99. const UA_NodeId *nodeId)
  100. {
  101. struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
  102. return getEnd_private(context);
  103. }
  104. static size_t
  105. lastIndex_randomindextest(UA_Server *server,
  106. void *hdbContext,
  107. const UA_NodeId *sessionId,
  108. void *sessionContext,
  109. const UA_NodeId *nodeId)
  110. {
  111. struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
  112. return context->tupels[context->tupelSize-2].index;
  113. }
  114. static size_t
  115. firstIndex_randomindextest(UA_Server *server,
  116. void *hdbContext,
  117. const UA_NodeId *sessionId,
  118. void *sessionContext,
  119. const UA_NodeId *nodeId)
  120. {
  121. struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
  122. return context->tupels[0].index;
  123. }
  124. static UA_Boolean
  125. search_randomindextest(struct context_randomindextest* ctx,
  126. const UA_DateTime timestamp,
  127. size_t *index) {
  128. for (size_t i = 0; i < ctx->tupelSize; ++i) {
  129. if (ctx->tupels[i].value.sourceTimestamp == timestamp) {
  130. *index = i;
  131. return true;
  132. }
  133. if (ctx->tupels[i].value.sourceTimestamp > timestamp) {
  134. *index = i;
  135. return false;
  136. }
  137. }
  138. *index = ctx->tupelSize-1;
  139. return false;
  140. }
  141. static size_t
  142. getDateTimeMatch_randomindextest(UA_Server *server,
  143. void *hdbContext,
  144. const UA_NodeId *sessionId,
  145. void *sessionContext,
  146. const UA_NodeId *nodeId,
  147. const UA_DateTime timestamp,
  148. const MatchStrategy strategy)
  149. {
  150. struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
  151. size_t current;
  152. UA_Boolean retval = search_randomindextest(context, timestamp, &current);
  153. if ((strategy == MATCH_EQUAL
  154. || strategy == MATCH_EQUAL_OR_AFTER
  155. || strategy == MATCH_EQUAL_OR_BEFORE)
  156. && retval)
  157. return context->tupels[current].index;
  158. switch (strategy) {
  159. case MATCH_AFTER:
  160. if (retval)
  161. return context->tupels[current+1].index;
  162. return context->tupels[current].index;
  163. case MATCH_EQUAL_OR_AFTER:
  164. return context->tupels[current].index;
  165. case MATCH_EQUAL_OR_BEFORE:
  166. // retval == true aka "equal" is handled before
  167. // Fall through if !retval
  168. case MATCH_BEFORE:
  169. if (current > 0)
  170. return context->tupels[current-1].index;
  171. else
  172. return context->tupels[context->tupelSize-1].index;
  173. default:
  174. break;
  175. }
  176. return context->tupels[context->tupelSize-1].index;
  177. }
  178. #define MYABSSUB(a,b) ((a)<(b)?((b)-(a)):(a)-(b))
  179. static size_t
  180. resultSize_randomindextest(UA_Server *server,
  181. void *hdbContext,
  182. const UA_NodeId *sessionId,
  183. void *sessionContext,
  184. const UA_NodeId *nodeId,
  185. size_t startIndex,
  186. size_t endIndex)
  187. {
  188. struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
  189. if (startIndex == getEnd_private(context)
  190. || endIndex == getEnd_private(context))
  191. return 0;
  192. size_t realEndIndex = indexByIndex_randomindextest(context, endIndex);
  193. size_t realStartIndex = indexByIndex_randomindextest(context, startIndex);
  194. size_t result = MYABSSUB(realEndIndex,realStartIndex);
  195. return result+1;
  196. }
  197. static UA_StatusCode
  198. copyDataValues_randomindextest(UA_Server *server,
  199. void *hdbContext,
  200. const UA_NodeId *sessionId,
  201. void *sessionContext,
  202. const UA_NodeId *nodeId,
  203. size_t startIndex,
  204. size_t endIndex,
  205. UA_Boolean reverse,
  206. size_t maxValues,
  207. UA_NumericRange range,
  208. UA_Boolean releaseContinuationPoints,
  209. const UA_ByteString *continuationPoint,
  210. UA_ByteString *outContinuationPoint,
  211. size_t *providedValues,
  212. UA_DataValue *values)
  213. {
  214. size_t skip = 0;
  215. if (continuationPoint->length > 0) {
  216. if (continuationPoint->length == sizeof(size_t)) {
  217. skip = *((size_t*)(continuationPoint->data));
  218. } else {
  219. return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
  220. }
  221. }
  222. struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
  223. size_t index = indexByIndex_randomindextest(context,startIndex);
  224. size_t counter = 0;
  225. size_t skipedValues = 0;
  226. if (reverse) {
  227. while (index >= indexByIndex_randomindextest(context,endIndex)
  228. && index < context->tupelSize-1
  229. && counter < maxValues) {
  230. if (skipedValues++ >= skip) {
  231. UA_DataValue_copy(&context->tupels[index].value, &values[counter]);
  232. ++counter;
  233. }
  234. --index;
  235. }
  236. } else {
  237. while (index <= indexByIndex_randomindextest(context,endIndex) && counter < maxValues) {
  238. if (skipedValues++ >= skip) {
  239. UA_DataValue_copy(&context->tupels[index].value, &values[counter]);
  240. ++counter;
  241. }
  242. ++index;
  243. }
  244. }
  245. if (providedValues)
  246. *providedValues = counter;
  247. if ((!reverse && (indexByIndex_randomindextest(context,endIndex)-indexByIndex_randomindextest(context,startIndex)-skip+1) > counter)
  248. || (reverse && (indexByIndex_randomindextest(context,startIndex)-indexByIndex_randomindextest(context,endIndex)-skip+1) > counter)) {
  249. outContinuationPoint->length = sizeof(size_t);
  250. size_t t = sizeof(size_t);
  251. outContinuationPoint->data = (UA_Byte*)UA_malloc(t);
  252. *((size_t*)(outContinuationPoint->data)) = skip + counter;
  253. }
  254. return UA_STATUSCODE_GOOD;
  255. }
  256. static const UA_DataValue*
  257. getDataValue_randomindextest(UA_Server *server,
  258. void *hdbContext,
  259. const UA_NodeId *sessionId,
  260. void *sessionContext,
  261. const UA_NodeId *nodeId,
  262. size_t index)
  263. {
  264. struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
  265. size_t realIndex = indexByIndex_randomindextest(context, index);
  266. return &context->tupels[realIndex].value;
  267. }
  268. static UA_Boolean
  269. boundSupported_randomindextest(UA_Server *server,
  270. void *hdbContext,
  271. const UA_NodeId *sessionId,
  272. void *sessionContext,
  273. const UA_NodeId *nodeId)
  274. {
  275. return true;
  276. }
  277. static UA_Boolean
  278. timestampsToReturnSupported_randomindextest(UA_Server *server,
  279. void *hdbContext,
  280. const UA_NodeId *sessionId,
  281. void *sessionContext,
  282. const UA_NodeId *nodeId,
  283. const UA_TimestampsToReturn timestampsToReturn)
  284. {
  285. return true;
  286. }
  287. UA_HistoryDataBackend
  288. UA_HistoryDataBackend_randomindextest(UA_DateTime *data);
  289. UA_HistoryDataBackend
  290. UA_HistoryDataBackend_randomindextest(UA_DateTime *data)
  291. {
  292. UA_HistoryDataBackend result;
  293. memset(&result, 0, sizeof(UA_HistoryDataBackend));
  294. result.serverSetHistoryData = &serverSetHistoryData_randomindextest;
  295. result.resultSize = &resultSize_randomindextest;
  296. result.getEnd = &getEnd_randomindextest;
  297. result.lastIndex = &lastIndex_randomindextest;
  298. result.firstIndex = &firstIndex_randomindextest;
  299. result.getDateTimeMatch = &getDateTimeMatch_randomindextest;
  300. result.copyDataValues = &copyDataValues_randomindextest;
  301. result.getDataValue = &getDataValue_randomindextest;
  302. result.boundSupported = &boundSupported_randomindextest;
  303. result.timestampsToReturnSupported = &timestampsToReturnSupported_randomindextest;
  304. result.deleteMembers = &deleteMembers_randomindextest;
  305. result.getHistoryData = NULL;
  306. result.context = generateTestContext_randomindextest(data);
  307. return result;
  308. }
  309. void
  310. UA_HistoryDataBackend_randomindextest_deleteMembers(UA_HistoryDataBackend *backend);
  311. void
  312. UA_HistoryDataBackend_randomindextest_deleteMembers(UA_HistoryDataBackend *backend)
  313. {
  314. deleteMembers_randomindextest(backend);
  315. }
  316. #endif // BACKEND_H