Files
open62541/tests/check_client_highlevel_write.c
Julius Pfrommer 335cead676 test(mt): synchronize remaining threaded fixture state
Use pointer-sized atomic run flags in threaded fixtures, including dynamically
allocated discovery and browse flags. Pointer sizing supports the MSVC atomic
implementation as well as C11 and GCC atomics.

Serialize the client error-injection test with the server network callbacks
before accessing the internal session and shared send buffer.
2026-09-21 16:23:09 +02:00

731 lines
27 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/. */
/* Client highlevel write, browse and method call tests */
#ifndef _GNU_SOURCE
# define _GNU_SOURCE
#endif
#include <open62541/client.h>
#include <open62541/client_config_default.h>
#include <open62541/client_highlevel.h>
#include <open62541/client_subscriptions.h>
#include <open62541/server.h>
#include <open62541/server_config_default.h>
#include <open62541/types.h>
#include <check.h>
#include "testing_clock.h"
#include "thread_wrapper.h"
#include "test_helpers.h"
static UA_Server *server;
static UA_atomic(uintptr_t) running;
static THREAD_HANDLE server_thread;
THREAD_CALLBACK(serverloop) {
while(UA_atomic_load(&running))
UA_Server_run_iterate(server, true);
return 0;
}
static void setup(void) {
server = UA_Server_newForUnitTest();
ck_assert(server != NULL);
/* Add a method node for testing */
UA_MethodAttributes methAttr = UA_MethodAttributes_default;
methAttr.displayName = UA_LOCALIZEDTEXT("en", "TestMethod");
methAttr.executable = true;
methAttr.userExecutable = true;
UA_Server_addMethodNode(server,
UA_NODEID_NUMERIC(1, 62000),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
UA_QUALIFIEDNAME(1, "TestMethod"),
methAttr, NULL, 0, NULL, 0, NULL, NULL, NULL);
/* Add a fully writable variable for writing tests */
UA_VariableAttributes varAttr = UA_VariableAttributes_default;
UA_Int32 val = 42;
UA_Variant_setScalar(&varAttr.value, &val, &UA_TYPES[UA_TYPES_INT32]);
varAttr.displayName = UA_LOCALIZEDTEXT("en", "WritableVar");
varAttr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE |
UA_ACCESSLEVELMASK_STATUSWRITE | UA_ACCESSLEVELMASK_TIMESTAMPWRITE;
varAttr.writeMask = UA_WRITEMASK_DISPLAYNAME | UA_WRITEMASK_DESCRIPTION |
UA_WRITEMASK_WRITEMASK | UA_WRITEMASK_ACCESSLEVEL |
UA_WRITEMASK_MINIMUMSAMPLINGINTERVAL | UA_WRITEMASK_HISTORIZING |
UA_WRITEMASK_VALUERANK | UA_WRITEMASK_ARRAYDIMENSIONS |
UA_WRITEMASK_DATATYPE;
UA_Server_addVariableNode(server,
UA_NODEID_NUMERIC(1, 62001),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "WritableVar"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
varAttr, NULL, NULL);
UA_atomic_store(&running, true);
UA_Server_run_startup(server);
THREAD_CREATE(server_thread, serverloop);
}
static void teardown(void) {
UA_atomic_store(&running, false);
THREAD_JOIN(server_thread);
UA_Server_run_shutdown(server);
UA_Server_delete(server);
}
static UA_Client *connectClient(void) {
UA_Client *client = UA_Client_newForUnitTest();
UA_StatusCode res = UA_Client_connect(client, "opc.tcp://localhost:4840");
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
return client;
}
static void disconnectClient(UA_Client *client) {
UA_Client_disconnect(client);
UA_Client_delete(client);
}
/* === Additional write attribute tests === */
START_TEST(hl_writeWriteMask) {
UA_Client *client = connectClient();
UA_UInt32 wm = UA_WRITEMASK_DISPLAYNAME;
UA_StatusCode res = UA_Client_writeWriteMaskAttribute(client,
UA_NODEID_NUMERIC(1, 62001), &wm);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_writeAccessLevel) {
UA_Client *client = connectClient();
UA_Byte al = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_StatusCode res = UA_Client_writeAccessLevelAttribute(client,
UA_NODEID_NUMERIC(1, 62001), &al);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_writeRbacAttributes) {
UA_Client *client = connectClient();
UA_Variant permissions;
UA_RolePermissionType permission;
UA_RolePermissionType_init(&permission);
permission.roleId = UA_NODEID_NUMERIC(0, UA_NS0ID_WELLKNOWNROLE_ANONYMOUS);
permission.permissions = UA_PERMISSIONTYPE_BROWSE;
UA_Variant_setArray(&permissions, &permission, 1,
&UA_TYPES[UA_TYPES_ROLEPERMISSIONTYPE]);
UA_StatusCode res = UA_Client_writeRolePermissionsAttribute(client,
UA_NODEID_NUMERIC(1, 62001), &permissions);
ck_assert(UA_StatusCode_isBad(res));
UA_AccessRestrictionType restrictions = UA_ACCESSRESTRICTIONTYPE_NONE;
res = UA_Client_writeAccessRestrictionsAttribute(client,
UA_NODEID_NUMERIC(1, 62001), &restrictions);
ck_assert(UA_StatusCode_isBad(res));
disconnectClient(client);
} END_TEST
START_TEST(hl_writeMinSampling) {
UA_Client *client = connectClient();
UA_Double val = 100.0;
UA_StatusCode res = UA_Client_writeMinimumSamplingIntervalAttribute(client,
UA_NODEID_NUMERIC(1, 62001), &val);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_writeHistorizing) {
UA_Client *client = connectClient();
UA_Boolean val = false;
UA_StatusCode res = UA_Client_writeHistorizingAttribute(client,
UA_NODEID_NUMERIC(1, 62001), &val);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_writeValueRank) {
UA_Client *client = connectClient();
UA_Int32 val = UA_VALUERANK_SCALAR;
UA_StatusCode res = UA_Client_writeValueRankAttribute(client,
UA_NODEID_NUMERIC(1, 62001), &val);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_writeValueScalar) {
UA_Client *client = connectClient();
UA_Int32 val = 999;
UA_StatusCode res = UA_Client_writeValueAttribute_scalar(client,
UA_NODEID_NUMERIC(1, 62001), &val, &UA_TYPES[UA_TYPES_INT32]);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_writeValueEx) {
UA_Client *client = connectClient();
UA_DataValue dv;
UA_DataValue_init(&dv);
dv.hasValue = true;
UA_Int32 val = 777;
UA_Variant_setScalar(&dv.value, &val, &UA_TYPES[UA_TYPES_INT32]);
dv.hasSourceTimestamp = true;
dv.sourceTimestamp = UA_DateTime_now();
UA_StatusCode res = UA_Client_writeValueAttributeEx(client,
UA_NODEID_NUMERIC(1, 62001), &dv);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
/* === Add various node types === */
START_TEST(hl_addVariableTypeNode) {
UA_Client *client = connectClient();
UA_NodeId outNodeId;
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "TestVarType");
UA_StatusCode res = UA_Client_addVariableTypeNode(client,
UA_NODEID_NUMERIC(1, 62100),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "TestVarType"),
attr, &outNodeId);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_addObjectTypeNode) {
UA_Client *client = connectClient();
UA_NodeId outNodeId;
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "TestObjType");
UA_StatusCode res = UA_Client_addObjectTypeNode(client,
UA_NODEID_NUMERIC(1, 62101),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "TestObjType"),
attr, &outNodeId);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_addReferenceTypeNode) {
UA_Client *client = connectClient();
UA_NodeId outNodeId;
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "TestRefType");
attr.isAbstract = false;
attr.symmetric = false;
UA_StatusCode res = UA_Client_addReferenceTypeNode(client,
UA_NODEID_NUMERIC(1, 62102),
UA_NODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "TestRefType"),
attr, &outNodeId);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_addDataTypeNode) {
UA_Client *client = connectClient();
UA_NodeId outNodeId;
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "TestDataType");
UA_StatusCode res = UA_Client_addDataTypeNode(client,
UA_NODEID_NUMERIC(1, 62103),
UA_NODEID_NUMERIC(0, UA_NS0ID_STRUCTURE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "TestDataType"),
attr, &outNodeId);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_addViewNode) {
UA_Client *client = connectClient();
UA_NodeId outNodeId;
UA_ViewAttributes attr = UA_ViewAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "TestView");
UA_StatusCode res = UA_Client_addViewNode(client,
UA_NODEID_NUMERIC(1, 62104),
UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "TestView"),
attr, &outNodeId);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
/* === Delete reference === */
START_TEST(hl_deleteReference) {
UA_Client *client = connectClient();
/* Add node with reference, then delete the reference */
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
UA_NodeId newNodeId;
UA_Client_addObjectNode(client,
UA_NODEID_NUMERIC(1, 62110),
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "DelRefTest"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
attr, &newNodeId);
UA_StatusCode res = UA_Client_deleteReference(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), true,
UA_EXPANDEDNODEID_NUMERIC(1, 62110), true);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
/* === Method call === */
START_TEST(hl_callMethod) {
UA_Client *client = connectClient();
/* Call GetMonitoredItems - a server-provided method */
UA_Variant input;
UA_UInt32 subId = 0;
UA_Variant_setScalar(&input, &subId, &UA_TYPES[UA_TYPES_UINT32]);
size_t outputSize = 0;
UA_Variant *output = NULL;
UA_StatusCode res = UA_Client_call(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER),
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS),
1, &input, &outputSize, &output);
/* May fail if subscription doesn't exist */
(void)res;
if(output)
UA_Array_delete(output, outputSize, &UA_TYPES[UA_TYPES_VARIANT]);
disconnectClient(client);
} END_TEST
/* === Browse and translate === */
START_TEST(hl_browseNext) {
UA_Client *client = connectClient();
/* Browse with limited results to get continuation point */
UA_BrowseRequest bReq;
UA_BrowseRequest_init(&bReq);
bReq.requestedMaxReferencesPerNode = 1;
bReq.nodesToBrowseSize = 1;
bReq.nodesToBrowse = UA_BrowseDescription_new();
bReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER);
bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL;
bReq.nodesToBrowse[0].browseDirection = UA_BROWSEDIRECTION_FORWARD;
UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
ck_assert_uint_eq(bResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
/* If continuation point exists, browse next */
if(bResp.resultsSize > 0 && bResp.results[0].continuationPoint.length > 0) {
UA_BrowseNextRequest bnReq;
UA_BrowseNextRequest_init(&bnReq);
bnReq.releaseContinuationPoints = false;
bnReq.continuationPointsSize = 1;
bnReq.continuationPoints = &bResp.results[0].continuationPoint;
UA_BrowseNextResponse bnResp =
UA_Client_Service_browseNext(client, bnReq);
ck_assert_uint_eq(bnResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
/* Release continuation point */
bnReq.releaseContinuationPoints = true;
UA_BrowseNextResponse bnResp2 =
UA_Client_Service_browseNext(client, bnReq);
(void)bnResp2;
/* Avoid double-free */
bnReq.continuationPoints = NULL;
bnReq.continuationPointsSize = 0;
UA_BrowseNextRequest_clear(&bnReq);
UA_BrowseNextResponse_clear(&bnResp);
UA_BrowseNextResponse_clear(&bnResp2);
}
UA_BrowseRequest_clear(&bReq);
UA_BrowseResponse_clear(&bResp);
disconnectClient(client);
} END_TEST
START_TEST(hl_translateBrowsePath) {
UA_Client *client = connectClient();
UA_BrowsePath bp;
UA_BrowsePath_init(&bp);
bp.startingNode = UA_NODEID_NUMERIC(0, UA_NS0ID_ROOTFOLDER);
UA_RelativePathElement rpe;
UA_RelativePathElement_init(&rpe);
rpe.referenceTypeId = UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES);
rpe.includeSubtypes = true;
rpe.targetName = UA_QUALIFIEDNAME(0, "Objects");
bp.relativePath.elements = &rpe;
bp.relativePath.elementsSize = 1;
UA_TranslateBrowsePathsToNodeIdsRequest tbReq;
UA_TranslateBrowsePathsToNodeIdsRequest_init(&tbReq);
tbReq.browsePaths = &bp;
tbReq.browsePathsSize = 1;
UA_TranslateBrowsePathsToNodeIdsResponse tbResp =
UA_Client_Service_translateBrowsePathsToNodeIds(client, tbReq);
ck_assert_uint_eq(tbResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
ck_assert_uint_gt(tbResp.resultsSize, 0);
ck_assert_uint_eq(tbResp.results[0].statusCode, UA_STATUSCODE_GOOD);
/* Prevent cleanup of stack-allocated data */
tbReq.browsePaths = NULL;
tbReq.browsePathsSize = 0;
UA_TranslateBrowsePathsToNodeIdsRequest_clear(&tbReq);
UA_TranslateBrowsePathsToNodeIdsResponse_clear(&tbResp);
disconnectClient(client);
} END_TEST
START_TEST(hl_namespaceGetIndex) {
UA_Client *client = connectClient();
UA_UInt16 nsIdx = 0;
UA_String nsUri = UA_STRING("http://opcfoundation.org/UA/");
UA_StatusCode res = UA_Client_NamespaceGetIndex(client, &nsUri, &nsIdx);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_uint_eq(nsIdx, 0);
disconnectClient(client);
} END_TEST
/* === forEachChildNodeCall === */
static UA_StatusCode
childCallback(UA_NodeId childId, UA_Boolean isInverse,
UA_NodeId referenceTypeId, void *handle) {
UA_UInt32 *count = (UA_UInt32 *)handle;
(*count)++;
return UA_STATUSCODE_GOOD;
}
START_TEST(hl_forEachChildNode) {
UA_Client *client = connectClient();
UA_UInt32 count = 0;
UA_StatusCode res = UA_Client_forEachChildNodeCall(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), childCallback, &count);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_uint_gt(count, 0);
disconnectClient(client);
} END_TEST
/* === Read additional attributes === */
START_TEST(hl_readArrayDimensions) {
UA_Client *client = connectClient();
UA_UInt32 *dims = NULL;
size_t dimsSize = 0;
UA_StatusCode res = UA_Client_readArrayDimensionsAttribute(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME),
&dimsSize, &dims);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
if(dims)
UA_Array_delete(dims, dimsSize, &UA_TYPES[UA_TYPES_UINT32]);
disconnectClient(client);
} END_TEST
START_TEST(hl_readExecutable) {
UA_Client *client = connectClient();
UA_Boolean val;
UA_StatusCode res = UA_Client_readExecutableAttribute(client,
UA_NODEID_NUMERIC(1, 62000), &val);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert(val == true);
disconnectClient(client);
} END_TEST
START_TEST(hl_readUserExecutable) {
UA_Client *client = connectClient();
UA_Boolean val;
UA_StatusCode res = UA_Client_readUserExecutableAttribute(client,
UA_NODEID_NUMERIC(1, 62000), &val);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_readUserAccessLevel) {
UA_Client *client = connectClient();
UA_Byte val;
UA_StatusCode res = UA_Client_readUserAccessLevelAttribute(client,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME), &val);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
#ifdef UA_ENABLE_SUBSCRIPTIONS
/* === Subscription tests === */
static void dataChangeCallback(UA_Client *client, UA_UInt32 subId,
void *subContext, UA_UInt32 monId,
void *monContext, UA_DataValue *value) {
/* Callback for data change notification */
(void)client; (void)subId; (void)subContext;
(void)monId; (void)monContext; (void)value;
}
START_TEST(hl_subscription_create_delete) {
UA_Client *client = connectClient();
UA_CreateSubscriptionRequest subReq = UA_CreateSubscriptionRequest_default();
UA_CreateSubscriptionResponse subResp =
UA_Client_Subscriptions_create(client, subReq, NULL, NULL, NULL);
ck_assert_uint_eq(subResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
UA_UInt32 subId = subResp.subscriptionId;
/* Delete subscription */
UA_StatusCode res = UA_Client_Subscriptions_deleteSingle(client, subId);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
START_TEST(hl_subscription_modify) {
UA_Client *client = connectClient();
UA_CreateSubscriptionRequest subReq = UA_CreateSubscriptionRequest_default();
UA_CreateSubscriptionResponse subResp =
UA_Client_Subscriptions_create(client, subReq, NULL, NULL, NULL);
ck_assert_uint_eq(subResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
UA_UInt32 subId = subResp.subscriptionId;
/* Modify */
UA_ModifySubscriptionRequest modReq;
UA_ModifySubscriptionRequest_init(&modReq);
modReq.subscriptionId = subId;
modReq.requestedPublishingInterval = 500.0;
modReq.requestedMaxKeepAliveCount = 10;
modReq.requestedLifetimeCount = 100;
modReq.maxNotificationsPerPublish = 100;
UA_ModifySubscriptionResponse modResp =
UA_Client_Subscriptions_modify(client, modReq);
ck_assert_uint_eq(modResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
UA_Client_Subscriptions_deleteSingle(client, subId);
disconnectClient(client);
} END_TEST
START_TEST(hl_monitored_item_create) {
UA_Client *client = connectClient();
UA_CreateSubscriptionRequest subReq = UA_CreateSubscriptionRequest_default();
UA_CreateSubscriptionResponse subResp =
UA_Client_Subscriptions_create(client, subReq, NULL, NULL, NULL);
ck_assert_uint_eq(subResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
UA_UInt32 subId = subResp.subscriptionId;
/* Create a monitored item */
UA_MonitoredItemCreateRequest monReq =
UA_MonitoredItemCreateRequest_default(
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME));
UA_MonitoredItemCreateResult monResp =
UA_Client_MonitoredItems_createDataChange(client, subId,
UA_TIMESTAMPSTORETURN_BOTH, monReq,
NULL, dataChangeCallback, NULL);
ck_assert_uint_eq(monResp.statusCode, UA_STATUSCODE_GOOD);
/* Run a few iterations to get data */
UA_Client_run_iterate(client, 100);
UA_Client_run_iterate(client, 100);
UA_Client_Subscriptions_deleteSingle(client, subId);
disconnectClient(client);
} END_TEST
START_TEST(hl_subscription_setPublishingMode) {
UA_Client *client = connectClient();
UA_CreateSubscriptionRequest subReq = UA_CreateSubscriptionRequest_default();
UA_CreateSubscriptionResponse subResp =
UA_Client_Subscriptions_create(client, subReq, NULL, NULL, NULL);
ck_assert_uint_eq(subResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
UA_UInt32 subId = subResp.subscriptionId;
/* Disable publishing */
UA_SetPublishingModeRequest spmReq;
UA_SetPublishingModeRequest_init(&spmReq);
spmReq.publishingEnabled = false;
spmReq.subscriptionIds = &subId;
spmReq.subscriptionIdsSize = 1;
UA_SetPublishingModeResponse spmResp =
UA_Client_Subscriptions_setPublishingMode(client, spmReq);
ck_assert_uint_eq(spmResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
spmReq.subscriptionIds = NULL;
spmReq.subscriptionIdsSize = 0;
UA_SetPublishingModeResponse_clear(&spmResp);
/* Re-enable */
spmReq.publishingEnabled = true;
spmReq.subscriptionIds = &subId;
spmReq.subscriptionIdsSize = 1;
spmResp = UA_Client_Subscriptions_setPublishingMode(client, spmReq);
ck_assert_uint_eq(spmResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
spmReq.subscriptionIds = NULL;
spmReq.subscriptionIdsSize = 0;
UA_SetPublishingModeResponse_clear(&spmResp);
UA_Client_Subscriptions_deleteSingle(client, subId);
disconnectClient(client);
} END_TEST
#endif /* UA_ENABLE_SUBSCRIPTIONS */
/* === Generic read/write === */
START_TEST(hl_genericRead) {
UA_Client *client = connectClient();
UA_ReadValueId rvi;
UA_ReadValueId_init(&rvi);
rvi.nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
rvi.attributeId = UA_ATTRIBUTEID_VALUE;
UA_DataValue dv = UA_Client_read(client, &rvi);
ck_assert(dv.hasValue);
UA_DataValue_clear(&dv);
disconnectClient(client);
} END_TEST
START_TEST(hl_genericWrite) {
UA_Client *client = connectClient();
UA_WriteValue wv;
UA_WriteValue_init(&wv);
wv.nodeId = UA_NODEID_NUMERIC(1, 62001);
wv.attributeId = UA_ATTRIBUTEID_VALUE;
wv.value.hasValue = true;
UA_Int32 val = 555;
UA_Variant_setScalar(&wv.value.value, &val, &UA_TYPES[UA_TYPES_INT32]);
UA_StatusCode res = UA_Client_write(client, &wv);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
disconnectClient(client);
} END_TEST
/* === Client state and endpoints === */
START_TEST(hl_getEndpoints) {
UA_Client *client = UA_Client_newForUnitTest();
UA_EndpointDescription *endpoints = NULL;
size_t endpointsSize = 0;
UA_StatusCode res = UA_Client_getEndpoints(client,
"opc.tcp://localhost:4840", &endpointsSize, &endpoints);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_uint_gt(endpointsSize, 0);
UA_Array_delete(endpoints, endpointsSize,
&UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
UA_Client_delete(client);
} END_TEST
START_TEST(hl_findServers) {
UA_Client *client = UA_Client_newForUnitTest();
UA_ApplicationDescription *apps = NULL;
size_t appsSize = 0;
UA_StatusCode res = UA_Client_findServers(client,
"opc.tcp://localhost:4840", 0, NULL, 0, NULL, &appsSize, &apps);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_uint_gt(appsSize, 0);
UA_Array_delete(apps, appsSize,
&UA_TYPES[UA_TYPES_APPLICATIONDESCRIPTION]);
UA_Client_delete(client);
} END_TEST
START_TEST(hl_connectDisconnect) {
UA_Client *client = UA_Client_newForUnitTest();
UA_StatusCode res = UA_Client_connect(client, "opc.tcp://localhost:4840");
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
/* Check state */
UA_SecureChannelState scState;
UA_SessionState sessState;
UA_StatusCode connectStatus;
UA_Client_getState(client, &scState, &sessState, &connectStatus);
ck_assert_uint_eq(connectStatus, UA_STATUSCODE_GOOD);
/* Disconnect */
UA_Client_disconnect(client);
UA_Client_getState(client, &scState, &sessState, &connectStatus);
UA_Client_delete(client);
} END_TEST
START_TEST(hl_connectFailed) {
UA_Client *client = UA_Client_newForUnitTest();
UA_ClientConfig *cc = UA_Client_getConfig(client);
cc->timeout = 1000;
UA_StatusCode res = UA_Client_connect(client, "opc.tcp://localhost:54321");
ck_assert_uint_ne(res, UA_STATUSCODE_GOOD);
UA_Client_delete(client);
} END_TEST
static Suite *testSuite_clientHL2(void) {
TCase *tc_write = tcase_create("HL_Write2");
tcase_add_checked_fixture(tc_write, setup, teardown);
tcase_add_test(tc_write, hl_writeWriteMask);
tcase_add_test(tc_write, hl_writeAccessLevel);
tcase_add_test(tc_write, hl_writeRbacAttributes);
tcase_add_test(tc_write, hl_writeMinSampling);
tcase_add_test(tc_write, hl_writeHistorizing);
tcase_add_test(tc_write, hl_writeValueRank);
tcase_add_test(tc_write, hl_writeValueScalar);
tcase_add_test(tc_write, hl_writeValueEx);
tcase_add_test(tc_write, hl_genericRead);
tcase_add_test(tc_write, hl_genericWrite);
TCase *tc_nodes = tcase_create("HL_NodeTypes");
tcase_add_checked_fixture(tc_nodes, setup, teardown);
tcase_add_test(tc_nodes, hl_addVariableTypeNode);
tcase_add_test(tc_nodes, hl_addObjectTypeNode);
tcase_add_test(tc_nodes, hl_addReferenceTypeNode);
tcase_add_test(tc_nodes, hl_addDataTypeNode);
tcase_add_test(tc_nodes, hl_addViewNode);
tcase_add_test(tc_nodes, hl_deleteReference);
TCase *tc_browse = tcase_create("HL_Browse2");
tcase_add_checked_fixture(tc_browse, setup, teardown);
tcase_add_test(tc_browse, hl_browseNext);
tcase_add_test(tc_browse, hl_translateBrowsePath);
tcase_add_test(tc_browse, hl_namespaceGetIndex);
tcase_add_test(tc_browse, hl_forEachChildNode);
tcase_add_test(tc_browse, hl_callMethod);
TCase *tc_read = tcase_create("HL_Read2");
tcase_add_checked_fixture(tc_read, setup, teardown);
tcase_add_test(tc_read, hl_readArrayDimensions);
tcase_add_test(tc_read, hl_readExecutable);
tcase_add_test(tc_read, hl_readUserExecutable);
tcase_add_test(tc_read, hl_readUserAccessLevel);
#ifdef UA_ENABLE_SUBSCRIPTIONS
TCase *tc_sub = tcase_create("HL_Subscriptions");
tcase_add_checked_fixture(tc_sub, setup, teardown);
tcase_add_test(tc_sub, hl_subscription_create_delete);
tcase_add_test(tc_sub, hl_subscription_modify);
tcase_add_test(tc_sub, hl_monitored_item_create);
tcase_add_test(tc_sub, hl_subscription_setPublishingMode);
#endif
TCase *tc_conn = tcase_create("HL_Connect");
tcase_add_checked_fixture(tc_conn, setup, teardown);
tcase_add_test(tc_conn, hl_getEndpoints);
tcase_add_test(tc_conn, hl_findServers);
tcase_add_test(tc_conn, hl_connectDisconnect);
tcase_add_test(tc_conn, hl_connectFailed);
Suite *s = suite_create("Client HighLevel API Extended");
suite_add_tcase(s, tc_write);
suite_add_tcase(s, tc_nodes);
suite_add_tcase(s, tc_browse);
suite_add_tcase(s, tc_read);
#ifdef UA_ENABLE_SUBSCRIPTIONS
suite_add_tcase(s, tc_sub);
#endif
suite_add_tcase(s, tc_conn);
return s;
}
int main(void) {
int number_failed = 0;
Suite *s = testSuite_clientHL2();
SRunner *sr = srunner_create(s);
srunner_set_fork_status(sr, CK_NOFORK);
srunner_run_all(sr, CK_NORMAL);
number_failed += srunner_ntests_failed(sr);
srunner_free(sr);
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}