From b18d28eec1992d2f3719b0d720551ae255e719d0 Mon Sep 17 00:00:00 2001 From: Simon Giesecke Date: Sat, 2 Feb 2019 12:11:11 +0100 Subject: [PATCH] Problem: no tests for v2 monitor events and test_socket_monitor_versioned Solution: add first test case --- tests/test_monitor.cpp | 70 ++++++++++++++++++++ tests/testutil_monitoring.hpp | 120 ++++++++++++++++++++++++++++++++++ 2 files changed, 190 insertions(+) diff --git a/tests/test_monitor.cpp b/tests/test_monitor.cpp index df27fc46..698a5cc2 100644 --- a/tests/test_monitor.cpp +++ b/tests/test_monitor.cpp @@ -114,6 +114,71 @@ void test_monitor_basic () test_context_socket_close_zero_linger (server_mon); } +#ifdef ZMQ_BUILD_DRAFT_API +void test_monitor_versioned_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_versioned ( + client, "inproc://monitor-client", ZMQ_EVENT_ALL_V2, 2)); + TEST_ASSERT_SUCCESS_ERRNO (zmq_socket_monitor_versioned ( + server, "inproc://monitor-server", ZMQ_EVENT_ALL_V2, 2)); + + // 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 + int64_t event = get_monitor_event_v2 (client_mon, NULL, NULL, NULL); + if (event == ZMQ_EVENT_CONNECT_DELAYED) + event = get_monitor_event_v2 (client_mon, NULL, NULL, NULL); + assert (event == ZMQ_EVENT_CONNECTED); + expect_monitor_event_v2 (client_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED); + expect_monitor_event_v2 (client_mon, ZMQ_EVENT_MONITOR_STOPPED); + + // This is the flow of server events + expect_monitor_event_v2 (server_mon, ZMQ_EVENT_LISTENING); + expect_monitor_event_v2 (server_mon, ZMQ_EVENT_ACCEPTED); + expect_monitor_event_v2 (server_mon, ZMQ_EVENT_HANDSHAKE_SUCCEEDED); + 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); + } + + // 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); +} +#endif + int main () { setup_test_environment (); @@ -121,5 +186,10 @@ int main () UNITY_BEGIN (); RUN_TEST (test_monitor_invalid_protocol_fails); RUN_TEST (test_monitor_basic); + +#ifdef ZMQ_BUILD_DRAFT_API + RUN_TEST (test_monitor_versioned_basic); +#endif + return UNITY_END (); } diff --git a/tests/testutil_monitoring.hpp b/tests/testutil_monitoring.hpp index 3a42b621..216e1d29 100644 --- a/tests/testutil_monitoring.hpp +++ b/tests/testutil_monitoring.hpp @@ -32,6 +32,9 @@ #include "testutil.hpp" +#define __STDC_FORMAT_MACROS +#include + // General, i.e. non-security specific, monitor utilities // Read one event off the monitor socket; return value and address @@ -190,4 +193,121 @@ int expect_monitor_event_multiple (void *server_mon_, return count_of_expected_events; } +#ifdef ZMQ_BUILD_DRAFT_API +static int64_t get_monitor_event_internal_v2 (void *monitor_, + uint64_t *value_, + char **local_address_, + char **remote_address_, + int recv_flag_) +{ + // First frame in message contains event number + zmq_msg_t msg; + zmq_msg_init (&msg); + if (zmq_msg_recv (&msg, monitor_, recv_flag_) == -1) { + assert (errno == EAGAIN); + return -1; // timed out or no message available + } + assert (zmq_msg_more (&msg)); + assert (sizeof (uint64_t) == zmq_msg_size (&msg)); + + uint64_t event; + memcpy (&event, zmq_msg_data (&msg), sizeof event); + + // Second frame in message contains event value + zmq_msg_init (&msg); + if (zmq_msg_recv (&msg, monitor_, recv_flag_) == -1) { + assert (errno == EAGAIN); + return -1; // timed out or no message available + } + assert (zmq_msg_more (&msg)); + assert (sizeof (uint64_t) == zmq_msg_size (&msg)); + + if (value_) + memcpy (value_, zmq_msg_data (&msg), sizeof *value_); + + // Third frame in message contains local address + zmq_msg_init (&msg); + int res = zmq_msg_recv (&msg, monitor_, recv_flag_) == -1; + assert (res != -1); + assert (zmq_msg_more (&msg)); + + if (local_address_) { + uint8_t *data = (uint8_t *) zmq_msg_data (&msg); + size_t size = zmq_msg_size (&msg); + *local_address_ = (char *) malloc (size + 1); + memcpy (*local_address_, data, size); + *local_address_[size] = 0; + } + + // Fourth and last frame in message contains remote address + zmq_msg_init (&msg); + res = zmq_msg_recv (&msg, monitor_, recv_flag_) == -1; + assert (res != -1); + assert (!zmq_msg_more (&msg)); + + if (remote_address_) { + uint8_t *data = (uint8_t *) zmq_msg_data (&msg); + size_t size = zmq_msg_size (&msg); + *remote_address_ = (char *) malloc (size + 1); + memcpy (*remote_address_, data, size); + *remote_address_[size] = 0; + } + return event; +} + +int64_t get_monitor_event_with_timeout_v2 (void *monitor_, + uint64_t *value_, + char **local_address_, + char **remote_address_, + int timeout_) +{ + int res; + if (timeout_ == -1) { + // process infinite timeout in small steps to allow the user + // to see some information on the console + + int timeout_step = 250; + int wait_time = 0; + zmq_setsockopt (monitor_, ZMQ_RCVTIMEO, &timeout_step, + sizeof (timeout_step)); + while ((res = get_monitor_event_internal_v2 ( + monitor_, value_, local_address_, remote_address_, 0)) + == -1) { + wait_time += timeout_step; + fprintf (stderr, "Still waiting for monitor event after %i ms\n", + wait_time); + } + } else { + zmq_setsockopt (monitor_, ZMQ_RCVTIMEO, &timeout_, sizeof (timeout_)); + res = get_monitor_event_internal_v2 (monitor_, value_, local_address_, + remote_address_, 0); + } + int timeout_infinite = -1; + zmq_setsockopt (monitor_, ZMQ_RCVTIMEO, &timeout_infinite, + sizeof (timeout_infinite)); + return res; +} + +int64_t get_monitor_event_v2 (void *monitor_, + uint64_t *value_, + char **local_address_, + char **remote_address_) +{ + return get_monitor_event_with_timeout_v2 (monitor_, value_, local_address_, + remote_address_, -1); +} + +void expect_monitor_event_v2 (void *monitor_, int64_t expected_event_) +{ + int64_t event = get_monitor_event_v2 (monitor_, NULL, NULL, NULL); + if (event != expected_event_) { + fprintf (stderr, + "Expected monitor event %" PRIx64 " but received %" PRIx64 + "\n", + expected_event_, event); + assert (event == expected_event_); + } +} +#endif + #endif