浏览代码

historydatabase_plugin: Add test for random index backend.

Peter Rustler 6 年之前
父节点
当前提交
ac8c5ff07e
共有 2 个文件被更改,包括 377 次插入1 次删除
  1. 32 1
      tests/server/check_server_historical_data.c
  2. 345 0
      tests/server/randomindextest_backend.h

+ 32 - 1
tests/server/check_server_historical_data.c

@@ -25,10 +25,10 @@
 #include "ua_historydatagathering_default.h"
 #ifdef UA_ENABLE_HISTORIZING
 #include "historical_read_test_data.h"
+#include "randomindextest_backend.h"
 #endif
 #include <stddef.h>
 
-
 static UA_Server *server;
 static UA_ServerConfig *config;
 #ifdef UA_ENABLE_HISTORIZING
@@ -982,6 +982,36 @@ START_TEST(Server_HistorizingBackendMemory)
 }
 END_TEST
 
+START_TEST(Server_HistorizingRandomIndexBackend)
+{
+    UA_HistoryDataBackend backend = UA_HistoryDataBackend_randomindextest(testData);
+    UA_HistorizingNodeIdSettings setting;
+    setting.historizingBackend = backend;
+    setting.maxHistoryDataResponseSize = 1000;
+    setting.historizingUpdateStrategy = UA_HISTORIZINGUPDATESTRATEGY_USER;
+    serverMutexLock();
+    UA_StatusCode ret = gathering->registerNodeId(server, gathering->context, &outNodeId, setting);
+    serverMutexUnlock();
+    ck_assert_str_eq(UA_StatusCode_name(ret), UA_StatusCode_name(UA_STATUSCODE_GOOD));
+
+    // read all in one
+    UA_UInt32 retval = testHistoricalDataBackend(100);
+    fprintf(stderr, "%d tests failed.\n", retval);
+    ck_assert_uint_eq(retval, 0);
+
+    // read continuous one at one request
+    retval = testHistoricalDataBackend(1);
+    fprintf(stderr, "%d tests failed.\n", retval);
+    ck_assert_uint_eq(retval, 0);
+
+    // read continuous two at one request
+    retval = testHistoricalDataBackend(2);
+    fprintf(stderr, "%d tests failed.\n", retval);
+    ck_assert_uint_eq(retval, 0);
+    UA_HistoryDataBackend_randomindextest_deleteMembers(&backend);
+}
+END_TEST
+
 #endif /*UA_ENABLE_HISTORIZING*/
 
 static Suite* testSuite_Client(void)
@@ -994,6 +1024,7 @@ static Suite* testSuite_Client(void)
     tcase_add_test(tc_server, Server_HistorizingStrategyUser);
     tcase_add_test(tc_server, Server_HistorizingStrategyValueSet);
     tcase_add_test(tc_server, Server_HistorizingBackendMemory);
+    tcase_add_test(tc_server, Server_HistorizingRandomIndexBackend);
     tcase_add_test(tc_server, Server_HistorizingUpdateDelete);
     tcase_add_test(tc_server, Server_HistorizingUpdateInsert);
     tcase_add_test(tc_server, Server_HistorizingUpdateReplace);

+ 345 - 0
tests/server/randomindextest_backend.h

@@ -0,0 +1,345 @@
+#ifndef BACKEND_H
+#define BACKEND_H
+
+#include "ua_plugin_history_data_backend.h"
+
+struct tupel {
+    size_t index;
+    UA_DataValue value;
+};
+
+// null terminated array
+struct context_randomindextest {
+    // null terminated array
+    struct tupel *tupels;
+    size_t tupelSize;
+};
+
+static size_t
+indexByIndex_randomindextest(struct context_randomindextest *context, size_t index)
+{
+    for (size_t i = 0; i < context->tupelSize; ++i) {
+        if (context->tupels[i].index == index)
+            return i;
+    }
+    return context->tupelSize;
+}
+
+// last value should be NULL, all values must be sorted
+static struct context_randomindextest*
+generateTestContext_randomindextest(const UA_DateTime *data) {
+    size_t count = 0;
+    while(data[count++]);
+    struct context_randomindextest* ret = (struct context_randomindextest*)UA_calloc(1, sizeof(struct context_randomindextest));
+    ret->tupels = (struct tupel*)UA_calloc(count, sizeof(struct tupel));
+    ret->tupelSize = count;
+    UA_DateTime *sortData;
+    UA_StatusCode retval = UA_Array_copy(data, count, (void**)&sortData, &UA_TYPES[UA_TYPES_DATETIME]);
+    if (retval != UA_STATUSCODE_GOOD)
+        return NULL;
+    for (size_t i = 0; i < count; ++i) {
+        size_t current = 0;
+        for (size_t j = 1; j < count-1; ++j){
+            UA_DateTime currentDate = sortData[current];
+            UA_DateTime jDate = sortData[j];
+            if (currentDate > jDate) {
+                current = j;
+            }
+        }
+        UA_DateTime nextValue = i == count-1 ? 0 : sortData[current];
+        sortData[current] = LLONG_MAX;
+        bool unique;
+        do {
+            unique = true;
+            ret->tupels[i].index = UA_UInt32_random();
+            for (size_t j = 0; j < i; ++j)
+                if (i != j && ret->tupels[i].index == ret->tupels[j].index)
+                        unique = false;
+        } while (!unique);
+        UA_DataValue_init(&ret->tupels[i].value);
+        ret->tupels[i].value.hasValue = true;
+        UA_Variant_setScalarCopy(&ret->tupels[i].value.value, &nextValue, &UA_TYPES[UA_TYPES_INT64]);
+        ret->tupels[i].value.hasStatus = true;
+        ret->tupels[i].value.status = UA_STATUSCODE_GOOD;
+        ret->tupels[i].value.hasServerTimestamp = true;
+        ret->tupels[i].value.serverTimestamp = nextValue;
+        ret->tupels[i].value.hasSourceTimestamp = true;
+        ret->tupels[i].value.sourceTimestamp = nextValue;
+    }
+    UA_free(sortData);
+    return ret;
+}
+
+static void
+deleteMembers_randomindextest(UA_HistoryDataBackend *backend)
+{
+    struct context_randomindextest* context = (struct context_randomindextest*)backend->context;
+    for (size_t i = 0; i < context->tupelSize; ++i) {
+        UA_DataValue_deleteMembers(&context->tupels[i].value);
+    }
+    UA_free(context->tupels);
+    UA_free(context);
+}
+
+static UA_StatusCode
+serverSetHistoryData_randomindextest(UA_Server *server,
+                                     void *hdbContext,
+                                     const UA_NodeId *sessionId,
+                                     void *sessionContext,
+                                     const UA_NodeId *nodeId,
+                                     UA_Boolean historizing,
+                                     const UA_DataValue *value)
+{
+    // we do not add data to the test data
+    return UA_STATUSCODE_GOOD;
+}
+
+static size_t
+getEnd_private(struct context_randomindextest* context)
+{
+    return context->tupels[context->tupelSize-1].index;
+}
+
+static size_t
+getEnd_randomindextest(UA_Server *server,
+                       void *hdbContext,
+                       const UA_NodeId *sessionId,
+                       void *sessionContext,
+                       const UA_NodeId *nodeId)
+{
+    struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
+    return getEnd_private(context);
+}
+
+static size_t
+lastIndex_randomindextest(UA_Server *server,
+                          void *hdbContext,
+                          const UA_NodeId *sessionId,
+                          void *sessionContext,
+                          const UA_NodeId *nodeId)
+{
+    struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
+    return context->tupels[context->tupelSize-2].index;
+}
+
+static size_t
+firstIndex_randomindextest(UA_Server *server,
+                           void *hdbContext,
+                           const UA_NodeId *sessionId,
+                           void *sessionContext,
+                           const UA_NodeId *nodeId)
+{
+    struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
+    return context->tupels[0].index;
+}
+
+static UA_Boolean
+search_randomindextest(struct context_randomindextest* ctx,
+                            const UA_DateTime timestamp,
+                            size_t *index) {
+    for (size_t i = 0; i < ctx->tupelSize; ++i) {
+        if (ctx->tupels[i].value.sourceTimestamp == timestamp) {
+            *index = i;
+            return true;
+        }
+        if (ctx->tupels[i].value.sourceTimestamp > timestamp) {
+            *index = i;
+            return false;
+        }
+    }
+    *index = ctx->tupelSize-1;
+    return false;
+}
+
+static size_t
+getDateTimeMatch_randomindextest(UA_Server *server,
+                                 void *hdbContext,
+                                 const UA_NodeId *sessionId,
+                                 void *sessionContext,
+                                 const UA_NodeId *nodeId,
+                                 const UA_DateTime timestamp,
+                                 const MatchStrategy strategy)
+{
+    struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
+    size_t current;
+
+    UA_Boolean retval = search_randomindextest(context, timestamp, &current);
+
+    if ((strategy == MATCH_EQUAL
+         || strategy == MATCH_EQUAL_OR_AFTER
+         || strategy == MATCH_EQUAL_OR_BEFORE)
+            && retval)
+        return context->tupels[current].index;
+    switch (strategy) {
+    case MATCH_AFTER:
+        if (retval)
+            return context->tupels[current+1].index;
+        return context->tupels[current].index;
+    case MATCH_EQUAL_OR_AFTER:
+        return context->tupels[current].index;
+    case MATCH_EQUAL_OR_BEFORE:
+        // retval == true aka "equal" is handled before
+        // Fall through if !retval
+    case MATCH_BEFORE:
+        if (current > 0)
+            return context->tupels[current-1].index;
+        else
+            return context->tupels[context->tupelSize-1].index;
+    default:
+        break;
+    }
+    return context->tupels[context->tupelSize-1].index;
+}
+
+
+#define MYABSSUB(a,b) ((a)<(b)?((b)-(a)):(a)-(b))
+static size_t
+resultSize_randomindextest(UA_Server *server,
+                           void *hdbContext,
+                           const UA_NodeId *sessionId,
+                           void *sessionContext,
+                           const UA_NodeId *nodeId,
+                           size_t startIndex,
+                           size_t endIndex)
+{
+    struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
+    if (startIndex == getEnd_private(context)
+            || endIndex == getEnd_private(context))
+        return 0;
+    size_t realEndIndex = indexByIndex_randomindextest(context, endIndex);
+    size_t realStartIndex = indexByIndex_randomindextest(context, startIndex);
+    size_t result = MYABSSUB(realEndIndex,realStartIndex);
+    return result+1;
+}
+
+static UA_StatusCode
+copyDataValues_randomindextest(UA_Server *server,
+                               void *hdbContext,
+                               const UA_NodeId *sessionId,
+                               void *sessionContext,
+                               const UA_NodeId *nodeId,
+                               size_t startIndex,
+                               size_t endIndex,
+                               UA_Boolean reverse,
+                               size_t maxValues,
+                               UA_NumericRange range,
+                               UA_Boolean releaseContinuationPoints,
+                               const UA_ByteString *continuationPoint,
+                               UA_ByteString *outContinuationPoint,
+                               size_t *providedValues,
+                               UA_DataValue *values)
+{
+    size_t skip = 0;
+    if (continuationPoint->length > 0) {
+        if (continuationPoint->length == sizeof(size_t)) {
+            skip = *((size_t*)(continuationPoint->data));
+        } else {
+            return UA_STATUSCODE_BADCONTINUATIONPOINTINVALID;
+        }
+    }
+    struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
+    size_t index = indexByIndex_randomindextest(context,startIndex);
+    size_t counter = 0;
+    size_t skipedValues = 0;
+    if (reverse) {
+        while (index >= indexByIndex_randomindextest(context,endIndex)
+               && index < context->tupelSize-1
+               && counter < maxValues) {
+            if (skipedValues++ >= skip) {
+                UA_DataValue_copy(&context->tupels[index].value, &values[counter]);
+                ++counter;
+            }
+            --index;
+        }
+    } else {
+        while (index <= indexByIndex_randomindextest(context,endIndex) && counter < maxValues) {
+            if (skipedValues++ >= skip) {
+                UA_DataValue_copy(&context->tupels[index].value, &values[counter]);
+                ++counter;
+            }
+            ++index;
+        }
+    }
+
+    if (providedValues)
+        *providedValues = counter;
+
+    if ((!reverse && (indexByIndex_randomindextest(context,endIndex)-indexByIndex_randomindextest(context,startIndex)-skip+1) > counter)
+            || (reverse && (indexByIndex_randomindextest(context,startIndex)-indexByIndex_randomindextest(context,endIndex)-skip+1) > counter)) {
+        outContinuationPoint->length = sizeof(size_t);
+        size_t t = sizeof(size_t);
+        outContinuationPoint->data = (UA_Byte*)UA_malloc(t);
+        *((size_t*)(outContinuationPoint->data)) = skip + counter;
+    }
+
+    return UA_STATUSCODE_GOOD;
+}
+
+static const UA_DataValue*
+getDataValue_randomindextest(UA_Server *server,
+                             void *hdbContext,
+                             const UA_NodeId *sessionId,
+                             void *sessionContext,
+                             const UA_NodeId *nodeId,
+                             size_t index)
+{
+    struct context_randomindextest* context = (struct context_randomindextest*)hdbContext;
+    size_t realIndex = indexByIndex_randomindextest(context, index);
+    return &context->tupels[realIndex].value;
+}
+
+static UA_Boolean
+boundSupported_randomindextest(UA_Server *server,
+                               void *hdbContext,
+                               const UA_NodeId *sessionId,
+                               void *sessionContext,
+                               const UA_NodeId *nodeId)
+{
+    return true;
+}
+
+static UA_Boolean
+timestampsToReturnSupported_randomindextest(UA_Server *server,
+                                            void *hdbContext,
+                                            const UA_NodeId *sessionId,
+                                            void *sessionContext,
+                                            const UA_NodeId *nodeId,
+                                            const UA_TimestampsToReturn timestampsToReturn)
+{
+    return true;
+}
+
+UA_HistoryDataBackend
+UA_HistoryDataBackend_randomindextest(UA_DateTime *data);
+
+UA_HistoryDataBackend
+UA_HistoryDataBackend_randomindextest(UA_DateTime *data)
+{
+    UA_HistoryDataBackend result;
+    memset(&result, 0, sizeof(UA_HistoryDataBackend));
+    result.serverSetHistoryData = &serverSetHistoryData_randomindextest;
+    result.resultSize = &resultSize_randomindextest;
+    result.getEnd = &getEnd_randomindextest;
+    result.lastIndex = &lastIndex_randomindextest;
+    result.firstIndex = &firstIndex_randomindextest;
+    result.getDateTimeMatch = &getDateTimeMatch_randomindextest;
+    result.copyDataValues = &copyDataValues_randomindextest;
+    result.getDataValue = &getDataValue_randomindextest;
+    result.boundSupported = &boundSupported_randomindextest;
+    result.timestampsToReturnSupported = &timestampsToReturnSupported_randomindextest;
+    result.deleteMembers = &deleteMembers_randomindextest;
+    result.getHistoryData = NULL;
+    result.context = generateTestContext_randomindextest(data);
+    return result;
+}
+
+void
+UA_HistoryDataBackend_randomindextest_deleteMembers(UA_HistoryDataBackend *backend);
+
+void
+UA_HistoryDataBackend_randomindextest_deleteMembers(UA_HistoryDataBackend *backend)
+{
+    deleteMembers_randomindextest(backend);
+}
+
+#endif // BACKEND_H