fix: Keep spdlog loggers valid between tests (#2614)

This commit is contained in:
Ayaz Salikhov
2025-09-15 14:47:35 +01:00
committed by GitHub
parent e996f2b7ab
commit 3f2ada3439
53 changed files with 353 additions and 204 deletions

View File

@@ -42,7 +42,7 @@ using namespace util;
static constexpr auto kLOG_FORMAT = "%Y-%m-%d %H:%M:%S.%f %^%3!l:%n%$ - %v"; static constexpr auto kLOG_FORMAT = "%Y-%m-%d %H:%M:%S.%f %^%3!l:%n%$ - %v";
struct BenchmarkLoggingInitializer { struct BenchmarkLoggingInitializer {
static std::shared_ptr<spdlog::sinks::sink> [[nodiscard]] static std::shared_ptr<spdlog::sinks::sink>
createFileSink(LogService::FileLoggingParams const& params) createFileSink(LogService::FileLoggingParams const& params)
{ {
return LogService::createFileSink(params, kLOG_FORMAT); return LogService::createFileSink(params, kLOG_FORMAT);
@@ -72,8 +72,6 @@ uniqueLogDir()
static void static void
benchmarkConcurrentFileLogging(benchmark::State& state) benchmarkConcurrentFileLogging(benchmark::State& state)
{ {
spdlog::drop_all();
auto const numThreads = static_cast<size_t>(state.range(0)); auto const numThreads = static_cast<size_t>(state.range(0));
auto const messagesPerThread = static_cast<size_t>(state.range(1)); auto const messagesPerThread = static_cast<size_t>(state.range(1));
@@ -84,7 +82,9 @@ benchmarkConcurrentFileLogging(benchmark::State& state)
state.PauseTiming(); state.PauseTiming();
std::filesystem::create_directories(logDir); std::filesystem::create_directories(logDir);
spdlog::init_thread_pool(8192, 1); static constexpr size_t kQUEUE_SIZE = 8192;
static constexpr size_t kTHREAD_COUNT = 1;
spdlog::init_thread_pool(kQUEUE_SIZE, kTHREAD_COUNT);
auto fileSink = BenchmarkLoggingInitializer::createFileSink({ auto fileSink = BenchmarkLoggingInitializer::createFileSink({
.logDir = logDir, .logDir = logDir,

View File

@@ -54,7 +54,7 @@ OnAssert::resetAction()
void void
OnAssert::defaultAction(std::string_view message) OnAssert::defaultAction(std::string_view message)
{ {
if (LogService::enabled()) { if (LogServiceState::initialized()) {
LOG(LogService::fatal()) << message; LOG(LogService::fatal()) << message;
} else { } else {
std::cerr << message; std::cerr << message;

View File

@@ -41,12 +41,12 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <algorithm> #include <algorithm>
#include <array>
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <filesystem> #include <filesystem>
#include <memory> #include <memory>
#include <optional> #include <optional>
#include <stdexcept>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <system_error> #include <system_error>
@@ -56,7 +56,10 @@
namespace util { namespace util {
LogService::Data LogService::data{}; bool LogServiceState::isAsync_{true};
Severity LogServiceState::defaultSeverity_{Severity::NFO};
std::vector<spdlog::sink_ptr> LogServiceState::sinks_{};
bool LogServiceState::initialized_{false};
namespace { namespace {
@@ -238,23 +241,71 @@ getMinSeverity(config::ClioConfigDefinition const& config, Severity defaultSever
return minSeverity; return minSeverity;
} }
std::shared_ptr<spdlog::logger> void
LogService::registerLogger(std::string const& channel, Severity severity) LogServiceState::init(bool isAsync, Severity defaultSeverity, std::vector<spdlog::sink_ptr> const& sinks)
{ {
std::shared_ptr<spdlog::logger> logger; if (initialized_) {
if (data.isAsync) { throw std::logic_error("LogServiceState is already initialized");
logger = std::make_shared<spdlog::async_logger>(
channel,
data.allSinks.begin(),
data.allSinks.end(),
spdlog::thread_pool(),
spdlog::async_overflow_policy::block
);
} else {
logger = std::make_shared<spdlog::logger>(channel, data.allSinks.begin(), data.allSinks.end());
} }
logger->set_level(toSpdlogLevel(severity)); isAsync_ = isAsync;
defaultSeverity_ = defaultSeverity;
sinks_ = sinks;
initialized_ = true;
spdlog::apply_all([](std::shared_ptr<spdlog::logger> logger) {
logger->set_level(toSpdlogLevel(defaultSeverity_));
});
if (isAsync) {
static constexpr size_t kQUEUE_SIZE = 8192;
static constexpr size_t kTHREAD_COUNT = 1;
spdlog::init_thread_pool(kQUEUE_SIZE, kTHREAD_COUNT);
}
}
bool
LogServiceState::initialized()
{
return initialized_;
}
void
LogServiceState::reset()
{
if (not initialized()) {
throw std::logic_error("LogService is not initialized");
}
isAsync_ = true;
defaultSeverity_ = Severity::NFO;
sinks_.clear();
initialized_ = false;
}
std::shared_ptr<spdlog::logger>
LogServiceState::registerLogger(std::string const& channel, std::optional<Severity> severity)
{
if (not initialized_) {
throw std::logic_error("LogService is not initialized");
}
std::shared_ptr<spdlog::logger> existingLogger = spdlog::get(channel);
if (existingLogger != nullptr) {
if (severity.has_value())
existingLogger->set_level(toSpdlogLevel(*severity));
return existingLogger;
}
std::shared_ptr<spdlog::logger> logger;
if (isAsync_) {
logger = std::make_shared<spdlog::async_logger>(
channel, sinks_.begin(), sinks_.end(), spdlog::thread_pool(), spdlog::async_overflow_policy::block
);
} else {
logger = std::make_shared<spdlog::logger>(channel, sinks_.begin(), sinks_.end());
}
logger->set_level(toSpdlogLevel(severity.value_or(defaultSeverity_)));
logger->flush_on(spdlog::level::err); logger->flush_on(spdlog::level::err);
spdlog::register_logger(logger); spdlog::register_logger(logger);
@@ -262,22 +313,12 @@ LogService::registerLogger(std::string const& channel, Severity severity)
return logger; return logger;
} }
std::expected<void, std::string> std::expected<std::vector<spdlog::sink_ptr>, std::string>
LogService::init(config::ClioConfigDefinition const& config) LogService::getSinks(config::ClioConfigDefinition const& config)
{ {
// Drop existing loggers
spdlog::drop_all();
data.isAsync = config.get<bool>("log.is_async");
data.defaultSeverity = getSeverityLevel(config.get<std::string>("log.level"));
std::string const format = config.get<std::string>("log.format"); std::string const format = config.get<std::string>("log.format");
if (data.isAsync) { std::vector<spdlog::sink_ptr> allSinks = createConsoleSinks(config.get<bool>("log.enable_console"), format);
spdlog::init_thread_pool(8192, 1);
}
data.allSinks = createConsoleSinks(config.get<bool>("log.enable_console"), format);
if (auto const logDir = config.maybeValue<std::string>("log.directory"); logDir.has_value()) { if (auto const logDir = config.maybeValue<std::string>("log.directory"); logDir.has_value()) {
std::filesystem::path const dirPath{logDir.value()}; std::filesystem::path const dirPath{logDir.value()};
@@ -294,11 +335,27 @@ LogService::init(config::ClioConfigDefinition const& config)
.rotationSizeMB = config.get<uint32_t>("log.rotation_size"), .rotationSizeMB = config.get<uint32_t>("log.rotation_size"),
.dirMaxFiles = config.get<uint32_t>("log.directory_max_files"), .dirMaxFiles = config.get<uint32_t>("log.directory_max_files"),
}; };
data.allSinks.push_back(createFileSink(params, format)); allSinks.push_back(createFileSink(params, format));
}
return allSinks;
}
std::expected<void, std::string>
LogService::init(config::ClioConfigDefinition const& config)
{
auto const sinksMaybe = getSinks(config);
if (!sinksMaybe.has_value()) {
return std::unexpected{sinksMaybe.error()};
} }
LogServiceState::init(
config.get<bool>("log.is_async"),
getSeverityLevel(config.get<std::string>("log.level")),
std::move(sinksMaybe).value()
);
// get min severity per channel, can be overridden using the `log.channels` array // get min severity per channel, can be overridden using the `log.channels` array
auto const maybeMinSeverity = getMinSeverity(config, data.defaultSeverity); auto const maybeMinSeverity = getMinSeverity(config, defaultSeverity_);
if (!maybeMinSeverity) { if (!maybeMinSeverity) {
return std::unexpected{maybeMinSeverity.error()}; return std::unexpected{maybeMinSeverity.error()};
} }
@@ -307,20 +364,23 @@ LogService::init(config::ClioConfigDefinition const& config)
// Create loggers for each channel // Create loggers for each channel
for (auto const& channel : Logger::kCHANNELS) { for (auto const& channel : Logger::kCHANNELS) {
auto const it = minSeverity.find(channel); auto const it = minSeverity.find(channel);
auto const severity = (it != minSeverity.end()) ? it->second : data.defaultSeverity; auto const severity = (it != minSeverity.end()) ? it->second : defaultSeverity_;
registerLogger(channel, severity); registerLogger(channel, severity);
} }
spdlog::set_default_logger(spdlog::get("General")); spdlog::set_default_logger(spdlog::get("General"));
LOG(LogService::info()) << "Default log level = " << toString(data.defaultSeverity); LOG(LogService::info()) << "Default log level = " << toString(defaultSeverity_);
return {}; return {};
} }
void void
LogService::shutdown() LogService::shutdown()
{ {
spdlog::shutdown(); if (initialized_ && isAsync_) {
// We run in async mode in production, so we need to make sure all logs are flushed before shutting down
spdlog::shutdown();
}
} }
Logger::Pump Logger::Pump
@@ -359,17 +419,15 @@ LogService::fatal(SourceLocationType const& loc)
return Logger(spdlog::default_logger()).fatal(loc); return Logger(spdlog::default_logger()).fatal(loc);
} }
bool void
LogService::enabled() LogServiceState::replaceSinks(std::vector<std::shared_ptr<spdlog::sinks::sink>> const& sinks)
{ {
return spdlog::get_level() != spdlog::level::off; sinks_ = sinks;
spdlog::apply_all([](std::shared_ptr<spdlog::logger> logger) { logger->sinks() = sinks_; });
} }
Logger::Logger(std::string channel) : logger_(spdlog::get(channel)) Logger::Logger(std::string channel) : logger_(LogServiceState::registerLogger(channel))
{ {
if (!logger_) {
logger_ = LogService::registerLogger(channel);
}
} }
Logger::Pump::Pump(std::shared_ptr<spdlog::logger> logger, Severity sev, SourceLocationType const& loc) Logger::Pump::Pump(std::shared_ptr<spdlog::logger> logger, Severity sev, SourceLocationType const& loc)

View File

@@ -26,6 +26,7 @@
#include <cstdint> #include <cstdint>
#include <expected> #include <expected>
#include <memory> #include <memory>
#include <optional>
#include <sstream> #include <sstream>
#include <string> #include <string>
#include <vector> #include <vector>
@@ -43,9 +44,15 @@ class sink; // NOLINT(readability-identifier-naming)
} // namespace spdlog } // namespace spdlog
struct BenchmarkLoggingInitializer; struct BenchmarkLoggingInitializer;
class LoggerFixture;
struct LogServiceInitTests;
namespace util { namespace util {
namespace impl {
class OnAssert;
} // namespace impl
namespace config { namespace config {
class ClioConfigDefinition; class ClioConfigDefinition;
} // namespace config } // namespace config
@@ -228,27 +235,78 @@ private:
Logger(std::shared_ptr<spdlog::logger> logger); Logger(std::shared_ptr<spdlog::logger> logger);
}; };
/**
* @brief Base state management class for the logging service.
*
* This class manages the global state and core functionality for the logging system,
* including initialization, sink management, and logger registration.
*/
class LogServiceState {
protected:
friend struct ::LogServiceInitTests;
friend class ::LoggerFixture;
friend class Logger;
friend class ::util::impl::OnAssert;
/**
* @brief Initialize the logging core with specified parameters.
*
* @param isAsync Whether logging should be asynchronous
* @param defaultSeverity The default severity level for new loggers
* @param sinks Vector of spdlog sinks to use for output
*/
static void
init(bool isAsync, Severity defaultSeverity, std::vector<std::shared_ptr<spdlog::sinks::sink>> const& sinks);
/**
* @brief Whether the LogService is initialized or not
*
* @return true if the LogService is initialized
*/
[[nodiscard]] static bool
initialized();
/**
* @brief Reset the logging service to uninitialized state.
*/
static void
reset();
/**
* @brief Replace the current sinks with a new set of sinks.
*
* @param sinks Vector of new spdlog sinks to replace the current ones
*/
static void
replaceSinks(std::vector<std::shared_ptr<spdlog::sinks::sink>> const& sinks);
/**
* @brief Register a new logger for the specified channel.
*
* Creates and registers a new spdlog logger instance for the given channel
* with the specified or default severity level.
*
* @param channel The name of the logging channel
* @param severity Optional severity level override; uses default if not specified
* @return Shared pointer to the registered spdlog logger
*/
static std::shared_ptr<spdlog::logger>
registerLogger(std::string const& channel, std::optional<Severity> severity = std::nullopt);
protected:
static bool isAsync_; // NOLINT(readability-identifier-naming)
static Severity defaultSeverity_; // NOLINT(readability-identifier-naming)
static std::vector<std::shared_ptr<spdlog::sinks::sink>> sinks_; // NOLINT(readability-identifier-naming)
static bool initialized_; // NOLINT(readability-identifier-naming)
};
/** /**
* @brief A global logging service. * @brief A global logging service.
* *
* Used to initialize and setup the logging core as well as a globally available * Used to initialize and setup the logging core as well as a globally available
* entrypoint for logging into the `General` channel as well as raising alerts. * entrypoint for logging into the `General` channel as well as raising alerts.
*/ */
class LogService { class LogService : public LogServiceState {
struct Data {
bool isAsync;
Severity defaultSeverity;
std::vector<std::shared_ptr<spdlog::sinks::sink>> allSinks;
};
friend class Logger;
private:
static Data data;
static std::shared_ptr<spdlog::logger>
registerLogger(std::string const& channel, Severity severity = data.defaultSeverity);
public: public:
LogService() = delete; LogService() = delete;
@@ -321,15 +379,16 @@ public:
[[nodiscard]] static Logger::Pump [[nodiscard]] static Logger::Pump
fatal(SourceLocationType const& loc = CURRENT_SRC_LOCATION); fatal(SourceLocationType const& loc = CURRENT_SRC_LOCATION);
/**
* @brief Whether the LogService is enabled or not
*
* @return true if the LogService is enabled, false otherwise
*/
[[nodiscard]] static bool
enabled();
private: private:
/**
* @brief Parses the sinks from a @ref config::ClioConfigDefinition
*
* @param config The configuration to parse sinks from
* @return A vector of sinks on success, error message on failure
*/
[[nodiscard]] static std::expected<std::vector<std::shared_ptr<spdlog::sinks::sink>>, std::string>
getSinks(config::ClioConfigDefinition const& config);
struct FileLoggingParams { struct FileLoggingParams {
std::string logDir; std::string logDir;

View File

@@ -40,7 +40,7 @@
* *
* This is meant to be used as a base for other fixtures. * This is meant to be used as a base for other fixtures.
*/ */
struct AsyncAsioContextTest : virtual public NoLoggerFixture { struct AsyncAsioContextTest : virtual public ::testing::Test {
AsyncAsioContextTest() AsyncAsioContextTest()
{ {
work_.emplace(boost::asio::make_work_guard(ctx_)); // make sure ctx does not stop on its own work_.emplace(boost::asio::make_work_guard(ctx_)); // make sure ctx does not stop on its own
@@ -79,7 +79,7 @@ private:
* Use `run_for(duration)` etc. directly on `ctx`. * Use `run_for(duration)` etc. directly on `ctx`.
* This is meant to be used as a base for other fixtures. * This is meant to be used as a base for other fixtures.
*/ */
struct SyncAsioContextTest : virtual public NoLoggerFixture { struct SyncAsioContextTest : virtual public ::testing::Test {
template <util::CoroutineFunction F> template <util::CoroutineFunction F>
void void
runCoroutine(F&& f, bool allowMockLeak = false) runCoroutine(F&& f, bool allowMockLeak = false)

View File

@@ -0,0 +1,43 @@
//------------------------------------------------------------------------------
/*
This file is part of clio: https://github.com/XRPLF/clio
Copyright (c) 2025, the clio developers.
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#pragma once
#include "util/StringBuffer.hpp"
#include <ostream>
#include <string>
class LoggerBuffer {
public:
std::string
getStrAndReset()
{
return buffer_.getStrAndReset();
}
std::ostream&
getStream()
{
return stream_;
}
private:
StringBuffer buffer_;
std::ostream stream_ = std::ostream{&buffer_};
};

View File

@@ -22,6 +22,7 @@
#include "util/log/Logger.hpp" #include "util/log/Logger.hpp"
#include <spdlog/common.h> #include <spdlog/common.h>
#include <spdlog/logger.h>
#include <spdlog/pattern_formatter.h> #include <spdlog/pattern_formatter.h>
#include <spdlog/sinks/ostream_sink.h> #include <spdlog/sinks/ostream_sink.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
@@ -29,32 +30,40 @@
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
LoggerFixture::LoggerFixture() void
LoggerFixture::init()
{ {
// Clear any existing loggers util::LogServiceState::init(false, util::Severity::FTL, {});
spdlog::drop_all();
// Create ostream sink for testing std::ranges::for_each(util::Logger::kCHANNELS, [](char const* channel) {
auto ostreamSink = std::make_shared<spdlog::sinks::ostream_sink_mt>(stream_); util::LogService::registerLogger(channel);
ostreamSink->set_formatter(std::make_unique<spdlog::pattern_formatter>("%^%3!l:%n%$ - %v"));
// Create loggers for each channel
std::ranges::for_each(util::Logger::kCHANNELS, [&ostreamSink](char const* channel) {
auto logger = std::make_shared<spdlog::logger>(channel, ostreamSink);
logger->set_level(spdlog::level::trace);
spdlog::register_logger(logger);
}); });
spdlog::get("General")->set_level(spdlog::level::debug);
auto traceLogger = std::make_shared<spdlog::logger>("Trace", ostreamSink);
traceLogger->set_level(spdlog::level::trace);
spdlog::register_logger(traceLogger);
spdlog::set_default_logger(spdlog::get("General")); spdlog::set_default_logger(spdlog::get("General"));
} }
NoLoggerFixture::NoLoggerFixture() void
LoggerFixture::resetTestingLoggers()
{ {
spdlog::set_level(spdlog::level::off); auto ostreamSink = std::make_shared<spdlog::sinks::ostream_sink_mt>(buffer_.getStream());
ostreamSink->set_formatter(std::make_unique<spdlog::pattern_formatter>("%^%3!l:%n%$ - %v"));
ostreamSink->set_level(spdlog::level::trace);
util::LogServiceState::replaceSinks({ostreamSink});
spdlog::apply_all([](std::shared_ptr<spdlog::logger> logger) { logger->set_level(spdlog::level::trace); });
spdlog::get("General")->set_level(spdlog::level::debug);
}
LoggerFixture::LoggerFixture()
{
util::LogServiceState::reset();
util::LogServiceState::init(false, util::Severity::TRC, {});
resetTestingLoggers();
}
LoggerFixture::~LoggerFixture()
{
util::LogServiceState::replaceSinks({});
spdlog::apply_all([](std::shared_ptr<spdlog::logger> logger) { logger->set_level(spdlog::level::critical); });
} }

View File

@@ -19,37 +19,39 @@
#pragma once #pragma once
#include "util/StringBuffer.hpp" #include "util/LoggerBuffer.hpp"
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <ostream>
#include <string> #include <string>
/** /**
* @brief A fixture for testing LogService and Logger. * @brief A fixture for testing LogService and Logger.
*/ */
class LoggerFixture : virtual public ::testing::Test { class LoggerFixture : virtual public ::testing::Test {
StringBuffer buffer_; protected:
std::ostream stream_ = std::ostream{&buffer_}; LoggerBuffer buffer_;
public: public:
// Simulates the `util::LogService::init(config)` call
LoggerFixture(); LoggerFixture();
~LoggerFixture() override;
/**
* @brief Sets up spdlog loggers for each channel. Should be called once before using any loggers.
* Simulates the `util::LogService::init(config)` call
*/
static void
init();
protected: protected:
[[nodiscard]]
std::string std::string
getLoggerString() getLoggerString()
{ {
return buffer_.getStrAndReset(); return buffer_.getStrAndReset();
} }
};
/** private:
* @brief Fixture with util::Logger support but completely disabled logging. void
* resetTestingLoggers();
* This is meant to be used as a base for other fixtures.
*/
struct NoLoggerFixture : virtual LoggerFixture {
NoLoggerFixture();
}; };

View File

@@ -29,7 +29,7 @@
#include <memory> #include <memory>
template <template <typename> typename MockType = ::testing::NiceMock> template <template <typename> typename MockType = ::testing::NiceMock>
struct MockBackendTestBase : virtual public NoLoggerFixture { struct MockBackendTestBase : virtual public ::testing::Test {
class BackendProxy { class BackendProxy {
std::shared_ptr<MockType<MockBackend>> backend_ = std::shared_ptr<MockType<MockBackend>> backend_ =
std::make_shared<MockType<MockBackend>>(util::config::ClioConfigDefinition{{}}); std::make_shared<MockType<MockBackend>>(util::config::ClioConfigDefinition{{}});

View File

@@ -25,7 +25,7 @@
/** /**
* @brief Fixture with mock counters * @brief Fixture with mock counters
*/ */
struct MockCountersTest : virtual public NoLoggerFixture { struct MockCountersTest : virtual public ::testing::Test {
protected: protected:
std::shared_ptr<MockCounters> mockCountersPtr_ = std::make_shared<MockCounters>(); std::shared_ptr<MockCounters> mockCountersPtr_ = std::make_shared<MockCounters>();
}; };

View File

@@ -33,7 +33,7 @@
* @brief Fixture with a mock etl service * @brief Fixture with a mock etl service
*/ */
template <template <typename> typename MockType = ::testing::NiceMock> template <template <typename> typename MockType = ::testing::NiceMock>
struct MockETLServiceTestBase : virtual public NoLoggerFixture { struct MockETLServiceTestBase : virtual public ::testing::Test {
using Mock = MockType<MockETLService>; using Mock = MockType<MockETLService>;
protected: protected:
@@ -63,7 +63,7 @@ using MockETLServiceTestStrict = MockETLServiceTestBase<::testing::StrictMock>;
/** /**
* @brief Fixture with a mock etl balancer * @brief Fixture with a mock etl balancer
*/ */
struct MockLoadBalancerTest : virtual public NoLoggerFixture { struct MockLoadBalancerTest : virtual public ::testing::Test {
protected: protected:
std::shared_ptr<MockLoadBalancer> mockLoadBalancerPtr_ = std::make_shared<MockLoadBalancer>(); std::shared_ptr<MockLoadBalancer> mockLoadBalancerPtr_ = std::make_shared<MockLoadBalancer>();
}; };
@@ -71,7 +71,7 @@ protected:
/** /**
* @brief Fixture with a mock NG etl balancer * @brief Fixture with a mock NG etl balancer
*/ */
struct MockNgLoadBalancerTest : virtual public NoLoggerFixture { struct MockNgLoadBalancerTest : virtual public ::testing::Test {
protected: protected:
std::shared_ptr<MockNgLoadBalancer> mockLoadBalancerPtr_ = std::make_shared<MockNgLoadBalancer>(); std::shared_ptr<MockNgLoadBalancer> mockLoadBalancerPtr_ = std::make_shared<MockNgLoadBalancer>();
}; };
@@ -79,7 +79,7 @@ protected:
/** /**
* @brief Fixture with a mock ledger fetcher * @brief Fixture with a mock ledger fetcher
*/ */
struct MockLedgerFetcherTest : virtual public NoLoggerFixture { struct MockLedgerFetcherTest : virtual public ::testing::Test {
protected: protected:
std::shared_ptr<MockNgLedgerFetcher> mockLedgerFetcherPtr_ = std::make_shared<MockNgLedgerFetcher>(); std::shared_ptr<MockNgLedgerFetcher> mockLedgerFetcherPtr_ = std::make_shared<MockNgLedgerFetcher>();
}; };
@@ -87,7 +87,7 @@ protected:
/** /**
* @brief Fixture with a mock ledger fetcher * @brief Fixture with a mock ledger fetcher
*/ */
struct MockAmendmentBlockHandlerTest : virtual public NoLoggerFixture { struct MockAmendmentBlockHandlerTest : virtual public ::testing::Test {
protected: protected:
std::shared_ptr<MockAmendmentBlockHandler> mockAmendmentBlockHandlerPtr_ = std::shared_ptr<MockAmendmentBlockHandler> mockAmendmentBlockHandlerPtr_ =
std::make_shared<MockAmendmentBlockHandler>(); std::make_shared<MockAmendmentBlockHandler>();

View File

@@ -28,7 +28,7 @@
#include <memory> #include <memory>
template <template <typename> typename MockType = ::testing::NiceMock> template <template <typename> typename MockType = ::testing::NiceMock>
struct MockMigrationBackendTestBase : virtual public NoLoggerFixture { struct MockMigrationBackendTestBase : virtual public ::testing::Test {
class BackendProxy { class BackendProxy {
std::shared_ptr<MockType<MockMigrationBackend>> backend_ = std::shared_ptr<MockType<MockMigrationBackend>> backend_ =
std::make_shared<MockType<MockMigrationBackend>>(util::config::ClioConfigDefinition{}); std::make_shared<MockType<MockMigrationBackend>>(util::config::ClioConfigDefinition{});

View File

@@ -30,7 +30,7 @@
* @brief Fixture with an embedded AnyExecutionContext wrapping a SyncExecutionContext * @brief Fixture with an embedded AnyExecutionContext wrapping a SyncExecutionContext
* *
*/ */
struct SyncExecutionCtxFixture : virtual public NoLoggerFixture { struct SyncExecutionCtxFixture : virtual public ::testing::Test {
protected: protected:
util::async::SyncExecutionContext syncCtx_; util::async::SyncExecutionContext syncCtx_;
util::async::AnyExecutionContext ctx_{syncCtx_}; util::async::AnyExecutionContext ctx_{syncCtx_};

View File

@@ -41,7 +41,7 @@ using namespace std;
using namespace data::cassandra; using namespace data::cassandra;
class BackendCassandraBaseTest : public NoLoggerFixture { class BackendCassandraBaseTest : public virtual ::testing::Test {
protected: protected:
static Handle static Handle
createHandle(std::string_view contactPoints, std::string_view keyspace) createHandle(std::string_view contactPoints, std::string_view keyspace)

View File

@@ -86,7 +86,7 @@ makeMigrationTestManagerAndBackend(ClioConfigDefinition const& config)
} }
} // namespace } // namespace
class MigrationCassandraSimpleTest : public WithPrometheus, public NoLoggerFixture { class MigrationCassandraSimpleTest : public WithPrometheus {
// This function is used to prepare the database before running the tests // This function is used to prepare the database before running the tests
// It is called in the SetUp function. Different tests can override this function to prepare the database // It is called in the SetUp function. Different tests can override this function to prepare the database
// differently // differently

View File

@@ -17,6 +17,7 @@
*/ */
//============================================================================== //==============================================================================
#include "util/LoggerFixtures.hpp"
#include "util/TerminationHandler.hpp" #include "util/TerminationHandler.hpp"
#include <gtest/gtest.h> #include <gtest/gtest.h>
@@ -27,5 +28,7 @@ main(int argc, char* argv[])
util::setTerminationHandler(); util::setTerminationHandler();
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
LoggerFixture::init();
return RUN_ALL_TESTS(); return RUN_ALL_TESTS();
} }

View File

@@ -37,7 +37,7 @@
using namespace app; using namespace app;
struct StopperTest : NoLoggerFixture { struct StopperTest : virtual public ::testing::Test {
protected: protected:
// Order here is important, stopper_ should die before mockCallback_, otherwise UB // Order here is important, stopper_ should die before mockCallback_, otherwise UB
testing::StrictMock<testing::MockFunction<void(boost::asio::yield_context)>> mockCallback_; testing::StrictMock<testing::MockFunction<void(boost::asio::yield_context)>> mockCallback_;

View File

@@ -54,7 +54,7 @@ using namespace app;
namespace http = boost::beast::http; namespace http = boost::beast::http;
using namespace util::config; using namespace util::config;
struct WebHandlersTest : virtual NoLoggerFixture { struct WebHandlersTest : virtual public ::testing::Test {
DOSGuardStrictMock dosGuardMock; DOSGuardStrictMock dosGuardMock;
util::TagDecoratorFactory const tagFactory{ util::TagDecoratorFactory const tagFactory{
ClioConfigDefinition{{"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("uint")}} ClioConfigDefinition{{"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("uint")}}

View File

@@ -27,7 +27,7 @@
using namespace data; using namespace data;
struct LedgerCacheTest : util::prometheus::WithPrometheus, NoLoggerFixture { struct LedgerCacheTest : util::prometheus::WithPrometheus {
LedgerCache cache; LedgerCache cache;
}; };
@@ -39,7 +39,7 @@ TEST_F(LedgerCacheTest, defaultState)
EXPECT_EQ(cache.latestLedgerSequence(), 0u); EXPECT_EQ(cache.latestLedgerSequence(), 0u);
} }
struct LedgerCachePrometheusMetricTest : util::prometheus::WithMockPrometheus, NoLoggerFixture { struct LedgerCachePrometheusMetricTest : util::prometheus::WithMockPrometheus {
LedgerCache cache; LedgerCache cache;
}; };

View File

@@ -77,7 +77,7 @@ getParseSettingsConfig(boost::json::value val)
return config; return config;
}; };
class SettingsProviderTest : public NoLoggerFixture {}; class SettingsProviderTest : virtual public ::testing::Test {};
TEST_F(SettingsProviderTest, Defaults) TEST_F(SettingsProviderTest, Defaults)
{ {

View File

@@ -30,7 +30,7 @@ using namespace data;
using namespace util::prometheus; using namespace util::prometheus;
using namespace testing; using namespace testing;
struct CorruptionDetectorTest : NoLoggerFixture, WithPrometheus {}; struct CorruptionDetectorTest : WithPrometheus {};
TEST_F(CorruptionDetectorTest, DisableCacheOnCorruption) TEST_F(CorruptionDetectorTest, DisableCacheOnCorruption)
{ {

View File

@@ -32,7 +32,7 @@ namespace json = boost::json;
using namespace util; using namespace util;
using namespace testing; using namespace testing;
struct ETLStateTest : public NoLoggerFixture { struct ETLStateTest : public virtual ::testing::Test {
MockSource source = MockSource{}; MockSource source = MockSource{};
}; };

View File

@@ -35,7 +35,7 @@ constexpr auto kSTART_SEQ = 1234;
} // namespace } // namespace
class ETLExtractionDataPipeTest : public NoLoggerFixture { class ETLExtractionDataPipeTest : public ::testing::Test {
protected: protected:
etl::impl::ExtractionDataPipe<uint32_t> pipe_{kSTRIDE, kSTART_SEQ}; etl::impl::ExtractionDataPipe<uint32_t> pipe_{kSTRIDE, kSTART_SEQ};
}; };

View File

@@ -34,7 +34,7 @@
using namespace testing; using namespace testing;
using namespace etl; using namespace etl;
struct ETLExtractorTest : util::prometheus::WithPrometheus, NoLoggerFixture { struct ETLExtractorTest : util::prometheus::WithPrometheus {
using ExtractionDataPipeType = MockExtractionDataPipe; using ExtractionDataPipeType = MockExtractionDataPipe;
using LedgerFetcherType = MockLedgerFetcher; using LedgerFetcherType = MockLedgerFetcher;
using ExtractorType = etl::impl::Extractor<ExtractionDataPipeType, LedgerFetcherType>; using ExtractorType = etl::impl::Extractor<ExtractionDataPipeType, LedgerFetcherType>;

View File

@@ -41,7 +41,7 @@
using namespace etl::impl; using namespace etl::impl;
using namespace util::config; using namespace util::config;
struct GrpcSourceTests : NoLoggerFixture, util::prometheus::WithPrometheus, tests::util::WithMockXrpLedgerAPIService { struct GrpcSourceTests : util::prometheus::WithPrometheus, tests::util::WithMockXrpLedgerAPIService {
GrpcSourceTests() GrpcSourceTests()
: WithMockXrpLedgerAPIService("localhost:0") : WithMockXrpLedgerAPIService("localhost:0")
, mockBackend_(std::make_shared<testing::StrictMock<MockBackend>>(ClioConfigDefinition{})) , mockBackend_(std::make_shared<testing::StrictMock<MockBackend>>(ClioConfigDefinition{}))

View File

@@ -56,7 +56,7 @@ constexpr auto kOFFER_ID = "AA86CBF29770F72FA3FF4A5D9A9FA54D6F399A8E038F72393EF7
} // namespace } // namespace
struct NFTHelpersTest : NoLoggerFixture { struct NFTHelpersTest : virtual public ::testing::Test {
protected: protected:
static void static void
verifyNFTTransactionsData( verifyNFTTransactionsData(

View File

@@ -50,7 +50,7 @@ constinit auto const kLEDGER_HASH2 = "1B8590C01B0006EDFA9ED60296DD052DC5E90F9965
constinit auto const kSEQ = 30; constinit auto const kSEQ = 30;
} // namespace } // namespace
struct ExtractionModelNgTests : NoLoggerFixture {}; struct ExtractionModelNgTests : virtual public ::testing::Test {};
TEST_F(ExtractionModelNgTests, LedgerDataCopyableAndEquatable) TEST_F(ExtractionModelNgTests, LedgerDataCopyableAndEquatable)
{ {
@@ -178,7 +178,7 @@ TEST_F(ExtractionModelNgTests, BookSuccessorCopyableAndEquatable)
} }
} }
struct ExtractionNgTests : NoLoggerFixture {}; struct ExtractionNgTests : public virtual ::testing::Test {};
TEST_F(ExtractionNgTests, ModType) TEST_F(ExtractionNgTests, ModType)
{ {
@@ -360,7 +360,7 @@ TEST_F(ExtractionNgTests, SuccessorsWithNoNeighborsIncluded)
ASSERT_FALSE(res.has_value()); ASSERT_FALSE(res.has_value());
} }
struct ExtractionAssertTest : common::util::WithMockAssert, NoLoggerFixture {}; struct ExtractionAssertTest : common::util::WithMockAssert {};
TEST_F(ExtractionAssertTest, InvalidModTypeAsserts) TEST_F(ExtractionAssertTest, InvalidModTypeAsserts)
{ {

View File

@@ -67,7 +67,7 @@ struct MockLoadObserver : etlng::InitialLoadObserverInterface {
); );
}; };
struct GrpcSourceNgTests : virtual NoLoggerFixture, tests::util::WithMockXrpLedgerAPIService { struct GrpcSourceNgTests : virtual public ::testing::Test, tests::util::WithMockXrpLedgerAPIService {
GrpcSourceNgTests() GrpcSourceNgTests()
: WithMockXrpLedgerAPIService("localhost:0"), grpcSource_("localhost", std::to_string(getXRPLMockPort())) : WithMockXrpLedgerAPIService("localhost:0"), grpcSource_("localhost", std::to_string(getXRPLMockPort()))
{ {

View File

@@ -32,7 +32,7 @@
using namespace etlng::impl; using namespace etlng::impl;
struct NetworkValidatedLedgersTests : NoLoggerFixture { struct NetworkValidatedLedgersTests : virtual public ::testing::Test {
protected: protected:
util::async::CoroExecutionContext ctx_{2}; util::async::CoroExecutionContext ctx_{2};
std::shared_ptr<etl::NetworkValidatedLedgersInterface> ledgers_ = std::shared_ptr<etl::NetworkValidatedLedgersInterface> ledgers_ =

View File

@@ -254,7 +254,7 @@ struct MockExtNftBurnReadonly {
} }
}; };
struct RegistryTest : NoLoggerFixture, util::prometheus::WithPrometheus { struct RegistryTest : util::prometheus::WithPrometheus {
RegistryTest() RegistryTest()
{ {
state_.isWriting = true; state_.isWriting = true;

View File

@@ -52,7 +52,7 @@ public:
}; };
} // namespace } // namespace
struct ForwardSchedulerTests : NoLoggerFixture { struct ForwardSchedulerTests : virtual public ::testing::Test {
protected: protected:
MockNetworkValidatedLedgersPtr networkValidatedLedgers_; MockNetworkValidatedLedgersPtr networkValidatedLedgers_;
}; };

View File

@@ -86,7 +86,7 @@ struct MockMonitor : etlng::MonitorInterface {
MOCK_METHOD(void, stop, (), (override)); MOCK_METHOD(void, stop, (), (override));
}; };
struct TaskManagerTests : NoLoggerFixture { struct TaskManagerTests : virtual public ::testing::Test {
using MockSchedulerType = testing::NiceMock<MockScheduler>; using MockSchedulerType = testing::NiceMock<MockScheduler>;
using MockExtractorType = testing::NiceMock<MockExtractor>; using MockExtractorType = testing::NiceMock<MockExtractor>;
using MockLoaderType = testing::NiceMock<MockLoader>; using MockLoaderType = testing::NiceMock<MockLoader>;

View File

@@ -59,7 +59,7 @@ createTestData()
} // namespace } // namespace
struct CacheExtTests : NoLoggerFixture, util::prometheus::WithPrometheus { struct CacheExtTests : util::prometheus::WithPrometheus {
protected: protected:
MockLedgerCache cache_; MockLedgerCache cache_;
std::shared_ptr<etlng::impl::CacheUpdater> updater_ = std::make_shared<etlng::impl::CacheUpdater>(cache_); std::shared_ptr<etlng::impl::CacheUpdater> updater_ = std::make_shared<etlng::impl::CacheUpdater>(cache_);

View File

@@ -26,7 +26,7 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
struct MigrationManagerFactoryTests : public NoLoggerFixture {}; struct MigrationManagerFactoryTests : public virtual ::testing::Test {};
TEST_F(MigrationManagerFactoryTests, InvalidDBType) TEST_F(MigrationManagerFactoryTests, InvalidDBType)
{ {

View File

@@ -76,7 +76,7 @@ TEST_F(FullTableScannerAssertTest, cursorsPerWorkerZero)
); );
} }
struct FullTableScannerTests : NoLoggerFixture {}; struct FullTableScannerTests : public virtual ::testing::Test {};
TEST_F(FullTableScannerTests, SingleThreadCtx) TEST_F(FullTableScannerTests, SingleThreadCtx)
{ {

View File

@@ -38,7 +38,7 @@ using namespace util::config;
using namespace rpc::impl; using namespace rpc::impl;
namespace json = boost::json; namespace json = boost::json;
class RPCAPIVersionTest : public NoLoggerFixture { class RPCAPIVersionTest : public virtual ::testing::Test {
protected: protected:
ProductionAPIVersionParser parser_{kDEFAULT_API_VERSION, kMIN_API_VERSION, kMAX_API_VERSION}; ProductionAPIVersionParser parser_{kDEFAULT_API_VERSION, kMIN_API_VERSION, kMAX_API_VERSION};
}; };

View File

@@ -49,7 +49,7 @@ using namespace rpc::modifiers;
namespace json = boost::json; namespace json = boost::json;
class RPCBaseTest : public NoLoggerFixture {}; class RPCBaseTest : public virtual ::testing::Test {};
TEST_F(RPCBaseTest, CheckType) TEST_F(RPCBaseTest, CheckType)
{ {

View File

@@ -38,7 +38,7 @@ using util::prometheus::CounterInt;
using util::prometheus::WithMockPrometheus; using util::prometheus::WithMockPrometheus;
using util::prometheus::WithPrometheus; using util::prometheus::WithPrometheus;
struct RPCCountersTest : WithPrometheus, NoLoggerFixture { struct RPCCountersTest : WithPrometheus {
WorkQueue queue{4u, 1024u}; // todo: mock instead WorkQueue queue{4u, 1024u}; // todo: mock instead
Counters counters{queue}; Counters counters{queue};
}; };

View File

@@ -39,7 +39,7 @@ using namespace util::config;
using namespace rpc; using namespace rpc;
using namespace util::prometheus; using namespace util::prometheus;
struct RPCWorkQueueTestBase : NoLoggerFixture { struct RPCWorkQueueTestBase : public virtual ::testing::Test {
ClioConfigDefinition cfg = { ClioConfigDefinition cfg = {
{"server.max_queue_size", ConfigValue{ConfigType::Integer}.defaultValue(2)}, {"server.max_queue_size", ConfigValue{ConfigType::Integer}.defaultValue(2)},
{"workers", ConfigValue{ConfigType::Integer}.defaultValue(4)} {"workers", ConfigValue{ConfigType::Integer}.defaultValue(4)}

View File

@@ -39,7 +39,7 @@ using namespace util::config;
using testing::MockFunction; using testing::MockFunction;
using testing::StrictMock; using testing::StrictMock;
struct SignalsHandlerTestsBase : NoLoggerFixture { struct SignalsHandlerTestsBase : public virtual ::testing::Test {
void void
allowTestToFinish() allowTestToFinish()
{ {

View File

@@ -327,7 +327,7 @@ TEST_F(IncorrectOverrideValues, InvalidJsonErrors)
EXPECT_EQ(expectedErrors, actualErrors); EXPECT_EQ(expectedErrors, actualErrors);
} }
struct ClioConfigDefinitionParseArrayTest : NoLoggerFixture { struct ClioConfigDefinitionParseArrayTest : public virtual ::testing::Test {
ClioConfigDefinition config{ ClioConfigDefinition config{
{"array.[].int", Array{ConfigValue{ConfigType::Integer}}}, {"array.[].int", Array{ConfigValue{ConfigType::Integer}}},
{"array.[].string", Array{ConfigValue{ConfigType::String}.optional()}} {"array.[].string", Array{ConfigValue{ConfigType::String}.optional()}}

View File

@@ -52,7 +52,8 @@ struct ConfigFileJsonParseTestBundle {
ValidationMap validationMap; ValidationMap validationMap;
}; };
struct ConfigFileJsonParseTest : NoLoggerFixture, testing::WithParamInterface<ConfigFileJsonParseTestBundle> {}; struct ConfigFileJsonParseTest : public virtual ::testing::Test,
testing::WithParamInterface<ConfigFileJsonParseTestBundle> {};
TEST_P(ConfigFileJsonParseTest, parseValues) TEST_P(ConfigFileJsonParseTest, parseValues)
{ {
@@ -309,7 +310,7 @@ INSTANTIATE_TEST_CASE_P(
tests::util::kNAME_GENERATOR tests::util::kNAME_GENERATOR
); );
struct ConfigFileJsonTest : NoLoggerFixture {}; struct ConfigFileJsonTest : public virtual ::testing::Test {};
TEST_F(ConfigFileJsonTest, getValue) TEST_F(ConfigFileJsonTest, getValue)
{ {

View File

@@ -35,7 +35,7 @@
using namespace util::config; using namespace util::config;
struct ConfigValueTest : common::util::WithMockAssert, NoLoggerFixture {}; struct ConfigValueTest : common::util::WithMockAssert {};
TEST_F(ConfigValueTest, construct) TEST_F(ConfigValueTest, construct)
{ {
@@ -138,7 +138,7 @@ TEST_F(ConfigValueConstraintTest, defaultValueWithConstraintCheckError)
} }
// A test for each constraint so it's easy to change in the future // A test for each constraint so it's easy to change in the future
struct ConstraintTest : NoLoggerFixture {}; struct ConstraintTest : public virtual ::testing::Test {};
TEST_F(ConstraintTest, PortConstraint) TEST_F(ConstraintTest, PortConstraint)
{ {

View File

@@ -17,7 +17,8 @@
*/ */
//============================================================================== //==============================================================================
#include "util/StringBuffer.hpp" #include "util/LoggerBuffer.hpp"
#include "util/LoggerFixtures.hpp"
#include "util/config/Array.hpp" #include "util/config/Array.hpp"
#include "util/config/ConfigConstraints.hpp" #include "util/config/ConfigConstraints.hpp"
#include "util/config/ConfigDefinition.hpp" #include "util/config/ConfigDefinition.hpp"
@@ -39,8 +40,6 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <limits> #include <limits>
#include <memory>
#include <ostream>
#include <string> #include <string>
#include <string_view> #include <string_view>
#include <vector> #include <vector>
@@ -51,7 +50,21 @@ using util::config::ConfigFileJson;
using util::config::ConfigType; using util::config::ConfigType;
using util::config::ConfigValue; using util::config::ConfigValue;
struct LogServiceInitTests : virtual public ::testing::Test { struct LogServiceInitTests : virtual public LoggerFixture {
public:
LogServiceInitTests()
{
LogServiceState::reset();
}
~LogServiceInitTests() override
{
if (LogService::initialized()) {
LogService::reset();
}
LogServiceState::init(false, Severity::FTL, {});
}
protected: protected:
util::config::ClioConfigDefinition config_{ util::config::ClioConfigDefinition config_{
{"log.channels.[].channel", Array{ConfigValue{ConfigType::String}}}, {"log.channels.[].channel", Array{ConfigValue{ConfigType::String}}},
@@ -80,26 +93,6 @@ protected:
{ {
return buffer_.getStrAndReset(); return buffer_.getStrAndReset();
} }
void
replaceSinks()
{
auto ostreamSink = std::make_shared<spdlog::sinks::ostream_sink_mt>(stream_);
ostreamSink->set_formatter(std::make_unique<spdlog::pattern_formatter>("%^%3!l:%n%$ - %v"));
for (auto const& channel : Logger::kCHANNELS) {
auto logger = spdlog::get(channel);
ASSERT_TRUE(logger != nullptr);
// It is expected that only stderrSink is present
ASSERT_EQ(logger->sinks().size(), 1);
logger->sinks().clear();
logger->sinks().push_back(ostreamSink);
}
}
private:
StringBuffer buffer_;
std::ostream stream_ = std::ostream{&buffer_};
}; };
TEST_F(LogServiceInitTests, DefaultLogLevel) TEST_F(LogServiceInitTests, DefaultLogLevel)
@@ -107,15 +100,15 @@ TEST_F(LogServiceInitTests, DefaultLogLevel)
auto const parsingErrors = auto const parsingErrors =
config_.parse(ConfigFileJson{boost::json::object{{"log", boost::json::object{{"level", "warn"}}}}}); config_.parse(ConfigFileJson{boost::json::object{{"log", boost::json::object{{"level", "warn"}}}}});
ASSERT_FALSE(parsingErrors.has_value()); ASSERT_FALSE(parsingErrors.has_value());
std::string const logString = "some log";
EXPECT_TRUE(LogService::init(config_)); EXPECT_TRUE(LogService::init(config_));
replaceSinks();
std::string const logString = "some log";
for (auto const& channel : Logger::kCHANNELS) { for (auto const& channel : Logger::kCHANNELS) {
Logger const log{channel}; Logger const log{channel};
log.trace() << logString; log.trace() << logString;
ASSERT_TRUE(getLoggerString().empty()); auto loggerStr = getLoggerString();
ASSERT_TRUE(loggerStr.empty()) << " channel: " << channel << " logger_str: " << loggerStr;
log.debug() << logString; log.debug() << logString;
ASSERT_TRUE(getLoggerString().empty()); ASSERT_TRUE(getLoggerString().empty());
@@ -149,11 +142,10 @@ TEST_F(LogServiceInitTests, ChannelLogLevel)
auto const parsingErrors = config_.parse(ConfigFileJson{boost::json::parse(configStr).as_object()}); auto const parsingErrors = config_.parse(ConfigFileJson{boost::json::parse(configStr).as_object()});
ASSERT_FALSE(parsingErrors.has_value()); ASSERT_FALSE(parsingErrors.has_value());
std::string const logString = "some log";
EXPECT_TRUE(LogService::init(config_)); EXPECT_TRUE(LogService::init(config_));
replaceSinks();
std::string const logString = "some log";
for (auto const& channel : Logger::kCHANNELS) { for (auto const& channel : Logger::kCHANNELS) {
Logger const log{channel}; Logger const log{channel};
log.trace() << logString; log.trace() << logString;

View File

@@ -29,12 +29,10 @@ using namespace util;
// Used as a fixture for tests with enabled logging // Used as a fixture for tests with enabled logging
class LoggerTest : public LoggerFixture {}; class LoggerTest : public LoggerFixture {};
// Used as a fixture for tests with disabled logging
class NoLoggerTest : public NoLoggerFixture {};
TEST_F(LoggerTest, Basic) TEST_F(LoggerTest, Basic)
{ {
Logger const log{"General"}; Logger const log{"General"};
log.info() << "Info line logged"; log.info() << "Info line logged";
ASSERT_EQ(getLoggerString(), "inf:General - Info line logged\n"); ASSERT_EQ(getLoggerString(), "inf:General - Info line logged\n");
@@ -53,10 +51,6 @@ TEST_F(LoggerTest, Filtering)
log.warn() << "Warning is logged"; log.warn() << "Warning is logged";
ASSERT_EQ(getLoggerString(), "war:General - Warning is logged\n"); ASSERT_EQ(getLoggerString(), "war:General - Warning is logged\n");
Logger const tlog{"Trace"};
tlog.trace() << "Trace line logged for 'Trace' component";
ASSERT_EQ(getLoggerString(), "tra:Trace - Trace line logged for 'Trace' component\n");
} }
#ifndef COVERAGE_ENABLED #ifndef COVERAGE_ENABLED
@@ -77,13 +71,3 @@ TEST_F(LoggerTest, LOGMacro)
EXPECT_TRUE(computeCalled); EXPECT_TRUE(computeCalled);
} }
#endif #endif
TEST_F(NoLoggerTest, Basic)
{
Logger const log{"Trace"};
log.trace() << "Nothing";
ASSERT_TRUE(getLoggerString().empty());
LogService::fatal() << "Still nothing";
ASSERT_TRUE(getLoggerString().empty());
}

View File

@@ -38,7 +38,7 @@
namespace http = boost::beast::http; namespace http = boost::beast::http;
using namespace util::config; using namespace util::config;
class IPAdminVerificationStrategyTest : public NoLoggerFixture { class IPAdminVerificationStrategyTest : public virtual ::testing::Test {
protected: protected:
web::IPAdminVerificationStrategy strat_; web::IPAdminVerificationStrategy strat_;
http::request<http::string_body> request_; http::request<http::string_body> request_;
@@ -53,7 +53,7 @@ TEST_F(IPAdminVerificationStrategyTest, IsAdminOnlyForIP_127_0_0_1)
EXPECT_FALSE(strat_.isAdmin(request_, "localhost")); EXPECT_FALSE(strat_.isAdmin(request_, "localhost"));
} }
class PasswordAdminVerificationStrategyTest : public NoLoggerFixture { class PasswordAdminVerificationStrategyTest : public virtual ::testing::Test {
protected: protected:
std::string const password_ = "secret"; std::string const password_ = "secret";
std::string const passwordHash_ = "2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b"; std::string const passwordHash_ = "2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b";

View File

@@ -141,7 +141,7 @@ getParseServerConfig(boost::json::value val)
return config; return config;
}; };
struct WebServerTest : NoLoggerFixture { struct WebServerTest : public virtual ::testing::Test {
~WebServerTest() override ~WebServerTest() override
{ {
work_.reset(); work_.reset();

View File

@@ -35,7 +35,7 @@
using namespace web; using namespace web;
using namespace util::config; using namespace util::config;
struct SubscriptionContextTests : NoLoggerFixture { struct SubscriptionContextTests : public virtual ::testing::Test {
protected: protected:
util::TagDecoratorFactory tagFactory_{ClioConfigDefinition{ util::TagDecoratorFactory tagFactory_{ClioConfigDefinition{
{"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("uint")}, {"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("uint")},

View File

@@ -40,7 +40,7 @@ using namespace std;
using namespace util::config; using namespace util::config;
using namespace web::dosguard; using namespace web::dosguard;
struct DOSGuardTest : NoLoggerFixture { struct DOSGuardTest : public virtual ::testing::Test {
static constexpr auto kJSON_DATA = R"JSON({ static constexpr auto kJSON_DATA = R"JSON({
"dos_guard": { "dos_guard": {
"max_fetches": 100, "max_fetches": 100,

View File

@@ -39,7 +39,7 @@ using namespace util;
using namespace util::config; using namespace util::config;
using namespace web::dosguard; using namespace web::dosguard;
struct WhitelistHandlerTest : NoLoggerFixture {}; struct WhitelistHandlerTest : public virtual ::testing::Test {};
inline static ClioConfigDefinition inline static ClioConfigDefinition
getParseWhitelistHandlerConfig(boost::json::value val) getParseWhitelistHandlerConfig(boost::json::value val)

View File

@@ -41,7 +41,7 @@ using namespace web::impl;
using namespace web; using namespace web;
using namespace util::config; using namespace util::config;
struct ErrorHandlingTests : NoLoggerFixture { struct ErrorHandlingTests : public virtual ::testing::Test {
protected: protected:
util::TagDecoratorFactory tagFactory_{ClioConfigDefinition{ util::TagDecoratorFactory tagFactory_{ClioConfigDefinition{
{"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("uint")}, {"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("uint")},

View File

@@ -73,9 +73,7 @@ struct MakeServerTestBundle {
bool expectSuccess; bool expectSuccess;
}; };
struct MakeServerTest : util::prometheus::WithPrometheus, struct MakeServerTest : util::prometheus::WithPrometheus, testing::WithParamInterface<MakeServerTestBundle> {
NoLoggerFixture,
testing::WithParamInterface<MakeServerTestBundle> {
protected: protected:
boost::asio::io_context ioContext_; boost::asio::io_context ioContext_;
}; };

View File

@@ -43,7 +43,7 @@ using namespace web::ng;
namespace http = boost::beast::http; namespace http = boost::beast::http;
struct NgErrorHandlingTests : NoLoggerFixture { struct NgErrorHandlingTests : public virtual ::testing::Test {
static Request static Request
makeRequest(bool isHttp, std::optional<std::string> body = std::nullopt) makeRequest(bool isHttp, std::optional<std::string> body = std::nullopt)
{ {