Files
open62541/tests/server/check_server_readwrite.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

547 lines
20 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/. */
/* Server service function 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/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);
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);
}
/* === Server-side node operations === */
START_TEST(srv_readWriteNode) {
/* Read a node attribute via server API */
UA_Variant val;
UA_Variant_init(&val);
UA_StatusCode res = UA_Server_readValue(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME), &val);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert(val.type == &UA_TYPES[UA_TYPES_DATETIME]);
UA_Variant_clear(&val);
} END_TEST
START_TEST(srv_readDisplayName) {
UA_LocalizedText lt;
UA_StatusCode res = UA_Server_readDisplayName(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &lt);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert(lt.text.length > 0);
UA_LocalizedText_clear(&lt);
} END_TEST
START_TEST(srv_readDescription) {
UA_LocalizedText lt;
UA_StatusCode res = UA_Server_readDescription(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &lt);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
UA_LocalizedText_clear(&lt);
} END_TEST
START_TEST(srv_readWriteMask) {
UA_UInt32 wm;
UA_StatusCode res = UA_Server_readWriteMask(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &wm);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_readNodeClass) {
UA_NodeClass nc;
UA_StatusCode res = UA_Server_readNodeClass(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &nc);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_int_eq(nc, UA_NODECLASS_OBJECT);
} END_TEST
START_TEST(srv_readBrowseName) {
UA_QualifiedName bn;
UA_StatusCode res = UA_Server_readBrowseName(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &bn);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
UA_QualifiedName_clear(&bn);
} END_TEST
START_TEST(srv_readNodeId) {
UA_NodeId nid;
UA_StatusCode res = UA_Server_readNodeId(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &nid);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
UA_NodeId_clear(&nid);
} END_TEST
START_TEST(srv_readAccessLevel) {
UA_Byte al;
UA_StatusCode res = UA_Server_readAccessLevel(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME), &al);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_readValueRank) {
UA_Int32 vr;
UA_StatusCode res = UA_Server_readValueRank(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME), &vr);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_readIsAbstract) {
UA_Boolean ia;
UA_StatusCode res = UA_Server_readIsAbstract(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE), &ia);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_readInverseName) {
UA_LocalizedText lt;
UA_StatusCode res = UA_Server_readInverseName(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES), &lt);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
UA_LocalizedText_clear(&lt);
} END_TEST
START_TEST(srv_readEventNotifier) {
UA_Byte en;
UA_StatusCode res = UA_Server_readEventNotifier(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER), &en);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
/* === Server-side write operations === */
START_TEST(srv_writeDisplayName) {
/* Add a writable node first */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 val = 1;
UA_Variant_setScalar(&attr.value, &val, &UA_TYPES[UA_TYPES_INT32]);
attr.writeMask = UA_WRITEMASK_DISPLAYNAME;
UA_NodeId newNode = UA_NODEID_NUMERIC(1, 63000);
UA_Server_addVariableNode(server, newNode,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "SrvWriteDN"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr, NULL, NULL);
UA_LocalizedText lt = UA_LOCALIZEDTEXT("en", "New Display Name");
UA_StatusCode res = UA_Server_writeDisplayName(server, newNode, lt);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_writeValue) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 initVal = 1;
UA_Variant_setScalar(&attr.value, &initVal, &UA_TYPES[UA_TYPES_INT32]);
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_NodeId newNode = UA_NODEID_NUMERIC(1, 63001);
UA_Server_addVariableNode(server, newNode,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "SrvWriteVal"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr, NULL, NULL);
UA_Int32 newVal = 999;
UA_Variant v;
UA_Variant_setScalar(&v, &newVal, &UA_TYPES[UA_TYPES_INT32]);
UA_StatusCode res = UA_Server_writeValue(server, newNode, v);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
/* Read back */
UA_Variant readVal;
UA_Variant_init(&readVal);
res = UA_Server_readValue(server, newNode, &readVal);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_int_eq(*(UA_Int32 *)readVal.data, 999);
UA_Variant_clear(&readVal);
} END_TEST
START_TEST(srv_writeAccessLevel) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 val = 1;
UA_Variant_setScalar(&attr.value, &val, &UA_TYPES[UA_TYPES_INT32]);
attr.writeMask = UA_WRITEMASK_ACCESSLEVEL;
UA_NodeId newNode = UA_NODEID_NUMERIC(1, 63002);
UA_Server_addVariableNode(server, newNode,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "SrvWriteAL"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr, NULL, NULL);
UA_Byte al = UA_ACCESSLEVELMASK_READ;
UA_StatusCode res = UA_Server_writeAccessLevel(server, newNode, al);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
/* === Node operations via client (services) === */
START_TEST(srv_registerNodes) {
UA_Client *client = connectClient();
UA_RegisterNodesRequest registerReq;
UA_RegisterNodesRequest_init(&registerReq);
UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
registerReq.nodesToRegister = &nodeId;
registerReq.nodesToRegisterSize = 1;
UA_RegisterNodesResponse registerResp =
UA_Client_Service_registerNodes(client, registerReq);
ck_assert_uint_eq(registerResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
/* Unregister */
UA_UnregisterNodesRequest unregReq;
UA_UnregisterNodesRequest_init(&unregReq);
unregReq.nodesToUnregister = registerResp.registeredNodeIds;
unregReq.nodesToUnregisterSize = registerResp.registeredNodeIdsSize;
UA_UnregisterNodesResponse unregResp =
UA_Client_Service_unregisterNodes(client, unregReq);
ck_assert_uint_eq(unregResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
/* Prevent double-free: null out stack pointers before clearing */
unregReq.nodesToUnregister = NULL;
unregReq.nodesToUnregisterSize = 0;
registerReq.nodesToRegister = NULL;
registerReq.nodesToRegisterSize = 0;
UA_UnregisterNodesResponse_clear(&unregResp);
UA_RegisterNodesResponse_clear(&registerResp);
disconnectClient(client);
} END_TEST
START_TEST(srv_multiRead) {
UA_Client *client = connectClient();
/* Read multiple attributes at once */
UA_ReadRequest readReq;
UA_ReadRequest_init(&readReq);
UA_ReadValueId rvids[3];
for(int i = 0; i < 3; i++)
UA_ReadValueId_init(&rvids[i]);
rvids[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
rvids[0].attributeId = UA_ATTRIBUTEID_VALUE;
rvids[1].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
rvids[1].attributeId = UA_ATTRIBUTEID_BROWSENAME;
rvids[2].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER);
rvids[2].attributeId = UA_ATTRIBUTEID_DISPLAYNAME;
readReq.nodesToRead = rvids;
readReq.nodesToReadSize = 3;
UA_ReadResponse readResp = UA_Client_Service_read(client, readReq);
ck_assert_uint_eq(readResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
ck_assert_uint_eq(readResp.resultsSize, 3);
readReq.nodesToRead = NULL;
readReq.nodesToReadSize = 0;
UA_ReadResponse_clear(&readResp);
disconnectClient(client);
} END_TEST
START_TEST(srv_multiWrite) {
UA_Client *client = connectClient();
/* Add writable node */
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 val = 1;
UA_Variant_setScalar(&attr.value, &val, &UA_TYPES[UA_TYPES_INT32]);
attr.accessLevel = UA_ACCESSLEVELMASK_READ | UA_ACCESSLEVELMASK_WRITE;
UA_NodeId node = UA_NODEID_NUMERIC(1, 63010);
UA_Server_addVariableNode(server, node,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "MultiWrite"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr, NULL, NULL);
UA_WriteRequest writeReq;
UA_WriteRequest_init(&writeReq);
UA_WriteValue wv;
UA_WriteValue_init(&wv);
wv.nodeId = node;
wv.attributeId = UA_ATTRIBUTEID_VALUE;
wv.value.hasValue = true;
UA_Int32 newVal = 42;
UA_Variant_setScalar(&wv.value.value, &newVal, &UA_TYPES[UA_TYPES_INT32]);
writeReq.nodesToWrite = &wv;
writeReq.nodesToWriteSize = 1;
UA_WriteResponse writeResp = UA_Client_Service_write(client, writeReq);
ck_assert_uint_eq(writeResp.responseHeader.serviceResult, UA_STATUSCODE_GOOD);
writeReq.nodesToWrite = NULL;
writeReq.nodesToWriteSize = 0;
UA_WriteResponse_clear(&writeResp);
disconnectClient(client);
} END_TEST
/* === Server config operations === */
START_TEST(srv_getConfig) {
UA_ServerConfig *config = UA_Server_getConfig(server);
ck_assert_ptr_ne(config, NULL);
ck_assert_uint_gt(config->maxSecureChannels, 0);
#ifdef UA_ENABLE_SUBSCRIPTIONS
ck_assert_uint_eq(config->maxSubscriptions, 1024);
ck_assert_uint_eq(config->maxSubscriptionsPerSession, 64);
ck_assert_uint_eq(config->maxMonitoredItems, 1024 * 32);
ck_assert_uint_eq(config->maxMonitoredItemsPerSubscription, 1024 * 32);
#endif
} END_TEST
START_TEST(srv_addNamespace) {
UA_UInt16 nsIdx = UA_Server_addNamespace(server, "http://test.example.com");
ck_assert_uint_gt(nsIdx, 0);
/* Adding same URI returns same index */
UA_UInt16 nsIdx2 = UA_Server_addNamespace(server, "http://test.example.com");
ck_assert_uint_eq(nsIdx, nsIdx2);
} END_TEST
START_TEST(srv_getNamespaceByName) {
size_t nsIdx;
UA_String uri = UA_STRING("http://opcfoundation.org/UA/");
UA_StatusCode res = UA_Server_getNamespaceByName(server, uri, &nsIdx);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
ck_assert_uint_eq(nsIdx, 0);
/* Non-existing namespace */
uri = UA_STRING("http://nonexistent.example.com");
res = UA_Server_getNamespaceByName(server, uri, &nsIdx);
ck_assert_uint_ne(res, UA_STATUSCODE_GOOD);
} END_TEST
/* === Server browse === */
START_TEST(srv_browseSimplified) {
UA_QualifiedName qn = UA_QUALIFIEDNAME(0, "Server");
UA_BrowsePathResult bpr =
UA_Server_browseSimplifiedBrowsePath(server,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), 1, &qn);
ck_assert_uint_eq(bpr.statusCode, UA_STATUSCODE_GOOD);
ck_assert_uint_gt(bpr.targetsSize, 0);
UA_BrowsePathResult_clear(&bpr);
} END_TEST
/* === Server node lifecycle === */
START_TEST(srv_addDeleteVariable) {
UA_VariableAttributes attr = UA_VariableAttributes_default;
UA_Int32 val = 42;
UA_Variant_setScalar(&attr.value, &val, &UA_TYPES[UA_TYPES_INT32]);
UA_NodeId newNode = UA_NODEID_NUMERIC(1, 64000);
UA_StatusCode res = UA_Server_addVariableNode(server, newNode,
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "SrvDelVar"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr, NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
res = UA_Server_deleteNode(server, newNode, true);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_addObjectType) {
UA_ObjectTypeAttributes attr = UA_ObjectTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "SrvObjType");
UA_NodeId newNode = UA_NODEID_NUMERIC(1, 64001);
UA_StatusCode res = UA_Server_addObjectTypeNode(server, newNode,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "SrvObjType"),
attr, NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_addVariableType) {
UA_VariableTypeAttributes attr = UA_VariableTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "SrvVarType");
UA_NodeId newNode = UA_NODEID_NUMERIC(1, 64002);
UA_StatusCode res = UA_Server_addVariableTypeNode(server, newNode,
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "SrvVarType"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEDATAVARIABLETYPE),
attr, NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_addReferenceType) {
UA_ReferenceTypeAttributes attr = UA_ReferenceTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "SrvRefType");
attr.symmetric = false;
attr.isAbstract = false;
UA_NodeId newNode = UA_NODEID_NUMERIC(1, 64003);
UA_StatusCode res = UA_Server_addReferenceTypeNode(server, newNode,
UA_NODEID_NUMERIC(0, UA_NS0ID_NONHIERARCHICALREFERENCES),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "SrvRefType"),
attr, NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_addDataType) {
UA_DataTypeAttributes attr = UA_DataTypeAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "SrvDataType");
UA_NodeId newNode = UA_NODEID_NUMERIC(1, 64004);
UA_StatusCode res = UA_Server_addDataTypeNode(server, newNode,
UA_NODEID_NUMERIC(0, UA_NS0ID_STRUCTURE),
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
UA_QUALIFIEDNAME(1, "SrvDataType"),
attr, NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_addViewNode) {
UA_ViewAttributes attr = UA_ViewAttributes_default;
attr.displayName = UA_LOCALIZEDTEXT("en", "SrvView");
UA_NodeId newNode = UA_NODEID_NUMERIC(1, 64005);
UA_StatusCode res = UA_Server_addViewNode(server, newNode,
UA_NODEID_NUMERIC(0, UA_NS0ID_VIEWSFOLDER),
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "SrvView"),
attr, NULL, NULL);
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
} END_TEST
START_TEST(srv_addDeleteReference) {
UA_NodeId source = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
UA_ObjectAttributes attr = UA_ObjectAttributes_default;
UA_NodeId target = UA_NODEID_NUMERIC(1, 64010);
UA_Server_addObjectNode(server, target,
source, UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
UA_QUALIFIEDNAME(1, "RefTarget"),
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
attr, NULL, NULL);
/* Add another reference */
UA_ExpandedNodeId expandedTarget;
UA_ExpandedNodeId_init(&expandedTarget);
expandedTarget.nodeId = target;
UA_StatusCode res = UA_Server_addReference(server, source,
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
expandedTarget, true);
/* May succeed or fail */
(void)res;
/* Delete the reference */
res = UA_Server_deleteReference(server, source,
UA_NODEID_NUMERIC(0, UA_NS0ID_HASCOMPONENT),
true, expandedTarget, true);
(void)res;
} END_TEST
static Suite *testSuite_serverServices(void) {
TCase *tc_read = tcase_create("Srv_Read");
tcase_add_checked_fixture(tc_read, setup, teardown);
tcase_add_test(tc_read, srv_readWriteNode);
tcase_add_test(tc_read, srv_readDisplayName);
tcase_add_test(tc_read, srv_readDescription);
tcase_add_test(tc_read, srv_readWriteMask);
tcase_add_test(tc_read, srv_readNodeClass);
tcase_add_test(tc_read, srv_readBrowseName);
tcase_add_test(tc_read, srv_readNodeId);
tcase_add_test(tc_read, srv_readAccessLevel);
tcase_add_test(tc_read, srv_readValueRank);
tcase_add_test(tc_read, srv_readIsAbstract);
tcase_add_test(tc_read, srv_readInverseName);
tcase_add_test(tc_read, srv_readEventNotifier);
TCase *tc_write = tcase_create("Srv_Write");
tcase_add_checked_fixture(tc_write, setup, teardown);
tcase_add_test(tc_write, srv_writeDisplayName);
tcase_add_test(tc_write, srv_writeValue);
tcase_add_test(tc_write, srv_writeAccessLevel);
TCase *tc_svc = tcase_create("Srv_Services");
tcase_add_checked_fixture(tc_svc, setup, teardown);
tcase_add_test(tc_svc, srv_registerNodes);
tcase_add_test(tc_svc, srv_multiRead);
tcase_add_test(tc_svc, srv_multiWrite);
TCase *tc_config = tcase_create("Srv_Config");
tcase_add_checked_fixture(tc_config, setup, teardown);
tcase_add_test(tc_config, srv_getConfig);
tcase_add_test(tc_config, srv_addNamespace);
tcase_add_test(tc_config, srv_getNamespaceByName);
tcase_add_test(tc_config, srv_browseSimplified);
TCase *tc_nodes = tcase_create("Srv_Nodes");
tcase_add_checked_fixture(tc_nodes, setup, teardown);
tcase_add_test(tc_nodes, srv_addDeleteVariable);
tcase_add_test(tc_nodes, srv_addObjectType);
tcase_add_test(tc_nodes, srv_addVariableType);
tcase_add_test(tc_nodes, srv_addReferenceType);
tcase_add_test(tc_nodes, srv_addDataType);
tcase_add_test(tc_nodes, srv_addViewNode);
tcase_add_test(tc_nodes, srv_addDeleteReference);
Suite *s = suite_create("Server Services Extended");
suite_add_tcase(s, tc_read);
suite_add_tcase(s, tc_write);
suite_add_tcase(s, tc_svc);
suite_add_tcase(s, tc_config);
suite_add_tcase(s, tc_nodes);
return s;
}
int main(void) {
int number_failed = 0;
Suite *s = testSuite_serverServices();
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;
}