Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions include/boost/redis/impl/request.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ auto has_response(std::string_view cmd) -> bool
return true;
if (cmd == "UNSUBSCRIBE")
return true;
if (cmd == "PUNSUBSCRIBE")
return true;
return false;
}

Expand Down
16 changes: 16 additions & 0 deletions test/common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,19 @@ void run_coroutine_test(net::awaitable<void> op, std::chrono::steady_clock::dura
throw std::runtime_error("Coroutine test did not finish");
}
#endif // BOOST_ASIO_HAS_CO_AWAIT

// Finds a value in the output of the CLIENT INFO command
// format: key1=value1 key2=value2
// TODO: duplicated
std::string_view find_client_info(std::string_view client_info, std::string_view key)
{
std::string prefix{key};
prefix += '=';

auto const pos = client_info.find(prefix);
if (pos == std::string_view::npos)
return {};
auto const pos_begin = pos + prefix.size();
auto const pos_end = client_info.find(' ', pos_begin);
return client_info.substr(pos_begin, pos_end - pos_begin);
}
5 changes: 5 additions & 0 deletions test/common.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

#include <chrono>
#include <memory>
#include <string_view>

// The timeout for tests involving communication to a real server.
// Some tests use a longer timeout by multiplying this value by some
Expand All @@ -35,3 +36,7 @@ void run(
boost::redis::config cfg = make_test_config(),
boost::system::error_code ec = boost::asio::error::operation_aborted,
boost::redis::operation op = boost::redis::operation::receive);

// Finds a value in the output of the CLIENT INFO command
// format: key1=value1 key2=value2
std::string_view find_client_info(std::string_view client_info, std::string_view key);
71 changes: 71 additions & 0 deletions test/test_conn_push.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,14 @@

#include <boost/redis/connection.hpp>
#include <boost/redis/logger.hpp>
#include <boost/redis/request.hpp>
#include <boost/redis/response.hpp>

#include <boost/asio/experimental/channel_error.hpp>
#include <boost/system/errc.hpp>

#include <string>

#define BOOST_TEST_MODULE conn_push
#include <boost/test/included/unit_test.hpp>

Expand Down Expand Up @@ -327,4 +331,71 @@ BOOST_AUTO_TEST_CASE(many_subscribers)
BOOST_TEST(finished);
}

BOOST_AUTO_TEST_CASE(test_unsubscribe)
{
net::io_context ioc;
connection conn{ioc};

// Subscribe to 3 channels and 2 patterns. Use CLIENT INFO to verify this took effect
request req_subscribe;
req_subscribe.push("SUBSCRIBE", "ch1", "ch2", "ch3");
req_subscribe.push("PSUBSCRIBE", "ch1*", "ch2*");
req_subscribe.push("CLIENT", "INFO");

// Then, unsubscribe from some of them, and verify again
request req_unsubscribe;
req_unsubscribe.push("UNSUBSCRIBE", "ch1");
req_unsubscribe.push("PUNSUBSCRIBE", "ch2*");
req_unsubscribe.push("CLIENT", "INFO");

// Finally, ping to verify that the connection is still usable
request req_ping;
req_ping.push("PING", "test_unsubscribe");

response<std::string> resp_subscribe, resp_unsubscribe, resp_ping;

bool subscribe_finished = false, unsubscribe_finished = false, ping_finished = false,
run_finished = false;

auto on_ping = [&](error_code ec, std::size_t) {
BOOST_TEST(ec == error_code());
ping_finished = true;
BOOST_TEST(std::get<0>(resp_ping).has_value());
BOOST_TEST(std::get<0>(resp_ping).value() == "test_unsubscribe");
conn.cancel();
};

auto on_unsubscribe = [&](error_code ec, std::size_t) {
unsubscribe_finished = true;
BOOST_TEST(ec == error_code());
BOOST_TEST(std::get<0>(resp_unsubscribe).has_value());
BOOST_TEST(find_client_info(std::get<0>(resp_unsubscribe).value(), "sub") == "2");
BOOST_TEST(find_client_info(std::get<0>(resp_unsubscribe).value(), "psub") == "1");
conn.async_exec(req_ping, resp_ping, on_ping);
};

auto on_subscribe = [&](error_code ec, std::size_t) {
subscribe_finished = true;
BOOST_TEST(ec == error_code());
BOOST_TEST(std::get<0>(resp_subscribe).has_value());
BOOST_TEST(find_client_info(std::get<0>(resp_subscribe).value(), "sub") == "3");
BOOST_TEST(find_client_info(std::get<0>(resp_subscribe).value(), "psub") == "2");
conn.async_exec(req_unsubscribe, resp_unsubscribe, on_unsubscribe);
};

conn.async_exec(req_subscribe, resp_subscribe, on_subscribe);

conn.async_run(make_test_config(), [&run_finished](error_code ec) {
BOOST_TEST(ec == net::error::operation_aborted);
run_finished = true;
});

ioc.run_for(test_timeout);

BOOST_TEST(subscribe_finished);
BOOST_TEST(unsubscribe_finished);
BOOST_TEST(ping_finished);
BOOST_TEST(run_finished);
}

} // namespace
15 changes: 0 additions & 15 deletions test/test_conn_setup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,6 @@ using boost::system::error_code;

namespace {

// Finds a value in the output of the CLIENT INFO command
// format: key1=value1 key2=value2
std::string_view find_client_info(std::string_view client_info, std::string_view key)
{
std::string prefix{key};
prefix += '=';

auto const pos = client_info.find(prefix);
if (pos == std::string_view::npos)
return {};
auto const pos_begin = pos + prefix.size();
auto const pos_end = client_info.find(' ', pos_begin);
return client_info.substr(pos_begin, pos_end - pos_begin);
}

// Creates a user with a known password. Harmless if the user already exists
void setup_password()
{
Expand Down