mirror of
https://github.com/boostorg/redis.git
synced 2026-01-19 04:42:09 +00:00
Progresses with coverage.
This commit is contained in:
@@ -38,6 +38,7 @@ add_executable(subscriber examples/subscriber.cpp)
|
||||
add_executable(subscriber_sync examples/subscriber_sync.cpp)
|
||||
add_executable(test_low_level tests/low_level.cpp)
|
||||
add_executable(test_connection tests/connection.cpp)
|
||||
add_executable(test_connection_push tests/connection_push.cpp)
|
||||
add_executable(low_level_sync tests/low_level_sync.cpp)
|
||||
|
||||
# Tests
|
||||
@@ -48,7 +49,7 @@ add_test(intro intro)
|
||||
add_test(intro_sync intro_sync)
|
||||
add_test(serialization serialization)
|
||||
add_test(test_low_level test_low_level)
|
||||
add_test(test_connection test_connection)
|
||||
add_test(test_connection_push test_connection_push)
|
||||
add_test(low_level_sync low_level_sync)
|
||||
|
||||
# Install
|
||||
|
||||
@@ -21,6 +21,7 @@ check_PROGRAMS += containers
|
||||
check_PROGRAMS += serialization
|
||||
check_PROGRAMS += test_low_level
|
||||
check_PROGRAMS += test_connection
|
||||
check_PROGRAMS += test_connection_push
|
||||
|
||||
EXTRA_PROGRAMS =
|
||||
if HAVE_COROUTINES
|
||||
@@ -45,6 +46,7 @@ intro_sync_SOURCES = $(top_srcdir)/examples/intro_sync.cpp
|
||||
containers_SOURCES = $(top_srcdir)/examples/containers.cpp
|
||||
serialization_SOURCES = $(top_srcdir)/examples/serialization.cpp
|
||||
test_connection_SOURCES = $(top_srcdir)/tests/connection.cpp
|
||||
test_connection_push_SOURCES = $(top_srcdir)/tests/connection_push.cpp
|
||||
subscriber_sync_SOURCES = $(top_srcdir)/examples/subscriber_sync.cpp
|
||||
if HAVE_COROUTINES
|
||||
subscriber_SOURCES = $(top_srcdir)/examples/subscriber.cpp
|
||||
|
||||
@@ -73,6 +73,7 @@ public:
|
||||
boost::system::error_code& ec)
|
||||
{
|
||||
using boost::variant2::visit;
|
||||
// TODO: Output an error instead of an assert.
|
||||
BOOST_ASSERT(i < adapters_.size());
|
||||
visit([&](auto& arg){arg(nd, ec);}, adapters_.at(i));
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ public:
|
||||
|
||||
if (is_aggregate(nd.data_type)) {
|
||||
if (i_ != -1) {
|
||||
ec = error::nested_aggregate_unsupported;
|
||||
ec = error::nested_aggregate_not_supported;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -371,6 +371,7 @@ public:
|
||||
Adapter adapter = adapt(),
|
||||
CompletionToken token = CompletionToken{})
|
||||
{
|
||||
// TODO: Use adapter::response_traits here instead of aedis::response_traits
|
||||
auto f =
|
||||
[adapter]
|
||||
(resp3::node<boost::string_view> const& node, boost::system::error_code& ec) mutable
|
||||
|
||||
@@ -105,6 +105,11 @@ struct receive_push_op {
|
||||
resp3::async_read(*conn->socket_, conn->make_dynamic_buffer(), adapter, std::move(self));
|
||||
if (ec) {
|
||||
conn->cancel(Conn::operation::run);
|
||||
|
||||
// Needed to cancel the channel, otherwise the read
|
||||
// operation will be blocked forever see
|
||||
// test_push_adapter.
|
||||
conn->cancel(Conn::operation::receive_push);
|
||||
self.complete(ec, 0);
|
||||
return;
|
||||
}
|
||||
@@ -493,6 +498,7 @@ struct run_op {
|
||||
|
||||
// Consider communicating the return of async_run_one as an
|
||||
// event here.
|
||||
// TODO: Add event trying_again and sent it here.
|
||||
|
||||
conn->ping_timer_.expires_after(conn->cfg_.reconnect_interval);
|
||||
yield
|
||||
|
||||
@@ -59,7 +59,7 @@ enum class error
|
||||
expects_resp3_set,
|
||||
|
||||
/// Nested response not supported.
|
||||
nested_aggregate_unsupported,
|
||||
nested_aggregate_not_supported,
|
||||
|
||||
/// Got RESP3 simple error.
|
||||
simple_error,
|
||||
|
||||
@@ -33,7 +33,7 @@ struct error_category_impl : boost::system::error_category {
|
||||
case error::expects_resp3_aggregate: return "Expects resp3 aggregate.";
|
||||
case error::expects_resp3_map: return "Expects resp3 map.";
|
||||
case error::expects_resp3_set: return "Expects resp3 set.";
|
||||
case error::nested_aggregate_unsupported: return "Nested aggregate unsupported.";
|
||||
case error::nested_aggregate_not_supported: return "Nested aggregate not_supported.";
|
||||
case error::simple_error: return "Got RESP3 simple-error.";
|
||||
case error::blob_error: return "Got RESP3 blob-error.";
|
||||
case error::incompatible_size: return "Aggregate container has incompatible size.";
|
||||
|
||||
@@ -80,9 +80,7 @@ char to_code(type t)
|
||||
case type::attribute: return '|';
|
||||
case type::map: return '%';
|
||||
|
||||
default:
|
||||
BOOST_ASSERT(false);
|
||||
return ' ';
|
||||
default: BOOST_ASSERT(false); return ' ';
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -125,56 +125,6 @@ BOOST_AUTO_TEST_CASE(test_quit)
|
||||
test_quit2(cfg);
|
||||
}
|
||||
|
||||
// Checks whether we get idle timeout when no push reader is set.
|
||||
void test_missing_push_reader1(connection::config const& cfg)
|
||||
{
|
||||
std::cout << "test_missing_push_reader1" << std::endl;
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
|
||||
request req;
|
||||
req.push("SUBSCRIBE", "channel");
|
||||
|
||||
db->async_run(req, adapt(), [](auto ec, auto){
|
||||
BOOST_TEST(!ec);
|
||||
});
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
void test_missing_push_reader2(connection::config const& cfg)
|
||||
{
|
||||
std::cout << "test_missing_push_reader2" << std::endl;
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
|
||||
request req; // Wrong command syntax.
|
||||
req.push("SUBSCRIBE");
|
||||
|
||||
db->async_run(req, adapt(), [](auto ec, auto){
|
||||
BOOST_TEST(!ec);
|
||||
});
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
void test_missing_push_reader3(connection::config const& cfg)
|
||||
{
|
||||
std::cout << "test_missing_push_reader3" << std::endl;
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
|
||||
request req; // Wrong command synthax.
|
||||
req.push("PING", "Message");
|
||||
req.push("SUBSCRIBE");
|
||||
|
||||
db->async_run(req, adapt(), [](auto ec, auto){
|
||||
BOOST_TEST(!ec);
|
||||
});
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_idle)
|
||||
{
|
||||
std::chrono::milliseconds ms{5000};
|
||||
@@ -228,138 +178,6 @@ BOOST_AUTO_TEST_CASE(test_idle)
|
||||
}
|
||||
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
net::awaitable<void> push_consumer1(std::shared_ptr<connection> db, bool& push_received)
|
||||
{
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_push(adapt(), as_tuple(net::use_awaitable));
|
||||
BOOST_TEST(!ec);
|
||||
}
|
||||
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_push(adapt(), as_tuple(net::use_awaitable));
|
||||
BOOST_CHECK_EQUAL(ec, boost::asio::experimental::channel_errc::channel_cancelled);
|
||||
}
|
||||
|
||||
push_received = true;
|
||||
}
|
||||
|
||||
net::awaitable<void> event_consumer1(std::shared_ptr<connection> db, bool& event_received)
|
||||
{
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_event(as_tuple(net::use_awaitable));
|
||||
auto const r = ev == connection::event::resolve;
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(!ec);
|
||||
}
|
||||
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_event(as_tuple(net::use_awaitable));
|
||||
auto const r = ev == connection::event::connect;
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(!ec);
|
||||
}
|
||||
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_event(as_tuple(net::use_awaitable));
|
||||
auto const r = ev == connection::event::hello;
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(!ec);
|
||||
}
|
||||
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_event(as_tuple(net::use_awaitable));
|
||||
BOOST_CHECK_EQUAL(ec, boost::asio::experimental::channel_errc::channel_cancelled);
|
||||
}
|
||||
|
||||
event_received = true;
|
||||
}
|
||||
|
||||
|
||||
void test_push_is_received1(connection::config const& cfg)
|
||||
{
|
||||
std::cout << "test_push_is_received1" << std::endl;
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
db->get_config().enable_events = true;
|
||||
|
||||
request req;
|
||||
req.push("SUBSCRIBE", "channel");
|
||||
req.push("QUIT");
|
||||
|
||||
db->async_run(req, adapt(), [db](auto ec, auto){
|
||||
BOOST_TEST(!ec);
|
||||
db->cancel(connection::operation::receive_event);
|
||||
db->cancel(connection::operation::receive_push);
|
||||
});
|
||||
|
||||
bool push_received = false;
|
||||
net::co_spawn(
|
||||
ioc.get_executor(),
|
||||
push_consumer1(db, push_received),
|
||||
net::detached);
|
||||
|
||||
bool event_received = false;
|
||||
net::co_spawn(
|
||||
ioc.get_executor(),
|
||||
event_consumer1(db, event_received),
|
||||
net::detached);
|
||||
|
||||
ioc.run();
|
||||
|
||||
BOOST_TEST(push_received);
|
||||
BOOST_TEST(event_received);
|
||||
}
|
||||
|
||||
void test_push_is_received2(connection::config const& cfg)
|
||||
{
|
||||
request req1;
|
||||
req1.push("PING", "Message1");
|
||||
|
||||
request req2;
|
||||
req2.push("SUBSCRIBE", "channel");
|
||||
|
||||
request req3;
|
||||
req3.push("PING", "Message2");
|
||||
req3.push("QUIT");
|
||||
|
||||
net::io_context ioc;
|
||||
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
db->get_config().enable_events = true;
|
||||
|
||||
auto handler =[](auto ec, auto...)
|
||||
{
|
||||
BOOST_TEST(!ec);
|
||||
};
|
||||
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req3, adapt(), handler);
|
||||
|
||||
db->async_run([db](auto ec, auto...) {
|
||||
BOOST_CHECK_EQUAL(ec, net::error::misc_errors::eof);
|
||||
db->cancel(connection::operation::receive_event);
|
||||
db->cancel(connection::operation::receive_push);
|
||||
});
|
||||
|
||||
bool push_received = false;
|
||||
net::co_spawn(
|
||||
ioc.get_executor(),
|
||||
push_consumer1(db, push_received),
|
||||
net::detached);
|
||||
|
||||
bool event_received = false;
|
||||
net::co_spawn(
|
||||
ioc.get_executor(),
|
||||
event_consumer1(db, event_received),
|
||||
net::detached);
|
||||
|
||||
ioc.run();
|
||||
|
||||
BOOST_TEST(push_received);
|
||||
BOOST_TEST(event_received);
|
||||
}
|
||||
|
||||
net::awaitable<void> test_reconnect_impl(std::shared_ptr<connection> db)
|
||||
{
|
||||
request req;
|
||||
@@ -412,80 +230,4 @@ void test_reconnect()
|
||||
std::cout << "End: test_reconnect()" << std::endl;
|
||||
}
|
||||
|
||||
net::awaitable<void>
|
||||
push_consumer3(std::shared_ptr<connection> db)
|
||||
{
|
||||
for (;;)
|
||||
co_await db->async_receive_push(adapt(), net::use_awaitable);
|
||||
}
|
||||
|
||||
// Test many subscribe requests.
|
||||
void test_push_many_subscribes(connection::config const& cfg)
|
||||
{
|
||||
std::cout << "test_push_many_subscribes" << std::endl;
|
||||
request req0;
|
||||
req0.push("HELLO", 3);
|
||||
|
||||
request req1;
|
||||
req1.push("PING", "Message1");
|
||||
|
||||
request req2;
|
||||
req2.push("SUBSCRIBE", "channel");
|
||||
|
||||
request req3;
|
||||
req3.push("QUIT");
|
||||
|
||||
auto handler =[](auto ec, auto...)
|
||||
{
|
||||
BOOST_TEST(!ec);
|
||||
};
|
||||
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
db->async_exec(req0, adapt(), handler);
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req3, adapt(), handler);
|
||||
|
||||
db->async_run([db](auto ec, auto...) {
|
||||
BOOST_CHECK_EQUAL(ec, net::error::misc_errors::eof);
|
||||
db->cancel(connection::operation::receive_push);
|
||||
});
|
||||
|
||||
net::co_spawn(ioc.get_executor(), push_consumer3(db), net::detached);
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_push)
|
||||
{
|
||||
connection::config cfg;
|
||||
|
||||
cfg.coalesce_requests = true;
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
test_push_is_received1(cfg);
|
||||
test_push_is_received2(cfg);
|
||||
test_push_many_subscribes(cfg);
|
||||
#endif
|
||||
test_missing_push_reader1(cfg);
|
||||
test_missing_push_reader3(cfg);
|
||||
|
||||
cfg.coalesce_requests = false;
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
test_push_is_received1(cfg);
|
||||
test_push_is_received2(cfg);
|
||||
test_push_many_subscribes(cfg);
|
||||
#endif
|
||||
test_missing_push_reader2(cfg);
|
||||
test_missing_push_reader3(cfg);
|
||||
}
|
||||
|
||||
|
||||
314
tests/connection_push.cpp
Normal file
314
tests/connection_push.cpp
Normal file
@@ -0,0 +1,314 @@
|
||||
/* Copyright (c) 2018-2022 Marcelo Zimbres Silva (mzimbres@gmail.com)
|
||||
*
|
||||
* Distributed under the Boost Software License, Version 1.0. (See
|
||||
* accompanying file LICENSE.txt)
|
||||
*/
|
||||
|
||||
// TODO: Avoid usage of co_await to improve tests is compilers that
|
||||
// don't support it.
|
||||
// TODO: Add reconnect test that kills the server and waits some
|
||||
// seconds.
|
||||
|
||||
#include <iostream>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/system/errc.hpp>
|
||||
#include <boost/asio/experimental/as_tuple.hpp>
|
||||
|
||||
#define BOOST_TEST_MODULE low level
|
||||
#include <boost/test/included/unit_test.hpp>
|
||||
|
||||
#include <aedis.hpp>
|
||||
#include <aedis/src.hpp>
|
||||
|
||||
namespace net = boost::asio;
|
||||
|
||||
using aedis::resp3::request;
|
||||
using aedis::adapt;
|
||||
using connection = aedis::connection<>;
|
||||
using error_code = boost::system::error_code;
|
||||
using net::experimental::as_tuple;
|
||||
|
||||
// Checks whether we get idle timeout when no push reader is set.
|
||||
void test_missing_push_reader1(connection::config const& cfg)
|
||||
{
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
|
||||
request req;
|
||||
req.push("SUBSCRIBE", "channel");
|
||||
|
||||
db->async_run(req, adapt(), [](auto ec, auto){
|
||||
BOOST_TEST(!ec);
|
||||
});
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
void test_missing_push_reader2(connection::config const& cfg)
|
||||
{
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
|
||||
request req; // Wrong command syntax.
|
||||
req.push("SUBSCRIBE");
|
||||
|
||||
db->async_run(req, adapt(), [](auto ec, auto){
|
||||
BOOST_TEST(!ec);
|
||||
});
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
void test_missing_push_reader3(connection::config const& cfg)
|
||||
{
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
|
||||
request req; // Wrong command synthax.
|
||||
req.push("PING", "Message");
|
||||
req.push("SUBSCRIBE");
|
||||
|
||||
db->async_run(req, adapt(), [](auto ec, auto){
|
||||
BOOST_TEST(!ec);
|
||||
});
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
net::awaitable<void> push_consumer1(std::shared_ptr<connection> db, bool& push_received)
|
||||
{
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_push(adapt(), as_tuple(net::use_awaitable));
|
||||
BOOST_TEST(!ec);
|
||||
}
|
||||
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_push(adapt(), as_tuple(net::use_awaitable));
|
||||
BOOST_CHECK_EQUAL(ec, boost::asio::experimental::channel_errc::channel_cancelled);
|
||||
}
|
||||
|
||||
push_received = true;
|
||||
}
|
||||
|
||||
net::awaitable<void> event_consumer1(std::shared_ptr<connection> db, bool& event_received)
|
||||
{
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_event(as_tuple(net::use_awaitable));
|
||||
auto const r = ev == connection::event::resolve;
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(!ec);
|
||||
}
|
||||
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_event(as_tuple(net::use_awaitable));
|
||||
auto const r = ev == connection::event::connect;
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(!ec);
|
||||
}
|
||||
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_event(as_tuple(net::use_awaitable));
|
||||
auto const r = ev == connection::event::hello;
|
||||
BOOST_TEST(r);
|
||||
BOOST_TEST(!ec);
|
||||
}
|
||||
|
||||
{
|
||||
auto [ec, ev] = co_await db->async_receive_event(as_tuple(net::use_awaitable));
|
||||
BOOST_CHECK_EQUAL(ec, boost::asio::experimental::channel_errc::channel_cancelled);
|
||||
}
|
||||
|
||||
event_received = true;
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_push_adapter)
|
||||
{
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc);
|
||||
|
||||
request req;
|
||||
req.push("PING");
|
||||
req.push("SUBSCRIBE", "channel");
|
||||
req.push("PING");
|
||||
|
||||
auto f = [](auto, auto, auto& ec)
|
||||
{
|
||||
ec = aedis::error::incompatible_size;
|
||||
};
|
||||
|
||||
// TODO: We should be able to use adapt here.
|
||||
db->async_receive_push(f, [](auto ec, auto) {
|
||||
BOOST_CHECK_EQUAL(ec, aedis::error::incompatible_size);
|
||||
});
|
||||
|
||||
db->async_run(req, adapt(), [db](auto, auto){
|
||||
// TODO: use async_run and async_exec.
|
||||
//BOOST_CHECK_EQUAL(ec, net::error::misc_errors::eof);
|
||||
});
|
||||
|
||||
ioc.run();
|
||||
|
||||
// TODO: Reset the ioc reconnect and send a quit to ensure
|
||||
// reconnection is possible after an error.
|
||||
}
|
||||
|
||||
void test_push_is_received1(connection::config const& cfg)
|
||||
{
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
db->get_config().enable_events = true;
|
||||
|
||||
request req;
|
||||
req.push("SUBSCRIBE", "channel");
|
||||
req.push("QUIT");
|
||||
|
||||
db->async_run(req, adapt(), [db](auto ec, auto){
|
||||
BOOST_TEST(!ec);
|
||||
db->cancel(connection::operation::receive_event);
|
||||
db->cancel(connection::operation::receive_push);
|
||||
});
|
||||
|
||||
bool push_received = false;
|
||||
net::co_spawn(
|
||||
ioc.get_executor(),
|
||||
push_consumer1(db, push_received),
|
||||
net::detached);
|
||||
|
||||
bool event_received = false;
|
||||
net::co_spawn(
|
||||
ioc.get_executor(),
|
||||
event_consumer1(db, event_received),
|
||||
net::detached);
|
||||
|
||||
ioc.run();
|
||||
|
||||
BOOST_TEST(push_received);
|
||||
BOOST_TEST(event_received);
|
||||
}
|
||||
|
||||
void test_push_is_received2(connection::config const& cfg)
|
||||
{
|
||||
request req1;
|
||||
req1.push("PING", "Message1");
|
||||
|
||||
request req2;
|
||||
req2.push("SUBSCRIBE", "channel");
|
||||
|
||||
request req3;
|
||||
req3.push("PING", "Message2");
|
||||
req3.push("QUIT");
|
||||
|
||||
net::io_context ioc;
|
||||
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
db->get_config().enable_events = true;
|
||||
|
||||
auto handler =[](auto ec, auto...)
|
||||
{
|
||||
BOOST_TEST(!ec);
|
||||
};
|
||||
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req3, adapt(), handler);
|
||||
|
||||
db->async_run([db](auto ec, auto...) {
|
||||
BOOST_CHECK_EQUAL(ec, net::error::misc_errors::eof);
|
||||
db->cancel(connection::operation::receive_event);
|
||||
db->cancel(connection::operation::receive_push);
|
||||
});
|
||||
|
||||
bool push_received = false;
|
||||
net::co_spawn(
|
||||
ioc.get_executor(),
|
||||
push_consumer1(db, push_received),
|
||||
net::detached);
|
||||
|
||||
bool event_received = false;
|
||||
net::co_spawn(
|
||||
ioc.get_executor(),
|
||||
event_consumer1(db, event_received),
|
||||
net::detached);
|
||||
|
||||
ioc.run();
|
||||
|
||||
BOOST_TEST(push_received);
|
||||
BOOST_TEST(event_received);
|
||||
}
|
||||
|
||||
net::awaitable<void> push_consumer3(std::shared_ptr<connection> db)
|
||||
{
|
||||
for (;;)
|
||||
co_await db->async_receive_push(adapt(), net::use_awaitable);
|
||||
}
|
||||
|
||||
// Test many subscribe requests.
|
||||
void test_push_many_subscribes(connection::config const& cfg)
|
||||
{
|
||||
request req0;
|
||||
req0.push("HELLO", 3);
|
||||
|
||||
request req1;
|
||||
req1.push("PING", "Message1");
|
||||
|
||||
request req2;
|
||||
req2.push("SUBSCRIBE", "channel");
|
||||
|
||||
request req3;
|
||||
req3.push("QUIT");
|
||||
|
||||
auto handler =[](auto ec, auto...)
|
||||
{
|
||||
BOOST_TEST(!ec);
|
||||
};
|
||||
|
||||
net::io_context ioc;
|
||||
auto db = std::make_shared<connection>(ioc, cfg);
|
||||
db->async_exec(req0, adapt(), handler);
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req1, adapt(), handler);
|
||||
db->async_exec(req2, adapt(), handler);
|
||||
db->async_exec(req3, adapt(), handler);
|
||||
|
||||
db->async_run([db](auto ec, auto...) {
|
||||
BOOST_CHECK_EQUAL(ec, net::error::misc_errors::eof);
|
||||
db->cancel(connection::operation::receive_push);
|
||||
});
|
||||
|
||||
net::co_spawn(ioc.get_executor(), push_consumer3(db), net::detached);
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_push)
|
||||
{
|
||||
connection::config cfg;
|
||||
|
||||
cfg.coalesce_requests = true;
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
test_push_is_received1(cfg);
|
||||
test_push_is_received2(cfg);
|
||||
test_push_many_subscribes(cfg);
|
||||
#endif
|
||||
test_missing_push_reader1(cfg);
|
||||
test_missing_push_reader3(cfg);
|
||||
|
||||
cfg.coalesce_requests = false;
|
||||
#ifdef BOOST_ASIO_HAS_CO_AWAIT
|
||||
test_push_is_received1(cfg);
|
||||
test_push_is_received2(cfg);
|
||||
test_push_many_subscribes(cfg);
|
||||
#endif
|
||||
test_missing_push_reader2(cfg);
|
||||
test_missing_push_reader3(cfg);
|
||||
}
|
||||
|
||||
@@ -155,41 +155,43 @@ BOOST_AUTO_TEST_CASE(test_bool)
|
||||
boost::optional<bool> ok;
|
||||
ok = true;
|
||||
|
||||
// Success.
|
||||
auto const in08 = expect<node_type>{"#f\r\n", node_type{resp3::type::boolean, 1UL, 0UL, {"f"}}, "bool.node (false)"};
|
||||
auto const in09 = expect<node_type>{"#t\r\n", node_type{resp3::type::boolean, 1UL, 0UL, {"t"}}, "bool.node (true)"};
|
||||
auto const in10 = expect<bool>{"#t\r\n", bool{true}, "bool.bool (true)"};
|
||||
auto const in11 = expect<bool>{"#f\r\n", bool{false}, "bool.bool (true)"};
|
||||
auto const in13 = expect<boost::optional<bool>>{"#t\r\n", ok, "optional.int"};
|
||||
|
||||
// Error
|
||||
auto const in01 = expect<boost::optional<bool>>{"#11\r\n", boost::optional<bool>{}, "bool.error", aedis::make_error_code(aedis::error::unexpected_bool_value)};
|
||||
auto const in03 = expect<std::set<int>>{"#t\r\n", std::set<int>{}, "bool.error", aedis::make_error_code(aedis::error::expects_resp3_set)};
|
||||
auto const in04 = expect<std::unordered_set<int>>{"#t\r\n", std::unordered_set<int>{}, "bool.error", aedis::make_error_code(aedis::error::expects_resp3_set)};
|
||||
auto const in05 = expect<std::map<int, int>>{"#t\r\n", std::map<int, int>{}, "bool.error", aedis::make_error_code(aedis::error::expects_resp3_map)};
|
||||
auto const in06 = expect<std::unordered_map<int, int>>{"#t\r\n", std::unordered_map<int, int>{}, "bool.error", aedis::make_error_code(aedis::error::expects_resp3_map)};
|
||||
auto const in02 = expect<std::set<int>>{"#t\r\n", std::set<int>{}, "bool.error", aedis::make_error_code(aedis::error::expects_resp3_set)};
|
||||
auto const in03 = expect<std::unordered_set<int>>{"#t\r\n", std::unordered_set<int>{}, "bool.error", aedis::make_error_code(aedis::error::expects_resp3_set)};
|
||||
auto const in04 = expect<std::map<int, int>>{"#t\r\n", std::map<int, int>{}, "bool.error", aedis::make_error_code(aedis::error::expects_resp3_map)};
|
||||
auto const in05 = expect<std::unordered_map<int, int>>{"#t\r\n", std::unordered_map<int, int>{}, "bool.error", aedis::make_error_code(aedis::error::expects_resp3_map)};
|
||||
// Success.
|
||||
auto const in06 = expect<node_type>{"#f\r\n", node_type{resp3::type::boolean, 1UL, 0UL, {"f"}}, "bool.node (false)"};
|
||||
auto const in07 = expect<node_type>{"#t\r\n", node_type{resp3::type::boolean, 1UL, 0UL, {"t"}}, "bool.node (true)"};
|
||||
auto const in08 = expect<bool>{"#t\r\n", bool{true}, "bool.bool (true)"};
|
||||
auto const in09 = expect<bool>{"#f\r\n", bool{false}, "bool.bool (true)"};
|
||||
auto const in10 = expect<boost::optional<bool>>{"#t\r\n", ok, "optional.int"};
|
||||
|
||||
|
||||
auto ex = ioc.get_executor();
|
||||
|
||||
test_sync(ex, in01);
|
||||
test_sync(ex, in02);
|
||||
test_sync(ex, in03);
|
||||
test_sync(ex, in04);
|
||||
test_sync(ex, in05);
|
||||
test_sync(ex, in06);
|
||||
test_sync(ex, in07);
|
||||
test_sync(ex, in08);
|
||||
test_sync(ex, in09);
|
||||
test_sync(ex, in10);
|
||||
test_sync(ex, in11);
|
||||
|
||||
test_async(ex, in01);
|
||||
test_async(ex, in02);
|
||||
test_async(ex, in03);
|
||||
test_async(ex, in04);
|
||||
test_async(ex, in05);
|
||||
test_async(ex, in06);
|
||||
test_async(ex, in07);
|
||||
test_async(ex, in08);
|
||||
test_async(ex, in09);
|
||||
test_async(ex, in10);
|
||||
test_async(ex, in11);
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
@@ -208,8 +210,8 @@ BOOST_AUTO_TEST_CASE(test_streamed_string)
|
||||
std::vector<node_type> e1b { {resp3::type::streamed_string_part, 1UL, 1UL, {}} };
|
||||
|
||||
auto const in01 = expect<std::vector<node_type>>{wire, e1a, "streamed_string.node"};
|
||||
auto const in03 = expect<std::string>{wire, std::string{"Hello word"}, "streamed_string.string"};
|
||||
auto const in02 = expect<std::vector<node_type>>{"$?\r\n;0\r\n", e1b, "streamed_string.node.empty"};
|
||||
auto const in02 = expect<std::string>{wire, std::string{"Hello word"}, "streamed_string.string"};
|
||||
auto const in03 = expect<std::vector<node_type>>{"$?\r\n;0\r\n", e1b, "streamed_string.node.empty"};
|
||||
|
||||
auto ex = ioc.get_executor();
|
||||
|
||||
@@ -347,10 +349,11 @@ BOOST_AUTO_TEST_CASE(test_map)
|
||||
test_sync(ex, in03);
|
||||
test_sync(ex, in04);
|
||||
test_sync(ex, in05);
|
||||
test_sync(ex, in06);
|
||||
test_sync(ex, in07);
|
||||
test_sync(ex, in08);
|
||||
test_sync(ex, in09);
|
||||
test_sync(ex, in00);
|
||||
test_sync(ex, in10);
|
||||
test_sync(ex, in11);
|
||||
test_sync(ex, in12);
|
||||
test_sync(ex, in13);
|
||||
@@ -361,10 +364,11 @@ BOOST_AUTO_TEST_CASE(test_map)
|
||||
test_async(ex, in03);
|
||||
test_async(ex, in04);
|
||||
test_async(ex, in05);
|
||||
test_async(ex, in06);
|
||||
test_async(ex, in07);
|
||||
test_async(ex, in08);
|
||||
test_async(ex, in09);
|
||||
test_async(ex, in00);
|
||||
test_async(ex, in10);
|
||||
test_async(ex, in11);
|
||||
test_async(ex, in12);
|
||||
test_async(ex, in13);
|
||||
@@ -401,8 +405,13 @@ void test_attribute(net::io_context& ioc)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_array)
|
||||
{
|
||||
using tuple_type = std::tuple<int, int>;
|
||||
using array_type = std::array<int, 3>;
|
||||
using array_type2 = std::array<int, 1>;
|
||||
|
||||
net::io_context ioc;
|
||||
char const* wire = "*3\r\n$2\r\n11\r\n$2\r\n22\r\n$1\r\n3\r\n";
|
||||
char const* wire_nested = "*1\r\n*1\r\n$2\r\nab\r\n";
|
||||
|
||||
std::vector<node_type> e1a
|
||||
{ {resp3::type::array, 3UL, 0UL, {}}
|
||||
@@ -415,7 +424,7 @@ BOOST_AUTO_TEST_CASE(test_array)
|
||||
std::vector<std::string> const e1c{"11", "22", "3"};
|
||||
std::vector<std::string> const e1d{};
|
||||
std::vector<node_type> const e1e{{resp3::type::array, 0UL, 0UL, {}}};
|
||||
std::array<int, 3> const e1f{11, 22, 3};
|
||||
array_type const e1f{11, 22, 3};
|
||||
std::list<int> const e1g{11, 22, 3};
|
||||
std::deque<int> const e1h{11, 22, 3};
|
||||
|
||||
@@ -424,11 +433,16 @@ BOOST_AUTO_TEST_CASE(test_array)
|
||||
auto const in03 = expect<std::vector<node_type>>{"*0\r\n", e1e, "array.node.empty"};
|
||||
auto const in04 = expect<std::vector<std::string>>{"*0\r\n", e1d, "array.string.empty"};
|
||||
auto const in05 = expect<std::vector<std::string>>{wire, e1c, "array.string"};
|
||||
auto const in06 = expect<std::array<int, 3>>{wire, e1f, "array.array"};
|
||||
auto const in06 = expect<array_type>{wire, e1f, "array.array"};
|
||||
auto const in07 = expect<std::list<int>>{wire, e1g, "array.list"};
|
||||
auto const in08 = expect<std::deque<int>>{wire, e1h, "array.deque"};
|
||||
auto const in09 = expect<std::vector<int>>{"_\r\n", std::vector<int>{}, "array.vector", aedis::make_error_code(aedis::error::null)};
|
||||
auto const in10 = expect<std::list<int>>{"_\r\n", std::list<int>{}, "array.list", aedis::make_error_code(aedis::error::null)};
|
||||
auto const in11 = expect<array_type>{"_\r\n", array_type{}, "array.null", aedis::make_error_code(aedis::error::null)};
|
||||
auto const in12 = expect<tuple_type>{wire, tuple_type{}, "array.list", aedis::make_error_code(aedis::error::incompatible_size)};
|
||||
auto const in13 = expect<array_type2>{wire_nested, array_type2{}, "array.nested", aedis::make_error_code(aedis::error::nested_aggregate_not_supported)};
|
||||
auto const in14 = expect<array_type2>{wire, array_type2{}, "array.null", aedis::make_error_code(aedis::error::incompatible_size)};
|
||||
auto const in15 = expect<array_type2>{":3\r\n", array_type2{}, "array.array", aedis::make_error_code(aedis::error::expects_resp3_aggregate)};
|
||||
|
||||
auto ex = ioc.get_executor();
|
||||
|
||||
@@ -441,6 +455,12 @@ BOOST_AUTO_TEST_CASE(test_array)
|
||||
test_sync(ex, in07);
|
||||
test_sync(ex, in08);
|
||||
test_sync(ex, in09);
|
||||
test_sync(ex, in10);
|
||||
test_sync(ex, in11);
|
||||
test_sync(ex, in12);
|
||||
test_sync(ex, in13);
|
||||
test_sync(ex, in14);
|
||||
test_sync(ex, in15);
|
||||
|
||||
test_async(ex, in01);
|
||||
test_async(ex, in02);
|
||||
@@ -451,6 +471,13 @@ BOOST_AUTO_TEST_CASE(test_array)
|
||||
test_async(ex, in07);
|
||||
test_async(ex, in08);
|
||||
test_async(ex, in09);
|
||||
test_async(ex, in10);
|
||||
test_async(ex, in11);
|
||||
test_async(ex, in12);
|
||||
test_async(ex, in13);
|
||||
test_async(ex, in14);
|
||||
test_async(ex, in15);
|
||||
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
@@ -671,12 +698,20 @@ BOOST_AUTO_TEST_CASE(test_simple_string)
|
||||
|
||||
BOOST_AUTO_TEST_CASE(test_resp3)
|
||||
{
|
||||
using map_type = std::map<std::string, std::string>;
|
||||
std::string const wire_map = "%rt\r\n$4\r\nkey1\r\n$6\r\nvalue1\r\n$4\r\nkey2\r\n$6\r\nvalue2\r\n";
|
||||
|
||||
std::string const wire_ssp = "$?\r\n;d\r\nHell\r\n;5\r\no wor\r\n;1\r\nd\r\n;0\r\n";
|
||||
|
||||
net::io_context ioc;
|
||||
auto const in01 = expect<int>{"s11\r\n", int{}, "number.error", aedis::make_error_code(aedis::error::invalid_data_type)};
|
||||
auto const in02 = expect<int>{":adf\r\n", int{11}, "number.int", aedis::make_error_code(aedis::error::not_a_number)};
|
||||
auto const in03 = expect<int>{":\r\n", int{}, "number.error (empty field)", aedis::make_error_code(aedis::error::empty_field)};
|
||||
auto const in04 = expect<boost::optional<bool>>{"#\r\n", boost::optional<bool>{}, "bool.error", aedis::make_error_code(aedis::error::empty_field)};
|
||||
auto const in05 = expect<std::string>{",\r\n", std::string{}, "double.error (empty field)", aedis::make_error_code(aedis::error::empty_field)};
|
||||
auto const in03 = expect<map_type>{wire_map, map_type{}, "map.error", aedis::make_error_code(aedis::error::not_a_number)};
|
||||
auto const in04 = expect<std::string>{wire_ssp, std::string{}, "streamed_string_part.error", aedis::make_error_code(aedis::error::not_a_number)};
|
||||
auto const in05 = expect<std::string>{"$l\r\nhh\r\n", std::string{}, "blob_string.error", aedis::make_error_code(aedis::error::not_a_number)};
|
||||
auto const in06 = expect<int>{":\r\n", int{}, "number.error (empty field)", aedis::make_error_code(aedis::error::empty_field)};
|
||||
auto const in07 = expect<boost::optional<bool>>{"#\r\n", boost::optional<bool>{}, "bool.error", aedis::make_error_code(aedis::error::empty_field)};
|
||||
auto const in08 = expect<std::string>{",\r\n", std::string{}, "double.error (empty field)", aedis::make_error_code(aedis::error::empty_field)};
|
||||
|
||||
auto ex = ioc.get_executor();
|
||||
|
||||
@@ -685,12 +720,18 @@ BOOST_AUTO_TEST_CASE(test_resp3)
|
||||
test_sync(ex, in03);
|
||||
test_sync(ex, in04);
|
||||
test_sync(ex, in05);
|
||||
test_sync(ex, in06);
|
||||
test_sync(ex, in07);
|
||||
test_sync(ex, in08);
|
||||
|
||||
test_async(ex, in01);
|
||||
test_async(ex, in02);
|
||||
test_async(ex, in03);
|
||||
test_async(ex, in04);
|
||||
test_async(ex, in05);
|
||||
test_async(ex, in06);
|
||||
test_async(ex, in07);
|
||||
test_async(ex, in08);
|
||||
ioc.run();
|
||||
}
|
||||
|
||||
@@ -773,7 +814,7 @@ BOOST_AUTO_TEST_CASE(error)
|
||||
check_error("aedis", aedis::error::expects_resp3_aggregate);
|
||||
check_error("aedis", aedis::error::expects_resp3_map);
|
||||
check_error("aedis", aedis::error::expects_resp3_set);
|
||||
check_error("aedis", aedis::error::nested_aggregate_unsupported);
|
||||
check_error("aedis", aedis::error::nested_aggregate_not_supported);
|
||||
check_error("aedis", aedis::error::simple_error);
|
||||
check_error("aedis", aedis::error::blob_error);
|
||||
check_error("aedis", aedis::error::incompatible_size);
|
||||
@@ -788,7 +829,7 @@ std::string get_type_as_str(aedis::resp3::type t)
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(type)
|
||||
BOOST_AUTO_TEST_CASE(type_string)
|
||||
{
|
||||
BOOST_TEST(!get_type_as_str(aedis::resp3::type::array).empty());
|
||||
BOOST_TEST(!get_type_as_str(aedis::resp3::type::push).empty());
|
||||
@@ -808,3 +849,29 @@ BOOST_AUTO_TEST_CASE(type)
|
||||
BOOST_TEST(!get_type_as_str(aedis::resp3::type::streamed_string_part).empty());
|
||||
BOOST_TEST(!get_type_as_str(aedis::resp3::type::invalid).empty());
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(type_convert)
|
||||
{
|
||||
using aedis::resp3::to_code;
|
||||
using aedis::resp3::to_type;
|
||||
using aedis::resp3::type;
|
||||
|
||||
#define CHECK_CASE(A) BOOST_CHECK_EQUAL(to_type(to_code(type::A)), type::A);
|
||||
CHECK_CASE(array);
|
||||
CHECK_CASE(push);
|
||||
CHECK_CASE(set);
|
||||
CHECK_CASE(map);
|
||||
CHECK_CASE(attribute);
|
||||
CHECK_CASE(simple_string);
|
||||
CHECK_CASE(simple_error);
|
||||
CHECK_CASE(number);
|
||||
CHECK_CASE(doublean);
|
||||
CHECK_CASE(boolean);
|
||||
CHECK_CASE(big_number);
|
||||
CHECK_CASE(null);
|
||||
CHECK_CASE(blob_error);
|
||||
CHECK_CASE(verbatim_string);
|
||||
CHECK_CASE(blob_string);
|
||||
CHECK_CASE(streamed_string_part);
|
||||
#undef CHECK_CASE
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user