|
|
|
/**
|
|
|
|
*
|
|
|
|
* \section COPYRIGHT
|
|
|
|
*
|
|
|
|
* Copyright 2013-2021 Software Radio Systems Limited
|
|
|
|
*
|
|
|
|
* By using this file, you agree to the terms and conditions set
|
|
|
|
* forth in the LICENSE file which can be found at the top level of
|
|
|
|
* the distribution.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "src/srslog/log_backend_impl.h"
|
|
|
|
#include "test_dummies.h"
|
|
|
|
#include "testing_helpers.h"
|
|
|
|
|
|
|
|
using namespace srslog;
|
|
|
|
|
|
|
|
static bool when_backend_is_started_then_is_started_returns_true()
|
|
|
|
{
|
|
|
|
log_backend_impl backend;
|
|
|
|
|
|
|
|
ASSERT_EQ(backend.is_running(), false);
|
|
|
|
backend.start();
|
|
|
|
ASSERT_EQ(backend.is_running(), true);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool when_backend_is_started_and_stopped_then_is_started_returns_false()
|
|
|
|
{
|
|
|
|
log_backend_impl backend;
|
|
|
|
|
|
|
|
backend.start();
|
|
|
|
backend.stop();
|
|
|
|
|
|
|
|
ASSERT_EQ(backend.is_running(), false);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
/// A Spy implementation of a log sink. Tests can query the last received memory
|
|
|
|
/// buffer by the sink and the number of invocations to the write method.
|
|
|
|
class sink_spy : public sink
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
sink_spy() :
|
|
|
|
sink(std::unique_ptr<log_formatter>(new test_dummies::log_formatter_dummy))
|
|
|
|
{}
|
|
|
|
|
|
|
|
detail::error_string write(detail::memory_buffer buffer) override
|
|
|
|
{
|
|
|
|
++count;
|
|
|
|
str.insert(0, buffer.data(), buffer.size());
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
|
|
|
detail::error_string flush() override { return {}; }
|
|
|
|
|
|
|
|
unsigned write_invocation_count() const { return count; }
|
|
|
|
|
|
|
|
const std::string& received_buffer() const { return str; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
unsigned count = 0;
|
|
|
|
std::string str;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
/// Builds a basic log entry.
|
|
|
|
static detail::log_entry build_log_entry(sink* s)
|
|
|
|
{
|
|
|
|
using tp_ty = std::chrono::time_point<std::chrono::high_resolution_clock>;
|
|
|
|
tp_ty tp;
|
|
|
|
|
|
|
|
fmt::dynamic_format_arg_store<fmt::printf_context> store;
|
|
|
|
store.push_back(88);
|
|
|
|
|
|
|
|
return {
|
|
|
|
s,
|
|
|
|
[](detail::log_entry_metadata&& metadata, fmt::memory_buffer& buffer) {},
|
|
|
|
{tp, {0, false}, "Text %d", std::move(store), "", '\0', small_str_buffer()}};
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool when_backend_is_not_started_then_pushed_log_entries_are_ignored()
|
|
|
|
{
|
|
|
|
sink_spy spy;
|
|
|
|
log_backend_impl backend;
|
|
|
|
|
|
|
|
backend.push(build_log_entry(&spy));
|
|
|
|
|
|
|
|
ASSERT_EQ(spy.write_invocation_count(), 0);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool when_backend_is_started_then_pushed_log_entries_are_sent_to_sink()
|
|
|
|
{
|
|
|
|
sink_spy spy;
|
|
|
|
|
|
|
|
log_backend_impl backend;
|
|
|
|
backend.start();
|
|
|
|
|
|
|
|
backend.push(build_log_entry(&spy));
|
|
|
|
|
|
|
|
// Stop the backend to ensure the entry has been processed.
|
|
|
|
backend.stop();
|
|
|
|
|
|
|
|
ASSERT_EQ(spy.write_invocation_count(), 1);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool when_backend_is_started_then_backend_invokes_format_func()
|
|
|
|
{
|
|
|
|
test_dummies::sink_dummy s;
|
|
|
|
|
|
|
|
log_backend_impl backend;
|
|
|
|
backend.start();
|
|
|
|
|
|
|
|
auto entry = build_log_entry(&s);
|
|
|
|
unsigned counter = 0;
|
|
|
|
entry.format_func = [&counter](detail::log_entry_metadata&& metadata,
|
|
|
|
fmt::memory_buffer& buffer) { ++counter; };
|
|
|
|
backend.push(std::move(entry));
|
|
|
|
|
|
|
|
// Stop the backend to ensure the entry has been processed.
|
|
|
|
backend.stop();
|
|
|
|
|
|
|
|
ASSERT_EQ(counter, 1);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
|
|
|
/// A Configurable Stub implementation of an object to be invoked by the
|
|
|
|
/// backend. Upon invocation, instances of this class return an error that can
|
|
|
|
/// be configured dynamically.
|
|
|
|
class sink_error_stub : public sink
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
explicit sink_error_stub(std::string err) :
|
|
|
|
sink(std::unique_ptr<log_formatter>(new test_dummies::log_formatter_dummy)),
|
|
|
|
err(std::move(err))
|
|
|
|
{}
|
|
|
|
|
|
|
|
detail::error_string write(detail::memory_buffer buffer) override
|
|
|
|
{
|
|
|
|
return err;
|
|
|
|
}
|
|
|
|
|
|
|
|
detail::error_string flush() override { return err; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
std::string err;
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
static bool when_sink_write_fails_then_error_handler_is_invoked()
|
|
|
|
{
|
|
|
|
std::string error_str("error");
|
|
|
|
sink_error_stub s(error_str);
|
|
|
|
|
|
|
|
bool valid_err = false;
|
|
|
|
unsigned count = 0;
|
|
|
|
// valid_err checks that the input error matches the expected string.
|
|
|
|
// The count variable counts the number of calls.
|
|
|
|
auto handler = [&count, &valid_err, error_str](const std::string& error) {
|
|
|
|
valid_err = (error == error_str);
|
|
|
|
++count;
|
|
|
|
};
|
|
|
|
|
|
|
|
log_backend_impl backend;
|
|
|
|
backend.set_error_handler(handler);
|
|
|
|
backend.start();
|
|
|
|
|
|
|
|
backend.push(build_log_entry(&s));
|
|
|
|
|
|
|
|
// Stop the backend to ensure the entry has been processed.
|
|
|
|
backend.stop();
|
|
|
|
|
|
|
|
ASSERT_EQ(valid_err, true);
|
|
|
|
ASSERT_EQ(count, 1);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool when_handler_is_set_after_start_then_handler_is_not_used()
|
|
|
|
{
|
|
|
|
sink_error_stub s("test");
|
|
|
|
|
|
|
|
unsigned count = 0;
|
|
|
|
// The count variable counts the number of calls.
|
|
|
|
auto handler = [&count](const std::string& error) { ++count; };
|
|
|
|
|
|
|
|
log_backend_impl backend;
|
|
|
|
// We want to remove output to stderr by the default handler.
|
|
|
|
backend.set_error_handler([](const std::string&) {});
|
|
|
|
backend.start();
|
|
|
|
backend.set_error_handler(handler);
|
|
|
|
|
|
|
|
backend.push(build_log_entry(&s));
|
|
|
|
|
|
|
|
// Stop the backend to ensure the entry has been processed.
|
|
|
|
backend.stop();
|
|
|
|
|
|
|
|
ASSERT_EQ(count, 0);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool when_empty_handler_is_used_then_backend_does_not_crash()
|
|
|
|
{
|
|
|
|
sink_error_stub s("test");
|
|
|
|
|
|
|
|
log_backend_impl backend;
|
|
|
|
// We want to remove output to stderr by the default handler.
|
|
|
|
backend.set_error_handler({});
|
|
|
|
backend.start();
|
|
|
|
|
|
|
|
backend.push(build_log_entry(&s));
|
|
|
|
|
|
|
|
// Stop the backend to ensure the entry has been processed.
|
|
|
|
backend.stop();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int main()
|
|
|
|
{
|
|
|
|
TEST_FUNCTION(when_backend_is_started_then_is_started_returns_true);
|
|
|
|
TEST_FUNCTION(
|
|
|
|
when_backend_is_started_and_stopped_then_is_started_returns_false);
|
|
|
|
TEST_FUNCTION(
|
|
|
|
when_backend_is_not_started_then_pushed_log_entries_are_ignored);
|
|
|
|
TEST_FUNCTION(
|
|
|
|
when_backend_is_started_then_pushed_log_entries_are_sent_to_sink);
|
|
|
|
TEST_FUNCTION(when_backend_is_started_then_backend_invokes_format_func);
|
|
|
|
TEST_FUNCTION(when_sink_write_fails_then_error_handler_is_invoked);
|
|
|
|
TEST_FUNCTION(when_handler_is_set_after_start_then_handler_is_not_used);
|
|
|
|
TEST_FUNCTION(when_empty_handler_is_used_then_backend_does_not_crash);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|