2025-01-05 08:17:31 +08:00
|
|
|
#include <tuple>
|
|
|
|
|
2018-05-23 02:59:27 +08:00
|
|
|
#include "includes.h"
|
2025-01-05 08:17:31 +08:00
|
|
|
#include "spdlog/sinks/async_sink.h"
|
2018-07-07 17:12:45 +08:00
|
|
|
#include "spdlog/sinks/basic_file_sink.h"
|
2018-05-26 23:48:39 +08:00
|
|
|
#include "test_sink.h"
|
2018-05-23 02:59:27 +08:00
|
|
|
|
2021-01-07 07:55:57 +08:00
|
|
|
#define TEST_FILENAME "test_logs/async_test.log"
|
|
|
|
|
2025-01-05 08:17:31 +08:00
|
|
|
using spdlog::sinks::async_sink;
|
|
|
|
using spdlog::sinks::sink;
|
|
|
|
using spdlog::sinks::test_sink_mt;
|
2025-01-18 04:25:28 +08:00
|
|
|
using namespace std::chrono_literals;
|
2025-01-05 08:17:31 +08:00
|
|
|
|
|
|
|
auto creat_async_logger(size_t queue_size, std::shared_ptr<sink> backend_sink) {
|
|
|
|
async_sink::config cfg;
|
|
|
|
cfg.queue_size = queue_size;
|
|
|
|
cfg.sinks.push_back(std::move(backend_sink));
|
|
|
|
auto s = std::make_shared<async_sink>(cfg);
|
|
|
|
auto logger = std::make_shared<spdlog::logger>("async_logger", s);
|
|
|
|
return std::make_tuple(logger, s);
|
|
|
|
}
|
|
|
|
|
2023-09-25 21:05:07 +08:00
|
|
|
TEST_CASE("basic async test ", "[async]") {
|
2025-01-05 08:17:31 +08:00
|
|
|
const auto test_sink = std::make_shared<test_sink_mt>();
|
2018-08-14 20:21:52 +08:00
|
|
|
size_t overrun_counter = 0;
|
2018-05-26 23:48:39 +08:00
|
|
|
size_t messages = 256;
|
|
|
|
{
|
2025-01-05 08:17:31 +08:00
|
|
|
constexpr size_t queue_size = 16;
|
|
|
|
auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
|
2023-09-25 21:05:07 +08:00
|
|
|
for (size_t i = 0; i < messages; i++) {
|
2018-05-26 23:48:39 +08:00
|
|
|
logger->info("Hello message #{}", i);
|
|
|
|
}
|
|
|
|
logger->flush();
|
2025-01-05 08:17:31 +08:00
|
|
|
overrun_counter = async_sink->get_overrun_counter();
|
2018-05-26 23:48:39 +08:00
|
|
|
}
|
2025-01-05 08:17:31 +08:00
|
|
|
// logger and async_sink are destroyed here so the queue should be emptied
|
2018-05-26 23:48:39 +08:00
|
|
|
REQUIRE(test_sink->msg_counter() == messages);
|
2018-05-27 07:53:16 +08:00
|
|
|
REQUIRE(test_sink->flush_counter() == 1);
|
2018-08-14 19:51:20 +08:00
|
|
|
REQUIRE(overrun_counter == 0);
|
2018-05-23 02:59:27 +08:00
|
|
|
}
|
|
|
|
|
2023-09-25 21:05:07 +08:00
|
|
|
TEST_CASE("discard policy ", "[async]") {
|
2025-01-05 08:17:31 +08:00
|
|
|
auto test_sink = std::make_shared<test_sink_mt>();
|
2025-01-18 04:25:28 +08:00
|
|
|
test_sink->set_delay(1ms);
|
2025-01-05 08:17:31 +08:00
|
|
|
async_sink::config config;
|
|
|
|
config.queue_size = 4;
|
|
|
|
config.policy = async_sink::overflow_policy::overrun_oldest;
|
|
|
|
config.sinks.push_back(test_sink);
|
2018-08-14 05:58:50 +08:00
|
|
|
size_t messages = 1024;
|
2025-01-05 08:17:31 +08:00
|
|
|
auto as = std::make_shared<async_sink>(config);
|
|
|
|
auto logger = std::make_shared<spdlog::logger>("async_logger", as);
|
|
|
|
REQUIRE(as->get_discard_counter() == 0);
|
|
|
|
REQUIRE(as->get_overrun_counter() == 0);
|
2023-09-25 21:05:07 +08:00
|
|
|
for (size_t i = 0; i < messages; i++) {
|
2018-07-22 04:30:26 +08:00
|
|
|
logger->info("Hello message");
|
2018-05-26 23:48:39 +08:00
|
|
|
}
|
2018-05-27 08:14:55 +08:00
|
|
|
REQUIRE(test_sink->msg_counter() < messages);
|
2025-01-05 08:17:31 +08:00
|
|
|
REQUIRE(as->get_overrun_counter() > 0);
|
|
|
|
as->reset_overrun_counter();
|
|
|
|
REQUIRE(as->get_overrun_counter() == 0);
|
2018-05-23 02:59:27 +08:00
|
|
|
}
|
|
|
|
|
2023-09-25 21:05:07 +08:00
|
|
|
TEST_CASE("discard policy discard_new ", "[async]") {
|
2025-01-05 08:17:31 +08:00
|
|
|
auto test_sink = std::make_shared<test_sink_mt>();
|
2025-01-18 04:25:28 +08:00
|
|
|
test_sink->set_delay(1ms);
|
2025-01-05 08:17:31 +08:00
|
|
|
async_sink::config config;
|
|
|
|
config.queue_size = 4;
|
|
|
|
config.policy = async_sink::overflow_policy::discard_new;
|
|
|
|
config.sinks.push_back(test_sink);
|
2023-09-10 04:05:08 +08:00
|
|
|
size_t messages = 1024;
|
2025-01-05 08:17:31 +08:00
|
|
|
auto as = std::make_shared<async_sink>(config);
|
|
|
|
auto logger = std::make_shared<spdlog::logger>("async_logger", as);
|
2023-09-10 04:05:08 +08:00
|
|
|
|
2025-01-05 08:17:31 +08:00
|
|
|
REQUIRE(as->get_config().policy == async_sink::overflow_policy::discard_new);
|
|
|
|
REQUIRE(as->get_discard_counter() == 0);
|
|
|
|
REQUIRE(as->get_overrun_counter() == 0);
|
2023-09-25 21:05:07 +08:00
|
|
|
for (size_t i = 0; i < messages; i++) {
|
2018-07-22 04:30:26 +08:00
|
|
|
logger->info("Hello message");
|
|
|
|
}
|
2018-08-14 05:58:50 +08:00
|
|
|
REQUIRE(test_sink->msg_counter() < messages);
|
2025-01-05 08:17:31 +08:00
|
|
|
REQUIRE(as->get_discard_counter() > 0);
|
|
|
|
as->reset_discard_counter();
|
|
|
|
REQUIRE(as->get_discard_counter() == 0);
|
2018-07-21 05:33:27 +08:00
|
|
|
}
|
|
|
|
|
2023-09-25 21:05:07 +08:00
|
|
|
TEST_CASE("flush", "[async]") {
|
2025-01-05 08:17:31 +08:00
|
|
|
auto test_sink = std::make_shared<test_sink_mt>();
|
2018-05-26 23:48:39 +08:00
|
|
|
size_t messages = 256;
|
|
|
|
{
|
2025-01-05 08:17:31 +08:00
|
|
|
constexpr size_t queue_size = 256;
|
|
|
|
auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
|
2023-09-25 21:05:07 +08:00
|
|
|
for (size_t i = 0; i < messages; i++) {
|
2018-05-26 23:48:39 +08:00
|
|
|
logger->info("Hello message #{}", i);
|
|
|
|
}
|
|
|
|
logger->flush();
|
|
|
|
}
|
|
|
|
REQUIRE(test_sink->msg_counter() == messages);
|
2018-05-27 07:53:16 +08:00
|
|
|
REQUIRE(test_sink->flush_counter() == 1);
|
|
|
|
}
|
|
|
|
|
2025-01-05 08:17:31 +08:00
|
|
|
TEST_CASE("wait_dtor ", "[async]") {
|
|
|
|
auto test_sink = std::make_shared<test_sink_mt>();
|
2025-01-18 04:25:28 +08:00
|
|
|
test_sink->set_delay(5ms);
|
2025-01-05 08:17:31 +08:00
|
|
|
async_sink::config config;
|
|
|
|
config.sinks.push_back(test_sink);
|
|
|
|
config.queue_size = 4;
|
|
|
|
config.policy = async_sink::overflow_policy::block;
|
2018-06-01 22:25:23 +08:00
|
|
|
size_t messages = 100;
|
2025-01-05 08:17:31 +08:00
|
|
|
{
|
|
|
|
auto as = std::make_shared<async_sink>(config);
|
|
|
|
auto logger = std::make_shared<spdlog::logger>("async_logger", as);
|
|
|
|
for (size_t i = 0; i < messages; i++) {
|
|
|
|
logger->info("Hello message #{}", i);
|
|
|
|
}
|
|
|
|
logger->flush();
|
|
|
|
REQUIRE(as->get_overrun_counter() == 0);
|
|
|
|
REQUIRE(as->get_discard_counter() == 0);
|
2018-05-27 07:53:16 +08:00
|
|
|
}
|
2018-06-01 22:25:23 +08:00
|
|
|
|
2018-05-27 07:53:16 +08:00
|
|
|
REQUIRE(test_sink->msg_counter() == messages);
|
|
|
|
REQUIRE(test_sink->flush_counter() == 1);
|
2018-05-23 02:59:27 +08:00
|
|
|
}
|
|
|
|
|
2023-09-25 21:05:07 +08:00
|
|
|
TEST_CASE("multi threads", "[async]") {
|
2020-04-08 23:17:21 +08:00
|
|
|
auto test_sink = std::make_shared<spdlog::sinks::test_sink_mt>();
|
2018-05-26 23:48:39 +08:00
|
|
|
size_t messages = 256;
|
|
|
|
size_t n_threads = 10;
|
|
|
|
{
|
2025-01-05 08:17:31 +08:00
|
|
|
constexpr size_t queue_size = 128;
|
|
|
|
auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
|
2018-05-26 23:48:39 +08:00
|
|
|
|
|
|
|
std::vector<std::thread> threads;
|
2023-09-25 21:05:07 +08:00
|
|
|
for (size_t i = 0; i < n_threads; i++) {
|
2025-01-05 08:17:31 +08:00
|
|
|
threads.emplace_back([l = logger, msgs = messages] {
|
|
|
|
for (size_t j = 0; j < msgs; j++) {
|
|
|
|
l->info("Hello message #{}", j);
|
2018-05-26 23:48:39 +08:00
|
|
|
}
|
|
|
|
});
|
2018-05-27 08:14:55 +08:00
|
|
|
logger->flush();
|
2018-05-26 23:48:39 +08:00
|
|
|
}
|
2018-05-23 02:59:27 +08:00
|
|
|
|
2023-09-25 21:05:07 +08:00
|
|
|
for (auto &t : threads) {
|
2018-05-26 23:48:39 +08:00
|
|
|
t.join();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
REQUIRE(test_sink->msg_counter() == messages * n_threads);
|
2018-05-27 07:53:16 +08:00
|
|
|
REQUIRE(test_sink->flush_counter() == n_threads);
|
2018-05-23 02:59:27 +08:00
|
|
|
}
|
|
|
|
|
2023-09-25 21:05:07 +08:00
|
|
|
TEST_CASE("to_file", "[async]") {
|
2018-05-27 07:21:49 +08:00
|
|
|
prepare_logdir();
|
|
|
|
size_t messages = 1024;
|
|
|
|
{
|
2025-01-05 08:17:31 +08:00
|
|
|
spdlog::filename_t filename = SPDLOG_FILENAME_T(TEST_FILENAME);
|
2018-07-07 17:12:45 +08:00
|
|
|
auto file_sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(filename, true);
|
2025-01-05 08:17:31 +08:00
|
|
|
auto [logger, async_sink] = creat_async_logger(messages, file_sink);
|
2018-05-27 07:21:49 +08:00
|
|
|
|
2023-09-25 21:05:07 +08:00
|
|
|
for (size_t j = 0; j < messages; j++) {
|
2018-05-27 07:21:49 +08:00
|
|
|
logger->info("Hello message #{}", j);
|
|
|
|
}
|
|
|
|
}
|
2021-01-07 07:55:57 +08:00
|
|
|
require_message_count(TEST_FILENAME, messages);
|
|
|
|
auto contents = file_contents(TEST_FILENAME);
|
2020-02-05 05:23:36 +08:00
|
|
|
using spdlog::details::os::default_eol;
|
2021-11-14 00:29:05 +08:00
|
|
|
REQUIRE(ends_with(contents, spdlog::fmt_lib::format("Hello message #1023{}", default_eol)));
|
2018-05-27 07:21:31 +08:00
|
|
|
}
|
2018-05-23 02:59:27 +08:00
|
|
|
|
2025-01-05 08:17:31 +08:00
|
|
|
TEST_CASE("bad_ctor", "[async]") {
|
|
|
|
async_sink::config cfg;
|
|
|
|
cfg.queue_size = 0;
|
|
|
|
REQUIRE_THROWS_AS(std::make_shared<async_sink>(cfg), spdlog::spdlog_ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("bad_ctor2", "[async]") {
|
|
|
|
async_sink::config cfg;
|
|
|
|
cfg.queue_size = async_sink::max_queue_size + 1;
|
|
|
|
REQUIRE_THROWS_AS(std::make_shared<async_sink>(cfg), spdlog::spdlog_ex);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("start_stop_clbks", "[async]") {
|
|
|
|
bool start_called = false;
|
|
|
|
bool stop_called = false;
|
|
|
|
{
|
|
|
|
async_sink::config cfg;
|
|
|
|
cfg.on_thread_start = [&] { start_called = true; };
|
|
|
|
cfg.on_thread_stop = [&] { stop_called = true; };
|
|
|
|
auto sink = std::make_shared<async_sink>(cfg);
|
|
|
|
}
|
|
|
|
REQUIRE(start_called);
|
|
|
|
REQUIRE(stop_called);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("start_stop_clbks2", "[async]") {
|
|
|
|
bool start_called = false;
|
|
|
|
bool stop_called = false;
|
|
|
|
{
|
|
|
|
async_sink::config cfg;
|
|
|
|
cfg.on_thread_start = [&] { start_called = true; };
|
|
|
|
auto sink = std::make_shared<async_sink>(cfg);
|
|
|
|
}
|
|
|
|
REQUIRE(start_called);
|
|
|
|
REQUIRE_FALSE(stop_called);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("start_stop_clbks3", "[async]") {
|
|
|
|
bool start_called = false;
|
|
|
|
bool stop_called = false;
|
|
|
|
{
|
|
|
|
async_sink::config cfg;
|
|
|
|
cfg.on_thread_start = nullptr;
|
|
|
|
cfg.on_thread_stop = [&] { stop_called = true; };
|
|
|
|
auto sink = std::make_shared<async_sink>(cfg);
|
|
|
|
}
|
|
|
|
REQUIRE_FALSE(start_called);
|
|
|
|
REQUIRE(stop_called);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("start_stop_clbks4", "[async]") {
|
|
|
|
bool start_called = false;
|
|
|
|
bool stop_called = false;
|
|
|
|
{
|
|
|
|
async_sink::config cfg;
|
|
|
|
cfg.on_thread_start = [&] { start_called = true; };
|
|
|
|
cfg.on_thread_stop = [&] { stop_called = true; };
|
|
|
|
cfg.queue_size = 128;
|
|
|
|
auto sink = std::make_shared<async_sink>(cfg);
|
|
|
|
}
|
|
|
|
REQUIRE(start_called);
|
|
|
|
REQUIRE(stop_called);
|
|
|
|
}
|
|
|
|
|
|
|
|
// should not start threads if queue size is invalid
|
|
|
|
TEST_CASE("start_stop_clbks5", "[async]") {
|
|
|
|
bool start_called = false;
|
|
|
|
bool stop_called = false;
|
|
|
|
{
|
|
|
|
async_sink::config cfg;
|
|
|
|
cfg.on_thread_start = [&] { start_called = true; };
|
|
|
|
cfg.on_thread_stop = [&] { stop_called = true; };
|
|
|
|
cfg.queue_size = 0;
|
|
|
|
REQUIRE_THROWS_AS(std::make_shared<async_sink>(cfg), spdlog::spdlog_ex);
|
|
|
|
}
|
|
|
|
REQUIRE_FALSE(start_called);
|
|
|
|
REQUIRE_FALSE(stop_called);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("multi-sinks", "[async]") {
|
2018-05-27 07:21:49 +08:00
|
|
|
prepare_logdir();
|
2025-01-05 08:17:31 +08:00
|
|
|
auto test_sink1 = std::make_shared<test_sink_mt>();
|
|
|
|
auto test_sink2 = std::make_shared<test_sink_mt>();
|
|
|
|
auto test_sink3 = std::make_shared<test_sink_mt>();
|
|
|
|
size_t messages = 1024;
|
2018-05-27 07:21:49 +08:00
|
|
|
{
|
2025-01-05 08:17:31 +08:00
|
|
|
async_sink::config cfg;
|
|
|
|
cfg.sinks.push_back(test_sink1);
|
|
|
|
cfg.sinks.push_back(test_sink2);
|
|
|
|
cfg.sinks.push_back(test_sink3);
|
|
|
|
auto as = std::make_shared<async_sink>(cfg);
|
|
|
|
spdlog::logger l("async_logger", as);
|
2018-05-27 07:21:49 +08:00
|
|
|
|
2023-09-25 21:05:07 +08:00
|
|
|
for (size_t j = 0; j < messages; j++) {
|
2025-01-05 08:17:31 +08:00
|
|
|
l.info("Hello message #{}", j);
|
2018-05-27 07:21:49 +08:00
|
|
|
}
|
|
|
|
}
|
2025-01-05 08:17:31 +08:00
|
|
|
REQUIRE(test_sink1->msg_counter() == messages);
|
|
|
|
REQUIRE(test_sink2->msg_counter() == messages);
|
|
|
|
REQUIRE(test_sink3->msg_counter() == messages);
|
2018-05-23 02:59:27 +08:00
|
|
|
}
|
2023-05-27 20:33:02 +08:00
|
|
|
|
2025-01-05 08:17:31 +08:00
|
|
|
TEST_CASE("level-off", "[async]") {
|
|
|
|
const auto test_sink = std::make_shared<test_sink_mt>();
|
|
|
|
test_sink->set_level(spdlog::level::critical);
|
|
|
|
{
|
|
|
|
constexpr size_t messages = 256;
|
|
|
|
constexpr size_t queue_size = 16;
|
|
|
|
auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
|
|
|
|
logger->flush_on(spdlog::level::critical);
|
|
|
|
for (size_t i = 0; i < messages; i++) {
|
|
|
|
logger->info("Hello message #{}", i);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// logger and async_sink are destroyed here so the queue should be emptied
|
2023-05-27 20:33:02 +08:00
|
|
|
REQUIRE(test_sink->msg_counter() == 0);
|
2025-01-05 08:17:31 +08:00
|
|
|
REQUIRE(test_sink->flush_counter() == 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
TEST_CASE("backend_ex", "[async]") {
|
|
|
|
const auto test_sink = std::make_shared<test_sink_mt>();
|
|
|
|
test_sink->set_exception(std::runtime_error("test backend exception"));
|
|
|
|
constexpr size_t queue_size = 16;
|
|
|
|
auto [logger, async_sink] = creat_async_logger(queue_size, test_sink);
|
|
|
|
REQUIRE_NOTHROW(logger->info("Hello message"));
|
|
|
|
REQUIRE_NOTHROW(logger->flush());
|
2023-05-27 20:33:02 +08:00
|
|
|
}
|
2025-01-17 19:30:37 +08:00
|
|
|
|
|
|
|
// test async custom error handler. trigger it using a backend exception and make sure it's called
|
|
|
|
TEST_CASE("custom_err_handler", "[async]") {
|
|
|
|
bool error_called = false;
|
|
|
|
auto test_sink = std::make_shared<test_sink_mt>();
|
|
|
|
test_sink->set_exception(std::runtime_error("test backend exception"));
|
|
|
|
async_sink::config config;
|
|
|
|
config.sinks.push_back(std::move(test_sink));
|
2025-01-18 02:59:46 +08:00
|
|
|
config.custom_err_handler = [&error_called](const std::string &) { error_called = true; };
|
2025-01-17 19:30:37 +08:00
|
|
|
auto asink = std::make_shared<async_sink>(config);
|
2025-01-18 02:59:46 +08:00
|
|
|
spdlog::logger("async_logger", std::move(asink)).info("Test");
|
2025-01-17 19:30:37 +08:00
|
|
|
// lvalue logger so will be destructed here already so all messages were processed
|
|
|
|
REQUIRE(error_called);
|
|
|
|
}
|
2025-01-17 22:17:11 +08:00
|
|
|
|
|
|
|
// test wait_all
|
|
|
|
TEST_CASE("wait_all", "[async]") {
|
|
|
|
auto test_sink = std::make_shared<test_sink_mt>();
|
2025-01-18 04:25:28 +08:00
|
|
|
auto delay = 10ms;
|
2025-01-17 22:17:11 +08:00
|
|
|
test_sink->set_delay(delay);
|
|
|
|
async_sink::config config;
|
|
|
|
config.sinks.push_back(test_sink);
|
|
|
|
size_t messages = 10;
|
|
|
|
auto as = std::make_shared<async_sink>(config);
|
|
|
|
auto logger = std::make_shared<spdlog::logger>("async_logger", as);
|
|
|
|
for (size_t i = 0; i < messages; i++) {
|
|
|
|
logger->info("Hello message");
|
|
|
|
}
|
2025-01-18 04:25:28 +08:00
|
|
|
REQUIRE_FALSE(as->wait_all(-10ms));
|
|
|
|
REQUIRE_FALSE(as->wait_all(0ms));
|
2025-01-17 22:17:11 +08:00
|
|
|
auto start = std::chrono::steady_clock::now();
|
|
|
|
REQUIRE_FALSE(as->wait_all(delay));
|
|
|
|
|
|
|
|
// should have waited approx 10ms before giving up
|
|
|
|
auto elapsed = std::chrono::steady_clock::now() - start;
|
|
|
|
REQUIRE(elapsed >= delay);
|
2025-01-18 05:18:33 +08:00
|
|
|
REQUIRE(elapsed < delay * 6); // big tolerance, to pass tests in slow virtual machines
|
2025-01-17 22:17:11 +08:00
|
|
|
// wait enough time for all messages to be processed
|
2025-01-18 04:25:28 +08:00
|
|
|
REQUIRE(as->wait_all(messages * delay + 500ms));
|
|
|
|
REQUIRE(as->wait_all(-10ms)); // no more messages
|
|
|
|
REQUIRE(as->wait_all(0ms)); // no more messages
|
|
|
|
REQUIRE(as->wait_all(10ms)); // no more messages
|
2025-01-17 22:17:11 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// test wait_all without timeout
|
|
|
|
TEST_CASE("wait_all2", "[async]") {
|
|
|
|
auto test_sink = std::make_shared<test_sink_mt>();
|
2025-01-18 04:25:28 +08:00
|
|
|
auto delay = 10ms;
|
2025-01-17 22:17:11 +08:00
|
|
|
test_sink->set_delay(delay);
|
|
|
|
async_sink::config config;
|
|
|
|
config.sinks.push_back(test_sink);
|
|
|
|
size_t messages = 10;
|
|
|
|
auto as = std::make_shared<async_sink>(config);
|
|
|
|
auto logger = std::make_shared<spdlog::logger>("async_logger", as);
|
|
|
|
for (size_t i = 0; i < messages; i++) {
|
|
|
|
logger->info("Hello message");
|
|
|
|
}
|
|
|
|
as->wait_all();
|
|
|
|
REQUIRE(test_sink->msg_counter() == messages);
|
|
|
|
}
|