浏览代码

fix #1069 and add a test case for object type instantiation

Julius Pfrommer 7 年之前
父节点
当前提交
55f2cfab80
共有 4 个文件被更改,包括 120 次插入20 次删除
  1. 14 7
      src/server/ua_nodes.c
  2. 1 0
      src/server/ua_server_internal.h
  3. 1 3
      src/server/ua_services_nodemanagement.c
  4. 104 10
      tests/check_services_nodemanagement.c

+ 14 - 7
src/server/ua_nodes.c

@@ -5,12 +5,7 @@
 #include "ua_server_internal.h"
 #include "ua_nodes.h"
 
-void UA_Node_deleteMembersAnyNodeClass(UA_Node *node) {
-    /* Delete standard content */
-    UA_NodeId_deleteMembers(&node->nodeId);
-    UA_QualifiedName_deleteMembers(&node->browseName);
-    UA_LocalizedText_deleteMembers(&node->displayName);
-    UA_LocalizedText_deleteMembers(&node->description);
+void UA_Node_deleteReferences(UA_Node *node) {
     for(size_t i = 0; i < node->referencesSize; ++i) {
         UA_NodeReferenceKind *refs = &node->references[i];
         for(size_t j = 0; j < refs->targetIdsSize; ++j)
@@ -18,9 +13,21 @@ void UA_Node_deleteMembersAnyNodeClass(UA_Node *node) {
         UA_free(refs->targetIds);
         UA_NodeId_deleteMembers(&refs->referenceTypeId);
     }
-    UA_free(node->references);
+    if(node->references)
+        UA_free(node->references);
     node->references = NULL;
     node->referencesSize = 0;
+}
+
+void UA_Node_deleteMembersAnyNodeClass(UA_Node *node) {
+    /* Delete standard content */
+    UA_NodeId_deleteMembers(&node->nodeId);
+    UA_QualifiedName_deleteMembers(&node->browseName);
+    UA_LocalizedText_deleteMembers(&node->displayName);
+    UA_LocalizedText_deleteMembers(&node->description);
+
+    /* Delete references */
+    UA_Node_deleteReferences(node);
 
     /* Delete unique content of the nodeclass */
     switch(node->nodeClass) {

+ 1 - 0
src/server/ua_server_internal.h

@@ -203,6 +203,7 @@ struct UA_Server {
 /*****************/
 
 void UA_Node_deleteMembersAnyNodeClass(UA_Node *node);
+void UA_Node_deleteReferences(UA_Node *node);
 UA_StatusCode UA_Node_copyAnyNodeClass(const UA_Node *src, UA_Node *dst);
 
 /* Calls callback on the node. In the multithreaded case, the node is copied before and replaced in

+ 1 - 3
src/server/ua_services_nodemanagement.c

@@ -455,9 +455,7 @@ copyChildNode(UA_Server *server, UA_Session *session,
         /* TODO: Be more clever in removing references that are re-added during
          * addnode_finish. That way, we can call addnode_finish also on children that were
          * manually added by the user during addnode_begin and addnode_finish. */
-        UA_Array_delete(node->references, node->referencesSize, &UA_TYPES[UA_TYPES_REFERENCENODE]);
-        node->references = NULL;
-        node->referencesSize = 0;
+        UA_Node_deleteReferences(node);
                 
         /* Add the node to the nodestore */
         retval = UA_NodeStore_insert(server->nodestore, node);

+ 104 - 10
tests/check_services_nodemanagement.c

@@ -244,7 +244,106 @@ START_TEST(DeleteObjectAndReferences) {
     UA_Server_delete(server);
 } END_TEST
 
-static Suite * testSuite_services_nodemanagement(void) {
+
+/* Example taken from tutorial_server_object.c */
+START_TEST(InstantiateObjectType) {
+    UA_Server *server = UA_Server_new(UA_ServerConfig_standard);
+
+    /* Define the object type */
+    UA_NodeId pumpTypeId = {1, UA_NODEIDTYPE_NUMERIC, {1001}};
+
+    UA_StatusCode retval;
+
+    /* Define the object type for "Device" */
+    UA_NodeId deviceTypeId; /* get the nodeid assigned by the server */
+    UA_ObjectTypeAttributes dtAttr;
+    UA_ObjectTypeAttributes_init(&dtAttr);
+    dtAttr.displayName = UA_LOCALIZEDTEXT("en_US", "DeviceType");
+    retval = UA_Server_addObjectTypeNode(server, UA_NODEID_NULL,
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
+                                         UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                         UA_QUALIFIEDNAME(1, "DeviceType"), dtAttr,
+                                         NULL, &deviceTypeId);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_VariableAttributes mnAttr;
+    UA_VariableAttributes_init(&mnAttr);
+    mnAttr.displayName = UA_LOCALIZEDTEXT("en_US", "ManufacturerName");
+    UA_NodeId manufacturerNameId;
+    retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                       UA_QUALIFIEDNAME(1, "ManufacturerName"),
+                                       UA_NODEID_NULL, mnAttr, NULL, &manufacturerNameId);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+    /* Make the manufacturer name mandatory */
+    retval = UA_Server_addReference(server, manufacturerNameId,
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
+                                    UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_VariableAttributes modelAttr;
+    UA_VariableAttributes_init(&modelAttr);
+    modelAttr.displayName = UA_LOCALIZEDTEXT("en_US", "ModelName");
+    retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, deviceTypeId,
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                       UA_QUALIFIEDNAME(1, "ModelName"),
+                                       UA_NODEID_NULL, modelAttr, NULL, NULL);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    /* Define the object type for "Pump" */
+    UA_ObjectTypeAttributes ptAttr;
+    UA_ObjectTypeAttributes_init(&ptAttr);
+    ptAttr.displayName = UA_LOCALIZEDTEXT("en_US", "PumpType");
+    retval = UA_Server_addObjectTypeNode(server, pumpTypeId,
+                                         deviceTypeId, UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
+                                         UA_QUALIFIEDNAME(1, "PumpType"), ptAttr,
+                                         NULL, NULL);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_VariableAttributes statusAttr;
+    UA_VariableAttributes_init(&statusAttr);
+    statusAttr.displayName = UA_LOCALIZEDTEXT("en_US", "Status");
+    statusAttr.valueRank = -1;
+    UA_NodeId statusId;
+    retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                       UA_QUALIFIEDNAME(1, "Status"),
+                                       UA_NODEID_NULL, statusAttr, NULL, &statusId);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    /* Make the status variable mandatory */
+    retval = UA_Server_addReference(server, statusId,
+                                    UA_NODEID_NUMERIC(0, UA_NS0ID_HASMODELLINGRULE),
+                                    UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_MODELLINGRULE_MANDATORY), true);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_VariableAttributes rpmAttr;
+    UA_VariableAttributes_init(&rpmAttr);
+    rpmAttr.displayName = UA_LOCALIZEDTEXT("en_US", "MotorRPM");
+    rpmAttr.valueRank = -1;
+    retval = UA_Server_addVariableNode(server, UA_NODEID_NULL, pumpTypeId,
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
+                                       UA_QUALIFIEDNAME(1, "MotorRPMs"),
+                                       UA_NODEID_NULL, rpmAttr, NULL, NULL);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    /* Instantiate the variable */
+    UA_ObjectAttributes oAttr;
+    UA_ObjectAttributes_init(&oAttr);
+    oAttr.displayName = UA_LOCALIZEDTEXT("en_US", "MyPump");
+    retval = UA_Server_addObjectNode(server, UA_NODEID_NULL,
+                                     UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
+                                     UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
+                                     UA_QUALIFIEDNAME(1, "MyPump"),
+                                     pumpTypeId, /* this refers to the object type
+                                                    identifier */
+                                     oAttr, NULL, NULL);
+    ck_assert_int_eq(retval, UA_STATUSCODE_GOOD);
+
+    UA_Server_delete(server);
+} END_TEST
+
+int main(void) {
     Suite *s = suite_create("services_nodemanagement");
 
     TCase *tc_addnodes = tcase_create("addnodes");
@@ -252,24 +351,19 @@ static Suite * testSuite_services_nodemanagement(void) {
     tcase_add_test(tc_addnodes, AddComplexTypeWithInheritance);
     tcase_add_test(tc_addnodes, AddNodeTwiceGivesError);
     tcase_add_test(tc_addnodes, AddObjectWithConstructor);
+    tcase_add_test(tc_addnodes, InstantiateObjectType);
 
     TCase *tc_deletenodes = tcase_create("deletenodes");
-    tcase_add_test(tc_addnodes, DeleteObjectWithDestructor);
-    tcase_add_test(tc_addnodes, DeleteObjectAndReferences);
+    tcase_add_test(tc_deletenodes, DeleteObjectWithDestructor);
+    tcase_add_test(tc_deletenodes, DeleteObjectAndReferences);
 
     suite_add_tcase(s, tc_addnodes);
     suite_add_tcase(s, tc_deletenodes);
-    return s;
-}
 
-int main(void) {
-    int number_failed = 0;
-    Suite *s;
-    s = testSuite_services_nodemanagement();
     SRunner *sr = srunner_create(s);
     srunner_set_fork_status(sr, CK_NOFORK);
     srunner_run_all(sr, CK_NORMAL);
-    number_failed += srunner_ntests_failed(sr);
+    int number_failed = srunner_ntests_failed(sr);
     srunner_free(sr);
     return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
 }