2
0
mirror of https://github.com/boostorg/redis.git synced 2026-01-19 04:42:09 +00:00
Files
redis/tests/high_level.cpp
2022-08-06 13:06:05 +02:00

413 lines
10 KiB
C++

/* 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>
#include <aedis.hpp>
#include <aedis/src.hpp>
#include "check.hpp"
namespace net = boost::asio;
using aedis::resp3::request;
using connection = aedis::connection<>;
using error_code = boost::system::error_code;
using net::experimental::as_tuple;
bool is_host_not_found(boost::system::error_code ec)
{
if (ec == net::error::netdb_errors::host_not_found) return true;
if (ec == net::error::netdb_errors::host_not_found_try_again) return true;
return false;
}
//----------------------------------------------------------------
// Tests whether resolve fails with the correct error.
void test_resolve()
{
connection::config cfg;
cfg.host = "Atibaia";
cfg.port = "6379";
cfg.resolve_timeout = std::chrono::seconds{100};
net::io_context ioc;
connection db{ioc, cfg};
db.async_run([](auto ec) {
expect_true(is_host_not_found(ec), "test_resolve");
});
ioc.run();
}
//----------------------------------------------------------------
void test_connect()
{
connection::config cfg;
cfg.host = "127.0.0.1";
cfg.port = "1";
cfg.connect_timeout = std::chrono::seconds{100};
net::io_context ioc;
connection db{ioc, cfg};
db.async_run([](auto ec) {
expect_error(ec, net::error::basic_errors::connection_refused, "test_connect");
});
ioc.run();
}
//----------------------------------------------------------------
// Test if quit causes async_run to exit.
void test_quit1(connection::config const& cfg)
{
net::io_context ioc;
auto db = std::make_shared<connection>(ioc, cfg);
request req;
req.push("QUIT");
db->async_exec(req, aedis::adapt(), [](auto ec, auto){
expect_no_error(ec, "test_quit1");
});
db->async_run([](auto ec){
expect_error(ec, net::error::misc_errors::eof, "test_quit1");
});
ioc.run();
}
void test_quit2(connection::config const& cfg)
{
std::cout << "test_quit2" << std::endl;
request req;
req.push("QUIT");
net::io_context ioc;
auto db = std::make_shared<connection>(ioc, cfg);
db->async_run(req, aedis::adapt(), [](auto ec, auto){
expect_no_error(ec, "test_quit2");
});
ioc.run();
}
void test_quit()
{
connection::config cfg;
cfg.coalesce_requests = true;
test_quit1(cfg);
cfg.coalesce_requests = false;
test_quit1(cfg);
cfg.coalesce_requests = true;
test_quit2(cfg);
cfg.coalesce_requests = false;
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, aedis::adapt(), [](auto ec, auto){
expect_no_error(ec, "test_missing_push_reader1");
});
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, aedis::adapt(), [](auto ec, auto){
expect_no_error(ec, "test_missing_push_reader2");
});
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, aedis::adapt(), [](auto ec, auto){
expect_no_error(ec, "test_missing_push_reader3");
});
ioc.run();
}
void test_idle()
{
std::cout << "test_idle" << std::endl;
connection::config cfg;
cfg.resolve_timeout = std::chrono::seconds{1};
cfg.connect_timeout = std::chrono::seconds{1};
cfg.ping_interval = std::chrono::seconds{1};
net::io_context ioc;
auto db = std::make_shared<connection>(ioc, cfg);
request req;
req.push("CLIENT", "PAUSE", 5000);
db->async_exec(req, aedis::adapt(), [](auto ec, auto){
expect_no_error(ec, "test_idle");
});
db->async_run([](auto ec){
expect_error(ec, aedis::error::idle_timeout, "test_idle");
});
ioc.run();
}
#ifdef BOOST_ASIO_HAS_CO_AWAIT
net::awaitable<void>
push_consumer1(std::shared_ptr<connection> db, bool& received, char const* msg)
{
{
auto [ec, ev] = co_await db->async_receive_event(aedis::adapt(), as_tuple(net::use_awaitable));
expect_no_error(ec, msg);
received = true;
}
{
auto [ec, ev] = co_await db->async_receive_event(aedis::adapt(), as_tuple(net::use_awaitable));
expect_error(ec, boost::asio::experimental::channel_errc::channel_cancelled, msg);
}
}
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);
request req;
req.push("SUBSCRIBE", "channel");
req.push("QUIT");
db->async_run(req, aedis::adapt(), [db](auto ec, auto){
expect_no_error(ec, "test_push_is_received1");
db->cancel_receiver();
});
bool received = false;
net::co_spawn(
ioc.get_executor(),
push_consumer1(db, received, "test_push_is_received1"),
net::detached);
ioc.run();
expect_true(received);
}
void test_push_is_received2(connection::config const& cfg)
{
std::cout << "test_push_is_received2" << std::endl;
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);
auto handler =[](auto ec, auto...)
{ expect_no_error(ec, "test_push_is_received2"); };
db->async_exec(req1, aedis::adapt(), handler);
db->async_exec(req2, aedis::adapt(), handler);
db->async_exec(req3, aedis::adapt(), handler);
db->async_run([db](auto ec, auto...) {
expect_error(ec, net::error::misc_errors::eof, "test_push_is_received2");
db->cancel_receiver();
});
bool received = false;
net::co_spawn(
ioc.get_executor(),
push_consumer1(db, received, "test_push_is_received2"),
net::detached);
ioc.run();
expect_true(received);
}
net::awaitable<void> run5(std::shared_ptr<connection> db)
{
{
request req;
req.push("QUIT");
db->async_exec(req, aedis::adapt(), [](auto ec, auto){
expect_no_error(ec, "test_reconnect");
});
auto [ec] = co_await db->async_run(as_tuple(net::use_awaitable));
expect_error(ec, net::error::misc_errors::eof, "run5a");
}
{
request req;
req.push("QUIT");
db->async_exec(req, aedis::adapt(), [](auto ec, auto){
expect_no_error(ec, "test_reconnect");
});
auto [ec] = co_await db->async_run(as_tuple(net::use_awaitable));
expect_error(ec, net::error::misc_errors::eof, "run5a");
}
co_return;
}
// Test whether the client works after a reconnect.
void test_reconnect()
{
std::cout << "test_reconnect" << std::endl;
net::io_context ioc;
auto db = std::make_shared<connection>(ioc.get_executor());
net::co_spawn(ioc, run5(db), net::detached);
ioc.run();
std::cout << "Success: test_reconnect()" << std::endl;
}
net::awaitable<void>
push_consumer3(std::shared_ptr<connection> db)
{
for (;;)
co_await db->async_receive_event(aedis::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...)
{
expect_no_error(ec, "test_push_many_subscribes");
};
net::io_context ioc;
auto db = std::make_shared<connection>(ioc, cfg);
db->async_exec(req0, aedis::adapt(), handler);
db->async_exec(req1, aedis::adapt(), handler);
db->async_exec(req2, aedis::adapt(), handler);
db->async_exec(req2, aedis::adapt(), handler);
db->async_exec(req1, aedis::adapt(), handler);
db->async_exec(req2, aedis::adapt(), handler);
db->async_exec(req1, aedis::adapt(), handler);
db->async_exec(req2, aedis::adapt(), handler);
db->async_exec(req2, aedis::adapt(), handler);
db->async_exec(req1, aedis::adapt(), handler);
db->async_exec(req2, aedis::adapt(), handler);
db->async_exec(req3, aedis::adapt(), handler);
db->async_run([db](auto ec, auto...) {
expect_error(ec, net::error::misc_errors::eof, "test_push_many_subscribes");
db->cancel_receiver();
});
net::co_spawn(ioc.get_executor(), push_consumer3(db), net::detached);
ioc.run();
}
#endif
void 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);
}
int main()
{
test_resolve();
test_connect();
test_quit();
test_push();
#ifdef BOOST_ASIO_HAS_CO_AWAIT
test_reconnect();
#endif
// Must come last as it sends a client pause.
test_idle();
}