mirror of
https://github.com/zeromq/cppzmq.git
synced 2025-10-18 11:39:03 +02:00

* Problem: Windows build broken because of multiple issues Windows issues: * missing includes files Solution: added missing <memory> and <unordered_map> Here <map> was replaced with <unordered_map> as there is no need for sorted map. * googletest fails because deprecation warning causing errors. Solution: D_SILENCE_TR1_NAMESPACE_DEPRECATION_WARNING option added. * googletest fails because by default, new Visual Studio projects link the C runtimes dynamically but Google Test links them statically. Solution: gtest_force_shared_crt=ON option added. Besides that adding appveyor.yml configuration to add Windows build to CI in order to prevent accidental Windows build breakage. For now only Debug configuration as Release requires more time to figure out. * Problem: Windows build takes too long Solution: disabling tests and perf tools * Problem: Windows unit_tests executable not finding lizmq dll. Solution: copy libzmq dll to build bin directory. * Problem: Windows build fails because wrong test path provided
232 lines
6.6 KiB
C++
232 lines
6.6 KiB
C++
#include <gtest/gtest.h>
|
|
#include <zmq.hpp>
|
|
|
|
#if defined(ZMQ_CPP11) && defined(ZMQ_BUILD_DRAFT_API)
|
|
|
|
#include <array>
|
|
#include <memory>
|
|
|
|
TEST(poller, create_destroy)
|
|
{
|
|
zmq::poller_t poller;
|
|
ASSERT_EQ(0u, poller.size ());
|
|
}
|
|
|
|
static_assert(!std::is_copy_constructible<zmq::poller_t>::value, "poller_t should not be copy-constructible");
|
|
static_assert(!std::is_copy_assignable<zmq::poller_t>::value, "poller_t should not be copy-assignable");
|
|
|
|
TEST(poller, move_construct_empty)
|
|
{
|
|
std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
|
|
zmq::poller_t b = std::move(*a);
|
|
|
|
ASSERT_EQ(0u, a->size ());
|
|
a.reset ();
|
|
ASSERT_EQ(0u, b.size ());
|
|
}
|
|
|
|
TEST(poller, move_assign_empty)
|
|
{
|
|
std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
|
|
zmq::poller_t b;
|
|
|
|
b = std::move(*a);
|
|
|
|
ASSERT_EQ(0u, a->size ());
|
|
a.reset ();
|
|
ASSERT_EQ(0u, b.size ());
|
|
}
|
|
|
|
TEST(poller, move_construct_non_empty)
|
|
{
|
|
zmq::context_t context;
|
|
zmq::socket_t socket{context, zmq::socket_type::router};
|
|
|
|
std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
|
|
a->add(socket, ZMQ_POLLIN, [](short) {});
|
|
zmq::poller_t b = std::move(*a);
|
|
|
|
ASSERT_EQ(0u, a->size ());
|
|
a.reset ();
|
|
ASSERT_EQ(1u, b.size ());
|
|
}
|
|
|
|
TEST(poller, move_assign_non_empty)
|
|
{
|
|
zmq::context_t context;
|
|
zmq::socket_t socket{context, zmq::socket_type::router};
|
|
|
|
std::unique_ptr<zmq::poller_t> a{new zmq::poller_t};
|
|
a->add(socket, ZMQ_POLLIN, [](short) {});
|
|
zmq::poller_t b;
|
|
|
|
b = std::move(*a);
|
|
|
|
ASSERT_EQ(0u, a->size ());
|
|
a.reset ();
|
|
ASSERT_EQ(1u, b.size ());
|
|
}
|
|
|
|
TEST(poller, add_handler)
|
|
{
|
|
zmq::context_t context;
|
|
zmq::socket_t socket{context, zmq::socket_type::router};
|
|
zmq::poller_t poller;
|
|
zmq::poller_t::handler_t handler;
|
|
ASSERT_NO_THROW(poller.add(socket, ZMQ_POLLIN, handler));
|
|
}
|
|
|
|
TEST(poller, add_handler_invalid_events_type)
|
|
{
|
|
zmq::context_t context;
|
|
zmq::socket_t socket{context, zmq::socket_type::router};
|
|
zmq::poller_t poller;
|
|
zmq::poller_t::handler_t handler;
|
|
short invalid_events_type = 2 << 10;
|
|
ASSERT_NO_THROW(poller.add(socket, invalid_events_type, handler));
|
|
}
|
|
|
|
TEST(poller, add_handler_twice_throws)
|
|
{
|
|
zmq::context_t context;
|
|
zmq::socket_t socket{context, zmq::socket_type::router};
|
|
zmq::poller_t poller;
|
|
zmq::poller_t::handler_t handler;
|
|
poller.add(socket, ZMQ_POLLIN, handler);
|
|
/// \todo the actual error code should be checked
|
|
ASSERT_THROW(poller.add(socket, ZMQ_POLLIN, handler), zmq::error_t);
|
|
}
|
|
|
|
TEST(poller, wait_with_no_handlers_throws)
|
|
{
|
|
zmq::poller_t poller;
|
|
/// \todo the actual error code should be checked
|
|
ASSERT_THROW(poller.wait(std::chrono::milliseconds{10}), zmq::error_t);
|
|
}
|
|
|
|
TEST(poller, remove_unregistered_throws)
|
|
{
|
|
zmq::context_t context;
|
|
zmq::socket_t socket{context, zmq::socket_type::router};
|
|
zmq::poller_t poller;
|
|
/// \todo the actual error code should be checked
|
|
ASSERT_THROW(poller.remove(socket), zmq::error_t);
|
|
}
|
|
|
|
/// \todo this should lead to an exception instead
|
|
TEST(poller, remove_registered_empty)
|
|
{
|
|
zmq::context_t context;
|
|
zmq::socket_t socket{context, zmq::socket_type::router};
|
|
zmq::poller_t poller;
|
|
poller.add(socket, ZMQ_POLLIN, zmq::poller_t::handler_t{});
|
|
ASSERT_NO_THROW(poller.remove(socket));
|
|
}
|
|
|
|
TEST(poller, remove_registered_non_empty)
|
|
{
|
|
zmq::context_t context;
|
|
zmq::socket_t socket{context, zmq::socket_type::router};
|
|
zmq::poller_t poller;
|
|
poller.add(socket, ZMQ_POLLIN, [](short) {});
|
|
ASSERT_NO_THROW(poller.remove(socket));
|
|
}
|
|
|
|
namespace {
|
|
|
|
class loopback_ip4_binder
|
|
{
|
|
public:
|
|
loopback_ip4_binder(zmq::socket_t &socket) { bind(socket); }
|
|
std::string endpoint() { return endpoint_; }
|
|
private:
|
|
// Helper function used in constructor
|
|
// as Gtest allows ASSERT_* only in void returning functions
|
|
// and constructor/destructor are not.
|
|
void bind(zmq::socket_t &socket)
|
|
{
|
|
ASSERT_NO_THROW(socket.bind("tcp://127.0.0.1:*"));
|
|
std::array<char, 100> endpoint{};
|
|
size_t endpoint_size = endpoint.size();
|
|
ASSERT_NO_THROW(socket.getsockopt(ZMQ_LAST_ENDPOINT, endpoint.data(),
|
|
&endpoint_size));
|
|
ASSERT_TRUE(endpoint_size < endpoint.size());
|
|
endpoint_ = std::string{endpoint.data()};
|
|
}
|
|
std::string endpoint_;
|
|
};
|
|
|
|
} //namespace
|
|
|
|
TEST(poller, poll_basic)
|
|
{
|
|
zmq::context_t context;
|
|
|
|
zmq::socket_t vent{context, zmq::socket_type::push};
|
|
auto endpoint = loopback_ip4_binder(vent).endpoint();
|
|
|
|
zmq::socket_t sink{context, zmq::socket_type::pull};
|
|
ASSERT_NO_THROW(sink.connect(endpoint));
|
|
|
|
ASSERT_NO_THROW(vent.send("Hi"));
|
|
|
|
zmq::poller_t poller;
|
|
bool message_received = false;
|
|
zmq::poller_t::handler_t handler = [&message_received](short events) {
|
|
ASSERT_TRUE(0 != (events & ZMQ_POLLIN));
|
|
message_received = true;
|
|
};
|
|
ASSERT_NO_THROW(poller.add(sink, ZMQ_POLLIN, handler));
|
|
ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
|
|
ASSERT_TRUE(message_received);
|
|
}
|
|
|
|
/// \todo this contains multiple test cases that should be split up
|
|
TEST(poller, client_server)
|
|
{
|
|
zmq::context_t context;
|
|
const std::string send_msg = "Hi";
|
|
|
|
// Setup server
|
|
zmq::socket_t server{context, zmq::socket_type::router};
|
|
auto endpoint = loopback_ip4_binder(server).endpoint();
|
|
|
|
// Setup poller
|
|
zmq::poller_t poller;
|
|
bool got_pollin = false;
|
|
bool got_pollout = false;
|
|
zmq::poller_t::handler_t handler = [&](short events) {
|
|
if (0 != (events & ZMQ_POLLIN)) {
|
|
zmq::message_t zmq_msg;
|
|
ASSERT_NO_THROW(server.recv(&zmq_msg)); // skip msg id
|
|
ASSERT_NO_THROW(server.recv(&zmq_msg)); // get message
|
|
std::string recv_msg(zmq_msg.data<char>(),
|
|
zmq_msg.size());
|
|
ASSERT_EQ(send_msg, recv_msg);
|
|
got_pollin = true;
|
|
} else if (0 != (events & ZMQ_POLLOUT)) {
|
|
got_pollout = true;
|
|
} else {
|
|
ASSERT_TRUE(false) << "Unexpected event type " << events;
|
|
}
|
|
};
|
|
ASSERT_NO_THROW(poller.add(server, ZMQ_POLLIN, handler));
|
|
|
|
// Setup client and send message
|
|
zmq::socket_t client{context, zmq::socket_type::dealer};
|
|
ASSERT_NO_THROW(client.connect(endpoint));
|
|
ASSERT_NO_THROW(client.send(send_msg));
|
|
|
|
ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
|
|
ASSERT_TRUE(got_pollin);
|
|
ASSERT_FALSE(got_pollout);
|
|
|
|
// Re-add server socket with pollout flag
|
|
ASSERT_NO_THROW(poller.remove(server));
|
|
ASSERT_NO_THROW(poller.add(server, ZMQ_POLLIN | ZMQ_POLLOUT, handler));
|
|
ASSERT_NO_THROW(poller.wait(std::chrono::milliseconds{-1}));
|
|
ASSERT_TRUE(got_pollout);
|
|
}
|
|
|
|
#endif
|