Browse Source

Merge pull request #1024 from open62541/feature/unit_tests

Client_highlevel unittests
Stefan Profanter 7 years ago
parent
commit
a865c841bf

+ 2 - 2
include/ua_client_highlevel.h

@@ -152,7 +152,7 @@ UA_Client_readValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,
 
 UA_StatusCode UA_EXPORT
 UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
-                                       UA_Int32 **outArrayDimensions,
+                                       UA_UInt32 **outArrayDimensions,
                                        size_t *outArrayDimensionsSize);
 
 static UA_INLINE UA_StatusCode
@@ -333,7 +333,7 @@ UA_Client_writeValueRankAttribute(UA_Client *client, const UA_NodeId nodeId,
 
 UA_StatusCode UA_EXPORT
 UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
-                                        const UA_Int32 *newArrayDimensions,
+                                        const UA_UInt32 *newArrayDimensions,
                                         size_t newArrayDimensionsSize);
 
 static UA_INLINE UA_StatusCode

+ 32 - 9
src/client/ua_client_highlevel.c

@@ -294,14 +294,22 @@ __UA_Client_writeAttribute(UA_Client *client, const UA_NodeId *nodeId,
     wReq.nodesToWriteSize = 1;
 
     UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);
+
     UA_StatusCode retval = wResp.responseHeader.serviceResult;
+    if(retval == UA_STATUSCODE_GOOD) {
+        if(wResp.resultsSize == 1)
+            retval = wResp.results[0];
+        else
+            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
+
     UA_WriteResponse_deleteMembers(&wResp);
     return retval;
 }
 
 UA_StatusCode
 UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
-                                        const UA_Int32 *newArrayDimensions,
+                                        const UA_UInt32 *newArrayDimensions,
                                         size_t newArrayDimensionsSize) {
     if(!newArrayDimensions)
       return UA_STATUSCODE_BADTYPEMISMATCH;
@@ -311,7 +319,7 @@ UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeI
     wValue.nodeId = nodeId;
     wValue.attributeId = UA_ATTRIBUTEID_ARRAYDIMENSIONS;
     UA_Variant_setArray(&wValue.value.value, (void*)(uintptr_t)newArrayDimensions,
-                        newArrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+                        newArrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
     wValue.value.hasValue = true;
     UA_WriteRequest wReq;
     UA_WriteRequest_init(&wReq);
@@ -319,7 +327,14 @@ UA_Client_writeArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeI
     wReq.nodesToWriteSize = 1;
 
     UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);
+
     UA_StatusCode retval = wResp.responseHeader.serviceResult;
+    if(retval == UA_STATUSCODE_GOOD) {
+        if(wResp.resultsSize == 1)
+            retval = wResp.results[0];
+        else
+            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
     UA_WriteResponse_deleteMembers(&wResp);
     return retval;
 }
@@ -342,8 +357,12 @@ __UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId,
     request.nodesToReadSize = 1;
     UA_ReadResponse response = UA_Client_Service_read(client, request);
     UA_StatusCode retval = response.responseHeader.serviceResult;
-    if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
-        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    if(retval == UA_STATUSCODE_GOOD) {
+        if(response.resultsSize == 1)
+            retval = response.results[0].status;
+        else
+            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
     if(retval != UA_STATUSCODE_GOOD) {
         UA_ReadResponse_deleteMembers(&response);
         return retval;
@@ -381,7 +400,7 @@ __UA_Client_readAttribute(UA_Client *client, const UA_NodeId *nodeId,
 
 UA_StatusCode
 UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId,
-                                       UA_Int32 **outArrayDimensions,
+                                       UA_UInt32 **outArrayDimensions,
                                        size_t *outArrayDimensionsSize) {
     UA_ReadValueId item;
     UA_ReadValueId_init(&item);
@@ -393,8 +412,12 @@ UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId
     request.nodesToReadSize = 1;
     UA_ReadResponse response = UA_Client_Service_read(client, request);
     UA_StatusCode retval = response.responseHeader.serviceResult;
-    if(retval == UA_STATUSCODE_GOOD && response.resultsSize != 1)
-        retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    if(retval == UA_STATUSCODE_GOOD) {
+        if(response.resultsSize == 1)
+            retval = response.results[0].status;
+        else
+            retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
+    }
     if(retval != UA_STATUSCODE_GOOD)
         goto cleanup;
 
@@ -407,14 +430,14 @@ UA_Client_readArrayDimensionsAttribute(UA_Client *client, const UA_NodeId nodeId
         goto cleanup;
 
     if(UA_Variant_isScalar(&res->value) ||
-       res->value.type != &UA_TYPES[UA_TYPES_INT32]) {
+       res->value.type != &UA_TYPES[UA_TYPES_UINT32]) {
         retval = UA_STATUSCODE_BADUNEXPECTEDERROR;
         goto cleanup;
     }
 
+    /* Move data out of the results structure instead of copying */
     *outArrayDimensions = res->value.data;
     *outArrayDimensionsSize = res->value.arrayLength;
-    UA_free(res->value.data);
     res->value.data = NULL;
     res->value.arrayLength = 0;
 

+ 1 - 1
src/server/ua_services_attribute.c

@@ -206,7 +206,7 @@ typeCheckValue(UA_Server *server, const UA_NodeId *targetDataTypeId,
 static UA_StatusCode
 readArrayDimensionsAttribute(const UA_VariableNode *vn, UA_DataValue *v) {
     UA_Variant_setArray(&v->value, vn->arrayDimensions,
-                        vn->arrayDimensionsSize, &UA_TYPES[UA_TYPES_INT32]);
+                        vn->arrayDimensionsSize, &UA_TYPES[UA_TYPES_UINT32]);
     v->value.storageType = UA_VARIANT_DATA_NODELETE;
     v->hasValue = true;
     return UA_STATUSCODE_GOOD;

+ 151 - 3
tests/check_client_highlevel.c

@@ -196,9 +196,7 @@ START_TEST(Node_Add)
             attr.description = UA_LOCALIZEDTEXT("en_US", "Top Coordinate");
             attr.displayName = UA_LOCALIZEDTEXT("en_US", "Top");
 
-            UA_Int32 values[2];
-            values[1] = 10;
-            values[2] = 20;
+            UA_Int32 values[2] = {10, 20};
 
             UA_Variant_setArray(&attr.value, values, 2, &UA_TYPES[UA_TYPES_INT32]);
             attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
@@ -282,6 +280,155 @@ START_TEST(Node_Add)
     }
 END_TEST
 
+unsigned int iteratedNodeCount = 0;
+UA_NodeId iteratedNodes[2];
+
+static UA_StatusCode
+nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId referenceTypeId, void *handle) {
+    if (isInverse ||
+            (referenceTypeId.identifierType == UA_NODEIDTYPE_NUMERIC &&
+                    referenceTypeId.identifier.numeric == UA_NS0ID_HASTYPEDEFINITION)
+            )
+        return UA_STATUSCODE_GOOD;
+
+    if (iteratedNodeCount >= 2)
+        return UA_STATUSCODE_BADINDEXRANGEINVALID;
+
+    UA_NodeId_copy(&childId, &iteratedNodes[iteratedNodeCount]);
+
+    iteratedNodeCount++;
+
+    return UA_STATUSCODE_GOOD;
+}
+
+START_TEST(Node_ReadWrite)
+    {
+        UA_StatusCode retval;
+        // Create a folder with two variables for testing
+
+        UA_NodeId unitTestNodeId;
+
+        UA_NodeId nodeArrayId;
+        UA_NodeId nodeIntId;
+
+        // create Coordinates Object within ObjectsFolder
+        {
+            UA_ObjectAttributes attr;
+            UA_ObjectAttributes_init(&attr);
+            attr.description = UA_LOCALIZEDTEXT("en_US", "UnitTest");
+            attr.displayName = UA_LOCALIZEDTEXT("en_US", "UnitTest");
+
+            retval = UA_Client_addObjectNode(client, UA_NODEID_NULL,
+                                             UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                             UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                             UA_QUALIFIEDNAME(1, "UnitTest"),
+                                             UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), attr, &unitTestNodeId);
+            ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+        }
+
+        // create Variable 'Top' within UnitTest Object
+        {
+            UA_VariableAttributes attr;
+            UA_VariableAttributes_init(&attr);
+            attr.description = UA_LOCALIZEDTEXT("en_US", "Array");
+            attr.displayName = UA_LOCALIZEDTEXT("en_US", "Array");
+
+            /*UA_Int32 values[2];
+            values[1] = 10;
+            values[2] = 20;
+
+            UA_Variant_setArray(&attr.value, values, 2, &UA_TYPES[UA_TYPES_INT32]);*/
+            attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+            attr.valueRank = 1; /* array with one dimension */
+            UA_UInt32 arrayDims[1] = {2};
+            attr.arrayDimensions = arrayDims;
+            attr.arrayDimensionsSize = 1;
+
+            retval = UA_Client_addVariableNode(client, UA_NODEID_NULL,
+                                               unitTestNodeId,
+                                               UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                               UA_QUALIFIEDNAME(1, "Array"),
+                                               UA_NODEID_NULL, attr, &nodeArrayId);
+            ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+        }
+
+        // create Variable 'Bottom' within UnitTest Object
+        {
+            UA_VariableAttributes attr;
+            UA_VariableAttributes_init(&attr);
+            attr.description = UA_LOCALIZEDTEXT("en_US", "Int");
+            attr.displayName = UA_LOCALIZEDTEXT("en_US", "Int");
+
+            UA_Int32 int_value = 5678;
+
+            UA_Variant_setScalar(&attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]);
+            attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
+
+            retval = UA_Client_addVariableNode(client, UA_NODEID_NULL,
+                                               unitTestNodeId,
+                                               UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                               UA_QUALIFIEDNAME(1, "Int"),
+                                               UA_NODEID_NULL, attr, &nodeIntId);
+
+            ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+        }
+
+        // iterate over children
+        {
+            retval = UA_Client_forEachChildNodeCall(client, unitTestNodeId,
+                                                    nodeIter, NULL);
+            ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+            ck_assert(UA_NodeId_equal(&nodeArrayId, &iteratedNodes[0]));
+            ck_assert(UA_NodeId_equal(&nodeIntId, &iteratedNodes[1]));
+        }
+
+
+        /* Read attribute */
+        UA_Int32 value = 0;
+        UA_Variant *val = UA_Variant_new();
+        retval = UA_Client_readValueAttribute(client, nodeIntId, val);
+        ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+        ck_assert(UA_Variant_isScalar(val) && val->type == &UA_TYPES[UA_TYPES_INT32]);
+        value = *(UA_Int32*)val->data;
+        ck_assert_int_eq(value, 5678);
+        UA_Variant_delete(val);
+
+        /* Write attribute */
+        value++;
+        val = UA_Variant_new();
+        UA_Variant_setScalarCopy(val, &value, &UA_TYPES[UA_TYPES_INT32]);
+        retval = UA_Client_writeValueAttribute(client, nodeIntId, val);
+        ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+        UA_Variant_delete(val);
+
+        /* Read again to check value */
+        val = UA_Variant_new();
+        retval = UA_Client_readValueAttribute(client, nodeIntId, val);
+        ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+        ck_assert(UA_Variant_isScalar(val) && val->type == &UA_TYPES[UA_TYPES_INT32]);
+        value = *(UA_Int32*)val->data;
+        ck_assert_int_eq(value, 5679);
+        UA_Variant_delete(val);
+
+        UA_UInt32 arrayDimsNew[] = {3};
+        retval = UA_Client_writeArrayDimensionsAttribute(client, nodeArrayId, arrayDimsNew , 1);
+        ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+
+
+        UA_UInt32 *arrayDimsRead;
+        size_t arrayDimsReadSize;
+        retval = UA_Client_readArrayDimensionsAttribute(client, nodeArrayId, &arrayDimsRead , &arrayDimsReadSize);
+        ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
+        ck_assert_int_eq(arrayDimsReadSize, 1);
+        ck_assert_int_eq(arrayDimsRead[0], 3);
+        UA_Array_delete(arrayDimsRead, arrayDimsReadSize, &UA_TYPES[UA_TYPES_UINT32]);
+
+    }
+END_TEST
+
 START_TEST(Node_Browse)
     {
 
@@ -407,6 +554,7 @@ static Suite *testSuite_Client(void) {
     tcase_add_checked_fixture(tc_nodes, setup, teardown);
     tcase_add_test(tc_nodes, Node_Add);
     tcase_add_test(tc_nodes, Node_Browse);
+    tcase_add_test(tc_nodes, Node_ReadWrite);
     tcase_add_test(tc_nodes, Node_Register);
     suite_add_tcase(s, tc_nodes);
     return s;

+ 1 - 1
tests/check_services_attributes.c

@@ -447,7 +447,7 @@ START_TEST(ReadSingleAttributeArrayDimensionsWithoutTimestamp) {
     UA_DataValue resp = UA_Server_read(server, &rvi, UA_TIMESTAMPSTORETURN_NEITHER);
 
     ck_assert_int_eq(0, resp.value.arrayLength);
-    ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_INT32], resp.value.type);
+    ck_assert_ptr_eq(&UA_TYPES[UA_TYPES_UINT32], resp.value.type);
     ck_assert_ptr_eq((UA_Int32*)resp.value.data,0);
     UA_DataValue_deleteMembers(&resp);
     UA_Server_delete(server);