Browse Source

added WG handling and extended pubsub information model tests. Fixed some memory leaks.

Andreas Ebner 5 years ago
parent
commit
7750c77fef

+ 1 - 1
src/pubsub/ua_pubsub.c

@@ -161,7 +161,7 @@ UA_Server_removeWriterGroup(UA_Server *server, const UA_NodeId writerGroup){
     if(UA_PubSubManager_removeRepeatedPubSubCallback(server, wg->publishCallbackId) != UA_STATUSCODE_GOOD)
         return UA_STATUSCODE_BADINTERNALERROR;
 #ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL
-    removeWriterGroupRepresentation(server, wg);
+    removeGroupRepresentation(server, wg);
 #endif
 
     UA_WriterGroup_deleteMembers(server, wg);

+ 70 - 2
src/pubsub/ua_pubsub_ns0.c

@@ -22,6 +22,20 @@ typedef struct{
     UA_UInt32 elementClassiefier;
 } UA_NodePropertyContext;
 
+//Prototypes
+static UA_StatusCode addWriterGroupAction(UA_Server *server,
+                                          const UA_NodeId *sessionId, void *sessionHandle,
+                                          const UA_NodeId *methodId, void *methodContext,
+                                          const UA_NodeId *objectId, void *objectContext,
+                                          size_t inputSize, const UA_Variant *input,
+                                          size_t outputSize, UA_Variant *output);
+static UA_StatusCode removeGroupAction(UA_Server *server,
+                                          const UA_NodeId *sessionId, void *sessionHandle,
+                                          const UA_NodeId *methodId, void *methodContext,
+                                          const UA_NodeId *objectId, void *objectContext,
+                                          size_t inputSize, const UA_Variant *input,
+                                          size_t outputSize, UA_Variant *output);
+
 static UA_StatusCode
 addPubSubObjectNode(UA_Server *server, char* name, UA_UInt32 objectid,
               UA_UInt32 parentid, UA_UInt32 referenceid, UA_UInt32 type_id) {
@@ -284,7 +298,7 @@ addPubSubConnectionAction(UA_Server *server,
     };
     UA_NetworkAddressUrlDataType_deleteMembers(&networkAddressUrlDataType);
     //set ouput value
-    UA_Variant_setScalar(output, &connectionId, &UA_TYPES[UA_TYPES_NODEID]);
+    UA_Variant_setScalarCopy(output, &connectionId, &UA_TYPES[UA_TYPES_NODEID]);
     return UA_STATUSCODE_GOOD;
 }
 #endif
@@ -533,13 +547,56 @@ addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup){
     return retVal;
 }
 
+#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
+static UA_StatusCode
+addWriterGroupAction(UA_Server *server,
+                             const UA_NodeId *sessionId, void *sessionHandle,
+                             const UA_NodeId *methodId, void *methodContext,
+                             const UA_NodeId *objectId, void *objectContext,
+                             size_t inputSize, const UA_Variant *input,
+                             size_t outputSize, UA_Variant *output){
+    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
+    UA_WriterGroupDataType *writerGroupDataType = ((UA_WriterGroupDataType *) input[0].data);
+    UA_NodeId generatedId;
+    UA_WriterGroupConfig writerGroupConfig;
+    memset(&writerGroupConfig, 0, sizeof(UA_WriterGroupConfig));
+    writerGroupConfig.name = writerGroupDataType->name;
+    writerGroupConfig.publishingInterval = writerGroupDataType->publishingInterval;
+    writerGroupConfig.writerGroupId = writerGroupDataType->writerGroupId;
+    writerGroupConfig.enabled = writerGroupDataType->enabled;
+    writerGroupConfig.priority = writerGroupDataType->priority;
+    //ToDo transfer all arguments to internal WGConfiguration
+    retVal |= UA_Server_addWriterGroup(server, *objectId, &writerGroupConfig, &generatedId);
+    UA_Variant_setScalarCopy(output, &generatedId, &UA_TYPES[UA_TYPES_NODEID]);
+    return retVal;
+}
+#endif
+
 UA_StatusCode
-removeWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup) {
+removeGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup) {
     UA_StatusCode retVal = UA_STATUSCODE_GOOD;
     retVal |= UA_Server_deleteNode(server, writerGroup->identifier, false);
     return retVal;
 }
 
+#ifdef UA_ENABLE_PUBSUB_INFORMATIONMODEL_METHODS
+static UA_StatusCode
+removeGroupAction(UA_Server *server,
+                             const UA_NodeId *sessionId, void *sessionHandle,
+                             const UA_NodeId *methodId, void *methodContext,
+                             const UA_NodeId *objectId, void *objectContext,
+                             size_t inputSize, const UA_Variant *input,
+                             size_t outputSize, UA_Variant *output){
+    UA_StatusCode retVal = UA_STATUSCODE_GOOD;
+    UA_NodeId nodeToRemove = *((UA_NodeId *) input[0].data);
+    if(UA_WriterGroup_findWGbyId(server, nodeToRemove) != NULL)
+        retVal |= UA_Server_removeWriterGroup(server, nodeToRemove);
+    //else
+        //retVal |= UA_Server_removeReaderGroup(server, nodeToRemve);
+    return retVal;
+}
+#endif
+
 /**********************************************/
 /*               DataSetWriter                */
 /**********************************************/
@@ -582,6 +639,15 @@ connectionTypeDestructor(UA_Server *server,
                          const UA_NodeId *typeId, void *typeContext,
                          const UA_NodeId *nodeId, void **nodeContext) {
     UA_LOG_INFO(server->config.logger, UA_LOGCATEGORY_USERLAND, "Connection destructor called!");
+    UA_NodeId publisherIdNode;
+    publisherIdNode = findSingleChildNode(server, UA_QUALIFIEDNAME(0, "PublisherId"),
+                                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY), *nodeId);
+    UA_NodePropertyContext *internalConnectionContext;
+    UA_Server_getNodeContext(server, publisherIdNode, (void **) &internalConnectionContext);
+    if(!UA_NodeId_equal(&UA_NODEID_NULL , &publisherIdNode)){
+        UA_free(internalConnectionContext);
+    }
+
 }
 
 static void
@@ -643,6 +709,8 @@ UA_Server_initPubSubNS0(UA_Server *server) {
                                                UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS), addPublishedDataItemsAction);
     retVal |= UA_Server_setMethodNode_callback(server,
                                                UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_REMOVEPUBLISHEDDATASET), removePublishedDataSetAction);
+    retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP), addWriterGroupAction);
+    retVal |= UA_Server_setMethodNode_callback(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_REMOVEGROUP), removeGroupAction);
 #else
     retVal |= UA_Server_deleteReference(server, UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE), UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT), true,
                                         UA_EXPANDEDNODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION),

+ 1 - 1
src/pubsub/ua_pubsub_ns0.h

@@ -28,7 +28,7 @@ UA_StatusCode
 addWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup);
 
 UA_StatusCode
-removeWriterGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup);
+removeGroupRepresentation(UA_Server *server, UA_WriterGroup *writerGroup);
 
 UA_StatusCode
 addDataSetWriterRepresentation(UA_Server *server, UA_DataSetWriter *dataSetWriter);

+ 144 - 28
tests/pubsub/check_pubsub_informationmodel_methods.c

@@ -7,7 +7,6 @@
 
 #include <string.h>
 #include <math.h>
-#include <src_generated/ua_types_generated.h>
 #include "src_generated/ua_types_generated.h"
 #include "ua_types.h"
 #include "src_generated/ua_types_generated_encoding_binary.h"
@@ -21,10 +20,6 @@
 #include "ua_config_default.h"
 #include "thread_wrapper.h"
 
-
-UA_NodeId connection1, connection2, writerGroup1, writerGroup2, writerGroup3,
-        publishedDataSet1, publishedDataSet2, dataSetWriter1, dataSetWriter2, dataSetWriter3;
-
 UA_Server *server = NULL;
 UA_ServerConfig *config = NULL;
 UA_Boolean running;
@@ -86,15 +81,7 @@ findSingleChildNode(UA_QualifiedName targetName,
     return resultNodeId;
 }
 
-START_TEST(AddNewPubSubConnectionUsingTheInformationModelMethod){
-    UA_StatusCode retVal;
-    UA_Client *client = UA_Client_new(UA_ClientConfig_default);
-    retVal = UA_Client_connect(client, "opc.tcp://localhost:4840");
-    if(retVal != UA_STATUSCODE_GOOD) {
-        UA_Client_delete(client);
-    }
-    ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
-
+static UA_NodeId addPubSubConnection(void){
     UA_Variant publisherId;
     UA_Variant_init(&publisherId);
     UA_UInt32 publisherIdValue = 13245;
@@ -137,33 +124,52 @@ START_TEST(AddNewPubSubConnectionUsingTheInformationModelMethod){
     callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE);
     callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_ADDCONNECTION);
 
+    UA_NodeId connectionId = UA_NODEID_NULL;
     UA_CallMethodResult result;
     UA_CallMethodResult_init(&result);
     result = UA_Server_call(server, &callMethodRequest);
     ck_assert_int_eq(1, result.outputArgumentsSize);
     ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD);
-    UA_NodeId createdConnection;
     if(result.outputArguments->type == &UA_TYPES[UA_TYPES_NODEID])
-        createdConnection = *((UA_NodeId *) result.outputArguments->data);
+        connectionId =  *((UA_NodeId *) result.outputArguments->data);
+    UA_ExtensionObject_deleteMembers(&eo);
+    callMethodRequest.inputArguments = NULL;
+    callMethodRequest.inputArgumentsSize = 0;
+    UA_CallMethodRequest_deleteMembers(&callMethodRequest);
+    UA_CallMethodResult_deleteMembers(&result);
+    return connectionId;
+}
+
+START_TEST(AddNewPubSubConnectionUsingTheInformationModelMethod){
+    UA_StatusCode retVal;
+    UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+    retVal = UA_Client_connect(client, "opc.tcp://localhost:4840");
+    if(retVal != UA_STATUSCODE_GOOD) {
+        UA_Client_delete(client);
+    }
+    ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
+
+    UA_NodeId createdConnection = addPubSubConnection();
     UA_LocalizedText connectionDisplayName;
     UA_LocalizedText_init(&connectionDisplayName);
     retVal = UA_Server_readDisplayName(server, createdConnection, &connectionDisplayName);
     ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
-    ck_assert_str_eq((const char *) connectionDisplayName.text.data, "Model Connection 1");
+    UA_String compareText = UA_STRING("Model Connection 1");
+    ck_assert(UA_String_equal(&connectionDisplayName.text, &compareText) == UA_TRUE);
     //todo browse and check childs
 
     UA_Variant serverPubSubConnectionValues;
     UA_Variant_init(&serverPubSubConnectionValues);
-    /*UA_NodeId connectionAddress = findSingleChildNode(UA_QUALIFIEDNAME(0, "Address"),
-                                                      UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
-                                                      createdConnection);*/
     UA_NodeId connectionPublisherId = findSingleChildNode(UA_QUALIFIEDNAME(0, "PublisherId"),
                                                       UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
                                                       createdConnection);
     ck_assert_int_eq(UA_Server_readValue(server, connectionPublisherId, &serverPubSubConnectionValues),
                      UA_STATUSCODE_GOOD);
-    ck_assert_uint_eq(*((UA_UInt32 *) serverPubSubConnectionValues.data), publisherIdValue);
-
+    ck_assert_uint_eq(*((UA_UInt32 *) serverPubSubConnectionValues.data), 13245);
+    UA_Variant_deleteMembers(&serverPubSubConnectionValues);
+    UA_Client_disconnect(client);
+    UA_Client_delete(client);
+    UA_LocalizedText_deleteMembers(&connectionDisplayName);
     } END_TEST
 
 START_TEST(AddAndRemovePublishedDataSetFolders){
@@ -200,11 +206,13 @@ START_TEST(AddAndRemovePublishedDataSetFolders){
         UA_LocalizedText_init(&connectionDisplayName);
         retVal = UA_Server_readDisplayName(server, createdFolder, &connectionDisplayName);
         ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
-        ck_assert_str_eq((const char *) connectionDisplayName.text.data, "TestFolder");
+        UA_String compareText = UA_STRING("TestFolder");
+        ck_assert(UA_String_equal(&connectionDisplayName.text, &compareText) == UA_TRUE);
         retVal = UA_Server_readNodeId(server, createdFolder, &createdFolder);
         ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
+        UA_CallMethodResult_deleteMembers(&result);
+        UA_LocalizedText_deleteMembers(&connectionDisplayName);
 
-        //TODO add folder inside the created folder
         //create folder inside the new folder
         folderName = UA_STRING("TestFolder2");
         UA_Variant_init(&inputArguments);
@@ -224,9 +232,11 @@ START_TEST(AddAndRemovePublishedDataSetFolders){
         UA_LocalizedText_init(&connectionDisplayName);
         retVal = UA_Server_readDisplayName(server, createdFolder2, &connectionDisplayName);
         ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
-        ck_assert_str_eq((const char *) connectionDisplayName.text.data, "TestFolder2");
+        compareText = UA_STRING("TestFolder2");
+        ck_assert(UA_String_equal(&connectionDisplayName.text, &compareText) == UA_TRUE);
         retVal = UA_Server_readNodeId(server, createdFolder2, &createdFolder2);
         ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
+        UA_CallMethodResult_deleteMembers(&result);
 
         //delete the folder
         UA_Variant_init(&inputArguments);
@@ -244,16 +254,122 @@ START_TEST(AddAndRemovePublishedDataSetFolders){
         retVal = UA_Server_readNodeId(server, createdFolder, NULL);
         ck_assert_int_eq(retVal, UA_STATUSCODE_BADNODEIDUNKNOWN);
 
-
+        UA_CallMethodResult_deleteMembers(&result);
+        UA_Client_disconnect(client);
+        UA_Client_delete(client);
+        UA_LocalizedText_deleteMembers(&connectionDisplayName);
     } END_TEST
 
+START_TEST(AddAndRemovePublishedDataSetItems){
+        UA_StatusCode retVal;
+        UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+        retVal = UA_Client_connect(client, "opc.tcp://localhost:4840");
+        if(retVal != UA_STATUSCODE_GOOD) {
+            UA_Client_delete(client);
+        }
+        ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
+
+        UA_Variant *inputArguments = (UA_Variant *) UA_calloc(4, (sizeof(UA_Variant)));
+
+        UA_String pdsName = UA_STRING("Test PDS");
+        UA_Variant_setScalar(&inputArguments[0], &pdsName, &UA_TYPES[UA_TYPES_STRING]);
+
+        UA_String *fieldNameAliases = (UA_String *) UA_calloc(2, sizeof(UA_String));
+        fieldNameAliases[0] = UA_STRING("field1");
+        fieldNameAliases[1] = UA_STRING("field2");
+        UA_Variant_setArray(&inputArguments[1], fieldNameAliases, 2, &UA_TYPES[UA_TYPES_STRING]);
+
+        UA_DataSetFieldFlags *dataSetFieldFlags = (UA_DataSetFieldFlags *) UA_calloc(2, sizeof(UA_DataSetFieldFlags));
+        dataSetFieldFlags[0] = UA_DATASETFIELDFLAGS_PROMOTEDFIELD;
+        dataSetFieldFlags[1] = UA_DATASETFIELDFLAGS_PROMOTEDFIELD;
+        UA_Variant_setArray(&inputArguments[2], dataSetFieldFlags, 2, &UA_TYPES[UA_TYPES_DATASETFIELDFLAGS]);
+
+        UA_PublishedVariableDataType *variablesToAdd = (UA_PublishedVariableDataType *) UA_calloc(2, sizeof(UA_PublishedVariableDataType));
+        variablesToAdd[0].publishedVariable = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_LOCALTIME);
+        variablesToAdd[0].attributeId = UA_ATTRIBUTEID_VALUE;
+        variablesToAdd[1].publishedVariable = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERREDUNDANCY_CURRENTSERVERID);
+        variablesToAdd[1].attributeId = UA_ATTRIBUTEID_VALUE;
+        UA_Variant_setArray(&inputArguments[3], variablesToAdd, 2, &UA_TYPES[UA_TYPES_PUBLISHEDVARIABLEDATATYPE]);
+
+        UA_CallMethodRequest callMethodRequest;
+        UA_CallMethodRequest_init(&callMethodRequest);
+        callMethodRequest.inputArgumentsSize = 4;
+        callMethodRequest.inputArguments = inputArguments;
+        callMethodRequest.objectId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBLISHSUBSCRIBE_PUBLISHEDDATASETS);
+        callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_DATASETFOLDERTYPE_ADDPUBLISHEDDATAITEMS);
+
+        UA_CallMethodResult result;
+        UA_CallMethodResult_init(&result);
+        result = UA_Server_call(server, &callMethodRequest);
+        ck_assert_int_eq(3, result.outputArgumentsSize);
+        ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD);
+
+        //TODO checked correctness of created items
+        UA_CallMethodResult_deleteMembers(&result);
+        UA_free(inputArguments);
+        UA_free(fieldNameAliases);
+        UA_free(dataSetFieldFlags);
+        UA_free(variablesToAdd);
+        UA_Client_disconnect(client);
+        UA_Client_delete(client);
+} END_TEST
+
+START_TEST(AddAndRemoveWriterGroups){
+        UA_StatusCode retVal;
+        UA_Client *client = UA_Client_new(UA_ClientConfig_default);
+        retVal = UA_Client_connect(client, "opc.tcp://localhost:4840");
+        if(retVal != UA_STATUSCODE_GOOD) {
+            UA_Client_delete(client);
+        }
+        ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
+        UA_NodeId createdConnection = addPubSubConnection();
+
+        UA_Variant *inputArgument = (UA_Variant *) UA_calloc(1, (sizeof(UA_Variant)));
+        UA_WriterGroupDataType writerGroupDataType;
+        UA_WriterGroupDataType_init(&writerGroupDataType);
+        writerGroupDataType.name = UA_STRING("TestWriterGroup");
+        writerGroupDataType.enabled = UA_TRUE;
+        writerGroupDataType.publishingInterval = 500;
+        writerGroupDataType.writerGroupId = 1234;
+        UA_Variant_setScalar(inputArgument, &writerGroupDataType, &UA_TYPES[UA_TYPES_WRITERGROUPDATATYPE]);
+
+        UA_CallMethodRequest callMethodRequest;
+        UA_CallMethodRequest_init(&callMethodRequest);
+        callMethodRequest.inputArgumentsSize = 1;
+        callMethodRequest.inputArguments = inputArgument;
+        callMethodRequest.objectId = createdConnection;
+        callMethodRequest.methodId = UA_NODEID_NUMERIC(0, UA_NS0ID_PUBSUBCONNECTIONTYPE_ADDWRITERGROUP);
+
+        UA_CallMethodResult result;
+        UA_CallMethodResult_init(&result);
+        result = UA_Server_call(server, &callMethodRequest);
+        ck_assert_int_eq(result.statusCode, UA_STATUSCODE_GOOD);
+        ck_assert_int_eq(1, result.outputArgumentsSize);
+
+        UA_NodeId createdWriterGroup;
+        if(result.outputArguments->type == &UA_TYPES[UA_TYPES_NODEID])
+            createdWriterGroup = *((UA_NodeId *) result.outputArguments->data);
+        UA_LocalizedText writerGroupDisplayName;
+        UA_LocalizedText_init(&writerGroupDisplayName);
+        retVal = UA_Server_readDisplayName(server, createdWriterGroup, &writerGroupDisplayName);
+        ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
+        UA_String compareText = UA_STRING("TestWriterGroup");
+        ck_assert(UA_String_equal(&writerGroupDisplayName.text, &compareText) == UA_TRUE);
+        UA_free(inputArgument);
+        UA_CallMethodResult_deleteMembers(&result);
+        UA_Client_disconnect(client);
+        UA_Client_delete(client);
+        UA_LocalizedText_deleteMembers(&writerGroupDisplayName);
+} END_TEST
+
 int main(void) {
     TCase *tc_add_pubsub_informationmodel_methods_connection = tcase_create("PubSub connection delete and creation using the information model methods");
     tcase_add_checked_fixture(tc_add_pubsub_informationmodel_methods_connection, setup, teardown);
     tcase_add_test(tc_add_pubsub_informationmodel_methods_connection, AddNewPubSubConnectionUsingTheInformationModelMethod);
     tcase_add_test(tc_add_pubsub_informationmodel_methods_connection, AddAndRemovePublishedDataSetFolders);
-
-
+    tcase_add_test(tc_add_pubsub_informationmodel_methods_connection, AddAndRemovePublishedDataSetItems);
+    tcase_add_test(tc_add_pubsub_informationmodel_methods_connection, AddAndRemoveWriterGroups);
+    //TODO TestCase add publishedDataItems and removePublishedDataItems, writergroup remove
 
     Suite *s = suite_create("PubSub CRUD configuration by the information model functions");
     suite_add_tcase(s, tc_add_pubsub_informationmodel_methods_connection);