mirror of
https://github.com/open62541/open62541.git
synced 2026-10-24 01:25:25 +08:00
287c5ad69b
The BrowseName is tracked in binary trees in other nodes for fast lookup. We would have to reinsert the node to all references lists of other nodes pointing here.
1081 lines
44 KiB
C
1081 lines
44 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/. */
|
|
|
|
#include <open62541/client.h>
|
|
#include <open62541/client_config_default.h>
|
|
#include <open62541/client_highlevel.h>
|
|
#include <open62541/server.h>
|
|
#include <open62541/server_config_default.h>
|
|
|
|
#include <check.h>
|
|
|
|
#include "thread_wrapper.h"
|
|
|
|
UA_Server *server;
|
|
UA_Boolean running;
|
|
UA_ServerNetworkLayer nl;
|
|
THREAD_HANDLE server_thread;
|
|
|
|
UA_Client *client;
|
|
|
|
#define CUSTOM_NS "http://open62541.org/ns/test"
|
|
#define CUSTOM_NS_UPPER "http://open62541.org/ns/Test"
|
|
|
|
THREAD_CALLBACK(serverloop) {
|
|
while (running)
|
|
UA_Server_run_iterate(server, true);
|
|
return 0;
|
|
}
|
|
|
|
static void setup(void) {
|
|
running = true;
|
|
server = UA_Server_new();
|
|
UA_ServerConfig_setDefault(UA_Server_getConfig(server));
|
|
|
|
ck_assert_uint_eq(2, UA_Server_addNamespace(server, CUSTOM_NS));
|
|
|
|
UA_Server_run_startup(server);
|
|
THREAD_CREATE(server_thread, serverloop);
|
|
|
|
client = UA_Client_new();
|
|
UA_ClientConfig_setDefault(UA_Client_getConfig(client));
|
|
UA_StatusCode retval = UA_Client_connect(client, "opc.tcp://localhost:4840");
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
static void teardown(void) {
|
|
UA_Client_disconnect(client);
|
|
UA_Client_delete(client);
|
|
running = false;
|
|
THREAD_JOIN(server_thread);
|
|
UA_Server_run_shutdown(server);
|
|
UA_Server_delete(server);
|
|
}
|
|
|
|
START_TEST(Misc_State) {
|
|
UA_ClientState state = UA_Client_getState(client);
|
|
ck_assert_uint_eq(state, UA_CLIENTSTATE_SESSION);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Misc_NamespaceGetIndex) {
|
|
UA_UInt16 idx;
|
|
UA_String ns = UA_STRING(CUSTOM_NS);
|
|
UA_StatusCode retval = UA_Client_NamespaceGetIndex(client, &ns, &idx);
|
|
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(idx, 2);
|
|
|
|
// namespace uri is case sensitive
|
|
ns = UA_STRING(CUSTOM_NS_UPPER);
|
|
retval = UA_Client_NamespaceGetIndex(client, &ns, &idx);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADNOTFOUND);
|
|
} END_TEST
|
|
|
|
UA_NodeId newReferenceTypeId;
|
|
UA_NodeId newObjectTypeId;
|
|
UA_NodeId newDataTypeId;
|
|
UA_NodeId newVariableTypeId;
|
|
UA_NodeId newObjectId;
|
|
UA_NodeId newVariableId;
|
|
UA_NodeId newMethodId;
|
|
UA_NodeId newViewId;
|
|
|
|
#ifdef UA_ENABLE_NODEMANAGEMENT
|
|
|
|
START_TEST(Node_Add) {
|
|
UA_StatusCode retval;
|
|
|
|
// Create custom reference type 'HasSubSubType' as child of HasSubtype
|
|
{
|
|
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Some HasSubSubType");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "HasSubSubType");
|
|
retval = UA_Client_addReferenceTypeNode(client, UA_NODEID_NULL,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
|
UA_QUALIFIEDNAME(1, "HasSubSubType"), attr,
|
|
&newReferenceTypeId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// Create TestObjectType SubType within BaseObjectType
|
|
{
|
|
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Some TestObjectType");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "TestObjectType");
|
|
retval = UA_Client_addObjectTypeNode(client, UA_NODEID_NULL,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
|
UA_QUALIFIEDNAME(1, "TestObjectType"), attr, &newObjectTypeId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
/* Minimal nodeset does not contain UA_NS0ID_INTEGER node */
|
|
#ifdef UA_GENERATED_NAMESPACE_ZERO
|
|
// Create Int128 DataType within Integer Datatype
|
|
{
|
|
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Some Int128");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Int128");
|
|
retval = UA_Client_addDataTypeNode(client, UA_NODEID_NULL,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_INTEGER),
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
|
UA_QUALIFIEDNAME(1, "Int128"), attr, &newDataTypeId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
#endif
|
|
|
|
// Create PointType VariableType within BaseDataVariableType
|
|
{
|
|
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
|
|
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
|
|
attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
|
|
UA_UInt32 arrayDims[1] = {2};
|
|
attr.arrayDimensions = arrayDims;
|
|
attr.arrayDimensionsSize = 1;
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "PointType");
|
|
|
|
/* a matching default value is required */
|
|
UA_Double zero[2] = {0.0, 0.0};
|
|
UA_Variant_setArray(&attr.value, zero, 2, &UA_TYPES[UA_TYPES_INT32]);
|
|
retval = UA_Client_addVariableTypeNode(client, UA_NODEID_NULL,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEVARIABLETYPE),
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
|
UA_QUALIFIEDNAME(1, "PointType"), attr, &newVariableTypeId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// create Coordinates Object within ObjectsFolder
|
|
{
|
|
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Some Coordinates");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Coordinates");
|
|
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, "Coordinates"),
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_FOLDERTYPE), attr, &newObjectId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// create Variable 'Top' within Coordinates Object
|
|
{
|
|
UA_VariableAttributes attr = UA_VariableAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Top Coordinate");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Top");
|
|
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;
|
|
attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
|
|
UA_UInt32 arrayDims[1] = {2};
|
|
attr.arrayDimensions = arrayDims;
|
|
attr.arrayDimensionsSize = 1;
|
|
retval = UA_Client_addVariableNode(client, UA_NODEID_NULL,
|
|
newObjectId,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASPROPERTY),
|
|
UA_QUALIFIEDNAME(1, "Top"),
|
|
newVariableTypeId, attr, &newVariableId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// create Method 'Dummy' within Coordinates Object.
|
|
{
|
|
UA_MethodAttributes attr = UA_MethodAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Dummy method");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Dummy");
|
|
attr.executable = true;
|
|
attr.userExecutable = true;
|
|
retval = UA_Client_addMethodNode(client, UA_NODEID_NULL,
|
|
newObjectId,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
|
|
UA_QUALIFIEDNAME(1, "Dummy"),
|
|
attr, &newMethodId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// create View 'AllTopCoordinates' whithin Views Folder
|
|
{
|
|
UA_ViewAttributes attr = UA_ViewAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "List of all top coordinates");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "AllTopCoordinates");
|
|
retval = UA_Client_addViewNode(client, UA_NODEID_NULL,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
|
UA_QUALIFIEDNAME(1, "AllTopCoordinates"),
|
|
attr, &newViewId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
UA_ExpandedNodeId target = UA_EXPANDEDNODEID_NULL;
|
|
target.nodeId = newObjectId;
|
|
|
|
// Add 'Top' to view
|
|
retval = UA_Client_addReference(client, newViewId, UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
|
UA_TRUE, UA_STRING_NULL, target, UA_NODECLASS_VARIABLE);
|
|
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
// Delete 'Top' from view
|
|
retval = UA_Client_deleteReference(client, newViewId,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
|
true, target, true);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
// Delete 'AllTopCoordinates' view
|
|
retval = UA_Client_deleteNode(client, newViewId, UA_TRUE);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
END_TEST
|
|
|
|
unsigned int iteratedNodeCount = 0;
|
|
UA_NodeId iteratedNodes[4];
|
|
|
|
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 >= 4)
|
|
return UA_STATUSCODE_BADINDEXRANGEINVALID;
|
|
|
|
UA_NodeId_copy(&childId, &iteratedNodes[iteratedNodeCount]);
|
|
iteratedNodeCount++;
|
|
return UA_STATUSCODE_GOOD;
|
|
}
|
|
|
|
#endif
|
|
|
|
START_TEST(Node_Browse) {
|
|
// Browse node in server folder
|
|
UA_BrowseRequest bReq;
|
|
UA_BrowseRequest_init(&bReq);
|
|
// normally is set to 0, to get all the nodes, but we want to test browse next
|
|
bReq.requestedMaxReferencesPerNode = 1;
|
|
bReq.nodesToBrowse = UA_BrowseDescription_new();
|
|
bReq.nodesToBrowseSize = 1;
|
|
bReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
|
|
bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL;
|
|
|
|
UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
|
|
ck_assert_uint_eq(bResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(bResp.resultsSize, 1);
|
|
ck_assert_uint_eq(bResp.results[0].statusCode, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(bResp.results[0].referencesSize, 1);
|
|
|
|
/* References might have a different order in generated nodesets */
|
|
/* UA_ReferenceDescription *ref = &(bResp.results[0].references[0]); */
|
|
/* ck_assert_uint_eq(ref->nodeId.nodeId.identifier.numeric, UA_NS0ID_SERVERTYPE); */
|
|
|
|
// browse next
|
|
UA_BrowseNextRequest bNextReq;
|
|
UA_BrowseNextRequest_init(&bNextReq);
|
|
// normally is set to 0, to get all the nodes, but we want to test browse next
|
|
bNextReq.releaseContinuationPoints = UA_FALSE;
|
|
bNextReq.continuationPoints = &bResp.results[0].continuationPoint;
|
|
bNextReq.continuationPointsSize = 1;
|
|
|
|
UA_BrowseNextResponse bNextResp = UA_Client_Service_browseNext(client, bNextReq);
|
|
|
|
ck_assert_uint_eq(bNextResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(bNextResp.resultsSize, 1);
|
|
ck_assert_uint_eq(bNextResp.results[0].statusCode, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(bNextResp.results[0].referencesSize, 1);
|
|
|
|
/* ref = &(bNextResp.results[0].references[0]); */
|
|
/* ck_assert_uint_eq(ref->nodeId.nodeId.identifier.numeric, UA_NS0ID_SERVER_NAMESPACEARRAY); */
|
|
|
|
UA_BrowseNextResponse_deleteMembers(&bNextResp);
|
|
|
|
bNextResp = UA_Client_Service_browseNext(client, bNextReq);
|
|
ck_assert_uint_eq(bNextResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(bNextResp.resultsSize, 1);
|
|
ck_assert_uint_eq(bNextResp.results[0].statusCode, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(bNextResp.results[0].referencesSize, 1);
|
|
|
|
/* ref = &(bNextResp.results[0].references[0]); */
|
|
/* ck_assert_uint_eq(ref->nodeId.nodeId.identifier.numeric, UA_NS0ID_SERVER_SERVERARRAY); */
|
|
|
|
UA_BrowseNextResponse_deleteMembers(&bNextResp);
|
|
|
|
// release continuation point. Result is then empty
|
|
bNextReq.releaseContinuationPoints = UA_TRUE;
|
|
bNextResp = UA_Client_Service_browseNext(client, bNextReq);
|
|
UA_BrowseNextResponse_deleteMembers(&bNextResp);
|
|
ck_assert_uint_eq(bNextResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(bNextResp.resultsSize, 0);
|
|
|
|
UA_BrowseRequest_deleteMembers(&bReq);
|
|
UA_BrowseResponse_deleteMembers(&bResp);
|
|
// already deleted by browse request
|
|
bNextReq.continuationPoints = NULL;
|
|
bNextReq.continuationPointsSize = 0;
|
|
UA_BrowseNextRequest_deleteMembers(&bNextReq);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_Register) {
|
|
UA_RegisterNodesRequest req;
|
|
UA_RegisterNodesRequest_init(&req);
|
|
|
|
req.nodesToRegister = UA_NodeId_new();
|
|
req.nodesToRegister[0] = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
|
|
req.nodesToRegisterSize = 1;
|
|
|
|
UA_RegisterNodesResponse res = UA_Client_Service_registerNodes(client, req);
|
|
|
|
ck_assert_uint_eq(res.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(res.registeredNodeIdsSize, 1);
|
|
|
|
UA_UnregisterNodesRequest reqUn;
|
|
UA_UnregisterNodesRequest_init(&reqUn);
|
|
|
|
reqUn.nodesToUnregister = UA_NodeId_new();
|
|
reqUn.nodesToUnregister[0] = res.registeredNodeIds[0];
|
|
reqUn.nodesToUnregisterSize = 1;
|
|
|
|
UA_UnregisterNodesResponse resUn = UA_Client_Service_unregisterNodes(client, reqUn);
|
|
ck_assert_uint_eq(resUn.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
|
|
|
|
UA_UnregisterNodesRequest_deleteMembers(&reqUn);
|
|
UA_UnregisterNodesResponse_deleteMembers(&resUn);
|
|
UA_RegisterNodesRequest_deleteMembers(&req);
|
|
UA_RegisterNodesResponse_deleteMembers(&res);
|
|
}
|
|
END_TEST
|
|
|
|
|
|
|
|
// NodeIds for ReadWrite testing
|
|
UA_NodeId nodeReadWriteUnitTest;
|
|
UA_NodeId nodeReadWriteArray;
|
|
UA_NodeId nodeReadWriteInt;
|
|
UA_NodeId nodeReadWriteGeneric;
|
|
UA_NodeId nodeReadWriteTestObjectType;
|
|
UA_NodeId nodeReadWriteTestHasSubSubType;
|
|
UA_NodeId nodeReadWriteView;
|
|
UA_NodeId nodeReadWriteMethod;
|
|
|
|
#ifdef UA_ENABLE_NODEMANAGEMENT
|
|
|
|
START_TEST(Node_AddReadWriteNodes) {
|
|
UA_StatusCode retval;
|
|
// Create a folder with two variables for testing
|
|
|
|
// create Coordinates Object within ObjectsFolder
|
|
{
|
|
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
|
|
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, &nodeReadWriteUnitTest);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// create Variable 'Top' within UnitTest Object
|
|
{
|
|
UA_VariableAttributes attr = UA_VariableAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Array");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Array");
|
|
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
|
|
attr.writeMask = UA_WRITEMASK_ARRRAYDIMENSIONS;
|
|
|
|
UA_Int32 values[2];
|
|
values[0] = 10;
|
|
values[1] = 20;
|
|
|
|
UA_Variant_setArray(&attr.value, values, 2, &UA_TYPES[UA_TYPES_INT32]);
|
|
attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
|
|
attr.valueRank = UA_VALUERANK_ONE_DIMENSION;
|
|
UA_UInt32 arrayDims[1] = {2};
|
|
attr.arrayDimensions = arrayDims;
|
|
attr.arrayDimensionsSize = 1;
|
|
|
|
retval = UA_Client_addVariableNode(client, UA_NODEID_NULL,
|
|
nodeReadWriteUnitTest,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
|
UA_QUALIFIEDNAME(1, "Array"),
|
|
UA_NODEID_NULL, attr, &nodeReadWriteArray);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// create Variable 'Int' within UnitTest Object
|
|
{
|
|
UA_VariableAttributes attr = UA_VariableAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Int");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Int");
|
|
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
|
|
attr.writeMask = 0xFFFFFFFF;
|
|
|
|
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,
|
|
nodeReadWriteUnitTest,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
|
UA_QUALIFIEDNAME(1, "Int"),
|
|
UA_NODEID_NULL, attr, &nodeReadWriteInt);
|
|
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// create Variable 'Generic' within UnitTest Object
|
|
{
|
|
UA_VariableAttributes attr = UA_VariableAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Generic");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Generic");
|
|
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
|
|
attr.writeMask = 0xFFFFFFFF;
|
|
|
|
// generic datatype
|
|
attr.dataType = UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATATYPE);
|
|
|
|
retval = UA_Client_addVariableNode(client, UA_NODEID_NULL,
|
|
nodeReadWriteUnitTest,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
|
UA_QUALIFIEDNAME(1, "Generic"),
|
|
UA_NODEID_NULL, attr, &nodeReadWriteGeneric);
|
|
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// create Method 'Dummy' within Coordinates Object.
|
|
{
|
|
UA_MethodAttributes attr = UA_MethodAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Dummy method");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "Dummy");
|
|
attr.executable = true;
|
|
attr.userExecutable = true;
|
|
attr.writeMask = 0xFFFFFFFF;
|
|
retval = UA_Client_addMethodNode(client, UA_NODEID_NULL,
|
|
nodeReadWriteUnitTest,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASORDEREDCOMPONENT),
|
|
UA_QUALIFIEDNAME(1, "Dummy"),
|
|
attr, &nodeReadWriteMethod);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// Create TestObjectType SubType within BaseObjectType
|
|
{
|
|
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Some TestObjectType");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "TestObjectType");
|
|
attr.writeMask = 0xFFFFFFFF;
|
|
retval = UA_Client_addObjectTypeNode(client, UA_NODEID_NULL,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
|
UA_QUALIFIEDNAME(1, "TestObjectType"), attr, &nodeReadWriteTestObjectType);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// Create custom reference type 'HasSubSubType' as child of HasSubtype
|
|
{
|
|
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "Some HasSubSubType");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "HasSubSubType");
|
|
attr.inverseName = UA_LOCALIZEDTEXT("en-US", "HasParentParentType");
|
|
attr.writeMask = 0xFFFFFFFF;
|
|
retval = UA_Client_addReferenceTypeNode(client, UA_NODEID_NULL,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
|
UA_QUALIFIEDNAME(1, "HasSubSubType"), attr,
|
|
&nodeReadWriteTestHasSubSubType);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
|
|
// create View 'AllTopCoordinates' whithin Views Folder
|
|
{
|
|
UA_ViewAttributes attr = UA_ViewAttributes_default;
|
|
attr.description = UA_LOCALIZEDTEXT("en-US", "List of all top coordinates");
|
|
attr.displayName = UA_LOCALIZEDTEXT("en-US", "AllTopCoordinates");
|
|
attr.writeMask = 0xFFFFFFFF;
|
|
retval = UA_Client_addViewNode(client, UA_NODEID_NULL,
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
|
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
|
UA_QUALIFIEDNAME(1, "AllTopCoordinates"),
|
|
attr, &nodeReadWriteView);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
|
|
// iterate over children
|
|
retval = UA_Client_forEachChildNodeCall(client, nodeReadWriteUnitTest, nodeIter, NULL);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert(UA_NodeId_equal(&nodeReadWriteArray, &iteratedNodes[0]));
|
|
ck_assert(UA_NodeId_equal(&nodeReadWriteInt, &iteratedNodes[1]));
|
|
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_Id) {
|
|
UA_NodeId newNodeId;
|
|
|
|
// read to check if node id was changed
|
|
UA_StatusCode retval = UA_Client_readNodeIdAttribute(client, nodeReadWriteInt, &newNodeId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert(UA_NodeId_equal(&newNodeId, &nodeReadWriteInt));
|
|
|
|
newNodeId.identifier.numeric = 900;
|
|
retval = UA_Client_writeNodeIdAttribute(client, nodeReadWriteInt, &newNodeId);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
|
|
|
|
}
|
|
END_TEST
|
|
|
|
static void checkNodeClass(UA_Client *clientNc, const UA_NodeId nodeId, const UA_NodeClass expectedClass) {
|
|
UA_NodeClass nodeClass = UA_NODECLASS_UNSPECIFIED;
|
|
UA_StatusCode retval = UA_Client_readNodeClassAttribute(clientNc, nodeId, &nodeClass);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(nodeClass, expectedClass);
|
|
}
|
|
|
|
START_TEST(Node_ReadWrite_Class) {
|
|
checkNodeClass(client, nodeReadWriteInt, UA_NODECLASS_VARIABLE);
|
|
checkNodeClass(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), UA_NODECLASS_OBJECT);
|
|
|
|
/* Minimal nodeset does not contain UA_NS0ID_SERVER_GETMONITOREDITEMS node */
|
|
#if defined(UA_ENABLE_METHODCALLS) && defined(UA_GENERATED_NAMESPACE_ZERO)
|
|
checkNodeClass(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_GETMONITOREDITEMS), UA_NODECLASS_METHOD);
|
|
#endif
|
|
|
|
UA_NodeClass newClass = UA_NODECLASS_METHOD;
|
|
UA_StatusCode retval = UA_Client_writeNodeClassAttribute(client, nodeReadWriteInt, &newClass);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_BrowseName) {
|
|
|
|
UA_QualifiedName browseName;
|
|
UA_StatusCode retval = UA_Client_readBrowseNameAttribute(client, nodeReadWriteInt, &browseName);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_QualifiedName orig = UA_QUALIFIEDNAME(1, "Int");
|
|
ck_assert_int_eq(browseName.namespaceIndex, orig.namespaceIndex);
|
|
ck_assert(UA_String_equal(&browseName.name, &orig.name));
|
|
|
|
UA_QualifiedName_deleteMembers(&browseName);
|
|
|
|
browseName = UA_QUALIFIEDNAME(1,"Int-Changed");
|
|
|
|
retval = UA_Client_writeBrowseNameAttribute(client, UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &browseName);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
|
|
|
|
retval = UA_Client_writeBrowseNameAttribute(client, nodeReadWriteInt, &browseName);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_DisplayName) {
|
|
|
|
UA_LocalizedText displayName;
|
|
UA_StatusCode retval = UA_Client_readDisplayNameAttribute(client, nodeReadWriteInt, &displayName);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_LocalizedText orig = UA_LOCALIZEDTEXT("en-US", "Int");
|
|
ck_assert(UA_String_equal(&displayName.locale, &orig.locale));
|
|
ck_assert(UA_String_equal(&displayName.text, &orig.text));
|
|
UA_LocalizedText_deleteMembers(&displayName);
|
|
|
|
UA_LocalizedText newLocale = UA_LOCALIZEDTEXT("en-US", "Int-Changed");
|
|
|
|
retval = UA_Client_writeDisplayNameAttribute(client, nodeReadWriteInt, &newLocale);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_LocalizedText displayNameChangedRead;
|
|
retval = UA_Client_readDisplayNameAttribute(client, nodeReadWriteInt, &displayNameChangedRead);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert(UA_String_equal(&newLocale.locale, &displayNameChangedRead.locale));
|
|
ck_assert(UA_String_equal(&newLocale.text, &displayNameChangedRead.text));
|
|
UA_LocalizedText_deleteMembers(&displayNameChangedRead);
|
|
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_Description) {
|
|
|
|
UA_LocalizedText description;
|
|
UA_StatusCode retval = UA_Client_readDescriptionAttribute(client, nodeReadWriteInt, &description);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_LocalizedText orig = UA_LOCALIZEDTEXT("en-US", "Int");
|
|
ck_assert(UA_String_equal(&description.locale, &orig.locale));
|
|
ck_assert(UA_String_equal(&description.text, &orig.text));
|
|
UA_LocalizedText_deleteMembers(&description);
|
|
|
|
UA_LocalizedText newLocale = UA_LOCALIZEDTEXT("en-US", "Int-Changed");
|
|
|
|
retval = UA_Client_writeDescriptionAttribute(client, nodeReadWriteInt, &newLocale);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_LocalizedText descriptionChangedRead;
|
|
retval = UA_Client_readDescriptionAttribute(client, nodeReadWriteInt, &descriptionChangedRead);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert(UA_String_equal(&newLocale.locale, &descriptionChangedRead.locale));
|
|
ck_assert(UA_String_equal(&newLocale.text, &descriptionChangedRead.text));
|
|
UA_LocalizedText_deleteMembers(&descriptionChangedRead);
|
|
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_WriteMask) {
|
|
|
|
UA_UInt32 writeMask;
|
|
UA_StatusCode retval = UA_Client_readWriteMaskAttribute(client, nodeReadWriteInt, &writeMask);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert_int_eq(writeMask, 0xFFFFFFFF);
|
|
|
|
// Disable a random write mask bit
|
|
UA_UInt32 newMask = 0xFFFFFFFF & ~UA_WRITEMASK_BROWSENAME;
|
|
|
|
retval = UA_Client_writeWriteMaskAttribute(client, nodeReadWriteInt, &newMask);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_UInt32 writeMaskChangedRead;
|
|
retval = UA_Client_readWriteMaskAttribute(client, nodeReadWriteInt, &writeMaskChangedRead);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(writeMaskChangedRead, newMask);
|
|
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_UserWriteMask) {
|
|
|
|
UA_UInt32 userWriteMask;
|
|
UA_StatusCode retval = UA_Client_readUserWriteMaskAttribute(client, nodeReadWriteInt, &userWriteMask);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(userWriteMask, 0xFFFFFFFF & ~UA_WRITEMASK_BROWSENAME);
|
|
|
|
// Disable a random write mask bit
|
|
UA_UInt32 newMask = 0xFFFFFFFF & ~UA_WRITEMASK_DISPLAYNAME;
|
|
|
|
retval = UA_Client_writeUserWriteMaskAttribute(client, nodeReadWriteInt, &newMask);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_IsAbstract) {
|
|
|
|
UA_Boolean isAbstract;
|
|
UA_StatusCode retval = UA_Client_readIsAbstractAttribute(client, nodeReadWriteInt, &isAbstract);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADATTRIBUTEIDINVALID);
|
|
retval = UA_Client_readIsAbstractAttribute(client, nodeReadWriteTestObjectType, &isAbstract);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(isAbstract, UA_FALSE);
|
|
|
|
UA_Boolean newIsAbstract = UA_TRUE;
|
|
|
|
retval = UA_Client_writeIsAbstractAttribute(client, nodeReadWriteTestObjectType, &newIsAbstract);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readIsAbstractAttribute(client, nodeReadWriteTestObjectType, &isAbstract);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(isAbstract, newIsAbstract);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_Symmetric) {
|
|
|
|
UA_Boolean symmetric;
|
|
UA_StatusCode retval = UA_Client_readSymmetricAttribute(client, nodeReadWriteInt, &symmetric);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADATTRIBUTEIDINVALID);
|
|
retval = UA_Client_readSymmetricAttribute(client, nodeReadWriteTestHasSubSubType, &symmetric);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(symmetric, UA_FALSE);
|
|
|
|
UA_Boolean newSymmetric = UA_TRUE;
|
|
|
|
retval = UA_Client_writeSymmetricAttribute(client, nodeReadWriteTestHasSubSubType, &newSymmetric);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readSymmetricAttribute(client, nodeReadWriteTestHasSubSubType, &symmetric);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(symmetric, newSymmetric);
|
|
}
|
|
END_TEST
|
|
|
|
|
|
START_TEST(Node_ReadWrite_InverseName) {
|
|
|
|
UA_LocalizedText inverseName;
|
|
UA_StatusCode retval = UA_Client_readInverseNameAttribute(client, nodeReadWriteTestHasSubSubType, &inverseName);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_LocalizedText orig = UA_LOCALIZEDTEXT("en-US", "HasParentParentType");
|
|
ck_assert(UA_String_equal(&inverseName.locale, &orig.locale));
|
|
ck_assert(UA_String_equal(&inverseName.text, &orig.text));
|
|
UA_LocalizedText_deleteMembers(&inverseName);
|
|
|
|
UA_LocalizedText newLocale = UA_LOCALIZEDTEXT("en-US", "HasParentParentType-Changed");
|
|
|
|
retval = UA_Client_writeInverseNameAttribute(client, nodeReadWriteTestHasSubSubType, &newLocale);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_LocalizedText inverseNameChangedRead;
|
|
retval = UA_Client_readInverseNameAttribute(client, nodeReadWriteTestHasSubSubType, &inverseNameChangedRead);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert(UA_String_equal(&newLocale.locale, &inverseNameChangedRead.locale));
|
|
ck_assert(UA_String_equal(&newLocale.text, &inverseNameChangedRead.text));
|
|
UA_LocalizedText_deleteMembers(&inverseNameChangedRead);
|
|
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_ContainsNoLoops) {
|
|
|
|
UA_Boolean containsNoLoops;
|
|
UA_StatusCode retval = UA_Client_readContainsNoLoopsAttribute(client, nodeReadWriteTestHasSubSubType, &containsNoLoops);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADATTRIBUTEIDINVALID);
|
|
retval = UA_Client_readContainsNoLoopsAttribute(client, nodeReadWriteView, &containsNoLoops);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(containsNoLoops, UA_FALSE);
|
|
|
|
UA_Boolean newContainsNoLoops = UA_TRUE;
|
|
|
|
retval = UA_Client_writeContainsNoLoopsAttribute(client, nodeReadWriteView, &newContainsNoLoops);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readContainsNoLoopsAttribute(client, nodeReadWriteView, &containsNoLoops);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(containsNoLoops, newContainsNoLoops);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_EventNotifier) {
|
|
|
|
UA_Byte eventNotifier = 0;
|
|
UA_StatusCode retval = UA_Client_readEventNotifierAttribute(client, nodeReadWriteTestHasSubSubType, &eventNotifier);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADATTRIBUTEIDINVALID);
|
|
retval = UA_Client_readEventNotifierAttribute(client, nodeReadWriteView, &eventNotifier);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(eventNotifier, 0);
|
|
|
|
UA_Byte newEventNotifier = 1;
|
|
|
|
retval = UA_Client_writeEventNotifierAttribute(client, nodeReadWriteView, &newEventNotifier);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readEventNotifierAttribute(client, nodeReadWriteView, &eventNotifier);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(eventNotifier, newEventNotifier);
|
|
}
|
|
END_TEST
|
|
|
|
|
|
START_TEST(Node_ReadWrite_Value) {
|
|
|
|
UA_Int32 value = 0;
|
|
UA_Variant *val = UA_Variant_new();
|
|
UA_StatusCode retval = UA_Client_readValueAttribute(client, nodeReadWriteInt, 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, nodeReadWriteInt, 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, nodeReadWriteInt, 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);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_DataType) {
|
|
UA_NodeId dataType;
|
|
|
|
// read to check if node id was changed
|
|
UA_StatusCode retval = UA_Client_readDataTypeAttribute(client, nodeReadWriteInt, &dataType);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert(UA_NodeId_equal(&dataType, &UA_TYPES[UA_TYPES_INT32].typeId));
|
|
|
|
UA_NodeId newDataType = UA_TYPES[UA_TYPES_VARIANT].typeId;
|
|
retval = UA_Client_writeDataTypeAttribute(client, nodeReadWriteGeneric, &newDataType);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readDataTypeAttribute(client, nodeReadWriteGeneric, &dataType);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert(UA_NodeId_equal(&dataType, &newDataType));
|
|
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_ValueRank) {
|
|
|
|
UA_Int32 valueRank = UA_VALUERANK_ONE_OR_MORE_DIMENSIONS;
|
|
UA_StatusCode retval = UA_Client_readValueRankAttribute(client, nodeReadWriteGeneric, &valueRank);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(valueRank, UA_VALUERANK_ANY);
|
|
|
|
// set the value to a scalar
|
|
UA_Double val = 0.0;
|
|
UA_Variant value;
|
|
UA_Variant_setScalar(&value, &val, &UA_TYPES[UA_TYPES_DOUBLE]);
|
|
retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
// we want an array
|
|
UA_Int32 newValueRank = UA_VALUERANK_ONE_DIMENSION;
|
|
|
|
// shall fail when the value is not compatible
|
|
retval = UA_Client_writeValueRankAttribute(client, nodeReadWriteGeneric, &newValueRank);
|
|
ck_assert(retval != UA_STATUSCODE_GOOD);
|
|
|
|
// set the value to an array
|
|
UA_Double vec[3] = {0.0, 0.0, 0.0};
|
|
UA_Variant_setArray(&value, vec, 3, &UA_TYPES[UA_TYPES_DOUBLE]);
|
|
retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
// try again
|
|
retval = UA_Client_writeValueRankAttribute(client, nodeReadWriteGeneric, &newValueRank);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readValueRankAttribute(client, nodeReadWriteGeneric, &valueRank);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(valueRank, newValueRank);
|
|
|
|
|
|
// set the value to no array
|
|
UA_Variant_init(&value);
|
|
retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
}
|
|
END_TEST
|
|
|
|
|
|
START_TEST(Node_ReadWrite_ArrayDimensions) {
|
|
UA_UInt32 *arrayDimsRead;
|
|
size_t arrayDimsReadSize;
|
|
UA_StatusCode retval = UA_Client_readArrayDimensionsAttribute(client, nodeReadWriteGeneric,
|
|
&arrayDimsReadSize, &arrayDimsRead);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(arrayDimsReadSize, 0);
|
|
|
|
// Set a vector of size 1 as the value
|
|
UA_Double vec2[2] = {0.0, 0.0};
|
|
UA_Variant value;
|
|
UA_Variant_setArray(&value, vec2, 2, &UA_TYPES[UA_TYPES_DOUBLE]);
|
|
retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
// writing the array dimensions shall fail at first
|
|
// because the current value is not conformant
|
|
UA_UInt32 arrayDimsNew[] = {1};
|
|
retval = UA_Client_writeArrayDimensionsAttribute(client, nodeReadWriteGeneric, 1, arrayDimsNew);
|
|
ck_assert(retval != UA_STATUSCODE_GOOD);
|
|
|
|
// Set a vector of size 1 as the value
|
|
UA_Double vec1[1] = {0.0};
|
|
UA_Variant_setArray(&value, vec1, 1, &UA_TYPES[UA_TYPES_DOUBLE]);
|
|
retval = UA_Client_writeValueAttribute(client, nodeReadWriteGeneric, &value);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
// Now we can set matching array-dimensions
|
|
retval = UA_Client_writeArrayDimensionsAttribute(client, nodeReadWriteGeneric, 1, arrayDimsNew);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readArrayDimensionsAttribute(client, nodeReadWriteGeneric,
|
|
&arrayDimsReadSize, &arrayDimsRead);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(arrayDimsReadSize, 1);
|
|
ck_assert_int_eq(arrayDimsRead[0], 1);
|
|
UA_Array_delete(arrayDimsRead, arrayDimsReadSize, &UA_TYPES[UA_TYPES_UINT32]);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_AccessLevel) {
|
|
|
|
UA_Byte accessLevel;
|
|
UA_StatusCode retval = UA_Client_readAccessLevelAttribute(client, nodeReadWriteInt, &accessLevel);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert_int_eq(accessLevel, UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE);
|
|
|
|
UA_Byte newMask = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD;
|
|
|
|
retval = UA_Client_writeAccessLevelAttribute(client, nodeReadWriteInt, &newMask);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
UA_Byte accessLevelChangedRead;
|
|
retval = UA_Client_readAccessLevelAttribute(client, nodeReadWriteInt, &accessLevelChangedRead);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(accessLevelChangedRead, newMask);
|
|
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_UserAccessLevel) {
|
|
|
|
UA_Byte userAccessLevel;
|
|
UA_StatusCode retval = UA_Client_readUserAccessLevelAttribute(client, nodeReadWriteInt, &userAccessLevel);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
ck_assert_int_eq(userAccessLevel, UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD);
|
|
|
|
UA_Byte newMask = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE | UA_ACCESSLEVELMASK_HISTORYREAD;
|
|
|
|
retval = UA_Client_writeUserAccessLevelAttribute(client, nodeReadWriteInt, &newMask);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_MinimumSamplingInterval) {
|
|
|
|
UA_Double minimumSamplingInterval = 0;
|
|
UA_StatusCode retval = UA_Client_readMinimumSamplingIntervalAttribute(client, nodeReadWriteGeneric, &minimumSamplingInterval);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert(minimumSamplingInterval == 0);
|
|
|
|
// we want an array
|
|
UA_Double newMinimumSamplingInterval = 1;
|
|
|
|
retval = UA_Client_writeMinimumSamplingIntervalAttribute(client, nodeReadWriteGeneric, &newMinimumSamplingInterval);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readMinimumSamplingIntervalAttribute(client, nodeReadWriteGeneric, &minimumSamplingInterval);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert(minimumSamplingInterval == newMinimumSamplingInterval);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_Historizing) {
|
|
|
|
UA_Boolean historizing;
|
|
UA_StatusCode retval = UA_Client_readHistorizingAttribute(client, nodeReadWriteInt, &historizing);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(historizing, UA_FALSE);
|
|
|
|
UA_Boolean newHistorizing = UA_TRUE;
|
|
|
|
retval = UA_Client_writeHistorizingAttribute(client, nodeReadWriteInt, &newHistorizing);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readHistorizingAttribute(client, nodeReadWriteInt, &historizing);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(historizing, newHistorizing);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_Executable) {
|
|
|
|
UA_Boolean executable;
|
|
UA_StatusCode retval = UA_Client_readExecutableAttribute(client, nodeReadWriteMethod, &executable);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(executable, UA_TRUE);
|
|
|
|
UA_Boolean newExecutable = UA_FALSE;
|
|
|
|
retval = UA_Client_writeExecutableAttribute(client, nodeReadWriteMethod, &newExecutable);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
|
|
retval = UA_Client_readExecutableAttribute(client, nodeReadWriteMethod, &executable);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(executable, newExecutable);
|
|
}
|
|
END_TEST
|
|
|
|
START_TEST(Node_ReadWrite_UserExecutable) {
|
|
|
|
UA_Boolean userExecutable;
|
|
UA_StatusCode retval = UA_Client_readUserExecutableAttribute(client, nodeReadWriteMethod, &userExecutable);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_GOOD);
|
|
ck_assert_int_eq(userExecutable, UA_FALSE);
|
|
|
|
UA_Boolean newUserExecutable = UA_TRUE;
|
|
|
|
retval = UA_Client_writeUserExecutableAttribute(client, nodeReadWriteMethod, &newUserExecutable);
|
|
ck_assert_uint_eq(retval, UA_STATUSCODE_BADWRITENOTSUPPORTED);
|
|
|
|
}
|
|
END_TEST
|
|
|
|
#endif
|
|
|
|
static Suite *testSuite_Client(void) {
|
|
Suite *s = suite_create("Client Highlevel");
|
|
TCase *tc_misc = tcase_create("Client Highlevel Misc");
|
|
tcase_add_checked_fixture(tc_misc, setup, teardown);
|
|
tcase_add_test(tc_misc, Misc_State);
|
|
tcase_add_test(tc_misc, Misc_NamespaceGetIndex);
|
|
suite_add_tcase(s, tc_misc);
|
|
|
|
TCase *tc_nodes = tcase_create("Client Highlevel Node Management");
|
|
tcase_add_checked_fixture(tc_nodes, setup, teardown);
|
|
#ifdef UA_ENABLE_NODEMANAGEMENT
|
|
tcase_add_test(tc_nodes, Node_Add);
|
|
#endif
|
|
tcase_add_test(tc_nodes, Node_Browse);
|
|
tcase_add_test(tc_nodes, Node_Register);
|
|
suite_add_tcase(s, tc_nodes);
|
|
|
|
#ifdef UA_ENABLE_NODEMANAGEMENT
|
|
TCase *tc_readwrite = tcase_create("Client Highlevel Read/Write");
|
|
tcase_add_unchecked_fixture(tc_readwrite, setup, teardown);
|
|
// first add some nodes where we test on
|
|
tcase_add_test(tc_readwrite, Node_AddReadWriteNodes);
|
|
// Now run all the read write tests
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_Id);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_Class);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_BrowseName);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_DisplayName);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_Description);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_WriteMask);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_UserWriteMask);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_IsAbstract);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_Symmetric);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_InverseName);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_ContainsNoLoops);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_EventNotifier);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_Value);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_DataType);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_ValueRank);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_ArrayDimensions);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_AccessLevel);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_UserAccessLevel);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_MinimumSamplingInterval);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_Historizing);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_Executable);
|
|
tcase_add_test(tc_readwrite, Node_ReadWrite_UserExecutable);
|
|
suite_add_tcase(s, tc_readwrite);
|
|
#endif
|
|
return s;
|
|
}
|
|
|
|
int main(void) {
|
|
Suite *s = testSuite_Client();
|
|
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;
|
|
}
|