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-04-23 16:37:53 +02:00

394 lines
8.6 KiB
C++

/* Copyright (c) 2019 Marcelo Zimbres Silva (mzimbres@gmail.com)
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <iostream>
#include <map>
#include <boost/asio.hpp>
#include <boost/system/errc.hpp>
#include <aedis/aedis.hpp>
#include <aedis/src.hpp>
#include "check.hpp"
namespace net = boost::asio;
namespace resp3 = aedis::resp3;
using aedis::resp3::node;
using aedis::redis::command;
using aedis::generic::make_serializer;
using aedis::adapter::adapt;
using aedis::adapter::adapter_t;
using node_type = aedis::resp3::node<std::string>;
using tcp = net::ip::tcp;
using tcp_socket = net::use_awaitable_t<>::as_default_on_t<tcp::socket>;
using client_type = aedis::generic::client<net::ip::tcp::socket, command>;
auto print_read = [](auto cmd, auto n)
{
std::cout << cmd << ": " << n << std::endl;
};
void test_resolve_error()
{
auto f = [](auto ec)
{
expect_error(ec, net::error::netdb_errors::host_not_found);
};
net::io_context ioc;
client_type db(ioc.get_executor());
db.async_run("Atibaia", "6379", f);
ioc.run();
}
void test_connect_error()
{
auto f = [](auto ec)
{
expect_error(ec, net::error::basic_errors::connection_refused);
};
net::io_context ioc;
client_type db(ioc.get_executor());
db.async_run("127.0.0.1", "1", f);
ioc.run();
}
struct receiver1 {
public:
receiver1(client_type& db) : db_{&db} {}
void on_read(command cmd, std::size_t)
{
// quit will be sent more than once. It doesn't matter.
db_->send(command::quit);
}
private:
client_type* db_;
};
// Test if a hello is automatically sent.
void test_hello()
{
auto f = [](auto ec)
{
expect_error(ec, net::error::misc_errors::eof);
};
net::io_context ioc;
client_type db(ioc.get_executor());
receiver1 recv{db};
db.set_read_handler([&recv](command cmd, std::size_t n){recv.on_read(cmd, n);});
db.async_run("127.0.0.1", "6379", f);
ioc.run();
}
struct receiver2 {
public:
receiver2(client_type& db) : db_{&db} {}
void on_write(std::size_t)
{
// Notice this causes a loop, but since quit stops the
// connection it is not a problem.
db_->send(command::quit);
}
private:
client_type* db_;
};
// Test if a hello is automatically sent but this time, uses on_write
// to send the quit command. Notice quit will be sent twice.
void test_hello2()
{
auto f = [](auto ec)
{
expect_error(ec, net::error::misc_errors::eof);
};
net::io_context ioc;
client_type db(ioc.get_executor());
receiver2 recv{db};
//db.set_read_handler(print_read);
db.set_write_handler([&recv](std::size_t n){recv.on_write(n);});
db.async_run("127.0.0.1", "6379", f);
ioc.run();
}
struct receiver3 {
public:
receiver3(client_type& db) : db_{&db} {}
void on_write(std::size_t)
{
// Notice this causes a loop.
db_->send(command::subscribe, "channel");
}
void on_push(std::size_t)
{
db_->send(command::quit);
}
private:
client_type* db_;
};
void test_push()
{
auto f = [](auto ec)
{
expect_error(ec, net::error::misc_errors::eof);
};
net::io_context ioc;
client_type db(ioc.get_executor());
receiver3 recv{db};
db.set_write_handler([&recv](std::size_t n){recv.on_write(n);});
db.set_push_handler([&recv](std::size_t n){recv.on_push(n);});
db.async_run("127.0.0.1", "6379", f);
ioc.run();
}
struct receiver4 {
public:
receiver4(client_type& db) : db_{&db} {}
void on_read()
{
// Notice this causes a loop.
db_->send(command::subscribe, "channel");
}
void on_push()
{
db_->send(command::quit);
}
private:
client_type* db_;
};
void test_push2()
{
auto f = [](auto ec)
{
expect_error(ec, net::error::misc_errors::eof);
};
net::io_context ioc;
client_type db(ioc.get_executor());
receiver4 recv{db};
db.set_read_handler([&recv](auto, auto){recv.on_read();});
db.set_push_handler([&recv](auto){recv.on_push();});
db.async_run("127.0.0.1", "6379", f);
ioc.run();
}
#include <boost/asio/yield.hpp>
struct receiver5 {
public:
int counter = 0;
receiver5(client_type& db)
: db_{&db}
, adapter_{adapt(counter)}
{}
void on_read(command) {}
void on_write()
{
if (counter == 0) {
// Avoid problems with previous runs.
db_->send(command::del, "receiver5-key");
db_->send(command::incr, "receiver5-key");
db_->send(command::quit);
}
if (counter == 1) {
db_->send(command::incr, "receiver5-key");
db_->send(command::quit);
}
}
void on_resp3(command cmd, node<boost::string_view> const& nd, boost::system::error_code& ec)
{
if (cmd == command::incr)
adapter_(nd, ec);
}
private:
client_type* db_;
adapter_t<int> adapter_;
};
template <class Receiver>
struct reconnect {
client_type db;
Receiver recv;
boost::asio::steady_timer timer;
net::coroutine coro;
reconnect(net::any_io_executor ex)
: db{ex}
, recv{db}
, timer{ex}
{
db.set_read_handler([this](auto cmd, auto){recv.on_read(cmd);});
db.set_write_handler([this](auto){recv.on_write();});
db.set_resp3_handler([this](auto a, auto b, auto c){recv.on_resp3(a, b, c);});
}
void on_event(boost::system::error_code ec)
{
reenter (coro) for (;;) {
yield db.async_run("127.0.0.1", "6379", [this](auto ec){ on_event(ec);});
expect_error(ec, net::error::misc_errors::eof);
expect_eq(recv.counter, 1, "Reconnect counter 1.");
yield db.async_run("127.0.0.1", "6379", [this](auto ec){ on_event(ec);});
expect_error(ec, net::error::misc_errors::eof);
expect_eq(recv.counter, 2, "Reconnect counter 2.");
yield db.async_run("127.0.0.1", "6379", [this](auto ec){ on_event(ec);});
expect_error(ec, net::error::misc_errors::eof);
expect_eq(recv.counter, 3, "Reconnect counter 3.");
return;
}
}
};
#include <boost/asio/unyield.hpp>
void test_reconnect()
{
net::io_context ioc;
reconnect<receiver5> rec{ioc.get_executor()};
rec.on_event({});
ioc.run();
}
struct receiver6 {
public:
int counter = 0;
receiver6(client_type& db)
: db_{&db}
, adapter_{adapt(counter)}
{}
void on_write() {}
void on_read(command cmd)
{
if (cmd == command::hello) {
db_->send(command::get, "receiver6-key");
if (counter == 0)
db_->send(command::del, "receiver6-key");
db_->send(command::incr, "receiver6-key");
db_->send(command::quit);
return;
}
}
void on_resp3(command cmd, node<boost::string_view> const& nd, boost::system::error_code& ec)
{
if (cmd == command::incr)
adapter_(nd, ec);
}
private:
client_type* db_;
adapter_t<int> adapter_;
};
void test_reconnect2()
{
net::io_context ioc;
reconnect<receiver6> rec{ioc.get_executor()};
rec.on_event({});
ioc.run();
}
struct receiver7 {
public:
int counter = 0;
receiver7(client_type& db)
: db_{&db}
, adapter_{adapt(counter)}
{}
void on_resp3(command cmd, node<boost::string_view> const& nd, boost::system::error_code& ec)
{
if (cmd == command::incr)
adapter_(nd, ec);
}
void on_write(std::size_t)
{
if (!std::exchange(sent_, true)) {
db_->send(command::del, "key");
db_->send(command::multi);
db_->send(command::ping, "aaa");
db_->send(command::incr, "key");
db_->send(command::ping, "bbb");
db_->send(command::discard);
db_->send(command::ping, "ccc");
db_->send(command::incr, "key");
db_->send(command::quit);
}
}
void on_read(command cmd, std::size_t)
{
}
private:
bool sent_ = false;
client_type* db_;
adapter_t<int> adapter_;
};
void test_discard()
{
auto f = [](auto ec)
{
expect_error(ec, net::error::misc_errors::eof);
};
net::io_context ioc;
client_type db(ioc.get_executor());
receiver7 recv{db};
db.set_read_handler([&recv](auto cmd, std::size_t n){recv.on_read(cmd, n);});
db.set_write_handler([&recv](std::size_t n){recv.on_write(n);});
db.set_resp3_handler([&recv](auto a, auto b, auto c){recv.on_resp3(a, b, c);});
db.async_run("127.0.0.1", "6379", f);
ioc.run();
expect_eq(recv.counter, 1, "test_discard.");
}
int main()
{
test_resolve_error();
test_connect_error();
test_hello();
test_hello2();
test_push();
test_push2();
test_reconnect();
test_reconnect2();
test_discard();
}