open62541/tests/pubsub/check_pubsub_subscribe_config_freeze.c
Julius Pfrommer 5bf6f0c3e7 refactor(pubsub): Remove the old direct-access API
The public Offset Table API should be used for realtime operations on
the NetworkMessages instead.
2025-01-19 22:33:50 +01:00

277 lines
14 KiB
C

/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2020 Kalycito Infotech Private Limited (Author: Suriya Narayanan)
*/
#include <open62541/server_config_default.h>
#include <open62541/server_pubsub.h>
#include "ua_server_internal.h"
#include "ua_pubsub_internal.h"
#include "test_helpers.h"
#include <check.h>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
UA_Server *server = NULL;
static void setup(void) {
server = UA_Server_newForUnitTest();
ck_assert(server != NULL);
UA_Server_run_startup(server);
}
static void teardown(void) {
UA_Server_run_shutdown(server);
UA_Server_delete(server);
}
START_TEST(CreateAndLockConfiguration) {
//create config
UA_NodeId connection1, readerGroup1, dataSetReader1;
UA_PubSubConnectionConfig connectionConfig;
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
connectionConfig.name = UA_STRING("UADP Connection");
UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL, UA_STRING("opc.udp://224.0.0.22:4840/")};
UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl, &UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
retVal |= UA_Server_addPubSubConnection(server, &connectionConfig, &connection1);
UA_ReaderGroupConfig readerGroupConfig;
memset(&readerGroupConfig, 0, sizeof(readerGroupConfig));
readerGroupConfig.name = UA_STRING("ReaderGroup 1");
retVal |= UA_Server_addReaderGroup(server, connection1, &readerGroupConfig, &readerGroup1);
UA_PubSubManager *psm = getPSM(server);
//get internal RG Pointer
UA_ReaderGroup *readerGroup = UA_ReaderGroup_find(psm, readerGroup1);
ck_assert(readerGroup->head.state == UA_PUBSUBSTATE_DISABLED);
ck_assert(readerGroup->configurationFrozen == UA_FALSE);
UA_DataSetReaderConfig dataSetReaderConfig;
memset(&dataSetReaderConfig, 0, sizeof(dataSetReaderConfig));
dataSetReaderConfig.name = UA_STRING("DataSetReader 1");
retVal |= UA_Server_addDataSetReader(server, readerGroup1, &dataSetReaderConfig, &dataSetReader1);
UA_DataSetReader *dataSetReader = UA_DataSetReader_find(psm, dataSetReader1);
ck_assert(dataSetReader != NULL);
//Lock the reader group and the child pubsub entities
UA_ReaderGroup *readerGroup_1 = UA_ReaderGroup_find(psm, readerGroup1);
UA_LOCK(&server->serviceMutex);
retVal |= UA_ReaderGroup_setPubSubState(getPSM(server), readerGroup_1, UA_PUBSUBSTATE_OPERATIONAL);
UA_UNLOCK(&server->serviceMutex);
ck_assert(readerGroup->configurationFrozen == UA_TRUE);
//set state to disabled and implicit unlock the configuration
UA_LOCK(&server->serviceMutex);
retVal |= UA_ReaderGroup_setPubSubState(getPSM(server), readerGroup_1, UA_PUBSUBSTATE_DISABLED);
UA_UNLOCK(&server->serviceMutex);
ck_assert(readerGroup->configurationFrozen == UA_FALSE);
ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(CreateAndReleaseMultipleLocks) {
//create config
UA_NodeId connection1, readerGroup1, readerGroup2, dataSetReader1, dataSetReader2, dataSetReader3;
UA_PubSubConnectionConfig connectionConfig;
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
connectionConfig.name = UA_STRING("UADP Connection");
UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL, UA_STRING("opc.udp://224.0.0.22:4840/")};
UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl,
&UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
retVal |= UA_Server_addPubSubConnection(server, &connectionConfig, &connection1);
//Add two reader groups
UA_ReaderGroupConfig readerGroupConfig;
memset(&readerGroupConfig, 0, sizeof(readerGroupConfig));
readerGroupConfig.name = UA_STRING("ReaderGroup 1");
retVal |= UA_Server_addReaderGroup(server, connection1, &readerGroupConfig, &readerGroup1);
readerGroupConfig.name = UA_STRING("ReaderGroup 2");
retVal |= UA_Server_addReaderGroup(server, connection1, &readerGroupConfig, &readerGroup2);
UA_DataSetReaderConfig dataSetReaderConfig;
memset(&dataSetReaderConfig, 0, sizeof(dataSetReaderConfig));
dataSetReaderConfig.name = UA_STRING("DataSetReader 1");
retVal |= UA_Server_addDataSetReader(server, readerGroup1, &dataSetReaderConfig, &dataSetReader1);
dataSetReaderConfig.name = UA_STRING("DataSetReader 2");
retVal |= UA_Server_addDataSetReader(server, readerGroup1, &dataSetReaderConfig, &dataSetReader2);
dataSetReaderConfig.name = UA_STRING("DataSetReader 3");
retVal |= UA_Server_addDataSetReader(server, readerGroup2, &dataSetReaderConfig, &dataSetReader3);
UA_PubSubManager *psm = getPSM(server);
UA_ReaderGroup *readerGroup_1 = UA_ReaderGroup_find(psm, readerGroup1);
UA_ReaderGroup *readerGroup_2 = UA_ReaderGroup_find(psm, readerGroup2);
//freeze configuration of both RG
ck_assert(readerGroup_1->configurationFrozen == UA_FALSE);
ck_assert(readerGroup_2->configurationFrozen == UA_FALSE);
UA_LOCK(&server->serviceMutex);
retVal |= UA_ReaderGroup_setPubSubState(getPSM(server), readerGroup_1, UA_PUBSUBSTATE_OPERATIONAL);
retVal |= UA_ReaderGroup_setPubSubState(getPSM(server), readerGroup_2, UA_PUBSUBSTATE_OPERATIONAL);
UA_UNLOCK(&server->serviceMutex);
ck_assert_int_eq(retVal, UA_STATUSCODE_GOOD);
ck_assert(readerGroup_1->configurationFrozen == UA_TRUE);
ck_assert(readerGroup_2->configurationFrozen == UA_TRUE);
//unlock one tree, get sure connection still locked
UA_LOCK(&server->serviceMutex);
UA_ReaderGroup_setPubSubState(getPSM(server), readerGroup_1, UA_PUBSUBSTATE_DISABLED);
UA_ReaderGroup_setPubSubState(getPSM(server), readerGroup_2, UA_PUBSUBSTATE_DISABLED);
UA_UNLOCK(&server->serviceMutex);
ck_assert(readerGroup_1->configurationFrozen == UA_FALSE);
ck_assert(readerGroup_2->configurationFrozen == UA_FALSE);
} END_TEST
START_TEST(CreateLockAndEditConfiguration) {
UA_NodeId connection1, readerGroup1, dataSetReader1, dataSetReader2;
UA_StatusCode retVal = UA_STATUSCODE_GOOD;
UA_PubSubConnectionConfig connectionConfig;
memset(&connectionConfig, 0, sizeof(UA_PubSubConnectionConfig));
connectionConfig.name = UA_STRING("UADP Connection");
UA_NetworkAddressUrlDataType networkAddressUrl = {UA_STRING_NULL, UA_STRING("opc.udp://224.0.0.22:4840/")};
UA_Variant_setScalar(&connectionConfig.address, &networkAddressUrl,
&UA_TYPES[UA_TYPES_NETWORKADDRESSURLDATATYPE]);
connectionConfig.transportProfileUri = UA_STRING("http://opcfoundation.org/UA-Profile/Transport/pubsub-udp-uadp");
retVal |= UA_Server_addPubSubConnection(server, &connectionConfig, &connection1);
UA_ReaderGroupConfig readerGroupConfig;
memset(&readerGroupConfig, 0, sizeof(readerGroupConfig));
readerGroupConfig.name = UA_STRING("ReaderGroup 1");
retVal |= UA_Server_addReaderGroup(server, connection1, &readerGroupConfig, &readerGroup1);
UA_PubSubManager *psm = getPSM(server);
//get internal RG Pointer
UA_ReaderGroup *readerGroup = UA_ReaderGroup_find(psm, readerGroup1);
ck_assert(readerGroup->head.state == UA_PUBSUBSTATE_DISABLED);
ck_assert(readerGroup->configurationFrozen == UA_FALSE);
UA_DataSetReaderConfig dataSetReaderConfig;
memset(&dataSetReaderConfig, 0, sizeof(dataSetReaderConfig));
dataSetReaderConfig.name = UA_STRING("DataSetReader 1");
/* Setting up Meta data configuration in DataSetReader for DateTime DataType */
UA_DataSetMetaDataType *pMetaData = &dataSetReaderConfig.dataSetMetaData;
/* FilltestMetadata function in subscriber implementation */
UA_DataSetMetaDataType_init(pMetaData);
pMetaData->name = UA_STRING("DataSet Test");
/* Static definition of number of fields size to 1 to create one
targetVariable */
pMetaData->fieldsSize = 1;
pMetaData->fields = (UA_FieldMetaData*)UA_Array_new (pMetaData->fieldsSize,
&UA_TYPES[UA_TYPES_FIELDMETADATA]);
/* DateTime DataType */
UA_FieldMetaData_init (&pMetaData->fields[0]);
UA_NodeId_copy (&UA_TYPES[UA_TYPES_DATETIME].typeId,
&pMetaData->fields[0].dataType);
pMetaData->fields[0].builtInType = UA_NS0ID_DATETIME;
pMetaData->fields[0].name = UA_STRING ("DateTime");
pMetaData->fields[0].valueRank = -1; /* scalar */
retVal |= UA_Server_addDataSetReader(server, readerGroup1, &dataSetReaderConfig, &dataSetReader1);
UA_NodeId folderId;
UA_String folderName = dataSetReaderConfig.dataSetMetaData.name;
UA_ObjectAttributes oAttr = UA_ObjectAttributes_default;
UA_QualifiedName folderBrowseName;
if(folderName.length > 0) {
oAttr.displayName.locale = UA_STRING ("en-US");
oAttr.displayName.text = folderName;
folderBrowseName.namespaceIndex = 1;
folderBrowseName.name = folderName;
}
else {
oAttr.displayName = UA_LOCALIZEDTEXT ("en-US", "Subscribed Variables");
folderBrowseName = UA_QUALIFIEDNAME (1, "Subscribed Variables");
}
retVal |= UA_Server_addObjectNode (server, UA_NODEID_NULL,
UA_NODEID_NUMERIC (0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC (0, UA_NS0ID_ORGANIZES),
folderBrowseName, UA_NODEID_NUMERIC (0,
UA_NS0ID_BASEOBJECTTYPE), oAttr, NULL, &folderId);
UA_FieldTargetDataType *targetVars = (UA_FieldTargetDataType *)
UA_calloc(dataSetReaderConfig.dataSetMetaData.fieldsSize, sizeof(UA_FieldTargetDataType));
for(size_t i = 0; i < dataSetReaderConfig.dataSetMetaData.fieldsSize; i++) {
/* Variable to subscribe data */
UA_VariableAttributes vAttr = UA_VariableAttributes_default;
UA_LocalizedText_copy(&dataSetReaderConfig.dataSetMetaData.fields[i].description,
&vAttr.description);
vAttr.displayName.locale = UA_STRING("en-US");
vAttr.displayName.text = dataSetReaderConfig.dataSetMetaData.fields[i].name;
vAttr.dataType = dataSetReaderConfig.dataSetMetaData.fields[i].dataType;
UA_NodeId newNode;
retVal |= UA_Server_addVariableNode(server, UA_NODEID_NUMERIC(1, (UA_UInt32)i + 50000),
folderId,
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, (char *)dataSetReaderConfig.dataSetMetaData.fields[i].name.data),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
vAttr, NULL, &newNode);
targetVars[i].attributeId = UA_ATTRIBUTEID_VALUE;
targetVars[i].targetNodeId = newNode;
}
retVal = UA_Server_enableDataSetReader(server, dataSetReader1);
ck_assert(retVal == UA_STATUSCODE_GOOD);
//Lock the reader group and the child pubsub entities
UA_ReaderGroup *rg1 = UA_ReaderGroup_find(psm, readerGroup1);
UA_LOCK(&server->serviceMutex);
UA_ReaderGroup_setPubSubState(getPSM(server), rg1, UA_PUBSUBSTATE_OPERATIONAL);
UA_UNLOCK(&server->serviceMutex);
//call not allowed configuration methods
retVal = UA_Server_DataSetReader_createTargetVariables(server, dataSetReader1,
dataSetReaderConfig.dataSetMetaData.fieldsSize,
targetVars);
ck_assert(retVal == UA_STATUSCODE_BADCONFIGURATIONERROR);
//unlock the reader group
UA_LOCK(&server->serviceMutex);
UA_ReaderGroup_setPubSubState(getPSM(server), rg1, UA_PUBSUBSTATE_DISABLED);
UA_UNLOCK(&server->serviceMutex);
retVal = UA_Server_disableDataSetReader(server, dataSetReader1);
ck_assert(retVal == UA_STATUSCODE_GOOD);
retVal = UA_Server_DataSetReader_createTargetVariables(server, dataSetReader1,
dataSetReaderConfig.dataSetMetaData.fieldsSize,
targetVars);
ck_assert(retVal == UA_STATUSCODE_GOOD);
retVal = UA_Server_addDataSetReader(server, readerGroup1, &dataSetReaderConfig, &dataSetReader2);
UA_free(targetVars);
UA_free(dataSetReaderConfig.dataSetMetaData.fields);
ck_assert(retVal == UA_STATUSCODE_GOOD);
retVal = UA_Server_removeDataSetReader(server, dataSetReader1);
ck_assert(retVal == UA_STATUSCODE_GOOD);
} END_TEST
int main(void) {
TCase *tc_lock_configuration = tcase_create("Create and Lock");
tcase_add_checked_fixture(tc_lock_configuration, setup, teardown);
tcase_add_test(tc_lock_configuration, CreateAndLockConfiguration);
tcase_add_test(tc_lock_configuration, CreateAndReleaseMultipleLocks);
tcase_add_test(tc_lock_configuration, CreateLockAndEditConfiguration);
Suite *s = suite_create("PubSub subscriber configuration lock mechanism");
suite_add_tcase(s, tc_lock_configuration);
SRunner *sr = srunner_create(s);
srunner_set_fork_status(sr, CK_NOFORK);
srunner_run_all(sr,CK_NORMAL);
int number_failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}