Squashed 'libs/libzmq/' content from commit 2b2fb9c7
git-subtree-dir: libs/libzmq git-subtree-split: 2b2fb9c7082dbc16c1323b97040a4edcfa2b997b
This commit is contained in:
322
tests/CMakeLists.txt
Normal file
322
tests/CMakeLists.txt
Normal file
@@ -0,0 +1,322 @@
|
||||
# CMake build script for ZeroMQ tests
|
||||
cmake_minimum_required(VERSION "2.8.1")
|
||||
|
||||
# On Windows: solution file will be called tests.sln
|
||||
project(tests)
|
||||
|
||||
set(tests
|
||||
test_ancillaries
|
||||
test_system
|
||||
test_pair_inproc
|
||||
test_pair_tcp
|
||||
test_reqrep_inproc
|
||||
test_reqrep_tcp
|
||||
test_hwm
|
||||
test_hwm_pubsub
|
||||
test_reqrep_device
|
||||
test_sub_forward
|
||||
test_invalid_rep
|
||||
test_msg_flags
|
||||
test_msg_ffn
|
||||
test_connect_resolve
|
||||
test_immediate
|
||||
test_last_endpoint
|
||||
test_term_endpoint
|
||||
test_router_mandatory
|
||||
test_probe_router
|
||||
test_stream
|
||||
test_stream_empty
|
||||
test_stream_disconnect
|
||||
test_disconnect_inproc
|
||||
test_unbind_wildcard
|
||||
test_ctx_options
|
||||
test_ctx_destroy
|
||||
test_security_no_zap_handler
|
||||
test_security_null
|
||||
test_security_plain
|
||||
test_security_zap
|
||||
test_iov
|
||||
test_spec_req
|
||||
test_spec_rep
|
||||
test_spec_dealer
|
||||
test_spec_router
|
||||
test_spec_pushpull
|
||||
test_req_correlate
|
||||
test_req_relaxed
|
||||
test_conflate
|
||||
test_inproc_connect
|
||||
test_issue_566
|
||||
test_shutdown_stress
|
||||
test_timeo
|
||||
test_many_sockets
|
||||
test_diffserv
|
||||
test_connect_rid
|
||||
test_xpub_nodrop
|
||||
test_pub_invert_matching
|
||||
test_setsockopt
|
||||
test_sockopt_hwm
|
||||
test_heartbeats
|
||||
test_atomics
|
||||
test_bind_src_address
|
||||
test_capabilities
|
||||
test_metadata
|
||||
test_router_handover
|
||||
test_srcfd
|
||||
test_stream_timeout
|
||||
test_xpub_manual
|
||||
test_xpub_welcome_msg
|
||||
test_xpub_verbose
|
||||
test_base85
|
||||
test_bind_after_connect_tcp
|
||||
test_sodium
|
||||
test_monitor
|
||||
test_socket_null
|
||||
test_reconnect_ivl
|
||||
test_reconnect_options
|
||||
test_tcp_accept_filter
|
||||
test_mock_pub_sub)
|
||||
|
||||
if(NOT WIN32)
|
||||
list(APPEND tests test_security_gssapi test_socks test_connect_null_fuzzer test_bind_null_fuzzer test_connect_fuzzer test_bind_fuzzer)
|
||||
endif()
|
||||
|
||||
if(ZMQ_HAVE_CURVE)
|
||||
# TODO: always fails running under Github Actions via CMake
|
||||
if(NOT CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
list(APPEND tests test_security_curve)
|
||||
endif()
|
||||
if(NOT WIN32)
|
||||
list(APPEND tests test_connect_curve_fuzzer test_bind_curve_fuzzer test_z85_decode_fuzzer)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
option(ENABLE_CAPSH "Run tests that require sudo and capsh (for cap_net_admin)" OFF)
|
||||
if(ENABLE_CAPSH)
|
||||
find_program(CAPSH_PROGRAM NAMES capsh)
|
||||
|
||||
if(CAPSH_PROGRAM)
|
||||
list(APPEND tests test_pair_tcp_cap_net_admin)
|
||||
else()
|
||||
message(STATUS "capsh not found, skipping tests that require CAP_NET_ADMIN")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ZMQ_HAVE_IPC)
|
||||
list(APPEND tests test_ipc_wildcard test_pair_ipc test_reqrep_ipc test_rebind_ipc)
|
||||
endif()
|
||||
|
||||
if(NOT WIN32)
|
||||
list(
|
||||
APPEND
|
||||
tests
|
||||
test_proxy
|
||||
test_proxy_hwm
|
||||
test_proxy_single_socket
|
||||
test_proxy_terminate
|
||||
test_getsockopt_memset
|
||||
test_filter_ipc
|
||||
test_stream_exceeds_buffer
|
||||
test_router_mandatory_hwm
|
||||
test_use_fd
|
||||
test_zmq_poll_fd)
|
||||
if(HAVE_FORK)
|
||||
list(APPEND tests test_fork)
|
||||
endif()
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
list(APPEND tests test_abstract_ipc)
|
||||
if(ZMQ_HAVE_TIPC)
|
||||
list(
|
||||
APPEND
|
||||
tests
|
||||
test_address_tipc
|
||||
test_pair_tipc
|
||||
test_reqrep_device_tipc
|
||||
test_reqrep_tipc
|
||||
test_router_mandatory_tipc
|
||||
test_sub_forward_tipc
|
||||
test_connect_delay_tipc
|
||||
test_shutdown_stress_tipc
|
||||
test_term_endpoint_tipc)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(WITH_VMCI)
|
||||
list(APPEND tests test_pair_vmci test_reqrep_vmci)
|
||||
endif()
|
||||
|
||||
if(ENABLE_DRAFTS)
|
||||
list(
|
||||
APPEND
|
||||
tests
|
||||
test_poller
|
||||
test_thread_safe
|
||||
test_client_server
|
||||
test_timers
|
||||
test_radio_dish
|
||||
test_scatter_gather
|
||||
test_dgram
|
||||
test_app_meta
|
||||
test_router_notify
|
||||
test_xpub_manual_last_value
|
||||
test_peer
|
||||
test_msg_init
|
||||
test_channel
|
||||
test_hello_msg
|
||||
test_disconnect_msg
|
||||
test_hiccup_msg
|
||||
test_zmq_ppoll_fd
|
||||
test_xsub_verbose
|
||||
)
|
||||
if(HAVE_FORK)
|
||||
list(APPEND tests test_zmq_ppoll_signals)
|
||||
endif()
|
||||
if(ZMQ_HAVE_BUSY_POLL)
|
||||
list(APPEND tests test_busy_poll)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(ZMQ_HAVE_WS)
|
||||
list(APPEND tests test_ws_transport)
|
||||
if(ZMQ_HAVE_WSS)
|
||||
list(APPEND tests test_wss_transport)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# add location of platform.hpp for Windows builds
|
||||
if(WIN32)
|
||||
add_definitions(-DZMQ_CUSTOM_PLATFORM_HPP)
|
||||
add_definitions(-D_WINSOCK_DEPRECATED_NO_WARNINGS)
|
||||
# Same name on 64bit systems
|
||||
link_libraries(ws2_32.lib)
|
||||
endif()
|
||||
|
||||
add_library(
|
||||
unity STATIC
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity.c" "${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity.h"
|
||||
"${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity_internals.h")
|
||||
set_target_properties(unity PROPERTIES PUBLIC_HEADER "${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity.h")
|
||||
target_compile_definitions(unity PUBLIC "UNITY_USE_COMMAND_LINE_ARGS" "UNITY_EXCLUDE_FLOAT")
|
||||
target_include_directories(unity PUBLIC "${CMAKE_CURRENT_LIST_DIR}/../external/unity")
|
||||
|
||||
set(TESTUTIL_SOURCES
|
||||
testutil.cpp
|
||||
testutil.hpp
|
||||
testutil_monitoring.cpp
|
||||
testutil_monitoring.hpp
|
||||
testutil_security.cpp
|
||||
testutil_security.hpp
|
||||
testutil_unity.cpp
|
||||
testutil_unity.hpp)
|
||||
if(BUILD_STATIC)
|
||||
add_library(testutil-static STATIC ${TESTUTIL_SOURCES})
|
||||
target_link_libraries(testutil-static libzmq-static ${OPTIONAL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} unity)
|
||||
endif()
|
||||
if(BUILD_SHARED)
|
||||
add_library(testutil STATIC ${TESTUTIL_SOURCES})
|
||||
target_link_libraries(testutil libzmq ${OPTIONAL_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT} unity)
|
||||
endif()
|
||||
if(BUILD_STATIC AND NOT BUILD_SHARED)
|
||||
# use testutil-static for both tests and unit tests
|
||||
set(TESTUTIL_LIB testutil-static)
|
||||
else()
|
||||
# use testutil for tests and testutil-static for unit tests
|
||||
set(TESTUTIL_LIB testutil)
|
||||
endif()
|
||||
|
||||
if(MSVC_VERSION LESS 1700)
|
||||
set_source_files_properties("${CMAKE_CURRENT_LIST_DIR}/../external/unity/unity.c" PROPERTIES LANGUAGE CXX)
|
||||
endif()
|
||||
|
||||
if(MSVC_VERSION LESS 1600)
|
||||
target_compile_definitions(unity PUBLIC "UNITY_EXCLUDE_STDINT_H")
|
||||
endif()
|
||||
|
||||
# add include dirs for all targets
|
||||
include_directories("${ZeroMQ_SOURCE_DIR}/../include" "${ZeroMQ_BINARY_DIR}")
|
||||
if(WIN32)
|
||||
add_definitions(-D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
endif()
|
||||
|
||||
# Does not work, times out every time
|
||||
if(WIN32)
|
||||
list(REMOVE_ITEM tests test_many_sockets)
|
||||
endif()
|
||||
|
||||
foreach(test ${tests})
|
||||
# target_sources not supported before CMake 3.1
|
||||
if(ZMQ_HAVE_CURVE AND ${test} MATCHES test_security_curve)
|
||||
add_executable(${test} ${test}.cpp "../src/tweetnacl.c" "../src/err.cpp" "../src/random.cpp" "../src/clock.cpp")
|
||||
else()
|
||||
add_executable(${test} ${test}.cpp)
|
||||
endif()
|
||||
target_link_libraries(${test} ${TESTUTIL_LIB})
|
||||
if(WIN32)
|
||||
# This is the output for Debug dynamic builds on Visual Studio 6.0 You should provide the correct directory, don't
|
||||
# know how to do it automatically
|
||||
find_path(LIBZMQ_PATH "libzmq.lib" PATHS "../bin/Win32/Debug/v120/dynamic")
|
||||
if(NOT ${LIBZMQ_PATH} STREQUAL "LIBZMQ_PATH-NOTFOUND")
|
||||
set_target_properties(${test} PROPERTIES LINK_FLAGS "/LIBPATH:${LIBZMQ_PATH}")
|
||||
endif()
|
||||
else()
|
||||
# per-test directories not generated on OS X / Darwin
|
||||
if(NOT ${CMAKE_CXX_COMPILER_ID} MATCHES "Clang.*")
|
||||
link_directories(${test} PRIVATE "${ZeroMQ_SOURCE_DIR}/../lib")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(RT_LIBRARY)
|
||||
target_link_libraries(${test} ${RT_LIBRARY})
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "QNX")
|
||||
target_link_libraries(${test} socket)
|
||||
target_link_libraries(${test} m)
|
||||
endif()
|
||||
|
||||
if(WIN32)
|
||||
add_test(
|
||||
NAME ${test}
|
||||
WORKING_DIRECTORY ${LIBRARY_OUTPUT_PATH}
|
||||
COMMAND ${test})
|
||||
else()
|
||||
if(${test} MATCHES "_cap_net_admin")
|
||||
add_test(NAME ${test} COMMAND sh -c "sudo ${CAPSH_PROGRAM} --caps=cap_net_admin+eip -- -c $<TARGET_FILE:${test}>")
|
||||
else()
|
||||
add_test(NAME ${test} COMMAND ${test})
|
||||
endif()
|
||||
endif()
|
||||
set_tests_properties(${test} PROPERTIES TIMEOUT 10)
|
||||
set_tests_properties(${test} PROPERTIES SKIP_RETURN_CODE 77)
|
||||
endforeach()
|
||||
|
||||
# override timeout for these tests
|
||||
set_tests_properties(test_heartbeats PROPERTIES TIMEOUT 60)
|
||||
|
||||
if(WIN32 AND ENABLE_DRAFTS)
|
||||
set_tests_properties(test_radio_dish PROPERTIES TIMEOUT 30)
|
||||
endif()
|
||||
|
||||
if(NOT CMAKE_SYSTEM_NAME MATCHES "Linux")
|
||||
if(ZMQ_HAVE_CURVE)
|
||||
set_tests_properties(test_security_curve PROPERTIES TIMEOUT 60)
|
||||
endif()
|
||||
# add additional required flags ZMQ_USE_TWEETNACL will already be defined when not using sodium
|
||||
if(ZMQ_HAVE_CURVE AND NOT ZMQ_USE_TWEETNACL)
|
||||
target_compile_definitions(test_security_curve PRIVATE "-DZMQ_USE_TWEETNACL")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_tests_properties(test_security_zap PROPERTIES TIMEOUT 60)
|
||||
set_tests_properties(test_reconnect_ivl PROPERTIES TIMEOUT 15)
|
||||
|
||||
# Check whether all tests in the current folder are present
|
||||
file(READ "${CMAKE_CURRENT_LIST_FILE}" CURRENT_LIST_FILE_CONTENT)
|
||||
file(GLOB ALL_TEST_SOURCES "test_*.cpp")
|
||||
foreach(TEST_SOURCE ${ALL_TEST_SOURCES})
|
||||
get_filename_component(TESTNAME "${TEST_SOURCE}" NAME_WE)
|
||||
string(REGEX MATCH "${TESTNAME}" MATCH_TESTNAME "${CURRENT_LIST_FILE_CONTENT}")
|
||||
if(NOT MATCH_TESTNAME)
|
||||
message(AUTHOR_WARNING "Test '${TESTNAME}' is not known to CTest.")
|
||||
endif()
|
||||
endforeach()
|
||||
45
tests/README.md
Normal file
45
tests/README.md
Normal file
@@ -0,0 +1,45 @@
|
||||
# Guidelines for tests
|
||||
|
||||
Write your test case as if you were writing clean application code. It should be safe to compile on all platforms.
|
||||
|
||||
Normally, you should only include the header files from the tests directory, e.g. `testutil.hpp`. Do not include files from src. Do not use the internal libzmq API. Tests for these should be placed in unittests instead.
|
||||
|
||||
If you must write non-portable code, wrap it in #ifdefs to ensure it will compile and run on all systems.
|
||||
|
||||
Note that testutil.hpp includes platform.h. Do not include it yourself as it changes location depending on the build system and OS.
|
||||
|
||||
All sources must contain the correct copyright header. Please copy from test_system.cpp if you're not certain.
|
||||
|
||||
Write new tests using the unity test framework. For an example, see test_sockopt_hwm.
|
||||
|
||||
Please use only ANSI C99 in test cases, no C++. This is to make the code more reusable.
|
||||
|
||||
On many slower environments, like embedded systems, VMs or CI systems, tests might
|
||||
fail because it takes time for sockets to settle after a connect. If you need
|
||||
to add a sleep, please be consistent with all the other tests and use:
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
# Ensure proper cleanup
|
||||
|
||||
If a test program uses unity, it will execute test cases individually, and will continue to run further test cases if an assertion in one test case fails. However, the test case that had an assertion failure will be aborted.
|
||||
To ensure that the resources of the test case are properly cleaned up, use appropriate setUp and tearDown functions. These are run by unity before each test case starts resp. after it ended (whether successfully or not).
|
||||
The same setUp and tearDown function is used for all test cases in a test program.
|
||||
|
||||
For many test cases, the following setUp and tearDown functions will be appropriate:
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
teardown_test_context ();
|
||||
}
|
||||
|
||||
Within the tests, do not use zmq_socket and zmq_close then but test_context_socket and test_context_socket_close instead. These functions will register/unregister sockets with the test_context.
|
||||
All sockets not closed when tearDown is executed, with forcibly be closed with linger=0 before terminating the context. Note that it is a misuse not to close sockets during successful test execution,
|
||||
and a warning will be output.
|
||||
|
||||
# Building tests in Windows
|
||||
|
||||
The tests are only built via cmake, not when using the checked-in Visual Studio .sln files.
|
||||
76
tests/test_abstract_ipc.cpp
Normal file
76
tests/test_abstract_ipc.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
static const char test_endpoint[] = "ipc://@tmp-tester";
|
||||
static const char test_endpoint_empty[] = "ipc://@";
|
||||
|
||||
void test_roundtrip ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, test_endpoint));
|
||||
|
||||
char endpoint[MAX_SOCKET_STRING];
|
||||
size_t size = sizeof (endpoint);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, endpoint, &size));
|
||||
TEST_ASSERT_EQUAL_INT (0, strncmp (endpoint, test_endpoint, size));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, test_endpoint));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void test_empty_abstract_name ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_bind (sb, test_endpoint_empty));
|
||||
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_roundtrip);
|
||||
RUN_TEST (test_empty_abstract_name);
|
||||
return UNITY_END ();
|
||||
}
|
||||
107
tests/test_address_tipc.cpp
Normal file
107
tests/test_address_tipc.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Copyright (c) 2007-2018 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_tipc_port_name_and_domain ()
|
||||
{
|
||||
// test Port Name addressing
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "tipc://{5560,0,0}"));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "tipc://{5560,0}@0.0.0"));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void test_tipc_port_identity ()
|
||||
{
|
||||
char endpoint[256];
|
||||
unsigned int z, c, n, ref;
|
||||
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
|
||||
// Test binding to random Port Identity and
|
||||
// test resolving assigned address, should return a properly formatted string
|
||||
bind_loopback_tipc (sb, endpoint, sizeof endpoint);
|
||||
|
||||
int rc = sscanf (&endpoint[0], "tipc://<%u.%u.%u:%u>", &z, &c, &n, &ref);
|
||||
TEST_ASSERT_EQUAL_INT (4, rc);
|
||||
|
||||
TEST_ASSERT_NOT_EQUAL_MESSAGE (
|
||||
0, ref, "tipc port number must not be 0 after random assignment");
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void test_tipc_bad_addresses ()
|
||||
{
|
||||
// Test Port Name addressing
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
|
||||
// Test binding to a fixed address, should fail
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_bind (sb, "tipc://<1.2.3:123123>"));
|
||||
|
||||
// Test connecting to random identity, should fail
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_connect (sb, "tipc://<*>"));
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
if (!is_tipc_available ()) {
|
||||
printf ("TIPC environment unavailable, skipping test\n");
|
||||
return 77;
|
||||
}
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_tipc_port_name_and_domain);
|
||||
RUN_TEST (test_tipc_port_identity);
|
||||
RUN_TEST (test_tipc_bad_addresses);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
71
tests/test_ancillaries.cpp
Normal file
71
tests/test_ancillaries.cpp
Normal file
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
* File for adding tests for ancillary API methods and other miscellaenous
|
||||
* API internals. Please ensure that when adding such tests into this file,
|
||||
* that they are short-lived so they do not trigger timeouts in the
|
||||
* CI build environments.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
void test_version ()
|
||||
{
|
||||
int major, minor, patch;
|
||||
|
||||
zmq_version (&major, &minor, &patch);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_VERSION_MAJOR, major);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_VERSION_MINOR, minor);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_VERSION_PATCH, patch);
|
||||
}
|
||||
|
||||
void test_strerrror ()
|
||||
{
|
||||
TEST_ASSERT_NOT_NULL (zmq_strerror (EINVAL));
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_version);
|
||||
RUN_TEST (test_strerrror);
|
||||
return UNITY_END ();
|
||||
}
|
||||
169
tests/test_app_meta.cpp
Normal file
169
tests/test_app_meta.cpp
Normal file
@@ -0,0 +1,169 @@
|
||||
/*
|
||||
Copyright (c) 2007-2018 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
#include <unity.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
void test_app_meta_reqrep ()
|
||||
{
|
||||
void *ctx;
|
||||
zmq_msg_t msg;
|
||||
void *rep_sock, *req_sock;
|
||||
char connect_address[MAX_SOCKET_STRING];
|
||||
const char *req_hello = "X-hello:hello";
|
||||
const char *req_connection = "X-connection:primary";
|
||||
const char *req_z85 = "X-bin:009c6";
|
||||
const char *rep_hello = "X-hello:world";
|
||||
const char *rep_connection = "X-connection:backup";
|
||||
const char *bad_strings[] = {
|
||||
":",
|
||||
"key:",
|
||||
":value",
|
||||
"keyvalue",
|
||||
"",
|
||||
"X-"
|
||||
"KeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKe"
|
||||
"yTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyT"
|
||||
"ooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyTooLongKeyToo"
|
||||
"LongKeyTooLongKeyTooLongKeyTooLongKeyTooLong:value"};
|
||||
|
||||
ctx = zmq_ctx_new ();
|
||||
rep_sock = zmq_socket (ctx, ZMQ_REP);
|
||||
TEST_ASSERT_NOT_NULL (rep_sock);
|
||||
req_sock = zmq_socket (ctx, ZMQ_REQ);
|
||||
TEST_ASSERT_NOT_NULL (req_sock);
|
||||
|
||||
int rc =
|
||||
zmq_setsockopt (rep_sock, ZMQ_METADATA, rep_hello, strlen (rep_hello));
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
int l = 0;
|
||||
rc = zmq_setsockopt (rep_sock, ZMQ_LINGER, &l, sizeof (l));
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
rc = zmq_setsockopt (rep_sock, ZMQ_METADATA, rep_connection,
|
||||
strlen (rep_connection));
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
for (int i = 0; i < 6; i++) {
|
||||
rc = zmq_setsockopt (rep_sock, ZMQ_METADATA, bad_strings[i],
|
||||
strlen (bad_strings[i]));
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
}
|
||||
|
||||
bind_loopback_ipv4 (rep_sock, connect_address, sizeof connect_address);
|
||||
|
||||
l = 0;
|
||||
rc = zmq_setsockopt (req_sock, ZMQ_LINGER, &l, sizeof (l));
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
rc = zmq_setsockopt (req_sock, ZMQ_METADATA, req_hello, strlen (req_hello));
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
rc = zmq_setsockopt (req_sock, ZMQ_METADATA, req_connection,
|
||||
strlen (req_connection));
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
rc = zmq_setsockopt (req_sock, ZMQ_METADATA, req_z85, strlen (req_z85));
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
rc = zmq_connect (req_sock, connect_address);
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
rc = zmq_msg_init_size (&msg, 1);
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
char *data = static_cast<char *> (zmq_msg_data (&msg));
|
||||
data[0] = 1;
|
||||
|
||||
rc = zmq_msg_send (&msg, req_sock, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
|
||||
rc = zmq_msg_init (&msg);
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
rc = zmq_msg_recv (&msg, rep_sock, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING ("hello", zmq_msg_gets (&msg, "X-hello"));
|
||||
TEST_ASSERT_EQUAL_STRING ("primary", zmq_msg_gets (&msg, "X-connection"));
|
||||
const char *const bindata = zmq_msg_gets (&msg, "X-bin");
|
||||
TEST_ASSERT_NOT_NULL (bindata);
|
||||
uint8_t rawdata[4];
|
||||
const uint8_t *const ret = zmq_z85_decode (rawdata, bindata);
|
||||
TEST_ASSERT_NOT_NULL (ret);
|
||||
TEST_ASSERT_EQUAL_UINT8 (0, rawdata[0]);
|
||||
TEST_ASSERT_EQUAL_UINT8 (1, rawdata[1]);
|
||||
TEST_ASSERT_EQUAL_UINT8 (2, rawdata[2]);
|
||||
TEST_ASSERT_EQUAL_UINT8 (3, rawdata[3]);
|
||||
|
||||
TEST_ASSERT_NULL (zmq_msg_gets (&msg, "X-foobar"));
|
||||
TEST_ASSERT_NULL (zmq_msg_gets (&msg, "foobar"));
|
||||
|
||||
rc = zmq_msg_send (&msg, rep_sock, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
|
||||
rc = zmq_msg_recv (&msg, req_sock, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING ("world", zmq_msg_gets (&msg, "X-hello"));
|
||||
TEST_ASSERT_EQUAL_STRING ("backup", zmq_msg_gets (&msg, "X-connection"));
|
||||
|
||||
rc = zmq_msg_close (&msg);
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
rc = zmq_close (req_sock);
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
rc = zmq_close (rep_sock);
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
|
||||
zmq_ctx_term (ctx);
|
||||
}
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_app_meta_reqrep);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
65
tests/test_atomics.cpp
Normal file
65
tests/test_atomics.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <unity.h>
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
void test ()
|
||||
{
|
||||
void *counter = zmq_atomic_counter_new ();
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_value (counter));
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_inc (counter));
|
||||
TEST_ASSERT_EQUAL_INT (1, zmq_atomic_counter_inc (counter));
|
||||
TEST_ASSERT_EQUAL_INT (2, zmq_atomic_counter_inc (counter));
|
||||
TEST_ASSERT_EQUAL_INT (3, zmq_atomic_counter_value (counter));
|
||||
TEST_ASSERT_EQUAL_INT (1, zmq_atomic_counter_dec (counter));
|
||||
TEST_ASSERT_EQUAL_INT (1, zmq_atomic_counter_dec (counter));
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_dec (counter));
|
||||
zmq_atomic_counter_set (counter, 2);
|
||||
TEST_ASSERT_EQUAL_INT (1, zmq_atomic_counter_dec (counter));
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_dec (counter));
|
||||
zmq_atomic_counter_destroy (&counter);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test);
|
||||
return UNITY_END ();
|
||||
}
|
||||
204
tests/test_base85.cpp
Normal file
204
tests/test_base85.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
Copyright (c) 2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
// Test vector: rfc.zeromq.org/spec:32/Z85
|
||||
void test__zmq_z85_encode__valid__success ()
|
||||
{
|
||||
static const size_t size = 8;
|
||||
static const size_t length = size * 5 / 4;
|
||||
static const uint8_t decoded[size] = {0x86, 0x4F, 0xD2, 0x6F,
|
||||
0xB5, 0x59, 0xF7, 0x5B};
|
||||
static const char expected[length + 1] = "HelloWorld";
|
||||
char out_encoded[length + 1] = {0};
|
||||
|
||||
errno = 0;
|
||||
TEST_ASSERT_NOT_NULL (zmq_z85_encode (out_encoded, decoded, size));
|
||||
TEST_ASSERT_EQUAL_STRING (expected, out_encoded);
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_errno ());
|
||||
}
|
||||
|
||||
// Buffer length must be evenly divisible by 4 or must fail with EINVAL.
|
||||
void test__zmq_z85_encode__invalid__failure (size_t size_)
|
||||
{
|
||||
errno = 0;
|
||||
TEST_ASSERT_NULL (zmq_z85_encode (NULL, NULL, size_));
|
||||
TEST_ASSERT_EQUAL_INT (EINVAL, zmq_errno ());
|
||||
}
|
||||
|
||||
// Test vector: rfc.zeromq.org/spec:32/Z85
|
||||
void test__zmq_z85_decode__valid__success ()
|
||||
{
|
||||
static const size_t size = 10 * 4 / 5;
|
||||
static const uint8_t expected[size] = {0x86, 0x4F, 0xD2, 0x6F,
|
||||
0xB5, 0x59, 0xF7, 0x5B};
|
||||
static const char *encoded = "HelloWorld";
|
||||
uint8_t out_decoded[size] = {0};
|
||||
|
||||
errno = 0;
|
||||
TEST_ASSERT_NOT_NULL (zmq_z85_decode (out_decoded, encoded));
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_errno ());
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY (expected, out_decoded, size);
|
||||
}
|
||||
|
||||
// Invalid input data must fail with EINVAL.
|
||||
template <size_t SIZE>
|
||||
void test__zmq_z85_decode__invalid__failure (const char (&encoded_)[SIZE])
|
||||
{
|
||||
uint8_t decoded[SIZE * 4 / 5 + 1];
|
||||
errno = 0;
|
||||
TEST_ASSERT_NULL (zmq_z85_decode (decoded, encoded_));
|
||||
TEST_ASSERT_EQUAL_INT (EINVAL, zmq_errno ());
|
||||
}
|
||||
|
||||
|
||||
// call zmq_z85_encode, then zmq_z85_decode, and compare the results with the original
|
||||
template <size_t SIZE>
|
||||
void test__zmq_z85_encode__zmq_z85_decode__roundtrip (
|
||||
const uint8_t (&test_data_)[SIZE])
|
||||
{
|
||||
char test_data_z85[SIZE * 5 / 4 + 1];
|
||||
const char *const res1 = zmq_z85_encode (test_data_z85, test_data_, SIZE);
|
||||
TEST_ASSERT_NOT_NULL (res1);
|
||||
|
||||
uint8_t test_data_decoded[SIZE];
|
||||
const uint8_t *const res2 =
|
||||
zmq_z85_decode (test_data_decoded, test_data_z85);
|
||||
TEST_ASSERT_NOT_NULL (res2);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY (test_data_, test_data_decoded, SIZE);
|
||||
}
|
||||
|
||||
// call zmq_z85_encode, then zmq_z85_decode, and compare the results with the original
|
||||
template <size_t SIZE>
|
||||
void test__zmq_z85_decode__zmq_z85_encode__roundtrip (
|
||||
const char (&test_data_)[SIZE])
|
||||
{
|
||||
const size_t decoded_size = (SIZE - 1) * 4 / 5;
|
||||
uint8_t test_data_decoded[decoded_size];
|
||||
const uint8_t *const res1 = zmq_z85_decode (test_data_decoded, test_data_);
|
||||
TEST_ASSERT_NOT_NULL (res1);
|
||||
|
||||
char test_data_z85[SIZE];
|
||||
const char *const res2 =
|
||||
zmq_z85_encode (test_data_z85, test_data_decoded, decoded_size);
|
||||
TEST_ASSERT_NOT_NULL (res2);
|
||||
|
||||
TEST_ASSERT_EQUAL_UINT8_ARRAY (test_data_, test_data_z85, SIZE);
|
||||
}
|
||||
|
||||
#define def_test__zmq_z85_basename(basename, name, param) \
|
||||
void test__zmq_z85_##basename##_##name () \
|
||||
{ \
|
||||
test__zmq_z85_##basename (param); \
|
||||
}
|
||||
|
||||
#define def_test__zmq_z85_encode__invalid__failure(name, param) \
|
||||
def_test__zmq_z85_basename (encode__invalid__failure, name, param)
|
||||
|
||||
def_test__zmq_z85_encode__invalid__failure (1, 1)
|
||||
def_test__zmq_z85_encode__invalid__failure (42, 42)
|
||||
|
||||
#define def_test__zmq_z85_decode__invalid__failure(name, param) \
|
||||
def_test__zmq_z85_basename (decode__invalid__failure, name, param)
|
||||
|
||||
// String length must be evenly divisible by 5 or must fail with EINVAL.
|
||||
def_test__zmq_z85_decode__invalid__failure (indivisble_by_5_multiple_chars,
|
||||
"01234567")
|
||||
def_test__zmq_z85_decode__invalid__failure (indivisble_by_5_one_char, "0")
|
||||
|
||||
// decode invalid data with the maximum representable value
|
||||
def_test__zmq_z85_decode__invalid__failure (max, "#####")
|
||||
|
||||
// decode invalid data with the minimum value beyond the limit
|
||||
// "%nSc0" is 0xffffffff
|
||||
def_test__zmq_z85_decode__invalid__failure (above_limit, "%nSc1")
|
||||
|
||||
// decode invalid data with an invalid character in the range of valid
|
||||
// characters
|
||||
def_test__zmq_z85_decode__invalid__failure (char_within, "####\0047")
|
||||
|
||||
// decode invalid data with an invalid character just below the range of valid
|
||||
// characters
|
||||
def_test__zmq_z85_decode__invalid__failure (char_adjacent_below, "####\0200")
|
||||
|
||||
// decode invalid data with an invalid character just above the range of valid
|
||||
// characters
|
||||
def_test__zmq_z85_decode__invalid__failure (char_adjacent_above, "####\0037")
|
||||
|
||||
#define def_test__encode__zmq_z85_decode__roundtrip(name, param) \
|
||||
def_test__zmq_z85_basename (encode__zmq_z85_decode__roundtrip, name, param)
|
||||
|
||||
const uint8_t test_data_min[] = {0x00, 0x00, 0x00, 0x00};
|
||||
const uint8_t test_data_max[] = {0xff, 0xff, 0xff, 0xff};
|
||||
|
||||
def_test__encode__zmq_z85_decode__roundtrip (min, test_data_min)
|
||||
def_test__encode__zmq_z85_decode__roundtrip (max, test_data_max)
|
||||
|
||||
#define def_test__decode__zmq_z85_encode__roundtrip(name, param) \
|
||||
def_test__zmq_z85_basename (decode__zmq_z85_encode__roundtrip, name, param)
|
||||
|
||||
const char test_data_regular[] = "r^/rM9M=rMToK)63O8dCvd9D<PY<7iGlC+{BiSnG";
|
||||
|
||||
def_test__decode__zmq_z85_encode__roundtrip (regular, test_data_regular)
|
||||
|
||||
int main ()
|
||||
{
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test__zmq_z85_encode__valid__success);
|
||||
RUN_TEST (test__zmq_z85_encode__invalid__failure_1);
|
||||
RUN_TEST (test__zmq_z85_encode__invalid__failure_42);
|
||||
|
||||
RUN_TEST (test__zmq_z85_decode__valid__success);
|
||||
RUN_TEST (
|
||||
test__zmq_z85_decode__invalid__failure_indivisble_by_5_multiple_chars);
|
||||
RUN_TEST (test__zmq_z85_decode__invalid__failure_indivisble_by_5_one_char);
|
||||
RUN_TEST (test__zmq_z85_decode__invalid__failure_max);
|
||||
RUN_TEST (test__zmq_z85_decode__invalid__failure_above_limit);
|
||||
RUN_TEST (test__zmq_z85_decode__invalid__failure_char_within);
|
||||
RUN_TEST (test__zmq_z85_decode__invalid__failure_char_adjacent_below);
|
||||
RUN_TEST (test__zmq_z85_decode__invalid__failure_char_adjacent_above);
|
||||
|
||||
RUN_TEST (test__zmq_z85_encode__zmq_z85_decode__roundtrip_min);
|
||||
RUN_TEST (test__zmq_z85_encode__zmq_z85_decode__roundtrip_max);
|
||||
|
||||
RUN_TEST (test__zmq_z85_decode__zmq_z85_encode__roundtrip_regular);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
63
tests/test_bind_after_connect_tcp.cpp
Normal file
63
tests/test_bind_after_connect_tcp.cpp
Normal file
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright (c) 2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_x ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_DEALER);
|
||||
void *sc = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, ENDPOINT_3));
|
||||
|
||||
send_string_expect_success (sc, "foobar", 0);
|
||||
send_string_expect_success (sc, "baz", 0);
|
||||
send_string_expect_success (sc, "buzz", 0);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, ENDPOINT_3));
|
||||
|
||||
recv_string_expect_success (sb, "foobar", 0);
|
||||
recv_string_expect_success (sb, "baz", 0);
|
||||
recv_string_expect_success (sb, "buzz", 0);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_x);
|
||||
return UNITY_END ();
|
||||
}
|
||||
150
tests/test_bind_curve_fuzzer.cpp
Normal file
150
tests/test_bind_curve_fuzzer.cpp
Normal file
@@ -0,0 +1,150 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_security.hpp"
|
||||
|
||||
// Test that the ZMTP engine handles invalid handshake when binding
|
||||
// https://rfc.zeromq.org/spec/37/
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *fixed_client_public =
|
||||
"{{k*81)yMWEF{/BxdMd[5RL^qRFxBgoL<8m.D^KD";
|
||||
const char *fixed_client_secret =
|
||||
"N?Gmik8R[2ACw{b7*[-$S6[4}aO#?DB?#=<OQPc7";
|
||||
const char *fixed_server_public =
|
||||
"3.9-xXwy{g*w72TP*3iB9IJJRxlBH<ufTAvPd2>C";
|
||||
const char *fixed_server_secret =
|
||||
"T}t5GLq%&Qm1)y3ywu-}pY3KEA//{^Ut!M1ut+B4";
|
||||
void *handler;
|
||||
void *zap_thread;
|
||||
void *server;
|
||||
void *server_mon;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
setup_test_context ();
|
||||
memcpy (valid_client_public, fixed_client_public, 41);
|
||||
setup_context_and_server_side (
|
||||
&handler, &zap_thread, &server, &server_mon, my_endpoint, &zap_handler,
|
||||
&socket_config_curve_server, (void *) fixed_server_secret);
|
||||
fd_t client = connect_socket (my_endpoint);
|
||||
|
||||
// If there is not enough data for a full greeting, just send what we can
|
||||
// Otherwise send greeting first, as expected by the protocol
|
||||
uint8_t buf[512];
|
||||
if (size >= 64) {
|
||||
send (client, (void *) data, 64, MSG_NOSIGNAL);
|
||||
data += 64;
|
||||
size -= 64;
|
||||
}
|
||||
recv (client, buf, 64, 0);
|
||||
// Then send HELLO and expect WELCOME if there's enough data
|
||||
if (size >= 202) {
|
||||
send (client, (void *) data, 202, MSG_NOSIGNAL);
|
||||
data += 202;
|
||||
size -= 202;
|
||||
recv (client, buf, 170, MSG_DONTWAIT);
|
||||
}
|
||||
// Then send READY and expect INITIATE if there's enough data
|
||||
if (size >= 301) {
|
||||
send (client, (void *) data, 301, MSG_NOSIGNAL);
|
||||
data += 301;
|
||||
size -= 301;
|
||||
recv (client, buf, 512, MSG_DONTWAIT);
|
||||
}
|
||||
msleep (250);
|
||||
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
|
||||
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
|
||||
sent = send (client, (const char *) data, size, MSG_NOSIGNAL);
|
||||
msleep (250);
|
||||
|
||||
// Drain the queue, if any
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
while (-1 != zmq_msg_recv (&msg, server, ZMQ_DONTWAIT)) {
|
||||
zmq_msg_close (&msg);
|
||||
zmq_msg_init (&msg);
|
||||
}
|
||||
|
||||
// A well-behaved client should work while the malformed data from the other
|
||||
// is being received
|
||||
curve_client_data_t curve_client_data = {
|
||||
fixed_server_public, fixed_client_public, fixed_client_secret};
|
||||
void *client_mon;
|
||||
void *client_good = create_and_connect_client (
|
||||
my_endpoint, socket_config_curve_client, &curve_client_data, &client_mon);
|
||||
|
||||
bounce (server, client_good);
|
||||
|
||||
close (client);
|
||||
test_context_socket_close_zero_linger (client_good);
|
||||
test_context_socket_close_zero_linger (client_mon);
|
||||
shutdown_context_and_server_side (zap_thread, server, server_mon, handler);
|
||||
teardown_test_context ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_bind_curve_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_bind_curve_fuzzer_seed_corpus", &data,
|
||||
&len, &num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_bind_curve_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
96
tests/test_bind_fuzzer.cpp
Normal file
96
tests/test_bind_fuzzer.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#ifndef PATH_MAX
|
||||
#define PATH_MAX 1024
|
||||
#endif
|
||||
|
||||
// Test that zmq_bind can handle malformed strings
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
// This test might create socket files, so move to /tmp to avoid clobbering
|
||||
// the working directory with random filenames
|
||||
char *pwd = (char *) malloc (PATH_MAX + 1);
|
||||
TEST_ASSERT_NOT_NULL (pwd);
|
||||
TEST_ASSERT_NOT_NULL (getcwd (pwd, PATH_MAX + 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (chdir ("/tmp"));
|
||||
|
||||
setup_test_context ();
|
||||
std::string my_endpoint (reinterpret_cast<const char *> (data), size);
|
||||
void *socket = test_context_socket (ZMQ_PUB);
|
||||
zmq_bind (socket, my_endpoint.c_str ());
|
||||
|
||||
test_context_socket_close_zero_linger (socket);
|
||||
teardown_test_context ();
|
||||
TEST_ASSERT_SUCCESS_ERRNO (chdir (pwd));
|
||||
free (pwd);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_bind_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_bind_fuzzer_seed_corpus", &data, &len,
|
||||
&num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_bind_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
113
tests/test_bind_null_fuzzer.cpp
Normal file
113
tests/test_bind_null_fuzzer.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
// Test that the ZMTP engine handles invalid handshake when binding
|
||||
// https://rfc.zeromq.org/spec/37/
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
setup_test_context ();
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
void *server = test_context_socket (ZMQ_PUB);
|
||||
// As per API by default there's no limit to the size of a message,
|
||||
// but the sanitizer allocator will barf over a gig or so
|
||||
int64_t max_msg_size = 64 * 1024 * 1024;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));
|
||||
fd_t client = connect_socket (my_endpoint);
|
||||
|
||||
void *client_good = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client_good, ZMQ_SUBSCRIBE, "", 0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_good, my_endpoint));
|
||||
|
||||
// If there is not enough data for a full greeting, just send what we can
|
||||
// Otherwise send greeting first, as expected by the protocol
|
||||
uint8_t buf[64];
|
||||
if (size >= 64) {
|
||||
send (client, (void *) data, 64, MSG_NOSIGNAL);
|
||||
data += 64;
|
||||
size -= 64;
|
||||
}
|
||||
recv (client, buf, 64, 0);
|
||||
msleep (250);
|
||||
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
|
||||
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
|
||||
sent = send (client, (const char *) data, size, MSG_NOSIGNAL);
|
||||
msleep (250);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (6, zmq_send_const (server, "HELLO", 6, 0));
|
||||
TEST_ASSERT_EQUAL_INT (6, zmq_recv (client_good, buf, 6, 0));
|
||||
|
||||
close (client);
|
||||
test_context_socket_close_zero_linger (client_good);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
teardown_test_context ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_bind_null_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_bind_null_fuzzer_seed_corpus", &data,
|
||||
&len, &num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_bind_null_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
56
tests/test_bind_src_address.cpp
Normal file
56
tests/test_bind_src_address.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_x ()
|
||||
{
|
||||
void *sock = test_context_socket (ZMQ_PUB);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (sock, "tcp://127.0.0.1:0;localhost:1234"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (sock, "tcp://localhost:5555;localhost:1235"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (sock, "tcp://lo:5555;localhost:1235"));
|
||||
|
||||
test_context_socket_close (sock);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_x);
|
||||
return UNITY_END ();
|
||||
}
|
||||
132
tests/test_bind_stream_fuzzer.cpp
Normal file
132
tests/test_bind_stream_fuzzer.cpp
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
// Test that the ZMTP engine handles invalid handshake when binding
|
||||
// https://rfc.zeromq.org/spec/37/
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
setup_test_context ();
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
void *server = test_context_socket (ZMQ_STREAM);
|
||||
// As per API by default there's no limit to the size of a message,
|
||||
// but the sanitizer allocator will barf over a gig or so
|
||||
int64_t max_msg_size = 64 * 1024 * 1024;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));
|
||||
fd_t client = connect_socket (my_endpoint);
|
||||
|
||||
// If there is not enough data for a full greeting, just send what we can
|
||||
// Otherwise send greeting first, as expected by the protocol
|
||||
uint8_t buf[64];
|
||||
if (size >= 64) {
|
||||
send (client, (void *) data, 64, MSG_NOSIGNAL);
|
||||
data += 64;
|
||||
size -= 64;
|
||||
}
|
||||
recv (client, buf, 64, MSG_DONTWAIT);
|
||||
msleep (250);
|
||||
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
|
||||
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
|
||||
sent = send (client, (const char *) data, size, MSG_NOSIGNAL);
|
||||
msleep (250);
|
||||
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
while (-1 != zmq_msg_recv (&msg, server, ZMQ_DONTWAIT)) {
|
||||
zmq_msg_close (&msg);
|
||||
zmq_msg_init (&msg);
|
||||
}
|
||||
|
||||
void *client_good = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_good, my_endpoint));
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (6, zmq_send_const (client_good, "HELLO", 6, 0));
|
||||
zmq_msg_t routing_id;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&routing_id));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&routing_id, server, 0));
|
||||
TEST_ASSERT_TRUE (zmq_msg_more (&routing_id));
|
||||
char const *peer_address = zmq_msg_gets (&routing_id, "Peer-Address");
|
||||
zmq_msg_close (&routing_id);
|
||||
TEST_ASSERT_NOT_NULL (peer_address);
|
||||
TEST_ASSERT_EQUAL_STRING ("127.0.0.1", peer_address);
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, buf, 64, 0)));
|
||||
zmq_msg_init (&msg);
|
||||
while (-1 != zmq_msg_recv (&msg, server, ZMQ_DONTWAIT)) {
|
||||
zmq_msg_close (&msg);
|
||||
zmq_msg_init (&msg);
|
||||
}
|
||||
|
||||
close (client);
|
||||
test_context_socket_close_zero_linger (client_good);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
teardown_test_context ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_bind_stream_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_bind_stream_fuzzer_seed_corpus",
|
||||
&data, &len, &num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_bind_stream_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
125
tests/test_bind_ws_fuzzer.cpp
Normal file
125
tests/test_bind_ws_fuzzer.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
// Test that the ZMTP WebSocket engine handles invalid handshake when connecting
|
||||
// https://rfc.zeromq.org/spec/45/
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
setup_test_context ();
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
size_t my_endpoint_size = sizeof (my_endpoint);
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
// As per API by default there's no limit to the size of a message,
|
||||
// but the sanitizer allocator will barf over a gig or so
|
||||
int64_t max_msg_size = 64 * 1024 * 1024;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, "ws://127.0.0.1:*"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (server, ZMQ_LAST_ENDPOINT,
|
||||
my_endpoint, &my_endpoint_size));
|
||||
// Remove trailing /
|
||||
my_endpoint[my_endpoint_size - 2] = '\0';
|
||||
fd_t client = connect_socket (my_endpoint, AF_INET, IPPROTO_WS);
|
||||
|
||||
void *client_good = test_context_socket (ZMQ_DEALER);
|
||||
my_endpoint[my_endpoint_size - 2] = '/';
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_good, my_endpoint));
|
||||
|
||||
// If there is not enough data for a full handshake, just send what we can
|
||||
// Otherwise send websocket handshake first, as expected by the protocol
|
||||
uint8_t buf[256];
|
||||
if (size >= 192) {
|
||||
send (client, (void *) data, 192, MSG_NOSIGNAL);
|
||||
data += 192;
|
||||
size -= 192;
|
||||
}
|
||||
recv (client, buf, 256, MSG_DONTWAIT);
|
||||
msleep (250);
|
||||
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
|
||||
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
|
||||
sent = send (client, (const char *) data, size, MSG_NOSIGNAL);
|
||||
msleep (250);
|
||||
recv (client, buf, 256, MSG_DONTWAIT);
|
||||
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
while (-1 != zmq_msg_recv (&msg, server, ZMQ_DONTWAIT)) {
|
||||
zmq_msg_close (&msg);
|
||||
zmq_msg_init (&msg);
|
||||
}
|
||||
|
||||
send_string_expect_success (client_good, "abc", 0);
|
||||
recv_string_expect_success (server, "abc", 0);
|
||||
|
||||
close (client);
|
||||
test_context_socket_close_zero_linger (client_good);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
teardown_test_context ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_bind_ws_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_bind_ws_fuzzer_seed_corpus", &data,
|
||||
&len, &num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_bind_ws_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
58
tests/test_busy_poll.cpp
Normal file
58
tests/test_busy_poll.cpp
Normal file
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
Copyright (c) 2007-2021 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_busy_poll ()
|
||||
{
|
||||
// Create a socket
|
||||
void *socket = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
// set socket ZMQ_BUSY_POLL options
|
||||
int busy_poll = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (socket, ZMQ_BUSY_POLL, &busy_poll, sizeof (int)));
|
||||
|
||||
// bind socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (socket, "tcp://127.0.0.1:*"));
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_busy_poll);
|
||||
return UNITY_END ();
|
||||
}
|
||||
99
tests/test_capabilities.cpp
Normal file
99
tests/test_capabilities.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
void test_capabilities ()
|
||||
{
|
||||
#if defined(ZMQ_HAVE_IPC)
|
||||
TEST_ASSERT_TRUE (zmq_has ("ipc"));
|
||||
#else
|
||||
TEST_ASSERT_TRUE (!zmq_has ("ipc"));
|
||||
#endif
|
||||
|
||||
#if defined(ZMQ_HAVE_OPENPGM)
|
||||
TEST_ASSERT_TRUE (zmq_has ("pgm"));
|
||||
#else
|
||||
TEST_ASSERT_TRUE (!zmq_has ("pgm"));
|
||||
#endif
|
||||
|
||||
#if defined(ZMQ_HAVE_TIPC)
|
||||
TEST_ASSERT_TRUE (zmq_has ("tipc"));
|
||||
#else
|
||||
TEST_ASSERT_TRUE (!zmq_has ("tipc"));
|
||||
#endif
|
||||
|
||||
#if defined(ZMQ_HAVE_NORM)
|
||||
TEST_ASSERT_TRUE (zmq_has ("norm"));
|
||||
#else
|
||||
TEST_ASSERT_TRUE (!zmq_has ("norm"));
|
||||
#endif
|
||||
|
||||
#if defined(ZMQ_HAVE_CURVE)
|
||||
TEST_ASSERT_TRUE (zmq_has ("curve"));
|
||||
#else
|
||||
TEST_ASSERT_TRUE (!zmq_has ("curve"));
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LIBGSSAPI_KRB5)
|
||||
TEST_ASSERT_TRUE (zmq_has ("gssapi"));
|
||||
#else
|
||||
TEST_ASSERT_TRUE (!zmq_has ("gssapi"));
|
||||
#endif
|
||||
|
||||
#if defined(ZMQ_HAVE_VMCI)
|
||||
TEST_ASSERT_TRUE (zmq_has ("vmci"));
|
||||
#else
|
||||
TEST_ASSERT_TRUE (!zmq_has ("vmci"));
|
||||
#endif
|
||||
|
||||
#if defined(ZMQ_BUILD_DRAFT_API)
|
||||
TEST_ASSERT_TRUE (zmq_has ("draft"));
|
||||
#else
|
||||
TEST_ASSERT_TRUE (!zmq_has ("draft"));
|
||||
#endif
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_capabilities);
|
||||
return UNITY_END ();
|
||||
}
|
||||
81
tests/test_channel.cpp
Normal file
81
tests/test_channel.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright (c) 2007-2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <unity.h>
|
||||
|
||||
void *sb;
|
||||
void *sc;
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
|
||||
sb = test_context_socket (ZMQ_CHANNEL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "inproc://a"));
|
||||
|
||||
sc = test_context_socket (ZMQ_CHANNEL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "inproc://a"));
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
|
||||
teardown_test_context ();
|
||||
}
|
||||
|
||||
void test_roundtrip ()
|
||||
{
|
||||
send_string_expect_success (sb, "HELLO", 0);
|
||||
recv_string_expect_success (sc, "HELLO", 0);
|
||||
|
||||
send_string_expect_success (sc, "WORLD", 0);
|
||||
recv_string_expect_success (sb, "WORLD", 0);
|
||||
}
|
||||
|
||||
void test_sndmore_fails ()
|
||||
{
|
||||
int rc = zmq_send (sc, "X", 1, ZMQ_SNDMORE);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (EINVAL, errno);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_roundtrip);
|
||||
RUN_TEST (test_sndmore_fails);
|
||||
return UNITY_END ();
|
||||
}
|
||||
135
tests/test_client_server.cpp
Normal file
135
tests/test_client_server.cpp
Normal file
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void create_inproc_client_server_pair (void **server_, void **client_)
|
||||
{
|
||||
*server_ = test_context_socket (ZMQ_SERVER);
|
||||
*client_ = test_context_socket (ZMQ_CLIENT);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_bind (*server_, "inproc://test-client-server"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (*client_, "inproc://test-client-server"));
|
||||
}
|
||||
|
||||
void send_sndmore_expect_failure (void *socket_)
|
||||
{
|
||||
int rc = zmq_send (socket_, "X", 1, ZMQ_SNDMORE);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (EINVAL, errno);
|
||||
}
|
||||
|
||||
void test_client_sndmore_fails ()
|
||||
{
|
||||
void *server, *client;
|
||||
create_inproc_client_server_pair (&server, &client);
|
||||
|
||||
send_sndmore_expect_failure (client);
|
||||
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (client);
|
||||
}
|
||||
|
||||
void test_server_sndmore_fails ()
|
||||
{
|
||||
void *server, *client;
|
||||
create_inproc_client_server_pair (&server, &client);
|
||||
|
||||
send_sndmore_expect_failure (server);
|
||||
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (client);
|
||||
}
|
||||
|
||||
void test_routing_id ()
|
||||
{
|
||||
void *server, *client;
|
||||
create_inproc_client_server_pair (&server, &client);
|
||||
|
||||
send_string_expect_success (client, "X", 0);
|
||||
|
||||
uint32_t routing_id;
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
|
||||
int rc = TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, server, 0));
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
|
||||
routing_id = zmq_msg_routing_id (&msg);
|
||||
TEST_ASSERT_NOT_EQUAL (0, routing_id);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
}
|
||||
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));
|
||||
|
||||
char *data = static_cast<char *> (zmq_msg_data (&msg));
|
||||
data[0] = 2;
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_set_routing_id (&msg, routing_id));
|
||||
|
||||
int rc = zmq_msg_send (&msg, server, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
}
|
||||
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
|
||||
int rc = zmq_msg_recv (&msg, client, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
|
||||
routing_id = zmq_msg_routing_id (&msg);
|
||||
TEST_ASSERT_EQUAL_UINT32 (0, routing_id);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
}
|
||||
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (client);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_client_sndmore_fails);
|
||||
RUN_TEST (test_server_sndmore_fails);
|
||||
RUN_TEST (test_routing_id);
|
||||
return UNITY_END ();
|
||||
}
|
||||
76
tests/test_conflate.cpp
Normal file
76
tests/test_conflate.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_conflate ()
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
int rc;
|
||||
|
||||
void *s_in = test_context_socket (ZMQ_PULL);
|
||||
|
||||
int conflate = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (s_in, ZMQ_CONFLATE, &conflate, sizeof (conflate)));
|
||||
bind_loopback_ipv4 (s_in, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
void *s_out = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (s_out, my_endpoint));
|
||||
|
||||
int message_count = 20;
|
||||
for (int j = 0; j < message_count; ++j) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_send (s_out, (void *) &j, sizeof (int), 0));
|
||||
}
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
int payload_recved = 0;
|
||||
rc = TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_recv (s_in, (void *) &payload_recved, sizeof (int), 0));
|
||||
TEST_ASSERT_GREATER_THAN_INT (0, rc);
|
||||
TEST_ASSERT_EQUAL_INT (message_count - 1, payload_recved);
|
||||
|
||||
test_context_socket_close (s_in);
|
||||
test_context_socket_close (s_out);
|
||||
}
|
||||
|
||||
int main (int, char *[])
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_conflate);
|
||||
return UNITY_END ();
|
||||
}
|
||||
139
tests/test_connect_curve_fuzzer.cpp
Normal file
139
tests/test_connect_curve_fuzzer.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_security.hpp"
|
||||
|
||||
// Test that the ZMTP engine handles invalid handshake when connecting
|
||||
// https://rfc.zeromq.org/spec/37/
|
||||
// https://rfc.zeromq.org/spec/26/
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
const char *fixed_client_public =
|
||||
"{{k*81)yMWEF{/BxdMd[5RL^qRFxBgoL<8m.D^KD";
|
||||
const char *fixed_client_secret =
|
||||
"N?Gmik8R[2ACw{b7*[-$S6[4}aO#?DB?#=<OQPc7";
|
||||
const char *fixed_server_public =
|
||||
"3.9-xXwy{g*w72TP*3iB9IJJRxlBH<ufTAvPd2>C";
|
||||
|
||||
setup_test_context ();
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
fd_t server = bind_socket_resolve_port ("127.0.0.1", "0", my_endpoint);
|
||||
|
||||
curve_client_data_t curve_client_data = {
|
||||
fixed_server_public, fixed_client_public, fixed_client_secret};
|
||||
void *client_mon;
|
||||
void *client = create_and_connect_client (
|
||||
my_endpoint, socket_config_curve_client, &curve_client_data, &client_mon);
|
||||
|
||||
fd_t server_accept =
|
||||
TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));
|
||||
|
||||
// If there is not enough data for a full greeting, just send what we can
|
||||
// Otherwise send greeting first, as expected by the protocol
|
||||
uint8_t buf[512];
|
||||
if (size >= 64) {
|
||||
send (server_accept, (void *) data, 64, MSG_NOSIGNAL);
|
||||
data += 64;
|
||||
size -= 64;
|
||||
}
|
||||
recv (server_accept, buf, 64, 0);
|
||||
// Then expect HELLO and send WELCOME if there's enough data
|
||||
if (size >= 170) {
|
||||
recv (server_accept, buf, 202, 0);
|
||||
send (server_accept, (void *) data, 170, MSG_NOSIGNAL);
|
||||
data += 170;
|
||||
size -= 170;
|
||||
}
|
||||
// Then expect INITIATE and send READY if there's enough data
|
||||
if (size >= 72) {
|
||||
recv (server_accept, buf, 512, 0);
|
||||
send (server_accept, (void *) data, 72, MSG_NOSIGNAL);
|
||||
data += 72;
|
||||
size -= 72;
|
||||
}
|
||||
msleep (250);
|
||||
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
|
||||
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
|
||||
sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);
|
||||
recv (server_accept, buf, 512, MSG_DONTWAIT);
|
||||
msleep (250);
|
||||
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT)) {
|
||||
zmq_msg_close (&msg);
|
||||
zmq_msg_init (&msg);
|
||||
}
|
||||
|
||||
close (server_accept);
|
||||
close (server);
|
||||
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (client_mon);
|
||||
teardown_test_context ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_connect_curve_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_connect_curve_fuzzer_seed_corpus",
|
||||
&data, &len, &num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_connect_curve_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
246
tests/test_connect_delay_tipc.cpp
Normal file
246
tests/test_connect_delay_tipc.cpp
Normal file
@@ -0,0 +1,246 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
#include "testutil_security.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_send_one_connected_one_unconnected ()
|
||||
{
|
||||
int val;
|
||||
// TEST 1.
|
||||
// First we're going to attempt to send messages to two
|
||||
// pipes, one connected, the other not. We should see
|
||||
// the PUSH load balancing to both pipes, and hence half
|
||||
// of the messages getting queued, as connect() creates a
|
||||
// pipe immediately.
|
||||
|
||||
void *to = test_context_socket (ZMQ_PULL);
|
||||
int timeout = 5000;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_LINGER, &timeout, sizeof (timeout)));
|
||||
|
||||
// Bind the one valid receiver
|
||||
val = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_LINGER, &val, sizeof (val)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (to, "tipc://{6555,0,0}"));
|
||||
|
||||
// Create a socket pushing to two endpoints - only 1 message should arrive.
|
||||
void *from = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
val = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (from, ZMQ_LINGER, &val, sizeof (val)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (from, ZMQ_LINGER, &timeout, sizeof (timeout)));
|
||||
// This pipe will not connect
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, "tipc://{5556,0}@0.0.0"));
|
||||
// This pipe will
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, "tipc://{6555,0}@0.0.0"));
|
||||
|
||||
// We send 10 messages, 5 should just get stuck in the queue
|
||||
// for the not-yet-connected pipe
|
||||
const int send_count = 10;
|
||||
for (int i = 0; i < send_count; ++i) {
|
||||
send_string_expect_success (from, "Hello", 0);
|
||||
}
|
||||
|
||||
// We now consume from the connected pipe
|
||||
// - we should see just 5
|
||||
timeout = SETTLE_TIME;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
|
||||
|
||||
int seen = 0;
|
||||
while (true) {
|
||||
char buffer[16];
|
||||
int rc = zmq_recv (to, &buffer, sizeof (buffer), 0);
|
||||
if (rc == -1) {
|
||||
TEST_ASSERT_EQUAL_INT (EAGAIN, zmq_errno ());
|
||||
break; // Break when we didn't get a message
|
||||
}
|
||||
seen++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT (send_count / 2, seen);
|
||||
|
||||
test_context_socket_close (from);
|
||||
test_context_socket_close (to);
|
||||
}
|
||||
|
||||
void test_send_one_connected_one_unconnected_with_delay ()
|
||||
{
|
||||
int val;
|
||||
|
||||
// TEST 2
|
||||
// This time we will do the same thing, connect two pipes,
|
||||
// one of which will succeed in connecting to a bound
|
||||
// receiver, the other of which will fail. However, we will
|
||||
// also set the delay attach on connect flag, which should
|
||||
// cause the pipe attachment to be delayed until the connection
|
||||
// succeeds.
|
||||
|
||||
// Bind the valid socket
|
||||
void *to = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (to, "tipc://{5560,0,0}"));
|
||||
int timeout = 5000;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_LINGER, &timeout, sizeof (timeout)));
|
||||
|
||||
val = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_LINGER, &val, sizeof (val)));
|
||||
|
||||
// Create a socket pushing to two endpoints - all messages should arrive.
|
||||
void *from = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
val = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (from, ZMQ_LINGER, &val, sizeof (val)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (from, ZMQ_LINGER, &timeout, sizeof (timeout)));
|
||||
|
||||
// Set the key flag
|
||||
val = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (from, ZMQ_DELAY_ATTACH_ON_CONNECT, &val, sizeof (val)));
|
||||
|
||||
// Connect to the invalid socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, "tipc://{5561,0}@0.0.0"));
|
||||
// Connect to the valid socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, "tipc://{5560,0}@0.0.0"));
|
||||
|
||||
// Send 10 messages, all should be routed to the connected pipe
|
||||
const int send_count = 10;
|
||||
for (int i = 0; i < send_count; ++i) {
|
||||
send_string_expect_success (from, "Hello", 0);
|
||||
}
|
||||
timeout = SETTLE_TIME;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
|
||||
|
||||
int seen = 0;
|
||||
while (true) {
|
||||
char buffer[16];
|
||||
int rc = zmq_recv (to, &buffer, sizeof (buffer), 0);
|
||||
if (rc == -1) {
|
||||
TEST_ASSERT_EQUAL_INT (EAGAIN, zmq_errno ());
|
||||
break; // Break when we didn't get a message
|
||||
}
|
||||
seen++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT (send_count, seen);
|
||||
|
||||
test_context_socket_close (from);
|
||||
test_context_socket_close (to);
|
||||
}
|
||||
|
||||
void test_send_disconnected_with_delay ()
|
||||
{
|
||||
// TEST 3
|
||||
// This time we want to validate that the same blocking behaviour
|
||||
// occurs with an existing connection that is broken. We will send
|
||||
// messages to a connected pipe, disconnect and verify the messages
|
||||
// block. Then we reconnect and verify messages flow again.
|
||||
void *backend = test_context_socket (ZMQ_DEALER);
|
||||
void *frontend = test_context_socket (ZMQ_DEALER);
|
||||
void *monitor = test_context_socket (ZMQ_PAIR);
|
||||
int rc;
|
||||
int zero = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (backend, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (frontend, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (frontend, "inproc://monitor",
|
||||
ZMQ_EVENT_DISCONNECTED));
|
||||
int timeout = 5000;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (backend, ZMQ_LINGER, &timeout, sizeof (timeout)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (frontend, ZMQ_LINGER, &timeout, sizeof (timeout)));
|
||||
|
||||
// Frontend connects to backend using DELAY_ATTACH_ON_CONNECT
|
||||
int on = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (frontend, ZMQ_DELAY_ATTACH_ON_CONNECT, &on, sizeof (on)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, "tipc://{5560,0,0}"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (monitor, "inproc://monitor"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (frontend, "tipc://{5560,0}@0.0.0"));
|
||||
|
||||
// Ping backend to frontend so we know when the connection is up
|
||||
send_string_expect_success (backend, "Hello", 0);
|
||||
recv_string_expect_success (frontend, "Hello", 0);
|
||||
|
||||
// Send message from frontend to backend
|
||||
send_string_expect_success (frontend, "Hello", ZMQ_DONTWAIT);
|
||||
|
||||
test_context_socket_close (backend);
|
||||
|
||||
// Wait for disconnect to happen
|
||||
expect_monitor_event (monitor, ZMQ_EVENT_DISCONNECTED);
|
||||
|
||||
// Send a message, might succeed depending on scheduling of the I/O thread
|
||||
do {
|
||||
rc = zmq_send (frontend, "Hello", 5, ZMQ_DONTWAIT);
|
||||
TEST_ASSERT_TRUE (rc == 5 || (rc == -1 && zmq_errno () == EAGAIN));
|
||||
} while (rc == 5);
|
||||
|
||||
// Recreate backend socket
|
||||
backend = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (backend, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, "tipc://{5560,0,0}"));
|
||||
|
||||
// Ping backend to frontend so we know when the connection is up
|
||||
send_string_expect_success (backend, "Hello", 0);
|
||||
recv_string_expect_success (frontend, "Hello", 0);
|
||||
|
||||
// After the reconnect, should succeed
|
||||
send_string_expect_success (frontend, "Hello", ZMQ_DONTWAIT);
|
||||
|
||||
test_context_socket_close (monitor);
|
||||
test_context_socket_close (backend);
|
||||
test_context_socket_close (frontend);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
if (!is_tipc_available ()) {
|
||||
printf ("TIPC environment unavailable, skipping test\n");
|
||||
return 77;
|
||||
}
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_send_one_connected_one_unconnected);
|
||||
RUN_TEST (test_send_one_connected_one_unconnected_with_delay);
|
||||
RUN_TEST (test_send_disconnected_with_delay);
|
||||
return UNITY_END ();
|
||||
}
|
||||
83
tests/test_connect_fuzzer.cpp
Normal file
83
tests/test_connect_fuzzer.cpp
Normal file
@@ -0,0 +1,83 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
// Test that zmq_connect can handle malformed strings
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
setup_test_context ();
|
||||
std::string my_endpoint (reinterpret_cast<const char *> (data), size);
|
||||
void *socket = test_context_socket (ZMQ_PUB);
|
||||
zmq_connect (socket, my_endpoint.c_str ());
|
||||
|
||||
test_context_socket_close_zero_linger (socket);
|
||||
teardown_test_context ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_connect_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_connect_fuzzer_seed_corpus", &data,
|
||||
&len, &num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_connect_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
118
tests/test_connect_null_fuzzer.cpp
Normal file
118
tests/test_connect_null_fuzzer.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
// Test that the ZMTP engine handles invalid handshake when connecting
|
||||
// https://rfc.zeromq.org/spec/37/
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
setup_test_context ();
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
fd_t server = bind_socket_resolve_port ("127.0.0.1", "0", my_endpoint);
|
||||
|
||||
void *client = test_context_socket (ZMQ_SUB);
|
||||
// As per API by default there's no limit to the size of a message,
|
||||
// but the sanitizer allocator will barf over a gig or so
|
||||
int64_t max_msg_size = 64 * 1024 * 1024;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_SUBSCRIBE, "", 0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
fd_t server_accept =
|
||||
TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));
|
||||
|
||||
// If there is not enough data for a full greeting, just send what we can
|
||||
// Otherwise send greeting first, as expected by the protocol
|
||||
uint8_t buf[64];
|
||||
if (size >= 64) {
|
||||
send (server_accept, (void *) data, 64, MSG_NOSIGNAL);
|
||||
data += 64;
|
||||
size -= 64;
|
||||
}
|
||||
recv (server_accept, buf, 64, 0);
|
||||
msleep (250);
|
||||
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
|
||||
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
|
||||
sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);
|
||||
msleep (250);
|
||||
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT)) {
|
||||
zmq_msg_close (&msg);
|
||||
zmq_msg_init (&msg);
|
||||
}
|
||||
|
||||
close (server_accept);
|
||||
close (server);
|
||||
|
||||
test_context_socket_close_zero_linger (client);
|
||||
teardown_test_context ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_connect_null_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_connect_null_fuzzer_seed_corpus",
|
||||
&data, &len, &num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_connect_null_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
104
tests/test_connect_resolve.cpp
Normal file
104
tests/test_connect_resolve.cpp
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <unity.h>
|
||||
|
||||
void *sock;
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
sock = test_context_socket (ZMQ_PUB);
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
test_context_socket_close (sock);
|
||||
sock = NULL;
|
||||
teardown_test_context ();
|
||||
}
|
||||
|
||||
void test_hostname_ipv4 ()
|
||||
{
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sock, "tcp://localhost:1234"));
|
||||
}
|
||||
|
||||
void test_loopback_ipv6 ()
|
||||
{
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sock, "tcp://[::1]:1234"));
|
||||
}
|
||||
|
||||
void test_invalid_service_fails ()
|
||||
{
|
||||
int rc = zmq_connect (sock, "tcp://localhost:invalid");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
}
|
||||
|
||||
void test_hostname_with_spaces_fails ()
|
||||
{
|
||||
int rc = zmq_connect (sock, "tcp://in val id:1234");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
}
|
||||
|
||||
void test_no_hostname_fails ()
|
||||
{
|
||||
int rc = zmq_connect (sock, "tcp://");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
}
|
||||
|
||||
void test_x ()
|
||||
{
|
||||
int rc = zmq_connect (sock, "tcp://192.168.0.200:*");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
}
|
||||
|
||||
void test_invalid_proto_fails ()
|
||||
{
|
||||
int rc = zmq_connect (sock, "invalid://localhost:1234");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (EPROTONOSUPPORT, errno);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_hostname_ipv4);
|
||||
RUN_TEST (test_loopback_ipv6);
|
||||
RUN_TEST (test_hostname_with_spaces_fails);
|
||||
RUN_TEST (test_no_hostname_fails);
|
||||
RUN_TEST (test_invalid_service_fails);
|
||||
RUN_TEST (test_invalid_proto_fails);
|
||||
return UNITY_END ();
|
||||
}
|
||||
252
tests/test_connect_rid.cpp
Normal file
252
tests/test_connect_rid.cpp
Normal file
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
const char *rconn1routing_id = "conn1";
|
||||
const char *x_routing_id = "X";
|
||||
const char *y_routing_id = "Y";
|
||||
const char *z_routing_id = "Z";
|
||||
|
||||
void test_stream_2_stream ()
|
||||
{
|
||||
char buff[256];
|
||||
const char msg[] = "hi 1";
|
||||
const int disabled = 0;
|
||||
const int zero = 0;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
// Set up listener STREAM.
|
||||
void *rbind = test_context_socket (ZMQ_STREAM);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (rbind, ZMQ_STREAM_NOTIFY, &disabled, sizeof (disabled)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (rbind, ZMQ_LINGER, &zero, sizeof zero));
|
||||
bind_loopback_ipv4 (rbind, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
// Set up connection stream.
|
||||
void *rconn1 = test_context_socket (ZMQ_STREAM);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (rconn1, ZMQ_LINGER, &zero, sizeof zero));
|
||||
|
||||
// Do the connection.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID,
|
||||
rconn1routing_id,
|
||||
strlen (rconn1routing_id)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, my_endpoint));
|
||||
|
||||
/* Uncomment to test assert on duplicate routing id.
|
||||
// Test duplicate connect attempt.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, rconn1routing_id, strlen(rconn1routing_id)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, bindip));
|
||||
*/
|
||||
// Send data to the bound stream.
|
||||
send_string_expect_success (rconn1, rconn1routing_id, ZMQ_SNDMORE);
|
||||
send_string_expect_success (rconn1, msg, 0);
|
||||
|
||||
// Accept data on the bound stream.
|
||||
TEST_ASSERT_GREATER_THAN (
|
||||
0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (rbind, buff, 256, 0)));
|
||||
TEST_ASSERT_EQUAL (0, buff[0]); // an auto-generated routing id
|
||||
recv_string_expect_success (rbind, msg, 0);
|
||||
|
||||
// Handle close of the socket.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (rbind, my_endpoint));
|
||||
test_context_socket_close (rbind);
|
||||
test_context_socket_close (rconn1);
|
||||
}
|
||||
|
||||
void test_router_2_router (bool named_)
|
||||
{
|
||||
char buff[256];
|
||||
const char msg[] = "hi 1";
|
||||
const int zero = 0;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
// Create bind socket.
|
||||
void *rbind = test_context_socket (ZMQ_ROUTER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (rbind, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
bind_loopback_ipv4 (rbind, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
// Create connection socket.
|
||||
void *rconn1 = test_context_socket (ZMQ_ROUTER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (rconn1, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
|
||||
// If we're in named mode, set some identities.
|
||||
if (named_) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (rbind, ZMQ_ROUTING_ID, x_routing_id, 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (rconn1, ZMQ_ROUTING_ID, y_routing_id, 1));
|
||||
}
|
||||
|
||||
// Make call to connect using a connect_routing_id.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID,
|
||||
rconn1routing_id,
|
||||
strlen (rconn1routing_id)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, my_endpoint));
|
||||
/* Uncomment to test assert on duplicate routing id
|
||||
// Test duplicate connect attempt.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (rconn1, ZMQ_CONNECT_ROUTING_ID, rconn1routing_id, strlen (rconn1routing_id)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rconn1, bindip));
|
||||
*/
|
||||
// Send some data.
|
||||
|
||||
send_string_expect_success (rconn1, rconn1routing_id, ZMQ_SNDMORE);
|
||||
send_string_expect_success (rconn1, msg, 0);
|
||||
|
||||
// Receive the name.
|
||||
const int routing_id_len = zmq_recv (rbind, buff, 256, 0);
|
||||
if (named_) {
|
||||
TEST_ASSERT_EQUAL_INT (strlen (y_routing_id), routing_id_len);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN (y_routing_id, buff, routing_id_len);
|
||||
} else {
|
||||
TEST_ASSERT_TRUE (routing_id_len && 0 == buff[0]);
|
||||
}
|
||||
|
||||
// Receive the data.
|
||||
recv_string_expect_success (rbind, msg, 0);
|
||||
|
||||
// Send some data back.
|
||||
const int ret = zmq_send (rbind, buff, routing_id_len, ZMQ_SNDMORE);
|
||||
TEST_ASSERT_EQUAL_INT (routing_id_len, ret);
|
||||
send_string_expect_success (rbind, "ok", 0);
|
||||
|
||||
// If bound socket identity naming a problem, we'll likely see something funky here.
|
||||
recv_string_expect_success (rconn1, rconn1routing_id, 0);
|
||||
recv_string_expect_success (rconn1, "ok", 0);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (rbind, my_endpoint));
|
||||
test_context_socket_close (rbind);
|
||||
test_context_socket_close (rconn1);
|
||||
}
|
||||
|
||||
void test_router_2_router_while_receiving ()
|
||||
{
|
||||
char buff[256];
|
||||
const char msg[] = "hi 1";
|
||||
const int zero = 0;
|
||||
char x_endpoint[MAX_SOCKET_STRING];
|
||||
char z_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
// Create xbind socket.
|
||||
void *xbind = test_context_socket (ZMQ_ROUTER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (xbind, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
bind_loopback_ipv4 (xbind, x_endpoint, sizeof x_endpoint);
|
||||
|
||||
// Create zbind socket.
|
||||
void *zbind = test_context_socket (ZMQ_ROUTER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (zbind, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
bind_loopback_ipv4 (zbind, z_endpoint, sizeof z_endpoint);
|
||||
|
||||
// Create connection socket.
|
||||
void *yconn = test_context_socket (ZMQ_ROUTER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (yconn, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
|
||||
// set identities for each socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
xbind, ZMQ_ROUTING_ID, x_routing_id, strlen (x_routing_id)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (yconn, ZMQ_ROUTING_ID, y_routing_id, 2));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
zbind, ZMQ_ROUTING_ID, z_routing_id, strlen (z_routing_id)));
|
||||
|
||||
// Connect Y to X using a routing id
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
yconn, ZMQ_CONNECT_ROUTING_ID, x_routing_id, strlen (x_routing_id)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (yconn, x_endpoint));
|
||||
|
||||
// Send some data from Y to X.
|
||||
send_string_expect_success (yconn, x_routing_id, ZMQ_SNDMORE);
|
||||
send_string_expect_success (yconn, msg, 0);
|
||||
|
||||
// wait for the Y->X message to be received
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Now X tries to connect to Z and send a message
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
xbind, ZMQ_CONNECT_ROUTING_ID, z_routing_id, strlen (z_routing_id)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (xbind, z_endpoint));
|
||||
|
||||
// Try to send some data from X to Z.
|
||||
send_string_expect_success (xbind, z_routing_id, ZMQ_SNDMORE);
|
||||
send_string_expect_success (xbind, msg, 0);
|
||||
|
||||
// wait for the X->Z message to be received (so that our non-blocking check will actually
|
||||
// fail if the message is routed to Y)
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// nothing should have been received on the Y socket
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN,
|
||||
zmq_recv (yconn, buff, 256, ZMQ_DONTWAIT));
|
||||
|
||||
// the message should have been received on the Z socket
|
||||
recv_string_expect_success (zbind, x_routing_id, 0);
|
||||
recv_string_expect_success (zbind, msg, 0);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (xbind, x_endpoint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (zbind, z_endpoint));
|
||||
|
||||
test_context_socket_close (yconn);
|
||||
test_context_socket_close (xbind);
|
||||
test_context_socket_close (zbind);
|
||||
}
|
||||
|
||||
void test_router_2_router_unnamed ()
|
||||
{
|
||||
test_router_2_router (false);
|
||||
}
|
||||
|
||||
void test_router_2_router_named ()
|
||||
{
|
||||
test_router_2_router (true);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_stream_2_stream);
|
||||
RUN_TEST (test_router_2_router_unnamed);
|
||||
RUN_TEST (test_router_2_router_named);
|
||||
RUN_TEST (test_router_2_router_while_receiving);
|
||||
return UNITY_END ();
|
||||
}
|
||||
117
tests/test_connect_stream_fuzzer.cpp
Normal file
117
tests/test_connect_stream_fuzzer.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
// Test that the ZMTP engine handles invalid handshake when connecting
|
||||
// https://rfc.zeromq.org/spec/37/
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
setup_test_context ();
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
fd_t server = bind_socket_resolve_port ("127.0.0.1", "0", my_endpoint);
|
||||
|
||||
void *client = test_context_socket (ZMQ_STREAM);
|
||||
// As per API by default there's no limit to the size of a message,
|
||||
// but the sanitizer allocator will barf over a gig or so
|
||||
int64_t max_msg_size = 64 * 1024 * 1024;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
fd_t server_accept =
|
||||
TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));
|
||||
|
||||
// If there is not enough data for a full greeting, just send what we can
|
||||
// Otherwise send greeting first, as expected by the protocol
|
||||
uint8_t buf[64];
|
||||
if (size >= 64) {
|
||||
send (server_accept, (void *) data, 64, MSG_NOSIGNAL);
|
||||
data += 64;
|
||||
size -= 64;
|
||||
}
|
||||
recv (server_accept, buf, 64, MSG_DONTWAIT);
|
||||
msleep (250);
|
||||
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
|
||||
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
|
||||
sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);
|
||||
msleep (250);
|
||||
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT)) {
|
||||
zmq_msg_close (&msg);
|
||||
zmq_msg_init (&msg);
|
||||
}
|
||||
|
||||
close (server_accept);
|
||||
close (server);
|
||||
|
||||
test_context_socket_close_zero_linger (client);
|
||||
teardown_test_context ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_connect_null_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_connect_null_fuzzer_seed_corpus",
|
||||
&data, &len, &num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_connect_null_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
125
tests/test_connect_ws_fuzzer.cpp
Normal file
125
tests/test_connect_ws_fuzzer.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright (c) 2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef ZMQ_USE_FUZZING_ENGINE
|
||||
#include <fuzzer/FuzzedDataProvider.h>
|
||||
#endif
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
// Test that the ZMTP WebSocket engine handles invalid handshake when connecting
|
||||
// https://rfc.zeromq.org/spec/45/
|
||||
extern "C" int LLVMFuzzerTestOneInput (const uint8_t *data, size_t size)
|
||||
{
|
||||
setup_test_context ();
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
fd_t server = bind_socket_resolve_port ("127.0.0.1", "0", my_endpoint,
|
||||
AF_INET, IPPROTO_WS);
|
||||
|
||||
void *client = test_context_socket (ZMQ_PULL);
|
||||
// As per API by default there's no limit to the size of a message,
|
||||
// but the sanitizer allocator will barf over a gig or so
|
||||
int64_t max_msg_size = 64 * 1024 * 1024;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_MAXMSGSIZE, &max_msg_size, sizeof (int64_t)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
fd_t server_accept =
|
||||
TEST_ASSERT_SUCCESS_RAW_ERRNO (accept (server, NULL, NULL));
|
||||
|
||||
// If there is not enough data for a full handshake, just send what we can
|
||||
// Otherwise send websocket handshake first, as expected by the protocol
|
||||
uint8_t buf[256];
|
||||
recv (server_accept, buf, 256, 0);
|
||||
if (size >= 166) {
|
||||
send (server_accept, (void *) data, 166, MSG_NOSIGNAL);
|
||||
data += 166;
|
||||
size -= 166;
|
||||
}
|
||||
recv (server_accept, buf, 256, MSG_DONTWAIT);
|
||||
// Then send the READY command
|
||||
if (size >= 29) {
|
||||
send (server_accept, (void *) data, 29, MSG_NOSIGNAL);
|
||||
data += 29;
|
||||
size -= 29;
|
||||
}
|
||||
msleep (250);
|
||||
for (ssize_t sent = 0; size > 0 && (sent != -1 || errno == EINTR);
|
||||
size -= sent > 0 ? sent : 0, data += sent > 0 ? sent : 0)
|
||||
sent = send (server_accept, (const char *) data, size, MSG_NOSIGNAL);
|
||||
msleep (250);
|
||||
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
while (-1 != zmq_msg_recv (&msg, client, ZMQ_DONTWAIT)) {
|
||||
zmq_msg_close (&msg);
|
||||
zmq_msg_init (&msg);
|
||||
}
|
||||
|
||||
close (server_accept);
|
||||
close (server);
|
||||
|
||||
test_context_socket_close_zero_linger (client);
|
||||
teardown_test_context ();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifndef ZMQ_USE_FUZZING_ENGINE
|
||||
void test_connect_ws_fuzzer ()
|
||||
{
|
||||
uint8_t **data;
|
||||
size_t *len, num_cases = 0;
|
||||
if (fuzzer_corpus_encode (
|
||||
"tests/libzmq-fuzz-corpora/test_connect_ws_fuzzer_seed_corpus", &data,
|
||||
&len, &num_cases)
|
||||
!= 0)
|
||||
exit (77);
|
||||
|
||||
while (num_cases-- > 0) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
LLVMFuzzerTestOneInput (data[num_cases], len[num_cases]));
|
||||
free (data[num_cases]);
|
||||
}
|
||||
|
||||
free (data);
|
||||
free (len);
|
||||
}
|
||||
|
||||
int main (int argc, char **argv)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_connect_ws_fuzzer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
#endif
|
||||
255
tests/test_ctx_destroy.cpp
Normal file
255
tests/test_ctx_destroy.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <unity.h>
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
static void receiver (void *socket_)
|
||||
{
|
||||
char buffer[16];
|
||||
int rc = zmq_recv (socket_, &buffer, sizeof (buffer), 0);
|
||||
// TODO which error is expected here? use TEST_ASSERT_FAILURE_ERRNO instead
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
}
|
||||
|
||||
void test_ctx_destroy ()
|
||||
{
|
||||
// Set up our context and sockets
|
||||
void *ctx = zmq_ctx_new ();
|
||||
TEST_ASSERT_NOT_NULL (ctx);
|
||||
|
||||
void *socket = zmq_socket (ctx, ZMQ_PULL);
|
||||
TEST_ASSERT_NOT_NULL (socket);
|
||||
|
||||
// Close the socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));
|
||||
|
||||
// Destroy the context
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));
|
||||
}
|
||||
|
||||
void test_ctx_shutdown ()
|
||||
{
|
||||
// Set up our context and sockets
|
||||
void *ctx = zmq_ctx_new ();
|
||||
TEST_ASSERT_NOT_NULL (ctx);
|
||||
|
||||
void *socket = zmq_socket (ctx, ZMQ_PULL);
|
||||
TEST_ASSERT_NOT_NULL (socket);
|
||||
|
||||
// Spawn a thread to receive on socket
|
||||
void *receiver_thread = zmq_threadstart (&receiver, socket);
|
||||
|
||||
// Wait for thread to start up and block
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Shutdown context, if we used destroy here we would deadlock.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_shutdown (ctx));
|
||||
|
||||
// Wait for thread to finish
|
||||
zmq_threadclose (receiver_thread);
|
||||
|
||||
// Close the socket.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));
|
||||
|
||||
// Destroy the context, will now not hang as we have closed the socket.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));
|
||||
}
|
||||
|
||||
void test_ctx_shutdown_socket_opened_after ()
|
||||
{
|
||||
// Set up our context.
|
||||
void *ctx = zmq_ctx_new ();
|
||||
TEST_ASSERT_NOT_NULL (ctx);
|
||||
|
||||
// Open a socket to start context, and close it immediately again.
|
||||
void *socket = zmq_socket (ctx, ZMQ_PULL);
|
||||
TEST_ASSERT_NOT_NULL (socket);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));
|
||||
|
||||
// Shutdown context.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_shutdown (ctx));
|
||||
|
||||
// Opening socket should now fail.
|
||||
TEST_ASSERT_NULL (zmq_socket (ctx, ZMQ_PULL));
|
||||
TEST_ASSERT_FAILURE_ERRNO (ETERM, -1);
|
||||
|
||||
// Destroy the context.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));
|
||||
}
|
||||
|
||||
void test_ctx_shutdown_only_socket_opened_after ()
|
||||
{
|
||||
// Set up our context.
|
||||
void *ctx = zmq_ctx_new ();
|
||||
TEST_ASSERT_NOT_NULL (ctx);
|
||||
|
||||
// Shutdown context.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_shutdown (ctx));
|
||||
|
||||
// Opening socket should now fail.
|
||||
TEST_ASSERT_NULL (zmq_socket (ctx, ZMQ_PULL));
|
||||
TEST_ASSERT_FAILURE_ERRNO (ETERM, -1);
|
||||
|
||||
// Destroy the context.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (ctx));
|
||||
}
|
||||
|
||||
void test_zmq_ctx_term_null_fails ()
|
||||
{
|
||||
int rc = zmq_ctx_term (NULL);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (EFAULT, errno);
|
||||
}
|
||||
|
||||
void test_zmq_term_null_fails ()
|
||||
{
|
||||
int rc = zmq_term (NULL);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (EFAULT, errno);
|
||||
}
|
||||
|
||||
void test_zmq_ctx_shutdown_null_fails ()
|
||||
{
|
||||
int rc = zmq_ctx_shutdown (NULL);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (EFAULT, errno);
|
||||
}
|
||||
|
||||
#ifdef ZMQ_HAVE_POLLER
|
||||
struct poller_test_data_t
|
||||
{
|
||||
int socket_type;
|
||||
void *ctx;
|
||||
void *counter;
|
||||
};
|
||||
|
||||
void run_poller (void *data_)
|
||||
{
|
||||
const poller_test_data_t *const poller_test_data =
|
||||
static_cast<const poller_test_data_t *> (data_);
|
||||
|
||||
void *socket =
|
||||
zmq_socket (poller_test_data->ctx, poller_test_data->socket_type);
|
||||
TEST_ASSERT_NOT_NULL (socket);
|
||||
|
||||
void *poller = zmq_poller_new ();
|
||||
TEST_ASSERT_NOT_NULL (poller);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller, socket, NULL, ZMQ_POLLIN));
|
||||
|
||||
zmq_atomic_counter_set (poller_test_data->counter, 1);
|
||||
|
||||
zmq_poller_event_t event;
|
||||
TEST_ASSERT_FAILURE_ERRNO (ETERM, zmq_poller_wait (poller, &event, -1));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));
|
||||
|
||||
// Close the socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_poller_exists_with_socket_on_zmq_ctx_term (const int socket_type_)
|
||||
{
|
||||
#ifdef ZMQ_HAVE_POLLER
|
||||
struct poller_test_data_t poller_test_data;
|
||||
|
||||
poller_test_data.socket_type = socket_type_;
|
||||
|
||||
// Set up our context and sockets
|
||||
poller_test_data.ctx = zmq_ctx_new ();
|
||||
TEST_ASSERT_NOT_NULL (poller_test_data.ctx);
|
||||
|
||||
poller_test_data.counter = zmq_atomic_counter_new ();
|
||||
TEST_ASSERT_NOT_NULL (poller_test_data.counter);
|
||||
|
||||
void *thread = zmq_threadstart (run_poller, &poller_test_data);
|
||||
TEST_ASSERT_NOT_NULL (thread);
|
||||
|
||||
while (zmq_atomic_counter_value (poller_test_data.counter) == 0) {
|
||||
msleep (10);
|
||||
}
|
||||
|
||||
// Destroy the context
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_destroy (poller_test_data.ctx));
|
||||
|
||||
zmq_threadclose (thread);
|
||||
|
||||
zmq_atomic_counter_destroy (&poller_test_data.counter);
|
||||
#else
|
||||
TEST_IGNORE_MESSAGE ("libzmq without zmq_poller_* support, ignoring test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_poller_exists_with_socket_on_zmq_ctx_term_thread_safe_socket ()
|
||||
{
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
test_poller_exists_with_socket_on_zmq_ctx_term (ZMQ_CLIENT);
|
||||
#else
|
||||
TEST_IGNORE_MESSAGE ("libzmq without DRAFT support, ignoring test");
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_poller_exists_with_socket_on_zmq_ctx_term_non_thread_safe_socket ()
|
||||
{
|
||||
test_poller_exists_with_socket_on_zmq_ctx_term (ZMQ_DEALER);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_ctx_destroy);
|
||||
RUN_TEST (test_ctx_shutdown);
|
||||
RUN_TEST (test_ctx_shutdown_socket_opened_after);
|
||||
RUN_TEST (test_ctx_shutdown_only_socket_opened_after);
|
||||
RUN_TEST (test_zmq_ctx_term_null_fails);
|
||||
RUN_TEST (test_zmq_term_null_fails);
|
||||
RUN_TEST (test_zmq_ctx_shutdown_null_fails);
|
||||
|
||||
RUN_TEST (
|
||||
test_poller_exists_with_socket_on_zmq_ctx_term_non_thread_safe_socket);
|
||||
RUN_TEST (
|
||||
test_poller_exists_with_socket_on_zmq_ctx_term_thread_safe_socket);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
310
tests/test_ctx_options.cpp
Normal file
310
tests/test_ctx_options.cpp
Normal file
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <limits>
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
#define WAIT_FOR_BACKGROUND_THREAD_INSPECTION (0)
|
||||
|
||||
#ifdef ZMQ_HAVE_LINUX
|
||||
#include <sys/time.h>
|
||||
#include <sys/resource.h>
|
||||
#include <unistd.h> // for sleep()
|
||||
#include <sched.h>
|
||||
|
||||
#define TEST_POLICY \
|
||||
(SCHED_OTHER) // NOTE: SCHED_OTHER is the default Linux scheduler
|
||||
|
||||
bool is_allowed_to_raise_priority ()
|
||||
{
|
||||
// NOTE1: if setrlimit() fails with EPERM, this means that current user has not enough permissions.
|
||||
// NOTE2: even for privileged users (e.g., root) getrlimit() would usually return 0 as nice limit; the only way to
|
||||
// discover if the user is able to increase the nice value is to actually try to change the rlimit:
|
||||
struct rlimit rlim;
|
||||
rlim.rlim_cur = 40;
|
||||
rlim.rlim_max = 40;
|
||||
if (setrlimit (RLIMIT_NICE, &rlim) == 0) {
|
||||
// rlim_cur == 40 means that this process is allowed to set a nice value of -20
|
||||
if (WAIT_FOR_BACKGROUND_THREAD_INSPECTION)
|
||||
printf ("This process has enough permissions to raise ZMQ "
|
||||
"background thread priority!\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (WAIT_FOR_BACKGROUND_THREAD_INSPECTION)
|
||||
printf ("This process has NOT enough permissions to raise ZMQ "
|
||||
"background thread priority.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#define TEST_POLICY (0)
|
||||
|
||||
bool is_allowed_to_raise_priority ()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
void test_ctx_thread_opts ()
|
||||
{
|
||||
// verify that setting negative values (e.g., default values) fail:
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_ctx_set (get_test_context (), ZMQ_THREAD_SCHED_POLICY,
|
||||
ZMQ_THREAD_SCHED_POLICY_DFLT));
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_ctx_set (get_test_context (),
|
||||
ZMQ_THREAD_PRIORITY,
|
||||
ZMQ_THREAD_PRIORITY_DFLT));
|
||||
|
||||
|
||||
// test scheduling policy:
|
||||
|
||||
// set context options that alter the background thread CPU scheduling/affinity settings;
|
||||
// as of ZMQ 4.2.3 this has an effect only on POSIX systems (nothing happens on Windows, but still it should return success):
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_ctx_set (get_test_context (), ZMQ_THREAD_SCHED_POLICY, TEST_POLICY));
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
TEST_POLICY, zmq_ctx_get (get_test_context (), ZMQ_THREAD_SCHED_POLICY));
|
||||
|
||||
// test priority:
|
||||
|
||||
// in theory SCHED_OTHER supports only the static priority 0 but quoting the docs
|
||||
// http://man7.org/linux/man-pages/man7/sched.7.html
|
||||
// "The thread to run is chosen from the static priority 0 list based on
|
||||
// a dynamic priority that is determined only inside this list. The
|
||||
// dynamic priority is based on the nice value [...]
|
||||
// The nice value can be modified using nice(2), setpriority(2), or sched_setattr(2)."
|
||||
// ZMQ will internally use nice(2) to set the nice value when using SCHED_OTHER.
|
||||
// However changing the nice value of a process requires appropriate permissions...
|
||||
// check that the current effective user is able to do that:
|
||||
if (is_allowed_to_raise_priority ()) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_set (
|
||||
get_test_context (), ZMQ_THREAD_PRIORITY,
|
||||
1 /* any positive value different than the default will be ok */));
|
||||
}
|
||||
|
||||
|
||||
// test affinity:
|
||||
|
||||
// this should result in background threads being placed only on the
|
||||
// first CPU available on this system; try experimenting with other values
|
||||
// (e.g., 5 to use CPU index 5) and use "top -H" or "taskset -pc" to see the result
|
||||
|
||||
int cpus_add[] = {0, 1};
|
||||
for (unsigned int idx = 0; idx < sizeof (cpus_add) / sizeof (cpus_add[0]);
|
||||
idx++) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_set (
|
||||
get_test_context (), ZMQ_THREAD_AFFINITY_CPU_ADD, cpus_add[idx]));
|
||||
}
|
||||
|
||||
// you can also remove CPUs from list of affinities:
|
||||
int cpus_remove[] = {1};
|
||||
for (unsigned int idx = 0;
|
||||
idx < sizeof (cpus_remove) / sizeof (cpus_remove[0]); idx++) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_set (get_test_context (),
|
||||
ZMQ_THREAD_AFFINITY_CPU_REMOVE,
|
||||
cpus_remove[idx]));
|
||||
}
|
||||
|
||||
|
||||
// test INTEGER thread name prefix:
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_ctx_set (get_test_context (), ZMQ_THREAD_NAME_PREFIX, 1234));
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1234, zmq_ctx_get (get_test_context (), ZMQ_THREAD_NAME_PREFIX));
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
// test STRING thread name prefix:
|
||||
|
||||
const char prefix[] = "MyPrefix9012345"; // max len is 16 chars
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_ctx_set_ext (get_test_context (), ZMQ_THREAD_NAME_PREFIX, prefix,
|
||||
sizeof (prefix) / sizeof (char)));
|
||||
|
||||
char buf[16];
|
||||
size_t buflen = sizeof (buf) / sizeof (char);
|
||||
zmq_ctx_get_ext (get_test_context (), ZMQ_THREAD_NAME_PREFIX, buf, &buflen);
|
||||
TEST_ASSERT_EQUAL_STRING (prefix, buf);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_ctx_zero_copy ()
|
||||
{
|
||||
#ifdef ZMQ_ZERO_COPY_RECV
|
||||
int zero_copy;
|
||||
// Default value is 1.
|
||||
zero_copy = zmq_ctx_get (get_test_context (), ZMQ_ZERO_COPY_RECV);
|
||||
TEST_ASSERT_EQUAL_INT (1, zero_copy);
|
||||
|
||||
// Test we can set it to 0.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_ctx_set (get_test_context (), ZMQ_ZERO_COPY_RECV, 0));
|
||||
zero_copy = zmq_ctx_get (get_test_context (), ZMQ_ZERO_COPY_RECV);
|
||||
TEST_ASSERT_EQUAL_INT (0, zero_copy);
|
||||
|
||||
// Create a TCP socket pair using the context and test that messages can be
|
||||
// received. Note that inproc sockets cannot be used for this test.
|
||||
void *pull = zmq_socket (get_test_context (), ZMQ_PULL);
|
||||
char endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (pull, endpoint, sizeof endpoint);
|
||||
|
||||
void *push = zmq_socket (get_test_context (), ZMQ_PUSH);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (push, endpoint));
|
||||
|
||||
const char *small_str = "abcd";
|
||||
const char *large_str =
|
||||
"01234567890123456789012345678901234567890123456789";
|
||||
|
||||
send_string_expect_success (push, small_str, 0);
|
||||
send_string_expect_success (push, large_str, 0);
|
||||
|
||||
recv_string_expect_success (pull, small_str, 0);
|
||||
recv_string_expect_success (pull, large_str, 0);
|
||||
|
||||
// Clean up.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (push));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (pull));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_ctx_set (get_test_context (), ZMQ_ZERO_COPY_RECV, 1));
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1, zmq_ctx_get (get_test_context (), ZMQ_ZERO_COPY_RECV));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_ctx_option_max_sockets ()
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_MAX_SOCKETS_DFLT,
|
||||
zmq_ctx_get (get_test_context (), ZMQ_MAX_SOCKETS));
|
||||
}
|
||||
|
||||
void test_ctx_option_socket_limit ()
|
||||
{
|
||||
#if defined(ZMQ_USE_SELECT)
|
||||
TEST_ASSERT_EQUAL_INT (FD_SETSIZE - 1, zmq_ctx_get (ctx, ZMQ_SOCKET_LIMIT));
|
||||
#elif defined(ZMQ_USE_POLL) || defined(ZMQ_USE_EPOLL) \
|
||||
|| defined(ZMQ_USE_DEVPOLL) || defined(ZMQ_USE_KQUEUE)
|
||||
TEST_ASSERT_EQUAL_INT (65535, zmq_ctx_get (ctx, ZMQ_SOCKET_LIMIT));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_ctx_option_io_threads ()
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_IO_THREADS_DFLT,
|
||||
zmq_ctx_get (get_test_context (), ZMQ_IO_THREADS));
|
||||
}
|
||||
|
||||
void test_ctx_option_ipv6 ()
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_ctx_get (get_test_context (), ZMQ_IPV6));
|
||||
}
|
||||
|
||||
void test_ctx_option_msg_t_size ()
|
||||
{
|
||||
#if defined(ZMQ_MSG_T_SIZE)
|
||||
TEST_ASSERT_EQUAL_INT (sizeof (zmq_msg_t),
|
||||
zmq_ctx_get (get_test_context (), ZMQ_MSG_T_SIZE));
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_ctx_option_ipv6_set ()
|
||||
{
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_ctx_set (get_test_context (), ZMQ_IPV6, true));
|
||||
TEST_ASSERT_EQUAL_INT (1, zmq_ctx_get (get_test_context (), ZMQ_IPV6));
|
||||
}
|
||||
|
||||
void test_ctx_option_blocky ()
|
||||
{
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_ctx_set (get_test_context (), ZMQ_IPV6, true));
|
||||
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
int value;
|
||||
size_t optsize = sizeof (int);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_IPV6, &value, &optsize));
|
||||
TEST_ASSERT_EQUAL_INT (1, value);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_LINGER, &value, &optsize));
|
||||
TEST_ASSERT_EQUAL_INT (-1, value);
|
||||
test_context_socket_close (router);
|
||||
|
||||
#if WAIT_FOR_BACKGROUND_THREAD_INSPECTION
|
||||
// this is useful when you want to use an external tool (like top or taskset) to view
|
||||
// properties of the background threads
|
||||
printf ("Sleeping for 100sec. You can now use 'top -H -p $(pgrep -f "
|
||||
"test_ctx_options)' and 'taskset -pc <ZMQ background thread PID>' "
|
||||
"to view ZMQ background thread properties.\n");
|
||||
sleep (100);
|
||||
#endif
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_ctx_set (get_test_context (), ZMQ_BLOCKY, false));
|
||||
TEST_ASSERT_EQUAL_INT (0, TEST_ASSERT_SUCCESS_ERRNO ((zmq_ctx_get (
|
||||
get_test_context (), ZMQ_BLOCKY))));
|
||||
router = test_context_socket (ZMQ_ROUTER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_LINGER, &value, &optsize));
|
||||
TEST_ASSERT_EQUAL_INT (0, value);
|
||||
test_context_socket_close (router);
|
||||
}
|
||||
|
||||
void test_ctx_option_invalid ()
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT (-1, zmq_ctx_set (get_test_context (), -1, 0));
|
||||
TEST_ASSERT_EQUAL_INT (EINVAL, errno);
|
||||
TEST_ASSERT_EQUAL_INT (-1, zmq_ctx_get (get_test_context (), -1));
|
||||
TEST_ASSERT_EQUAL_INT (EINVAL, errno);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_ctx_option_max_sockets);
|
||||
RUN_TEST (test_ctx_option_socket_limit);
|
||||
RUN_TEST (test_ctx_option_io_threads);
|
||||
RUN_TEST (test_ctx_option_ipv6);
|
||||
RUN_TEST (test_ctx_option_msg_t_size);
|
||||
RUN_TEST (test_ctx_option_ipv6_set);
|
||||
RUN_TEST (test_ctx_thread_opts);
|
||||
RUN_TEST (test_ctx_zero_copy);
|
||||
RUN_TEST (test_ctx_option_blocky);
|
||||
RUN_TEST (test_ctx_option_invalid);
|
||||
return UNITY_END ();
|
||||
}
|
||||
107
tests/test_dgram.cpp
Normal file
107
tests/test_dgram.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Copyright (c) 2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void str_send_to (void *s_, const char *content_, const char *address_)
|
||||
{
|
||||
send_string_expect_success (s_, address_, ZMQ_SNDMORE);
|
||||
send_string_expect_success (s_, content_, 0);
|
||||
}
|
||||
|
||||
void str_recv_from (void *s_, char **ptr_content_, char **ptr_address_)
|
||||
{
|
||||
*ptr_address_ = s_recv (s_);
|
||||
TEST_ASSERT_NOT_NULL (ptr_address_);
|
||||
|
||||
*ptr_content_ = s_recv (s_);
|
||||
TEST_ASSERT_NOT_NULL (ptr_content_);
|
||||
}
|
||||
|
||||
static const char test_question[] = "Is someone there ?";
|
||||
static const char test_answer[] = "Yes, there is !";
|
||||
|
||||
void test_connect_fails ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_DGRAM);
|
||||
|
||||
// Connecting dgram should fail
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOCOMPATPROTO,
|
||||
zmq_connect (socket, ENDPOINT_4));
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_roundtrip ()
|
||||
{
|
||||
char *message_string;
|
||||
char *address;
|
||||
|
||||
void *sender = test_context_socket (ZMQ_DGRAM);
|
||||
void *listener = test_context_socket (ZMQ_DGRAM);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (listener, ENDPOINT_4));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sender, ENDPOINT_5));
|
||||
|
||||
str_send_to (sender, test_question, strrchr (ENDPOINT_4, '/') + 1);
|
||||
|
||||
str_recv_from (listener, &message_string, &address);
|
||||
TEST_ASSERT_EQUAL_STRING (test_question, message_string);
|
||||
TEST_ASSERT_EQUAL_STRING (strrchr (ENDPOINT_5, '/') + 1, address);
|
||||
free (message_string);
|
||||
|
||||
str_send_to (listener, test_answer, address);
|
||||
free (address);
|
||||
|
||||
str_recv_from (sender, &message_string, &address);
|
||||
TEST_ASSERT_EQUAL_STRING (test_answer, message_string);
|
||||
TEST_ASSERT_EQUAL_STRING (strrchr (ENDPOINT_4, '/') + 1, address);
|
||||
free (message_string);
|
||||
free (address);
|
||||
|
||||
test_context_socket_close (sender);
|
||||
test_context_socket_close (listener);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_connect_fails);
|
||||
RUN_TEST (test_roundtrip);
|
||||
return UNITY_END ();
|
||||
}
|
||||
72
tests/test_diffserv.cpp
Normal file
72
tests/test_diffserv.cpp
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_diffserv ()
|
||||
{
|
||||
int tos = 0x28;
|
||||
int o_tos;
|
||||
size_t tos_size = sizeof (tos);
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sb, ZMQ_TOS, &tos, tos_size));
|
||||
bind_loopback_ipv4 (sb, my_endpoint, sizeof (my_endpoint));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (sb, ZMQ_TOS, &o_tos, &tos_size));
|
||||
TEST_ASSERT_EQUAL (tos, o_tos);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PAIR);
|
||||
tos = 0x58;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sc, ZMQ_TOS, &tos, tos_size));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (sc, ZMQ_TOS, &o_tos, &tos_size));
|
||||
TEST_ASSERT_EQUAL (tos, o_tos);
|
||||
|
||||
// Wireshark can be used to verify that the server socket is
|
||||
// using DSCP 0x28 in packets to the client while the client
|
||||
// is using 0x58 in packets to the server.
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_diffserv);
|
||||
return UNITY_END ();
|
||||
}
|
||||
137
tests/test_disconnect_inproc.cpp
Normal file
137
tests/test_disconnect_inproc.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
/// Initialize a zeromq message with a given null-terminated string
|
||||
#define ZMQ_PREPARE_STRING(msg, data, size) \
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg)); \
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, size + 1)); \
|
||||
memcpy (zmq_msg_data (&msg), data, size + 1);
|
||||
|
||||
static int publicationsReceived = 0;
|
||||
static bool isSubscribed = false;
|
||||
|
||||
void test_disconnect_inproc ()
|
||||
{
|
||||
void *pub_socket = test_context_socket (ZMQ_XPUB);
|
||||
void *sub_socket = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, "foo", 3));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_bind (pub_socket, "inproc://someInProcDescriptor"));
|
||||
|
||||
int more;
|
||||
size_t more_size = sizeof (more);
|
||||
|
||||
for (int iteration = 0;; ++iteration) {
|
||||
zmq_pollitem_t items[] = {
|
||||
{sub_socket, 0, ZMQ_POLLIN, 0}, // read publications
|
||||
{pub_socket, 0, ZMQ_POLLIN, 0}, // read subscriptions
|
||||
};
|
||||
int rc = zmq_poll (items, 2, 100);
|
||||
|
||||
if (items[1].revents & ZMQ_POLLIN) {
|
||||
for (more = 1; more;) {
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, pub_socket, 0));
|
||||
const char *const buffer =
|
||||
static_cast<const char *> (zmq_msg_data (&msg));
|
||||
|
||||
if (buffer[0] == 0) {
|
||||
TEST_ASSERT_TRUE (isSubscribed);
|
||||
isSubscribed = false;
|
||||
} else {
|
||||
TEST_ASSERT_FALSE (isSubscribed);
|
||||
isSubscribed = true;
|
||||
}
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (pub_socket, ZMQ_RCVMORE, &more, &more_size));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
}
|
||||
}
|
||||
|
||||
if (items[0].revents & ZMQ_POLLIN) {
|
||||
more = 1;
|
||||
for (more = 1; more;) {
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sub_socket, 0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (sub_socket, ZMQ_RCVMORE, &more, &more_size));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
}
|
||||
publicationsReceived++;
|
||||
}
|
||||
if (iteration == 1) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (sub_socket, "inproc://someInProcDescriptor"));
|
||||
msleep (SETTLE_TIME);
|
||||
}
|
||||
if (iteration == 4) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_disconnect (sub_socket, "inproc://someInProcDescriptor"));
|
||||
}
|
||||
if (iteration > 4 && rc == 0)
|
||||
break;
|
||||
|
||||
zmq_msg_t channel_envlp;
|
||||
ZMQ_PREPARE_STRING (channel_envlp, "foo", 3);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_send (&channel_envlp, pub_socket, ZMQ_SNDMORE));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&channel_envlp));
|
||||
|
||||
zmq_msg_t message;
|
||||
ZMQ_PREPARE_STRING (message, "this is foo!", 12);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&message, pub_socket, 0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&message));
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT (3, publicationsReceived);
|
||||
TEST_ASSERT_FALSE (isSubscribed);
|
||||
|
||||
test_context_socket_close (pub_socket);
|
||||
test_context_socket_close (sub_socket);
|
||||
}
|
||||
|
||||
int main (int, char **)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_disconnect_inproc);
|
||||
return UNITY_END ();
|
||||
}
|
||||
118
tests/test_disconnect_msg.cpp
Normal file
118
tests/test_disconnect_msg.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test (const char *address)
|
||||
{
|
||||
// Create a server
|
||||
void *server = test_context_socket (ZMQ_SERVER);
|
||||
|
||||
// set server socket options
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_DISCONNECT_MSG, "D", 1));
|
||||
|
||||
// bind server
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, address));
|
||||
|
||||
// Create a client
|
||||
void *client = test_context_socket (ZMQ_CLIENT);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_HELLO_MSG, "H", 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, address));
|
||||
|
||||
// Receive the hello message from client
|
||||
recv_string_expect_success (server, "H", 0);
|
||||
|
||||
// Kill the client
|
||||
test_context_socket_close (client);
|
||||
|
||||
// Receive the disconnect message
|
||||
recv_string_expect_success (server, "D", 0);
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (server);
|
||||
}
|
||||
|
||||
void test_tcp ()
|
||||
{
|
||||
test ("tcp://127.0.0.1:5569");
|
||||
}
|
||||
|
||||
void test_inproc ()
|
||||
{
|
||||
test ("inproc://disconnect-msg");
|
||||
}
|
||||
|
||||
|
||||
void test_inproc_disconnect ()
|
||||
{
|
||||
const char *address = "inproc://disconnect-msg";
|
||||
|
||||
// Create a server
|
||||
void *server = test_context_socket (ZMQ_SERVER);
|
||||
|
||||
// set server socket options
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_DISCONNECT_MSG, "D", 1));
|
||||
|
||||
// bind server
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, address));
|
||||
|
||||
// Create a client
|
||||
void *client = test_context_socket (ZMQ_CLIENT);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_HELLO_MSG, "H", 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, address));
|
||||
|
||||
// Receive the hello message from client
|
||||
recv_string_expect_success (server, "H", 0);
|
||||
|
||||
// disconnect the client
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (client, address));
|
||||
|
||||
// Receive the disconnect message
|
||||
recv_string_expect_success (server, "D", 0);
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (client);
|
||||
test_context_socket_close (server);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_tcp);
|
||||
RUN_TEST (test_inproc);
|
||||
RUN_TEST (test_inproc_disconnect);
|
||||
return UNITY_END ();
|
||||
}
|
||||
220
tests/test_filter_ipc.cpp
Normal file
220
tests/test_filter_ipc.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <grp.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
static void bounce_fail (void *server_, void *client_)
|
||||
{
|
||||
const char *content = "12345678ABCDEFGH12345678abcdefgh";
|
||||
char buffer[32];
|
||||
|
||||
// Send message from client to server
|
||||
send_string_expect_success (client_, content, ZMQ_SNDMORE);
|
||||
send_string_expect_success (client_, content, 0);
|
||||
|
||||
// Receive message at server side (should not succeed)
|
||||
int timeout = SETTLE_TIME;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server_, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (server_, buffer, 32, 0));
|
||||
|
||||
// Send message from server to client to test other direction
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server_, ZMQ_SNDTIMEO, &timeout, sizeof (int)));
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN,
|
||||
zmq_send (server_, content, 32, ZMQ_SNDMORE));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void
|
||||
run_test (int opt_, T optval_, int expected_error_, int bounce_test_)
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
if (opt_) {
|
||||
const int rc = zmq_setsockopt (sb, opt_, &optval_, sizeof (optval_));
|
||||
if (expected_error_) {
|
||||
TEST_ASSERT_FAILURE_ERRNO (expected_error_, rc);
|
||||
} else {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
}
|
||||
}
|
||||
|
||||
void *sc = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
// If a test fails, don't hang for too long
|
||||
int timeout = 2500;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sb, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sb, ZMQ_SNDTIMEO, &timeout, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sc, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sc, ZMQ_SNDTIMEO, &timeout, sizeof (int)));
|
||||
int interval = -1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sc, ZMQ_RECONNECT_IVL, &interval, sizeof (int)));
|
||||
|
||||
if (bounce_test_) {
|
||||
const char *endpoint = "ipc://test_filter_ipc.sock";
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, endpoint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint));
|
||||
|
||||
if (bounce_test_ > 0)
|
||||
bounce (sb, sc);
|
||||
else
|
||||
bounce_fail (sb, sc);
|
||||
}
|
||||
|
||||
// TODO only use zero linger when bounce_test_ < 0?
|
||||
test_context_socket_close_zero_linger (sc);
|
||||
test_context_socket_close_zero_linger (sb);
|
||||
}
|
||||
|
||||
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
|
||||
gid_t group, supgroup, notgroup;
|
||||
|
||||
void init_groups ()
|
||||
{
|
||||
// Get the group and supplemental groups of the process owner
|
||||
gid_t groups[100];
|
||||
int ngroups = getgroups (100, groups);
|
||||
TEST_ASSERT_NOT_EQUAL (-1, ngroups);
|
||||
group = getgid ();
|
||||
supgroup = group;
|
||||
notgroup = group + 1;
|
||||
for (int i = 0; i < ngroups; i++) {
|
||||
if (supgroup == group && group != groups[i]) {
|
||||
if (getgrgid (groups[i]))
|
||||
supgroup = groups[i];
|
||||
}
|
||||
if (notgroup <= groups[i])
|
||||
notgroup = groups[i] + 1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_no_filters ()
|
||||
{
|
||||
run_test<int> (0, 0, 0, 1);
|
||||
}
|
||||
|
||||
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
|
||||
void test_filter_with_process_owner_uid ()
|
||||
{
|
||||
run_test<uid_t> (ZMQ_IPC_FILTER_UID, getuid (), 0, 1);
|
||||
}
|
||||
void test_filter_with_possibly_nonexistent_uid ()
|
||||
{
|
||||
run_test<uid_t> (ZMQ_IPC_FILTER_UID, getuid () + 1, 0, -1);
|
||||
}
|
||||
void test_filter_with_process_owner_gid ()
|
||||
{
|
||||
run_test<gid_t> (ZMQ_IPC_FILTER_GID, group, 0, 1);
|
||||
}
|
||||
void test_filter_with_supplemental_process_owner_gid ()
|
||||
{
|
||||
run_test<gid_t> (ZMQ_IPC_FILTER_GID, supgroup, 0, 1);
|
||||
}
|
||||
void test_filter_with_possibly_nonexistent_gid ()
|
||||
{
|
||||
run_test<gid_t> (ZMQ_IPC_FILTER_GID, notgroup, 0, -1);
|
||||
}
|
||||
#if defined ZMQ_HAVE_SO_PEERCRED
|
||||
void test_filter_with_current_process_pid ()
|
||||
{
|
||||
run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid (), 0, 1);
|
||||
}
|
||||
void test_filter_with_possibly_nonexistent_pid ()
|
||||
{
|
||||
run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid () + 1, 0, -1);
|
||||
}
|
||||
#else
|
||||
void test_filter_with_pid_fails ()
|
||||
{
|
||||
// Setup of PID filter should fail with operation not supported error
|
||||
// TODO EINVAL is not ENOTSUP (!)
|
||||
run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid (), EINVAL, 0);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
void test_filter_with_zero_uid_fails ()
|
||||
{
|
||||
run_test<uid_t> (ZMQ_IPC_FILTER_UID, 0, EINVAL, 0);
|
||||
}
|
||||
void test_filter_with_zero_gid_fails ()
|
||||
{
|
||||
run_test<gid_t> (ZMQ_IPC_FILTER_GID, 0, EINVAL, 0);
|
||||
}
|
||||
void test_filter_with_zero_pid_fails ()
|
||||
{
|
||||
run_test<pid_t> (ZMQ_IPC_FILTER_PID, 0, EINVAL, 0);
|
||||
}
|
||||
#endif // defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
|
||||
|
||||
int main (void)
|
||||
{
|
||||
#if !defined(ZMQ_HAVE_WINDOWS)
|
||||
setup_test_environment ();
|
||||
|
||||
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
|
||||
init_groups ();
|
||||
#endif
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_no_filters);
|
||||
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
|
||||
RUN_TEST (test_filter_with_process_owner_uid);
|
||||
RUN_TEST (test_filter_with_possibly_nonexistent_uid);
|
||||
RUN_TEST (test_filter_with_process_owner_gid);
|
||||
RUN_TEST (test_filter_with_supplemental_process_owner_gid);
|
||||
RUN_TEST (test_filter_with_possibly_nonexistent_gid);
|
||||
#if defined ZMQ_HAVE_SO_PEERCRED
|
||||
RUN_TEST (test_filter_with_current_process_pid);
|
||||
RUN_TEST (test_filter_with_possibly_nonexistent_pid);
|
||||
#else
|
||||
RUN_TEST (test_filter_with_pid_fails);
|
||||
#endif
|
||||
#else
|
||||
RUN_TEST (test_filter_with_zero_uid_fails);
|
||||
RUN_TEST (test_filter_with_zero_gid_fails);
|
||||
RUN_TEST (test_filter_with_zero_pid_fails);
|
||||
#endif // defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
|
||||
return UNITY_END ();
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
103
tests/test_fork.cpp
Normal file
103
tests/test_fork.cpp
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
char connect_address[MAX_SOCKET_STRING];
|
||||
|
||||
#define NUM_MESSAGES 5
|
||||
|
||||
void test_fork ()
|
||||
{
|
||||
#if !defined(ZMQ_HAVE_WINDOWS)
|
||||
// Create and bind pull socket to receive messages
|
||||
void *pull = test_context_socket (ZMQ_PULL);
|
||||
bind_loopback_ipv4 (pull, connect_address, sizeof connect_address);
|
||||
|
||||
int pid = fork ();
|
||||
if (pid == 0) {
|
||||
// use regular assertions in the child process
|
||||
|
||||
// Child process
|
||||
// Immediately close parent sockets and context
|
||||
zmq_close (pull);
|
||||
zmq_ctx_term (get_test_context ());
|
||||
|
||||
// Create new context, socket, connect and send some messages
|
||||
void *child_ctx = zmq_ctx_new ();
|
||||
assert (child_ctx);
|
||||
void *push = zmq_socket (child_ctx, ZMQ_PUSH);
|
||||
assert (push);
|
||||
int rc = zmq_connect (push, connect_address);
|
||||
assert (rc == 0);
|
||||
int count;
|
||||
for (count = 0; count < NUM_MESSAGES; count++)
|
||||
zmq_send (push, "Hello", 5, 0);
|
||||
|
||||
zmq_close (push);
|
||||
zmq_ctx_destroy (child_ctx);
|
||||
exit (0);
|
||||
} else {
|
||||
// Parent process
|
||||
int count;
|
||||
for (count = 0; count < NUM_MESSAGES; count++) {
|
||||
recv_string_expect_success (pull, "Hello", 0);
|
||||
}
|
||||
int child_status;
|
||||
while (true) {
|
||||
int rc = waitpid (pid, &child_status, 0);
|
||||
if (rc == -1 && errno == EINTR)
|
||||
continue;
|
||||
TEST_ASSERT_GREATER_THAN (0, rc);
|
||||
// Verify the status code of the child was zero
|
||||
TEST_ASSERT_EQUAL (0, WEXITSTATUS (child_status));
|
||||
break;
|
||||
}
|
||||
test_context_socket_close (pull);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_fork);
|
||||
return UNITY_END ();
|
||||
}
|
||||
61
tests/test_getsockopt_memset.cpp
Normal file
61
tests/test_getsockopt_memset.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_getsockopt_memset ()
|
||||
{
|
||||
int64_t more;
|
||||
size_t more_size = sizeof (more);
|
||||
|
||||
void *sb = test_context_socket (ZMQ_PUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "inproc://a"));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "inproc://a"));
|
||||
|
||||
memset (&more, 0xFF, sizeof (int64_t));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (sc, ZMQ_RCVMORE, &more, &more_size));
|
||||
TEST_ASSERT_EQUAL_INT (sizeof (int), more_size);
|
||||
TEST_ASSERT_EQUAL_INT (0, more);
|
||||
|
||||
// Cleanup
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_getsockopt_memset);
|
||||
return UNITY_END ();
|
||||
}
|
||||
449
tests/test_heartbeats.cpp
Normal file
449
tests/test_heartbeats.cpp
Normal file
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of 0MQ.
|
||||
|
||||
0MQ is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
0MQ is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#if defined(ZMQ_HAVE_WINDOWS)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stdexcept>
|
||||
#define close closesocket
|
||||
typedef SOCKET raw_socket;
|
||||
#else
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
typedef int raw_socket;
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// TODO remove this here, either ensure that UINT16_MAX is always properly
|
||||
// defined or handle this at a more central location
|
||||
#ifndef UINT16_MAX
|
||||
#define UINT16_MAX 65535
|
||||
#endif
|
||||
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
// Read one event off the monitor socket; return value and address
|
||||
// by reference, if not null, and event number by value. Returns -1
|
||||
// in case of error.
|
||||
|
||||
static int get_monitor_event (void *monitor_)
|
||||
{
|
||||
for (int i = 0; i < 10; i++) {
|
||||
// First frame in message contains event number and value
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
if (zmq_msg_recv (&msg, monitor_, ZMQ_DONTWAIT) == -1) {
|
||||
msleep (SETTLE_TIME);
|
||||
continue; // Interrupted, presumably
|
||||
}
|
||||
TEST_ASSERT_TRUE (zmq_msg_more (&msg));
|
||||
|
||||
uint8_t *data = static_cast<uint8_t *> (zmq_msg_data (&msg));
|
||||
uint16_t event = *reinterpret_cast<uint16_t *> (data);
|
||||
|
||||
// Second frame in message contains event address
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
if (zmq_msg_recv (&msg, monitor_, 0) == -1) {
|
||||
return -1; // Interrupted, presumably
|
||||
}
|
||||
TEST_ASSERT_FALSE (zmq_msg_more (&msg));
|
||||
|
||||
return event;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void recv_with_retry (raw_socket fd_, char *buffer_, int bytes_)
|
||||
{
|
||||
int received = 0;
|
||||
while (true) {
|
||||
int rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (
|
||||
recv (fd_, buffer_ + received, bytes_ - received, 0));
|
||||
TEST_ASSERT_GREATER_THAN_INT (0, rc);
|
||||
received += rc;
|
||||
TEST_ASSERT_LESS_OR_EQUAL_INT (bytes_, received);
|
||||
if (received == bytes_)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mock_handshake (raw_socket fd_, int mock_ping_)
|
||||
{
|
||||
char buffer[128];
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
memcpy (buffer, zmtp_greeting_null, sizeof (zmtp_greeting_null));
|
||||
|
||||
int rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (
|
||||
send (fd_, buffer, sizeof (zmtp_greeting_null), 0));
|
||||
TEST_ASSERT_EQUAL_INT (sizeof (zmtp_greeting_null), rc);
|
||||
|
||||
recv_with_retry (fd_, buffer, sizeof (zmtp_greeting_null));
|
||||
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
memcpy (buffer, zmtp_ready_dealer, sizeof (zmtp_ready_dealer));
|
||||
rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (
|
||||
send (fd_, buffer, sizeof (zmtp_ready_dealer), 0));
|
||||
TEST_ASSERT_EQUAL_INT (sizeof (zmtp_ready_dealer), rc);
|
||||
|
||||
// greeting
|
||||
recv_with_retry (fd_, buffer, sizeof (zmtp_ready_dealer));
|
||||
|
||||
if (mock_ping_) {
|
||||
// test PING context - should be replicated in the PONG
|
||||
// to avoid timeouts, do a bulk send
|
||||
const uint8_t zmtp_ping[12] = {4, 10, 4, 'P', 'I', 'N',
|
||||
'G', 0, 0, 'L', 'O', 'L'};
|
||||
uint8_t zmtp_pong[10] = {4, 8, 4, 'P', 'O', 'N', 'G', 'L', 'O', 'L'};
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
memcpy (buffer, zmtp_ping, 12);
|
||||
rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (fd_, buffer, 12, 0));
|
||||
TEST_ASSERT_EQUAL_INT (12, rc);
|
||||
|
||||
// test a larger body that won't fit in a small message and should get
|
||||
// truncated
|
||||
memset (buffer, 'z', sizeof (buffer));
|
||||
memcpy (buffer, zmtp_ping, 12);
|
||||
buffer[1] = 65;
|
||||
rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (fd_, buffer, 67, 0));
|
||||
TEST_ASSERT_EQUAL_INT (67, rc);
|
||||
|
||||
// small pong
|
||||
recv_with_retry (fd_, buffer, 10);
|
||||
TEST_ASSERT_EQUAL_INT (0, memcmp (zmtp_pong, buffer, 10));
|
||||
// large pong
|
||||
recv_with_retry (fd_, buffer, 23);
|
||||
uint8_t zmtp_pooong[65] = {4, 21, 4, 'P', 'O', 'N', 'G', 'L', 'O', 'L'};
|
||||
memset (zmtp_pooong + 10, 'z', 55);
|
||||
TEST_ASSERT_EQUAL_INT (0, memcmp (zmtp_pooong, buffer, 23));
|
||||
}
|
||||
}
|
||||
|
||||
static void setup_curve (void *socket_, int is_server_)
|
||||
{
|
||||
const char *secret_key;
|
||||
const char *public_key;
|
||||
const char *server_key;
|
||||
|
||||
if (is_server_) {
|
||||
secret_key = "JTKVSB%%)wK0E.X)V>+}o?pNmC{O&4W4b!Ni{Lh6";
|
||||
public_key = "rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7";
|
||||
server_key = NULL;
|
||||
} else {
|
||||
secret_key = "D:)Q[IlAW!ahhC2ac:9*A}h:p?([4%wOTJ%JR%cs";
|
||||
public_key = "Yne@$w-vo<fVvi]a<NY6T1ed:M$fCG*[IaLV{hID";
|
||||
server_key = "rq:rM>}U?@Lns47E1%kR.o@n%FcmmsL/@{H8]yf7";
|
||||
}
|
||||
|
||||
zmq_setsockopt (socket_, ZMQ_CURVE_SECRETKEY, secret_key,
|
||||
strlen (secret_key));
|
||||
zmq_setsockopt (socket_, ZMQ_CURVE_PUBLICKEY, public_key,
|
||||
strlen (public_key));
|
||||
if (is_server_)
|
||||
zmq_setsockopt (socket_, ZMQ_CURVE_SERVER, &is_server_,
|
||||
sizeof (is_server_));
|
||||
else
|
||||
zmq_setsockopt (socket_, ZMQ_CURVE_SERVERKEY, server_key,
|
||||
strlen (server_key));
|
||||
}
|
||||
|
||||
static void prep_server_socket (int set_heartbeats_,
|
||||
int is_curve_,
|
||||
void **server_out_,
|
||||
void **mon_out_,
|
||||
char *endpoint_,
|
||||
size_t ep_length_,
|
||||
int socket_type_)
|
||||
{
|
||||
// We'll be using this socket in raw mode
|
||||
void *server = test_context_socket (socket_type_);
|
||||
|
||||
int value = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_LINGER, &value, sizeof (value)));
|
||||
|
||||
if (set_heartbeats_) {
|
||||
value = 50;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_HEARTBEAT_IVL, &value, sizeof (value)));
|
||||
}
|
||||
|
||||
if (is_curve_)
|
||||
setup_curve (server, 1);
|
||||
|
||||
bind_loopback_ipv4 (server, endpoint_, ep_length_);
|
||||
|
||||
// Create and connect a socket for collecting monitor events on dealer
|
||||
void *server_mon = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (
|
||||
server, "inproc://monitor-dealer",
|
||||
ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_ACCEPTED));
|
||||
|
||||
// Connect to the inproc endpoint so we'll get events
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (server_mon, "inproc://monitor-dealer"));
|
||||
|
||||
*server_out_ = server;
|
||||
*mon_out_ = server_mon;
|
||||
}
|
||||
|
||||
// This checks for a broken TCP connection (or, in this case a stuck one
|
||||
// where the peer never responds to PINGS). There should be an accepted event
|
||||
// then a disconnect event.
|
||||
static void test_heartbeat_timeout (int server_type_, int mock_ping_)
|
||||
{
|
||||
int rc;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *server, *server_mon;
|
||||
prep_server_socket (!mock_ping_, 0, &server, &server_mon, my_endpoint,
|
||||
MAX_SOCKET_STRING, server_type_);
|
||||
|
||||
fd_t s = connect_socket (my_endpoint);
|
||||
|
||||
// Mock a ZMTP 3 client so we can forcibly time out a connection
|
||||
mock_handshake (s, mock_ping_);
|
||||
|
||||
// By now everything should report as connected
|
||||
rc = get_monitor_event (server_mon);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, rc);
|
||||
|
||||
if (!mock_ping_) {
|
||||
// We should have been disconnected
|
||||
rc = get_monitor_event (server_mon);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_DISCONNECTED, rc);
|
||||
}
|
||||
|
||||
close (s);
|
||||
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (server_mon);
|
||||
}
|
||||
|
||||
// This checks that peers respect the TTL value in ping messages
|
||||
// We set up a mock ZMTP 3 client and send a ping message with a TLL
|
||||
// to a server that is not doing any heartbeating. Then we sleep,
|
||||
// if the server disconnects the client, then we know the TTL did
|
||||
// its thing correctly.
|
||||
static void test_heartbeat_ttl (int client_type_, int server_type_)
|
||||
{
|
||||
int rc, value;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *server, *server_mon, *client;
|
||||
prep_server_socket (0, 0, &server, &server_mon, my_endpoint,
|
||||
MAX_SOCKET_STRING, server_type_);
|
||||
|
||||
client = test_context_socket (client_type_);
|
||||
|
||||
// Set the heartbeat TTL to 0.1 seconds
|
||||
value = 100;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_HEARTBEAT_TTL, &value, sizeof (value)));
|
||||
|
||||
// Set the heartbeat interval to much longer than the TTL so that
|
||||
// the socket times out oon the remote side.
|
||||
value = 250;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_HEARTBEAT_IVL, &value, sizeof (value)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
// By now everything should report as connected
|
||||
rc = get_monitor_event (server_mon);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, rc);
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// We should have been disconnected
|
||||
rc = get_monitor_event (server_mon);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_DISCONNECTED, rc);
|
||||
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (server_mon);
|
||||
test_context_socket_close (client);
|
||||
}
|
||||
|
||||
// This checks for normal operation - that is pings and pongs being
|
||||
// exchanged normally. There should be an accepted event on the server,
|
||||
// and then no event afterwards.
|
||||
static void
|
||||
test_heartbeat_notimeout (int is_curve_, int client_type_, int server_type_)
|
||||
{
|
||||
int rc;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *server, *server_mon;
|
||||
prep_server_socket (1, is_curve_, &server, &server_mon, my_endpoint,
|
||||
MAX_SOCKET_STRING, server_type_);
|
||||
|
||||
void *client = test_context_socket (client_type_);
|
||||
if (is_curve_)
|
||||
setup_curve (client, 0);
|
||||
rc = zmq_connect (client, my_endpoint);
|
||||
|
||||
// Give it a sec to connect and handshake
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// By now everything should report as connected
|
||||
rc = get_monitor_event (server_mon);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, rc);
|
||||
|
||||
// We should still be connected because pings and pongs are happenin'
|
||||
rc = get_monitor_event (server_mon);
|
||||
// TODO: this fails ~1% of the runs on OBS but it does not seem to be reproducible anywhere else
|
||||
if (rc == 512)
|
||||
TEST_IGNORE_MESSAGE (
|
||||
"Unreliable test occasionally fails on slow CIs, ignoring");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
|
||||
test_context_socket_close (client);
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (server_mon);
|
||||
}
|
||||
|
||||
void test_heartbeat_timeout_router ()
|
||||
{
|
||||
test_heartbeat_timeout (ZMQ_ROUTER, 0);
|
||||
}
|
||||
|
||||
void test_heartbeat_timeout_router_mock_ping ()
|
||||
{
|
||||
test_heartbeat_timeout (ZMQ_ROUTER, 1);
|
||||
}
|
||||
|
||||
#define DEFINE_TESTS(first, second, first_define, second_define) \
|
||||
void test_heartbeat_ttl_##first##_##second () \
|
||||
{ \
|
||||
test_heartbeat_ttl (first_define, second_define); \
|
||||
} \
|
||||
void test_heartbeat_notimeout_##first##_##second () \
|
||||
{ \
|
||||
test_heartbeat_notimeout (0, first_define, second_define); \
|
||||
} \
|
||||
void test_heartbeat_notimeout_##first##_##second##_with_curve () \
|
||||
{ \
|
||||
test_heartbeat_notimeout (1, first_define, second_define); \
|
||||
}
|
||||
|
||||
DEFINE_TESTS (dealer, router, ZMQ_DEALER, ZMQ_ROUTER)
|
||||
DEFINE_TESTS (req, rep, ZMQ_REQ, ZMQ_REP)
|
||||
DEFINE_TESTS (pull, push, ZMQ_PULL, ZMQ_PUSH)
|
||||
DEFINE_TESTS (sub, pub, ZMQ_SUB, ZMQ_PUB)
|
||||
DEFINE_TESTS (pair, pair, ZMQ_PAIR, ZMQ_PAIR)
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
DEFINE_TESTS (gather, scatter, ZMQ_GATHER, ZMQ_SCATTER)
|
||||
DEFINE_TESTS (client, server, ZMQ_CLIENT, ZMQ_SERVER)
|
||||
#endif
|
||||
|
||||
const int deciseconds_per_millisecond = 100;
|
||||
const int heartbeat_ttl_max =
|
||||
(UINT16_MAX + 1) * deciseconds_per_millisecond - 1;
|
||||
|
||||
void test_setsockopt_heartbeat_success (const int value_)
|
||||
{
|
||||
void *const socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (socket, ZMQ_HEARTBEAT_TTL, &value_, sizeof (value_)));
|
||||
|
||||
int value_read;
|
||||
size_t value_read_size = sizeof (value_read);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (socket, ZMQ_HEARTBEAT_TTL,
|
||||
&value_read, &value_read_size));
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (value_ - value_ % deciseconds_per_millisecond,
|
||||
value_read);
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_setsockopt_heartbeat_ttl_max ()
|
||||
{
|
||||
test_setsockopt_heartbeat_success (heartbeat_ttl_max);
|
||||
}
|
||||
|
||||
void test_setsockopt_heartbeat_ttl_more_than_max_fails ()
|
||||
{
|
||||
void *const socket = test_context_socket (ZMQ_PAIR);
|
||||
const int value = heartbeat_ttl_max + 1;
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL,
|
||||
zmq_setsockopt (socket, ZMQ_HEARTBEAT_TTL, &value, sizeof (value)));
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_setsockopt_heartbeat_ttl_near_zero ()
|
||||
{
|
||||
test_setsockopt_heartbeat_success (deciseconds_per_millisecond - 1);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
// The test cases are very long-running. The default timeout of 60 seconds
|
||||
// is not always enough.
|
||||
setup_test_environment (90);
|
||||
|
||||
UNITY_BEGIN ();
|
||||
|
||||
RUN_TEST (test_heartbeat_timeout_router);
|
||||
RUN_TEST (test_heartbeat_timeout_router_mock_ping);
|
||||
|
||||
RUN_TEST (test_heartbeat_ttl_dealer_router);
|
||||
RUN_TEST (test_heartbeat_ttl_req_rep);
|
||||
RUN_TEST (test_heartbeat_ttl_pull_push);
|
||||
RUN_TEST (test_heartbeat_ttl_sub_pub);
|
||||
RUN_TEST (test_heartbeat_ttl_pair_pair);
|
||||
|
||||
RUN_TEST (test_setsockopt_heartbeat_ttl_max);
|
||||
RUN_TEST (test_setsockopt_heartbeat_ttl_more_than_max_fails);
|
||||
RUN_TEST (test_setsockopt_heartbeat_ttl_near_zero);
|
||||
|
||||
RUN_TEST (test_heartbeat_notimeout_dealer_router);
|
||||
RUN_TEST (test_heartbeat_notimeout_req_rep);
|
||||
RUN_TEST (test_heartbeat_notimeout_pull_push);
|
||||
RUN_TEST (test_heartbeat_notimeout_sub_pub);
|
||||
RUN_TEST (test_heartbeat_notimeout_pair_pair);
|
||||
|
||||
RUN_TEST (test_heartbeat_notimeout_dealer_router_with_curve);
|
||||
RUN_TEST (test_heartbeat_notimeout_req_rep_with_curve);
|
||||
RUN_TEST (test_heartbeat_notimeout_pull_push_with_curve);
|
||||
RUN_TEST (test_heartbeat_notimeout_sub_pub_with_curve);
|
||||
RUN_TEST (test_heartbeat_notimeout_pair_pair_with_curve);
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
RUN_TEST (test_heartbeat_ttl_client_server);
|
||||
RUN_TEST (test_heartbeat_ttl_gather_scatter);
|
||||
|
||||
RUN_TEST (test_heartbeat_notimeout_client_server);
|
||||
RUN_TEST (test_heartbeat_notimeout_gather_scatter);
|
||||
|
||||
RUN_TEST (test_heartbeat_notimeout_client_server_with_curve);
|
||||
RUN_TEST (test_heartbeat_notimeout_gather_scatter_with_curve);
|
||||
#endif
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
107
tests/test_hello_msg.cpp
Normal file
107
tests/test_hello_msg.cpp
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
Copyright (c) 2007-2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test (const char *address)
|
||||
{
|
||||
// Create a router
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
// set router socket options
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_HELLO_MSG, "H", 1));
|
||||
|
||||
// bind router
|
||||
test_bind (router, address, my_endpoint, MAX_SOCKET_STRING);
|
||||
|
||||
// Create a dealer
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));
|
||||
|
||||
// Receive the hello message
|
||||
recv_string_expect_success (dealer, "H", 0);
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (dealer);
|
||||
test_context_socket_close (router);
|
||||
}
|
||||
|
||||
void test_tcp ()
|
||||
{
|
||||
test ("tcp://127.0.0.1:*");
|
||||
}
|
||||
|
||||
void test_inproc ()
|
||||
{
|
||||
test ("inproc://hello-msg");
|
||||
}
|
||||
|
||||
void test_inproc_late_bind ()
|
||||
{
|
||||
char address[] = "inproc://late-hello-msg";
|
||||
|
||||
// Create a server
|
||||
void *server = test_context_socket (ZMQ_SERVER);
|
||||
|
||||
// set server socket options
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (server, ZMQ_HELLO_MSG, "W", 1));
|
||||
|
||||
// Create a dealer
|
||||
void *client = test_context_socket (ZMQ_CLIENT);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_HELLO_MSG, "H", 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, address));
|
||||
|
||||
// bind server after the dealer
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, address));
|
||||
|
||||
// Receive the welcome message from server
|
||||
recv_string_expect_success (client, "W", 0);
|
||||
|
||||
// Receive the hello message from client
|
||||
recv_string_expect_success (server, "H", 0);
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (client);
|
||||
test_context_socket_close (server);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_tcp);
|
||||
RUN_TEST (test_inproc);
|
||||
RUN_TEST (test_inproc_late_bind);
|
||||
return UNITY_END ();
|
||||
}
|
||||
76
tests/test_hiccup_msg.cpp
Normal file
76
tests/test_hiccup_msg.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (c) 2007-2021 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test ()
|
||||
{
|
||||
char address[MAX_SOCKET_STRING];
|
||||
size_t addr_length = sizeof (address);
|
||||
|
||||
// Create a server
|
||||
void *server = test_context_socket (ZMQ_SERVER);
|
||||
|
||||
// bind server
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (server, "tcp://127.0.0.1:*"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (server, ZMQ_LAST_ENDPOINT, address, &addr_length));
|
||||
|
||||
// Create a client
|
||||
void *client = test_context_socket (ZMQ_CLIENT);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_HELLO_MSG, "HELLO", 5));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_HICCUP_MSG, "HICCUP", 6));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, address));
|
||||
|
||||
// Receive the hello message from client
|
||||
recv_string_expect_success (server, "HELLO", 0);
|
||||
|
||||
// Kill the server
|
||||
test_context_socket_close (server);
|
||||
|
||||
// Receive the hiccup message
|
||||
recv_string_expect_success (client, "HICCUP", 0);
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (client);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test);
|
||||
return UNITY_END ();
|
||||
}
|
||||
306
tests/test_hwm.cpp
Normal file
306
tests/test_hwm.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
const int MAX_SENDS = 10000;
|
||||
|
||||
enum TestType
|
||||
{
|
||||
BIND_FIRST,
|
||||
CONNECT_FIRST
|
||||
};
|
||||
|
||||
void test_defaults ()
|
||||
{
|
||||
// Set up bind socket
|
||||
void *bind_socket = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://a"));
|
||||
|
||||
// Set up connect socket
|
||||
void *connect_socket = test_context_socket (ZMQ_PUSH);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://a"));
|
||||
|
||||
// Send until we block
|
||||
int send_count = 0;
|
||||
while (send_count < MAX_SENDS
|
||||
&& zmq_send (connect_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++send_count;
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Now receive all sent messages
|
||||
int recv_count = 0;
|
||||
while (zmq_recv (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++recv_count;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (send_count, recv_count);
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (connect_socket);
|
||||
test_context_socket_close (bind_socket);
|
||||
|
||||
// Default values are 1000 on send and 1000 one receive, so 2000 total
|
||||
TEST_ASSERT_EQUAL_INT (2000, send_count);
|
||||
}
|
||||
|
||||
int count_msg (int send_hwm_, int recv_hwm_, TestType test_type_)
|
||||
{
|
||||
void *bind_socket;
|
||||
void *connect_socket;
|
||||
if (test_type_ == BIND_FIRST) {
|
||||
// Set up bind socket
|
||||
bind_socket = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
bind_socket, ZMQ_RCVHWM, &recv_hwm_, sizeof (recv_hwm_)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://a"));
|
||||
|
||||
// Set up connect socket
|
||||
connect_socket = test_context_socket (ZMQ_PUSH);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
connect_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://a"));
|
||||
|
||||
// we must wait for the connect to succeed here, unfortunately we don't
|
||||
// have monitoring events for inproc, so we just hope SETTLE_TIME suffices
|
||||
msleep (SETTLE_TIME);
|
||||
} else {
|
||||
// Set up connect socket
|
||||
connect_socket = test_context_socket (ZMQ_PUSH);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
connect_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://a"));
|
||||
|
||||
// Set up bind socket
|
||||
bind_socket = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
bind_socket, ZMQ_RCVHWM, &recv_hwm_, sizeof (recv_hwm_)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://a"));
|
||||
}
|
||||
|
||||
// Send until we block
|
||||
int send_count = 0;
|
||||
while (send_count < MAX_SENDS
|
||||
&& zmq_send (connect_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++send_count;
|
||||
|
||||
// Now receive all sent messages
|
||||
int recv_count = 0;
|
||||
while (zmq_recv (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++recv_count;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (send_count, recv_count);
|
||||
|
||||
// Now it should be possible to send one more.
|
||||
send_string_expect_success (connect_socket, NULL, 0);
|
||||
|
||||
// Consume the remaining message.
|
||||
recv_string_expect_success (bind_socket, NULL, 0);
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (connect_socket);
|
||||
test_context_socket_close (bind_socket);
|
||||
|
||||
return send_count;
|
||||
}
|
||||
|
||||
int test_inproc_bind_first (int send_hwm_, int recv_hwm_)
|
||||
{
|
||||
return count_msg (send_hwm_, recv_hwm_, BIND_FIRST);
|
||||
}
|
||||
|
||||
int test_inproc_connect_first (int send_hwm_, int recv_hwm_)
|
||||
{
|
||||
return count_msg (send_hwm_, recv_hwm_, CONNECT_FIRST);
|
||||
}
|
||||
|
||||
int test_inproc_connect_and_close_first (int send_hwm_, int recv_hwm_)
|
||||
{
|
||||
// Set up connect socket
|
||||
void *connect_socket = test_context_socket (ZMQ_PUSH);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (connect_socket, ZMQ_SNDHWM,
|
||||
&send_hwm_, sizeof (send_hwm_)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://a"));
|
||||
|
||||
// Send until we block
|
||||
int send_count = 0;
|
||||
while (send_count < MAX_SENDS
|
||||
&& zmq_send (connect_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++send_count;
|
||||
|
||||
// Close connect
|
||||
test_context_socket_close (connect_socket);
|
||||
|
||||
// Set up bind socket
|
||||
void *bind_socket = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (bind_socket, ZMQ_RCVHWM, &recv_hwm_, sizeof (recv_hwm_)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://a"));
|
||||
|
||||
// Now receive all sent messages
|
||||
int recv_count = 0;
|
||||
while (zmq_recv (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++recv_count;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (send_count, recv_count);
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (bind_socket);
|
||||
|
||||
return send_count;
|
||||
}
|
||||
|
||||
int test_inproc_bind_and_close_first (int send_hwm_, int /* recv_hwm */)
|
||||
{
|
||||
// Set up bind socket
|
||||
void *bind_socket = test_context_socket (ZMQ_PUSH);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (bind_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://a"));
|
||||
|
||||
// Send until we block
|
||||
int send_count = 0;
|
||||
while (send_count < MAX_SENDS
|
||||
&& zmq_send (bind_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++send_count;
|
||||
|
||||
// Close bind
|
||||
test_context_socket_close (bind_socket);
|
||||
|
||||
/* TODO Can't currently do connect without then wiring up a bind as things hang, this needs top be fixed.
|
||||
// Set up connect socket
|
||||
void *connect_socket = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (connect_socket, ZMQ_RCVHWM, &recv_hwm, sizeof (recv_hwm)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://a"));
|
||||
|
||||
// Now receive all sent messages
|
||||
int recv_count = 0;
|
||||
while (zmq_recv (connect_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++recv_count;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT(send_count, recv_count);
|
||||
*/
|
||||
|
||||
// Clean up
|
||||
//test_context_socket_close (connect_socket);
|
||||
|
||||
return send_count;
|
||||
}
|
||||
|
||||
void test_infinite_both_inproc_bind_first ()
|
||||
{
|
||||
int count = test_inproc_bind_first (0, 0);
|
||||
TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);
|
||||
}
|
||||
|
||||
void test_infinite_both_inproc_connect_first ()
|
||||
{
|
||||
int count = test_inproc_connect_first (0, 0);
|
||||
TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);
|
||||
}
|
||||
|
||||
void test_infinite_receive_inproc_bind_first ()
|
||||
{
|
||||
int count = test_inproc_bind_first (1, 0);
|
||||
TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);
|
||||
}
|
||||
|
||||
void test_infinite_receive_inproc_connect_first ()
|
||||
{
|
||||
int count = test_inproc_connect_first (1, 0);
|
||||
TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);
|
||||
}
|
||||
|
||||
void test_infinite_send_inproc_bind_first ()
|
||||
{
|
||||
int count = test_inproc_bind_first (0, 1);
|
||||
TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);
|
||||
}
|
||||
|
||||
void test_infinite_send_inproc_connect_first ()
|
||||
{
|
||||
int count = test_inproc_connect_first (0, 1);
|
||||
TEST_ASSERT_EQUAL_INT (MAX_SENDS, count);
|
||||
}
|
||||
|
||||
void test_finite_both_bind_first ()
|
||||
{
|
||||
// Send and recv buffers hwm 1, so total that can be queued is 2
|
||||
int count = test_inproc_bind_first (1, 1);
|
||||
TEST_ASSERT_EQUAL_INT (2, count);
|
||||
}
|
||||
void test_finite_both_connect_first ()
|
||||
{
|
||||
// Send and recv buffers hwm 1, so total that can be queued is 2
|
||||
int count = test_inproc_connect_first (1, 1);
|
||||
TEST_ASSERT_EQUAL_INT (2, count);
|
||||
}
|
||||
|
||||
void test_infinite_recv_connect_and_close_first ()
|
||||
{
|
||||
// Send hwm of 1, send before bind so total that can be queued is 1
|
||||
int count = test_inproc_connect_and_close_first (1, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, count);
|
||||
}
|
||||
|
||||
void test_infinite_recv_bind_and_close_first ()
|
||||
{
|
||||
// Send hwm of 1, send from bind side before connect so total that can be queued should be 1,
|
||||
// however currently all messages get thrown away before the connect. BUG?
|
||||
/*int count = */ test_inproc_bind_and_close_first (1, 0);
|
||||
// TEST_ASSERT_EQUAL_INT (1, count);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_defaults);
|
||||
|
||||
RUN_TEST (test_infinite_both_inproc_bind_first);
|
||||
RUN_TEST (test_infinite_both_inproc_connect_first);
|
||||
|
||||
RUN_TEST (test_infinite_receive_inproc_bind_first);
|
||||
RUN_TEST (test_infinite_receive_inproc_connect_first);
|
||||
|
||||
RUN_TEST (test_infinite_send_inproc_bind_first);
|
||||
RUN_TEST (test_infinite_send_inproc_connect_first);
|
||||
|
||||
RUN_TEST (test_finite_both_bind_first);
|
||||
RUN_TEST (test_finite_both_connect_first);
|
||||
|
||||
RUN_TEST (test_infinite_recv_connect_and_close_first);
|
||||
RUN_TEST (test_infinite_recv_bind_and_close_first);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
304
tests/test_hwm_pubsub.cpp
Normal file
304
tests/test_hwm_pubsub.cpp
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
// NOTE: on OSX the endpoint returned by ZMQ_LAST_ENDPOINT may be quite long,
|
||||
// ensure we have extra space for that:
|
||||
#define SOCKET_STRING_LEN (MAX_SOCKET_STRING * 4)
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
int test_defaults (int send_hwm_, int msg_cnt_, const char *endpoint_)
|
||||
{
|
||||
char pub_endpoint[SOCKET_STRING_LEN];
|
||||
|
||||
// Set up and bind XPUB socket
|
||||
void *pub_socket = test_context_socket (ZMQ_XPUB);
|
||||
test_bind (pub_socket, endpoint_, pub_endpoint, sizeof pub_endpoint);
|
||||
|
||||
// Set up and connect SUB socket
|
||||
void *sub_socket = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, pub_endpoint));
|
||||
|
||||
//set a hwm on publisher
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (pub_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, 0, 0));
|
||||
|
||||
// Wait before starting TX operations till 1 subscriber has subscribed
|
||||
// (in this test there's 1 subscriber only)
|
||||
const char subscription_to_all_topics[] = {1, 0};
|
||||
recv_string_expect_success (pub_socket, subscription_to_all_topics, 0);
|
||||
|
||||
// Send until we reach "mute" state
|
||||
int send_count = 0;
|
||||
while (send_count < msg_cnt_
|
||||
&& zmq_send (pub_socket, "test message", 13, ZMQ_DONTWAIT) == 13)
|
||||
++send_count;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (send_hwm_, send_count);
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Now receive all sent messages
|
||||
int recv_count = 0;
|
||||
char dummybuff[64];
|
||||
while (13 == zmq_recv (sub_socket, &dummybuff, 64, ZMQ_DONTWAIT)) {
|
||||
++recv_count;
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (send_hwm_, recv_count);
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (sub_socket);
|
||||
test_context_socket_close (pub_socket);
|
||||
|
||||
return recv_count;
|
||||
}
|
||||
|
||||
int receive (void *socket_, int *is_termination_)
|
||||
{
|
||||
int recv_count = 0;
|
||||
*is_termination_ = 0;
|
||||
|
||||
// Now receive all sent messages
|
||||
char buffer[255];
|
||||
int len;
|
||||
while ((len = zmq_recv (socket_, buffer, sizeof (buffer), 0)) >= 0) {
|
||||
++recv_count;
|
||||
|
||||
if (len == 3 && strncmp (buffer, "end", len) == 0) {
|
||||
*is_termination_ = 1;
|
||||
return recv_count;
|
||||
}
|
||||
}
|
||||
|
||||
return recv_count;
|
||||
}
|
||||
|
||||
int test_blocking (int send_hwm_, int msg_cnt_, const char *endpoint_)
|
||||
{
|
||||
char pub_endpoint[SOCKET_STRING_LEN];
|
||||
|
||||
// Set up bind socket
|
||||
void *pub_socket = test_context_socket (ZMQ_XPUB);
|
||||
test_bind (pub_socket, endpoint_, pub_endpoint, sizeof pub_endpoint);
|
||||
|
||||
// Set up connect socket
|
||||
void *sub_socket = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, pub_endpoint));
|
||||
|
||||
//set a hwm on publisher
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (pub_socket, ZMQ_SNDHWM, &send_hwm_, sizeof (send_hwm_)));
|
||||
int wait = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (pub_socket, ZMQ_XPUB_NODROP, &wait, sizeof (wait)));
|
||||
int timeout_ms = 10;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
sub_socket, ZMQ_RCVTIMEO, &timeout_ms, sizeof (timeout_ms)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, 0, 0));
|
||||
|
||||
// Wait before starting TX operations till 1 subscriber has subscribed
|
||||
// (in this test there's 1 subscriber only)
|
||||
const uint8_t subscription_to_all_topics[] = {1};
|
||||
recv_array_expect_success (pub_socket, subscription_to_all_topics, 0);
|
||||
|
||||
// Send until we block
|
||||
int send_count = 0;
|
||||
int recv_count = 0;
|
||||
int blocked_count = 0;
|
||||
int is_termination = 0;
|
||||
while (send_count < msg_cnt_) {
|
||||
const int rc = zmq_send (pub_socket, NULL, 0, ZMQ_DONTWAIT);
|
||||
if (rc == 0) {
|
||||
++send_count;
|
||||
} else if (-1 == rc) {
|
||||
// if the PUB socket blocks due to HWM, errno should be EAGAIN:
|
||||
blocked_count++;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, -1);
|
||||
recv_count += receive (sub_socket, &is_termination);
|
||||
}
|
||||
}
|
||||
|
||||
// if send_hwm_ < msg_cnt_, we should block at least once:
|
||||
char counts_string[128];
|
||||
snprintf (counts_string, sizeof counts_string - 1,
|
||||
"sent = %i, received = %i", send_count, recv_count);
|
||||
TEST_ASSERT_GREATER_THAN_INT_MESSAGE (0, blocked_count, counts_string);
|
||||
|
||||
// dequeue SUB socket again, to make sure XPUB has space to send the termination message
|
||||
recv_count += receive (sub_socket, &is_termination);
|
||||
|
||||
// send termination message
|
||||
send_string_expect_success (pub_socket, "end", 0);
|
||||
|
||||
// now block on the SUB side till we get the termination message
|
||||
while (is_termination == 0)
|
||||
recv_count += receive (sub_socket, &is_termination);
|
||||
|
||||
// remove termination message from the count:
|
||||
recv_count--;
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (send_count, recv_count);
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (sub_socket);
|
||||
test_context_socket_close (pub_socket);
|
||||
|
||||
return recv_count;
|
||||
}
|
||||
|
||||
// hwm should apply to the messages that have already been received
|
||||
// with hwm 11024: send 9999 msg, receive 9999, send 1100, receive 1100
|
||||
void test_reset_hwm ()
|
||||
{
|
||||
const int first_count = 9999;
|
||||
const int second_count = 1100;
|
||||
int hwm = 11024;
|
||||
char my_endpoint[SOCKET_STRING_LEN];
|
||||
|
||||
// Set up bind socket
|
||||
void *pub_socket = test_context_socket (ZMQ_PUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (pub_socket, ZMQ_SNDHWM, &hwm, sizeof (hwm)));
|
||||
bind_loopback_ipv4 (pub_socket, my_endpoint, MAX_SOCKET_STRING);
|
||||
|
||||
// Set up connect socket
|
||||
void *sub_socket = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub_socket, ZMQ_RCVHWM, &hwm, sizeof (hwm)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_socket, my_endpoint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub_socket, ZMQ_SUBSCRIBE, 0, 0));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Send messages
|
||||
int send_count = 0;
|
||||
while (send_count < first_count
|
||||
&& zmq_send (pub_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++send_count;
|
||||
TEST_ASSERT_EQUAL_INT (first_count, send_count);
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Now receive all sent messages
|
||||
int recv_count = 0;
|
||||
while (0 == zmq_recv (sub_socket, NULL, 0, ZMQ_DONTWAIT)) {
|
||||
++recv_count;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT (first_count, recv_count);
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Send messages
|
||||
send_count = 0;
|
||||
while (send_count < second_count
|
||||
&& zmq_send (pub_socket, NULL, 0, ZMQ_DONTWAIT) == 0)
|
||||
++send_count;
|
||||
TEST_ASSERT_EQUAL_INT (second_count, send_count);
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Now receive all sent messages
|
||||
recv_count = 0;
|
||||
while (0 == zmq_recv (sub_socket, NULL, 0, ZMQ_DONTWAIT)) {
|
||||
++recv_count;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT (second_count, recv_count);
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (sub_socket);
|
||||
test_context_socket_close (pub_socket);
|
||||
}
|
||||
|
||||
void test_defaults_large (const char *bind_endpoint_)
|
||||
{
|
||||
// send 1000 msg on hwm 1000, receive 1000
|
||||
TEST_ASSERT_EQUAL_INT (1000, test_defaults (1000, 1000, bind_endpoint_));
|
||||
}
|
||||
|
||||
void test_defaults_small (const char *bind_endpoint_)
|
||||
{
|
||||
// send 1000 msg on hwm 100, receive 100
|
||||
TEST_ASSERT_EQUAL_INT (100, test_defaults (100, 100, bind_endpoint_));
|
||||
}
|
||||
|
||||
void test_blocking (const char *bind_endpoint_)
|
||||
{
|
||||
// send 6000 msg on hwm 2000, drops above hwm, only receive hwm:
|
||||
TEST_ASSERT_EQUAL_INT (6000, test_blocking (2000, 6000, bind_endpoint_));
|
||||
}
|
||||
|
||||
#define DEFINE_REGULAR_TEST_CASES(name, bind_endpoint) \
|
||||
void test_defaults_large_##name () \
|
||||
{ \
|
||||
test_defaults_large (bind_endpoint); \
|
||||
} \
|
||||
\
|
||||
void test_defaults_small_##name () \
|
||||
{ \
|
||||
test_defaults_small (bind_endpoint); \
|
||||
} \
|
||||
\
|
||||
void test_blocking_##name () { test_blocking (bind_endpoint); }
|
||||
|
||||
#define RUN_REGULAR_TEST_CASES(name) \
|
||||
RUN_TEST (test_defaults_large_##name); \
|
||||
RUN_TEST (test_defaults_small_##name); \
|
||||
RUN_TEST (test_blocking_##name)
|
||||
|
||||
DEFINE_REGULAR_TEST_CASES (tcp, "tcp://127.0.0.1:*")
|
||||
DEFINE_REGULAR_TEST_CASES (inproc, "inproc://a")
|
||||
|
||||
#if !defined(ZMQ_HAVE_WINDOWS) && !defined(ZMQ_HAVE_GNU)
|
||||
DEFINE_REGULAR_TEST_CASES (ipc, "ipc://*")
|
||||
#endif
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
|
||||
RUN_REGULAR_TEST_CASES (tcp);
|
||||
RUN_REGULAR_TEST_CASES (inproc);
|
||||
|
||||
#if !defined(ZMQ_HAVE_WINDOWS) && !defined(ZMQ_HAVE_GNU)
|
||||
RUN_REGULAR_TEST_CASES (ipc);
|
||||
#endif
|
||||
RUN_TEST (test_reset_hwm);
|
||||
return UNITY_END ();
|
||||
}
|
||||
225
tests/test_immediate.cpp
Normal file
225
tests/test_immediate.cpp
Normal file
@@ -0,0 +1,225 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_immediate_1 ()
|
||||
{
|
||||
int val;
|
||||
int rc;
|
||||
char buffer[16];
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
// TEST 1.
|
||||
// First we're going to attempt to send messages to two
|
||||
// pipes, one connected, the other not. We should see
|
||||
// the PUSH load balancing to both pipes, and hence half
|
||||
// of the messages getting queued, as connect() creates a
|
||||
// pipe immediately.
|
||||
|
||||
void *to = test_context_socket (ZMQ_PULL);
|
||||
|
||||
// Bind the one valid receiver
|
||||
val = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_LINGER, &val, sizeof (val)));
|
||||
bind_loopback_ipv4 (to, my_endpoint, len);
|
||||
|
||||
// Create a socket pushing to two endpoints - only 1 message should arrive.
|
||||
void *from = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
val = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (from, ZMQ_LINGER, &val, sizeof (val)));
|
||||
// This pipe will not connect (provided the ephemeral port is not 5556)
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, "tcp://localhost:5556"));
|
||||
// This pipe will
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, my_endpoint));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// We send 10 messages, 5 should just get stuck in the queue
|
||||
// for the not-yet-connected pipe
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
send_string_expect_success (from, "Hello", 0);
|
||||
}
|
||||
|
||||
// We now consume from the connected pipe
|
||||
// - we should see just 5
|
||||
int timeout = 250;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
|
||||
|
||||
int seen = 0;
|
||||
while (true) {
|
||||
rc = zmq_recv (to, &buffer, sizeof (buffer), 0);
|
||||
if (rc == -1)
|
||||
break; // Break when we didn't get a message
|
||||
seen++;
|
||||
}
|
||||
// TODO: this fails ~1% of the runs on OBS but it does not seem to be reproducible anywhere else
|
||||
if (seen == 0)
|
||||
TEST_IGNORE_MESSAGE (
|
||||
"Unreliable test occasionally fails on slow CIs, ignoring");
|
||||
TEST_ASSERT_EQUAL_INT (5, seen);
|
||||
|
||||
test_context_socket_close (from);
|
||||
test_context_socket_close (to);
|
||||
}
|
||||
|
||||
|
||||
void test_immediate_2 ()
|
||||
{
|
||||
// This time we will do the same thing, connect two pipes,
|
||||
// one of which will succeed in connecting to a bound
|
||||
// receiver, the other of which will fail. However, we will
|
||||
// also set the delay attach on connect flag, which should
|
||||
// cause the pipe attachment to be delayed until the connection
|
||||
// succeeds.
|
||||
|
||||
// Bind the valid socket
|
||||
void *to = test_context_socket (ZMQ_PULL);
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (to, my_endpoint, len);
|
||||
|
||||
int val = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_LINGER, &val, sizeof (val)));
|
||||
|
||||
// Create a socket pushing to two endpoints - all messages should arrive.
|
||||
void *from = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
val = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (from, ZMQ_LINGER, &val, sizeof (val)));
|
||||
|
||||
// Set the key flag
|
||||
val = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (from, ZMQ_IMMEDIATE, &val, sizeof (val)));
|
||||
|
||||
// Connect to the invalid socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, "tcp://localhost:5561"));
|
||||
// Connect to the valid socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (from, my_endpoint));
|
||||
|
||||
// Send 10 messages, all should be routed to the connected pipe
|
||||
for (int i = 0; i < 10; ++i) {
|
||||
send_string_expect_success (from, "Hello", 0);
|
||||
}
|
||||
int timeout = 250;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (to, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
|
||||
|
||||
int seen = 0;
|
||||
while (true) {
|
||||
char buffer[16];
|
||||
int rc = zmq_recv (to, &buffer, sizeof (buffer), 0);
|
||||
if (rc == -1)
|
||||
break; // Break when we didn't get a message
|
||||
seen++;
|
||||
}
|
||||
TEST_ASSERT_EQUAL_INT (10, seen);
|
||||
|
||||
test_context_socket_close (from);
|
||||
test_context_socket_close (to);
|
||||
}
|
||||
|
||||
void test_immediate_3 ()
|
||||
{
|
||||
// This time we want to validate that the same blocking behaviour
|
||||
// occurs with an existing connection that is broken. We will send
|
||||
// messages to a connected pipe, disconnect and verify the messages
|
||||
// block. Then we reconnect and verify messages flow again.
|
||||
void *backend = test_context_socket (ZMQ_DEALER);
|
||||
void *frontend = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
int zero = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (backend, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (frontend, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
|
||||
// Frontend connects to backend using IMMEDIATE
|
||||
int on = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (frontend, ZMQ_IMMEDIATE, &on, sizeof (on)));
|
||||
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (backend, my_endpoint, len);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (frontend, my_endpoint));
|
||||
|
||||
// Ping backend to frontend so we know when the connection is up
|
||||
send_string_expect_success (backend, "Hello", 0);
|
||||
recv_string_expect_success (frontend, "Hello", 0);
|
||||
|
||||
// Send message from frontend to backend
|
||||
send_string_expect_success (frontend, "Hello", ZMQ_DONTWAIT);
|
||||
|
||||
test_context_socket_close (backend);
|
||||
|
||||
// Give time to process disconnect
|
||||
msleep (SETTLE_TIME * 10);
|
||||
|
||||
// Send a message, should fail
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN,
|
||||
zmq_send (frontend, "Hello", 5, ZMQ_DONTWAIT));
|
||||
|
||||
// Recreate backend socket
|
||||
backend = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (backend, ZMQ_LINGER, &zero, sizeof (zero)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, my_endpoint));
|
||||
|
||||
// Ping backend to frontend so we know when the connection is up
|
||||
send_string_expect_success (backend, "Hello", 0);
|
||||
recv_string_expect_success (frontend, "Hello", 0);
|
||||
|
||||
// After the reconnect, should succeed
|
||||
send_string_expect_success (frontend, "Hello", ZMQ_DONTWAIT);
|
||||
|
||||
test_context_socket_close (backend);
|
||||
test_context_socket_close (frontend);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_immediate_1);
|
||||
RUN_TEST (test_immediate_2);
|
||||
RUN_TEST (test_immediate_3);
|
||||
return UNITY_END ();
|
||||
}
|
||||
355
tests/test_inproc_connect.cpp
Normal file
355
tests/test_inproc_connect.cpp
Normal file
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
static void pusher (void * /*unused*/)
|
||||
{
|
||||
// Connect first
|
||||
// do not use test_context_socket here, as it is not thread-safe
|
||||
void *connect_socket = zmq_socket (get_test_context (), ZMQ_PAIR);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://sink"));
|
||||
|
||||
// Queue up some data
|
||||
send_string_expect_success (connect_socket, "foobar", 0);
|
||||
|
||||
// Cleanup
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (connect_socket));
|
||||
}
|
||||
|
||||
static void simult_conn (void *endpt_)
|
||||
{
|
||||
// Pull out arguments - endpoint string
|
||||
const char *endpt = static_cast<const char *> (endpt_);
|
||||
|
||||
// Connect
|
||||
// do not use test_context_socket here, as it is not thread-safe
|
||||
void *connect_socket = zmq_socket (get_test_context (), ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, endpt));
|
||||
recv_string_expect_success (connect_socket, "foobar", 0);
|
||||
|
||||
// Cleanup
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (connect_socket));
|
||||
}
|
||||
|
||||
static void simult_bind (void *endpt_)
|
||||
{
|
||||
// Pull out arguments - context followed by endpoint string
|
||||
const char *endpt = static_cast<const char *> (endpt_);
|
||||
|
||||
// Bind
|
||||
// do not use test_context_socket here, as it is not thread-safe
|
||||
void *bind_socket = zmq_socket (get_test_context (), ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, endpt));
|
||||
send_string_expect_success (bind_socket, "foobar", 0);
|
||||
|
||||
// Cleanup
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (bind_socket));
|
||||
}
|
||||
|
||||
void test_bind_before_connect ()
|
||||
{
|
||||
// Bind first
|
||||
void *bind_socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://bbc"));
|
||||
|
||||
// Now connect
|
||||
void *connect_socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://bbc"));
|
||||
|
||||
// Queue up some data
|
||||
send_string_expect_success (connect_socket, "foobar", 0);
|
||||
|
||||
// Read pending message
|
||||
recv_string_expect_success (bind_socket, "foobar", 0);
|
||||
|
||||
// Cleanup
|
||||
test_context_socket_close (connect_socket);
|
||||
test_context_socket_close (bind_socket);
|
||||
}
|
||||
|
||||
void test_connect_before_bind ()
|
||||
{
|
||||
// Connect first
|
||||
void *connect_socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://cbb"));
|
||||
|
||||
// Queue up some data
|
||||
send_string_expect_success (connect_socket, "foobar", 0);
|
||||
|
||||
// Now bind
|
||||
void *bind_socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://cbb"));
|
||||
|
||||
// Read pending message
|
||||
recv_string_expect_success (bind_socket, "foobar", 0);
|
||||
|
||||
// Cleanup
|
||||
test_context_socket_close (connect_socket);
|
||||
test_context_socket_close (bind_socket);
|
||||
}
|
||||
|
||||
void test_connect_before_bind_pub_sub ()
|
||||
{
|
||||
// Connect first
|
||||
void *connect_socket = test_context_socket (ZMQ_PUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://cbbps"));
|
||||
|
||||
// Queue up some data, this will be dropped
|
||||
send_string_expect_success (connect_socket, "before", 0);
|
||||
|
||||
// Now bind
|
||||
void *bind_socket = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (bind_socket, ZMQ_SUBSCRIBE, "", 0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://cbbps"));
|
||||
|
||||
// Wait for pub-sub connection to happen
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Queue up some data, this not will be dropped
|
||||
send_string_expect_success (connect_socket, "after", 0);
|
||||
|
||||
// Read pending message
|
||||
recv_string_expect_success (bind_socket, "after", 0);
|
||||
|
||||
// Cleanup
|
||||
test_context_socket_close (connect_socket);
|
||||
test_context_socket_close (bind_socket);
|
||||
}
|
||||
|
||||
void test_connect_before_bind_ctx_term ()
|
||||
{
|
||||
for (int i = 0; i < 20; ++i) {
|
||||
// Connect first
|
||||
void *connect_socket = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
char ep[32];
|
||||
sprintf (ep, "inproc://cbbrr%d", i);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, ep));
|
||||
|
||||
// Cleanup
|
||||
test_context_socket_close (connect_socket);
|
||||
}
|
||||
}
|
||||
|
||||
void test_multiple_connects ()
|
||||
{
|
||||
const unsigned int no_of_connects = 10;
|
||||
|
||||
void *connect_socket[no_of_connects];
|
||||
|
||||
// Connect first
|
||||
for (unsigned int i = 0; i < no_of_connects; ++i) {
|
||||
connect_socket[i] = test_context_socket (ZMQ_PUSH);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (connect_socket[i], "inproc://multiple"));
|
||||
|
||||
// Queue up some data
|
||||
send_string_expect_success (connect_socket[i], "foobar", 0);
|
||||
}
|
||||
|
||||
// Now bind
|
||||
void *bind_socket = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://multiple"));
|
||||
|
||||
for (unsigned int i = 0; i < no_of_connects; ++i) {
|
||||
recv_string_expect_success (bind_socket, "foobar", 0);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
for (unsigned int i = 0; i < no_of_connects; ++i) {
|
||||
test_context_socket_close (connect_socket[i]);
|
||||
}
|
||||
|
||||
test_context_socket_close (bind_socket);
|
||||
}
|
||||
|
||||
void test_multiple_threads ()
|
||||
{
|
||||
const unsigned int no_of_threads = 30;
|
||||
|
||||
void *threads[no_of_threads];
|
||||
|
||||
// Connect first
|
||||
for (unsigned int i = 0; i < no_of_threads; ++i) {
|
||||
threads[i] = zmq_threadstart (&pusher, NULL);
|
||||
}
|
||||
|
||||
// Now bind
|
||||
void *bind_socket = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket, "inproc://sink"));
|
||||
|
||||
for (unsigned int i = 0; i < no_of_threads; ++i) {
|
||||
// Read pending message
|
||||
recv_string_expect_success (bind_socket, "foobar", 0);
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
for (unsigned int i = 0; i < no_of_threads; ++i) {
|
||||
zmq_threadclose (threads[i]);
|
||||
}
|
||||
|
||||
test_context_socket_close (bind_socket);
|
||||
}
|
||||
|
||||
void test_simultaneous_connect_bind_threads ()
|
||||
{
|
||||
const unsigned int no_of_times = 50;
|
||||
void *threads[no_of_times * 2];
|
||||
void *thr_args[no_of_times];
|
||||
char endpts[no_of_times][20];
|
||||
|
||||
// Set up thread arguments: context followed by endpoint string
|
||||
for (unsigned int i = 0; i < no_of_times; ++i) {
|
||||
thr_args[i] = (void *) endpts[i];
|
||||
sprintf (endpts[i], "inproc://foo_%d", i);
|
||||
}
|
||||
|
||||
// Spawn all threads as simultaneously as possible
|
||||
for (unsigned int i = 0; i < no_of_times; ++i) {
|
||||
threads[i * 2 + 0] = zmq_threadstart (&simult_conn, thr_args[i]);
|
||||
threads[i * 2 + 1] = zmq_threadstart (&simult_bind, thr_args[i]);
|
||||
}
|
||||
|
||||
// Close all threads
|
||||
for (unsigned int i = 0; i < no_of_times; ++i) {
|
||||
zmq_threadclose (threads[i * 2 + 0]);
|
||||
zmq_threadclose (threads[i * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
void test_routing_id ()
|
||||
{
|
||||
// Create the infrastructure
|
||||
void *sc = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "inproc://routing_id"));
|
||||
|
||||
void *sb = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "inproc://routing_id"));
|
||||
|
||||
// Send 2-part message.
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (sc, "A", 1, ZMQ_SNDMORE)));
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (sc, "B", 1, 0)));
|
||||
|
||||
// Routing id comes first.
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0));
|
||||
TEST_ASSERT_EQUAL_INT (1, zmq_msg_more (&msg));
|
||||
|
||||
// Then the first part of the message body.
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0)));
|
||||
TEST_ASSERT_EQUAL_INT (1, zmq_msg_more (&msg));
|
||||
|
||||
// And finally, the second part of the message body.
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0)));
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_msg_more (&msg));
|
||||
|
||||
// Deallocate the infrastructure.
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void test_connect_only ()
|
||||
{
|
||||
void *connect_socket = test_context_socket (ZMQ_PUSH);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://a"));
|
||||
|
||||
test_context_socket_close (connect_socket);
|
||||
}
|
||||
|
||||
|
||||
void test_unbind ()
|
||||
{
|
||||
// Bind and unbind socket 1
|
||||
void *bind_socket1 = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket1, "inproc://unbind"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (bind_socket1, "inproc://unbind"));
|
||||
|
||||
// Bind socket 2
|
||||
void *bind_socket2 = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (bind_socket2, "inproc://unbind"));
|
||||
|
||||
// Now connect
|
||||
void *connect_socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://unbind"));
|
||||
|
||||
// Queue up some data
|
||||
send_string_expect_success (connect_socket, "foobar", 0);
|
||||
|
||||
// Read pending message
|
||||
recv_string_expect_success (bind_socket2, "foobar", 0);
|
||||
|
||||
// Cleanup
|
||||
test_context_socket_close (connect_socket);
|
||||
test_context_socket_close (bind_socket1);
|
||||
test_context_socket_close (bind_socket2);
|
||||
}
|
||||
|
||||
void test_shutdown_during_pend ()
|
||||
{
|
||||
// Connect first
|
||||
void *connect_socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (connect_socket, "inproc://cbb"));
|
||||
|
||||
zmq_ctx_shutdown (get_test_context ());
|
||||
|
||||
// Cleanup
|
||||
test_context_socket_close (connect_socket);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_bind_before_connect);
|
||||
RUN_TEST (test_connect_before_bind);
|
||||
RUN_TEST (test_connect_before_bind_pub_sub);
|
||||
RUN_TEST (test_connect_before_bind_ctx_term);
|
||||
RUN_TEST (test_multiple_connects);
|
||||
RUN_TEST (test_multiple_threads);
|
||||
RUN_TEST (test_simultaneous_connect_bind_threads);
|
||||
RUN_TEST (test_routing_id);
|
||||
RUN_TEST (test_connect_only);
|
||||
RUN_TEST (test_unbind);
|
||||
RUN_TEST (test_shutdown_during_pend);
|
||||
return UNITY_END ();
|
||||
}
|
||||
91
tests/test_invalid_rep.cpp
Normal file
91
tests/test_invalid_rep.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_invalid_rep ()
|
||||
{
|
||||
// Create REQ/ROUTER wiring.
|
||||
void *router_socket = test_context_socket (ZMQ_ROUTER);
|
||||
void *req_socket = test_context_socket (ZMQ_REQ);
|
||||
|
||||
int linger = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (router_socket, ZMQ_LINGER, &linger, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (req_socket, ZMQ_LINGER, &linger, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router_socket, "inproc://hi"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req_socket, "inproc://hi"));
|
||||
|
||||
// Initial request.
|
||||
send_string_expect_success (req_socket, "r", 0);
|
||||
|
||||
// Receive the request.
|
||||
char addr[32];
|
||||
int addr_size;
|
||||
char bottom[1];
|
||||
char body[1];
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
addr_size = zmq_recv (router_socket, addr, sizeof (addr), 0));
|
||||
TEST_ASSERT_EQUAL_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (
|
||||
router_socket, bottom, sizeof (bottom), 0)));
|
||||
TEST_ASSERT_EQUAL_INT (1, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (
|
||||
router_socket, body, sizeof (body), 0)));
|
||||
|
||||
// Send invalid reply.
|
||||
TEST_ASSERT_EQUAL_INT (addr_size, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (
|
||||
router_socket, addr, addr_size, 0)));
|
||||
|
||||
// Send valid reply.
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
addr_size, TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_send (router_socket, addr, addr_size, ZMQ_SNDMORE)));
|
||||
TEST_ASSERT_EQUAL_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_send (
|
||||
router_socket, bottom, 0, ZMQ_SNDMORE)));
|
||||
send_string_expect_success (router_socket, "b", 0);
|
||||
|
||||
// Check whether we've got the valid reply.
|
||||
recv_string_expect_success (req_socket, "b", 0);
|
||||
|
||||
// Tear down the wiring.
|
||||
test_context_socket_close (router_socket);
|
||||
test_context_socket_close (req_socket);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_invalid_rep);
|
||||
return UNITY_END ();
|
||||
}
|
||||
154
tests/test_iov.cpp
Normal file
154
tests/test_iov.cpp
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
// XSI vector I/O
|
||||
#if defined ZMQ_HAVE_UIO
|
||||
#include <sys/uio.h>
|
||||
#else
|
||||
struct iovec
|
||||
{
|
||||
void *iov_base;
|
||||
size_t iov_len;
|
||||
};
|
||||
#endif
|
||||
|
||||
static void do_check (void *sb_, void *sc_, size_t msg_size_)
|
||||
{
|
||||
TEST_ASSERT_NOT_NULL (sb_);
|
||||
TEST_ASSERT_NOT_NULL (sc_);
|
||||
TEST_ASSERT_GREATER_THAN (0, msg_size_);
|
||||
|
||||
const char msg_val = '1';
|
||||
const int num_messages = 10;
|
||||
size_t send_count, recv_count;
|
||||
|
||||
send_count = recv_count = num_messages;
|
||||
|
||||
char *ref_msg = static_cast<char *> (malloc (msg_size_));
|
||||
TEST_ASSERT_NOT_NULL (ref_msg);
|
||||
memset (ref_msg, msg_val, msg_size_);
|
||||
|
||||
// zmq_sendiov(3) as a single multi-part send
|
||||
struct iovec send_iov[num_messages];
|
||||
char *buf = static_cast<char *> (malloc (msg_size_ * num_messages));
|
||||
|
||||
for (int i = 0; i < num_messages; i++) {
|
||||
send_iov[i].iov_base = &buf[i * msg_size_];
|
||||
send_iov[i].iov_len = msg_size_;
|
||||
memcpy (send_iov[i].iov_base, ref_msg, msg_size_);
|
||||
|
||||
// TODO: this assertion only checks if memcpy behaves as expected... remove this or assert something else?
|
||||
TEST_ASSERT_EQUAL_HEX8_ARRAY (ref_msg, send_iov[i].iov_base, msg_size_);
|
||||
}
|
||||
|
||||
// Test errors - zmq_recviov - null socket
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
ENOTSOCK, zmq_sendiov (NULL, send_iov, send_count, ZMQ_SNDMORE));
|
||||
// Test errors - zmq_recviov - invalid send count
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_sendiov (sc_, send_iov, 0, 0));
|
||||
// Test errors - zmq_recviov - null iovec
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_sendiov (sc_, NULL, send_count, 0));
|
||||
|
||||
// Test success
|
||||
|
||||
// The zmq_sendiov(3) API method does not follow the same semantics as
|
||||
// zmq_recviov(3); the latter returns the count of messages sent, rightly
|
||||
// so, whilst the former sends the number of bytes successfully sent from
|
||||
// the last message, which does not hold much sense from a batch send
|
||||
// perspective; hence the assert checks if the result is same as msg_size.
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
(int) msg_size_, TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_sendiov (sc_, send_iov, send_count, ZMQ_SNDMORE)));
|
||||
|
||||
// zmq_recviov(3) single-shot
|
||||
struct iovec recv_iov[num_messages];
|
||||
|
||||
// Test errors - zmq_recviov - null socket
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK,
|
||||
zmq_recviov (NULL, recv_iov, &recv_count, 0));
|
||||
// Test error - zmq_recviov - invalid receive count
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_recviov (sb_, recv_iov, NULL, 0));
|
||||
size_t invalid_recv_count = 0;
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_recviov (sb_, recv_iov, &invalid_recv_count, 0));
|
||||
// Test error - zmq_recviov - null iovec
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_recviov (sb_, NULL, &recv_count, 0));
|
||||
|
||||
// Test success
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
num_messages,
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_recviov (sb_, recv_iov, &recv_count, 0)));
|
||||
|
||||
for (int i = 0; i < num_messages; i++) {
|
||||
TEST_ASSERT_NOT_NULL (recv_iov[i].iov_base);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN (ref_msg, recv_iov[i].iov_base, msg_size_);
|
||||
free (recv_iov[i].iov_base);
|
||||
}
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (send_count, recv_count);
|
||||
free (ref_msg);
|
||||
free (buf);
|
||||
}
|
||||
|
||||
void test_iov ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "inproc://a"));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PUSH);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "inproc://a"));
|
||||
|
||||
// message bigger than VSM max
|
||||
do_check (sb, sc, 100);
|
||||
|
||||
// message smaller than VSM max
|
||||
do_check (sb, sc, 10);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_iov);
|
||||
return UNITY_END ();
|
||||
}
|
||||
57
tests/test_ipc_wildcard.cpp
Normal file
57
tests/test_ipc_wildcard.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_ipc_wildcard ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
char endpoint[200];
|
||||
bind_loopback_ipc (sb, endpoint, sizeof endpoint);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_ipc_wildcard);
|
||||
return UNITY_END ();
|
||||
}
|
||||
98
tests/test_issue_566.cpp
Normal file
98
tests/test_issue_566.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
// Issue 566 describes a problem in libzmq v4.0.0 where a dealer to router
|
||||
// connection would fail randomly. The test works when the two sockets are
|
||||
// on the same context, and failed when they were on separate contexts.
|
||||
// Fixed by https://github.com/zeromq/libzmq/commit/be25cf.
|
||||
void test_issue_566 ()
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
void *ctx1 = zmq_ctx_new ();
|
||||
TEST_ASSERT_NOT_NULL (ctx1);
|
||||
|
||||
void *ctx2 = zmq_ctx_new ();
|
||||
TEST_ASSERT_NOT_NULL (ctx2);
|
||||
|
||||
void *router = zmq_socket (ctx1, ZMQ_ROUTER);
|
||||
int on = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY, &on, sizeof (on)));
|
||||
bind_loopback_ipv4 (router, my_endpoint, sizeof (my_endpoint));
|
||||
|
||||
// Repeat often enough to be sure this works as it should
|
||||
for (int cycle = 0; cycle < 100; cycle++) {
|
||||
// Create dealer with unique explicit routing id
|
||||
// We assume the router learns this out-of-band
|
||||
void *dealer = zmq_socket (ctx2, ZMQ_DEALER);
|
||||
// Leave space for NULL char from sprintf, gcc warning
|
||||
char routing_id[11];
|
||||
sprintf (routing_id, "%09d", cycle);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer, ZMQ_ROUTING_ID, routing_id, 10));
|
||||
int rcvtimeo = 1000;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer, ZMQ_RCVTIMEO, &rcvtimeo, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));
|
||||
|
||||
// Router will try to send to dealer, at short intervals.
|
||||
// It typically takes 2-5 msec for the connection to establish
|
||||
// on a loopback interface, but we'll allow up to one second
|
||||
// before failing the test (e.g. for running on a debugger or
|
||||
// a very slow system).
|
||||
for (int attempt = 0; attempt < 500; attempt++) {
|
||||
zmq_poll (NULL, 0, 2);
|
||||
int rc = zmq_send (router, routing_id, 10, ZMQ_SNDMORE);
|
||||
if (rc == -1 && errno == EHOSTUNREACH)
|
||||
continue;
|
||||
TEST_ASSERT_EQUAL (10, rc);
|
||||
send_string_expect_success (router, "HELLO", 0);
|
||||
break;
|
||||
}
|
||||
recv_string_expect_success (dealer, "HELLO", 0);
|
||||
close_zero_linger (dealer);
|
||||
}
|
||||
zmq_close (router);
|
||||
zmq_ctx_destroy (ctx1);
|
||||
zmq_ctx_destroy (ctx2);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_issue_566);
|
||||
return UNITY_END ();
|
||||
}
|
||||
65
tests/test_last_endpoint.cpp
Normal file
65
tests/test_last_endpoint.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
static void do_bind_and_verify (void *s_, const char *endpoint_)
|
||||
{
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (s_, endpoint_));
|
||||
char reported[255];
|
||||
size_t size = 255;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (s_, ZMQ_LAST_ENDPOINT, reported, &size));
|
||||
TEST_ASSERT_EQUAL_STRING (endpoint_, reported);
|
||||
}
|
||||
|
||||
void test_last_endpoint ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_ROUTER);
|
||||
int val = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sb, ZMQ_LINGER, &val, sizeof (val)));
|
||||
|
||||
do_bind_and_verify (sb, ENDPOINT_1);
|
||||
do_bind_and_verify (sb, ENDPOINT_2);
|
||||
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_last_endpoint);
|
||||
return UNITY_END ();
|
||||
}
|
||||
98
tests/test_many_sockets.cpp
Normal file
98
tests/test_many_sockets.cpp
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <vector>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_system_max ()
|
||||
{
|
||||
// Keep allocating sockets until we run out of system resources
|
||||
const int no_of_sockets = 2 * 65536;
|
||||
zmq_ctx_set (get_test_context (), ZMQ_MAX_SOCKETS, no_of_sockets);
|
||||
std::vector<void *> sockets;
|
||||
|
||||
while (true) {
|
||||
void *socket = zmq_socket (get_test_context (), ZMQ_PAIR);
|
||||
if (!socket)
|
||||
break;
|
||||
sockets.push_back (socket);
|
||||
}
|
||||
TEST_ASSERT_LESS_OR_EQUAL (no_of_sockets,
|
||||
static_cast<int> (sockets.size ()));
|
||||
printf ("Socket creation failed after %i sockets\n",
|
||||
static_cast<int> (sockets.size ()));
|
||||
|
||||
// System is out of resources, further calls to zmq_socket should return NULL
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
TEST_ASSERT_NULL (zmq_socket (get_test_context (), ZMQ_PAIR));
|
||||
}
|
||||
// Clean up.
|
||||
for (unsigned int i = 0; i < sockets.size (); ++i)
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (sockets[i]));
|
||||
}
|
||||
|
||||
void test_zmq_default_max ()
|
||||
{
|
||||
// Keep allocating sockets until we hit the default limit
|
||||
std::vector<void *> sockets;
|
||||
|
||||
while (true) {
|
||||
void *socket = zmq_socket (get_test_context (), ZMQ_PAIR);
|
||||
if (!socket)
|
||||
break;
|
||||
sockets.push_back (socket);
|
||||
}
|
||||
// We may stop sooner if system has fewer available sockets
|
||||
TEST_ASSERT_LESS_OR_EQUAL (ZMQ_MAX_SOCKETS_DFLT, sockets.size ());
|
||||
|
||||
// Further calls to zmq_socket should return NULL
|
||||
for (unsigned int i = 0; i < 10; ++i) {
|
||||
TEST_ASSERT_NULL (zmq_socket (get_test_context (), ZMQ_PAIR));
|
||||
}
|
||||
|
||||
// Clean up
|
||||
for (unsigned int i = 0; i < sockets.size (); ++i)
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (sockets[i]));
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_system_max);
|
||||
RUN_TEST (test_zmq_default_max);
|
||||
return UNITY_END ();
|
||||
}
|
||||
187
tests/test_metadata.cpp
Normal file
187
tests/test_metadata.cpp
Normal file
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <unity.h>
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
static void zap_handler (void *handler_)
|
||||
{
|
||||
uint8_t metadata[] = {5, 'H', 'e', 'l', 'l', 'o', 0, 0,
|
||||
0, 5, 'W', 'o', 'r', 'l', 'd'};
|
||||
|
||||
// Process ZAP requests forever
|
||||
while (true) {
|
||||
char *version = s_recv (handler_);
|
||||
if (!version)
|
||||
break; // Terminating
|
||||
|
||||
char *sequence = s_recv (handler_);
|
||||
char *domain = s_recv (handler_);
|
||||
char *address = s_recv (handler_);
|
||||
char *routing_id = s_recv (handler_);
|
||||
char *mechanism = s_recv (handler_);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING ("1.0", version);
|
||||
TEST_ASSERT_EQUAL_STRING ("NULL", mechanism);
|
||||
|
||||
send_string_expect_success (handler_, version, ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, sequence, ZMQ_SNDMORE);
|
||||
if (streq (domain, "DOMAIN")) {
|
||||
send_string_expect_success (handler_, "200", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "OK", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "anonymous", ZMQ_SNDMORE);
|
||||
zmq_send (handler_, metadata, sizeof (metadata), 0);
|
||||
} else {
|
||||
send_string_expect_success (handler_, "400", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "BAD DOMAIN", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "", 0);
|
||||
}
|
||||
free (version);
|
||||
free (sequence);
|
||||
free (domain);
|
||||
free (address);
|
||||
free (routing_id);
|
||||
free (mechanism);
|
||||
}
|
||||
close_zero_linger (handler_);
|
||||
}
|
||||
|
||||
void test_metadata ()
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
setup_test_context ();
|
||||
|
||||
// Spawn ZAP handler
|
||||
// We create and bind ZAP socket in main thread to avoid case
|
||||
// where child thread does not start up fast enough.
|
||||
void *handler = zmq_socket (get_test_context (), ZMQ_REP);
|
||||
TEST_ASSERT_NOT_NULL (handler);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, "inproc://zeromq.zap.01"));
|
||||
void *zap_thread = zmq_threadstart (&zap_handler, handler);
|
||||
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "DOMAIN", 6));
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
send_string_expect_success (client, "This is a message", 0);
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, server, 0));
|
||||
TEST_ASSERT_EQUAL_STRING ("World", zmq_msg_gets (&msg, "Hello"));
|
||||
TEST_ASSERT_EQUAL_STRING ("DEALER", zmq_msg_gets (&msg, "Socket-Type"));
|
||||
TEST_ASSERT_EQUAL_STRING ("anonymous", zmq_msg_gets (&msg, "User-Id"));
|
||||
TEST_ASSERT_EQUAL_STRING ("127.0.0.1", zmq_msg_gets (&msg, "Peer-Address"));
|
||||
|
||||
TEST_ASSERT_NULL (zmq_msg_gets (&msg, "No Such"));
|
||||
TEST_ASSERT_EQUAL_INT (EINVAL, zmq_errno ());
|
||||
zmq_msg_close (&msg);
|
||||
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
|
||||
// Shutdown
|
||||
teardown_test_context ();
|
||||
|
||||
// Wait until ZAP handler terminates
|
||||
zmq_threadclose (zap_thread);
|
||||
}
|
||||
|
||||
void test_router_prefetch_metadata ()
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
setup_test_context ();
|
||||
|
||||
// Spawn ZAP handler
|
||||
// We create and bind ZAP socket in main thread to avoid case
|
||||
// where child thread does not start up fast enough.
|
||||
void *handler = zmq_socket (get_test_context (), ZMQ_REP);
|
||||
TEST_ASSERT_NOT_NULL (handler);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, "inproc://zeromq.zap.01"));
|
||||
void *zap_thread = zmq_threadstart (&zap_handler, handler);
|
||||
|
||||
void *server = test_context_socket (ZMQ_ROUTER);
|
||||
void *client = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "DOMAIN", 6));
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
send_string_expect_success (client, "This is a message", 0);
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Check for messages in the ROUTER socket which will trigger a prefetch
|
||||
unsigned long int dummy;
|
||||
size_t dummy_size = sizeof (dummy);
|
||||
zmq_getsockopt (server, ZMQ_EVENTS, &dummy, &dummy_size);
|
||||
|
||||
zmq_msg_t msg;
|
||||
|
||||
// Ensure all frames in the message contain metadata
|
||||
for (int i = 0; i < 3; i++) {
|
||||
zmq_msg_init (&msg);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, server, 0));
|
||||
TEST_ASSERT_EQUAL_STRING ("World", zmq_msg_gets (&msg, "Hello"));
|
||||
zmq_msg_close (&msg);
|
||||
}
|
||||
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
|
||||
// Shutdown
|
||||
teardown_test_context ();
|
||||
|
||||
// Wait until ZAP handler terminates
|
||||
zmq_threadclose (zap_thread);
|
||||
}
|
||||
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_metadata);
|
||||
RUN_TEST (test_router_prefetch_metadata);
|
||||
return UNITY_END ();
|
||||
}
|
||||
244
tests/test_mock_pub_sub.cpp
Normal file
244
tests/test_mock_pub_sub.cpp
Normal file
@@ -0,0 +1,244 @@
|
||||
/*
|
||||
Copyright (c) 2018 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of 0MQ.
|
||||
|
||||
0MQ is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License as published by
|
||||
the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
0MQ is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
// Read one event off the monitor socket; return value and address
|
||||
// by reference, if not null, and event number by value. Returns -1
|
||||
// in case of error.
|
||||
|
||||
static int get_monitor_event (void *monitor_)
|
||||
{
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// First frame in message contains event number and value
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
if (zmq_msg_recv (&msg, monitor_, ZMQ_DONTWAIT) == -1) {
|
||||
msleep (SETTLE_TIME);
|
||||
continue; // Interrupted, presumably
|
||||
}
|
||||
TEST_ASSERT_TRUE (zmq_msg_more (&msg));
|
||||
|
||||
uint8_t *data = static_cast<uint8_t *> (zmq_msg_data (&msg));
|
||||
uint16_t event = *reinterpret_cast<uint16_t *> (data);
|
||||
|
||||
// Second frame in message contains event address
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
if (zmq_msg_recv (&msg, monitor_, 0) == -1) {
|
||||
return -1; // Interrupted, presumably
|
||||
}
|
||||
TEST_ASSERT_FALSE (zmq_msg_more (&msg));
|
||||
|
||||
return event;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void recv_with_retry (fd_t fd_, char *buffer_, int bytes_)
|
||||
{
|
||||
int received = 0;
|
||||
while (true) {
|
||||
int rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (
|
||||
recv (fd_, buffer_ + received, bytes_ - received, 0));
|
||||
TEST_ASSERT_GREATER_THAN_INT (0, rc);
|
||||
received += rc;
|
||||
TEST_ASSERT_LESS_OR_EQUAL_INT (bytes_, received);
|
||||
if (received == bytes_)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void mock_handshake (fd_t fd_, bool sub_command, bool mock_pub)
|
||||
{
|
||||
char buffer[128];
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
memcpy (buffer, zmtp_greeting_null, sizeof (zmtp_greeting_null));
|
||||
|
||||
// Mock ZMTP 3.1 which uses commands
|
||||
if (sub_command) {
|
||||
buffer[11] = 1;
|
||||
}
|
||||
int rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (fd_, buffer, 64, 0));
|
||||
TEST_ASSERT_EQUAL_INT (64, rc);
|
||||
|
||||
recv_with_retry (fd_, buffer, 64);
|
||||
|
||||
if (!mock_pub) {
|
||||
rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (
|
||||
fd_, (const char *) zmtp_ready_sub, sizeof (zmtp_ready_sub), 0));
|
||||
TEST_ASSERT_EQUAL_INT (sizeof (zmtp_ready_sub), rc);
|
||||
} else {
|
||||
rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (
|
||||
fd_, (const char *) zmtp_ready_xpub, sizeof (zmtp_ready_xpub), 0));
|
||||
TEST_ASSERT_EQUAL_INT (sizeof (zmtp_ready_xpub), rc);
|
||||
}
|
||||
|
||||
// greeting - XPUB has one extra byte
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
recv_with_retry (fd_, buffer,
|
||||
mock_pub ? sizeof (zmtp_ready_sub)
|
||||
: sizeof (zmtp_ready_xpub));
|
||||
}
|
||||
|
||||
static void prep_server_socket (void **server_out_,
|
||||
void **mon_out_,
|
||||
char *endpoint_,
|
||||
size_t ep_length_,
|
||||
int socket_type)
|
||||
{
|
||||
// We'll be using this socket in raw mode
|
||||
void *server = test_context_socket (socket_type);
|
||||
|
||||
int value = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_LINGER, &value, sizeof (value)));
|
||||
|
||||
bind_loopback_ipv4 (server, endpoint_, ep_length_);
|
||||
|
||||
// Create and connect a socket for collecting monitor events on xpub
|
||||
void *server_mon = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (
|
||||
server, "inproc://monitor-dealer",
|
||||
ZMQ_EVENT_CONNECTED | ZMQ_EVENT_DISCONNECTED | ZMQ_EVENT_ACCEPTED));
|
||||
|
||||
// Connect to the inproc endpoint so we'll get events
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (server_mon, "inproc://monitor-dealer"));
|
||||
|
||||
*server_out_ = server;
|
||||
*mon_out_ = server_mon;
|
||||
}
|
||||
|
||||
static void test_mock_pub_sub (bool sub_command_, bool mock_pub_)
|
||||
{
|
||||
int rc;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *server, *server_mon;
|
||||
prep_server_socket (&server, &server_mon, my_endpoint, MAX_SOCKET_STRING,
|
||||
mock_pub_ ? ZMQ_SUB : ZMQ_XPUB);
|
||||
|
||||
fd_t s = connect_socket (my_endpoint);
|
||||
|
||||
// Mock a ZMTP 3 client so we can forcibly try sub commands
|
||||
mock_handshake (s, sub_command_, mock_pub_);
|
||||
|
||||
// By now everything should report as connected
|
||||
rc = get_monitor_event (server_mon);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_ACCEPTED, rc);
|
||||
|
||||
char buffer[32];
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
|
||||
if (mock_pub_) {
|
||||
rc = zmq_setsockopt (server, ZMQ_SUBSCRIBE, "A", 1);
|
||||
TEST_ASSERT_EQUAL_INT (0, rc);
|
||||
// SUB binds, let its state machine run
|
||||
// Because zeromq attach the pipe after the handshake, we need more time here before we can run the state-machine
|
||||
msleep (1);
|
||||
zmq_recv (server, buffer, 16, ZMQ_DONTWAIT);
|
||||
|
||||
if (sub_command_) {
|
||||
recv_with_retry (s, buffer, 13);
|
||||
TEST_ASSERT_EQUAL_INT (0,
|
||||
memcmp (buffer, "\4\xb\x9SUBSCRIBEA", 13));
|
||||
} else {
|
||||
recv_with_retry (s, buffer, 4);
|
||||
TEST_ASSERT_EQUAL_INT (0, memcmp (buffer, "\0\2\1A", 4));
|
||||
}
|
||||
|
||||
memcpy (buffer, "\0\4ALOL", 6);
|
||||
rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (send (s, buffer, 6, 0));
|
||||
TEST_ASSERT_EQUAL_INT (6, rc);
|
||||
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
rc = zmq_recv (server, buffer, 4, 0);
|
||||
TEST_ASSERT_EQUAL_INT (4, rc);
|
||||
TEST_ASSERT_EQUAL_INT (0, memcmp (buffer, "ALOL", 4));
|
||||
} else {
|
||||
if (sub_command_) {
|
||||
const uint8_t sub[13] = {4, 11, 9, 'S', 'U', 'B', 'S',
|
||||
'C', 'R', 'I', 'B', 'E', 'A'};
|
||||
rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (
|
||||
send (s, (const char *) sub, 13, 0));
|
||||
TEST_ASSERT_EQUAL_INT (13, rc);
|
||||
} else {
|
||||
const uint8_t sub[4] = {0, 2, 1, 'A'};
|
||||
rc = TEST_ASSERT_SUCCESS_RAW_ERRNO (
|
||||
send (s, (const char *) sub, 4, 0));
|
||||
TEST_ASSERT_EQUAL_INT (4, rc);
|
||||
}
|
||||
rc = zmq_recv (server, buffer, 2, 0);
|
||||
TEST_ASSERT_EQUAL_INT (2, rc);
|
||||
TEST_ASSERT_EQUAL_INT (0, memcmp (buffer, "\1A", 2));
|
||||
|
||||
rc = zmq_send (server, "ALOL", 4, 0);
|
||||
TEST_ASSERT_EQUAL_INT (4, rc);
|
||||
|
||||
memset (buffer, 0, sizeof (buffer));
|
||||
recv_with_retry (s, buffer, 6);
|
||||
TEST_ASSERT_EQUAL_INT (0, memcmp (buffer, "\0\4ALOL", 6));
|
||||
}
|
||||
|
||||
close (s);
|
||||
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (server_mon);
|
||||
}
|
||||
|
||||
void test_mock_sub_command ()
|
||||
{
|
||||
test_mock_pub_sub (true, false);
|
||||
}
|
||||
|
||||
void test_mock_sub_legacy ()
|
||||
{
|
||||
test_mock_pub_sub (false, false);
|
||||
}
|
||||
|
||||
void test_mock_pub_command ()
|
||||
{
|
||||
test_mock_pub_sub (true, true);
|
||||
}
|
||||
|
||||
void test_mock_pub_legacy ()
|
||||
{
|
||||
test_mock_pub_sub (false, true);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
|
||||
RUN_TEST (test_mock_sub_command);
|
||||
RUN_TEST (test_mock_sub_legacy);
|
||||
RUN_TEST (test_mock_pub_command);
|
||||
RUN_TEST (test_mock_pub_legacy);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
465
tests/test_monitor.cpp
Normal file
465
tests/test_monitor.cpp
Normal file
@@ -0,0 +1,465 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_monitoring.hpp"
|
||||
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_monitor_invalid_protocol_fails ()
|
||||
{
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
// Socket monitoring only works over inproc://
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EPROTONOSUPPORT, zmq_socket_monitor (client, "tcp://127.0.0.1:*", 0));
|
||||
|
||||
#ifdef ZMQ_EVENT_PIPES_STATS
|
||||
// Stats command needs to be called on a valid socket with monitoring
|
||||
// enabled
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK, zmq_socket_monitor_pipes_stats (NULL));
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_socket_monitor_pipes_stats (client));
|
||||
#endif
|
||||
|
||||
test_context_socket_close_zero_linger (client);
|
||||
}
|
||||
|
||||
void test_monitor_basic ()
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
// We'll monitor these two sockets
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
// Monitor all events on client and server sockets
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_socket_monitor (client, "inproc://monitor-client", ZMQ_EVENT_ALL));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_socket_monitor (server, "inproc://monitor-server", ZMQ_EVENT_ALL));
|
||||
|
||||
// Create two sockets for collecting monitor events
|
||||
void *client_mon = test_context_socket (ZMQ_PAIR);
|
||||
void *server_mon = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
// Connect these to the inproc endpoints so they'll get events
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (client_mon, "inproc://monitor-client"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (server_mon, "inproc://monitor-server"));
|
||||
|
||||
// Now do a basic ping test
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
bounce (server, client);
|
||||
|
||||
// Close client and server
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
|
||||
// Now collect and check events from both sockets
|
||||
int event = get_monitor_event (client_mon, NULL, NULL);
|
||||
if (event == ZMQ_EVENT_CONNECT_DELAYED)
|
||||
event = get_monitor_event (client_mon, NULL, NULL);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_CONNECTED, event);
|
||||
expect_monitor_event (client_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
|
||||
event = get_monitor_event (client_mon, NULL, NULL);
|
||||
if (event == ZMQ_EVENT_DISCONNECTED) {
|
||||
expect_monitor_event (client_mon, ZMQ_EVENT_CONNECT_RETRIED);
|
||||
expect_monitor_event (client_mon, ZMQ_EVENT_MONITOR_STOPPED);
|
||||
} else
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_MONITOR_STOPPED, event);
|
||||
|
||||
// This is the flow of server events
|
||||
expect_monitor_event (server_mon, ZMQ_EVENT_LISTENING);
|
||||
expect_monitor_event (server_mon, ZMQ_EVENT_ACCEPTED);
|
||||
expect_monitor_event (server_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
|
||||
event = get_monitor_event (server_mon, NULL, NULL);
|
||||
// Sometimes the server sees the client closing before it gets closed.
|
||||
if (event != ZMQ_EVENT_DISCONNECTED) {
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_CLOSED, event);
|
||||
event = get_monitor_event (server_mon, NULL, NULL);
|
||||
}
|
||||
if (event != ZMQ_EVENT_DISCONNECTED) {
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_MONITOR_STOPPED, event);
|
||||
}
|
||||
// TODO: When not waiting until the monitor stopped, the I/O thread runs
|
||||
// into some deadlock. This must be fixed, but until it is fixed, we wait
|
||||
// here in order to have more reliable test execution.
|
||||
while (event != ZMQ_EVENT_MONITOR_STOPPED) {
|
||||
event = get_monitor_event (server_mon, NULL, NULL);
|
||||
}
|
||||
|
||||
// Close down the sockets
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (client_mon);
|
||||
test_context_socket_close_zero_linger (server_mon);
|
||||
}
|
||||
|
||||
#if (defined ZMQ_CURRENT_EVENT_VERSION && ZMQ_CURRENT_EVENT_VERSION >= 2) \
|
||||
|| (defined ZMQ_CURRENT_EVENT_VERSION \
|
||||
&& ZMQ_CURRENT_EVENT_VERSION_DRAFT >= 2)
|
||||
void test_monitor_versioned_invalid_socket_type ()
|
||||
{
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
// Socket monitoring only works with ZMQ_PAIR, ZMQ_PUB and ZMQ_PUSH.
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_socket_monitor_versioned (
|
||||
client, "inproc://invalid-socket-type", 0, 2, ZMQ_CLIENT));
|
||||
|
||||
test_context_socket_close_zero_linger (client);
|
||||
}
|
||||
|
||||
void test_monitor_versioned_basic (bind_function_t bind_function_,
|
||||
const char *expected_prefix_,
|
||||
int type_)
|
||||
{
|
||||
char server_endpoint[MAX_SOCKET_STRING];
|
||||
char client_mon_endpoint[MAX_SOCKET_STRING];
|
||||
char server_mon_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
// Create a unique endpoint for each call so we don't have
|
||||
// to wait for the sockets to unbind.
|
||||
snprintf (client_mon_endpoint, MAX_SOCKET_STRING, "inproc://client%s%d",
|
||||
expected_prefix_, type_);
|
||||
snprintf (server_mon_endpoint, MAX_SOCKET_STRING, "inproc://server%s%d",
|
||||
expected_prefix_, type_);
|
||||
|
||||
// We'll monitor these two sockets
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
// Monitor all events on client and server sockets
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor_versioned (
|
||||
client, client_mon_endpoint, ZMQ_EVENT_ALL_V2, 2, type_));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor_versioned (
|
||||
server, server_mon_endpoint, ZMQ_EVENT_ALL_V2, 2, type_));
|
||||
|
||||
// Choose the appropriate consumer socket type.
|
||||
int mon_type = ZMQ_PAIR;
|
||||
switch (type_) {
|
||||
case ZMQ_PAIR:
|
||||
mon_type = ZMQ_PAIR;
|
||||
break;
|
||||
case ZMQ_PUSH:
|
||||
mon_type = ZMQ_PULL;
|
||||
break;
|
||||
case ZMQ_PUB:
|
||||
mon_type = ZMQ_SUB;
|
||||
break;
|
||||
}
|
||||
|
||||
// Create two sockets for collecting monitor events
|
||||
void *client_mon = test_context_socket (mon_type);
|
||||
void *server_mon = test_context_socket (mon_type);
|
||||
|
||||
// Additionally subscribe to all events if a PUB socket is used.
|
||||
if (type_ == ZMQ_PUB) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client_mon, ZMQ_SUBSCRIBE, "", 0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server_mon, ZMQ_SUBSCRIBE, "", 0));
|
||||
}
|
||||
|
||||
// Connect these to the inproc endpoints so they'll get events
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_mon, client_mon_endpoint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (server_mon, server_mon_endpoint));
|
||||
|
||||
// Now do a basic ping test
|
||||
bind_function_ (server, server_endpoint, sizeof server_endpoint);
|
||||
|
||||
int ipv6;
|
||||
size_t ipv6_size = sizeof (ipv6);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (server, ZMQ_IPV6, &ipv6, &ipv6_size));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_IPV6, &ipv6, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, server_endpoint));
|
||||
bounce (server, client);
|
||||
|
||||
// Close client and server
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
|
||||
char *client_local_address = NULL;
|
||||
char *client_remote_address = NULL;
|
||||
|
||||
// Now collect and check events from both sockets
|
||||
int64_t event = get_monitor_event_v2 (
|
||||
client_mon, NULL, &client_local_address, &client_remote_address);
|
||||
if (event == ZMQ_EVENT_CONNECT_DELAYED) {
|
||||
free (client_local_address);
|
||||
free (client_remote_address);
|
||||
event = get_monitor_event_v2 (client_mon, NULL, &client_local_address,
|
||||
&client_remote_address);
|
||||
}
|
||||
TEST_ASSERT_EQUAL (ZMQ_EVENT_CONNECTED, event);
|
||||
TEST_ASSERT_EQUAL_STRING (server_endpoint, client_remote_address);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN (expected_prefix_, client_local_address,
|
||||
strlen (expected_prefix_));
|
||||
TEST_ASSERT_NOT_EQUAL (
|
||||
0, strcmp (client_local_address, client_remote_address));
|
||||
|
||||
expect_monitor_event_v2 (client_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED,
|
||||
client_local_address, client_remote_address);
|
||||
event = get_monitor_event_v2 (client_mon, NULL, NULL, NULL);
|
||||
if (event == ZMQ_EVENT_DISCONNECTED) {
|
||||
expect_monitor_event_v2 (client_mon, ZMQ_EVENT_CONNECT_RETRIED,
|
||||
client_local_address, client_remote_address);
|
||||
expect_monitor_event_v2 (client_mon, ZMQ_EVENT_MONITOR_STOPPED, "", "");
|
||||
} else
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_MONITOR_STOPPED, event);
|
||||
|
||||
// This is the flow of server events
|
||||
expect_monitor_event_v2 (server_mon, ZMQ_EVENT_LISTENING,
|
||||
client_remote_address, "");
|
||||
expect_monitor_event_v2 (server_mon, ZMQ_EVENT_ACCEPTED,
|
||||
client_remote_address, client_local_address);
|
||||
expect_monitor_event_v2 (server_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED,
|
||||
client_remote_address, client_local_address);
|
||||
event = get_monitor_event_v2 (server_mon, NULL, NULL, NULL);
|
||||
// Sometimes the server sees the client closing before it gets closed.
|
||||
if (event != ZMQ_EVENT_DISCONNECTED) {
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_CLOSED, event);
|
||||
event = get_monitor_event_v2 (server_mon, NULL, NULL, NULL);
|
||||
}
|
||||
if (event != ZMQ_EVENT_DISCONNECTED) {
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_MONITOR_STOPPED, event);
|
||||
}
|
||||
// TODO: When not waiting until the monitor stopped, the I/O thread runs
|
||||
// into some deadlock. This must be fixed, but until it is fixed, we wait
|
||||
// here in order to have more reliable test execution.
|
||||
while (event != ZMQ_EVENT_MONITOR_STOPPED) {
|
||||
event = get_monitor_event_v2 (server_mon, NULL, NULL, NULL);
|
||||
}
|
||||
free (client_local_address);
|
||||
free (client_remote_address);
|
||||
|
||||
// Close down the sockets
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (client_mon);
|
||||
test_context_socket_close_zero_linger (server_mon);
|
||||
}
|
||||
|
||||
void test_monitor_versioned_basic_tcp_ipv4 ()
|
||||
{
|
||||
static const char prefix[] = "tcp://127.0.0.1:";
|
||||
test_monitor_versioned_basic (bind_loopback_ipv4, prefix, ZMQ_PAIR);
|
||||
test_monitor_versioned_basic (bind_loopback_ipv4, prefix, ZMQ_PUB);
|
||||
test_monitor_versioned_basic (bind_loopback_ipv4, prefix, ZMQ_PUSH);
|
||||
}
|
||||
|
||||
void test_monitor_versioned_basic_tcp_ipv6 ()
|
||||
{
|
||||
static const char prefix[] = "tcp://[::1]:";
|
||||
test_monitor_versioned_basic (bind_loopback_ipv6, prefix, ZMQ_PAIR);
|
||||
test_monitor_versioned_basic (bind_loopback_ipv6, prefix, ZMQ_PUB);
|
||||
test_monitor_versioned_basic (bind_loopback_ipv6, prefix, ZMQ_PUSH);
|
||||
}
|
||||
|
||||
void test_monitor_versioned_basic_ipc ()
|
||||
{
|
||||
static const char prefix[] = "ipc://";
|
||||
test_monitor_versioned_basic (bind_loopback_ipc, prefix, ZMQ_PAIR);
|
||||
test_monitor_versioned_basic (bind_loopback_ipc, prefix, ZMQ_PUB);
|
||||
test_monitor_versioned_basic (bind_loopback_ipc, prefix, ZMQ_PUSH);
|
||||
}
|
||||
|
||||
void test_monitor_versioned_basic_tipc ()
|
||||
{
|
||||
static const char prefix[] = "tipc://";
|
||||
test_monitor_versioned_basic (bind_loopback_tipc, prefix, ZMQ_PAIR);
|
||||
test_monitor_versioned_basic (bind_loopback_tipc, prefix, ZMQ_PUB);
|
||||
test_monitor_versioned_basic (bind_loopback_tipc, prefix, ZMQ_PUSH);
|
||||
}
|
||||
|
||||
#ifdef ZMQ_EVENT_PIPES_STATS
|
||||
void test_monitor_versioned_stats (bind_function_t bind_function_,
|
||||
const char *expected_prefix_)
|
||||
{
|
||||
char server_endpoint[MAX_SOCKET_STRING];
|
||||
const int pulls_count = 4;
|
||||
void *pulls[pulls_count];
|
||||
|
||||
// We'll monitor these two sockets
|
||||
void *push = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor_versioned (
|
||||
push, "inproc://monitor-push", ZMQ_EVENT_PIPES_STATS, 2, ZMQ_PAIR));
|
||||
|
||||
// Should fail if there are no pipes to monitor
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_socket_monitor_pipes_stats (push));
|
||||
|
||||
void *push_mon = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (push_mon, "inproc://monitor-push"));
|
||||
|
||||
// Set lower HWM - queues will be filled so we should see it in the stats
|
||||
int send_hwm = 500;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (push, ZMQ_SNDHWM, &send_hwm, sizeof (send_hwm)));
|
||||
// Set very low TCP buffers so that messages cannot be stored in-flight
|
||||
const int tcp_buffer_size = 4096;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
push, ZMQ_SNDBUF, &tcp_buffer_size, sizeof (tcp_buffer_size)));
|
||||
bind_function_ (push, server_endpoint, sizeof (server_endpoint));
|
||||
|
||||
int ipv6;
|
||||
size_t ipv6_size = sizeof (ipv6);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (push, ZMQ_IPV6, &ipv6, &ipv6_size));
|
||||
for (int i = 0; i < pulls_count; ++i) {
|
||||
pulls[i] = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (pulls[i], ZMQ_IPV6, &ipv6, sizeof (int)));
|
||||
int timeout_ms = 10;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
pulls[i], ZMQ_RCVTIMEO, &timeout_ms, sizeof (timeout_ms)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (pulls[i], ZMQ_RCVHWM, &send_hwm, sizeof (send_hwm)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
pulls[i], ZMQ_RCVBUF, &tcp_buffer_size, sizeof (tcp_buffer_size)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pulls[i], server_endpoint));
|
||||
}
|
||||
|
||||
// Send until we block
|
||||
int send_count = 0;
|
||||
// Saturate the TCP buffers too
|
||||
char data[tcp_buffer_size * 2];
|
||||
memset (data, 0, sizeof (data));
|
||||
// Saturate all pipes - send + receive - on all connections
|
||||
while (send_count < send_hwm * 2 * pulls_count) {
|
||||
TEST_ASSERT_EQUAL_INT (sizeof (data),
|
||||
zmq_send (push, data, sizeof (data), 0));
|
||||
++send_count;
|
||||
}
|
||||
|
||||
// Drain one of the pulls - doesn't matter how many messages, at least one
|
||||
send_count = send_count / 4;
|
||||
do {
|
||||
zmq_recv (pulls[0], data, sizeof (data), 0);
|
||||
--send_count;
|
||||
} while (send_count > 0);
|
||||
|
||||
// To kick the application thread, do a dummy getsockopt - users here
|
||||
// should use the monitor and the other sockets in a poll.
|
||||
unsigned long int dummy;
|
||||
size_t dummy_size = sizeof (dummy);
|
||||
msleep (SETTLE_TIME);
|
||||
// Note that the pipe stats on the sender will not get updated until the
|
||||
// receiver has processed at least lwm ((hwm + 1) / 2) messages AND until
|
||||
// the application thread has ran through the mailbox, as the update is
|
||||
// delivered via a message (send_activate_write)
|
||||
zmq_getsockopt (push, ZMQ_EVENTS, &dummy, &dummy_size);
|
||||
|
||||
// Ask for stats and check that they match
|
||||
zmq_socket_monitor_pipes_stats (push);
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
zmq_getsockopt (push, ZMQ_EVENTS, &dummy, &dummy_size);
|
||||
|
||||
for (int i = 0; i < pulls_count; ++i) {
|
||||
char *push_local_address = NULL;
|
||||
char *push_remote_address = NULL;
|
||||
uint64_t *queue_stat = NULL;
|
||||
int64_t event = get_monitor_event_v2 (
|
||||
push_mon, &queue_stat, &push_local_address, &push_remote_address);
|
||||
TEST_ASSERT_EQUAL_STRING (server_endpoint, push_local_address);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN (expected_prefix_, push_remote_address,
|
||||
strlen (expected_prefix_));
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_PIPES_STATS, event);
|
||||
TEST_ASSERT_NOT_NULL (queue_stat);
|
||||
TEST_ASSERT_EQUAL_INT (i == 0 ? 0 : send_hwm, queue_stat[0]);
|
||||
TEST_ASSERT_EQUAL_INT (0, queue_stat[1]);
|
||||
free (push_local_address);
|
||||
free (push_remote_address);
|
||||
free (queue_stat);
|
||||
}
|
||||
|
||||
// Close client and server
|
||||
test_context_socket_close_zero_linger (push_mon);
|
||||
test_context_socket_close_zero_linger (push);
|
||||
for (int i = 0; i < pulls_count; ++i)
|
||||
test_context_socket_close_zero_linger (pulls[i]);
|
||||
}
|
||||
|
||||
void test_monitor_versioned_stats_tcp_ipv4 ()
|
||||
{
|
||||
static const char prefix[] = "tcp://127.0.0.1:";
|
||||
test_monitor_versioned_stats (bind_loopback_ipv4, prefix);
|
||||
}
|
||||
|
||||
void test_monitor_versioned_stats_tcp_ipv6 ()
|
||||
{
|
||||
static const char prefix[] = "tcp://[::1]:";
|
||||
test_monitor_versioned_stats (bind_loopback_ipv6, prefix);
|
||||
}
|
||||
|
||||
void test_monitor_versioned_stats_ipc ()
|
||||
{
|
||||
static const char prefix[] = "ipc://";
|
||||
test_monitor_versioned_stats (bind_loopback_ipc, prefix);
|
||||
}
|
||||
#endif // ZMQ_EVENT_PIPES_STATS
|
||||
#endif
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_monitor_invalid_protocol_fails);
|
||||
RUN_TEST (test_monitor_basic);
|
||||
|
||||
#if (defined ZMQ_CURRENT_EVENT_VERSION && ZMQ_CURRENT_EVENT_VERSION >= 2) \
|
||||
|| (defined ZMQ_CURRENT_EVENT_VERSION \
|
||||
&& ZMQ_CURRENT_EVENT_VERSION_DRAFT >= 2)
|
||||
RUN_TEST (test_monitor_versioned_invalid_socket_type);
|
||||
RUN_TEST (test_monitor_versioned_basic_tcp_ipv4);
|
||||
RUN_TEST (test_monitor_versioned_basic_tcp_ipv6);
|
||||
RUN_TEST (test_monitor_versioned_basic_ipc);
|
||||
RUN_TEST (test_monitor_versioned_basic_tipc);
|
||||
#ifdef ZMQ_EVENT_PIPES_STATS
|
||||
RUN_TEST (test_monitor_versioned_stats_tcp_ipv4);
|
||||
RUN_TEST (test_monitor_versioned_stats_tcp_ipv6);
|
||||
RUN_TEST (test_monitor_versioned_stats_ipc);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
126
tests/test_msg_ffn.cpp
Normal file
126
tests/test_msg_ffn.cpp
Normal file
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void ffn (void *data_, void *hint_)
|
||||
{
|
||||
// Signal that ffn has been called by writing "freed" to hint
|
||||
(void) data_; // Suppress 'unused' warnings at compile time
|
||||
memcpy (hint_, (void *) "freed", 5);
|
||||
}
|
||||
|
||||
void test_msg_init_ffn ()
|
||||
{
|
||||
// Create the infrastructure
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));
|
||||
|
||||
// Test that creating and closing a message triggers ffn
|
||||
zmq_msg_t msg;
|
||||
char hint[5];
|
||||
char data[255];
|
||||
memset (data, 0, 255);
|
||||
memcpy (data, (void *) "data", 4);
|
||||
memcpy (hint, (void *) "hint", 4);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_init_data (&msg, (void *) data, 255, ffn, (void *) hint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN ("freed", hint, 5);
|
||||
memcpy (hint, (void *) "hint", 4);
|
||||
|
||||
// Making and closing a copy triggers ffn
|
||||
zmq_msg_t msg2;
|
||||
zmq_msg_init (&msg2);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_init_data (&msg, (void *) data, 255, ffn, (void *) hint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_copy (&msg2, &msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg2));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN ("freed", hint, 5);
|
||||
memcpy (hint, (void *) "hint", 4);
|
||||
|
||||
// Test that sending a message triggers ffn
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_init_data (&msg, (void *) data, 255, ffn, (void *) hint));
|
||||
|
||||
zmq_msg_send (&msg, dealer, 0);
|
||||
char buf[255];
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (router, buf, 255, 0));
|
||||
TEST_ASSERT_EQUAL_INT (255, zmq_recv (router, buf, 255, 0));
|
||||
TEST_ASSERT_EQUAL_STRING_LEN (data, buf, 4);
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN ("freed", hint, 5);
|
||||
memcpy (hint, (void *) "hint", 4);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
|
||||
// Sending a copy of a message triggers ffn
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg2));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_init_data (&msg, (void *) data, 255, ffn, (void *) hint));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_copy (&msg2, &msg));
|
||||
|
||||
zmq_msg_send (&msg, dealer, 0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (router, buf, 255, 0));
|
||||
TEST_ASSERT_EQUAL_INT (255, zmq_recv (router, buf, 255, 0));
|
||||
TEST_ASSERT_EQUAL_STRING_LEN (data, buf, 4);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg2));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN ("freed", hint, 5);
|
||||
|
||||
// Deallocate the infrastructure.
|
||||
test_context_socket_close (router);
|
||||
test_context_socket_close (dealer);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_msg_init_ffn);
|
||||
return UNITY_END ();
|
||||
}
|
||||
117
tests/test_msg_flags.cpp
Normal file
117
tests/test_msg_flags.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_more ()
|
||||
{
|
||||
// Create the infrastructure
|
||||
void *sb = test_context_socket (ZMQ_ROUTER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "inproc://a"));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "inproc://a"));
|
||||
|
||||
// Send 2-part message.
|
||||
send_string_expect_success (sc, "A", ZMQ_SNDMORE);
|
||||
send_string_expect_success (sc, "B", 0);
|
||||
|
||||
// Routing id comes first.
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0));
|
||||
TEST_ASSERT_EQUAL_INT (1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_more (&msg)));
|
||||
|
||||
// Then the first part of the message body.
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0)));
|
||||
TEST_ASSERT_EQUAL_INT (1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_more (&msg)));
|
||||
|
||||
// And finally, the second part of the message body.
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, sb, 0)));
|
||||
TEST_ASSERT_EQUAL_INT (0, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_more (&msg)));
|
||||
|
||||
// Deallocate the infrastructure.
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void test_shared_refcounted ()
|
||||
{
|
||||
// Test ZMQ_SHARED property (case 1, refcounted messages)
|
||||
zmq_msg_t msg_a;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_init_size (&msg_a, 1024)); // large enough to be a type_lmsg
|
||||
|
||||
// Message is not shared
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_get (&msg_a, ZMQ_SHARED));
|
||||
|
||||
zmq_msg_t msg_b;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg_b));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_copy (&msg_b, &msg_a));
|
||||
|
||||
// Message is now shared
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_get (&msg_b, ZMQ_SHARED)));
|
||||
|
||||
// cleanup
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg_a));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg_b));
|
||||
}
|
||||
|
||||
void test_shared_const ()
|
||||
{
|
||||
zmq_msg_t msg_a;
|
||||
// Test ZMQ_SHARED property (case 2, constant data messages)
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_init_data (&msg_a, (void *) "TEST", 5, 0, 0));
|
||||
|
||||
// Message reports as shared
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
1, TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_get (&msg_a, ZMQ_SHARED)));
|
||||
|
||||
// cleanup
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg_a));
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_more);
|
||||
RUN_TEST (test_shared_refcounted);
|
||||
RUN_TEST (test_shared_const);
|
||||
return UNITY_END ();
|
||||
}
|
||||
86
tests/test_msg_init.cpp
Normal file
86
tests/test_msg_init.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_msg_init ()
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
}
|
||||
|
||||
void test_msg_init_size ()
|
||||
{
|
||||
const char *data = "foobar";
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 6));
|
||||
TEST_ASSERT_EQUAL_INT (6, zmq_msg_size (&msg));
|
||||
memcpy (zmq_msg_data (&msg), data, 6);
|
||||
TEST_ASSERT_EQUAL_STRING_LEN (data, zmq_msg_data (&msg), 6);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
|
||||
zmq_msg_t msg2;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg2, 0));
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&msg2));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg2));
|
||||
}
|
||||
|
||||
void test_msg_init_buffer ()
|
||||
{
|
||||
const char *data = "foobar";
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_buffer (&msg, data, 6));
|
||||
TEST_ASSERT_EQUAL_INT (6, zmq_msg_size (&msg));
|
||||
TEST_ASSERT (data != zmq_msg_data (&msg));
|
||||
TEST_ASSERT_EQUAL_STRING_LEN (data, zmq_msg_data (&msg), 6);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
|
||||
zmq_msg_t msg2;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_buffer (&msg2, NULL, 0));
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_msg_size (&msg2));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg2));
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_msg_init);
|
||||
RUN_TEST (test_msg_init_size);
|
||||
RUN_TEST (test_msg_init_buffer);
|
||||
return UNITY_END ();
|
||||
}
|
||||
82
tests/test_pair_inproc.cpp
Normal file
82
tests/test_pair_inproc.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <unity.h>
|
||||
|
||||
void *sb;
|
||||
void *sc;
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
|
||||
sb = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "inproc://a"));
|
||||
|
||||
sc = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "inproc://a"));
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
|
||||
teardown_test_context ();
|
||||
}
|
||||
|
||||
void test_roundtrip ()
|
||||
{
|
||||
bounce (sb, sc);
|
||||
}
|
||||
|
||||
// TODO it appears that this has nothing to do with pair or inproc, and belongs somewhere else
|
||||
void test_zmq_send_const ()
|
||||
{
|
||||
TEST_ASSERT_EQUAL_INT (3, TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_send_const (sb, "foo", 3, ZMQ_SNDMORE)));
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
6, TEST_ASSERT_SUCCESS_ERRNO (zmq_send_const (sb, "foobar", 6, 0)));
|
||||
|
||||
recv_string_expect_success (sc, "foo", 0);
|
||||
recv_string_expect_success (sc, "foobar", 0);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_roundtrip);
|
||||
RUN_TEST (test_zmq_send_const);
|
||||
return UNITY_END ();
|
||||
}
|
||||
81
tests/test_pair_ipc.cpp
Normal file
81
tests/test_pair_ipc.cpp
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_roundtrip ()
|
||||
{
|
||||
char my_endpoint[256];
|
||||
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
bind_loopback_ipc (sb, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
static const char prefix[] = "ipc://";
|
||||
|
||||
void test_endpoint_too_long ()
|
||||
{
|
||||
std::string endpoint_too_long;
|
||||
endpoint_too_long.append (prefix);
|
||||
for (size_t i = 0; i < 108; ++i) {
|
||||
endpoint_too_long.append ("a");
|
||||
}
|
||||
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
// TODO ENAMETOOLONG is not listed in the errors returned by zmq_bind,
|
||||
// should this be EINVAL?
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENAMETOOLONG,
|
||||
zmq_bind (sb, endpoint_too_long.data ()));
|
||||
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_roundtrip);
|
||||
RUN_TEST (test_endpoint_too_long);
|
||||
return UNITY_END ();
|
||||
}
|
||||
161
tests/test_pair_tcp.cpp
Normal file
161
tests/test_pair_tcp.cpp
Normal file
@@ -0,0 +1,161 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#if defined _WIN32
|
||||
#include "../src/windows.hpp"
|
||||
#endif
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
typedef void (*extra_func_t) (void *socket_);
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT
|
||||
void set_sockopt_fastpath (void *socket)
|
||||
{
|
||||
int value = 1;
|
||||
int rc =
|
||||
zmq_setsockopt (socket, ZMQ_LOOPBACK_FASTPATH, &value, sizeof value);
|
||||
assert (rc == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_pair_tcp (extra_func_t extra_func_ = NULL)
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
if (extra_func_)
|
||||
extra_func_ (sb);
|
||||
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (sb, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PAIR);
|
||||
if (extra_func_)
|
||||
extra_func_ (sc);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void test_pair_tcp_regular ()
|
||||
{
|
||||
test_pair_tcp ();
|
||||
}
|
||||
|
||||
void test_pair_tcp_connect_by_name ()
|
||||
{
|
||||
// all other tcp test cases bind to a loopback wildcard address, then
|
||||
// retrieve the bound endpoint, which is numerical, and use that to
|
||||
// connect. this test cases specifically uses "localhost" to connect
|
||||
// to ensure that names are correctly resolved
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
char bound_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (sb, bound_endpoint, sizeof bound_endpoint);
|
||||
|
||||
// extract the bound port number
|
||||
const char *pos = strrchr (bound_endpoint, ':');
|
||||
TEST_ASSERT_NOT_NULL (pos);
|
||||
const char connect_endpoint_prefix[] = "tcp://localhost";
|
||||
char connect_endpoint[MAX_SOCKET_STRING];
|
||||
strcpy (connect_endpoint, connect_endpoint_prefix);
|
||||
strcat (connect_endpoint, pos);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, connect_endpoint));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT
|
||||
void test_pair_tcp_fastpath ()
|
||||
{
|
||||
test_pair_tcp (set_sockopt_fastpath);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
void test_io_completion_port ()
|
||||
{
|
||||
void *const s = test_context_socket (ZMQ_PAIR);
|
||||
SOCKET fd;
|
||||
size_t fd_size = sizeof fd;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (s, ZMQ_FD, &fd, &fd_size));
|
||||
|
||||
::WSAPROTOCOL_INFO pi;
|
||||
TEST_ASSERT_SUCCESS_RAW_ERRNO (
|
||||
::WSADuplicateSocket (fd, ::GetCurrentProcessId (), &pi));
|
||||
const SOCKET socket = ::WSASocket (pi.iAddressFamily /*AF_INET*/,
|
||||
pi.iSocketType /*SOCK_STREAM*/,
|
||||
pi.iProtocol /*IPPROTO_TCP*/, &pi, 0, 0);
|
||||
|
||||
const HANDLE iocp =
|
||||
::CreateIoCompletionPort (INVALID_HANDLE_VALUE, NULL, 0, 0);
|
||||
TEST_ASSERT_NOT_EQUAL (NULL, iocp);
|
||||
const HANDLE res =
|
||||
::CreateIoCompletionPort (reinterpret_cast<HANDLE> (socket), iocp, 0, 0);
|
||||
TEST_ASSERT_NOT_EQUAL (NULL, res);
|
||||
|
||||
TEST_ASSERT_SUCCESS_RAW_ERRNO (closesocket (socket));
|
||||
TEST_ASSERT_TRUE (CloseHandle (iocp));
|
||||
|
||||
test_context_socket_close (s);
|
||||
}
|
||||
#endif
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_pair_tcp_regular);
|
||||
RUN_TEST (test_pair_tcp_connect_by_name);
|
||||
#ifdef ZMQ_BUILD_DRAFT
|
||||
RUN_TEST (test_pair_tcp_fastpath);
|
||||
#endif
|
||||
#ifdef _WIN32
|
||||
RUN_TEST (test_io_completion_port);
|
||||
#endif
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
86
tests/test_pair_tcp_cap_net_admin.cpp
Normal file
86
tests/test_pair_tcp_cap_net_admin.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
typedef void (*extra_func_t) (void *socket_);
|
||||
|
||||
void set_sockopt_bind_to_device (void *socket)
|
||||
{
|
||||
const char device[] = "lo";
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (socket, ZMQ_BINDTODEVICE, &device, sizeof (device) - 1));
|
||||
}
|
||||
|
||||
// TODO this is duplicated from test_pair_tcp
|
||||
void test_pair_tcp (extra_func_t extra_func_ = NULL)
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
if (extra_func_)
|
||||
extra_func_ (sb);
|
||||
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
size_t my_endpoint_length = sizeof my_endpoint;
|
||||
int rc = zmq_bind (sb, "tcp://127.0.0.1:*");
|
||||
if (rc < 0 && errno == EOPNOTSUPP)
|
||||
TEST_IGNORE_MESSAGE ("SO_BINDTODEVICE not supported");
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (sb, ZMQ_LAST_ENDPOINT, my_endpoint, &my_endpoint_length));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PAIR);
|
||||
if (extra_func_)
|
||||
extra_func_ (sc);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void test_pair_tcp_bind_to_device ()
|
||||
{
|
||||
test_pair_tcp (set_sockopt_bind_to_device);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_pair_tcp_bind_to_device);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
60
tests/test_pair_tipc.cpp
Normal file
60
tests/test_pair_tipc.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_roundtrip ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "tipc://{5560,0,0}"));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "tipc://{5560,0}@0.0.0"));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
if (!is_tipc_available ()) {
|
||||
printf ("TIPC environment unavailable, skipping test\n");
|
||||
return 77;
|
||||
}
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_roundtrip);
|
||||
return UNITY_END ();
|
||||
}
|
||||
67
tests/test_pair_vmci.cpp
Normal file
67
tests/test_pair_vmci.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vmci_sockets.h>
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_pair_vmci ()
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "vmci://" << VMCISock_GetLocalCID () << ":" << 5560;
|
||||
std::string endpoint = s.str ();
|
||||
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
int rc = zmq_bind (sb, endpoint.c_str ());
|
||||
if (rc < 0 && errno == EAFNOSUPPORT)
|
||||
TEST_IGNORE_MESSAGE ("VMCI not supported");
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint.c_str ()));
|
||||
|
||||
expect_bounce_fail (sb, sc);
|
||||
|
||||
test_context_socket_close_zero_linger (sc);
|
||||
test_context_socket_close_zero_linger (sb);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_pair_vmci);
|
||||
return UNITY_END ();
|
||||
}
|
||||
113
tests/test_peer.cpp
Normal file
113
tests/test_peer.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_peer ()
|
||||
{
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *peer1 = test_context_socket (ZMQ_PEER);
|
||||
bind_loopback (peer1, false, my_endpoint, len);
|
||||
|
||||
void *peer2 = test_context_socket (ZMQ_PEER);
|
||||
uint32_t peer1_routing_id = zmq_connect_peer (peer2, my_endpoint);
|
||||
TEST_ASSERT_NOT_EQUAL (0, peer1_routing_id);
|
||||
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));
|
||||
|
||||
char *data = static_cast<char *> (zmq_msg_data (&msg));
|
||||
data[0] = 1;
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_set_routing_id (&msg, peer1_routing_id));
|
||||
|
||||
int rc = zmq_msg_send (&msg, peer2, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
}
|
||||
|
||||
uint32_t peer2_routing_id;
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
|
||||
int rc = TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, peer1, 0));
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
|
||||
peer2_routing_id = zmq_msg_routing_id (&msg);
|
||||
TEST_ASSERT_NOT_EQUAL (0, peer2_routing_id);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
}
|
||||
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, 1));
|
||||
|
||||
char *data = static_cast<char *> (zmq_msg_data (&msg));
|
||||
data[0] = 2;
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_set_routing_id (&msg, peer2_routing_id));
|
||||
|
||||
int rc = zmq_msg_send (&msg, peer1, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
}
|
||||
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
|
||||
int rc = zmq_msg_recv (&msg, peer2, 0);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
|
||||
uint32_t routing_id = zmq_msg_routing_id (&msg);
|
||||
TEST_ASSERT_EQUAL_UINT32 (peer1_routing_id, routing_id);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
}
|
||||
|
||||
test_context_socket_close (peer1);
|
||||
test_context_socket_close (peer2);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_peer);
|
||||
return UNITY_END ();
|
||||
}
|
||||
778
tests/test_poller.cpp
Normal file
778
tests/test_poller.cpp
Normal file
@@ -0,0 +1,778 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
fd_t get_fd (void *socket_)
|
||||
{
|
||||
fd_t fd;
|
||||
size_t fd_size = sizeof fd;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (socket_, ZMQ_FD, &fd, &fd_size));
|
||||
return fd;
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_destroy_direct ()
|
||||
{
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_destroy (NULL));
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_destroy_indirect ()
|
||||
{
|
||||
void *null_poller = NULL;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_destroy (&null_poller));
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_size_direct ()
|
||||
{
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_size (NULL));
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_size_indirect ()
|
||||
{
|
||||
void *null_poller = NULL;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_size (&null_poller));
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_add_direct ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_add (NULL, socket, NULL, ZMQ_POLLIN));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_add_indirect ()
|
||||
{
|
||||
void *null_poller = NULL;
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EFAULT, zmq_poller_add (&null_poller, socket, NULL, ZMQ_POLLIN));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_modify_direct ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_modify (NULL, socket, ZMQ_POLLIN));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_modify_indirect ()
|
||||
{
|
||||
void *null_poller = NULL;
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EFAULT, zmq_poller_modify (&null_poller, socket, ZMQ_POLLIN));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_remove_direct ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_remove (NULL, socket));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_remove_indirect ()
|
||||
{
|
||||
void *null_poller = NULL;
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_remove (&null_poller, socket));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_add_fd_direct ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
const fd_t fd = get_fd (socket);
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_add_fd (NULL, fd, NULL, ZMQ_POLLIN));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_add_fd_indirect ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
const fd_t fd = get_fd (socket);
|
||||
void *null_poller = NULL;
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EFAULT, zmq_poller_add_fd (&null_poller, fd, NULL, ZMQ_POLLIN));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_modify_fd_direct ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
const fd_t fd = get_fd (socket);
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_modify_fd (NULL, fd, ZMQ_POLLIN));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_modify_fd_indirect ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
const fd_t fd = get_fd (socket);
|
||||
void *null_poller = NULL;
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EFAULT, zmq_poller_modify_fd (&null_poller, fd, ZMQ_POLLIN));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_remove_fd_direct ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
const fd_t fd = get_fd (socket);
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_remove_fd (NULL, fd));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_remove_fd_indirect ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
const fd_t fd = get_fd (socket);
|
||||
void *null_poller = NULL;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_remove_fd (&null_poller, fd));
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_wait_direct ()
|
||||
{
|
||||
zmq_poller_event_t event;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_wait (NULL, &event, 0));
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_wait_indirect ()
|
||||
{
|
||||
zmq_poller_event_t event;
|
||||
void *null_poller = NULL;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_wait (&null_poller, &event, 0));
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_wait_all_direct ()
|
||||
{
|
||||
zmq_poller_event_t event;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_wait_all (NULL, &event, 1, 0));
|
||||
}
|
||||
|
||||
void test_null_poller_pointers_wait_all_indirect ()
|
||||
{
|
||||
zmq_poller_event_t event;
|
||||
void *null_poller = NULL;
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EFAULT, zmq_poller_wait_all (&null_poller, &event, 1, 0));
|
||||
}
|
||||
|
||||
void test_null_poller_pointer_poller_fd ()
|
||||
{
|
||||
void *null_poller = NULL;
|
||||
fd_t fd;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_fd (&null_poller, &fd));
|
||||
}
|
||||
|
||||
void test_null_socket_pointers ()
|
||||
{
|
||||
void *poller = zmq_poller_new ();
|
||||
TEST_ASSERT_NOT_NULL (poller);
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK,
|
||||
zmq_poller_add (poller, NULL, NULL, ZMQ_POLLIN));
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK,
|
||||
zmq_poller_modify (poller, NULL, ZMQ_POLLIN));
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOTSOCK, zmq_poller_remove (poller, NULL));
|
||||
|
||||
fd_t null_socket_fd = retired_fd;
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EBADF, zmq_poller_add_fd (poller, null_socket_fd, NULL, ZMQ_POLLIN));
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EBADF, zmq_poller_modify_fd (poller, null_socket_fd, ZMQ_POLLIN));
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (EBADF,
|
||||
zmq_poller_remove_fd (poller, null_socket_fd));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));
|
||||
}
|
||||
|
||||
typedef void (*extra_poller_socket_func_t) (void *poller_, void *socket_);
|
||||
|
||||
void test_with_empty_poller (extra_poller_socket_func_t extra_func_)
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
void *poller = zmq_poller_new ();
|
||||
TEST_ASSERT_NOT_NULL (poller);
|
||||
|
||||
extra_func_ (poller, socket);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
typedef void (*extra_poller_func_t) (void *poller_);
|
||||
|
||||
void test_with_valid_poller (extra_poller_func_t extra_func_)
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
void *poller = zmq_poller_new ();
|
||||
TEST_ASSERT_NOT_NULL (poller);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller, socket, NULL, ZMQ_POLLIN));
|
||||
|
||||
extra_func_ (poller);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_call_poller_fd_no_signaler ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
void *poller = zmq_poller_new ();
|
||||
TEST_ASSERT_NOT_NULL (poller);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller, socket, NULL, ZMQ_POLLIN));
|
||||
|
||||
fd_t fd;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_poller_fd (poller, &fd));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_call_poller_fd ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_CLIENT);
|
||||
|
||||
void *poller = zmq_poller_new ();
|
||||
TEST_ASSERT_NOT_NULL (poller);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller, socket, NULL, ZMQ_POLLIN));
|
||||
|
||||
fd_t fd;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_fd (poller, &fd));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void call_poller_wait_null_event_fails (void *poller_)
|
||||
{
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_wait (poller_, NULL, 0));
|
||||
}
|
||||
|
||||
void call_poller_wait_all_null_event_fails_event_count_nonzero (void *poller_)
|
||||
{
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_wait_all (poller_, NULL, 1, 0));
|
||||
}
|
||||
|
||||
void call_poller_wait_all_null_event_fails_event_count_zero (void *poller_)
|
||||
{
|
||||
#if 0
|
||||
// TODO this causes an assertion, which is not consistent if the number
|
||||
// of events may be 0, the pointer should be allowed to by NULL in that
|
||||
// case too
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait_all (poller, NULL, 0, 0));
|
||||
#endif
|
||||
}
|
||||
|
||||
#define TEST_CASE_FUNC_PARAM(name, func) \
|
||||
void test_##name () { func (name); }
|
||||
|
||||
TEST_CASE_FUNC_PARAM (call_poller_wait_null_event_fails, test_with_valid_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_wait_all_null_event_fails_event_count_nonzero,
|
||||
test_with_valid_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_wait_all_null_event_fails_event_count_zero,
|
||||
test_with_valid_poller)
|
||||
|
||||
void call_poller_size (void *poller_, void *socket_)
|
||||
{
|
||||
int rc = zmq_poller_size (poller_);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
TEST_ASSERT_EQUAL (rc, 0);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller_, socket_, NULL, ZMQ_POLLIN));
|
||||
rc = zmq_poller_size (poller_);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
TEST_ASSERT_EQUAL (rc, 1);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_modify (poller_, socket_, 0));
|
||||
rc = zmq_poller_size (poller_);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
TEST_ASSERT_EQUAL (rc, 1);
|
||||
|
||||
fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add_fd (poller_, plain_socket, NULL, ZMQ_POLLOUT));
|
||||
rc = zmq_poller_size (poller_);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
TEST_ASSERT_EQUAL (rc, 2);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove (poller_, socket_));
|
||||
rc = zmq_poller_size (poller_);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
TEST_ASSERT_EQUAL (rc, 1);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove_fd (poller_, plain_socket));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));
|
||||
rc = zmq_poller_size (poller_);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
TEST_ASSERT_EQUAL (rc, 0);
|
||||
}
|
||||
|
||||
void call_poller_add_twice_fails (void *poller_, void *socket_)
|
||||
{
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller_, socket_, NULL, ZMQ_POLLIN));
|
||||
|
||||
// attempt to add the same socket twice
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_poller_add (poller_, socket_, NULL, ZMQ_POLLIN));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove (poller_, socket_));
|
||||
}
|
||||
|
||||
void call_poller_remove_unregistered_fails (void *poller_, void *socket_)
|
||||
{
|
||||
// attempt to remove socket that is not present
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_poller_remove (poller_, socket_));
|
||||
}
|
||||
|
||||
void call_poller_modify_unregistered_fails (void *poller_, void *socket_)
|
||||
{
|
||||
// attempt to modify socket that is not present
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_poller_modify (poller_, socket_, ZMQ_POLLIN));
|
||||
}
|
||||
|
||||
void call_poller_add_no_events (void *poller_, void *socket_)
|
||||
{
|
||||
// add a socket with no events initially (may be activated later with
|
||||
// zmq_poller_modify)
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_add (poller_, socket_, NULL, 0));
|
||||
// TODO test that no events are signalled
|
||||
}
|
||||
|
||||
void call_poller_modify_no_events (void *poller_, void *socket_)
|
||||
{
|
||||
// deactivates all events for a socket temporarily (may be activated again
|
||||
// later with zmq_poller_modify)
|
||||
zmq_poller_add (poller_, socket_, NULL, ZMQ_POLLIN);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_modify (poller_, socket_, 0));
|
||||
// TODO test that no events are signalled
|
||||
}
|
||||
|
||||
void call_poller_add_fd_twice_fails (void *poller_, void * /*zeromq_socket*/)
|
||||
{
|
||||
fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add_fd (poller_, plain_socket, NULL, ZMQ_POLLIN));
|
||||
|
||||
// attempt to add the same plain socket twice
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_poller_add_fd (poller_, plain_socket, NULL, ZMQ_POLLIN));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove_fd (poller_, plain_socket));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));
|
||||
}
|
||||
|
||||
void call_poller_remove_fd_unregistered_fails (void *poller_,
|
||||
void * /*zeromq_socket*/)
|
||||
{
|
||||
fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
// attempt to remove plain socket that is not present
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL,
|
||||
zmq_poller_remove_fd (poller_, plain_socket));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));
|
||||
}
|
||||
|
||||
void call_poller_modify_fd_unregistered_fails (void *poller_,
|
||||
void * /*zeromq_socket*/)
|
||||
{
|
||||
fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
|
||||
// attempt to remove plain socket that is not present
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_poller_modify_fd (poller_, plain_socket, ZMQ_POLLIN));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));
|
||||
}
|
||||
|
||||
void call_poller_add_invalid_events_fails (void *poller_, void *zeromq_socket_)
|
||||
{
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_poller_add (poller_, zeromq_socket_, NULL, SHRT_MAX));
|
||||
}
|
||||
|
||||
void call_poller_modify_invalid_events_fails (void *poller_,
|
||||
void *zeromq_socket_)
|
||||
{
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller_, zeromq_socket_, NULL, 0));
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_poller_modify (poller_, zeromq_socket_, SHRT_MAX));
|
||||
}
|
||||
|
||||
void call_poller_add_fd_invalid_events_fails (void *poller_,
|
||||
void * /*zeromq_socket*/)
|
||||
{
|
||||
fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_poller_add_fd (poller_, plain_socket, NULL, SHRT_MAX));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));
|
||||
}
|
||||
|
||||
void call_poller_modify_fd_invalid_events_fails (void *poller_,
|
||||
void * /*zeromq_socket*/)
|
||||
{
|
||||
fd_t plain_socket = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add_fd (poller_, plain_socket, NULL, 0));
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_poller_modify_fd (poller_, plain_socket, SHRT_MAX));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (close (plain_socket));
|
||||
}
|
||||
|
||||
TEST_CASE_FUNC_PARAM (call_poller_size, test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_add_twice_fails, test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_remove_unregistered_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_modify_unregistered_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_add_no_events, test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_modify_no_events, test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_add_fd_twice_fails, test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_remove_fd_unregistered_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_modify_fd_unregistered_fails,
|
||||
test_with_empty_poller)
|
||||
|
||||
TEST_CASE_FUNC_PARAM (call_poller_add_invalid_events_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_modify_invalid_events_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_add_fd_invalid_events_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_modify_fd_invalid_events_fails,
|
||||
test_with_empty_poller)
|
||||
|
||||
void call_poller_wait_empty_with_timeout_fails (void *poller_,
|
||||
void * /*socket*/)
|
||||
{
|
||||
zmq_poller_event_t event;
|
||||
// waiting on poller with no registered sockets should report error
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_poller_wait (poller_, &event, 0));
|
||||
}
|
||||
|
||||
void call_poller_wait_empty_without_timeout_fails (void *poller_,
|
||||
void * /*socket*/)
|
||||
{
|
||||
zmq_poller_event_t event;
|
||||
// this would never be able to return since no socket was registered, and should yield an error
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT, zmq_poller_wait (poller_, &event, -1));
|
||||
}
|
||||
|
||||
void call_poller_wait_all_empty_negative_count_fails (void *poller_,
|
||||
void * /*socket*/)
|
||||
{
|
||||
zmq_poller_event_t event;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL,
|
||||
zmq_poller_wait_all (poller_, &event, -1, 0));
|
||||
}
|
||||
|
||||
void call_poller_wait_all_empty_without_timeout_fails (void *poller_,
|
||||
void * /*socket*/)
|
||||
{
|
||||
zmq_poller_event_t event;
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN,
|
||||
zmq_poller_wait_all (poller_, &event, 0, 0));
|
||||
}
|
||||
|
||||
void call_poller_wait_all_empty_with_timeout_fails (void *poller_,
|
||||
void * /*socket*/)
|
||||
{
|
||||
zmq_poller_event_t event;
|
||||
// this would never be able to return since no socket was registered, and should yield an error
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_wait_all (poller_, &event, 0, -1));
|
||||
}
|
||||
|
||||
void call_poller_wait_all_inf_disabled_fails (void *poller_, void *socket_)
|
||||
{
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_add (poller_, socket_, NULL, 0));
|
||||
|
||||
zmq_poller_event_t events[1];
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN,
|
||||
zmq_poller_wait_all (poller_, events, 1, 0));
|
||||
TEST_ASSERT_FAILURE_ERRNO (EFAULT,
|
||||
zmq_poller_wait_all (poller_, events, 1, -1));
|
||||
}
|
||||
|
||||
TEST_CASE_FUNC_PARAM (call_poller_wait_empty_with_timeout_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_wait_empty_without_timeout_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_wait_all_empty_negative_count_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_wait_all_empty_without_timeout_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_wait_all_empty_with_timeout_fails,
|
||||
test_with_empty_poller)
|
||||
TEST_CASE_FUNC_PARAM (call_poller_wait_all_inf_disabled_fails,
|
||||
test_with_empty_poller)
|
||||
|
||||
void test_poll_basic ()
|
||||
{
|
||||
// Create few sockets
|
||||
void *vent = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (vent, my_endpoint, len);
|
||||
|
||||
void *sink = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sink, my_endpoint));
|
||||
|
||||
// Set up poller
|
||||
void *poller = zmq_poller_new ();
|
||||
|
||||
// register sink
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_add (poller, sink, sink, ZMQ_POLLIN));
|
||||
|
||||
// Send a message
|
||||
const char *vent_sink_msg = "H";
|
||||
send_string_expect_success (vent, vent_sink_msg, 0);
|
||||
|
||||
// We expect a message only on the sink
|
||||
zmq_poller_event_t event;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait (poller, &event, -1));
|
||||
TEST_ASSERT_EQUAL_PTR (sink, event.socket);
|
||||
TEST_ASSERT_EQUAL_PTR (sink, event.user_data);
|
||||
recv_string_expect_success (sink, vent_sink_msg, 0);
|
||||
|
||||
// We expect timed out
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_poller_wait (poller, &event, 0));
|
||||
|
||||
// Stop polling sink
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove (poller, sink));
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (vent);
|
||||
test_context_socket_close (sink);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));
|
||||
}
|
||||
|
||||
void test_poll_fd ()
|
||||
{
|
||||
// Create sockets
|
||||
void *vent = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (vent, my_endpoint, len);
|
||||
|
||||
void *bowl = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (bowl, my_endpoint));
|
||||
|
||||
// Set up poller
|
||||
void *poller = zmq_poller_new ();
|
||||
|
||||
// Check we can poll an FD
|
||||
const fd_t fd = get_fd (bowl);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add_fd (poller, fd, bowl, ZMQ_POLLIN));
|
||||
|
||||
zmq_poller_event_t event;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait (poller, &event, 500));
|
||||
TEST_ASSERT_NULL (event.socket);
|
||||
TEST_ASSERT_EQUAL (fd, event.fd);
|
||||
TEST_ASSERT_EQUAL_PTR (bowl, event.user_data);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove_fd (poller, fd));
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (vent);
|
||||
test_context_socket_close (bowl);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));
|
||||
}
|
||||
|
||||
void test_poll_client_server ()
|
||||
{
|
||||
#if defined(ZMQ_SERVER) && defined(ZMQ_CLIENT)
|
||||
// Create sockets
|
||||
void *server = test_context_socket (ZMQ_SERVER);
|
||||
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (server, my_endpoint, len);
|
||||
|
||||
void *client = test_context_socket (ZMQ_CLIENT);
|
||||
|
||||
// Set up poller
|
||||
void *poller = zmq_poller_new ();
|
||||
|
||||
// Polling on thread safe sockets
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller, server, NULL, ZMQ_POLLIN));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
const char *client_server_msg = "I";
|
||||
send_string_expect_success (client, client_server_msg, 0);
|
||||
|
||||
zmq_poller_event_t event;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait (poller, &event, 500));
|
||||
TEST_ASSERT_EQUAL_PTR (server, event.socket);
|
||||
TEST_ASSERT_NULL (event.user_data);
|
||||
#ifndef _WIN32
|
||||
TEST_ASSERT (event.fd == -1);
|
||||
#endif
|
||||
recv_string_expect_success (server, client_server_msg, 0);
|
||||
|
||||
// Polling on pollout
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_modify (poller, server, ZMQ_POLLOUT | ZMQ_POLLIN));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_wait (poller, &event, 0));
|
||||
TEST_ASSERT_EQUAL_PTR (server, event.socket);
|
||||
TEST_ASSERT_NULL (event.user_data);
|
||||
#ifndef _WIN32
|
||||
TEST_ASSERT (event.fd == -1);
|
||||
#endif
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_POLLOUT, event.events);
|
||||
|
||||
// Stop polling server
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_remove (poller, server));
|
||||
|
||||
// Clean up
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (client);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_poller_destroy (&poller));
|
||||
#endif
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_null_poller_pointers_destroy_direct);
|
||||
RUN_TEST (test_null_poller_pointers_destroy_indirect);
|
||||
RUN_TEST (test_null_poller_pointers_size_direct);
|
||||
RUN_TEST (test_null_poller_pointers_size_indirect);
|
||||
RUN_TEST (test_null_poller_pointers_add_direct);
|
||||
RUN_TEST (test_null_poller_pointers_add_indirect);
|
||||
RUN_TEST (test_null_poller_pointers_modify_direct);
|
||||
RUN_TEST (test_null_poller_pointers_modify_indirect);
|
||||
RUN_TEST (test_null_poller_pointers_remove_direct);
|
||||
RUN_TEST (test_null_poller_pointers_remove_indirect);
|
||||
RUN_TEST (test_null_poller_pointers_add_fd_direct);
|
||||
RUN_TEST (test_null_poller_pointers_add_fd_indirect);
|
||||
RUN_TEST (test_null_poller_pointers_modify_fd_direct);
|
||||
RUN_TEST (test_null_poller_pointers_modify_fd_indirect);
|
||||
RUN_TEST (test_null_poller_pointers_remove_fd_direct);
|
||||
RUN_TEST (test_null_poller_pointers_remove_fd_indirect);
|
||||
RUN_TEST (test_null_poller_pointers_wait_direct);
|
||||
RUN_TEST (test_null_poller_pointers_wait_indirect);
|
||||
RUN_TEST (test_null_poller_pointers_wait_all_direct);
|
||||
RUN_TEST (test_null_poller_pointers_wait_all_indirect);
|
||||
RUN_TEST (test_null_poller_pointer_poller_fd);
|
||||
|
||||
RUN_TEST (test_null_socket_pointers);
|
||||
|
||||
RUN_TEST (test_call_poller_wait_null_event_fails);
|
||||
RUN_TEST (test_call_poller_wait_all_null_event_fails_event_count_nonzero);
|
||||
RUN_TEST (test_call_poller_wait_all_null_event_fails_event_count_zero);
|
||||
|
||||
RUN_TEST (test_call_poller_size);
|
||||
RUN_TEST (test_call_poller_add_twice_fails);
|
||||
RUN_TEST (test_call_poller_remove_unregistered_fails);
|
||||
RUN_TEST (test_call_poller_modify_unregistered_fails);
|
||||
RUN_TEST (test_call_poller_add_no_events);
|
||||
RUN_TEST (test_call_poller_modify_no_events);
|
||||
RUN_TEST (test_call_poller_add_fd_twice_fails);
|
||||
RUN_TEST (test_call_poller_remove_fd_unregistered_fails);
|
||||
RUN_TEST (test_call_poller_modify_fd_unregistered_fails);
|
||||
RUN_TEST (test_call_poller_add_invalid_events_fails);
|
||||
RUN_TEST (test_call_poller_modify_invalid_events_fails);
|
||||
RUN_TEST (test_call_poller_add_fd_invalid_events_fails);
|
||||
RUN_TEST (test_call_poller_modify_fd_invalid_events_fails);
|
||||
|
||||
RUN_TEST (test_call_poller_wait_empty_with_timeout_fails);
|
||||
RUN_TEST (test_call_poller_wait_empty_without_timeout_fails);
|
||||
RUN_TEST (test_call_poller_wait_all_empty_negative_count_fails);
|
||||
RUN_TEST (test_call_poller_wait_all_empty_without_timeout_fails);
|
||||
RUN_TEST (test_call_poller_wait_all_empty_with_timeout_fails);
|
||||
RUN_TEST (test_call_poller_wait_all_inf_disabled_fails);
|
||||
|
||||
RUN_TEST (test_call_poller_fd_no_signaler);
|
||||
RUN_TEST (test_call_poller_fd);
|
||||
|
||||
RUN_TEST (test_poll_basic);
|
||||
RUN_TEST (test_poll_fd);
|
||||
RUN_TEST (test_poll_client_server);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
113
tests/test_probe_router.cpp
Normal file
113
tests/test_probe_router.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_probe_router_router ()
|
||||
{
|
||||
// Create server and bind to endpoint
|
||||
void *server = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));
|
||||
|
||||
// Create client and connect to server, doing a probe
|
||||
void *client = test_context_socket (ZMQ_ROUTER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_ROUTING_ID, "X", 1));
|
||||
int probe = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PROBE_ROUTER, &probe, sizeof (probe)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
// We expect a routing id=X + empty message from client
|
||||
recv_string_expect_success (server, "X", 0);
|
||||
unsigned char buffer[255];
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
0, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, buffer, 255, 0)));
|
||||
|
||||
// Send a message to client now
|
||||
send_string_expect_success (server, "X", ZMQ_SNDMORE);
|
||||
send_string_expect_success (server, "Hello", 0);
|
||||
|
||||
// receive the routing ID, which is auto-generated in this case, since the
|
||||
// peer did not set one explicitly
|
||||
TEST_ASSERT_EQUAL_INT (
|
||||
5, TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (client, buffer, 255, 0)));
|
||||
|
||||
recv_string_expect_success (client, "Hello", 0);
|
||||
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (client);
|
||||
}
|
||||
|
||||
void test_probe_router_dealer ()
|
||||
{
|
||||
// Create server and bind to endpoint
|
||||
void *server = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof (my_endpoint));
|
||||
|
||||
// Create client and connect to server, doing a probe
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (client, ZMQ_ROUTING_ID, "X", 1));
|
||||
int probe = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PROBE_ROUTER, &probe, sizeof (probe)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
// We expect a routing id=X + empty message from client
|
||||
recv_string_expect_success (server, "X", 0);
|
||||
unsigned char buffer[255];
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_recv (server, buffer, 255, 0));
|
||||
|
||||
// Send a message to client now
|
||||
send_string_expect_success (server, "X", ZMQ_SNDMORE);
|
||||
send_string_expect_success (server, "Hello", 0);
|
||||
|
||||
recv_string_expect_success (client, "Hello", 0);
|
||||
|
||||
test_context_socket_close (server);
|
||||
test_context_socket_close (client);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
|
||||
RUN_TEST (test_probe_router_router);
|
||||
RUN_TEST (test_probe_router_dealer);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
470
tests/test_proxy.cpp
Normal file
470
tests/test_proxy.cpp
Normal file
@@ -0,0 +1,470 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
#define CONTENT_SIZE 13
|
||||
#define CONTENT_SIZE_MAX 32
|
||||
#define ROUTING_ID_SIZE 10
|
||||
#define ROUTING_ID_SIZE_MAX 32
|
||||
#define QT_WORKERS 5
|
||||
#define QT_CLIENTS 3
|
||||
#define is_verbose 0
|
||||
|
||||
struct thread_data
|
||||
{
|
||||
int id;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t msg_in;
|
||||
uint64_t bytes_in;
|
||||
uint64_t msg_out;
|
||||
uint64_t bytes_out;
|
||||
} zmq_socket_stats_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
zmq_socket_stats_t frontend;
|
||||
zmq_socket_stats_t backend;
|
||||
} zmq_proxy_stats_t;
|
||||
|
||||
void *g_clients_pkts_out = NULL;
|
||||
void *g_workers_pkts_out = NULL;
|
||||
|
||||
// Asynchronous client-to-server (DEALER to ROUTER) - pure libzmq
|
||||
//
|
||||
// While this example runs in a single process, that is to make
|
||||
// it easier to start and stop the example. Each task may have its own
|
||||
// context and conceptually acts as a separate process. To have this
|
||||
// behaviour, it is necessary to replace the inproc transport of the
|
||||
// control socket by a tcp transport.
|
||||
|
||||
// This is our client task
|
||||
// It connects to the server, and then sends a request once per second
|
||||
// It collects responses as they arrive, and it prints them out. We will
|
||||
// run several client tasks in parallel, each with a different random ID.
|
||||
|
||||
static void client_task (void *db_)
|
||||
{
|
||||
const thread_data *const databag = static_cast<const thread_data *> (db_);
|
||||
// Endpoint socket gets random port to avoid test failing when port in use
|
||||
void *endpoint = zmq_socket (get_test_context (), ZMQ_PAIR);
|
||||
TEST_ASSERT_NOT_NULL (endpoint);
|
||||
int linger = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (endpoint, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
char endpoint_source[256];
|
||||
sprintf (endpoint_source, "inproc://endpoint%d", databag->id);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (endpoint, endpoint_source));
|
||||
char *my_endpoint = s_recv (endpoint);
|
||||
TEST_ASSERT_NOT_NULL (my_endpoint);
|
||||
|
||||
void *client = zmq_socket (get_test_context (), ZMQ_DEALER);
|
||||
TEST_ASSERT_NOT_NULL (client);
|
||||
|
||||
// Control socket receives terminate command from main over inproc
|
||||
void *control = zmq_socket (get_test_context (), ZMQ_SUB);
|
||||
TEST_ASSERT_NOT_NULL (control);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (control, ZMQ_SUBSCRIBE, "", 0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, "inproc://control"));
|
||||
|
||||
char content[CONTENT_SIZE_MAX] = {};
|
||||
// Set random routing id to make tracing easier
|
||||
char routing_id[ROUTING_ID_SIZE] = {};
|
||||
sprintf (routing_id, "%04X-%04X", rand () % 0xFFFF, rand () % 0xFFFF);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
client, ZMQ_ROUTING_ID, routing_id,
|
||||
ROUTING_ID_SIZE)); // includes '\0' as an helper for printf
|
||||
linger = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
zmq_pollitem_t items[] = {{client, 0, ZMQ_POLLIN, 0},
|
||||
{control, 0, ZMQ_POLLIN, 0}};
|
||||
int request_nbr = 0;
|
||||
bool run = true;
|
||||
bool keep_sending = true;
|
||||
while (run) {
|
||||
// Tick once per 200 ms, pulling in arriving messages
|
||||
int centitick;
|
||||
for (centitick = 0; centitick < 20; centitick++) {
|
||||
zmq_poll (items, 2, 10);
|
||||
if (items[0].revents & ZMQ_POLLIN) {
|
||||
int rcvmore;
|
||||
size_t sz = sizeof (rcvmore);
|
||||
int rc = TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_recv (client, content, CONTENT_SIZE_MAX, 0));
|
||||
TEST_ASSERT_EQUAL_INT (CONTENT_SIZE, rc);
|
||||
if (is_verbose)
|
||||
printf (
|
||||
"client receive - routing_id = %s content = %s\n",
|
||||
routing_id, content);
|
||||
// Check that message is still the same
|
||||
TEST_ASSERT_EQUAL_STRING_LEN ("request #", content, 9);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (client, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_FALSE (rcvmore);
|
||||
}
|
||||
if (items[1].revents & ZMQ_POLLIN) {
|
||||
int rc = zmq_recv (control, content, CONTENT_SIZE_MAX, 0);
|
||||
|
||||
if (rc > 0) {
|
||||
content[rc] = 0; // NULL-terminate the command string
|
||||
if (is_verbose)
|
||||
printf (
|
||||
"client receive - routing_id = %s command = %s\n",
|
||||
routing_id, content);
|
||||
if (memcmp (content, "TERMINATE", 9) == 0) {
|
||||
run = false;
|
||||
break;
|
||||
}
|
||||
if (memcmp (content, "STOP", 4) == 0) {
|
||||
keep_sending = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keep_sending) {
|
||||
sprintf (content, "request #%03d", ++request_nbr); // CONTENT_SIZE
|
||||
if (is_verbose)
|
||||
printf ("client send - routing_id = %s request #%03d\n",
|
||||
routing_id, request_nbr);
|
||||
zmq_atomic_counter_inc (g_clients_pkts_out);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (CONTENT_SIZE,
|
||||
zmq_send (client, content, CONTENT_SIZE, 0));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (client));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (endpoint));
|
||||
free (my_endpoint);
|
||||
}
|
||||
|
||||
// This is our server task.
|
||||
// It uses the multithreaded server model to deal requests out to a pool
|
||||
// of workers and route replies back to clients. One worker can handle
|
||||
// one request at a time but one client can talk to multiple workers at
|
||||
// once.
|
||||
|
||||
static void server_worker (void * /*unused_*/);
|
||||
|
||||
void server_task (void * /*unused_*/)
|
||||
{
|
||||
// Frontend socket talks to clients over TCP
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
void *frontend = zmq_socket (get_test_context (), ZMQ_ROUTER);
|
||||
TEST_ASSERT_NOT_NULL (frontend);
|
||||
int linger = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (frontend, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
bind_loopback_ipv4 (frontend, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
// Backend socket talks to workers over inproc
|
||||
void *backend = zmq_socket (get_test_context (), ZMQ_DEALER);
|
||||
TEST_ASSERT_NOT_NULL (backend);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (backend, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, "inproc://backend"));
|
||||
|
||||
// Control socket receives terminate command from main over inproc
|
||||
void *control = zmq_socket (get_test_context (), ZMQ_REP);
|
||||
TEST_ASSERT_NOT_NULL (control);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, "inproc://control_proxy"));
|
||||
|
||||
// Launch pool of worker threads, precise number is not critical
|
||||
int thread_nbr;
|
||||
void *threads[5];
|
||||
for (thread_nbr = 0; thread_nbr < QT_WORKERS; thread_nbr++)
|
||||
threads[thread_nbr] = zmq_threadstart (&server_worker, NULL);
|
||||
|
||||
// Endpoint socket sends random port to avoid test failing when port in use
|
||||
void *endpoint_receivers[QT_CLIENTS];
|
||||
char endpoint_source[256];
|
||||
for (int i = 0; i < QT_CLIENTS; ++i) {
|
||||
endpoint_receivers[i] = zmq_socket (get_test_context (), ZMQ_PAIR);
|
||||
TEST_ASSERT_NOT_NULL (endpoint_receivers[i]);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
endpoint_receivers[i], ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
sprintf (endpoint_source, "inproc://endpoint%d", i);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_bind (endpoint_receivers[i], endpoint_source));
|
||||
}
|
||||
|
||||
for (int i = 0; i < QT_CLIENTS; ++i) {
|
||||
send_string_expect_success (endpoint_receivers[i], my_endpoint, 0);
|
||||
}
|
||||
|
||||
// Connect backend to frontend via a proxy
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_proxy_steerable (frontend, backend, NULL, control));
|
||||
|
||||
for (thread_nbr = 0; thread_nbr < QT_WORKERS; thread_nbr++)
|
||||
zmq_threadclose (threads[thread_nbr]);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (frontend));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (backend));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));
|
||||
for (int i = 0; i < QT_CLIENTS; ++i) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (endpoint_receivers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
// Each worker task works on one request at a time and sends a random number
|
||||
// of replies back, with random delays between replies:
|
||||
// The comments in the first column, if suppressed, makes it a poller version
|
||||
|
||||
static void server_worker (void * /*unused_*/)
|
||||
{
|
||||
void *worker = zmq_socket (get_test_context (), ZMQ_DEALER);
|
||||
TEST_ASSERT_NOT_NULL (worker);
|
||||
int linger = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (worker, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (worker, "inproc://backend"));
|
||||
|
||||
// Control socket receives terminate command from main over inproc
|
||||
void *control = zmq_socket (get_test_context (), ZMQ_SUB);
|
||||
TEST_ASSERT_NOT_NULL (control);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (control, ZMQ_SUBSCRIBE, "", 0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, "inproc://control"));
|
||||
|
||||
char content[CONTENT_SIZE_MAX] =
|
||||
{}; // bigger than what we need to check that
|
||||
char routing_id[ROUTING_ID_SIZE_MAX] =
|
||||
{}; // the size received is the size sent
|
||||
|
||||
bool run = true;
|
||||
bool keep_sending = true;
|
||||
while (run) {
|
||||
int rc = zmq_recv (control, content, CONTENT_SIZE_MAX,
|
||||
ZMQ_DONTWAIT); // usually, rc == -1 (no message)
|
||||
if (rc > 0) {
|
||||
content[rc] = 0; // NULL-terminate the command string
|
||||
if (is_verbose)
|
||||
printf ("server_worker receives command = %s\n", content);
|
||||
if (memcmp (content, "TERMINATE", 9) == 0)
|
||||
run = false;
|
||||
if (memcmp (content, "STOP", 4) == 0)
|
||||
keep_sending = false;
|
||||
}
|
||||
// The DEALER socket gives us the reply envelope and message
|
||||
// if we don't poll, we have to use ZMQ_DONTWAIT, if we poll, we can block-receive with 0
|
||||
rc = zmq_recv (worker, routing_id, ROUTING_ID_SIZE_MAX, ZMQ_DONTWAIT);
|
||||
if (rc == ROUTING_ID_SIZE) {
|
||||
rc = zmq_recv (worker, content, CONTENT_SIZE_MAX, 0);
|
||||
TEST_ASSERT_EQUAL_INT (CONTENT_SIZE, rc);
|
||||
if (is_verbose)
|
||||
printf ("server receive - routing_id = %s content = %s\n",
|
||||
routing_id, content);
|
||||
|
||||
// Send 0..4 replies back
|
||||
if (keep_sending) {
|
||||
int reply, replies = rand () % 5;
|
||||
for (reply = 0; reply < replies; reply++) {
|
||||
// Sleep for some fraction of a second
|
||||
msleep (rand () % 10 + 1);
|
||||
|
||||
// Send message from server to client
|
||||
if (is_verbose)
|
||||
printf ("server send - routing_id = %s reply\n",
|
||||
routing_id);
|
||||
zmq_atomic_counter_inc (g_workers_pkts_out);
|
||||
|
||||
rc = zmq_send (worker, routing_id, ROUTING_ID_SIZE,
|
||||
ZMQ_SNDMORE);
|
||||
TEST_ASSERT_EQUAL_INT (ROUTING_ID_SIZE, rc);
|
||||
rc = zmq_send (worker, content, CONTENT_SIZE, 0);
|
||||
TEST_ASSERT_EQUAL_INT (CONTENT_SIZE, rc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (worker));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));
|
||||
}
|
||||
|
||||
uint64_t recv_stat (void *sock_, bool last_)
|
||||
{
|
||||
uint64_t res;
|
||||
zmq_msg_t stats_msg;
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&stats_msg));
|
||||
TEST_ASSERT_EQUAL_INT (sizeof (uint64_t),
|
||||
zmq_recvmsg (sock_, &stats_msg, 0));
|
||||
memcpy (&res, zmq_msg_data (&stats_msg), zmq_msg_size (&stats_msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&stats_msg));
|
||||
|
||||
int more;
|
||||
size_t moresz = sizeof more;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (sock_, ZMQ_RCVMORE, &more, &moresz));
|
||||
TEST_ASSERT_TRUE ((last_ && !more) || (!last_ && more));
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Utility function to interrogate the proxy:
|
||||
|
||||
void check_proxy_stats (void *control_proxy_)
|
||||
{
|
||||
zmq_proxy_stats_t total_stats;
|
||||
|
||||
send_string_expect_success (control_proxy_, "STATISTICS", 0);
|
||||
|
||||
// first frame of the reply contains FRONTEND stats:
|
||||
total_stats.frontend.msg_in = recv_stat (control_proxy_, false);
|
||||
total_stats.frontend.bytes_in = recv_stat (control_proxy_, false);
|
||||
total_stats.frontend.msg_out = recv_stat (control_proxy_, false);
|
||||
total_stats.frontend.bytes_out = recv_stat (control_proxy_, false);
|
||||
|
||||
// second frame of the reply contains BACKEND stats:
|
||||
total_stats.backend.msg_in = recv_stat (control_proxy_, false);
|
||||
total_stats.backend.bytes_in = recv_stat (control_proxy_, false);
|
||||
total_stats.backend.msg_out = recv_stat (control_proxy_, false);
|
||||
total_stats.backend.bytes_out = recv_stat (control_proxy_, true);
|
||||
|
||||
// check stats
|
||||
|
||||
if (is_verbose) {
|
||||
printf (
|
||||
"frontend: pkts_in=%lu bytes_in=%lu pkts_out=%lu bytes_out=%lu\n",
|
||||
static_cast<unsigned long int> (total_stats.frontend.msg_in),
|
||||
static_cast<unsigned long int> (total_stats.frontend.bytes_in),
|
||||
static_cast<unsigned long int> (total_stats.frontend.msg_out),
|
||||
static_cast<unsigned long int> (total_stats.frontend.bytes_out));
|
||||
printf (
|
||||
"backend: pkts_in=%lu bytes_in=%lu pkts_out=%lu bytes_out=%lu\n",
|
||||
static_cast<unsigned long int> (total_stats.backend.msg_in),
|
||||
static_cast<unsigned long int> (total_stats.backend.bytes_in),
|
||||
static_cast<unsigned long int> (total_stats.backend.msg_out),
|
||||
static_cast<unsigned long int> (total_stats.backend.bytes_out));
|
||||
|
||||
printf ("clients sent out %d requests\n",
|
||||
zmq_atomic_counter_value (g_clients_pkts_out));
|
||||
printf ("workers sent out %d replies\n",
|
||||
zmq_atomic_counter_value (g_workers_pkts_out));
|
||||
}
|
||||
TEST_ASSERT_EQUAL_UINT (
|
||||
(unsigned) zmq_atomic_counter_value (g_clients_pkts_out),
|
||||
total_stats.frontend.msg_in);
|
||||
TEST_ASSERT_EQUAL_UINT (
|
||||
(unsigned) zmq_atomic_counter_value (g_workers_pkts_out),
|
||||
total_stats.frontend.msg_out);
|
||||
TEST_ASSERT_EQUAL_UINT (
|
||||
(unsigned) zmq_atomic_counter_value (g_workers_pkts_out),
|
||||
total_stats.backend.msg_in);
|
||||
TEST_ASSERT_EQUAL_UINT (
|
||||
(unsigned) zmq_atomic_counter_value (g_clients_pkts_out),
|
||||
total_stats.backend.msg_out);
|
||||
}
|
||||
|
||||
|
||||
// The main thread simply starts several clients and a server, and then
|
||||
// waits for the server to finish.
|
||||
|
||||
void test_proxy ()
|
||||
{
|
||||
g_clients_pkts_out = zmq_atomic_counter_new ();
|
||||
g_workers_pkts_out = zmq_atomic_counter_new ();
|
||||
|
||||
// Control socket receives terminate command from main over inproc
|
||||
void *control = test_context_socket (ZMQ_PUB);
|
||||
int linger = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (control, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (control, "inproc://control"));
|
||||
|
||||
// Control socket receives terminate command from main over inproc
|
||||
void *control_proxy = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (control_proxy, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_bind (control_proxy, "inproc://control_proxy"));
|
||||
|
||||
void *threads[QT_CLIENTS + 1];
|
||||
struct thread_data databags[QT_CLIENTS + 1];
|
||||
for (int i = 0; i < QT_CLIENTS; i++) {
|
||||
databags[i].id = i;
|
||||
threads[i] = zmq_threadstart (&client_task, &databags[i]);
|
||||
}
|
||||
threads[QT_CLIENTS] = zmq_threadstart (&server_task, NULL);
|
||||
msleep (500); // Run for 500 ms then quit
|
||||
|
||||
if (is_verbose)
|
||||
printf ("stopping all clients and server workers\n");
|
||||
send_string_expect_success (control, "STOP", 0);
|
||||
|
||||
msleep (500); // Wait for all clients and workers to STOP
|
||||
|
||||
if (is_verbose)
|
||||
printf ("retrieving stats from the proxy\n");
|
||||
check_proxy_stats (control_proxy);
|
||||
|
||||
if (is_verbose)
|
||||
printf ("shutting down all clients and server workers\n");
|
||||
send_string_expect_success (control, "TERMINATE", 0);
|
||||
|
||||
if (is_verbose)
|
||||
printf ("shutting down the proxy\n");
|
||||
send_string_expect_success (control_proxy, "TERMINATE", 0);
|
||||
|
||||
test_context_socket_close (control);
|
||||
test_context_socket_close (control_proxy);
|
||||
|
||||
for (int i = 0; i < QT_CLIENTS + 1; i++)
|
||||
zmq_threadclose (threads[i]);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment (360);
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_proxy);
|
||||
return UNITY_END ();
|
||||
}
|
||||
426
tests/test_proxy_hwm.cpp
Normal file
426
tests/test_proxy_hwm.cpp
Normal file
@@ -0,0 +1,426 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
#include <string.h>
|
||||
#include <unity.h>
|
||||
#include <assert.h>
|
||||
#include <unistd.h>
|
||||
|
||||
//
|
||||
// Asynchronous proxy test using ZMQ_XPUB_NODROP and HWM:
|
||||
//
|
||||
// Topology:
|
||||
//
|
||||
// XPUB SUB
|
||||
// | |
|
||||
// \-----> XSUB -> XPUB -----/
|
||||
// ^^^^^^^^^^^^^^
|
||||
// ZMQ proxy
|
||||
//
|
||||
// All connections use "inproc" transport and have artificially-low HWMs set.
|
||||
// Then the PUB socket starts flooding the Proxy. The SUB is artificially slow
|
||||
// at receiving messages.
|
||||
// This scenario simulates what happens when a SUB is slower than
|
||||
// its (X)PUB: since ZMQ_XPUB_NODROP=1, the XPUB will block and then
|
||||
// also the (X)PUB socket will block.
|
||||
// The exact number of the messages that go through before (X)PUB blocks depends
|
||||
// on ZeroMQ internals and how the OS will schedule the different threads.
|
||||
// In the meanwhile asking statistics to the Proxy must NOT be blocking.
|
||||
//
|
||||
|
||||
|
||||
#define HWM 10
|
||||
#define NUM_BYTES_PER_MSG 50000
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
void *context;
|
||||
const char *frontend_endpoint;
|
||||
const char *backend_endpoint;
|
||||
const char *control_endpoint;
|
||||
|
||||
void *subscriber_received_all;
|
||||
} proxy_hwm_cfg_t;
|
||||
|
||||
static void lower_hwm (void *skt_)
|
||||
{
|
||||
int send_hwm = HWM;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (skt_, ZMQ_SNDHWM, &send_hwm, sizeof (send_hwm)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (skt_, ZMQ_RCVHWM, &send_hwm, sizeof (send_hwm)));
|
||||
}
|
||||
|
||||
static void publisher_thread_main (void *pvoid_)
|
||||
{
|
||||
const proxy_hwm_cfg_t *const cfg =
|
||||
static_cast<const proxy_hwm_cfg_t *> (pvoid_);
|
||||
|
||||
void *pubsocket = zmq_socket (cfg->context, ZMQ_XPUB);
|
||||
assert (pubsocket);
|
||||
|
||||
lower_hwm (pubsocket);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (pubsocket, cfg->frontend_endpoint));
|
||||
|
||||
int optval = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (pubsocket, ZMQ_XPUB_NODROP, &optval, sizeof (optval)));
|
||||
|
||||
// Wait before starting TX operations till 1 subscriber has subscribed
|
||||
// (in this test there's 1 subscriber only)
|
||||
const char subscription_to_all_topics[] = {1, 0};
|
||||
recv_string_expect_success (pubsocket, subscription_to_all_topics, 0);
|
||||
|
||||
uint64_t send_count = 0;
|
||||
while (true) {
|
||||
zmq_msg_t msg;
|
||||
int rc = zmq_msg_init_size (&msg, NUM_BYTES_PER_MSG);
|
||||
assert (rc == 0);
|
||||
|
||||
/* Fill in message content with 'AAAAAA' */
|
||||
memset (zmq_msg_data (&msg), 'A', NUM_BYTES_PER_MSG);
|
||||
|
||||
/* Send the message to the socket */
|
||||
rc = zmq_msg_send (&msg, pubsocket, ZMQ_DONTWAIT);
|
||||
if (rc != -1) {
|
||||
send_count++;
|
||||
} else {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// VERIFY EXPECTED RESULTS
|
||||
// EXPLANATION FOR TX TO BE CONSIDERED SUCCESSFUL:
|
||||
// this test has 3 threads doing I/O across 2 queues. Depending on the scheduling,
|
||||
// it might happen that 20, 30 or 40 messages go through before the pub blocks.
|
||||
// That's because the receiver thread gets kicked once every (hwm_ + 1) / 2 sent
|
||||
// messages (search for zeromq sources compute_lwm function).
|
||||
// So depending on the scheduling of the second thread, the publisher might get one,
|
||||
// two or three more batches in. The ceiling is 40 as there's 2 queues.
|
||||
//
|
||||
assert (4 * HWM >= send_count && 2 * HWM <= send_count);
|
||||
|
||||
// CLEANUP
|
||||
|
||||
zmq_close (pubsocket);
|
||||
}
|
||||
|
||||
static void subscriber_thread_main (void *pvoid_)
|
||||
{
|
||||
const proxy_hwm_cfg_t *const cfg =
|
||||
static_cast<const proxy_hwm_cfg_t *> (pvoid_);
|
||||
|
||||
void *subsocket = zmq_socket (cfg->context, ZMQ_SUB);
|
||||
assert (subsocket);
|
||||
|
||||
lower_hwm (subsocket);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (subsocket, ZMQ_SUBSCRIBE, 0, 0));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (subsocket, cfg->backend_endpoint));
|
||||
|
||||
|
||||
// receive all sent messages
|
||||
uint64_t rxsuccess = 0;
|
||||
bool success = true;
|
||||
while (success) {
|
||||
zmq_msg_t msg;
|
||||
int rc = zmq_msg_init (&msg);
|
||||
assert (rc == 0);
|
||||
|
||||
rc = zmq_msg_recv (&msg, subsocket, 0);
|
||||
if (rc != -1) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
rxsuccess++;
|
||||
|
||||
// after receiving 1st message, set a finite timeout (default is infinite)
|
||||
int timeout_ms = 100;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
subsocket, ZMQ_RCVTIMEO, &timeout_ms, sizeof (timeout_ms)));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
msleep (100);
|
||||
}
|
||||
|
||||
|
||||
// VERIFY EXPECTED RESULTS
|
||||
// EXPLANATION FOR RX TO BE CONSIDERED SUCCESSFUL:
|
||||
// see publisher thread why we have 3 possible outcomes as number of RX messages
|
||||
|
||||
assert (4 * HWM >= rxsuccess && 2 * HWM <= rxsuccess);
|
||||
|
||||
// INFORM THAT WE COMPLETED:
|
||||
|
||||
zmq_atomic_counter_inc (cfg->subscriber_received_all);
|
||||
|
||||
// CLEANUP
|
||||
|
||||
zmq_close (subsocket);
|
||||
}
|
||||
|
||||
bool recv_stat (void *sock_, bool last_, uint64_t *res_)
|
||||
{
|
||||
zmq_msg_t stats_msg;
|
||||
|
||||
int rc = zmq_msg_init (&stats_msg);
|
||||
assert (rc == 0);
|
||||
|
||||
rc = zmq_msg_recv (&stats_msg, sock_, 0); //ZMQ_DONTWAIT);
|
||||
if (rc == -1 && errno == EAGAIN) {
|
||||
rc = zmq_msg_close (&stats_msg);
|
||||
assert (rc == 0);
|
||||
return false; // cannot retrieve the stat
|
||||
}
|
||||
|
||||
assert (rc == sizeof (uint64_t));
|
||||
memcpy (res_, zmq_msg_data (&stats_msg), zmq_msg_size (&stats_msg));
|
||||
|
||||
rc = zmq_msg_close (&stats_msg);
|
||||
assert (rc == 0);
|
||||
|
||||
int more;
|
||||
size_t moresz = sizeof more;
|
||||
rc = zmq_getsockopt (sock_, ZMQ_RCVMORE, &more, &moresz);
|
||||
assert (rc == 0);
|
||||
assert ((last_ && !more) || (!last_ && more));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Utility function to interrogate the proxy:
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint64_t msg_in;
|
||||
uint64_t bytes_in;
|
||||
uint64_t msg_out;
|
||||
uint64_t bytes_out;
|
||||
} zmq_socket_stats_t;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
zmq_socket_stats_t frontend;
|
||||
zmq_socket_stats_t backend;
|
||||
} zmq_proxy_stats_t;
|
||||
|
||||
bool check_proxy_stats (void *control_proxy_)
|
||||
{
|
||||
zmq_proxy_stats_t total_stats;
|
||||
int rc;
|
||||
|
||||
rc = zmq_send (control_proxy_, "STATISTICS", 10, ZMQ_DONTWAIT);
|
||||
assert (rc == 10 || (rc == -1 && errno == EAGAIN));
|
||||
if (rc == -1 && errno == EAGAIN) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// first frame of the reply contains FRONTEND stats:
|
||||
if (!recv_stat (control_proxy_, false, &total_stats.frontend.msg_in)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
recv_stat (control_proxy_, false, &total_stats.frontend.bytes_in);
|
||||
recv_stat (control_proxy_, false, &total_stats.frontend.msg_out);
|
||||
recv_stat (control_proxy_, false, &total_stats.frontend.bytes_out);
|
||||
|
||||
// second frame of the reply contains BACKEND stats:
|
||||
recv_stat (control_proxy_, false, &total_stats.backend.msg_in);
|
||||
recv_stat (control_proxy_, false, &total_stats.backend.bytes_in);
|
||||
recv_stat (control_proxy_, false, &total_stats.backend.msg_out);
|
||||
recv_stat (control_proxy_, true, &total_stats.backend.bytes_out);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void proxy_stats_asker_thread_main (void *pvoid_)
|
||||
{
|
||||
const proxy_hwm_cfg_t *const cfg =
|
||||
static_cast<const proxy_hwm_cfg_t *> (pvoid_);
|
||||
|
||||
// CONTROL REQ
|
||||
|
||||
void *control_req =
|
||||
zmq_socket (cfg->context,
|
||||
ZMQ_REQ); // this one can be used to send command to the proxy
|
||||
assert (control_req);
|
||||
|
||||
// connect CONTROL-REQ: a socket to which send commands
|
||||
int rc = zmq_connect (control_req, cfg->control_endpoint);
|
||||
assert (rc == 0);
|
||||
|
||||
|
||||
// IMPORTANT: by setting the tx/rx timeouts, we avoid getting blocked when interrogating a proxy which is
|
||||
// itself blocked in a zmq_msg_send() on its XPUB socket having ZMQ_XPUB_NODROP=1!
|
||||
|
||||
int optval = 10;
|
||||
rc = zmq_setsockopt (control_req, ZMQ_SNDTIMEO, &optval, sizeof (optval));
|
||||
assert (rc == 0);
|
||||
rc = zmq_setsockopt (control_req, ZMQ_RCVTIMEO, &optval, sizeof (optval));
|
||||
assert (rc == 0);
|
||||
|
||||
optval = 10;
|
||||
rc =
|
||||
zmq_setsockopt (control_req, ZMQ_REQ_CORRELATE, &optval, sizeof (optval));
|
||||
assert (rc == 0);
|
||||
|
||||
rc =
|
||||
zmq_setsockopt (control_req, ZMQ_REQ_RELAXED, &optval, sizeof (optval));
|
||||
assert (rc == 0);
|
||||
|
||||
|
||||
// Start!
|
||||
|
||||
while (!zmq_atomic_counter_value (cfg->subscriber_received_all)) {
|
||||
check_proxy_stats (control_req);
|
||||
usleep (1000); // 1ms -> in best case we will get 1000updates/second
|
||||
}
|
||||
|
||||
|
||||
// Ask the proxy to exit: the subscriber has received all messages
|
||||
|
||||
rc = zmq_send (control_req, "TERMINATE", 9, 0);
|
||||
assert (rc == 9);
|
||||
|
||||
zmq_close (control_req);
|
||||
}
|
||||
|
||||
static void proxy_thread_main (void *pvoid_)
|
||||
{
|
||||
const proxy_hwm_cfg_t *const cfg =
|
||||
static_cast<const proxy_hwm_cfg_t *> (pvoid_);
|
||||
int rc;
|
||||
|
||||
// FRONTEND SUB
|
||||
|
||||
void *frontend_xsub = zmq_socket (
|
||||
cfg->context,
|
||||
ZMQ_XSUB); // the frontend is the one exposed to internal threads (INPROC)
|
||||
assert (frontend_xsub);
|
||||
|
||||
lower_hwm (frontend_xsub);
|
||||
|
||||
// bind FRONTEND
|
||||
rc = zmq_bind (frontend_xsub, cfg->frontend_endpoint);
|
||||
assert (rc == 0);
|
||||
|
||||
|
||||
// BACKEND PUB
|
||||
|
||||
void *backend_xpub = zmq_socket (
|
||||
cfg->context,
|
||||
ZMQ_XPUB); // the backend is the one exposed to the external world (TCP)
|
||||
assert (backend_xpub);
|
||||
|
||||
int optval = 1;
|
||||
rc =
|
||||
zmq_setsockopt (backend_xpub, ZMQ_XPUB_NODROP, &optval, sizeof (optval));
|
||||
assert (rc == 0);
|
||||
|
||||
lower_hwm (backend_xpub);
|
||||
|
||||
// bind BACKEND
|
||||
rc = zmq_bind (backend_xpub, cfg->backend_endpoint);
|
||||
assert (rc == 0);
|
||||
|
||||
|
||||
// CONTROL REP
|
||||
|
||||
void *control_rep = zmq_socket (
|
||||
cfg->context,
|
||||
ZMQ_REP); // this one is used by the proxy to receive&reply to commands
|
||||
assert (control_rep);
|
||||
|
||||
// bind CONTROL
|
||||
rc = zmq_bind (control_rep, cfg->control_endpoint);
|
||||
assert (rc == 0);
|
||||
|
||||
|
||||
// start proxying!
|
||||
|
||||
zmq_proxy_steerable (frontend_xsub, backend_xpub, NULL, control_rep);
|
||||
|
||||
zmq_close (frontend_xsub);
|
||||
zmq_close (backend_xpub);
|
||||
zmq_close (control_rep);
|
||||
}
|
||||
|
||||
|
||||
// The main thread simply starts several clients and a server, and then
|
||||
// waits for the server to finish.
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
void *context = zmq_ctx_new ();
|
||||
assert (context);
|
||||
|
||||
|
||||
// START ALL SECONDARY THREADS
|
||||
|
||||
proxy_hwm_cfg_t cfg;
|
||||
cfg.context = context;
|
||||
cfg.frontend_endpoint = "inproc://frontend";
|
||||
cfg.backend_endpoint = "inproc://backend";
|
||||
cfg.control_endpoint = "inproc://ctrl";
|
||||
cfg.subscriber_received_all = zmq_atomic_counter_new ();
|
||||
|
||||
void *proxy = zmq_threadstart (&proxy_thread_main, (void *) &cfg);
|
||||
assert (proxy != 0);
|
||||
void *publisher = zmq_threadstart (&publisher_thread_main, (void *) &cfg);
|
||||
assert (publisher != 0);
|
||||
void *subscriber = zmq_threadstart (&subscriber_thread_main, (void *) &cfg);
|
||||
assert (subscriber != 0);
|
||||
void *asker =
|
||||
zmq_threadstart (&proxy_stats_asker_thread_main, (void *) &cfg);
|
||||
assert (asker != 0);
|
||||
|
||||
|
||||
// CLEANUP
|
||||
|
||||
zmq_threadclose (publisher);
|
||||
zmq_threadclose (subscriber);
|
||||
zmq_threadclose (asker);
|
||||
zmq_threadclose (proxy);
|
||||
|
||||
int rc = zmq_ctx_term (context);
|
||||
assert (rc == 0);
|
||||
|
||||
zmq_atomic_counter_destroy (&cfg.subscriber_received_all);
|
||||
|
||||
return 0;
|
||||
}
|
||||
101
tests/test_proxy_single_socket.cpp
Normal file
101
tests/test_proxy_single_socket.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
// This is our server task.
|
||||
// It runs a proxy with a single REP socket as both frontend and backend.
|
||||
|
||||
void server_task (void * /*unused_*/)
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
void *rep = zmq_socket (get_test_context (), ZMQ_REP);
|
||||
TEST_ASSERT_NOT_NULL (rep);
|
||||
bind_loopback_ipv4 (rep, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
// Control socket receives terminate command from main over inproc
|
||||
void *control = zmq_socket (get_test_context (), ZMQ_REQ);
|
||||
TEST_ASSERT_NOT_NULL (control);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, "inproc://control"));
|
||||
send_string_expect_success (control, my_endpoint, 0);
|
||||
|
||||
// Use rep as both frontend and backend
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_proxy_steerable (rep, rep, NULL, control));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (rep));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));
|
||||
}
|
||||
|
||||
|
||||
// The main thread simply starts several clients and a server, and then
|
||||
// waits for the server to finish.
|
||||
void test_proxy_single_socket ()
|
||||
{
|
||||
void *server_thread = zmq_threadstart (&server_task, NULL);
|
||||
|
||||
// Control socket receives terminate command from main over inproc
|
||||
void *control = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_NOT_NULL (control);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (control, "inproc://control"));
|
||||
char *my_endpoint = s_recv (control);
|
||||
TEST_ASSERT_NOT_NULL (my_endpoint);
|
||||
|
||||
// client socket pings proxy over tcp
|
||||
void *req = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_NOT_NULL (req);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, my_endpoint));
|
||||
|
||||
send_string_expect_success (req, "msg1", 0);
|
||||
recv_string_expect_success (req, "msg1", 0);
|
||||
|
||||
send_string_expect_success (req, "msg22", 0);
|
||||
recv_string_expect_success (req, "msg22", 0);
|
||||
|
||||
send_string_expect_success (control, "TERMINATE", 0);
|
||||
|
||||
test_context_socket_close (control);
|
||||
test_context_socket_close (req);
|
||||
free (my_endpoint);
|
||||
|
||||
zmq_threadclose (server_thread);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_proxy_single_socket);
|
||||
return UNITY_END ();
|
||||
}
|
||||
116
tests/test_proxy_terminate.cpp
Normal file
116
tests/test_proxy_terminate.cpp
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
// This is a test for issue #1382. The server thread creates a SUB-PUSH
|
||||
// steerable proxy. The main process then sends messages to the SUB
|
||||
// but there is no pull on the other side, previously the proxy blocks
|
||||
// in writing to the backend, preventing the proxy from terminating
|
||||
|
||||
void server_task (void * /*unused_*/)
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
// Frontend socket talks to main process
|
||||
void *frontend = zmq_socket (get_test_context (), ZMQ_SUB);
|
||||
TEST_ASSERT_NOT_NULL (frontend);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (frontend, ZMQ_SUBSCRIBE, "", 0));
|
||||
bind_loopback_ipv4 (frontend, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
// Nice socket which is never read
|
||||
void *backend = zmq_socket (get_test_context (), ZMQ_PUSH);
|
||||
TEST_ASSERT_NOT_NULL (backend);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (backend, "tcp://127.0.0.1:*"));
|
||||
|
||||
// Control socket receives terminate command from main over inproc
|
||||
void *control = zmq_socket (get_test_context (), ZMQ_REQ);
|
||||
TEST_ASSERT_NOT_NULL (control);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (control, "inproc://control"));
|
||||
send_string_expect_success (control, my_endpoint, 0);
|
||||
|
||||
// Connect backend to frontend via a proxy
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_proxy_steerable (frontend, backend, NULL, control));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (frontend));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (backend));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (control));
|
||||
}
|
||||
|
||||
|
||||
// The main thread simply starts a basic steerable proxy server, publishes some messages, and then
|
||||
// waits for the server to terminate.
|
||||
void test_proxy_terminate ()
|
||||
{
|
||||
void *thread = zmq_threadstart (&server_task, NULL);
|
||||
|
||||
// Control socket receives terminate command from main over inproc
|
||||
void *control = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_NOT_NULL (control);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (control, "inproc://control"));
|
||||
char *my_endpoint = s_recv (control);
|
||||
TEST_ASSERT_NOT_NULL (my_endpoint);
|
||||
|
||||
msleep (500); // Run for 500 ms
|
||||
|
||||
// Start a secondary publisher which writes data to the SUB-PUSH server socket
|
||||
void *publisher = test_context_socket (ZMQ_PUB);
|
||||
TEST_ASSERT_NOT_NULL (publisher);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (publisher, my_endpoint));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
send_string_expect_success (publisher, "This is a test", 0);
|
||||
|
||||
msleep (50);
|
||||
send_string_expect_success (publisher, "This is a test", 0);
|
||||
|
||||
msleep (50);
|
||||
send_string_expect_success (publisher, "This is a test", 0);
|
||||
send_string_expect_success (control, "TERMINATE", 0);
|
||||
|
||||
test_context_socket_close (publisher);
|
||||
test_context_socket_close (control);
|
||||
free (my_endpoint);
|
||||
|
||||
zmq_threadclose (thread);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_proxy_terminate);
|
||||
return UNITY_END ();
|
||||
}
|
||||
120
tests/test_pub_invert_matching.cpp
Normal file
120
tests/test_pub_invert_matching.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test ()
|
||||
{
|
||||
// Create a publisher
|
||||
void *pub = test_context_socket (ZMQ_PUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, "inproc://soname"));
|
||||
|
||||
// Create two subscribers
|
||||
void *sub1 = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub1, "inproc://soname"));
|
||||
|
||||
void *sub2 = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub2, "inproc://soname"));
|
||||
|
||||
// Subscribe pub1 to one prefix
|
||||
// and pub2 to another prefix.
|
||||
const char prefi_x1[] = "prefix1";
|
||||
const char prefi_x2[] = "p2";
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub1, ZMQ_SUBSCRIBE, prefi_x1, strlen (prefi_x1)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub2, ZMQ_SUBSCRIBE, prefi_x2, strlen (prefi_x2)));
|
||||
|
||||
// Send a message with the first prefix
|
||||
send_string_expect_success (pub, prefi_x1, 0);
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// sub1 should receive it, but not sub2
|
||||
recv_string_expect_success (sub1, prefi_x1, ZMQ_DONTWAIT);
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (sub2, NULL, 0, ZMQ_DONTWAIT));
|
||||
|
||||
// Send a message with the second prefix
|
||||
send_string_expect_success (pub, prefi_x2, 0);
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// sub2 should receive it, but not sub1
|
||||
recv_string_expect_success (sub2, prefi_x2, ZMQ_DONTWAIT);
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (sub1, NULL, 0, ZMQ_DONTWAIT));
|
||||
|
||||
// Now invert the matching
|
||||
int invert = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (pub, ZMQ_INVERT_MATCHING, &invert, sizeof (invert)));
|
||||
|
||||
// ... on both sides, otherwise the SUB socket will filter the messages out
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub1, ZMQ_INVERT_MATCHING, &invert, sizeof (invert)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub2, ZMQ_INVERT_MATCHING, &invert, sizeof (invert)));
|
||||
|
||||
// Send a message with the first prefix
|
||||
send_string_expect_success (pub, prefi_x1, 0);
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// sub2 should receive it, but not sub1
|
||||
recv_string_expect_success (sub2, prefi_x1, ZMQ_DONTWAIT);
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (sub1, NULL, 0, ZMQ_DONTWAIT));
|
||||
|
||||
// Send a message with the second prefix
|
||||
send_string_expect_success (pub, prefi_x2, 0);
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// sub1 should receive it, but not sub2
|
||||
recv_string_expect_success (sub1, prefi_x2, ZMQ_DONTWAIT);
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (sub2, NULL, 0, ZMQ_DONTWAIT));
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (pub);
|
||||
test_context_socket_close (sub1);
|
||||
test_context_socket_close (sub2);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test);
|
||||
return UNITY_END ();
|
||||
}
|
||||
82
tests/test_pubsub.cpp
Normal file
82
tests/test_pubsub.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (c) 2007-2020 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test (const char *address)
|
||||
{
|
||||
// Create a publisher
|
||||
void *publisher = test_context_socket (ZMQ_PUB);
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
// Bind publisher
|
||||
test_bind (publisher, address, my_endpoint, MAX_SOCKET_STRING);
|
||||
|
||||
// Create a subscriber
|
||||
void *subscriber = test_context_socket (ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (subscriber, my_endpoint));
|
||||
|
||||
// Subscribe to all messages.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (subscriber, ZMQ_SUBSCRIBE, "", 0));
|
||||
|
||||
// Wait a bit till the subscription gets to the publisher
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Send an empty message
|
||||
send_string_expect_success (publisher, "test", 0);
|
||||
|
||||
// Receive the message in the subscriber
|
||||
recv_string_expect_success (subscriber, "test", 0);
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (publisher);
|
||||
test_context_socket_close (subscriber);
|
||||
}
|
||||
|
||||
void test_norm ()
|
||||
{
|
||||
#if defined ZMQ_HAVE_NORM
|
||||
test ("norm://224.1.2.3:5556");
|
||||
#else
|
||||
TEST_IGNORE_MESSAGE ("libzmq without NORM, ignoring test");
|
||||
#endif
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_norm);
|
||||
return UNITY_END ();
|
||||
}
|
||||
555
tests/test_radio_dish.cpp
Normal file
555
tests/test_radio_dish.cpp
Normal file
@@ -0,0 +1,555 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
// Helper macro to define the v4/v6 function pairs
|
||||
#define MAKE_TEST_V4V6(_test) \
|
||||
static void _test##_ipv4 () { _test (false); } \
|
||||
\
|
||||
static void _test##_ipv6 () \
|
||||
{ \
|
||||
if (!is_ipv6_available ()) { \
|
||||
TEST_IGNORE_MESSAGE ("ipv6 is not available"); \
|
||||
} \
|
||||
_test (true); \
|
||||
}
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void msg_send_expect_success (void *s_, const char *group_, const char *body_)
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
const size_t len = strlen (body_);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init_size (&msg, len));
|
||||
|
||||
memcpy (zmq_msg_data (&msg), body_, len);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_set_group (&msg, group_));
|
||||
|
||||
int rc = zmq_msg_send (&msg, s_, 0);
|
||||
TEST_ASSERT_EQUAL_INT ((int) len, rc);
|
||||
|
||||
// TODO isn't the msg closed by zmq_msg_send?
|
||||
zmq_msg_close (&msg);
|
||||
}
|
||||
|
||||
void msg_recv_cmp (void *s_, const char *group_, const char *body_)
|
||||
{
|
||||
zmq_msg_t msg;
|
||||
const size_t len = strlen (body_);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
|
||||
int recv_rc = TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, s_, 0));
|
||||
TEST_ASSERT_EQUAL_INT (len, recv_rc);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING (group_, zmq_msg_group (&msg));
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING_LEN (body_, zmq_msg_data (&msg), len);
|
||||
|
||||
zmq_msg_close (&msg);
|
||||
}
|
||||
|
||||
void test_leave_unjoined_fails ()
|
||||
{
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
// Leaving a group which we didn't join
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_leave (dish, "Movies"));
|
||||
|
||||
test_context_socket_close (dish);
|
||||
}
|
||||
|
||||
void test_long_group ()
|
||||
{
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
bind_loopback (radio, false, my_endpoint, len);
|
||||
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
// Joining to a long group, over 14 chars
|
||||
char group[19] = "0123456789ABCDEFGH";
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, group));
|
||||
|
||||
// Connecting
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dish, my_endpoint));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// This is going to be sent to the dish
|
||||
msg_send_expect_success (radio, group, "HELLO");
|
||||
|
||||
// Check the correct message arrived
|
||||
msg_recv_cmp (dish, group, "HELLO");
|
||||
|
||||
test_context_socket_close (dish);
|
||||
test_context_socket_close (radio);
|
||||
}
|
||||
|
||||
void test_join_too_long_fails ()
|
||||
{
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
// Joining too long group
|
||||
char too_long_group[ZMQ_GROUP_MAX_LENGTH + 2];
|
||||
for (int index = 0; index < ZMQ_GROUP_MAX_LENGTH + 2; index++)
|
||||
too_long_group[index] = 'A';
|
||||
too_long_group[ZMQ_GROUP_MAX_LENGTH + 1] = '\0';
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_join (dish, too_long_group));
|
||||
|
||||
test_context_socket_close (dish);
|
||||
}
|
||||
|
||||
void test_join_twice_fails ()
|
||||
{
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, "Movies"));
|
||||
|
||||
// Duplicate Joining
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL, zmq_join (dish, "Movies"));
|
||||
|
||||
test_context_socket_close (dish);
|
||||
}
|
||||
|
||||
void test_radio_dish_tcp_poll (int ipv6_)
|
||||
{
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
bind_loopback (radio, ipv6_, my_endpoint, len);
|
||||
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
// Joining
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, "Movies"));
|
||||
|
||||
// Connecting
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dish, my_endpoint));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// This is not going to be sent as dish only subscribe to "Movies"
|
||||
msg_send_expect_success (radio, "TV", "Friends");
|
||||
|
||||
// This is going to be sent to the dish
|
||||
msg_send_expect_success (radio, "Movies", "Godfather");
|
||||
|
||||
// Check the correct message arrived
|
||||
msg_recv_cmp (dish, "Movies", "Godfather");
|
||||
|
||||
// Join group during connection optvallen
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, "TV"));
|
||||
|
||||
zmq_sleep (1);
|
||||
|
||||
// This should arrive now as we joined the group
|
||||
msg_send_expect_success (radio, "TV", "Friends");
|
||||
|
||||
// Check the correct message arrived
|
||||
msg_recv_cmp (dish, "TV", "Friends");
|
||||
|
||||
// Leaving group
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_leave (dish, "TV"));
|
||||
|
||||
zmq_sleep (1);
|
||||
|
||||
// This is not going to be sent as dish only subscribe to "Movies"
|
||||
msg_send_expect_success (radio, "TV", "Friends");
|
||||
|
||||
// This is going to be sent to the dish
|
||||
msg_send_expect_success (radio, "Movies", "Godfather");
|
||||
|
||||
// test zmq_poll with dish
|
||||
zmq_pollitem_t items[] = {
|
||||
{radio, 0, ZMQ_POLLIN, 0}, // read publications
|
||||
{dish, 0, ZMQ_POLLIN, 0}, // read subscriptions
|
||||
};
|
||||
int rc = zmq_poll (items, 2, 2000);
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_POLLIN, items[1].revents);
|
||||
|
||||
// Check the correct message arrived
|
||||
msg_recv_cmp (dish, "Movies", "Godfather");
|
||||
|
||||
test_context_socket_close (dish);
|
||||
test_context_socket_close (radio);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_radio_dish_tcp_poll)
|
||||
|
||||
void test_dish_connect_fails (int ipv6_)
|
||||
{
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
const char *url = ipv6_ ? "udp://[::1]:5556" : "udp://127.0.0.1:5556";
|
||||
|
||||
// Connecting dish should fail
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOCOMPATPROTO, zmq_connect (dish, url));
|
||||
|
||||
test_context_socket_close (dish);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_dish_connect_fails)
|
||||
|
||||
void test_radio_bind_fails (int ipv6_)
|
||||
{
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
// Connecting dish should fail
|
||||
// Bind radio should fail
|
||||
TEST_ASSERT_FAILURE_ERRNO (ENOCOMPATPROTO,
|
||||
zmq_bind (radio, "udp://*:5556"));
|
||||
|
||||
test_context_socket_close (radio);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_radio_bind_fails)
|
||||
|
||||
void test_radio_dish_udp (int ipv6_)
|
||||
{
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
const char *radio_url = ipv6_ ? "udp://[::1]:5556" : "udp://127.0.0.1:5556";
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dish, "udp://*:5556"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (radio, radio_url));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, "TV"));
|
||||
|
||||
msg_send_expect_success (radio, "TV", "Friends");
|
||||
msg_recv_cmp (dish, "TV", "Friends");
|
||||
|
||||
test_context_socket_close (dish);
|
||||
test_context_socket_close (radio);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_radio_dish_udp)
|
||||
|
||||
#define MCAST_IPV4 "226.8.5.5"
|
||||
#define MCAST_IPV6 "ff02::7a65:726f:6df1:0a01"
|
||||
|
||||
static const char *mcast_url (int ipv6_)
|
||||
{
|
||||
if (ipv6_) {
|
||||
return "udp://[" MCAST_IPV6 "]:5555";
|
||||
}
|
||||
return "udp://" MCAST_IPV4 ":5555";
|
||||
}
|
||||
|
||||
// OSX uses a different name for this socket option
|
||||
#ifndef IPV6_ADD_MEMBERSHIP
|
||||
#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP
|
||||
#endif
|
||||
|
||||
union sa_u
|
||||
{
|
||||
struct sockaddr generic;
|
||||
struct sockaddr_in ipv4;
|
||||
struct sockaddr_in6 ipv6;
|
||||
};
|
||||
|
||||
// Test if multicast is available on this machine by attempting to
|
||||
// send a receive a multicast datagram
|
||||
static bool is_multicast_available (int ipv6_)
|
||||
{
|
||||
int family = ipv6_ ? AF_INET6 : AF_INET;
|
||||
fd_t bind_sock = retired_fd;
|
||||
fd_t send_sock = retired_fd;
|
||||
int port = 5555;
|
||||
bool success = false;
|
||||
const char *msg = "it works";
|
||||
char buf[32];
|
||||
union sa_u any;
|
||||
union sa_u mcast;
|
||||
socklen_t sl;
|
||||
int rc;
|
||||
|
||||
if (ipv6_) {
|
||||
struct sockaddr_in6 *any_ipv6 = &any.ipv6;
|
||||
struct sockaddr_in6 *mcast_ipv6 = &mcast.ipv6;
|
||||
|
||||
any_ipv6->sin6_family = AF_INET6;
|
||||
any_ipv6->sin6_port = htons (port);
|
||||
any_ipv6->sin6_flowinfo = 0;
|
||||
any_ipv6->sin6_scope_id = 0;
|
||||
|
||||
rc = test_inet_pton (AF_INET6, "::", &any_ipv6->sin6_addr);
|
||||
if (rc == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
*mcast_ipv6 = *any_ipv6;
|
||||
|
||||
rc = test_inet_pton (AF_INET6, MCAST_IPV6, &mcast_ipv6->sin6_addr);
|
||||
if (rc == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
sl = sizeof (*any_ipv6);
|
||||
} else {
|
||||
struct sockaddr_in *any_ipv4 = &any.ipv4;
|
||||
struct sockaddr_in *mcast_ipv4 = &mcast.ipv4;
|
||||
|
||||
any_ipv4->sin_family = AF_INET;
|
||||
any_ipv4->sin_port = htons (5555);
|
||||
|
||||
rc = test_inet_pton (AF_INET, "0.0.0.0", &any_ipv4->sin_addr);
|
||||
if (rc == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
*mcast_ipv4 = *any_ipv4;
|
||||
|
||||
rc = test_inet_pton (AF_INET, MCAST_IPV4, &mcast_ipv4->sin_addr);
|
||||
if (rc == 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
sl = sizeof (*any_ipv4);
|
||||
}
|
||||
|
||||
bind_sock = socket (family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (bind_sock < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
send_sock = socket (family, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (bind_sock < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = bind (bind_sock, &any.generic, sl);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (ipv6_) {
|
||||
struct ipv6_mreq mreq;
|
||||
const sockaddr_in6 *const mcast_ipv6 = &mcast.ipv6;
|
||||
|
||||
mreq.ipv6mr_multiaddr = mcast_ipv6->sin6_addr;
|
||||
mreq.ipv6mr_interface = 0;
|
||||
|
||||
rc = setsockopt (bind_sock, IPPROTO_IPV6, IPV6_ADD_MEMBERSHIP,
|
||||
as_setsockopt_opt_t (&mreq), sizeof (mreq));
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
int loop = 1;
|
||||
rc = setsockopt (send_sock, IPPROTO_IPV6, IPV6_MULTICAST_LOOP,
|
||||
as_setsockopt_opt_t (&loop), sizeof (loop));
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
} else {
|
||||
struct ip_mreq mreq;
|
||||
const sockaddr_in *const mcast_ipv4 = &mcast.ipv4;
|
||||
|
||||
mreq.imr_multiaddr = mcast_ipv4->sin_addr;
|
||||
mreq.imr_interface.s_addr = htonl (INADDR_ANY);
|
||||
|
||||
rc = setsockopt (bind_sock, IPPROTO_IP, IP_ADD_MEMBERSHIP,
|
||||
as_setsockopt_opt_t (&mreq), sizeof (mreq));
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
int loop = 1;
|
||||
rc = setsockopt (send_sock, IPPROTO_IP, IP_MULTICAST_LOOP,
|
||||
as_setsockopt_opt_t (&loop), sizeof (loop));
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
rc = sendto (send_sock, msg, static_cast<socklen_t> (strlen (msg)), 0,
|
||||
&mcast.generic, sl);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
rc = recvfrom (bind_sock, buf, sizeof (buf) - 1, 0, NULL, 0);
|
||||
if (rc < 0) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
buf[rc] = '\0';
|
||||
|
||||
success = (strcmp (msg, buf) == 0);
|
||||
|
||||
out:
|
||||
if (bind_sock >= 0) {
|
||||
close (bind_sock);
|
||||
}
|
||||
|
||||
if (send_sock >= 0) {
|
||||
close (send_sock);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
static void ignore_if_unavailable (int ipv6_)
|
||||
{
|
||||
if (ipv6_ && !is_ipv6_available ())
|
||||
TEST_IGNORE_MESSAGE ("No IPV6 available");
|
||||
if (!is_multicast_available (ipv6_))
|
||||
TEST_IGNORE_MESSAGE ("No multicast available");
|
||||
}
|
||||
|
||||
static void test_radio_dish_mcast (int ipv6_)
|
||||
{
|
||||
ignore_if_unavailable (ipv6_);
|
||||
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
const char *url = mcast_url (ipv6_);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dish, url));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (radio, url));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, "TV"));
|
||||
|
||||
msg_send_expect_success (radio, "TV", "Friends");
|
||||
msg_recv_cmp (dish, "TV", "Friends");
|
||||
|
||||
test_context_socket_close (dish);
|
||||
test_context_socket_close (radio);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_radio_dish_mcast)
|
||||
|
||||
static void test_radio_dish_no_loop (int ipv6_)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
TEST_IGNORE_MESSAGE (
|
||||
"ZMQ_MULTICAST_LOOP=false does not appear to work on Windows (TODO)");
|
||||
#endif
|
||||
ignore_if_unavailable (ipv6_);
|
||||
|
||||
void *radio = test_context_socket (ZMQ_RADIO);
|
||||
void *dish = test_context_socket (ZMQ_DISH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (radio, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dish, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
|
||||
// Disable multicast loop for radio
|
||||
int loop = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (radio, ZMQ_MULTICAST_LOOP, &loop, sizeof (int)));
|
||||
|
||||
const char *url = mcast_url (ipv6_);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dish, url));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (radio, url));
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_join (dish, "TV"));
|
||||
|
||||
msg_send_expect_success (radio, "TV", "Friends");
|
||||
|
||||
// Looping is disabled, we shouldn't receive anything
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (dish, NULL, 0, ZMQ_DONTWAIT));
|
||||
|
||||
test_context_socket_close (dish);
|
||||
test_context_socket_close (radio);
|
||||
}
|
||||
MAKE_TEST_V4V6 (test_radio_dish_no_loop)
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_leave_unjoined_fails);
|
||||
RUN_TEST (test_join_too_long_fails);
|
||||
RUN_TEST (test_long_group);
|
||||
RUN_TEST (test_join_twice_fails);
|
||||
RUN_TEST (test_radio_bind_fails_ipv4);
|
||||
RUN_TEST (test_radio_bind_fails_ipv6);
|
||||
RUN_TEST (test_dish_connect_fails_ipv4);
|
||||
RUN_TEST (test_dish_connect_fails_ipv6);
|
||||
RUN_TEST (test_radio_dish_tcp_poll_ipv4);
|
||||
RUN_TEST (test_radio_dish_tcp_poll_ipv6);
|
||||
RUN_TEST (test_radio_dish_udp_ipv4);
|
||||
RUN_TEST (test_radio_dish_udp_ipv6);
|
||||
|
||||
RUN_TEST (test_radio_dish_mcast_ipv4);
|
||||
RUN_TEST (test_radio_dish_no_loop_ipv4);
|
||||
|
||||
RUN_TEST (test_radio_dish_mcast_ipv6);
|
||||
RUN_TEST (test_radio_dish_no_loop_ipv6);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
69
tests/test_rebind_ipc.cpp
Normal file
69
tests/test_rebind_ipc.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_rebind_ipc ()
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
make_random_ipc_endpoint (my_endpoint);
|
||||
|
||||
void *sb0 = test_context_socket (ZMQ_PUSH);
|
||||
void *sb1 = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb0, my_endpoint));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_PULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));
|
||||
|
||||
send_string_expect_success (sb0, "42", 0);
|
||||
recv_string_expect_success (sc, "42", 0);
|
||||
|
||||
test_context_socket_close (sb0);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb1, my_endpoint));
|
||||
|
||||
send_string_expect_success (sb1, "42", 0);
|
||||
recv_string_expect_success (sc, "42", 0);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb1);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_rebind_ipc);
|
||||
return UNITY_END ();
|
||||
}
|
||||
111
tests/test_reconnect_ivl.cpp
Normal file
111
tests/test_reconnect_ivl.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*
|
||||
Copyright (c) 2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_reconnect_ivl_against_pair_socket (const char *my_endpoint_,
|
||||
void *sb_)
|
||||
{
|
||||
void *sc = test_context_socket (ZMQ_PAIR);
|
||||
int interval = -1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sc, ZMQ_RECONNECT_IVL, &interval, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_));
|
||||
|
||||
bounce (sb_, sc);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb_, my_endpoint_));
|
||||
|
||||
expect_bounce_fail (sb_, sc);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb_, my_endpoint_));
|
||||
|
||||
expect_bounce_fail (sb_, sc);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_));
|
||||
|
||||
bounce (sb_, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
}
|
||||
|
||||
#if defined(ZMQ_HAVE_IPC) && !defined(ZMQ_HAVE_GNU)
|
||||
void test_reconnect_ivl_ipc (void)
|
||||
{
|
||||
char my_endpoint[256];
|
||||
make_random_ipc_endpoint (my_endpoint);
|
||||
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, my_endpoint));
|
||||
|
||||
test_reconnect_ivl_against_pair_socket (my_endpoint, sb);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_reconnect_ivl_tcp (bind_function_t bind_function_)
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *sb = test_context_socket (ZMQ_PAIR);
|
||||
bind_function_ (sb, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
test_reconnect_ivl_against_pair_socket (my_endpoint, sb);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void test_reconnect_ivl_tcp_ipv4 ()
|
||||
{
|
||||
test_reconnect_ivl_tcp (bind_loopback_ipv4);
|
||||
}
|
||||
|
||||
void test_reconnect_ivl_tcp_ipv6 ()
|
||||
{
|
||||
if (is_ipv6_available ()) {
|
||||
zmq_ctx_set (get_test_context (), ZMQ_IPV6, 1);
|
||||
test_reconnect_ivl_tcp (bind_loopback_ipv6);
|
||||
}
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
#if defined(ZMQ_HAVE_IPC) && !defined(ZMQ_HAVE_GNU)
|
||||
RUN_TEST (test_reconnect_ivl_ipc);
|
||||
#endif
|
||||
RUN_TEST (test_reconnect_ivl_tcp_ipv4);
|
||||
RUN_TEST (test_reconnect_ivl_tcp_ipv6);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
297
tests/test_reconnect_options.cpp
Normal file
297
tests/test_reconnect_options.cpp
Normal file
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
Copyright (c) 2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <assert.h>
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
#include "testutil_monitoring.hpp"
|
||||
|
||||
#include <unity.h>
|
||||
|
||||
// test behavior with (mostly) default values
|
||||
void reconnect_default ()
|
||||
{
|
||||
// setup pub socket
|
||||
void *pub = test_context_socket (ZMQ_PUB);
|
||||
// Bind pub socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));
|
||||
|
||||
// setup sub socket
|
||||
void *sub = test_context_socket (ZMQ_SUB);
|
||||
// Monitor all events on sub
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_socket_monitor (sub, "inproc://monitor-sub", ZMQ_EVENT_ALL));
|
||||
// Create socket for collecting monitor events
|
||||
void *sub_mon = test_context_socket (ZMQ_PAIR);
|
||||
// Connect so they'll get events
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, "inproc://monitor-sub"));
|
||||
// set reconnect interval so only a single reconnect is tried
|
||||
int interval = 60 * 1000;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub, ZMQ_RECONNECT_IVL, &interval, sizeof (interval)));
|
||||
// connect to pub
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, ENDPOINT_0));
|
||||
|
||||
// confirm that we get following events
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
|
||||
|
||||
// close the pub socket
|
||||
test_context_socket_close_zero_linger (pub);
|
||||
|
||||
// confirm that we get following events
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);
|
||||
|
||||
// ZMQ_EVENT_CONNECT_RETRIED should be last event, because of timeout set above
|
||||
int event;
|
||||
char *event_address;
|
||||
int rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
|
||||
2 * 1000);
|
||||
assert (rc == -1);
|
||||
|
||||
// Close sub
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (sub);
|
||||
|
||||
// Close monitor
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (sub_mon);
|
||||
}
|
||||
|
||||
|
||||
// test successful reconnect
|
||||
void reconnect_success ()
|
||||
{
|
||||
// setup pub socket
|
||||
void *pub = test_context_socket (ZMQ_PUB);
|
||||
// Bind pub socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));
|
||||
|
||||
// setup sub socket
|
||||
void *sub = test_context_socket (ZMQ_SUB);
|
||||
// Monitor all events on sub
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_socket_monitor (sub, "inproc://monitor-sub", ZMQ_EVENT_ALL));
|
||||
// Create socket for collecting monitor events
|
||||
void *sub_mon = test_context_socket (ZMQ_PAIR);
|
||||
// Connect so they'll get events
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, "inproc://monitor-sub"));
|
||||
// set reconnect interval so only a single reconnect is tried
|
||||
int interval = 1 * 1000;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sub, ZMQ_RECONNECT_IVL, &interval, sizeof (interval)));
|
||||
// connect to pub
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, ENDPOINT_0));
|
||||
|
||||
// confirm that we get following events
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
|
||||
|
||||
// close the pub socket
|
||||
test_context_socket_close_zero_linger (pub);
|
||||
|
||||
// confirm that we get following events
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);
|
||||
|
||||
// ZMQ_EVENT_CONNECT_RETRIED should be last event, because of timeout set above
|
||||
int event;
|
||||
char *event_address;
|
||||
int rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
|
||||
SETTLE_TIME);
|
||||
assert (rc == -1);
|
||||
|
||||
// Now re-bind pub socket and wait for re-connect
|
||||
pub = test_context_socket (ZMQ_PUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// confirm that we get following events
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
|
||||
|
||||
// ZMQ_EVENT_HANDSHAKE_SUCCEEDED should be last event
|
||||
rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
|
||||
SETTLE_TIME);
|
||||
assert (rc == -1);
|
||||
|
||||
// Close sub
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (sub);
|
||||
test_context_socket_close_zero_linger (pub);
|
||||
|
||||
// Close monitor
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (sub_mon);
|
||||
}
|
||||
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
// test stopping reconnect on connection refused
|
||||
void reconnect_stop_on_refused ()
|
||||
{
|
||||
// setup pub socket
|
||||
void *pub = test_context_socket (ZMQ_PUB);
|
||||
// Bind pub socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (pub, ENDPOINT_0));
|
||||
|
||||
// setup sub socket
|
||||
void *sub = test_context_socket (ZMQ_SUB);
|
||||
// Monitor all events on sub
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_socket_monitor (sub, "inproc://monitor-sub", ZMQ_EVENT_ALL));
|
||||
// Create socket for collecting monitor events
|
||||
void *sub_mon = test_context_socket (ZMQ_PAIR);
|
||||
// Connect so they'll get events
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, "inproc://monitor-sub"));
|
||||
// set option to stop reconnecting on error
|
||||
int stopReconnectOnError = ZMQ_RECONNECT_STOP_CONN_REFUSED;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_RECONNECT_STOP,
|
||||
&stopReconnectOnError,
|
||||
sizeof (stopReconnectOnError)));
|
||||
// connect to pub
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, ENDPOINT_0));
|
||||
|
||||
// confirm that we get following events
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
|
||||
|
||||
// close the pub socket
|
||||
test_context_socket_close_zero_linger (pub);
|
||||
|
||||
// confirm that we get following events
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_RETRIED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CLOSED);
|
||||
|
||||
// ZMQ_EVENT_CLOSED should be last event, because of ZMQ_RECONNECT_STOP set above
|
||||
int event = 0;
|
||||
char *event_address;
|
||||
int rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
|
||||
2 * 1000);
|
||||
int limit = 0;
|
||||
while ((rc != -1) && (++limit < 1000)) {
|
||||
print_unexpected_event_stderr (event, rc, 0, -1);
|
||||
rc = get_monitor_event_with_timeout (sub_mon, &event, &event_address,
|
||||
2 * 1000);
|
||||
}
|
||||
|
||||
// Close sub
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (sub);
|
||||
|
||||
// Close monitor
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (sub_mon);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
// test stopping reconnect on connection refused
|
||||
void reconnect_stop_on_handshake_failed ()
|
||||
{
|
||||
char bind_address[MAX_SOCKET_STRING];
|
||||
size_t addr_length = sizeof (bind_address);
|
||||
void *dummy = test_context_socket (ZMQ_STREAM);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dummy, "tcp://127.0.0.1:0"));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (dummy, ZMQ_LAST_ENDPOINT, bind_address, &addr_length));
|
||||
|
||||
// setup sub socket
|
||||
void *sub = test_context_socket (ZMQ_SUB);
|
||||
// Monitor all events on sub
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_socket_monitor (sub, "inproc://monitor-sub", ZMQ_EVENT_ALL));
|
||||
// Create socket for collecting monitor events
|
||||
void *sub_mon = test_context_socket (ZMQ_PAIR);
|
||||
// Connect so they'll get events
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub_mon, "inproc://monitor-sub"));
|
||||
// set handshake interval (i.e., timeout) to a more reasonable value
|
||||
int handshakeInterval = 1000;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
sub, ZMQ_HANDSHAKE_IVL, &handshakeInterval, sizeof (handshakeInterval)));
|
||||
// set option to stop reconnecting on failed handshake
|
||||
int stopReconnectOnError = ZMQ_RECONNECT_STOP_HANDSHAKE_FAILED;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sub, ZMQ_RECONNECT_STOP,
|
||||
&stopReconnectOnError,
|
||||
sizeof (stopReconnectOnError)));
|
||||
// connect to dummy stream socket above
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sub, bind_address));
|
||||
|
||||
#if 1
|
||||
// ZMQ_EVENT_DISCONNECTED should be last event, because of ZMQ_RECONNECT_STOP set above
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECT_DELAYED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_CONNECTED);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL);
|
||||
expect_monitor_event (sub_mon, ZMQ_EVENT_DISCONNECTED);
|
||||
#else
|
||||
print_events (sub_mon, 2 * 1000, 1000);
|
||||
#endif
|
||||
|
||||
// Close sub
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (sub);
|
||||
test_context_socket_close_zero_linger (dummy);
|
||||
|
||||
// Close monitor
|
||||
// TODO why does this use zero_linger?
|
||||
test_context_socket_close_zero_linger (sub_mon);
|
||||
}
|
||||
#endif
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
teardown_test_context ();
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
|
||||
RUN_TEST (reconnect_default);
|
||||
RUN_TEST (reconnect_success);
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
RUN_TEST (reconnect_stop_on_refused);
|
||||
RUN_TEST (reconnect_stop_on_handshake_failed);
|
||||
#endif
|
||||
return UNITY_END ();
|
||||
}
|
||||
120
tests/test_req_correlate.cpp
Normal file
120
tests/test_req_correlate.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_req_correlate ()
|
||||
{
|
||||
void *req = test_context_socket (ZMQ_REQ);
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
int enabled = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (req, ZMQ_REQ_CORRELATE, &enabled, sizeof (int)));
|
||||
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, my_endpoint));
|
||||
|
||||
// Send a multi-part request.
|
||||
s_send_seq (req, "ABC", "DEF", SEQ_END);
|
||||
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init (&msg);
|
||||
|
||||
// Receive peer routing id
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, router, 0));
|
||||
TEST_ASSERT_GREATER_THAN_INT (0, zmq_msg_size (&msg));
|
||||
zmq_msg_t peer_id_msg;
|
||||
zmq_msg_init (&peer_id_msg);
|
||||
zmq_msg_copy (&peer_id_msg, &msg);
|
||||
|
||||
int more = 0;
|
||||
size_t more_size = sizeof (more);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_RCVMORE, &more, &more_size));
|
||||
TEST_ASSERT_TRUE (more);
|
||||
|
||||
// Receive request id 1
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, router, 0));
|
||||
TEST_ASSERT_EQUAL_UINT (sizeof (uint32_t), zmq_msg_size (&msg));
|
||||
const uint32_t req_id = *static_cast<uint32_t *> (zmq_msg_data (&msg));
|
||||
zmq_msg_t req_id_msg;
|
||||
zmq_msg_init (&req_id_msg);
|
||||
zmq_msg_copy (&req_id_msg, &msg);
|
||||
|
||||
more = 0;
|
||||
more_size = sizeof (more);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_RCVMORE, &more, &more_size));
|
||||
TEST_ASSERT_TRUE (more);
|
||||
|
||||
// Receive the rest.
|
||||
s_recv_seq (router, 0, "ABC", "DEF", SEQ_END);
|
||||
|
||||
uint32_t bad_req_id = req_id + 1;
|
||||
|
||||
// Send back a bad reply: wrong req id, 0, data
|
||||
zmq_msg_copy (&msg, &peer_id_msg);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&msg, router, ZMQ_SNDMORE));
|
||||
zmq_msg_init_data (&msg, &bad_req_id, sizeof (uint32_t), NULL, NULL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&msg, router, ZMQ_SNDMORE));
|
||||
s_send_seq (router, 0, "DATA", SEQ_END);
|
||||
|
||||
// Send back a good reply: good req id, 0, data
|
||||
zmq_msg_copy (&msg, &peer_id_msg);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&msg, router, ZMQ_SNDMORE));
|
||||
zmq_msg_copy (&msg, &req_id_msg);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_send (&msg, router, ZMQ_SNDMORE));
|
||||
s_send_seq (router, 0, "GHI", SEQ_END);
|
||||
|
||||
// Receive reply. If bad reply got through, we wouldn't see
|
||||
// this particular data.
|
||||
s_recv_seq (req, "GHI", SEQ_END);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&peer_id_msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_close (&req_id_msg));
|
||||
|
||||
test_context_socket_close_zero_linger (req);
|
||||
test_context_socket_close_zero_linger (router);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_req_correlate);
|
||||
return UNITY_END ();
|
||||
}
|
||||
233
tests/test_req_relaxed.cpp
Normal file
233
tests/test_req_relaxed.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <unity.h>
|
||||
|
||||
const size_t services = 5;
|
||||
|
||||
void *req;
|
||||
void *rep[services];
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
req = test_context_socket (ZMQ_REQ);
|
||||
|
||||
int enabled = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (req, ZMQ_REQ_RELAXED, &enabled, sizeof (int)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (req, ZMQ_REQ_CORRELATE, &enabled, sizeof (int)));
|
||||
|
||||
bind_loopback_ipv4 (req, my_endpoint, sizeof (my_endpoint));
|
||||
|
||||
for (size_t peer = 0; peer < services; peer++) {
|
||||
rep[peer] = test_context_socket (ZMQ_REP);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rep[peer], my_endpoint));
|
||||
|
||||
// These tests require strict ordering, so wait for the connections to
|
||||
// happen before opening the next, so that messages flow in the
|
||||
// expected direction
|
||||
msleep (SETTLE_TIME);
|
||||
}
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
test_context_socket_close_zero_linger (req);
|
||||
for (size_t peer = 0; peer < services; peer++)
|
||||
test_context_socket_close_zero_linger (rep[peer]);
|
||||
|
||||
teardown_test_context ();
|
||||
}
|
||||
|
||||
static void bounce (void *socket_)
|
||||
{
|
||||
int more;
|
||||
size_t more_size = sizeof (more);
|
||||
do {
|
||||
zmq_msg_t recv_part, sent_part;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&recv_part));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&recv_part, socket_, 0));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket_, ZMQ_RCVMORE, &more, &more_size));
|
||||
|
||||
zmq_msg_init (&sent_part);
|
||||
zmq_msg_copy (&sent_part, &recv_part);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_send (&sent_part, socket_, more ? ZMQ_SNDMORE : 0));
|
||||
|
||||
zmq_msg_close (&recv_part);
|
||||
} while (more);
|
||||
}
|
||||
|
||||
static int get_events (void *socket_)
|
||||
{
|
||||
int events;
|
||||
size_t events_size = sizeof (events);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket_, ZMQ_EVENTS, &events, &events_size));
|
||||
return events;
|
||||
}
|
||||
|
||||
void test_case_1 ()
|
||||
{
|
||||
// Case 1: Second send() before a reply arrives in a pipe.
|
||||
|
||||
int events = get_events (req);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_POLLOUT, events);
|
||||
|
||||
// Send a request, ensure it arrives, don't send a reply
|
||||
s_send_seq (req, "A", "B", SEQ_END);
|
||||
s_recv_seq (rep[0], "A", "B", SEQ_END);
|
||||
|
||||
events = get_events (req);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_POLLOUT, events);
|
||||
|
||||
// Send another request on the REQ socket
|
||||
s_send_seq (req, "C", "D", SEQ_END);
|
||||
s_recv_seq (rep[1], "C", "D", SEQ_END);
|
||||
|
||||
events = get_events (req);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_POLLOUT, events);
|
||||
|
||||
// Send a reply to the first request - that should be discarded by the REQ
|
||||
s_send_seq (rep[0], "WRONG", SEQ_END);
|
||||
|
||||
// Send the expected reply
|
||||
s_send_seq (rep[1], "OK", SEQ_END);
|
||||
s_recv_seq (req, "OK", SEQ_END);
|
||||
|
||||
// Another standard req-rep cycle, just to check
|
||||
s_send_seq (req, "E", SEQ_END);
|
||||
s_recv_seq (rep[2], "E", SEQ_END);
|
||||
s_send_seq (rep[2], "F", "G", SEQ_END);
|
||||
s_recv_seq (req, "F", "G", SEQ_END);
|
||||
}
|
||||
|
||||
void test_case_2 ()
|
||||
{
|
||||
// Case 2: Second send() after a reply is already in a pipe on the REQ.
|
||||
|
||||
// TODO instead of rerunning the previous test cases, only do the relevant parts (or change the peer)
|
||||
test_case_1 ();
|
||||
|
||||
// Send a request, ensure it arrives, send a reply
|
||||
s_send_seq (req, "H", SEQ_END);
|
||||
s_recv_seq (rep[3], "H", SEQ_END);
|
||||
s_send_seq (rep[3], "BAD", SEQ_END);
|
||||
|
||||
// Wait for message to be there.
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
// Without receiving that reply, send another request on the REQ socket
|
||||
s_send_seq (req, "I", SEQ_END);
|
||||
s_recv_seq (rep[4], "I", SEQ_END);
|
||||
|
||||
// Send the expected reply
|
||||
s_send_seq (rep[4], "GOOD", SEQ_END);
|
||||
s_recv_seq (req, "GOOD", SEQ_END);
|
||||
}
|
||||
|
||||
void test_case_3 ()
|
||||
{
|
||||
// Case 3: Check issue #1690. Two send() in a row should not close the
|
||||
// communication pipes. For example pipe from req to rep[0] should not be
|
||||
// closed after executing Case 1. So rep[0] should be the next to receive,
|
||||
// not rep[1].
|
||||
|
||||
// TODO instead of rerunning the previous test cases, only do the relevant parts (or change the peer)
|
||||
test_case_2 ();
|
||||
|
||||
s_send_seq (req, "J", SEQ_END);
|
||||
s_recv_seq (rep[0], "J", SEQ_END);
|
||||
}
|
||||
|
||||
void test_case_4 ()
|
||||
{
|
||||
// TODO this test case does not use the sockets from setUp
|
||||
|
||||
// Case 4: Check issue #1695. As messages may pile up before a responder
|
||||
// is available, we check that responses to messages other than the last
|
||||
// sent one are correctly discarded by the REQ pipe
|
||||
|
||||
// Setup REQ socket as client
|
||||
void *req = test_context_socket (ZMQ_REQ);
|
||||
|
||||
int enabled = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (req, ZMQ_REQ_RELAXED, &enabled, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (req, ZMQ_REQ_CORRELATE, &enabled, sizeof (int)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, ENDPOINT_0));
|
||||
|
||||
// Setup ROUTER socket as server but do not bind it just yet
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
// Send two requests
|
||||
s_send_seq (req, "TO_BE_DISCARDED", SEQ_END);
|
||||
s_send_seq (req, "TO_BE_ANSWERED", SEQ_END);
|
||||
|
||||
// Bind server allowing it to receive messages
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, ENDPOINT_0));
|
||||
|
||||
// Read the two messages and send them back as is
|
||||
bounce (router);
|
||||
bounce (router);
|
||||
|
||||
// Read the expected correlated reply. As the ZMQ_REQ_CORRELATE is active,
|
||||
// the expected answer is "TO_BE_ANSWERED", not "TO_BE_DISCARDED".
|
||||
s_recv_seq (req, "TO_BE_ANSWERED", SEQ_END);
|
||||
|
||||
test_context_socket_close_zero_linger (req);
|
||||
test_context_socket_close_zero_linger (router);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_case_1);
|
||||
RUN_TEST (test_case_2);
|
||||
RUN_TEST (test_case_3);
|
||||
RUN_TEST (test_case_4);
|
||||
return UNITY_END ();
|
||||
}
|
||||
125
tests/test_reqrep_device.cpp
Normal file
125
tests/test_reqrep_device.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_roundtrip ()
|
||||
{
|
||||
char endpoint1[MAX_SOCKET_STRING];
|
||||
char endpoint2[MAX_SOCKET_STRING];
|
||||
|
||||
// Create a req/rep device.
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
bind_loopback_ipv4 (dealer, endpoint1, sizeof (endpoint1));
|
||||
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
bind_loopback_ipv4 (router, endpoint2, sizeof (endpoint2));
|
||||
|
||||
// Create a worker.
|
||||
void *rep = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rep, endpoint1));
|
||||
|
||||
// Create a client.
|
||||
void *req = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, endpoint2));
|
||||
|
||||
// Send a request.
|
||||
send_string_expect_success (req, "ABC", ZMQ_SNDMORE);
|
||||
send_string_expect_success (req, "DEF", 0);
|
||||
|
||||
// Pass the request through the device.
|
||||
for (int i = 0; i != 4; i++) {
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, router, 0));
|
||||
int rcvmore;
|
||||
size_t sz = sizeof (rcvmore);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_send (&msg, dealer, rcvmore ? ZMQ_SNDMORE : 0));
|
||||
}
|
||||
|
||||
// Receive the request.
|
||||
recv_string_expect_success (rep, "ABC", 0);
|
||||
int rcvmore;
|
||||
size_t sz = sizeof (rcvmore);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (rep, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_TRUE (rcvmore);
|
||||
recv_string_expect_success (rep, "DEF", 0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (rep, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_FALSE (rcvmore);
|
||||
|
||||
// Send the reply.
|
||||
send_string_expect_success (rep, "GHI", ZMQ_SNDMORE);
|
||||
send_string_expect_success (rep, "JKL", 0);
|
||||
|
||||
// Pass the reply through the device.
|
||||
for (int i = 0; i != 4; i++) {
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, dealer, 0));
|
||||
int rcvmore;
|
||||
size_t sz = sizeof (rcvmore);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (dealer, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_send (&msg, router, rcvmore ? ZMQ_SNDMORE : 0));
|
||||
}
|
||||
|
||||
// Receive the reply.
|
||||
recv_string_expect_success (req, "GHI", 0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (req, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_TRUE (rcvmore);
|
||||
recv_string_expect_success (req, "JKL", 0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (req, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_FALSE (rcvmore);
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (req);
|
||||
test_context_socket_close (rep);
|
||||
test_context_socket_close (router);
|
||||
test_context_socket_close (dealer);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_roundtrip);
|
||||
return UNITY_END ();
|
||||
}
|
||||
125
tests/test_reqrep_device_tipc.cpp
Normal file
125
tests/test_reqrep_device_tipc.cpp
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
// TODO this is heavily duplicated with test_reqrep_device.cpp
|
||||
void test_roundtrip ()
|
||||
{
|
||||
// Create a req/rep device.
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (dealer, "tipc://{5560,0,0}"));
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, "tipc://{5561,0,0}"));
|
||||
|
||||
// Create a worker.
|
||||
void *rep = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (rep, "tipc://{5560,0}@0.0.0"));
|
||||
|
||||
// Create a client.
|
||||
void *req = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (req, "tipc://{5561,0}@0.0.0"));
|
||||
|
||||
// Send a request.
|
||||
send_string_expect_success (req, "ABC", ZMQ_SNDMORE);
|
||||
send_string_expect_success (req, "DEF", 0);
|
||||
|
||||
// Pass the request through the device.
|
||||
for (int i = 0; i != 4; i++) {
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, router, 0));
|
||||
int rcvmore;
|
||||
size_t sz = sizeof (rcvmore);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_send (&msg, dealer, rcvmore ? ZMQ_SNDMORE : 0));
|
||||
}
|
||||
|
||||
// Receive the request.
|
||||
recv_string_expect_success (rep, "ABC", 0);
|
||||
int rcvmore;
|
||||
size_t sz = sizeof (rcvmore);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (rep, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_TRUE (rcvmore);
|
||||
recv_string_expect_success (rep, "DEF", 0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (rep, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_FALSE (rcvmore);
|
||||
|
||||
// Send the reply.
|
||||
send_string_expect_success (rep, "GHI", ZMQ_SNDMORE);
|
||||
send_string_expect_success (rep, "JKL", 0);
|
||||
|
||||
// Pass the reply through the device.
|
||||
for (int i = 0; i != 4; i++) {
|
||||
zmq_msg_t msg;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_init (&msg));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_msg_recv (&msg, dealer, 0));
|
||||
int rcvmore;
|
||||
size_t sz = sizeof (rcvmore);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (dealer, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_msg_send (&msg, router, rcvmore ? ZMQ_SNDMORE : 0));
|
||||
}
|
||||
|
||||
// Receive the reply.
|
||||
recv_string_expect_success (req, "GHI", 0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (req, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_TRUE (rcvmore);
|
||||
recv_string_expect_success (req, "JKL", 0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (req, ZMQ_RCVMORE, &rcvmore, &sz));
|
||||
TEST_ASSERT_FALSE (rcvmore);
|
||||
|
||||
// Clean up.
|
||||
test_context_socket_close (req);
|
||||
test_context_socket_close (rep);
|
||||
test_context_socket_close (router);
|
||||
test_context_socket_close (dealer);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
if (!is_tipc_available ()) {
|
||||
printf ("TIPC environment unavailable, skipping test\n");
|
||||
return 77;
|
||||
}
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_roundtrip);
|
||||
return UNITY_END ();
|
||||
}
|
||||
56
tests/test_reqrep_inproc.cpp
Normal file
56
tests/test_reqrep_inproc.cpp
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_roundtrip ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "inproc://a"));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "inproc://a"));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_roundtrip);
|
||||
return UNITY_END ();
|
||||
}
|
||||
86
tests/test_reqrep_ipc.cpp
Normal file
86
tests/test_reqrep_ipc.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_leak ()
|
||||
{
|
||||
char my_endpoint[256];
|
||||
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
bind_loopback_ipc (sb, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));
|
||||
|
||||
static const char leakymsg[] = "leakymsg";
|
||||
send_string_expect_success (sc, leakymsg, 0);
|
||||
|
||||
char *buf = s_recv (sb);
|
||||
free (buf);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
|
||||
msleep (SETTLE_TIME);
|
||||
|
||||
send_string_expect_success (sb, leakymsg, 0);
|
||||
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void test_simple (void)
|
||||
{
|
||||
char my_endpoint[256];
|
||||
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
bind_loopback_ipc (sb, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_simple);
|
||||
RUN_TEST (test_leak);
|
||||
return UNITY_END ();
|
||||
}
|
||||
220
tests/test_reqrep_tcp.cpp
Normal file
220
tests/test_reqrep_tcp.cpp
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_single_connect (int ipv6_)
|
||||
{
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
bind_loopback (sb, ipv6_, my_endpoint, len);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sc, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
// the sockets are disconnected and unbound explicitly in this test case
|
||||
// to check that this can be done successfully with the expected
|
||||
// endpoints/addresses
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, my_endpoint));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb, my_endpoint));
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
void make_connect_address (char *connect_address_,
|
||||
const int ipv6_,
|
||||
const int port_,
|
||||
const char *bind_address_)
|
||||
{
|
||||
sprintf (connect_address_, "tcp://%s:%i;%s", ipv6_ ? "[::1]" : "127.0.0.1",
|
||||
port_, strrchr (bind_address_, '/') + 1);
|
||||
}
|
||||
|
||||
void test_multi_connect (int ipv6_)
|
||||
{
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint_0[MAX_SOCKET_STRING];
|
||||
char my_endpoint_1[MAX_SOCKET_STRING];
|
||||
char my_endpoint_2[MAX_SOCKET_STRING];
|
||||
char my_endpoint_3[MAX_SOCKET_STRING * 2];
|
||||
|
||||
void *sb0 = test_context_socket (ZMQ_REP);
|
||||
bind_loopback (sb0, ipv6_, my_endpoint_0, len);
|
||||
|
||||
void *sb1 = test_context_socket (ZMQ_REP);
|
||||
bind_loopback (sb1, ipv6_, my_endpoint_1, len);
|
||||
|
||||
void *sb2 = test_context_socket (ZMQ_REP);
|
||||
bind_loopback (sb2, ipv6_, my_endpoint_2, len);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sc, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_1));
|
||||
make_connect_address (my_endpoint_3, ipv6_, 5564, my_endpoint_2);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, my_endpoint_3));
|
||||
|
||||
bounce (sb0, sc);
|
||||
bounce (sb1, sc);
|
||||
bounce (sb2, sc);
|
||||
bounce (sb0, sc);
|
||||
bounce (sb1, sc);
|
||||
bounce (sb2, sc);
|
||||
bounce (sb0, sc);
|
||||
|
||||
/// see comment on zmq_disconnect/zmq_unbind in test_single_connect
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, my_endpoint_0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, my_endpoint_3));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc, my_endpoint_1));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb0, my_endpoint_0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb1, my_endpoint_1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb2, my_endpoint_2));
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb0);
|
||||
test_context_socket_close (sb1);
|
||||
test_context_socket_close (sb2);
|
||||
}
|
||||
|
||||
void test_multi_connect_same_port (int ipv6_)
|
||||
{
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint_0[MAX_SOCKET_STRING];
|
||||
char my_endpoint_1[MAX_SOCKET_STRING];
|
||||
char my_endpoint_2[MAX_SOCKET_STRING * 2];
|
||||
char my_endpoint_3[MAX_SOCKET_STRING * 2];
|
||||
char my_endpoint_4[MAX_SOCKET_STRING * 2];
|
||||
char my_endpoint_5[MAX_SOCKET_STRING * 2];
|
||||
|
||||
void *sb0 = test_context_socket (ZMQ_REP);
|
||||
bind_loopback (sb0, ipv6_, my_endpoint_0, len);
|
||||
|
||||
void *sb1 = test_context_socket (ZMQ_REP);
|
||||
bind_loopback (sb1, ipv6_, my_endpoint_1, len);
|
||||
|
||||
void *sc0 = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sc0, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
make_connect_address (my_endpoint_2, ipv6_, 5564, my_endpoint_0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc0, my_endpoint_2));
|
||||
make_connect_address (my_endpoint_3, ipv6_, 5565, my_endpoint_1);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc0, my_endpoint_3));
|
||||
|
||||
void *sc1 = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (sc1, ZMQ_IPV6, &ipv6_, sizeof (int)));
|
||||
make_connect_address (my_endpoint_4, ipv6_, 5565, my_endpoint_0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc1, my_endpoint_4));
|
||||
make_connect_address (my_endpoint_5, ipv6_, 5564, my_endpoint_1);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc1, my_endpoint_5));
|
||||
|
||||
bounce (sb0, sc0);
|
||||
bounce (sb1, sc0);
|
||||
bounce (sb0, sc1);
|
||||
bounce (sb1, sc1);
|
||||
bounce (sb0, sc0);
|
||||
bounce (sb1, sc0);
|
||||
|
||||
/// see comment on zmq_disconnect/zmq_unbind in test_single_connect
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc1, my_endpoint_4));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc1, my_endpoint_5));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc0, my_endpoint_2));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (sc0, my_endpoint_3));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb0, my_endpoint_0));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_unbind (sb1, my_endpoint_1));
|
||||
|
||||
test_context_socket_close (sc0);
|
||||
test_context_socket_close (sc1);
|
||||
test_context_socket_close (sb0);
|
||||
test_context_socket_close (sb1);
|
||||
}
|
||||
|
||||
void test_single_connect_ipv4 ()
|
||||
{
|
||||
test_single_connect (false);
|
||||
}
|
||||
|
||||
void test_multi_connect_ipv4 ()
|
||||
{
|
||||
test_multi_connect (false);
|
||||
}
|
||||
|
||||
void test_multi_connect_same_port_ipv4 ()
|
||||
{
|
||||
test_multi_connect_same_port (false);
|
||||
}
|
||||
|
||||
void test_single_connect_ipv6 ()
|
||||
{
|
||||
test_single_connect (true);
|
||||
}
|
||||
|
||||
void test_multi_connect_ipv6 ()
|
||||
{
|
||||
test_multi_connect (true);
|
||||
}
|
||||
|
||||
void test_multi_connect_same_port_ipv6 ()
|
||||
{
|
||||
test_multi_connect_same_port (true);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_single_connect_ipv4);
|
||||
RUN_TEST (test_multi_connect_ipv4);
|
||||
RUN_TEST (test_multi_connect_same_port_ipv4);
|
||||
RUN_TEST (test_single_connect_ipv6);
|
||||
RUN_TEST (test_multi_connect_ipv6);
|
||||
RUN_TEST (test_multi_connect_same_port_ipv6);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
60
tests/test_reqrep_tipc.cpp
Normal file
60
tests/test_reqrep_tipc.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_roundtrip ()
|
||||
{
|
||||
void *sb = test_context_socket (ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, "tipc://{5560,0,0}"));
|
||||
|
||||
void *sc = test_context_socket (ZMQ_REQ);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, "tipc://{5560,0}@0.0.0"));
|
||||
|
||||
bounce (sb, sc);
|
||||
|
||||
test_context_socket_close (sc);
|
||||
test_context_socket_close (sb);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
if (!is_tipc_available ()) {
|
||||
printf ("TIPC environment unavailable, skipping test\n");
|
||||
return 77;
|
||||
}
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_roundtrip);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
67
tests/test_reqrep_vmci.cpp
Normal file
67
tests/test_reqrep_vmci.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <vmci_sockets.h>
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_reqrep_vmci ()
|
||||
{
|
||||
std::stringstream s;
|
||||
s << "vmci://" << VMCISock_GetLocalCID () << ":" << 5560;
|
||||
std::string endpoint = s.str ();
|
||||
|
||||
void *sb = test_context_socket (ZMQ_DEALER);
|
||||
int rc = zmq_bind (sb, endpoint.c_str ());
|
||||
if (rc < 0 && errno == EAFNOSUPPORT)
|
||||
TEST_IGNORE_MESSAGE ("VMCI not supported");
|
||||
TEST_ASSERT_SUCCESS_ERRNO (rc);
|
||||
|
||||
void *sc = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint.c_str ()));
|
||||
|
||||
expect_bounce_fail (sb, sc);
|
||||
|
||||
test_context_socket_close_zero_linger (sc);
|
||||
test_context_socket_close_zero_linger (sb);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_reqrep_vmci);
|
||||
return UNITY_END ();
|
||||
}
|
||||
155
tests/test_router_handover.cpp
Normal file
155
tests/test_router_handover.cpp
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_with_handover ()
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
// Enable the handover flag
|
||||
int handover = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_HANDOVER,
|
||||
&handover, sizeof (handover)));
|
||||
|
||||
// Create dealer called "X" and connect it to our router
|
||||
void *dealer_one = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer_one, ZMQ_ROUTING_ID, "X", 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer_one, my_endpoint));
|
||||
|
||||
// Get message from dealer to know when connection is ready
|
||||
char buffer[255];
|
||||
send_string_expect_success (dealer_one, "Hello", 0);
|
||||
|
||||
recv_string_expect_success (router, "X", 0);
|
||||
recv_string_expect_success (router, "Hello", 0);
|
||||
|
||||
// Now create a second dealer that uses the same routing id
|
||||
void *dealer_two = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer_two, ZMQ_ROUTING_ID, "X", 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer_two, my_endpoint));
|
||||
|
||||
// Get message from dealer to know when connection is ready
|
||||
send_string_expect_success (dealer_two, "Hello", 0);
|
||||
|
||||
recv_string_expect_success (router, "X", 0);
|
||||
recv_string_expect_success (router, "Hello", 0);
|
||||
|
||||
// Send a message to 'X' routing id. This should be delivered
|
||||
// to the second dealer, instead of the first because of the handover.
|
||||
send_string_expect_success (router, "X", ZMQ_SNDMORE);
|
||||
send_string_expect_success (router, "Hello", 0);
|
||||
|
||||
// Ensure that the first dealer doesn't receive the message
|
||||
// but the second one does
|
||||
const int timeout = SETTLE_TIME;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer_one, ZMQ_RCVTIMEO, &timeout, sizeof timeout));
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (dealer_one, buffer, 255, 0));
|
||||
|
||||
recv_string_expect_success (dealer_two, "Hello", 0);
|
||||
|
||||
test_context_socket_close (router);
|
||||
test_context_socket_close (dealer_one);
|
||||
test_context_socket_close (dealer_two);
|
||||
}
|
||||
|
||||
void test_without_handover ()
|
||||
{
|
||||
size_t len = MAX_SOCKET_STRING;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, "tcp://127.0.0.1:*"));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_LAST_ENDPOINT, my_endpoint, &len));
|
||||
|
||||
// Create dealer called "X" and connect it to our router
|
||||
void *dealer_one = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer_one, ZMQ_ROUTING_ID, "X", 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer_one, my_endpoint));
|
||||
|
||||
// Get message from dealer to know when connection is ready
|
||||
char buffer[255];
|
||||
send_string_expect_success (dealer_one, "Hello", 0);
|
||||
|
||||
recv_string_expect_success (router, "X", 0);
|
||||
recv_string_expect_success (router, "Hello", 0);
|
||||
|
||||
// Now create a second dealer that uses the same routing id
|
||||
void *dealer_two = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer_two, ZMQ_ROUTING_ID, "X", 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer_two, my_endpoint));
|
||||
|
||||
// Send message from second dealer
|
||||
send_string_expect_success (dealer_two, "Hello", 0);
|
||||
|
||||
// This should be ignored by the router
|
||||
const int timeout = SETTLE_TIME;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (router, ZMQ_RCVTIMEO, &timeout, sizeof timeout));
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (router, buffer, 255, 0));
|
||||
|
||||
// Send a message to 'X' routing id. This should be delivered
|
||||
// to the second dealer, instead of the first because of the handover.
|
||||
send_string_expect_success (router, "X", ZMQ_SNDMORE);
|
||||
send_string_expect_success (router, "Hello", 0);
|
||||
|
||||
// Ensure that the second dealer doesn't receive the message
|
||||
// but the first one does
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer_two, ZMQ_RCVTIMEO, &timeout, sizeof timeout));
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (dealer_two, buffer, 255, 0));
|
||||
|
||||
recv_string_expect_success (dealer_one, "Hello", 0);
|
||||
|
||||
test_context_socket_close (router);
|
||||
test_context_socket_close (dealer_one);
|
||||
test_context_socket_close (dealer_two);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_with_handover);
|
||||
RUN_TEST (test_without_handover);
|
||||
return UNITY_END ();
|
||||
}
|
||||
233
tests/test_router_mandatory.cpp
Normal file
233
tests/test_router_mandatory.cpp
Normal file
@@ -0,0 +1,233 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
bool send_msg_to_peer_if_ready (void *router_, const char *peer_routing_id_)
|
||||
{
|
||||
int rc = TEST_ASSERT_SUCCESS_MESSAGE_ERRNO (
|
||||
zmq_socket_get_peer_state (router_, peer_routing_id_, 1),
|
||||
peer_routing_id_);
|
||||
if (rc & ZMQ_POLLOUT) {
|
||||
send_string_expect_success (router_, peer_routing_id_,
|
||||
ZMQ_SNDMORE | ZMQ_DONTWAIT);
|
||||
send_string_expect_success (router_, "Hello", ZMQ_DONTWAIT);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_get_peer_state ()
|
||||
{
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
int mandatory = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY,
|
||||
&mandatory, sizeof (mandatory)));
|
||||
|
||||
const char *my_endpoint = "inproc://test_get_peer_state";
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (router, my_endpoint));
|
||||
|
||||
void *dealer1 = test_context_socket (ZMQ_DEALER);
|
||||
void *dealer2 = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
// Lower HWMs to allow doing the test with fewer messages
|
||||
const int hwm = 100;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (router, ZMQ_SNDHWM, &hwm, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer1, ZMQ_RCVHWM, &hwm, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer2, ZMQ_RCVHWM, &hwm, sizeof (int)));
|
||||
|
||||
const char *dealer1_routing_id = "X";
|
||||
const char *dealer2_routing_id = "Y";
|
||||
|
||||
// Name dealer1 "X" and connect it to our router
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer1, ZMQ_ROUTING_ID, dealer1_routing_id, 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer1, my_endpoint));
|
||||
|
||||
// Name dealer2 "Y" and connect it to our router
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer2, ZMQ_ROUTING_ID, dealer2_routing_id, 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer2, my_endpoint));
|
||||
|
||||
// Get message from both dealers to know when connection is ready
|
||||
send_string_expect_success (dealer1, "Hello", 0);
|
||||
recv_string_expect_success (router, dealer1_routing_id, 0);
|
||||
recv_string_expect_success (router, "Hello", 0);
|
||||
|
||||
send_string_expect_success (dealer2, "Hello", 0);
|
||||
recv_string_expect_success (router, dealer2_routing_id, 0);
|
||||
recv_string_expect_success (router, "Hello", 0);
|
||||
|
||||
void *poller = zmq_poller_new ();
|
||||
TEST_ASSERT_NOT_NULL (poller);
|
||||
|
||||
// Poll on router and dealer1, but not on dealer2
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller, router, NULL, ZMQ_POLLOUT));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_add (poller, dealer1, NULL, ZMQ_POLLIN));
|
||||
|
||||
const unsigned int count = 10000;
|
||||
const unsigned int event_size = 2;
|
||||
bool dealer2_blocked = false;
|
||||
unsigned int dealer1_sent = 0, dealer2_sent = 0, dealer1_received = 0;
|
||||
zmq_poller_event_t events[event_size];
|
||||
for (unsigned int iteration = 0; iteration < count; ++iteration) {
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_poller_wait_all (poller, events, event_size, -1));
|
||||
for (unsigned int event_no = 0; event_no < event_size; ++event_no) {
|
||||
const zmq_poller_event_t ¤t_event = events[event_no];
|
||||
if (current_event.socket == router
|
||||
&& current_event.events & ZMQ_POLLOUT) {
|
||||
if (send_msg_to_peer_if_ready (router, dealer1_routing_id))
|
||||
++dealer1_sent;
|
||||
|
||||
if (send_msg_to_peer_if_ready (router, dealer2_routing_id))
|
||||
++dealer2_sent;
|
||||
else
|
||||
dealer2_blocked = true;
|
||||
}
|
||||
if (current_event.socket == dealer1
|
||||
&& current_event.events & ZMQ_POLLIN) {
|
||||
recv_string_expect_success (dealer1, "Hello", ZMQ_DONTWAIT);
|
||||
int more;
|
||||
size_t more_size = sizeof (more);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (dealer1, ZMQ_RCVMORE, &more, &more_size));
|
||||
TEST_ASSERT_FALSE (more);
|
||||
|
||||
++dealer1_received;
|
||||
}
|
||||
// never read from dealer2, so its pipe becomes full eventually
|
||||
}
|
||||
}
|
||||
printf ("dealer1_sent = %u, dealer2_sent = %u, dealer1_received = %u\n",
|
||||
dealer1_sent, dealer2_sent, dealer1_received);
|
||||
TEST_ASSERT_TRUE (dealer2_blocked);
|
||||
zmq_poller_destroy (&poller);
|
||||
|
||||
test_context_socket_close (router);
|
||||
test_context_socket_close (dealer1);
|
||||
test_context_socket_close (dealer2);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_get_peer_state_corner_cases ()
|
||||
{
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
const char peer_routing_id[] = "foo";
|
||||
|
||||
// call get_peer_state with NULL socket
|
||||
int rc = zmq_socket_get_peer_state (NULL, peer_routing_id,
|
||||
strlen (peer_routing_id));
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno);
|
||||
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
// call get_peer_state with a non-ROUTER socket
|
||||
rc = zmq_socket_get_peer_state (dealer, peer_routing_id,
|
||||
strlen (peer_routing_id));
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSUP, errno);
|
||||
|
||||
// call get_peer_state for an unknown routing id
|
||||
rc = zmq_socket_get_peer_state (router, peer_routing_id,
|
||||
strlen (peer_routing_id));
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (EHOSTUNREACH, errno);
|
||||
|
||||
test_context_socket_close (router);
|
||||
test_context_socket_close (dealer);
|
||||
#endif
|
||||
}
|
||||
|
||||
void test_basic ()
|
||||
{
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
// Send a message to an unknown peer with the default setting
|
||||
// This will not report any error
|
||||
send_string_expect_success (router, "UNKNOWN", ZMQ_SNDMORE);
|
||||
send_string_expect_success (router, "DATA", 0);
|
||||
|
||||
// Send a message to an unknown peer with mandatory routing
|
||||
// This will fail
|
||||
int mandatory = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY,
|
||||
&mandatory, sizeof (mandatory)));
|
||||
int rc = zmq_send (router, "UNKNOWN", 7, ZMQ_SNDMORE);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (EHOSTUNREACH, errno);
|
||||
|
||||
// Create dealer called "X" and connect it to our router
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (dealer, ZMQ_ROUTING_ID, "X", 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));
|
||||
|
||||
// Get message from dealer to know when connection is ready
|
||||
send_string_expect_success (dealer, "Hello", 0);
|
||||
recv_string_expect_success (router, "X", 0);
|
||||
|
||||
// Send a message to connected dealer now
|
||||
// It should work
|
||||
send_string_expect_success (router, "X", ZMQ_SNDMORE);
|
||||
send_string_expect_success (router, "Hello", 0);
|
||||
|
||||
test_context_socket_close (router);
|
||||
test_context_socket_close (dealer);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_basic);
|
||||
RUN_TEST (test_get_peer_state);
|
||||
RUN_TEST (test_get_peer_state_corner_cases);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
120
tests/test_router_mandatory_hwm.cpp
Normal file
120
tests/test_router_mandatory_hwm.cpp
Normal file
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
// DEBUG shouldn't be defined in sources as it will cause a redefined symbol
|
||||
// error when it is defined in the build configuration. It appears that the
|
||||
// intent here is to semi-permanently disable DEBUG tracing statements, so the
|
||||
// implementation is changed to accommodate that intent.
|
||||
//#define DEBUG 0
|
||||
#define TRACE_ENABLED 0
|
||||
|
||||
void test_router_mandatory_hwm ()
|
||||
{
|
||||
if (TRACE_ENABLED)
|
||||
fprintf (stderr, "Staring router mandatory HWM test ...\n");
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
// Configure router socket to mandatory routing and set HWM and linger
|
||||
int mandatory = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (router, ZMQ_ROUTER_MANDATORY,
|
||||
&mandatory, sizeof (mandatory)));
|
||||
int sndhwm = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (router, ZMQ_SNDHWM, &sndhwm, sizeof (sndhwm)));
|
||||
int linger = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (router, ZMQ_LINGER, &linger, sizeof (linger)));
|
||||
|
||||
bind_loopback_ipv4 (router, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
// Create dealer called "X" and connect it to our router, configure HWM
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (dealer, ZMQ_ROUTING_ID, "X", 1));
|
||||
int rcvhwm = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer, ZMQ_RCVHWM, &rcvhwm, sizeof (rcvhwm)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, my_endpoint));
|
||||
|
||||
// Get message from dealer to know when connection is ready
|
||||
send_string_expect_success (dealer, "Hello", 0);
|
||||
recv_string_expect_success (router, "X", 0);
|
||||
|
||||
int i;
|
||||
const int buf_size = 65536;
|
||||
const uint8_t buf[buf_size] = {0};
|
||||
// Send first batch of messages
|
||||
for (i = 0; i < 100000; ++i) {
|
||||
if (TRACE_ENABLED)
|
||||
fprintf (stderr, "Sending message %d ...\n", i);
|
||||
const int rc = zmq_send (router, "X", 1, ZMQ_DONTWAIT | ZMQ_SNDMORE);
|
||||
if (rc == -1 && zmq_errno () == EAGAIN)
|
||||
break;
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
send_array_expect_success (router, buf, ZMQ_DONTWAIT);
|
||||
}
|
||||
// This should fail after one message but kernel buffering could
|
||||
// skew results
|
||||
TEST_ASSERT_LESS_THAN_INT (10, i);
|
||||
msleep (1000);
|
||||
// Send second batch of messages
|
||||
for (; i < 100000; ++i) {
|
||||
if (TRACE_ENABLED)
|
||||
fprintf (stderr, "Sending message %d (part 2) ...\n", i);
|
||||
const int rc = zmq_send (router, "X", 1, ZMQ_DONTWAIT | ZMQ_SNDMORE);
|
||||
if (rc == -1 && zmq_errno () == EAGAIN)
|
||||
break;
|
||||
TEST_ASSERT_EQUAL_INT (1, rc);
|
||||
send_array_expect_success (router, buf, ZMQ_DONTWAIT);
|
||||
}
|
||||
// This should fail after two messages but kernel buffering could
|
||||
// skew results
|
||||
TEST_ASSERT_LESS_THAN_INT (20, i);
|
||||
|
||||
if (TRACE_ENABLED)
|
||||
fprintf (stderr, "Done sending messages.\n");
|
||||
|
||||
test_context_socket_close (router);
|
||||
test_context_socket_close (dealer);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_router_mandatory_hwm);
|
||||
return UNITY_END ();
|
||||
}
|
||||
70
tests/test_router_mandatory_tipc.cpp
Normal file
70
tests/test_router_mandatory_tipc.cpp
Normal file
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include "testutil.hpp"
|
||||
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_router_mandatory_tipc ()
|
||||
{
|
||||
if (!is_tipc_available ()) {
|
||||
TEST_IGNORE_MESSAGE ("TIPC environment unavailable, skipping test");
|
||||
}
|
||||
|
||||
// Creating the first socket.
|
||||
void *sa = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sa, "tipc://{15560,0,0}"));
|
||||
|
||||
// Sending a message to an unknown peer with the default setting
|
||||
send_string_expect_success (sa, "UNKNOWN", ZMQ_SNDMORE);
|
||||
send_string_expect_success (sa, "DATA", 0);
|
||||
|
||||
int mandatory = 1;
|
||||
|
||||
// Set mandatory routing on socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (sa, ZMQ_ROUTER_MANDATORY,
|
||||
&mandatory, sizeof (mandatory)));
|
||||
|
||||
// Send a message and check that it fails
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EHOSTUNREACH, zmq_send (sa, "UNKNOWN", 7, ZMQ_SNDMORE | ZMQ_DONTWAIT));
|
||||
|
||||
test_context_socket_close (sa);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_router_mandatory_tipc);
|
||||
return UNITY_END ();
|
||||
}
|
||||
322
tests/test_router_notify.cpp
Normal file
322
tests/test_router_notify.cpp
Normal file
@@ -0,0 +1,322 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_sockopt_router_notify ()
|
||||
{
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
int opt_notify;
|
||||
|
||||
int opt_notify_read;
|
||||
size_t opt_notify_read_size = sizeof (opt_notify_read);
|
||||
|
||||
|
||||
// default value is off when socket is constructed
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
|
||||
|
||||
TEST_ASSERT_EQUAL (0, opt_notify_read);
|
||||
|
||||
|
||||
// valid value - Connect
|
||||
opt_notify = ZMQ_NOTIFY_CONNECT;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
|
||||
|
||||
TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
|
||||
|
||||
|
||||
// valid value - Disconnect
|
||||
opt_notify = ZMQ_NOTIFY_DISCONNECT;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
|
||||
|
||||
TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
|
||||
|
||||
|
||||
// valid value - Off
|
||||
opt_notify = 0;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
|
||||
|
||||
TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
|
||||
|
||||
|
||||
// valid value - Both
|
||||
opt_notify = ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
|
||||
|
||||
TEST_ASSERT_EQUAL (opt_notify, opt_notify_read);
|
||||
|
||||
|
||||
// value boundary
|
||||
opt_notify = -1;
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_setsockopt (router, ZMQ_ROUTER_NOTIFY, &opt_notify,
|
||||
sizeof (opt_notify)));
|
||||
|
||||
opt_notify = (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT) + 1;
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_setsockopt (router, ZMQ_ROUTER_NOTIFY, &opt_notify,
|
||||
sizeof (opt_notify)));
|
||||
|
||||
// failures don't update the value
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
|
||||
|
||||
TEST_ASSERT_EQUAL (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT,
|
||||
opt_notify_read);
|
||||
|
||||
|
||||
test_context_socket_close (router);
|
||||
|
||||
|
||||
// check a non-router socket type
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
// setsockopt fails for non-router sockets
|
||||
opt_notify = ZMQ_NOTIFY_CONNECT;
|
||||
TEST_ASSERT_FAILURE_ERRNO (
|
||||
EINVAL, zmq_setsockopt (dealer, ZMQ_ROUTER_NOTIFY, &opt_notify,
|
||||
sizeof (opt_notify)));
|
||||
|
||||
// getsockopts returns off for any non-router socket
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_getsockopt (
|
||||
dealer, ZMQ_ROUTER_NOTIFY, &opt_notify_read, &opt_notify_read_size));
|
||||
|
||||
TEST_ASSERT_EQUAL (0, opt_notify_read);
|
||||
|
||||
|
||||
test_context_socket_close (dealer);
|
||||
}
|
||||
|
||||
|
||||
void test_router_notify_helper (int opt_notify_)
|
||||
{
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
int opt_more;
|
||||
size_t opt_more_length = sizeof (opt_more);
|
||||
int opt_events;
|
||||
size_t opt_events_length = sizeof (opt_events);
|
||||
char connect_address[MAX_SOCKET_STRING];
|
||||
|
||||
|
||||
// valid values
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify_, sizeof (opt_notify_)));
|
||||
|
||||
bind_loopback_ipv4 (router, connect_address, sizeof connect_address);
|
||||
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
const char *dealer_routing_id = "X";
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer, ZMQ_ROUTING_ID, dealer_routing_id, 1));
|
||||
|
||||
// dealer connects
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, connect_address));
|
||||
|
||||
// connection notification msg
|
||||
if (opt_notify_ & ZMQ_NOTIFY_CONNECT) {
|
||||
// routing-id only message of the connect
|
||||
recv_string_expect_success (router, dealer_routing_id,
|
||||
0); // 1st part: routing-id
|
||||
recv_string_expect_success (router, "", 0); // 2nd part: empty
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));
|
||||
TEST_ASSERT_EQUAL (0, opt_more);
|
||||
}
|
||||
|
||||
// test message from the dealer
|
||||
send_string_expect_success (dealer, "Hello", 0);
|
||||
recv_string_expect_success (router, dealer_routing_id, 0);
|
||||
recv_string_expect_success (router, "Hello", 0);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));
|
||||
TEST_ASSERT_EQUAL (0, opt_more);
|
||||
|
||||
// dealer disconnects
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (dealer, connect_address));
|
||||
|
||||
// need one more process_commands() (???)
|
||||
msleep (SETTLE_TIME);
|
||||
zmq_getsockopt (dealer, ZMQ_EVENTS, &opt_events, &opt_events_length);
|
||||
|
||||
// connection notification msg
|
||||
if (opt_notify_ & ZMQ_NOTIFY_DISCONNECT) {
|
||||
// routing-id only message of the connect
|
||||
recv_string_expect_success (router, dealer_routing_id,
|
||||
0); // 1st part: routing-id
|
||||
recv_string_expect_success (router, "", 0); // 2nd part: empty
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (router, ZMQ_RCVMORE, &opt_more, &opt_more_length));
|
||||
TEST_ASSERT_EQUAL (0, opt_more);
|
||||
}
|
||||
|
||||
test_context_socket_close (dealer);
|
||||
test_context_socket_close (router);
|
||||
}
|
||||
|
||||
|
||||
void test_router_notify_connect ()
|
||||
{
|
||||
test_router_notify_helper (ZMQ_NOTIFY_CONNECT);
|
||||
}
|
||||
|
||||
|
||||
void test_router_notify_disconnect ()
|
||||
{
|
||||
test_router_notify_helper (ZMQ_NOTIFY_DISCONNECT);
|
||||
}
|
||||
|
||||
|
||||
void test_router_notify_both ()
|
||||
{
|
||||
test_router_notify_helper (ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT);
|
||||
}
|
||||
|
||||
|
||||
void test_handshake_fail ()
|
||||
{
|
||||
// setup router socket
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
int opt_timeout = 200;
|
||||
int opt_notify = ZMQ_NOTIFY_CONNECT | ZMQ_NOTIFY_DISCONNECT;
|
||||
char connect_address[MAX_SOCKET_STRING];
|
||||
|
||||
// valid values
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
router, ZMQ_RCVTIMEO, &opt_timeout, sizeof (opt_timeout)));
|
||||
|
||||
bind_loopback_ipv4 (router, connect_address, sizeof connect_address);
|
||||
|
||||
// send something on raw tcp
|
||||
void *stream = test_context_socket (ZMQ_STREAM);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (stream, connect_address));
|
||||
|
||||
send_string_expect_success (stream, "not-a-handshake", 0);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_disconnect (stream, connect_address));
|
||||
test_context_socket_close (stream);
|
||||
|
||||
// no notification delivered
|
||||
char buffer[255];
|
||||
TEST_ASSERT_FAILURE_ERRNO (EAGAIN,
|
||||
zmq_recv (router, buffer, sizeof (buffer), 0));
|
||||
|
||||
test_context_socket_close (router);
|
||||
}
|
||||
|
||||
|
||||
void test_error_during_multipart ()
|
||||
{
|
||||
/*
|
||||
* If the disconnect occurs in the middle of the multipart
|
||||
* message, the socket should not add the notification at the
|
||||
* end of the incomplete message. It must discard the incomplete
|
||||
* message, and delivert the notification as a new message.
|
||||
*/
|
||||
|
||||
char connect_address[MAX_SOCKET_STRING];
|
||||
char long_str[128] = {0};
|
||||
memset (long_str, '*', sizeof (long_str) - 1);
|
||||
|
||||
// setup router
|
||||
void *router = test_context_socket (ZMQ_ROUTER);
|
||||
|
||||
int opt_notify = ZMQ_NOTIFY_DISCONNECT;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
router, ZMQ_ROUTER_NOTIFY, &opt_notify, sizeof (opt_notify)));
|
||||
|
||||
int64_t opt_maxmsgsize = 64; // the handshake fails if this is too small
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
router, ZMQ_MAXMSGSIZE, &opt_maxmsgsize, sizeof (opt_maxmsgsize)));
|
||||
|
||||
bind_loopback_ipv4 (router, connect_address, sizeof connect_address);
|
||||
|
||||
// setup dealer
|
||||
void *dealer = test_context_socket (ZMQ_DEALER);
|
||||
const char *dealer_routing_id = "X";
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (dealer, ZMQ_ROUTING_ID, dealer_routing_id, 1));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (dealer, connect_address));
|
||||
|
||||
|
||||
// send multipart message, the 2nd part causes a disconnect.
|
||||
send_string_expect_success (dealer, "Hello2", ZMQ_SNDMORE);
|
||||
send_string_expect_success (dealer, long_str, 0);
|
||||
|
||||
// disconnect notification
|
||||
recv_string_expect_success (router, dealer_routing_id, 0);
|
||||
recv_string_expect_success (router, "", 0);
|
||||
|
||||
|
||||
test_context_socket_close (dealer);
|
||||
test_context_socket_close (router);
|
||||
}
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_sockopt_router_notify);
|
||||
RUN_TEST (test_router_notify_connect);
|
||||
RUN_TEST (test_router_notify_disconnect);
|
||||
RUN_TEST (test_router_notify_both);
|
||||
RUN_TEST (test_handshake_fail);
|
||||
RUN_TEST (test_error_during_multipart);
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
88
tests/test_scatter_gather.cpp
Normal file
88
tests/test_scatter_gather.cpp
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_scatter_gather_multipart_fails ()
|
||||
{
|
||||
void *scatter = test_context_socket (ZMQ_SCATTER);
|
||||
void *gather = test_context_socket (ZMQ_GATHER);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_bind (scatter, "inproc://test-scatter-gather"));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (gather, "inproc://test-scatter-gather"));
|
||||
|
||||
// Should fail, multipart is not supported
|
||||
TEST_ASSERT_FAILURE_ERRNO (EINVAL,
|
||||
zmq_send_const (scatter, "1", 1, ZMQ_SNDMORE));
|
||||
|
||||
test_context_socket_close (scatter);
|
||||
test_context_socket_close (gather);
|
||||
}
|
||||
|
||||
void test_scatter_gather ()
|
||||
{
|
||||
void *scatter = test_context_socket (ZMQ_SCATTER);
|
||||
void *gather = test_context_socket (ZMQ_GATHER);
|
||||
void *gather2 = test_context_socket (ZMQ_GATHER);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_bind (scatter, "inproc://test-scatter-gather"));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (gather, "inproc://test-scatter-gather"));
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (gather2, "inproc://test-scatter-gather"));
|
||||
|
||||
send_string_expect_success (scatter, "1", 0);
|
||||
send_string_expect_success (scatter, "2", 0);
|
||||
|
||||
recv_string_expect_success (gather, "1", 0);
|
||||
recv_string_expect_success (gather2, "2", 0);
|
||||
|
||||
test_context_socket_close (scatter);
|
||||
test_context_socket_close (gather);
|
||||
test_context_socket_close (gather2);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_scatter_gather);
|
||||
RUN_TEST (test_scatter_gather_multipart_fails);
|
||||
return UNITY_END ();
|
||||
}
|
||||
608
tests/test_security_curve.cpp
Normal file
608
tests/test_security_curve.cpp
Normal file
@@ -0,0 +1,608 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
// TODO remove this workaround for handling libsodium/tweetnacl
|
||||
|
||||
// To define SIZE_MAX with older compilers
|
||||
#define __STDC_LIMIT_MACROS
|
||||
|
||||
#if defined ZMQ_CUSTOM_PLATFORM_HPP
|
||||
#include "platform.hpp"
|
||||
#else
|
||||
#include "../src/platform.hpp"
|
||||
#endif
|
||||
|
||||
#ifndef ZMQ_USE_TWEETNACL
|
||||
#define ZMQ_USE_TWEETNACL
|
||||
#endif
|
||||
#ifdef ZMQ_USE_LIBSODIUM
|
||||
#undef ZMQ_USE_LIBSODIUM
|
||||
#endif
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_security.hpp"
|
||||
#include <unity.h>
|
||||
|
||||
#include "../src/tweetnacl.h"
|
||||
#include "../src/curve_client_tools.hpp"
|
||||
#include "../src/random.hpp"
|
||||
|
||||
char error_message_buffer[256];
|
||||
|
||||
void *handler;
|
||||
void *zap_thread;
|
||||
void *server;
|
||||
void *server_mon;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
setup_context_and_server_side (&handler, &zap_thread, &server, &server_mon,
|
||||
my_endpoint);
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
shutdown_context_and_server_side (zap_thread, server, server_mon, handler);
|
||||
teardown_test_context ();
|
||||
}
|
||||
|
||||
const int timeout = 250;
|
||||
|
||||
const char large_routing_id[] = "0123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789"
|
||||
"0123456789012345678901234567890123456789"
|
||||
"012345678901234";
|
||||
|
||||
static void zap_handler_large_routing_id (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_ok, large_routing_id);
|
||||
}
|
||||
|
||||
void expect_new_client_curve_bounce_fail (const char *server_public_,
|
||||
const char *client_public_,
|
||||
const char *client_secret_,
|
||||
char *my_endpoint_,
|
||||
void *server_,
|
||||
void **client_mon_ = NULL,
|
||||
int expected_client_event_ = 0,
|
||||
int expected_client_value_ = 0)
|
||||
{
|
||||
curve_client_data_t curve_client_data = {server_public_, client_public_,
|
||||
client_secret_};
|
||||
expect_new_client_bounce_fail (
|
||||
my_endpoint_, server_, socket_config_curve_client, &curve_client_data,
|
||||
client_mon_, expected_client_event_, expected_client_value_);
|
||||
}
|
||||
|
||||
void test_null_key (void *server_,
|
||||
void *server_mon_,
|
||||
char *my_endpoint_,
|
||||
char *server_public_,
|
||||
char *client_public_,
|
||||
char *client_secret_)
|
||||
{
|
||||
expect_new_client_curve_bounce_fail (server_public_, client_public_,
|
||||
client_secret_, my_endpoint_, server_);
|
||||
|
||||
int handshake_failed_encryption_event_count =
|
||||
expect_monitor_event_multiple (server_mon_,
|
||||
ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,
|
||||
ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
|
||||
|
||||
// handshake_failed_encryption_event_count should be at least two because
|
||||
// expect_bounce_fail involves two exchanges
|
||||
// however, with valgrind we see only one event (maybe the next one takes
|
||||
// very long, or does not happen at all because something else takes very
|
||||
// long)
|
||||
|
||||
fprintf (stderr,
|
||||
"count of "
|
||||
"ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL/"
|
||||
"ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC events: %i\n",
|
||||
handshake_failed_encryption_event_count);
|
||||
}
|
||||
|
||||
void test_curve_security_with_valid_credentials ()
|
||||
{
|
||||
curve_client_data_t curve_client_data = {
|
||||
valid_server_public, valid_client_public, valid_client_secret};
|
||||
void *client_mon;
|
||||
void *client = create_and_connect_client (
|
||||
my_endpoint, socket_config_curve_client, &curve_client_data, &client_mon);
|
||||
bounce (server, client);
|
||||
test_context_socket_close (client);
|
||||
|
||||
int event = get_monitor_event_with_timeout (server_mon, NULL, NULL, -1);
|
||||
assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
|
||||
|
||||
assert_no_more_monitor_events_with_timeout (server_mon, timeout);
|
||||
|
||||
event = get_monitor_event_with_timeout (client_mon, NULL, NULL, -1);
|
||||
assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
|
||||
|
||||
assert_no_more_monitor_events_with_timeout (client_mon, timeout);
|
||||
|
||||
test_context_socket_close (client_mon);
|
||||
}
|
||||
|
||||
void test_curve_security_with_bogus_client_credentials ()
|
||||
{
|
||||
// This must be caught by the ZAP handler
|
||||
char bogus_public[41];
|
||||
char bogus_secret[41];
|
||||
zmq_curve_keypair (bogus_public, bogus_secret);
|
||||
|
||||
expect_new_client_curve_bounce_fail (
|
||||
valid_server_public, bogus_public, bogus_secret, my_endpoint, server,
|
||||
NULL, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 400);
|
||||
|
||||
int server_event_count = 0;
|
||||
server_event_count = expect_monitor_event_multiple (
|
||||
server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 400);
|
||||
TEST_ASSERT_LESS_OR_EQUAL_INT (1, server_event_count);
|
||||
|
||||
// there may be more than one ZAP request due to repeated attempts by the client
|
||||
TEST_ASSERT (0 == server_event_count
|
||||
|| 1 <= zmq_atomic_counter_value (zap_requests_handled));
|
||||
}
|
||||
|
||||
void expect_zmtp_mechanism_mismatch (void *client_,
|
||||
char *my_endpoint_,
|
||||
void *server_,
|
||||
void *server_mon_)
|
||||
{
|
||||
// This must be caught by the curve_server class, not passed to ZAP
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client_, my_endpoint_));
|
||||
expect_bounce_fail (server_, client_);
|
||||
test_context_socket_close_zero_linger (client_);
|
||||
|
||||
expect_monitor_event_multiple (server_mon_,
|
||||
ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,
|
||||
ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH);
|
||||
|
||||
TEST_ASSERT_EQUAL_INT (0, zmq_atomic_counter_value (zap_requests_handled));
|
||||
}
|
||||
|
||||
void test_curve_security_with_null_client_credentials ()
|
||||
{
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
|
||||
expect_zmtp_mechanism_mismatch (client, my_endpoint, server, server_mon);
|
||||
}
|
||||
|
||||
void test_curve_security_with_plain_client_credentials ()
|
||||
{
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, "admin", 5));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, "password", 8));
|
||||
|
||||
expect_zmtp_mechanism_mismatch (client, my_endpoint, server, server_mon);
|
||||
}
|
||||
|
||||
void test_curve_security_unauthenticated_message ()
|
||||
{
|
||||
// Unauthenticated messages from a vanilla socket shouldn't be received
|
||||
fd_t s = connect_socket (my_endpoint);
|
||||
// send anonymous ZMTP/1.0 greeting
|
||||
send (s, "\x01\x00", 2, 0);
|
||||
// send sneaky message that shouldn't be received
|
||||
send (s, "\x08\x00sneaky\0", 9, 0);
|
||||
|
||||
zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
|
||||
char *buf = s_recv (server);
|
||||
TEST_ASSERT_NULL_MESSAGE (buf, "Received unauthenticated message");
|
||||
close (s);
|
||||
}
|
||||
|
||||
void send_all (fd_t fd_, const char *data_, socket_size_t size_)
|
||||
{
|
||||
while (size_ > 0) {
|
||||
int res = send (fd_, data_, size_, 0);
|
||||
TEST_ASSERT_GREATER_THAN_INT (0, res);
|
||||
size_ -= res;
|
||||
data_ += res;
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t N> void send (fd_t fd_, const char (&data_)[N])
|
||||
{
|
||||
send_all (fd_, data_, N - 1);
|
||||
}
|
||||
|
||||
template <size_t N> void send (fd_t fd_, const uint8_t (&data_)[N])
|
||||
{
|
||||
send_all (fd_, reinterpret_cast<const char *> (&data_), N);
|
||||
}
|
||||
|
||||
void test_curve_security_invalid_hello_wrong_length ()
|
||||
{
|
||||
fd_t s = connect_socket (my_endpoint);
|
||||
|
||||
send (s, zmtp_greeting_curve);
|
||||
|
||||
// send CURVE HELLO of wrong size
|
||||
send (s, "\x04\x06\x05HELLO");
|
||||
|
||||
expect_monitor_event_multiple (
|
||||
server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,
|
||||
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
|
||||
|
||||
close (s);
|
||||
}
|
||||
|
||||
const size_t hello_length = 200;
|
||||
const size_t welcome_length = 168;
|
||||
|
||||
zmq::curve_client_tools_t make_curve_client_tools ()
|
||||
{
|
||||
uint8_t valid_client_secret_decoded[32];
|
||||
uint8_t valid_client_public_decoded[32];
|
||||
|
||||
zmq_z85_decode (valid_client_public_decoded, valid_client_public);
|
||||
zmq_z85_decode (valid_client_secret_decoded, valid_client_secret);
|
||||
|
||||
uint8_t valid_server_public_decoded[32];
|
||||
zmq_z85_decode (valid_server_public_decoded, valid_server_public);
|
||||
|
||||
return zmq::curve_client_tools_t (valid_client_public_decoded,
|
||||
valid_client_secret_decoded,
|
||||
valid_server_public_decoded);
|
||||
}
|
||||
|
||||
// same as htonll, which is only available on few platforms (recent Windows, but not on Linux, e.g.(
|
||||
static uint64_t host_to_network (uint64_t value_)
|
||||
{
|
||||
// The answer is 42
|
||||
static const int num = 42;
|
||||
|
||||
// Check the endianness
|
||||
if (*reinterpret_cast<const char *> (&num) == num) {
|
||||
const uint32_t high_part = htonl (static_cast<uint32_t> (value_ >> 32));
|
||||
const uint32_t low_part =
|
||||
htonl (static_cast<uint32_t> (value_ & 0xFFFFFFFFLL));
|
||||
|
||||
return (static_cast<uint64_t> (low_part) << 32) | high_part;
|
||||
}
|
||||
return value_;
|
||||
}
|
||||
|
||||
template <size_t N> void send_command (fd_t s_, char (&command_)[N])
|
||||
{
|
||||
if (N < 256) {
|
||||
send (s_, "\x04");
|
||||
char len = (char) N;
|
||||
send_all (s_, &len, 1);
|
||||
} else {
|
||||
send (s_, "\x06");
|
||||
uint64_t len = host_to_network (N);
|
||||
send_all (s_, reinterpret_cast<char *> (&len), 8);
|
||||
}
|
||||
send_all (s_, command_, N);
|
||||
}
|
||||
|
||||
void test_curve_security_invalid_hello_command_name ()
|
||||
{
|
||||
fd_t s = connect_socket (my_endpoint);
|
||||
|
||||
send (s, zmtp_greeting_curve);
|
||||
|
||||
zmq::curve_client_tools_t tools = make_curve_client_tools ();
|
||||
|
||||
// send CURVE HELLO with a misspelled command name (but otherwise correct)
|
||||
char hello[hello_length];
|
||||
TEST_ASSERT_SUCCESS_ERRNO (tools.produce_hello (hello, 0));
|
||||
hello[5] = 'X';
|
||||
|
||||
send_command (s, hello);
|
||||
|
||||
expect_monitor_event_multiple (server_mon,
|
||||
ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,
|
||||
ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
|
||||
|
||||
close (s);
|
||||
}
|
||||
|
||||
void test_curve_security_invalid_hello_version ()
|
||||
{
|
||||
fd_t s = connect_socket (my_endpoint);
|
||||
|
||||
send (s, zmtp_greeting_curve);
|
||||
|
||||
zmq::curve_client_tools_t tools = make_curve_client_tools ();
|
||||
|
||||
// send CURVE HELLO with a wrong version number (but otherwise correct)
|
||||
char hello[hello_length];
|
||||
TEST_ASSERT_SUCCESS_ERRNO (tools.produce_hello (hello, 0));
|
||||
hello[6] = 2;
|
||||
|
||||
send_command (s, hello);
|
||||
|
||||
expect_monitor_event_multiple (
|
||||
server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,
|
||||
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
|
||||
|
||||
close (s);
|
||||
}
|
||||
|
||||
void flush_read (fd_t fd_)
|
||||
{
|
||||
int res;
|
||||
char buf[256];
|
||||
|
||||
while ((res = recv (fd_, buf, 256, 0)) == 256) {
|
||||
}
|
||||
TEST_ASSERT_NOT_EQUAL (-1, res);
|
||||
}
|
||||
|
||||
void recv_all (fd_t fd_, uint8_t *data_, socket_size_t len_)
|
||||
{
|
||||
socket_size_t received = 0;
|
||||
while (received < len_) {
|
||||
int res = recv (fd_, reinterpret_cast<char *> (data_), len_, 0);
|
||||
TEST_ASSERT_GREATER_THAN_INT (0, res);
|
||||
|
||||
data_ += res;
|
||||
received += res;
|
||||
}
|
||||
}
|
||||
|
||||
void recv_greeting (fd_t fd_)
|
||||
{
|
||||
uint8_t greeting[64];
|
||||
recv_all (fd_, greeting, 64);
|
||||
// TODO assert anything about the greeting received from the server?
|
||||
}
|
||||
|
||||
fd_t connect_exchange_greeting_and_send_hello (
|
||||
char *my_endpoint_, zmq::curve_client_tools_t &tools_)
|
||||
{
|
||||
fd_t s = connect_socket (my_endpoint_);
|
||||
|
||||
send (s, zmtp_greeting_curve);
|
||||
recv_greeting (s);
|
||||
|
||||
// send valid CURVE HELLO
|
||||
char hello[hello_length];
|
||||
TEST_ASSERT_SUCCESS_ERRNO (tools_.produce_hello (hello, 0));
|
||||
|
||||
send_command (s, hello);
|
||||
return s;
|
||||
}
|
||||
|
||||
void test_curve_security_invalid_initiate_wrong_length ()
|
||||
{
|
||||
zmq::curve_client_tools_t tools = make_curve_client_tools ();
|
||||
|
||||
fd_t s = connect_exchange_greeting_and_send_hello (my_endpoint, tools);
|
||||
|
||||
// receive but ignore WELCOME
|
||||
flush_read (s);
|
||||
|
||||
int res = get_monitor_event_with_timeout (server_mon, NULL, NULL, timeout);
|
||||
TEST_ASSERT_EQUAL_INT (-1, res);
|
||||
|
||||
send (s, "\x04\x09\x08INITIATE");
|
||||
|
||||
expect_monitor_event_multiple (
|
||||
server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,
|
||||
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE);
|
||||
|
||||
close (s);
|
||||
}
|
||||
|
||||
fd_t connect_exchange_greeting_and_hello_welcome (
|
||||
char *my_endpoint_,
|
||||
void *server_mon_,
|
||||
int timeout_,
|
||||
zmq::curve_client_tools_t &tools_)
|
||||
{
|
||||
fd_t s = connect_exchange_greeting_and_send_hello (my_endpoint_, tools_);
|
||||
|
||||
// receive but ignore WELCOME
|
||||
uint8_t welcome[welcome_length + 2];
|
||||
recv_all (s, welcome, welcome_length + 2);
|
||||
|
||||
uint8_t cn_precom[crypto_box_BEFORENMBYTES];
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
tools_.process_welcome (welcome + 2, welcome_length, cn_precom));
|
||||
|
||||
const int res =
|
||||
get_monitor_event_with_timeout (server_mon_, NULL, NULL, timeout_);
|
||||
TEST_ASSERT_EQUAL_INT (-1, res);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
void test_curve_security_invalid_initiate_command_name ()
|
||||
{
|
||||
zmq::curve_client_tools_t tools = make_curve_client_tools ();
|
||||
fd_t s = connect_exchange_greeting_and_hello_welcome (
|
||||
my_endpoint, server_mon, timeout, tools);
|
||||
|
||||
char initiate[257];
|
||||
tools.produce_initiate (initiate, 257, 1, NULL, 0);
|
||||
// modify command name
|
||||
initiate[5] = 'X';
|
||||
|
||||
send_command (s, initiate);
|
||||
|
||||
expect_monitor_event_multiple (server_mon,
|
||||
ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,
|
||||
ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
|
||||
|
||||
close (s);
|
||||
}
|
||||
|
||||
void test_curve_security_invalid_initiate_command_encrypted_cookie ()
|
||||
{
|
||||
zmq::curve_client_tools_t tools = make_curve_client_tools ();
|
||||
fd_t s = connect_exchange_greeting_and_hello_welcome (
|
||||
my_endpoint, server_mon, timeout, tools);
|
||||
|
||||
char initiate[257];
|
||||
tools.produce_initiate (initiate, 257, 1, NULL, 0);
|
||||
// make garbage from encrypted cookie
|
||||
initiate[30] = !initiate[30];
|
||||
|
||||
send_command (s, initiate);
|
||||
|
||||
expect_monitor_event_multiple (server_mon,
|
||||
ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,
|
||||
ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
|
||||
|
||||
close (s);
|
||||
}
|
||||
|
||||
void test_curve_security_invalid_initiate_command_encrypted_content ()
|
||||
{
|
||||
zmq::curve_client_tools_t tools = make_curve_client_tools ();
|
||||
fd_t s = connect_exchange_greeting_and_hello_welcome (
|
||||
my_endpoint, server_mon, timeout, tools);
|
||||
|
||||
char initiate[257];
|
||||
tools.produce_initiate (initiate, 257, 1, NULL, 0);
|
||||
// make garbage from encrypted content
|
||||
initiate[150] = !initiate[150];
|
||||
|
||||
send_command (s, initiate);
|
||||
|
||||
expect_monitor_event_multiple (server_mon,
|
||||
ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL,
|
||||
ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
|
||||
|
||||
close (s);
|
||||
}
|
||||
|
||||
void test_curve_security_invalid_keysize (void *ctx_)
|
||||
{
|
||||
// Check return codes for invalid buffer sizes
|
||||
void *client = zmq_socket (ctx_, ZMQ_DEALER);
|
||||
TEST_ASSERT_NOT_NULL (client);
|
||||
errno = 0;
|
||||
int rc =
|
||||
zmq_setsockopt (client, ZMQ_CURVE_SERVERKEY, valid_server_public, 123);
|
||||
assert (rc == -1 && errno == EINVAL);
|
||||
errno = 0;
|
||||
rc = zmq_setsockopt (client, ZMQ_CURVE_PUBLICKEY, valid_client_public, 123);
|
||||
assert (rc == -1 && errno == EINVAL);
|
||||
errno = 0;
|
||||
rc = zmq_setsockopt (client, ZMQ_CURVE_SECRETKEY, valid_client_secret, 123);
|
||||
assert (rc == -1 && errno == EINVAL);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (client));
|
||||
}
|
||||
|
||||
// TODO why isn't this const?
|
||||
char null_key[] = "0000000000000000000000000000000000000000";
|
||||
|
||||
void test_null_server_key ()
|
||||
{
|
||||
// Check CURVE security with a null server key
|
||||
// This will be caught by the curve_server class, not passed to ZAP
|
||||
test_null_key (server, server_mon, my_endpoint, null_key,
|
||||
valid_client_public, valid_client_secret);
|
||||
}
|
||||
|
||||
void test_null_client_public_key ()
|
||||
{
|
||||
// Check CURVE security with a null client public key
|
||||
// This will be caught by the curve_server class, not passed to ZAP
|
||||
test_null_key (server, server_mon, my_endpoint, valid_server_public,
|
||||
null_key, valid_client_secret);
|
||||
}
|
||||
|
||||
void test_null_client_secret_key ()
|
||||
{
|
||||
// Check CURVE security with a null client public key
|
||||
// This will be caught by the curve_server class, not passed to ZAP
|
||||
test_null_key (server, server_mon, my_endpoint, valid_server_public,
|
||||
valid_client_public, null_key);
|
||||
}
|
||||
|
||||
|
||||
int main (void)
|
||||
{
|
||||
if (!zmq_has ("curve")) {
|
||||
printf ("CURVE encryption not installed, skipping test\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
zmq::random_open ();
|
||||
|
||||
setup_testutil_security_curve ();
|
||||
|
||||
|
||||
setup_test_environment (180);
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_curve_security_with_valid_credentials);
|
||||
RUN_TEST (test_null_server_key);
|
||||
RUN_TEST (test_null_client_public_key);
|
||||
RUN_TEST (test_null_client_secret_key);
|
||||
RUN_TEST (test_curve_security_with_bogus_client_credentials);
|
||||
RUN_TEST (test_curve_security_with_null_client_credentials);
|
||||
RUN_TEST (test_curve_security_with_plain_client_credentials);
|
||||
RUN_TEST (test_curve_security_unauthenticated_message);
|
||||
|
||||
// tests with misbehaving CURVE client
|
||||
RUN_TEST (test_curve_security_invalid_hello_wrong_length);
|
||||
RUN_TEST (test_curve_security_invalid_hello_command_name);
|
||||
RUN_TEST (test_curve_security_invalid_hello_version);
|
||||
RUN_TEST (test_curve_security_invalid_initiate_wrong_length);
|
||||
RUN_TEST (test_curve_security_invalid_initiate_command_name);
|
||||
RUN_TEST (test_curve_security_invalid_initiate_command_encrypted_cookie);
|
||||
RUN_TEST (test_curve_security_invalid_initiate_command_encrypted_content);
|
||||
|
||||
// TODO this requires a deviating test setup, must be moved to a separate executable/fixture
|
||||
// test with a large routing id (resulting in large metadata)
|
||||
fprintf (stderr,
|
||||
"test_curve_security_with_valid_credentials (large routing id)\n");
|
||||
setup_test_context ();
|
||||
setup_context_and_server_side (&handler, &zap_thread, &server, &server_mon,
|
||||
my_endpoint, &zap_handler_large_routing_id,
|
||||
&socket_config_curve_server,
|
||||
&valid_server_secret, large_routing_id);
|
||||
test_curve_security_with_valid_credentials ();
|
||||
shutdown_context_and_server_side (zap_thread, server, server_mon, handler);
|
||||
teardown_test_context ();
|
||||
|
||||
void *ctx = zmq_ctx_new ();
|
||||
test_curve_security_invalid_keysize (ctx);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_ctx_term (ctx));
|
||||
|
||||
zmq::random_close ();
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
274
tests/test_security_gssapi.cpp
Normal file
274
tests/test_security_gssapi.cpp
Normal file
@@ -0,0 +1,274 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_monitoring.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
// This test requires a KRB5 environment with the following
|
||||
// service principal (substitute your host.domain and REALM):
|
||||
//
|
||||
// zmqtest2/host.domain@REALM (host.domain should be host running test)
|
||||
//
|
||||
// Export keys for this principal to a keytab file and set the environment
|
||||
// variables KRB5_KTNAME and KRB5_CLIENT_KTNAME to FILE:/path/to/your/keytab.
|
||||
// The test will use it both for client and server roles.
|
||||
//
|
||||
// The test is derived in large part from test_security_curve.cpp
|
||||
|
||||
const char *name = "zmqtest2";
|
||||
|
||||
static volatile int zap_deny_all = 0;
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// This methods receives and validates ZAP requests (allowing or denying
|
||||
// each client connection).
|
||||
// N.B. on failure, each crypto type in keytab will be tried
|
||||
|
||||
static void zap_handler (void *handler_)
|
||||
{
|
||||
// Process ZAP requests forever
|
||||
while (true) {
|
||||
char *version = s_recv (handler_);
|
||||
if (!version)
|
||||
break; // Terminating
|
||||
|
||||
char *sequence = s_recv (handler_);
|
||||
char *domain = s_recv (handler_);
|
||||
char *address = s_recv (handler_);
|
||||
char *routing_id = s_recv (handler_);
|
||||
char *mechanism = s_recv (handler_);
|
||||
char *principal = s_recv (handler_);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING ("1.0", version);
|
||||
TEST_ASSERT_EQUAL_STRING ("GSSAPI", mechanism);
|
||||
|
||||
send_string_expect_success (handler_, version, ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, sequence, ZMQ_SNDMORE);
|
||||
|
||||
if (!zap_deny_all) {
|
||||
send_string_expect_success (handler_, "200", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "OK", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "anonymous", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "", 0);
|
||||
//fprintf (stderr, "ALLOW %s\n", principal);
|
||||
} else {
|
||||
send_string_expect_success (handler_, "400", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "Denied", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "", 0);
|
||||
//fprintf (stderr, "DENY %s\n", principal);
|
||||
}
|
||||
free (version);
|
||||
free (sequence);
|
||||
free (domain);
|
||||
free (address);
|
||||
free (routing_id);
|
||||
free (mechanism);
|
||||
free (principal);
|
||||
}
|
||||
zmq_close (handler_);
|
||||
}
|
||||
|
||||
static char my_endpoint[MAX_SOCKET_STRING];
|
||||
static void *zap_thread;
|
||||
static void *server;
|
||||
static void *server_mon;
|
||||
|
||||
void check_krb_available ()
|
||||
{
|
||||
if (!getenv ("KRB5_KTNAME") || !getenv ("KRB5_CLIENT_KTNAME")) {
|
||||
TEST_IGNORE_MESSAGE ("KRB5 environment unavailable, skipping test");
|
||||
}
|
||||
}
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
|
||||
zap_thread = 0;
|
||||
server = NULL;
|
||||
server_mon = NULL;
|
||||
|
||||
check_krb_available ();
|
||||
|
||||
// Spawn ZAP handler
|
||||
// We create and bind ZAP socket in main thread to avoid case
|
||||
// where child thread does not start up fast enough.
|
||||
void *handler = zmq_socket (get_test_context (), ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, "inproc://zeromq.zap.01"));
|
||||
zap_thread = zmq_threadstart (&zap_handler, handler);
|
||||
|
||||
// Server socket will accept connections
|
||||
server = test_context_socket (ZMQ_DEALER);
|
||||
int as_server = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_GSSAPI_SERVER, &as_server, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_GSSAPI_PRINCIPAL, name, strlen (name) + 1));
|
||||
int name_type = ZMQ_GSSAPI_NT_HOSTBASED;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
server, ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, &name_type, sizeof (name_type)));
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
// Monitor handshake events on the server
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor (
|
||||
server, "inproc://monitor-server",
|
||||
ZMQ_EVENT_HANDSHAKE_SUCCEEDED | ZMQ_EVENT_HANDSHAKE_FAILED_AUTH
|
||||
| ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL));
|
||||
|
||||
// Create socket for collecting monitor events
|
||||
server_mon = test_context_socket (ZMQ_PAIR);
|
||||
|
||||
// Connect it to the inproc endpoints so they'll get events
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_connect (server_mon, "inproc://monitor-server"));
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
// Shutdown
|
||||
if (server_mon)
|
||||
test_context_socket_close_zero_linger (server_mon);
|
||||
if (server)
|
||||
test_context_socket_close (server);
|
||||
teardown_test_context ();
|
||||
|
||||
// Wait until ZAP handler terminates
|
||||
if (zap_thread)
|
||||
zmq_threadclose (zap_thread);
|
||||
}
|
||||
|
||||
void test_valid_creds ()
|
||||
{
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
client, ZMQ_GSSAPI_SERVICE_PRINCIPAL, name, strlen (name) + 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_GSSAPI_PRINCIPAL, name, strlen (name) + 1));
|
||||
int name_type = ZMQ_GSSAPI_NT_HOSTBASED;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
client, ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, &name_type, sizeof (name_type)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
bounce (server, client);
|
||||
test_context_socket_close (client);
|
||||
|
||||
int event = get_monitor_event (server_mon, NULL, NULL);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_HANDSHAKE_SUCCEEDED, event);
|
||||
}
|
||||
|
||||
// Check security with valid but unauthorized credentials
|
||||
// Note: ZAP may see multiple requests - after a failure, client will
|
||||
// fall back to other crypto types for principal, if available.
|
||||
void test_unauth_creds ()
|
||||
{
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
client, ZMQ_GSSAPI_SERVICE_PRINCIPAL, name, strlen (name) + 1));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_GSSAPI_PRINCIPAL, name, strlen (name) + 1));
|
||||
int name_type = ZMQ_GSSAPI_NT_HOSTBASED;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_setsockopt (
|
||||
client, ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, &name_type, sizeof (name_type)));
|
||||
zap_deny_all = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
|
||||
expect_bounce_fail (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
|
||||
int event = get_monitor_event (server_mon, NULL, NULL);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, event);
|
||||
}
|
||||
|
||||
// Check GSSAPI security with NULL client credentials
|
||||
// This must be caught by the gssapi_server class, not passed to ZAP
|
||||
void test_null_creds ()
|
||||
{
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
expect_bounce_fail (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
|
||||
int error;
|
||||
int event = get_monitor_event (server_mon, &error, NULL);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, event);
|
||||
TEST_ASSERT_EQUAL_INT (ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH, error);
|
||||
}
|
||||
|
||||
// Check GSSAPI security with PLAIN client credentials
|
||||
// This must be caught by the curve_server class, not passed to ZAP
|
||||
void test_plain_creds ()
|
||||
{
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, "admin", 5));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, "password", 8));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
expect_bounce_fail (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
}
|
||||
|
||||
// Unauthenticated messages from a vanilla socket shouldn't be received
|
||||
void test_vanilla_socket ()
|
||||
{
|
||||
fd_t s = connect_socket (my_endpoint);
|
||||
// send anonymous ZMTP/1.0 greeting
|
||||
send (s, "\x01\x00", 2, 0);
|
||||
// send sneaky message that shouldn't be received
|
||||
send (s, "\x08\x00sneaky\0", 9, 0);
|
||||
int timeout = 250;
|
||||
zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
|
||||
char *buf = s_recv (server);
|
||||
if (buf != NULL) {
|
||||
printf ("Received unauthenticated message: %s\n", buf);
|
||||
TEST_ASSERT_NULL (buf);
|
||||
}
|
||||
close (s);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
// Avoid entanglements with user's credential cache
|
||||
setenv ("KRB5CCNAME", "MEMORY", 1);
|
||||
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_valid_creds);
|
||||
RUN_TEST (test_null_creds);
|
||||
RUN_TEST (test_plain_creds);
|
||||
RUN_TEST (test_vanilla_socket);
|
||||
RUN_TEST (test_unauth_creds);
|
||||
return UNITY_END ();
|
||||
}
|
||||
82
tests/test_security_no_zap_handler.cpp
Normal file
82
tests/test_security_no_zap_handler.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_no_zap_handler ()
|
||||
{
|
||||
// We first test client/server with a ZAP domain but with no handler
|
||||
// If there is no handler, libzmq should ignore the ZAP option unless
|
||||
// ZMQ_ZAP_ENFORCE_DOMAIN is set
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 5));
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
bounce (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
}
|
||||
|
||||
void test_no_zap_handler_enforce_domain ()
|
||||
{
|
||||
#ifdef ZMQ_ZAP_ENFORCE_DOMAIN
|
||||
// Now set ZMQ_ZAP_ENFORCE_DOMAIN which strictly enforces the ZAP
|
||||
// RFC but is backward-incompatible, now it should fail
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
int required = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ZAP_ENFORCE_DOMAIN, &required, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 5));
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
expect_bounce_fail (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
#endif
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_no_zap_handler);
|
||||
RUN_TEST (test_no_zap_handler_enforce_domain);
|
||||
return UNITY_END ();
|
||||
}
|
||||
199
tests/test_security_null.cpp
Normal file
199
tests/test_security_null.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#if defined(ZMQ_HAVE_WINDOWS)
|
||||
#include <winsock2.h>
|
||||
#include <ws2tcpip.h>
|
||||
#include <stdexcept>
|
||||
#define close closesocket
|
||||
#else
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static void zap_handler (void *handler_)
|
||||
{
|
||||
// Process ZAP requests forever
|
||||
while (true) {
|
||||
char *version = s_recv (handler_);
|
||||
if (!version)
|
||||
break; // Terminating
|
||||
|
||||
char *sequence = s_recv (handler_);
|
||||
char *domain = s_recv (handler_);
|
||||
char *address = s_recv (handler_);
|
||||
char *routing_id = s_recv (handler_);
|
||||
char *mechanism = s_recv (handler_);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING ("1.0", version);
|
||||
TEST_ASSERT_EQUAL_STRING ("NULL", mechanism);
|
||||
|
||||
send_string_expect_success (handler_, version, ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, sequence, ZMQ_SNDMORE);
|
||||
if (streq (domain, "TEST")) {
|
||||
send_string_expect_success (handler_, "200", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "OK", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "anonymous", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "", 0);
|
||||
} else {
|
||||
send_string_expect_success (handler_, "400", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "BAD DOMAIN", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "", ZMQ_SNDMORE);
|
||||
send_string_expect_success (handler_, "", 0);
|
||||
}
|
||||
free (version);
|
||||
free (sequence);
|
||||
free (domain);
|
||||
free (address);
|
||||
free (routing_id);
|
||||
free (mechanism);
|
||||
}
|
||||
close_zero_linger (handler_);
|
||||
}
|
||||
|
||||
void *zap_thread;
|
||||
|
||||
static void setup_zap_handler ()
|
||||
{
|
||||
// Spawn ZAP handler
|
||||
// We create and bind ZAP socket in main thread to avoid case
|
||||
// where child thread does not start up fast enough.
|
||||
void *handler = zmq_socket (get_test_context (), ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, "inproc://zeromq.zap.01"));
|
||||
zap_thread = zmq_threadstart (&zap_handler, handler);
|
||||
}
|
||||
|
||||
static void teardown_zap_handler ()
|
||||
{
|
||||
// Wait until ZAP handler terminates
|
||||
zmq_threadclose (zap_thread);
|
||||
}
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
setup_zap_handler ();
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
teardown_test_context ();
|
||||
teardown_zap_handler ();
|
||||
}
|
||||
|
||||
void test_no_domain ()
|
||||
{
|
||||
// We first test client/server with no ZAP domain
|
||||
// Libzmq does not call our ZAP handler, the connect must succeed
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
bounce (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
}
|
||||
|
||||
void test_wrong_domain_fails ()
|
||||
{
|
||||
// Now define a ZAP domain for the server; this enables
|
||||
// authentication. We're using the wrong domain so this test
|
||||
// must fail.
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "WRONG", 5));
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
expect_bounce_fail (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
}
|
||||
|
||||
void test_success ()
|
||||
{
|
||||
// Now use the right domain, the test must pass
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 4));
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
bounce (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
}
|
||||
|
||||
void test_vanilla_socket ()
|
||||
{
|
||||
// Unauthenticated messages from a vanilla socket shouldn't be received
|
||||
void *server = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "WRONG", 5));
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
|
||||
|
||||
fd_t s = connect_socket (my_endpoint);
|
||||
|
||||
// send anonymous ZMTP/1.0 greeting
|
||||
send (s, "\x01\x00", 2, 0);
|
||||
// send sneaky message that shouldn't be received
|
||||
send (s, "\x08\x00sneaky\0", 9, 0);
|
||||
int timeout = 250;
|
||||
zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
|
||||
char *buf = s_recv (server);
|
||||
if (buf != NULL) {
|
||||
printf ("Received unauthenticated message: %s\n", buf);
|
||||
TEST_ASSERT_NULL (buf);
|
||||
}
|
||||
close (s);
|
||||
test_context_socket_close_zero_linger (server);
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_no_domain);
|
||||
RUN_TEST (test_wrong_domain_fails);
|
||||
RUN_TEST (test_success);
|
||||
RUN_TEST (test_vanilla_socket);
|
||||
return UNITY_END ();
|
||||
}
|
||||
211
tests/test_security_plain.cpp
Normal file
211
tests/test_security_plain.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
static void zap_handler (void *zap_)
|
||||
{
|
||||
// Process ZAP requests forever
|
||||
while (true) {
|
||||
char *version = s_recv (zap_);
|
||||
if (!version)
|
||||
break; // Terminating
|
||||
char *sequence = s_recv (zap_);
|
||||
char *domain = s_recv (zap_);
|
||||
char *address = s_recv (zap_);
|
||||
char *routing_id = s_recv (zap_);
|
||||
char *mechanism = s_recv (zap_);
|
||||
char *username = s_recv (zap_);
|
||||
char *password = s_recv (zap_);
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING ("1.0", version);
|
||||
TEST_ASSERT_EQUAL_STRING ("PLAIN", mechanism);
|
||||
TEST_ASSERT_EQUAL_STRING ("IDENT", routing_id);
|
||||
|
||||
send_string_expect_success (zap_, version, ZMQ_SNDMORE);
|
||||
send_string_expect_success (zap_, sequence, ZMQ_SNDMORE);
|
||||
if (streq (username, "admin") && streq (password, "password")) {
|
||||
send_string_expect_success (zap_, "200", ZMQ_SNDMORE);
|
||||
send_string_expect_success (zap_, "OK", ZMQ_SNDMORE);
|
||||
send_string_expect_success (zap_, "anonymous", ZMQ_SNDMORE);
|
||||
send_string_expect_success (zap_, "", 0);
|
||||
} else {
|
||||
send_string_expect_success (zap_, "400", ZMQ_SNDMORE);
|
||||
send_string_expect_success (zap_, "Invalid username or password",
|
||||
ZMQ_SNDMORE);
|
||||
send_string_expect_success (zap_, "", ZMQ_SNDMORE);
|
||||
send_string_expect_success (zap_, "", 0);
|
||||
}
|
||||
free (version);
|
||||
free (sequence);
|
||||
free (domain);
|
||||
free (address);
|
||||
free (routing_id);
|
||||
free (mechanism);
|
||||
free (username);
|
||||
free (password);
|
||||
}
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (zap_));
|
||||
}
|
||||
|
||||
void *zap_thread;
|
||||
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
static void setup_zap_handler ()
|
||||
{
|
||||
// Spawn ZAP handler
|
||||
// We create and bind ZAP socket in main thread to avoid case
|
||||
// where child thread does not start up fast enough.
|
||||
void *handler = zmq_socket (get_test_context (), ZMQ_REP);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (handler, "inproc://zeromq.zap.01"));
|
||||
zap_thread = zmq_threadstart (&zap_handler, handler);
|
||||
}
|
||||
|
||||
static void teardown_zap_handler ()
|
||||
{
|
||||
// Wait until ZAP handler terminates
|
||||
zmq_threadclose (zap_thread);
|
||||
}
|
||||
|
||||
const char domain[] = "test";
|
||||
|
||||
void *server;
|
||||
|
||||
static void setup_server ()
|
||||
{
|
||||
// Server socket will accept connections
|
||||
server = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ROUTING_ID, "IDENT", 6));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, domain, strlen (domain)));
|
||||
const int as_server = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (server, ZMQ_PLAIN_SERVER, &as_server, sizeof (int)));
|
||||
bind_loopback_ipv4 (server, my_endpoint, sizeof my_endpoint);
|
||||
}
|
||||
|
||||
static void teardown_server ()
|
||||
{
|
||||
test_context_socket_close (server);
|
||||
}
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
setup_test_context ();
|
||||
setup_zap_handler ();
|
||||
setup_server ();
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
teardown_server ();
|
||||
teardown_test_context ();
|
||||
teardown_zap_handler ();
|
||||
}
|
||||
|
||||
void test_plain_success ()
|
||||
{
|
||||
// Check PLAIN security with correct username/password
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
const char username[] = "admin";
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, username, strlen (username)));
|
||||
const char password[] = "password";
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, password, strlen (password)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
bounce (server, client);
|
||||
test_context_socket_close (client);
|
||||
}
|
||||
|
||||
void test_plain_client_as_server_fails ()
|
||||
{
|
||||
// Check PLAIN security with badly configured client (as_server)
|
||||
// This will be caught by the plain_server class, not passed to ZAP
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_ZAP_DOMAIN, domain, strlen (domain)));
|
||||
const int as_server = 1;
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PLAIN_SERVER, &as_server, sizeof (int)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
expect_bounce_fail (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
}
|
||||
|
||||
void test_plain_wrong_credentials_fails ()
|
||||
{
|
||||
// Check PLAIN security -- failed authentication
|
||||
void *client = test_context_socket (ZMQ_DEALER);
|
||||
const char username[] = "wronguser";
|
||||
const char password[] = "wrongpass";
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, username, strlen (username)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, password, strlen (password)));
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (client, my_endpoint));
|
||||
expect_bounce_fail (server, client);
|
||||
test_context_socket_close_zero_linger (client);
|
||||
}
|
||||
|
||||
void test_plain_vanilla_socket ()
|
||||
{
|
||||
// Unauthenticated messages from a vanilla socket shouldn't be received
|
||||
fd_t s = connect_socket (my_endpoint);
|
||||
// send anonymous ZMTP/1.0 greeting
|
||||
send (s, "\x01\x00", 2, 0);
|
||||
// send sneaky message that shouldn't be received
|
||||
send (s, "\x08\x00sneaky\0", 9, 0);
|
||||
int timeout = 250;
|
||||
zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
|
||||
char *buf = s_recv (server);
|
||||
if (buf != NULL) {
|
||||
printf ("Received unauthenticated message: %s\n", buf);
|
||||
TEST_ASSERT_NULL (buf);
|
||||
}
|
||||
close (s);
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_plain_success);
|
||||
RUN_TEST (test_plain_client_as_server_fails);
|
||||
RUN_TEST (test_plain_wrong_credentials_fails);
|
||||
RUN_TEST (test_plain_vanilla_socket);
|
||||
return UNITY_END ();
|
||||
}
|
||||
472
tests/test_security_zap.cpp
Normal file
472
tests/test_security_zap.cpp
Normal file
@@ -0,0 +1,472 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil_security.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
static void zap_handler_wrong_version (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_wrong_version);
|
||||
}
|
||||
|
||||
static void zap_handler_wrong_request_id (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_wrong_request_id);
|
||||
}
|
||||
|
||||
static void zap_handler_wrong_status_invalid (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_status_invalid);
|
||||
}
|
||||
|
||||
static void zap_handler_wrong_status_temporary_failure (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_status_temporary_failure);
|
||||
}
|
||||
|
||||
static void zap_handler_wrong_status_internal_error (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_status_internal_error);
|
||||
}
|
||||
|
||||
static void zap_handler_too_many_parts (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_too_many_parts);
|
||||
}
|
||||
|
||||
static void zap_handler_disconnect (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_disconnect);
|
||||
}
|
||||
|
||||
static void zap_handler_do_not_recv (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_do_not_recv);
|
||||
}
|
||||
|
||||
static void zap_handler_do_not_send (void * /*unused_*/)
|
||||
{
|
||||
zap_handler_generic (zap_do_not_send);
|
||||
}
|
||||
|
||||
int expect_new_client_bounce_fail_and_count_monitor_events (
|
||||
char *my_endpoint_,
|
||||
void *server_,
|
||||
socket_config_fn socket_config_,
|
||||
void *socket_config_data_,
|
||||
void **client_mon_,
|
||||
void *server_mon_,
|
||||
int expected_server_event_,
|
||||
int expected_server_value_,
|
||||
int expected_client_event_ = 0,
|
||||
int expected_client_value_ = 0)
|
||||
{
|
||||
expect_new_client_bounce_fail (
|
||||
my_endpoint_, server_, socket_config_, socket_config_data_, client_mon_,
|
||||
expected_client_event_, expected_client_value_);
|
||||
|
||||
int events_received = 0;
|
||||
events_received = expect_monitor_event_multiple (
|
||||
server_mon_, expected_server_event_, expected_server_value_);
|
||||
|
||||
return events_received;
|
||||
}
|
||||
|
||||
void test_zap_unsuccessful (char *my_endpoint_,
|
||||
void *server_,
|
||||
void *server_mon_,
|
||||
int expected_server_event_,
|
||||
int expected_server_value_,
|
||||
socket_config_fn socket_config_,
|
||||
void *socket_config_data_,
|
||||
void **client_mon_ = NULL,
|
||||
int expected_client_event_ = 0,
|
||||
int expected_client_value_ = 0)
|
||||
{
|
||||
int server_events_received =
|
||||
expect_new_client_bounce_fail_and_count_monitor_events (
|
||||
my_endpoint_, server_, socket_config_, socket_config_data_, client_mon_,
|
||||
server_mon_, expected_server_event_, expected_server_value_,
|
||||
expected_client_event_, expected_client_value_);
|
||||
|
||||
// there may be more than one ZAP request due to repeated attempts by the
|
||||
// client (actually only in case if ZAP status code 300)
|
||||
TEST_ASSERT_TRUE (server_events_received == 0
|
||||
|| 1 <= zmq_atomic_counter_value (zap_requests_handled));
|
||||
}
|
||||
|
||||
void test_zap_unsuccessful_no_handler (char *my_endpoint_,
|
||||
void *server_,
|
||||
void *server_mon_,
|
||||
int expected_event_,
|
||||
int expected_err_,
|
||||
socket_config_fn socket_config_,
|
||||
void *socket_config_data_,
|
||||
void **client_mon_ = NULL)
|
||||
{
|
||||
const int events_received =
|
||||
expect_new_client_bounce_fail_and_count_monitor_events (
|
||||
my_endpoint_, server_, socket_config_, socket_config_data_, client_mon_,
|
||||
server_mon_, expected_event_, expected_err_);
|
||||
|
||||
// there may be more than one ZAP request due to repeated attempts by the
|
||||
// client
|
||||
TEST_ASSERT_GREATER_THAN_INT (0, events_received);
|
||||
}
|
||||
|
||||
void test_zap_protocol_error (char *my_endpoint_,
|
||||
void *server_,
|
||||
void *server_mon_,
|
||||
socket_config_fn socket_config_,
|
||||
void *socket_config_data_,
|
||||
int expected_error_)
|
||||
{
|
||||
test_zap_unsuccessful (my_endpoint_, server_, server_mon_,
|
||||
ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL, expected_error_,
|
||||
socket_config_, socket_config_data_);
|
||||
}
|
||||
|
||||
void test_zap_unsuccessful_status_300 (char *my_endpoint_,
|
||||
void *server_,
|
||||
void *server_mon_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_)
|
||||
{
|
||||
void *client_mon;
|
||||
test_zap_unsuccessful (
|
||||
my_endpoint_, server_, server_mon_, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 300,
|
||||
client_socket_config_, client_socket_config_data_, &client_mon);
|
||||
|
||||
// we can use a 0 timeout here, since the client socket is already closed
|
||||
assert_no_more_monitor_events_with_timeout (client_mon, 0);
|
||||
|
||||
test_context_socket_close (client_mon);
|
||||
}
|
||||
|
||||
void test_zap_unsuccessful_status_500 (char *my_endpoint_,
|
||||
void *server_,
|
||||
void *server_mon_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_)
|
||||
{
|
||||
test_zap_unsuccessful (my_endpoint_, server_, server_mon_,
|
||||
ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 500,
|
||||
client_socket_config_, client_socket_config_data_,
|
||||
NULL, ZMQ_EVENT_HANDSHAKE_FAILED_AUTH, 500);
|
||||
}
|
||||
|
||||
static void
|
||||
test_zap_protocol_error_closure (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_,
|
||||
void *server_socket_config_data_,
|
||||
zmq_thread_fn zap_handler_,
|
||||
int expected_failure_)
|
||||
{
|
||||
void *handler, *zap_thread, *server, *server_mon;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
|
||||
setup_context_and_server_side (
|
||||
&handler, &zap_thread, &server, &server_mon, my_endpoint, zap_handler_,
|
||||
server_socket_config_, server_socket_config_data_);
|
||||
test_zap_protocol_error (my_endpoint, server, server_mon,
|
||||
client_socket_config_, client_socket_config_data_,
|
||||
expected_failure_);
|
||||
shutdown_context_and_server_side (zap_thread, server, server_mon, handler);
|
||||
}
|
||||
|
||||
static void
|
||||
test_zap_protocol_error_wrong_version (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_,
|
||||
void *server_socket_config_data_)
|
||||
{
|
||||
test_zap_protocol_error_closure (
|
||||
server_socket_config_, client_socket_config_, client_socket_config_data_,
|
||||
server_socket_config_data_, &zap_handler_wrong_version,
|
||||
ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION);
|
||||
}
|
||||
|
||||
static void test_zap_protocol_error_wrong_request_id (
|
||||
socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_,
|
||||
void *server_socket_config_data_)
|
||||
{
|
||||
test_zap_protocol_error_closure (
|
||||
server_socket_config_, client_socket_config_, client_socket_config_data_,
|
||||
server_socket_config_data_, &zap_handler_wrong_request_id,
|
||||
ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID);
|
||||
}
|
||||
|
||||
static void test_zap_protocol_error_wrong_status_invalid (
|
||||
socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_,
|
||||
void *server_socket_config_data_)
|
||||
{
|
||||
test_zap_protocol_error_closure (
|
||||
server_socket_config_, client_socket_config_, client_socket_config_data_,
|
||||
server_socket_config_data_, &zap_handler_wrong_status_invalid,
|
||||
ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_zap_protocol_error_too_many_parts (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_,
|
||||
void *server_socket_config_data_)
|
||||
{
|
||||
test_zap_protocol_error_closure (
|
||||
server_socket_config_, client_socket_config_, client_socket_config_data_,
|
||||
server_socket_config_data_, &zap_handler_too_many_parts,
|
||||
ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY);
|
||||
}
|
||||
|
||||
// TODO the failed status (300/500) should be observable as monitoring events on the client side as well (they are
|
||||
// already transmitted as an ERROR message)
|
||||
|
||||
static void
|
||||
test_zap_wrong_status_temporary_failure (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_,
|
||||
void *server_socket_config_data_)
|
||||
{
|
||||
void *handler, *zap_thread, *server, *server_mon;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
setup_context_and_server_side (
|
||||
&handler, &zap_thread, &server, &server_mon, my_endpoint,
|
||||
&zap_handler_wrong_status_temporary_failure, server_socket_config_,
|
||||
server_socket_config_data_);
|
||||
test_zap_unsuccessful_status_300 (my_endpoint, server, server_mon,
|
||||
client_socket_config_,
|
||||
client_socket_config_data_);
|
||||
shutdown_context_and_server_side (zap_thread, server, server_mon, handler);
|
||||
}
|
||||
|
||||
static void
|
||||
test_zap_wrong_status_internal_error (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_)
|
||||
{
|
||||
void *handler, *zap_thread, *server, *server_mon;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
setup_context_and_server_side (
|
||||
&handler, &zap_thread, &server, &server_mon, my_endpoint,
|
||||
&zap_handler_wrong_status_internal_error, server_socket_config_);
|
||||
test_zap_unsuccessful_status_500 (my_endpoint, server, server_mon,
|
||||
client_socket_config_,
|
||||
client_socket_config_data_);
|
||||
shutdown_context_and_server_side (zap_thread, server, server_mon, handler);
|
||||
}
|
||||
|
||||
static void
|
||||
test_zap_unsuccesful_no_handler_started (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_,
|
||||
void *server_socket_config_data_)
|
||||
{
|
||||
#ifdef ZMQ_ZAP_ENFORCE_DOMAIN
|
||||
void *handler, *zap_thread, *server, *server_mon;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
// TODO this looks wrong, where will the enforce value be used?
|
||||
|
||||
// no ZAP handler
|
||||
int enforce = 1;
|
||||
setup_context_and_server_side (
|
||||
&handler, &zap_thread, &server, &server_mon, my_endpoint, NULL,
|
||||
server_socket_config_,
|
||||
server_socket_config_data_ ? server_socket_config_data_ : &enforce);
|
||||
test_zap_unsuccessful_no_handler (
|
||||
my_endpoint, server, server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL,
|
||||
EFAULT, client_socket_config_, client_socket_config_data_);
|
||||
shutdown_context_and_server_side (zap_thread, server, server_mon, handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
test_zap_unsuccesful_no_handler_closure (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_,
|
||||
zmq_thread_fn zap_handler_func_,
|
||||
bool zap_handler_disconnected_ = false)
|
||||
{
|
||||
void *handler, *zap_thread, *server, *server_mon;
|
||||
char my_endpoint[MAX_SOCKET_STRING];
|
||||
setup_context_and_server_side (&handler, &zap_thread, &server, &server_mon,
|
||||
my_endpoint, zap_handler_func_,
|
||||
server_socket_config_);
|
||||
test_zap_unsuccessful_no_handler (
|
||||
my_endpoint, server, server_mon, ZMQ_EVENT_HANDSHAKE_FAILED_NO_DETAIL,
|
||||
EPIPE, client_socket_config_, client_socket_config_data_);
|
||||
shutdown_context_and_server_side (zap_thread, server, server_mon, handler,
|
||||
zap_handler_disconnected_);
|
||||
}
|
||||
|
||||
static void
|
||||
test_zap_unsuccesful_disconnect (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_)
|
||||
{
|
||||
test_zap_unsuccesful_no_handler_closure (
|
||||
server_socket_config_, client_socket_config_, client_socket_config_data_,
|
||||
&zap_handler_disconnect, true);
|
||||
}
|
||||
|
||||
static void
|
||||
test_zap_unsuccesful_do_not_recv (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_)
|
||||
{
|
||||
test_zap_unsuccesful_no_handler_closure (
|
||||
server_socket_config_, client_socket_config_, client_socket_config_data_,
|
||||
&zap_handler_do_not_recv);
|
||||
}
|
||||
|
||||
static void
|
||||
test_zap_unsuccesful_do_not_send (socket_config_fn server_socket_config_,
|
||||
socket_config_fn client_socket_config_,
|
||||
void *client_socket_config_data_)
|
||||
{
|
||||
test_zap_unsuccesful_no_handler_closure (
|
||||
server_socket_config_, client_socket_config_, client_socket_config_data_,
|
||||
&zap_handler_do_not_send);
|
||||
}
|
||||
|
||||
#define DEFINE_ZAP_ERROR_TESTS( \
|
||||
name_, server_socket_config_, server_socket_config_data_, \
|
||||
client_socket_config_, client_socket_config_data_) \
|
||||
void test_zap_protocol_error_wrong_version_##name_ () \
|
||||
{ \
|
||||
test_zap_protocol_error_wrong_version ( \
|
||||
server_socket_config_, client_socket_config_, \
|
||||
client_socket_config_data_, server_socket_config_data_); \
|
||||
} \
|
||||
void test_zap_protocol_error_wrong_request_id_##name_ () \
|
||||
{ \
|
||||
test_zap_protocol_error_wrong_request_id ( \
|
||||
server_socket_config_, client_socket_config_, \
|
||||
client_socket_config_data_, server_socket_config_data_); \
|
||||
} \
|
||||
void test_zap_protocol_error_wrong_status_invalid_##name_ () \
|
||||
{ \
|
||||
test_zap_protocol_error_wrong_status_invalid ( \
|
||||
server_socket_config_, client_socket_config_, \
|
||||
client_socket_config_data_, server_socket_config_data_); \
|
||||
} \
|
||||
void test_zap_protocol_error_too_many_parts_##name_ () \
|
||||
{ \
|
||||
test_zap_protocol_error_too_many_parts ( \
|
||||
server_socket_config_, client_socket_config_, \
|
||||
client_socket_config_data_, server_socket_config_data_); \
|
||||
} \
|
||||
void test_zap_wrong_status_temporary_failure_##name_ () \
|
||||
{ \
|
||||
test_zap_wrong_status_temporary_failure ( \
|
||||
server_socket_config_, client_socket_config_, \
|
||||
client_socket_config_data_, server_socket_config_data_); \
|
||||
} \
|
||||
void test_zap_wrong_status_internal_error_##name_ () \
|
||||
{ \
|
||||
test_zap_wrong_status_internal_error (server_socket_config_, \
|
||||
client_socket_config_, \
|
||||
client_socket_config_data_); \
|
||||
} \
|
||||
void test_zap_unsuccessful_no_handler_started_##name_ () \
|
||||
{ \
|
||||
test_zap_unsuccesful_no_handler_started ( \
|
||||
server_socket_config_, client_socket_config_, \
|
||||
client_socket_config_data_, server_socket_config_data_); \
|
||||
} \
|
||||
void test_zap_unsuccessful_disconnect_##name_ () \
|
||||
{ \
|
||||
test_zap_unsuccesful_disconnect (server_socket_config_, \
|
||||
client_socket_config_, \
|
||||
client_socket_config_data_); \
|
||||
} \
|
||||
void test_zap_unsuccessful_do_not_recv_##name_ () \
|
||||
{ \
|
||||
test_zap_unsuccesful_do_not_recv (server_socket_config_, \
|
||||
client_socket_config_, \
|
||||
client_socket_config_data_); \
|
||||
} \
|
||||
void test_zap_unsuccessful_do_not_send_##name_ () \
|
||||
{ \
|
||||
test_zap_unsuccesful_do_not_send (server_socket_config_, \
|
||||
client_socket_config_, \
|
||||
client_socket_config_data_); \
|
||||
}
|
||||
|
||||
DEFINE_ZAP_ERROR_TESTS (
|
||||
null, &socket_config_null_server, NULL, &socket_config_null_client, NULL)
|
||||
|
||||
DEFINE_ZAP_ERROR_TESTS (
|
||||
plain, &socket_config_plain_server, NULL, &socket_config_plain_client, NULL)
|
||||
|
||||
static curve_client_data_t curve_client_data = {
|
||||
valid_server_public, valid_client_public, valid_client_secret};
|
||||
|
||||
DEFINE_ZAP_ERROR_TESTS (curve,
|
||||
&socket_config_curve_server,
|
||||
valid_server_secret,
|
||||
&socket_config_curve_client,
|
||||
&curve_client_data)
|
||||
|
||||
#define RUN_ZAP_ERROR_TESTS(name_) \
|
||||
{ \
|
||||
RUN_TEST (test_zap_protocol_error_wrong_version_##name_); \
|
||||
RUN_TEST (test_zap_protocol_error_wrong_request_id_##name_); \
|
||||
RUN_TEST (test_zap_protocol_error_wrong_status_invalid_##name_); \
|
||||
RUN_TEST (test_zap_protocol_error_too_many_parts_##name_); \
|
||||
RUN_TEST (test_zap_wrong_status_temporary_failure_##name_); \
|
||||
RUN_TEST (test_zap_wrong_status_internal_error_##name_); \
|
||||
RUN_TEST (test_zap_unsuccessful_no_handler_started_##name_); \
|
||||
RUN_TEST (test_zap_unsuccessful_disconnect_##name_); \
|
||||
RUN_TEST (test_zap_unsuccessful_do_not_recv_##name_); \
|
||||
RUN_TEST (test_zap_unsuccessful_do_not_send_##name_); \
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
if (zmq_has ("curve")) {
|
||||
setup_testutil_security_curve ();
|
||||
}
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_ZAP_ERROR_TESTS (null);
|
||||
RUN_ZAP_ERROR_TESTS (plain);
|
||||
if (zmq_has ("curve")) {
|
||||
RUN_ZAP_ERROR_TESTS (curve);
|
||||
}
|
||||
return UNITY_END ();
|
||||
}
|
||||
185
tests/test_setsockopt.cpp
Normal file
185
tests/test_setsockopt.cpp
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
SETUP_TEARDOWN_TESTCONTEXT
|
||||
|
||||
void test_setsockopt_tcp_recv_buffer ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
int val = 0;
|
||||
size_t placeholder = sizeof (val);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_RCVBUF, &val, &placeholder));
|
||||
TEST_ASSERT_EQUAL_INT (-1, val);
|
||||
|
||||
val = 16384;
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (socket, ZMQ_RCVBUF, &val, sizeof (val)));
|
||||
TEST_ASSERT_EQUAL_INT (16384, val);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_RCVBUF, &val, &placeholder));
|
||||
TEST_ASSERT_EQUAL_INT (16384, val);
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_setsockopt_tcp_send_buffer ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
int val = 0;
|
||||
size_t placeholder = sizeof (val);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_SNDBUF, &val, &placeholder));
|
||||
TEST_ASSERT_EQUAL_INT (-1, val);
|
||||
|
||||
val = 16384;
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (socket, ZMQ_SNDBUF, &val, sizeof (val)));
|
||||
TEST_ASSERT_EQUAL_INT (16384, val);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_SNDBUF, &val, &placeholder));
|
||||
TEST_ASSERT_EQUAL_INT (16384, val);
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_setsockopt_use_fd ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
int val = 0;
|
||||
size_t placeholder = sizeof (val);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_USE_FD, &val, &placeholder));
|
||||
TEST_ASSERT_EQUAL_INT (-1, val);
|
||||
|
||||
val = 3;
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (socket, ZMQ_USE_FD, &val, sizeof (val)));
|
||||
TEST_ASSERT_EQUAL_INT (3, val);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_USE_FD, &val, &placeholder));
|
||||
TEST_ASSERT_EQUAL_INT (3, val);
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
#define BOUNDDEVBUFSZ 16
|
||||
void test_setsockopt_bindtodevice ()
|
||||
{
|
||||
void *socket = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
#ifdef ZMQ_BINDTODEVICE
|
||||
char devname[BOUNDDEVBUFSZ];
|
||||
size_t buflen = BOUNDDEVBUFSZ;
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_BINDTODEVICE, devname, &buflen));
|
||||
TEST_ASSERT_EQUAL_INT8 ('\0', devname[0]);
|
||||
TEST_ASSERT_EQUAL_UINT (1, buflen);
|
||||
|
||||
sprintf (devname, "testdev");
|
||||
buflen = strlen (devname);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (socket, ZMQ_BINDTODEVICE, devname, buflen));
|
||||
|
||||
buflen = BOUNDDEVBUFSZ;
|
||||
memset (devname, 0, buflen);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_BINDTODEVICE, devname, &buflen));
|
||||
TEST_ASSERT_EQUAL_STRING_LEN ("testdev", devname, buflen);
|
||||
#endif
|
||||
|
||||
test_context_socket_close (socket);
|
||||
}
|
||||
|
||||
void test_setsockopt_priority ()
|
||||
{
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
#ifdef ZMQ_HAVE_SO_PRIORITY
|
||||
void *socket = test_context_socket (ZMQ_PUSH);
|
||||
|
||||
int val = 5;
|
||||
size_t placeholder = sizeof (val);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_PRIORITY, &val, &placeholder));
|
||||
TEST_ASSERT_EQUAL_INT (0, val);
|
||||
|
||||
val = 3;
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_setsockopt (socket, ZMQ_PRIORITY, &val, sizeof (val)));
|
||||
TEST_ASSERT_EQUAL_INT (3, val);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (
|
||||
zmq_getsockopt (socket, ZMQ_PRIORITY, &val, &placeholder));
|
||||
TEST_ASSERT_EQUAL_INT (3, val);
|
||||
|
||||
test_context_socket_close (socket);
|
||||
#else
|
||||
TEST_IGNORE_MESSAGE ("libzmq without ZMQ_PRIORITY support, "
|
||||
"ignoring setsockopt_priority test");
|
||||
#endif
|
||||
#else
|
||||
TEST_IGNORE_MESSAGE ("libzmq without DRAFT support, ignoring "
|
||||
"setsockopt_priority test");
|
||||
#endif
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment ();
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_setsockopt_tcp_recv_buffer);
|
||||
RUN_TEST (test_setsockopt_tcp_send_buffer);
|
||||
RUN_TEST (test_setsockopt_use_fd);
|
||||
RUN_TEST (test_setsockopt_bindtodevice);
|
||||
RUN_TEST (test_setsockopt_priority);
|
||||
return UNITY_END ();
|
||||
}
|
||||
97
tests/test_shutdown_stress.cpp
Normal file
97
tests/test_shutdown_stress.cpp
Normal file
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
#define THREAD_COUNT 100
|
||||
|
||||
struct thread_data
|
||||
{
|
||||
char endpoint[MAX_SOCKET_STRING];
|
||||
};
|
||||
|
||||
extern "C" {
|
||||
static void worker (void *data_)
|
||||
{
|
||||
const thread_data *const tdata = static_cast<const thread_data *> (data_);
|
||||
|
||||
void *socket = zmq_socket (get_test_context (), ZMQ_SUB);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (socket, tdata->endpoint));
|
||||
|
||||
// Start closing the socket while the connecting process is underway.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (socket));
|
||||
}
|
||||
}
|
||||
|
||||
void test_shutdown_stress ()
|
||||
{
|
||||
void *threads[THREAD_COUNT];
|
||||
|
||||
for (int j = 0; j != 10; j++) {
|
||||
// Check the shutdown with many parallel I/O threads.
|
||||
struct thread_data tdata;
|
||||
setup_test_context ();
|
||||
zmq_ctx_set (get_test_context (), ZMQ_IO_THREADS, 7);
|
||||
|
||||
void *socket = test_context_socket (ZMQ_PUB);
|
||||
|
||||
bind_loopback_ipv4 (socket, tdata.endpoint, sizeof (tdata.endpoint));
|
||||
|
||||
for (int i = 0; i != THREAD_COUNT; i++) {
|
||||
threads[i] = zmq_threadstart (&worker, &tdata);
|
||||
}
|
||||
|
||||
for (int i = 0; i != THREAD_COUNT; i++) {
|
||||
zmq_threadclose (threads[i]);
|
||||
}
|
||||
|
||||
test_context_socket_close (socket);
|
||||
|
||||
teardown_test_context ();
|
||||
}
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
setup_test_environment (180);
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_shutdown_stress);
|
||||
return UNITY_END ();
|
||||
}
|
||||
99
tests/test_shutdown_stress_tipc.cpp
Normal file
99
tests/test_shutdown_stress_tipc.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
#include "testutil_unity.hpp"
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
#define THREAD_COUNT 100
|
||||
|
||||
extern "C" {
|
||||
static void *worker (void *ctx)
|
||||
{
|
||||
void *s = zmq_socket (ctx, ZMQ_SUB);
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (s, "tipc://{5560,0}@0.0.0"));
|
||||
|
||||
// Start closing the socket while the connecting process is underway.
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_close (s));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void test_shutdown_stress_tipc ()
|
||||
{
|
||||
void *s1;
|
||||
int i;
|
||||
int j;
|
||||
pthread_t threads[THREAD_COUNT];
|
||||
|
||||
for (j = 0; j != 10; j++) {
|
||||
// Check the shutdown with many parallel I/O threads.
|
||||
setup_test_context ();
|
||||
zmq_ctx_set (get_test_context (), ZMQ_IO_THREADS, 7);
|
||||
|
||||
s1 = test_context_socket (ZMQ_PUB);
|
||||
|
||||
TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (s1, "tipc://{5560,0,0}"));
|
||||
|
||||
for (i = 0; i != THREAD_COUNT; i++) {
|
||||
TEST_ASSERT_SUCCESS_RAW_ERRNO (
|
||||
pthread_create (&threads[i], NULL, worker, get_test_context ()));
|
||||
}
|
||||
|
||||
for (i = 0; i != THREAD_COUNT; i++) {
|
||||
TEST_ASSERT_SUCCESS_RAW_ERRNO (pthread_join (threads[i], NULL));
|
||||
}
|
||||
|
||||
test_context_socket_close (s1);
|
||||
|
||||
teardown_test_context ();
|
||||
}
|
||||
}
|
||||
|
||||
int main ()
|
||||
{
|
||||
if (!is_tipc_available ()) {
|
||||
printf ("TIPC environment unavailable, skipping test\n");
|
||||
return 77;
|
||||
}
|
||||
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_shutdown_stress_tipc);
|
||||
return UNITY_END ();
|
||||
}
|
||||
145
tests/test_socket_null.cpp
Normal file
145
tests/test_socket_null.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
|
||||
|
||||
This file is part of libzmq, the ZeroMQ core engine in C++.
|
||||
|
||||
libzmq is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU Lesser General Public License (LGPL) as published
|
||||
by the Free Software Foundation; either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
As a special exception, the Contributors give you permission to link
|
||||
this library with independent modules to produce an executable,
|
||||
regardless of the license terms of these independent modules, and to
|
||||
copy and distribute the resulting executable under terms of your choice,
|
||||
provided that you also meet, for each linked independent module, the
|
||||
terms and conditions of the license of that module. An independent
|
||||
module is a module which is not derived from or based on this library.
|
||||
If you modify this library, you must extend this exception to your
|
||||
version of the library.
|
||||
|
||||
libzmq is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
|
||||
License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "testutil.hpp"
|
||||
|
||||
#include <unity.h>
|
||||
|
||||
void setUp ()
|
||||
{
|
||||
}
|
||||
|
||||
void tearDown ()
|
||||
{
|
||||
}
|
||||
|
||||
// tests all socket-related functions with a NULL socket argument
|
||||
void test_zmq_socket_null_context ()
|
||||
{
|
||||
TEST_ASSERT_NULL (zmq_socket (NULL, ZMQ_PAIR));
|
||||
TEST_ASSERT_EQUAL_INT (EFAULT, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
void test_zmq_close_null_socket ()
|
||||
{
|
||||
int rc = zmq_close (NULL);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
void test_zmq_setsockopt_null_socket ()
|
||||
{
|
||||
int hwm = 100;
|
||||
size_t hwm_size = sizeof hwm;
|
||||
int rc = zmq_setsockopt (NULL, ZMQ_SNDHWM, &hwm, hwm_size);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
void test_zmq_getsockopt_null_socket ()
|
||||
{
|
||||
int hwm;
|
||||
size_t hwm_size = sizeof hwm;
|
||||
int rc = zmq_getsockopt (NULL, ZMQ_SNDHWM, &hwm, &hwm_size);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
void test_zmq_socket_monitor_null_socket ()
|
||||
{
|
||||
int rc = zmq_socket_monitor (NULL, "inproc://monitor", ZMQ_EVENT_ALL);
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
void test_zmq_join_null_socket ()
|
||||
{
|
||||
int rc = zmq_join (NULL, "group");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
void test_zmq_leave_null_socket ()
|
||||
{
|
||||
int rc = zmq_leave (NULL, "group");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void test_zmq_bind_null_socket ()
|
||||
{
|
||||
int rc = zmq_bind (NULL, "inproc://socket");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
void test_zmq_connect_null_socket ()
|
||||
{
|
||||
int rc = zmq_connect (NULL, "inproc://socket");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
void test_zmq_unbind_null_socket ()
|
||||
{
|
||||
int rc = zmq_unbind (NULL, "inproc://socket");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
void test_zmq_disconnect_null_socket ()
|
||||
{
|
||||
int rc = zmq_disconnect (NULL, "inproc://socket");
|
||||
TEST_ASSERT_EQUAL_INT (-1, rc);
|
||||
TEST_ASSERT_EQUAL_INT (ENOTSOCK, errno); // TODO use EINVAL instead?
|
||||
}
|
||||
|
||||
int main (void)
|
||||
{
|
||||
UNITY_BEGIN ();
|
||||
RUN_TEST (test_zmq_socket_null_context);
|
||||
RUN_TEST (test_zmq_close_null_socket);
|
||||
RUN_TEST (test_zmq_setsockopt_null_socket);
|
||||
RUN_TEST (test_zmq_getsockopt_null_socket);
|
||||
RUN_TEST (test_zmq_socket_monitor_null_socket);
|
||||
RUN_TEST (test_zmq_bind_null_socket);
|
||||
RUN_TEST (test_zmq_connect_null_socket);
|
||||
RUN_TEST (test_zmq_unbind_null_socket);
|
||||
RUN_TEST (test_zmq_disconnect_null_socket);
|
||||
|
||||
#ifdef ZMQ_BUILD_DRAFT_API
|
||||
RUN_TEST (test_zmq_join_null_socket);
|
||||
RUN_TEST (test_zmq_leave_null_socket);
|
||||
#endif
|
||||
|
||||
return UNITY_END ();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user