mirror of
https://github.com/open62541/open62541.git
synced 2026-10-17 04:42:09 +08:00
488 lines
20 KiB
C
488 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/.
|
|
*
|
|
* Copyright 2026 (c) open62541 contributors
|
|
* Copyright 2026 (c) o6 Automation GmbH (Author: Julius Pfrommer)
|
|
*/
|
|
|
|
#include <open62541/transport_generated.h>
|
|
#include <open62541/types.h>
|
|
#include <open62541/server.h>
|
|
#include <open62541/server_config_default.h>
|
|
|
|
#include "ua_securechannel.h"
|
|
|
|
#include "test_helpers.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <check.h>
|
|
|
|
/* Provide ck_assert_ptr_null / ck_assert_ptr_nonnull on top of older
|
|
* libcheck (Ubuntu 20.04 ships 0.10.x where these shorthands are not
|
|
* yet defined). The ck_assert_msg form compiles on every libcheck
|
|
* version. */
|
|
#ifndef ck_assert_ptr_null
|
|
# define ck_assert_ptr_null(p) ck_assert_msg((p) == NULL, #p " != NULL")
|
|
#endif
|
|
#ifndef ck_assert_ptr_nonnull
|
|
# define ck_assert_ptr_nonnull(p) ck_assert_msg((p) != NULL, #p " == NULL")
|
|
#endif
|
|
|
|
/* These tests exercise the helper/utility surface of the SecureChannel that
|
|
* does not need a network connection manager. They run against a freshly
|
|
* initialised UA_SecureChannel whose SecurityPolicy is the server's built-in
|
|
* SecurityPolicy#None (so setSecurityPolicy succeeds without encryption). */
|
|
|
|
static UA_Server *server;
|
|
static UA_SecureChannel ch;
|
|
|
|
static UA_SecurityPolicy *
|
|
getNonePolicy(void) {
|
|
UA_ServerConfig *cfg = UA_Server_getConfig(server);
|
|
ck_assert_ptr_ne(cfg, NULL);
|
|
ck_assert_uint_gt(cfg->securityPoliciesSize, 0);
|
|
return &cfg->securityPolicies[0];
|
|
}
|
|
|
|
static void
|
|
setup(void) {
|
|
server = UA_Server_newForUnitTest();
|
|
ck_assert_ptr_ne(server, NULL);
|
|
|
|
UA_SecureChannel_init(&ch);
|
|
ch.config = UA_ConnectionConfig_default;
|
|
UA_StatusCode spv = UA_SecureChannel_setSecurityPolicy(
|
|
&ch, getNonePolicy(), &ch.remoteCertificate);
|
|
ck_assert_uint_eq(spv, UA_STATUSCODE_GOOD);
|
|
ch.securityMode = UA_MESSAGESECURITYMODE_NONE;
|
|
}
|
|
|
|
static void
|
|
teardown(void) {
|
|
UA_SecureChannel_clear(&ch);
|
|
UA_Server_delete(server);
|
|
}
|
|
|
|
/* ==== UA_SecureChannel_setSecurityMode reject paths ==== */
|
|
|
|
START_TEST(setSecurityMode_invalidMode_rejected) {
|
|
/* UA_MESSAGESECURITYMODE_INVALID is below the valid range and must be
|
|
* rejected before the SecurityPolicy is even consulted. */
|
|
UA_StatusCode res = UA_SecureChannel_setSecurityMode(
|
|
&ch, UA_MESSAGESECURITYMODE_INVALID);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_BADSECURITYMODEREJECTED);
|
|
ck_assert_uint_eq(ch.securityMode, UA_MESSAGESECURITYMODE_NONE);
|
|
} END_TEST
|
|
|
|
START_TEST(setSecurityMode_outOfRange_rejected) {
|
|
/* (UA_MessageSecurityMode)99 is above the valid enum range and must be
|
|
* rejected by the same upper-bound check. */
|
|
UA_StatusCode res = UA_SecureChannel_setSecurityMode(
|
|
&ch, (UA_MessageSecurityMode)99);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_BADSECURITYMODEREJECTED);
|
|
ck_assert_uint_eq(ch.securityMode, UA_MESSAGESECURITYMODE_NONE);
|
|
} END_TEST
|
|
|
|
START_TEST(setSecurityMode_noPolicy_rejected) {
|
|
/* A freshly initialised channel has no SecurityPolicy. The mode setter
|
|
* must reject with BADSECURITYMODEREJECTED and leave the mode unchanged. */
|
|
UA_SecureChannel ch2;
|
|
UA_SecureChannel_init(&ch2);
|
|
UA_StatusCode res = UA_SecureChannel_setSecurityMode(
|
|
&ch2, UA_MESSAGESECURITYMODE_NONE);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_BADSECURITYMODEREJECTED);
|
|
/* Tear down (no policy was set so clear is just a reset). */
|
|
UA_SecureChannel_clear(&ch2);
|
|
} END_TEST
|
|
|
|
START_TEST(setSecurityMode_nonePolicyWithSign_rejected) {
|
|
/* The #None SecurityPolicy only accepts UA_MESSAGESECURITYMODE_NONE.
|
|
* Setting any other mode must fail. */
|
|
UA_StatusCode res = UA_SecureChannel_setSecurityMode(
|
|
&ch, UA_MESSAGESECURITYMODE_SIGN);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_BADSECURITYMODEREJECTED);
|
|
ck_assert_uint_eq(ch.securityMode, UA_MESSAGESECURITYMODE_NONE);
|
|
} END_TEST
|
|
|
|
START_TEST(setSecurityMode_noneMode_accepted) {
|
|
/* The positive case: NONE mode is accepted when the policy is #None. */
|
|
UA_StatusCode res = UA_SecureChannel_setSecurityMode(
|
|
&ch, UA_MESSAGESECURITYMODE_NONE);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(ch.securityMode, UA_MESSAGESECURITYMODE_NONE);
|
|
} END_TEST
|
|
|
|
/* ==== UA_SecureChannel_setSecurityPolicy reject paths ==== */
|
|
|
|
START_TEST(setSecurityPolicy_alreadyConfigured_rejected) {
|
|
/* src/ua_securechannel.c:39-42:
|
|
* UA_CHECK_ERROR(!channel->securityPolicy,
|
|
* return UA_STATUSCODE_BADINTERNALERROR, ...);
|
|
* The setup() helper has already called setSecurityPolicy once.
|
|
* A second call must fail with BADINTERNALERROR. None of the
|
|
* existing tests exercises this guard. */
|
|
UA_StatusCode res = UA_SecureChannel_setSecurityPolicy(
|
|
&ch, getNonePolicy(), &ch.remoteCertificate);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_BADINTERNALERROR);
|
|
/* The channel's policy must remain the original (untouched) */
|
|
ck_assert_ptr_nonnull((void*)ch.securityPolicy);
|
|
} END_TEST
|
|
|
|
START_TEST(setSecurityPolicyWithoutOPN_withoutCertificate_hasNoContext) {
|
|
UA_SecureChannel direct;
|
|
UA_SecureChannel_init(&direct);
|
|
UA_SecurityPolicy *policy = getNonePolicy();
|
|
ck_assert_uint_eq(
|
|
UA_SecureChannel_setSecurityPolicyWithoutOPN(
|
|
&direct, policy, NULL, UA_MESSAGESECURITYMODE_NONE),
|
|
UA_STATUSCODE_GOOD);
|
|
ck_assert_ptr_eq(direct.securityPolicy, policy);
|
|
ck_assert_ptr_null(direct.channelContext);
|
|
ck_assert_uint_eq(direct.remoteCertificate.length, 0);
|
|
ck_assert_uint_eq(direct.enhancedSecurity,
|
|
UA_SecurityPolicy_isEnhancedSecurity(policy));
|
|
ck_assert_uint_eq(direct.legacySequenceNumbers,
|
|
UA_SecurityPolicy_useLegacySequenceNumbers(policy));
|
|
UA_SecureChannel_clear(&direct);
|
|
} END_TEST
|
|
|
|
#ifdef UA_ENABLE_ENCRYPTION
|
|
START_TEST(setSecurityPolicyWithoutOPN_enhancedPolicy_rejected) {
|
|
UA_SecureChannel direct;
|
|
UA_SecureChannel_init(&direct);
|
|
UA_SecurityPolicy policy = *getNonePolicy();
|
|
const UA_String enhancedPolicyUri = UA_STRING_STATIC(
|
|
"http://opcfoundation.org/UA/SecurityPolicy#ECC_nistP256_AesGcm");
|
|
policy.policyUri = enhancedPolicyUri;
|
|
ck_assert(UA_SecurityPolicy_isEnhancedSecurity(&policy));
|
|
ck_assert_uint_eq(
|
|
UA_SecureChannel_setSecurityPolicyWithoutOPN(
|
|
&direct, &policy, NULL, UA_MESSAGESECURITYMODE_SIGNANDENCRYPT),
|
|
UA_STATUSCODE_BADSECURITYPOLICYREJECTED);
|
|
ck_assert_ptr_null(direct.securityPolicy);
|
|
UA_SecureChannel_clear(&direct);
|
|
} END_TEST
|
|
#endif
|
|
|
|
/* ==== UA_SecureChannel_processHELACK ==== */
|
|
|
|
START_TEST(processHELACK_happyPath_returnsGood) {
|
|
/* Both sides offer 65535-byte buffers and unlimited message size. The
|
|
* lowest common values are used; the function must return GOOD. */
|
|
UA_TcpAcknowledgeMessage remote;
|
|
memset(&remote, 0, sizeof(remote));
|
|
remote.protocolVersion = 0;
|
|
remote.receiveBufferSize = 65535;
|
|
remote.sendBufferSize = 65535;
|
|
remote.maxMessageSize = 0; /* "unlimited" */
|
|
remote.maxChunkCount = 0; /* "unlimited" */
|
|
|
|
UA_StatusCode res = UA_SecureChannel_processHELACK(&ch, &remote);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
|
|
/* Remote and local have the same size, so they should be unchanged. */
|
|
ck_assert_uint_eq(ch.config.recvBufferSize, 65535);
|
|
ck_assert_uint_eq(ch.config.sendBufferSize, 65535);
|
|
} END_TEST
|
|
|
|
START_TEST(processHELACK_remoteReceiveCapped_capsSendBuffer) {
|
|
/* The remote receive-buffer (16384) is smaller than our send-buffer
|
|
* (65535), so our send-buffer is capped to the remote's value. */
|
|
UA_TcpAcknowledgeMessage remote;
|
|
memset(&remote, 0, sizeof(remote));
|
|
remote.protocolVersion = 0;
|
|
remote.receiveBufferSize = 16384;
|
|
remote.sendBufferSize = 65535;
|
|
remote.maxMessageSize = 0;
|
|
remote.maxChunkCount = 0;
|
|
|
|
UA_StatusCode res = UA_SecureChannel_processHELACK(&ch, &remote);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(ch.config.sendBufferSize, 16384);
|
|
} END_TEST
|
|
|
|
START_TEST(processHELACK_remoteSendCapped_capsRecvBuffer) {
|
|
/* Symmetric: the remote send-buffer (16384) is smaller than our
|
|
* recv-buffer, so our recv-buffer is capped to the remote's value. */
|
|
UA_TcpAcknowledgeMessage remote;
|
|
memset(&remote, 0, sizeof(remote));
|
|
remote.protocolVersion = 0;
|
|
remote.receiveBufferSize = 65535;
|
|
remote.sendBufferSize = 16384;
|
|
remote.maxMessageSize = 0;
|
|
remote.maxChunkCount = 0;
|
|
|
|
UA_StatusCode res = UA_SecureChannel_processHELACK(&ch, &remote);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(ch.config.recvBufferSize, 16384);
|
|
} END_TEST
|
|
|
|
START_TEST(processHELACK_lowProtocolVersion_capsVersion) {
|
|
/* The local protocol version must be capped to the lower of the two. */
|
|
ch.config.protocolVersion = 0;
|
|
UA_TcpAcknowledgeMessage remote;
|
|
memset(&remote, 0, sizeof(remote));
|
|
remote.protocolVersion = 0; /* local is also 0 - check that it stays */
|
|
remote.receiveBufferSize = 65535;
|
|
remote.sendBufferSize = 65535;
|
|
remote.maxMessageSize = 0;
|
|
remote.maxChunkCount = 0;
|
|
|
|
UA_StatusCode res = UA_SecureChannel_processHELACK(&ch, &remote);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(ch.config.protocolVersion, 0);
|
|
} END_TEST
|
|
|
|
START_TEST(processHELACK_bufferTooSmall_returnsBad) {
|
|
/* The protocol mandates at least 8192-byte buffers. A remote offering
|
|
* only 1024-byte buffers must be rejected with BADINTERNALERROR. */
|
|
UA_TcpAcknowledgeMessage remote;
|
|
memset(&remote, 0, sizeof(remote));
|
|
remote.protocolVersion = 0;
|
|
remote.receiveBufferSize = 1024;
|
|
remote.sendBufferSize = 65535;
|
|
remote.maxMessageSize = 0;
|
|
remote.maxChunkCount = 0;
|
|
|
|
UA_StatusCode res = UA_SecureChannel_processHELACK(&ch, &remote);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_BADINTERNALERROR);
|
|
} END_TEST
|
|
|
|
START_TEST(processHELACK_maxMessageSizeTooSmall_returnsBad) {
|
|
/* Even if the buffers are large, a maxMessageSize limit below 8192 must
|
|
* cause rejection (the third branch in the 8192-byte check). */
|
|
UA_TcpAcknowledgeMessage remote;
|
|
memset(&remote, 0, sizeof(remote));
|
|
remote.protocolVersion = 0;
|
|
remote.receiveBufferSize = 65535;
|
|
remote.sendBufferSize = 65535;
|
|
remote.maxMessageSize = 4096; /* below 8192 floor */
|
|
remote.maxChunkCount = 0;
|
|
|
|
UA_StatusCode res = UA_SecureChannel_processHELACK(&ch, &remote);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_BADINTERNALERROR);
|
|
} END_TEST
|
|
|
|
/* ==== UA_SecureChannel_deleteBuffered ==== */
|
|
|
|
START_TEST(deleteBuffered_noBuffer_isNoop) {
|
|
/* Fresh channel has no unprocessed buffer and no chunks. deleteBuffered
|
|
* must be a no-op and not crash. */
|
|
UA_SecureChannel_deleteBuffered(&ch);
|
|
/* No asserts needed - the test passes if the call returns. */
|
|
} END_TEST
|
|
|
|
START_TEST(deleteBuffered_unprocessedCopied_clears) {
|
|
/* A copied unprocessed buffer must be cleared. Use a heap-allocated
|
|
* buffer so the inner free() is well-defined. */
|
|
UA_Byte initData[4] = {1, 2, 3, 4};
|
|
UA_ByteString tmp = {4, (UA_Byte*)UA_malloc(4)};
|
|
memcpy(tmp.data, initData, 4);
|
|
ch.unprocessed = tmp;
|
|
ch.unprocessedCopied = true;
|
|
UA_SecureChannel_deleteBuffered(&ch);
|
|
ck_assert_msg(ch.unprocessed.data == NULL, "expected unprocessed.data to be NULL");
|
|
ck_assert_uint_eq(ch.unprocessed.length, 0);
|
|
/* unprocessedCopied is left as-is by the implementation; reset for
|
|
* the next test. */
|
|
ch.unprocessedCopied = false;
|
|
} END_TEST
|
|
|
|
START_TEST(deleteBuffered_unprocessedNotCopied_isNoop) {
|
|
/* When the buffer was not copied, deleteBuffered must leave the
|
|
* pointer alone. Use a heap-allocated buffer to keep teardown safe. */
|
|
UA_Byte initData[4] = {1, 2, 3, 4};
|
|
UA_Byte *data = (UA_Byte*)UA_malloc(4);
|
|
memcpy(data, initData, 4);
|
|
ch.unprocessed.data = data;
|
|
ch.unprocessed.length = 4;
|
|
ch.unprocessedCopied = false;
|
|
UA_SecureChannel_deleteBuffered(&ch);
|
|
ck_assert_ptr_eq((void*)ch.unprocessed.data, (void*)data);
|
|
ck_assert_uint_eq(ch.unprocessed.length, 4);
|
|
/* Clean up ourselves since teardown won't free this (not copied). */
|
|
UA_free(data);
|
|
} END_TEST
|
|
|
|
/* ==== UA_SecureChannel_loadBuffer ==== */
|
|
|
|
START_TEST(loadBuffer_emptyChannel_usesBuffer) {
|
|
/* When no unprocessed data exists, the new buffer is adopted as-is and
|
|
* marked as not-copied. Use a heap buffer so teardown is safe. */
|
|
UA_Byte *data = (UA_Byte*)UA_malloc(8);
|
|
UA_ByteString buf = {8, data};
|
|
UA_StatusCode res = UA_SecureChannel_loadBuffer(&ch, buf);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
|
|
ck_assert_ptr_eq((void*)ch.unprocessed.data, (void*)data);
|
|
ck_assert_uint_eq(ch.unprocessed.length, 8);
|
|
ck_assert(!ch.unprocessedCopied);
|
|
/* Clean up ourselves - teardown won't free this (not copied). */
|
|
UA_free(data);
|
|
ch.unprocessed.data = NULL;
|
|
ch.unprocessed.length = 0;
|
|
} END_TEST
|
|
|
|
START_TEST(loadBuffer_append_reallocates) {
|
|
/* Set up the channel with a heap-allocated copied buffer, then
|
|
* loadBuffer must realloc the existing buffer and append. */
|
|
UA_Byte initData[4] = {1, 2, 3, 4};
|
|
UA_Byte extraData[4] = {5, 6, 7, 8};
|
|
UA_Byte *initial = (UA_Byte*)UA_malloc(4);
|
|
memcpy(initial, initData, 4);
|
|
ch.unprocessed.data = initial;
|
|
ch.unprocessed.length = 4;
|
|
ch.unprocessedCopied = true;
|
|
|
|
UA_Byte *extra = (UA_Byte*)UA_malloc(4);
|
|
memcpy(extra, extraData, 4);
|
|
UA_ByteString buf2 = {4, extra};
|
|
|
|
UA_StatusCode res = UA_SecureChannel_loadBuffer(&ch, buf2);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(ch.unprocessed.length, 8);
|
|
ck_assert(ch.unprocessedCopied);
|
|
ck_assert_msg(ch.unprocessed.data[0] == 1 &&
|
|
ch.unprocessed.data[3] == 4 &&
|
|
ch.unprocessed.data[4] == 5 &&
|
|
ch.unprocessed.data[7] == 8,
|
|
"Appended buffer contents wrong");
|
|
/* teardown's deleteBuffered will free this since unprocessedCopied=true */
|
|
UA_free(extra); /* the buf2 data is referenced but not adopted */
|
|
} END_TEST
|
|
|
|
START_TEST(loadBuffer_emptyBuffer_keepsExisting) {
|
|
/* Existing heap-allocated copied buffer + an empty input. The empty
|
|
* loadBuffer is a no-op realloc that keeps the existing data. */
|
|
UA_Byte initData[4] = {1, 2, 3, 4};
|
|
UA_Byte *initial = (UA_Byte*)UA_malloc(4);
|
|
memcpy(initial, initData, 4);
|
|
ch.unprocessed.data = initial;
|
|
ch.unprocessed.length = 4;
|
|
ch.unprocessedCopied = true;
|
|
|
|
UA_ByteString bufEmpty = {0, NULL};
|
|
UA_StatusCode res = UA_SecureChannel_loadBuffer(&ch, bufEmpty);
|
|
ck_assert_uint_eq(res, UA_STATUSCODE_GOOD);
|
|
ck_assert_uint_eq(ch.unprocessed.length, 4);
|
|
/* teardown's deleteBuffered will free this */
|
|
} END_TEST
|
|
|
|
/* ==== UA_SecureChannel_isConnected ==== */
|
|
|
|
START_TEST(isConnected_closedState_returnsFalse) {
|
|
ch.state = UA_SECURECHANNELSTATE_CLOSED;
|
|
ck_assert(!UA_SecureChannel_isConnected(&ch));
|
|
} END_TEST
|
|
|
|
START_TEST(isConnected_connectedState_returnsTrue) {
|
|
/* OPEN is the canonical "connected" state. */
|
|
ch.state = UA_SECURECHANNELSTATE_OPEN;
|
|
ck_assert(UA_SecureChannel_isConnected(&ch));
|
|
} END_TEST
|
|
|
|
START_TEST(isConnected_closingState_returnsFalse) {
|
|
/* CLOSING is past the upper bound of the connected range. */
|
|
ch.state = UA_SECURECHANNELSTATE_CLOSING;
|
|
ck_assert(!UA_SecureChannel_isConnected(&ch));
|
|
} END_TEST
|
|
|
|
/* ==== UA_SecureChannel_clear on a freshly-init'd channel ==== */
|
|
|
|
START_TEST(clear_emptyChannel_doesNotCrash) {
|
|
/* The clear function asserts no sessions are attached. Calling it on
|
|
* a freshly-initialised channel must not crash. */
|
|
UA_SecureChannel ch2;
|
|
UA_SecureChannel_init(&ch2);
|
|
UA_SecureChannel_clear(&ch2);
|
|
/* If we get here, the test passes. */
|
|
} END_TEST
|
|
|
|
START_TEST(shutdown_notConnected_isNoop) {
|
|
/* Shutdown on a CLOSED channel must be a no-op (the early-return path
|
|
* guarded by !UA_SecureChannel_isConnected). */
|
|
ch.state = UA_SECURECHANNELSTATE_CLOSED;
|
|
UA_SecureChannel_shutdown(&ch, UA_SHUTDOWNREASON_CLOSE);
|
|
/* State must stay CLOSED. */
|
|
ck_assert_uint_eq(ch.state, UA_SECURECHANNELSTATE_CLOSED);
|
|
} END_TEST
|
|
|
|
START_TEST(shutdown_withoutOwnedConnection_setsStateAndReason) {
|
|
ch.state = UA_SECURECHANNELSTATE_OPEN;
|
|
UA_SecureChannel_shutdown(&ch, UA_SHUTDOWNREASON_CLOSE);
|
|
ck_assert_uint_eq(ch.state, UA_SECURECHANNELSTATE_CLOSING);
|
|
ck_assert_uint_eq(ch.shutdownReason, UA_SHUTDOWNREASON_CLOSE);
|
|
} END_TEST
|
|
|
|
START_TEST(shutdown_closingIsNoop) {
|
|
ch.state = UA_SECURECHANNELSTATE_CLOSING;
|
|
ch.shutdownReason = UA_SHUTDOWNREASON_CLOSE;
|
|
UA_SecureChannel_shutdown(&ch, UA_SHUTDOWNREASON_ABORT);
|
|
ck_assert_uint_eq(ch.state, UA_SECURECHANNELSTATE_CLOSING);
|
|
ck_assert_uint_eq(ch.shutdownReason, UA_SHUTDOWNREASON_CLOSE);
|
|
} END_TEST
|
|
|
|
static Suite *
|
|
testSuite(void) {
|
|
Suite *s = suite_create("SecureChannel unit");
|
|
|
|
TCase *tc_mode = tcase_create("setSecurityMode reject paths");
|
|
tcase_add_checked_fixture(tc_mode, setup, teardown);
|
|
tcase_add_test(tc_mode, setSecurityMode_invalidMode_rejected);
|
|
tcase_add_test(tc_mode, setSecurityMode_outOfRange_rejected);
|
|
tcase_add_test(tc_mode, setSecurityMode_noPolicy_rejected);
|
|
tcase_add_test(tc_mode, setSecurityMode_nonePolicyWithSign_rejected);
|
|
tcase_add_test(tc_mode, setSecurityMode_noneMode_accepted);
|
|
tcase_add_test(tc_mode, setSecurityPolicy_alreadyConfigured_rejected);
|
|
tcase_add_test(tc_mode,
|
|
setSecurityPolicyWithoutOPN_withoutCertificate_hasNoContext);
|
|
#ifdef UA_ENABLE_ENCRYPTION
|
|
tcase_add_test(tc_mode,
|
|
setSecurityPolicyWithoutOPN_enhancedPolicy_rejected);
|
|
#endif
|
|
suite_add_tcase(s, tc_mode);
|
|
|
|
TCase *tc_hel = tcase_create("processHELACK");
|
|
tcase_add_checked_fixture(tc_hel, setup, teardown);
|
|
tcase_add_test(tc_hel, processHELACK_happyPath_returnsGood);
|
|
tcase_add_test(tc_hel, processHELACK_remoteReceiveCapped_capsSendBuffer);
|
|
tcase_add_test(tc_hel, processHELACK_remoteSendCapped_capsRecvBuffer);
|
|
tcase_add_test(tc_hel, processHELACK_lowProtocolVersion_capsVersion);
|
|
tcase_add_test(tc_hel, processHELACK_bufferTooSmall_returnsBad);
|
|
tcase_add_test(tc_hel, processHELACK_maxMessageSizeTooSmall_returnsBad);
|
|
suite_add_tcase(s, tc_hel);
|
|
|
|
TCase *tc_buf = tcase_create("deleteBuffered/loadBuffer");
|
|
tcase_add_checked_fixture(tc_buf, setup, teardown);
|
|
tcase_add_test(tc_buf, deleteBuffered_noBuffer_isNoop);
|
|
tcase_add_test(tc_buf, deleteBuffered_unprocessedCopied_clears);
|
|
tcase_add_test(tc_buf, deleteBuffered_unprocessedNotCopied_isNoop);
|
|
tcase_add_test(tc_buf, loadBuffer_emptyChannel_usesBuffer);
|
|
tcase_add_test(tc_buf, loadBuffer_append_reallocates);
|
|
tcase_add_test(tc_buf, loadBuffer_emptyBuffer_keepsExisting);
|
|
suite_add_tcase(s, tc_buf);
|
|
|
|
TCase *tc_state = tcase_create("isConnected / clear");
|
|
tcase_add_checked_fixture(tc_state, setup, teardown);
|
|
tcase_add_test(tc_state, isConnected_closedState_returnsFalse);
|
|
tcase_add_test(tc_state, isConnected_connectedState_returnsTrue);
|
|
tcase_add_test(tc_state, isConnected_closingState_returnsFalse);
|
|
tcase_add_test(tc_state, clear_emptyChannel_doesNotCrash);
|
|
tcase_add_test(tc_state, shutdown_notConnected_isNoop);
|
|
tcase_add_test(tc_state, shutdown_withoutOwnedConnection_setsStateAndReason);
|
|
tcase_add_test(tc_state, shutdown_closingIsNoop);
|
|
suite_add_tcase(s, tc_state);
|
|
|
|
return s;
|
|
}
|
|
|
|
int main(void) {
|
|
Suite *s = testSuite();
|
|
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;
|
|
}
|