mirror of
				https://github.com/XRPLF/clio.git
				synced 2025-11-04 03:45:50 +00:00 
			
		
		
		
	fix: Keep spdlog loggers valid between tests (#2614)
This commit is contained in:
		@@ -42,7 +42,7 @@ using namespace util;
 | 
			
		||||
static constexpr auto kLOG_FORMAT = "%Y-%m-%d %H:%M:%S.%f %^%3!l:%n%$ - %v";
 | 
			
		||||
 | 
			
		||||
struct BenchmarkLoggingInitializer {
 | 
			
		||||
    static std::shared_ptr<spdlog::sinks::sink>
 | 
			
		||||
    [[nodiscard]] static std::shared_ptr<spdlog::sinks::sink>
 | 
			
		||||
    createFileSink(LogService::FileLoggingParams const& params)
 | 
			
		||||
    {
 | 
			
		||||
        return LogService::createFileSink(params, kLOG_FORMAT);
 | 
			
		||||
@@ -72,8 +72,6 @@ uniqueLogDir()
 | 
			
		||||
static void
 | 
			
		||||
benchmarkConcurrentFileLogging(benchmark::State& state)
 | 
			
		||||
{
 | 
			
		||||
    spdlog::drop_all();
 | 
			
		||||
 | 
			
		||||
    auto const numThreads = static_cast<size_t>(state.range(0));
 | 
			
		||||
    auto const messagesPerThread = static_cast<size_t>(state.range(1));
 | 
			
		||||
 | 
			
		||||
@@ -84,7 +82,9 @@ benchmarkConcurrentFileLogging(benchmark::State& state)
 | 
			
		||||
        state.PauseTiming();
 | 
			
		||||
 | 
			
		||||
        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({
 | 
			
		||||
            .logDir = logDir,
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ OnAssert::resetAction()
 | 
			
		||||
void
 | 
			
		||||
OnAssert::defaultAction(std::string_view message)
 | 
			
		||||
{
 | 
			
		||||
    if (LogService::enabled()) {
 | 
			
		||||
    if (LogServiceState::initialized()) {
 | 
			
		||||
        LOG(LogService::fatal()) << message;
 | 
			
		||||
    } else {
 | 
			
		||||
        std::cerr << message;
 | 
			
		||||
 
 | 
			
		||||
@@ -41,12 +41,12 @@
 | 
			
		||||
#include <spdlog/spdlog.h>
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <filesystem>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <stdexcept>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
#include <system_error>
 | 
			
		||||
@@ -56,7 +56,10 @@
 | 
			
		||||
 | 
			
		||||
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 {
 | 
			
		||||
 | 
			
		||||
@@ -238,23 +241,71 @@ getMinSeverity(config::ClioConfigDefinition const& config, Severity defaultSever
 | 
			
		||||
    return minSeverity;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::shared_ptr<spdlog::logger>
 | 
			
		||||
LogService::registerLogger(std::string const& channel, Severity severity)
 | 
			
		||||
void
 | 
			
		||||
LogServiceState::init(bool isAsync, Severity defaultSeverity, std::vector<spdlog::sink_ptr> const& sinks)
 | 
			
		||||
{
 | 
			
		||||
    std::shared_ptr<spdlog::logger> logger;
 | 
			
		||||
    if (data.isAsync) {
 | 
			
		||||
        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());
 | 
			
		||||
    if (initialized_) {
 | 
			
		||||
        throw std::logic_error("LogServiceState is already initialized");
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
    spdlog::register_logger(logger);
 | 
			
		||||
@@ -262,22 +313,12 @@ LogService::registerLogger(std::string const& channel, Severity severity)
 | 
			
		||||
    return logger;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
std::expected<void, std::string>
 | 
			
		||||
LogService::init(config::ClioConfigDefinition const& config)
 | 
			
		||||
std::expected<std::vector<spdlog::sink_ptr>, std::string>
 | 
			
		||||
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");
 | 
			
		||||
 | 
			
		||||
    if (data.isAsync) {
 | 
			
		||||
        spdlog::init_thread_pool(8192, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    data.allSinks = createConsoleSinks(config.get<bool>("log.enable_console"), format);
 | 
			
		||||
    std::vector<spdlog::sink_ptr> allSinks = createConsoleSinks(config.get<bool>("log.enable_console"), format);
 | 
			
		||||
 | 
			
		||||
    if (auto const logDir = config.maybeValue<std::string>("log.directory"); logDir.has_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"),
 | 
			
		||||
            .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
 | 
			
		||||
    auto const maybeMinSeverity = getMinSeverity(config, data.defaultSeverity);
 | 
			
		||||
    auto const maybeMinSeverity = getMinSeverity(config, defaultSeverity_);
 | 
			
		||||
    if (!maybeMinSeverity) {
 | 
			
		||||
        return std::unexpected{maybeMinSeverity.error()};
 | 
			
		||||
    }
 | 
			
		||||
@@ -307,20 +364,23 @@ LogService::init(config::ClioConfigDefinition const& config)
 | 
			
		||||
    // Create loggers for each channel
 | 
			
		||||
    for (auto const& channel : Logger::kCHANNELS) {
 | 
			
		||||
        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);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 {};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void
 | 
			
		||||
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
 | 
			
		||||
@@ -359,17 +419,15 @@ LogService::fatal(SourceLocationType const& loc)
 | 
			
		||||
    return Logger(spdlog::default_logger()).fatal(loc);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool
 | 
			
		||||
LogService::enabled()
 | 
			
		||||
void
 | 
			
		||||
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)
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <expected>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <optional>
 | 
			
		||||
#include <sstream>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <vector>
 | 
			
		||||
@@ -43,9 +44,15 @@ class sink;  // NOLINT(readability-identifier-naming)
 | 
			
		||||
}  // namespace spdlog
 | 
			
		||||
 | 
			
		||||
struct BenchmarkLoggingInitializer;
 | 
			
		||||
class LoggerFixture;
 | 
			
		||||
struct LogServiceInitTests;
 | 
			
		||||
 | 
			
		||||
namespace util {
 | 
			
		||||
 | 
			
		||||
namespace impl {
 | 
			
		||||
class OnAssert;
 | 
			
		||||
}  // namespace impl
 | 
			
		||||
 | 
			
		||||
namespace config {
 | 
			
		||||
class ClioConfigDefinition;
 | 
			
		||||
}  // namespace config
 | 
			
		||||
@@ -228,27 +235,78 @@ private:
 | 
			
		||||
    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.
 | 
			
		||||
 *
 | 
			
		||||
 * 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.
 | 
			
		||||
 */
 | 
			
		||||
class LogService {
 | 
			
		||||
    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);
 | 
			
		||||
 | 
			
		||||
class LogService : public LogServiceState {
 | 
			
		||||
public:
 | 
			
		||||
    LogService() = delete;
 | 
			
		||||
 | 
			
		||||
@@ -321,15 +379,16 @@ public:
 | 
			
		||||
    [[nodiscard]] static Logger::Pump
 | 
			
		||||
    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:
 | 
			
		||||
    /**
 | 
			
		||||
     * @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 {
 | 
			
		||||
        std::string logDir;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@
 | 
			
		||||
 *
 | 
			
		||||
 * This is meant to be used as a base for other fixtures.
 | 
			
		||||
 */
 | 
			
		||||
struct AsyncAsioContextTest : virtual public NoLoggerFixture {
 | 
			
		||||
struct AsyncAsioContextTest : virtual public ::testing::Test {
 | 
			
		||||
    AsyncAsioContextTest()
 | 
			
		||||
    {
 | 
			
		||||
        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`.
 | 
			
		||||
 * 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>
 | 
			
		||||
    void
 | 
			
		||||
    runCoroutine(F&& f, bool allowMockLeak = false)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										43
									
								
								tests/common/util/LoggerBuffer.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								tests/common/util/LoggerBuffer.hpp
									
									
									
									
									
										Normal 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_};
 | 
			
		||||
};
 | 
			
		||||
@@ -22,6 +22,7 @@
 | 
			
		||||
#include "util/log/Logger.hpp"
 | 
			
		||||
 | 
			
		||||
#include <spdlog/common.h>
 | 
			
		||||
#include <spdlog/logger.h>
 | 
			
		||||
#include <spdlog/pattern_formatter.h>
 | 
			
		||||
#include <spdlog/sinks/ostream_sink.h>
 | 
			
		||||
#include <spdlog/spdlog.h>
 | 
			
		||||
@@ -29,32 +30,40 @@
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
LoggerFixture::LoggerFixture()
 | 
			
		||||
void
 | 
			
		||||
LoggerFixture::init()
 | 
			
		||||
{
 | 
			
		||||
    // Clear any existing loggers
 | 
			
		||||
    spdlog::drop_all();
 | 
			
		||||
    util::LogServiceState::init(false, util::Severity::FTL, {});
 | 
			
		||||
 | 
			
		||||
    // Create ostream sink for testing
 | 
			
		||||
    auto ostreamSink = std::make_shared<spdlog::sinks::ostream_sink_mt>(stream_);
 | 
			
		||||
    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);
 | 
			
		||||
    std::ranges::for_each(util::Logger::kCHANNELS, [](char const* channel) {
 | 
			
		||||
        util::LogService::registerLogger(channel);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    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"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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); });
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -19,37 +19,39 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include "util/StringBuffer.hpp"
 | 
			
		||||
#include "util/LoggerBuffer.hpp"
 | 
			
		||||
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
#include <ostream>
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief A fixture for testing LogService and Logger.
 | 
			
		||||
 */
 | 
			
		||||
class LoggerFixture : virtual public ::testing::Test {
 | 
			
		||||
    StringBuffer buffer_;
 | 
			
		||||
    std::ostream stream_ = std::ostream{&buffer_};
 | 
			
		||||
protected:
 | 
			
		||||
    LoggerBuffer buffer_;
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    // Simulates the `util::LogService::init(config)` call
 | 
			
		||||
    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:
 | 
			
		||||
    [[nodiscard]]
 | 
			
		||||
    std::string
 | 
			
		||||
    getLoggerString()
 | 
			
		||||
    {
 | 
			
		||||
        return buffer_.getStrAndReset();
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Fixture with util::Logger support but completely disabled logging.
 | 
			
		||||
 *
 | 
			
		||||
 * This is meant to be used as a base for other fixtures.
 | 
			
		||||
 */
 | 
			
		||||
struct NoLoggerFixture : virtual LoggerFixture {
 | 
			
		||||
    NoLoggerFixture();
 | 
			
		||||
private:
 | 
			
		||||
    void
 | 
			
		||||
    resetTestingLoggers();
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -29,7 +29,7 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
template <template <typename> typename MockType = ::testing::NiceMock>
 | 
			
		||||
struct MockBackendTestBase : virtual public NoLoggerFixture {
 | 
			
		||||
struct MockBackendTestBase : virtual public ::testing::Test {
 | 
			
		||||
    class BackendProxy {
 | 
			
		||||
        std::shared_ptr<MockType<MockBackend>> backend_ =
 | 
			
		||||
            std::make_shared<MockType<MockBackend>>(util::config::ClioConfigDefinition{{}});
 | 
			
		||||
 
 | 
			
		||||
@@ -25,7 +25,7 @@
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Fixture with mock counters
 | 
			
		||||
 */
 | 
			
		||||
struct MockCountersTest : virtual public NoLoggerFixture {
 | 
			
		||||
struct MockCountersTest : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    std::shared_ptr<MockCounters> mockCountersPtr_ = std::make_shared<MockCounters>();
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -33,7 +33,7 @@
 | 
			
		||||
 * @brief Fixture with a mock etl service
 | 
			
		||||
 */
 | 
			
		||||
template <template <typename> typename MockType = ::testing::NiceMock>
 | 
			
		||||
struct MockETLServiceTestBase : virtual public NoLoggerFixture {
 | 
			
		||||
struct MockETLServiceTestBase : virtual public ::testing::Test {
 | 
			
		||||
    using Mock = MockType<MockETLService>;
 | 
			
		||||
 | 
			
		||||
protected:
 | 
			
		||||
@@ -63,7 +63,7 @@ using MockETLServiceTestStrict = MockETLServiceTestBase<::testing::StrictMock>;
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Fixture with a mock etl balancer
 | 
			
		||||
 */
 | 
			
		||||
struct MockLoadBalancerTest : virtual public NoLoggerFixture {
 | 
			
		||||
struct MockLoadBalancerTest : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    std::shared_ptr<MockLoadBalancer> mockLoadBalancerPtr_ = std::make_shared<MockLoadBalancer>();
 | 
			
		||||
};
 | 
			
		||||
@@ -71,7 +71,7 @@ protected:
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Fixture with a mock NG etl balancer
 | 
			
		||||
 */
 | 
			
		||||
struct MockNgLoadBalancerTest : virtual public NoLoggerFixture {
 | 
			
		||||
struct MockNgLoadBalancerTest : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    std::shared_ptr<MockNgLoadBalancer> mockLoadBalancerPtr_ = std::make_shared<MockNgLoadBalancer>();
 | 
			
		||||
};
 | 
			
		||||
@@ -79,7 +79,7 @@ protected:
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Fixture with a mock ledger fetcher
 | 
			
		||||
 */
 | 
			
		||||
struct MockLedgerFetcherTest : virtual public NoLoggerFixture {
 | 
			
		||||
struct MockLedgerFetcherTest : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    std::shared_ptr<MockNgLedgerFetcher> mockLedgerFetcherPtr_ = std::make_shared<MockNgLedgerFetcher>();
 | 
			
		||||
};
 | 
			
		||||
@@ -87,7 +87,7 @@ protected:
 | 
			
		||||
/**
 | 
			
		||||
 * @brief Fixture with a mock ledger fetcher
 | 
			
		||||
 */
 | 
			
		||||
struct MockAmendmentBlockHandlerTest : virtual public NoLoggerFixture {
 | 
			
		||||
struct MockAmendmentBlockHandlerTest : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    std::shared_ptr<MockAmendmentBlockHandler> mockAmendmentBlockHandlerPtr_ =
 | 
			
		||||
        std::make_shared<MockAmendmentBlockHandler>();
 | 
			
		||||
 
 | 
			
		||||
@@ -28,7 +28,7 @@
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
template <template <typename> typename MockType = ::testing::NiceMock>
 | 
			
		||||
struct MockMigrationBackendTestBase : virtual public NoLoggerFixture {
 | 
			
		||||
struct MockMigrationBackendTestBase : virtual public ::testing::Test {
 | 
			
		||||
    class BackendProxy {
 | 
			
		||||
        std::shared_ptr<MockType<MockMigrationBackend>> backend_ =
 | 
			
		||||
            std::make_shared<MockType<MockMigrationBackend>>(util::config::ClioConfigDefinition{});
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@
 | 
			
		||||
 * @brief Fixture with an embedded AnyExecutionContext wrapping a SyncExecutionContext
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
struct SyncExecutionCtxFixture : virtual public NoLoggerFixture {
 | 
			
		||||
struct SyncExecutionCtxFixture : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    util::async::SyncExecutionContext syncCtx_;
 | 
			
		||||
    util::async::AnyExecutionContext ctx_{syncCtx_};
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ using namespace std;
 | 
			
		||||
 | 
			
		||||
using namespace data::cassandra;
 | 
			
		||||
 | 
			
		||||
class BackendCassandraBaseTest : public NoLoggerFixture {
 | 
			
		||||
class BackendCassandraBaseTest : public virtual ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    static Handle
 | 
			
		||||
    createHandle(std::string_view contactPoints, std::string_view keyspace)
 | 
			
		||||
 
 | 
			
		||||
@@ -86,7 +86,7 @@ makeMigrationTestManagerAndBackend(ClioConfigDefinition const& config)
 | 
			
		||||
}
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
class MigrationCassandraSimpleTest : public WithPrometheus, public NoLoggerFixture {
 | 
			
		||||
class MigrationCassandraSimpleTest : public WithPrometheus {
 | 
			
		||||
    // 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
 | 
			
		||||
    // differently
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,7 @@
 | 
			
		||||
*/
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#include "util/LoggerFixtures.hpp"
 | 
			
		||||
#include "util/TerminationHandler.hpp"
 | 
			
		||||
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
@@ -27,5 +28,7 @@ main(int argc, char* argv[])
 | 
			
		||||
    util::setTerminationHandler();
 | 
			
		||||
    testing::InitGoogleTest(&argc, argv);
 | 
			
		||||
 | 
			
		||||
    LoggerFixture::init();
 | 
			
		||||
 | 
			
		||||
    return RUN_ALL_TESTS();
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -37,7 +37,7 @@
 | 
			
		||||
 | 
			
		||||
using namespace app;
 | 
			
		||||
 | 
			
		||||
struct StopperTest : NoLoggerFixture {
 | 
			
		||||
struct StopperTest : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    // Order here is important, stopper_ should die before mockCallback_, otherwise UB
 | 
			
		||||
    testing::StrictMock<testing::MockFunction<void(boost::asio::yield_context)>> mockCallback_;
 | 
			
		||||
 
 | 
			
		||||
@@ -54,7 +54,7 @@ using namespace app;
 | 
			
		||||
namespace http = boost::beast::http;
 | 
			
		||||
using namespace util::config;
 | 
			
		||||
 | 
			
		||||
struct WebHandlersTest : virtual NoLoggerFixture {
 | 
			
		||||
struct WebHandlersTest : virtual public ::testing::Test {
 | 
			
		||||
    DOSGuardStrictMock dosGuardMock;
 | 
			
		||||
    util::TagDecoratorFactory const tagFactory{
 | 
			
		||||
        ClioConfigDefinition{{"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("uint")}}
 | 
			
		||||
 
 | 
			
		||||
@@ -27,7 +27,7 @@
 | 
			
		||||
 | 
			
		||||
using namespace data;
 | 
			
		||||
 | 
			
		||||
struct LedgerCacheTest : util::prometheus::WithPrometheus, NoLoggerFixture {
 | 
			
		||||
struct LedgerCacheTest : util::prometheus::WithPrometheus {
 | 
			
		||||
    LedgerCache cache;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@@ -39,7 +39,7 @@ TEST_F(LedgerCacheTest, defaultState)
 | 
			
		||||
    EXPECT_EQ(cache.latestLedgerSequence(), 0u);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct LedgerCachePrometheusMetricTest : util::prometheus::WithMockPrometheus, NoLoggerFixture {
 | 
			
		||||
struct LedgerCachePrometheusMetricTest : util::prometheus::WithMockPrometheus {
 | 
			
		||||
    LedgerCache cache;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -77,7 +77,7 @@ getParseSettingsConfig(boost::json::value val)
 | 
			
		||||
    return config;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class SettingsProviderTest : public NoLoggerFixture {};
 | 
			
		||||
class SettingsProviderTest : virtual public ::testing::Test {};
 | 
			
		||||
 | 
			
		||||
TEST_F(SettingsProviderTest, Defaults)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -30,7 +30,7 @@ using namespace data;
 | 
			
		||||
using namespace util::prometheus;
 | 
			
		||||
using namespace testing;
 | 
			
		||||
 | 
			
		||||
struct CorruptionDetectorTest : NoLoggerFixture, WithPrometheus {};
 | 
			
		||||
struct CorruptionDetectorTest : WithPrometheus {};
 | 
			
		||||
 | 
			
		||||
TEST_F(CorruptionDetectorTest, DisableCacheOnCorruption)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@ namespace json = boost::json;
 | 
			
		||||
using namespace util;
 | 
			
		||||
using namespace testing;
 | 
			
		||||
 | 
			
		||||
struct ETLStateTest : public NoLoggerFixture {
 | 
			
		||||
struct ETLStateTest : public virtual ::testing::Test {
 | 
			
		||||
    MockSource source = MockSource{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@ constexpr auto kSTART_SEQ = 1234;
 | 
			
		||||
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
class ETLExtractionDataPipeTest : public NoLoggerFixture {
 | 
			
		||||
class ETLExtractionDataPipeTest : public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    etl::impl::ExtractionDataPipe<uint32_t> pipe_{kSTRIDE, kSTART_SEQ};
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -34,7 +34,7 @@
 | 
			
		||||
using namespace testing;
 | 
			
		||||
using namespace etl;
 | 
			
		||||
 | 
			
		||||
struct ETLExtractorTest : util::prometheus::WithPrometheus, NoLoggerFixture {
 | 
			
		||||
struct ETLExtractorTest : util::prometheus::WithPrometheus {
 | 
			
		||||
    using ExtractionDataPipeType = MockExtractionDataPipe;
 | 
			
		||||
    using LedgerFetcherType = MockLedgerFetcher;
 | 
			
		||||
    using ExtractorType = etl::impl::Extractor<ExtractionDataPipeType, LedgerFetcherType>;
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@
 | 
			
		||||
using namespace etl::impl;
 | 
			
		||||
using namespace util::config;
 | 
			
		||||
 | 
			
		||||
struct GrpcSourceTests : NoLoggerFixture, util::prometheus::WithPrometheus, tests::util::WithMockXrpLedgerAPIService {
 | 
			
		||||
struct GrpcSourceTests : util::prometheus::WithPrometheus, tests::util::WithMockXrpLedgerAPIService {
 | 
			
		||||
    GrpcSourceTests()
 | 
			
		||||
        : WithMockXrpLedgerAPIService("localhost:0")
 | 
			
		||||
        , mockBackend_(std::make_shared<testing::StrictMock<MockBackend>>(ClioConfigDefinition{}))
 | 
			
		||||
 
 | 
			
		||||
@@ -56,7 +56,7 @@ constexpr auto kOFFER_ID = "AA86CBF29770F72FA3FF4A5D9A9FA54D6F399A8E038F72393EF7
 | 
			
		||||
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
struct NFTHelpersTest : NoLoggerFixture {
 | 
			
		||||
struct NFTHelpersTest : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    static void
 | 
			
		||||
    verifyNFTTransactionsData(
 | 
			
		||||
 
 | 
			
		||||
@@ -50,7 +50,7 @@ constinit auto const kLEDGER_HASH2 = "1B8590C01B0006EDFA9ED60296DD052DC5E90F9965
 | 
			
		||||
constinit auto const kSEQ = 30;
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
struct ExtractionModelNgTests : NoLoggerFixture {};
 | 
			
		||||
struct ExtractionModelNgTests : virtual public ::testing::Test {};
 | 
			
		||||
 | 
			
		||||
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)
 | 
			
		||||
{
 | 
			
		||||
@@ -360,7 +360,7 @@ TEST_F(ExtractionNgTests, SuccessorsWithNoNeighborsIncluded)
 | 
			
		||||
    ASSERT_FALSE(res.has_value());
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ExtractionAssertTest : common::util::WithMockAssert, NoLoggerFixture {};
 | 
			
		||||
struct ExtractionAssertTest : common::util::WithMockAssert {};
 | 
			
		||||
 | 
			
		||||
TEST_F(ExtractionAssertTest, InvalidModTypeAsserts)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
        : WithMockXrpLedgerAPIService("localhost:0"), grpcSource_("localhost", std::to_string(getXRPLMockPort()))
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,7 @@
 | 
			
		||||
 | 
			
		||||
using namespace etlng::impl;
 | 
			
		||||
 | 
			
		||||
struct NetworkValidatedLedgersTests : NoLoggerFixture {
 | 
			
		||||
struct NetworkValidatedLedgersTests : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    util::async::CoroExecutionContext ctx_{2};
 | 
			
		||||
    std::shared_ptr<etl::NetworkValidatedLedgersInterface> ledgers_ =
 | 
			
		||||
 
 | 
			
		||||
@@ -254,7 +254,7 @@ struct MockExtNftBurnReadonly {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct RegistryTest : NoLoggerFixture, util::prometheus::WithPrometheus {
 | 
			
		||||
struct RegistryTest : util::prometheus::WithPrometheus {
 | 
			
		||||
    RegistryTest()
 | 
			
		||||
    {
 | 
			
		||||
        state_.isWriting = true;
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,7 @@ public:
 | 
			
		||||
};
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
struct ForwardSchedulerTests : NoLoggerFixture {
 | 
			
		||||
struct ForwardSchedulerTests : virtual public ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    MockNetworkValidatedLedgersPtr networkValidatedLedgers_;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -86,7 +86,7 @@ struct MockMonitor : etlng::MonitorInterface {
 | 
			
		||||
    MOCK_METHOD(void, stop, (), (override));
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct TaskManagerTests : NoLoggerFixture {
 | 
			
		||||
struct TaskManagerTests : virtual public ::testing::Test {
 | 
			
		||||
    using MockSchedulerType = testing::NiceMock<MockScheduler>;
 | 
			
		||||
    using MockExtractorType = testing::NiceMock<MockExtractor>;
 | 
			
		||||
    using MockLoaderType = testing::NiceMock<MockLoader>;
 | 
			
		||||
 
 | 
			
		||||
@@ -59,7 +59,7 @@ createTestData()
 | 
			
		||||
 | 
			
		||||
}  // namespace
 | 
			
		||||
 | 
			
		||||
struct CacheExtTests : NoLoggerFixture, util::prometheus::WithPrometheus {
 | 
			
		||||
struct CacheExtTests : util::prometheus::WithPrometheus {
 | 
			
		||||
protected:
 | 
			
		||||
    MockLedgerCache cache_;
 | 
			
		||||
    std::shared_ptr<etlng::impl::CacheUpdater> updater_ = std::make_shared<etlng::impl::CacheUpdater>(cache_);
 | 
			
		||||
 
 | 
			
		||||
@@ -26,7 +26,7 @@
 | 
			
		||||
 | 
			
		||||
#include <gtest/gtest.h>
 | 
			
		||||
 | 
			
		||||
struct MigrationManagerFactoryTests : public NoLoggerFixture {};
 | 
			
		||||
struct MigrationManagerFactoryTests : public virtual ::testing::Test {};
 | 
			
		||||
 | 
			
		||||
TEST_F(MigrationManagerFactoryTests, InvalidDBType)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -76,7 +76,7 @@ TEST_F(FullTableScannerAssertTest, cursorsPerWorkerZero)
 | 
			
		||||
    );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct FullTableScannerTests : NoLoggerFixture {};
 | 
			
		||||
struct FullTableScannerTests : public virtual ::testing::Test {};
 | 
			
		||||
 | 
			
		||||
TEST_F(FullTableScannerTests, SingleThreadCtx)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ using namespace util::config;
 | 
			
		||||
using namespace rpc::impl;
 | 
			
		||||
namespace json = boost::json;
 | 
			
		||||
 | 
			
		||||
class RPCAPIVersionTest : public NoLoggerFixture {
 | 
			
		||||
class RPCAPIVersionTest : public virtual ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    ProductionAPIVersionParser parser_{kDEFAULT_API_VERSION, kMIN_API_VERSION, kMAX_API_VERSION};
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -49,7 +49,7 @@ using namespace rpc::modifiers;
 | 
			
		||||
 | 
			
		||||
namespace json = boost::json;
 | 
			
		||||
 | 
			
		||||
class RPCBaseTest : public NoLoggerFixture {};
 | 
			
		||||
class RPCBaseTest : public virtual ::testing::Test {};
 | 
			
		||||
 | 
			
		||||
TEST_F(RPCBaseTest, CheckType)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@ using util::prometheus::CounterInt;
 | 
			
		||||
using util::prometheus::WithMockPrometheus;
 | 
			
		||||
using util::prometheus::WithPrometheus;
 | 
			
		||||
 | 
			
		||||
struct RPCCountersTest : WithPrometheus, NoLoggerFixture {
 | 
			
		||||
struct RPCCountersTest : WithPrometheus {
 | 
			
		||||
    WorkQueue queue{4u, 1024u};  // todo: mock instead
 | 
			
		||||
    Counters counters{queue};
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ using namespace util::config;
 | 
			
		||||
using namespace rpc;
 | 
			
		||||
using namespace util::prometheus;
 | 
			
		||||
 | 
			
		||||
struct RPCWorkQueueTestBase : NoLoggerFixture {
 | 
			
		||||
struct RPCWorkQueueTestBase : public virtual ::testing::Test {
 | 
			
		||||
    ClioConfigDefinition cfg = {
 | 
			
		||||
        {"server.max_queue_size", ConfigValue{ConfigType::Integer}.defaultValue(2)},
 | 
			
		||||
        {"workers", ConfigValue{ConfigType::Integer}.defaultValue(4)}
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ using namespace util::config;
 | 
			
		||||
using testing::MockFunction;
 | 
			
		||||
using testing::StrictMock;
 | 
			
		||||
 | 
			
		||||
struct SignalsHandlerTestsBase : NoLoggerFixture {
 | 
			
		||||
struct SignalsHandlerTestsBase : public virtual ::testing::Test {
 | 
			
		||||
    void
 | 
			
		||||
    allowTestToFinish()
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
@@ -327,7 +327,7 @@ TEST_F(IncorrectOverrideValues, InvalidJsonErrors)
 | 
			
		||||
    EXPECT_EQ(expectedErrors, actualErrors);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
struct ClioConfigDefinitionParseArrayTest : NoLoggerFixture {
 | 
			
		||||
struct ClioConfigDefinitionParseArrayTest : public virtual ::testing::Test {
 | 
			
		||||
    ClioConfigDefinition config{
 | 
			
		||||
        {"array.[].int", Array{ConfigValue{ConfigType::Integer}}},
 | 
			
		||||
        {"array.[].string", Array{ConfigValue{ConfigType::String}.optional()}}
 | 
			
		||||
 
 | 
			
		||||
@@ -52,7 +52,8 @@ struct ConfigFileJsonParseTestBundle {
 | 
			
		||||
    ValidationMap validationMap;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct ConfigFileJsonParseTest : NoLoggerFixture, testing::WithParamInterface<ConfigFileJsonParseTestBundle> {};
 | 
			
		||||
struct ConfigFileJsonParseTest : public virtual ::testing::Test,
 | 
			
		||||
                                 testing::WithParamInterface<ConfigFileJsonParseTestBundle> {};
 | 
			
		||||
 | 
			
		||||
TEST_P(ConfigFileJsonParseTest, parseValues)
 | 
			
		||||
{
 | 
			
		||||
@@ -309,7 +310,7 @@ INSTANTIATE_TEST_CASE_P(
 | 
			
		||||
    tests::util::kNAME_GENERATOR
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
struct ConfigFileJsonTest : NoLoggerFixture {};
 | 
			
		||||
struct ConfigFileJsonTest : public virtual ::testing::Test {};
 | 
			
		||||
 | 
			
		||||
TEST_F(ConfigFileJsonTest, getValue)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@
 | 
			
		||||
 | 
			
		||||
using namespace util::config;
 | 
			
		||||
 | 
			
		||||
struct ConfigValueTest : common::util::WithMockAssert, NoLoggerFixture {};
 | 
			
		||||
struct ConfigValueTest : common::util::WithMockAssert {};
 | 
			
		||||
 | 
			
		||||
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
 | 
			
		||||
struct ConstraintTest : NoLoggerFixture {};
 | 
			
		||||
struct ConstraintTest : public virtual ::testing::Test {};
 | 
			
		||||
 | 
			
		||||
TEST_F(ConstraintTest, PortConstraint)
 | 
			
		||||
{
 | 
			
		||||
 
 | 
			
		||||
@@ -17,7 +17,8 @@
 | 
			
		||||
*/
 | 
			
		||||
//==============================================================================
 | 
			
		||||
 | 
			
		||||
#include "util/StringBuffer.hpp"
 | 
			
		||||
#include "util/LoggerBuffer.hpp"
 | 
			
		||||
#include "util/LoggerFixtures.hpp"
 | 
			
		||||
#include "util/config/Array.hpp"
 | 
			
		||||
#include "util/config/ConfigConstraints.hpp"
 | 
			
		||||
#include "util/config/ConfigDefinition.hpp"
 | 
			
		||||
@@ -39,8 +40,6 @@
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <cstdint>
 | 
			
		||||
#include <limits>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <ostream>
 | 
			
		||||
#include <string>
 | 
			
		||||
#include <string_view>
 | 
			
		||||
#include <vector>
 | 
			
		||||
@@ -51,7 +50,21 @@ using util::config::ConfigFileJson;
 | 
			
		||||
using util::config::ConfigType;
 | 
			
		||||
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:
 | 
			
		||||
    util::config::ClioConfigDefinition config_{
 | 
			
		||||
        {"log.channels.[].channel", Array{ConfigValue{ConfigType::String}}},
 | 
			
		||||
@@ -80,26 +93,6 @@ protected:
 | 
			
		||||
    {
 | 
			
		||||
        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)
 | 
			
		||||
@@ -107,15 +100,15 @@ TEST_F(LogServiceInitTests, DefaultLogLevel)
 | 
			
		||||
    auto const parsingErrors =
 | 
			
		||||
        config_.parse(ConfigFileJson{boost::json::object{{"log", boost::json::object{{"level", "warn"}}}}});
 | 
			
		||||
    ASSERT_FALSE(parsingErrors.has_value());
 | 
			
		||||
    std::string const logString = "some log";
 | 
			
		||||
 | 
			
		||||
    EXPECT_TRUE(LogService::init(config_));
 | 
			
		||||
    replaceSinks();
 | 
			
		||||
 | 
			
		||||
    std::string const logString = "some log";
 | 
			
		||||
    for (auto const& channel : Logger::kCHANNELS) {
 | 
			
		||||
        Logger const log{channel};
 | 
			
		||||
        log.trace() << logString;
 | 
			
		||||
        ASSERT_TRUE(getLoggerString().empty());
 | 
			
		||||
        auto loggerStr = getLoggerString();
 | 
			
		||||
        ASSERT_TRUE(loggerStr.empty()) << " channel: " << channel << " logger_str: " << loggerStr;
 | 
			
		||||
 | 
			
		||||
        log.debug() << logString;
 | 
			
		||||
        ASSERT_TRUE(getLoggerString().empty());
 | 
			
		||||
@@ -149,11 +142,10 @@ TEST_F(LogServiceInitTests, ChannelLogLevel)
 | 
			
		||||
 | 
			
		||||
    auto const parsingErrors = config_.parse(ConfigFileJson{boost::json::parse(configStr).as_object()});
 | 
			
		||||
    ASSERT_FALSE(parsingErrors.has_value());
 | 
			
		||||
    std::string const logString = "some log";
 | 
			
		||||
 | 
			
		||||
    EXPECT_TRUE(LogService::init(config_));
 | 
			
		||||
    replaceSinks();
 | 
			
		||||
 | 
			
		||||
    std::string const logString = "some log";
 | 
			
		||||
    for (auto const& channel : Logger::kCHANNELS) {
 | 
			
		||||
        Logger const log{channel};
 | 
			
		||||
        log.trace() << logString;
 | 
			
		||||
 
 | 
			
		||||
@@ -29,12 +29,10 @@ using namespace util;
 | 
			
		||||
// Used as a fixture for tests with enabled logging
 | 
			
		||||
class LoggerTest : public LoggerFixture {};
 | 
			
		||||
 | 
			
		||||
// Used as a fixture for tests with disabled logging
 | 
			
		||||
class NoLoggerTest : public NoLoggerFixture {};
 | 
			
		||||
 | 
			
		||||
TEST_F(LoggerTest, Basic)
 | 
			
		||||
{
 | 
			
		||||
    Logger const log{"General"};
 | 
			
		||||
 | 
			
		||||
    log.info() << "Info line logged";
 | 
			
		||||
    ASSERT_EQ(getLoggerString(), "inf:General - Info line logged\n");
 | 
			
		||||
 | 
			
		||||
@@ -53,10 +51,6 @@ TEST_F(LoggerTest, Filtering)
 | 
			
		||||
 | 
			
		||||
    log.warn() << "Warning is logged";
 | 
			
		||||
    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
 | 
			
		||||
@@ -77,13 +71,3 @@ TEST_F(LoggerTest, LOGMacro)
 | 
			
		||||
    EXPECT_TRUE(computeCalled);
 | 
			
		||||
}
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
TEST_F(NoLoggerTest, Basic)
 | 
			
		||||
{
 | 
			
		||||
    Logger const log{"Trace"};
 | 
			
		||||
    log.trace() << "Nothing";
 | 
			
		||||
    ASSERT_TRUE(getLoggerString().empty());
 | 
			
		||||
 | 
			
		||||
    LogService::fatal() << "Still nothing";
 | 
			
		||||
    ASSERT_TRUE(getLoggerString().empty());
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -38,7 +38,7 @@
 | 
			
		||||
namespace http = boost::beast::http;
 | 
			
		||||
using namespace util::config;
 | 
			
		||||
 | 
			
		||||
class IPAdminVerificationStrategyTest : public NoLoggerFixture {
 | 
			
		||||
class IPAdminVerificationStrategyTest : public virtual ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    web::IPAdminVerificationStrategy strat_;
 | 
			
		||||
    http::request<http::string_body> request_;
 | 
			
		||||
@@ -53,7 +53,7 @@ TEST_F(IPAdminVerificationStrategyTest, IsAdminOnlyForIP_127_0_0_1)
 | 
			
		||||
    EXPECT_FALSE(strat_.isAdmin(request_, "localhost"));
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class PasswordAdminVerificationStrategyTest : public NoLoggerFixture {
 | 
			
		||||
class PasswordAdminVerificationStrategyTest : public virtual ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    std::string const password_ = "secret";
 | 
			
		||||
    std::string const passwordHash_ = "2bb80d537b1da3e38bd30361aa855686bde0eacd7162fef6a25fe97bf527a25b";
 | 
			
		||||
 
 | 
			
		||||
@@ -141,7 +141,7 @@ getParseServerConfig(boost::json::value val)
 | 
			
		||||
    return config;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct WebServerTest : NoLoggerFixture {
 | 
			
		||||
struct WebServerTest : public virtual ::testing::Test {
 | 
			
		||||
    ~WebServerTest() override
 | 
			
		||||
    {
 | 
			
		||||
        work_.reset();
 | 
			
		||||
 
 | 
			
		||||
@@ -35,7 +35,7 @@
 | 
			
		||||
using namespace web;
 | 
			
		||||
using namespace util::config;
 | 
			
		||||
 | 
			
		||||
struct SubscriptionContextTests : NoLoggerFixture {
 | 
			
		||||
struct SubscriptionContextTests : public virtual ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    util::TagDecoratorFactory tagFactory_{ClioConfigDefinition{
 | 
			
		||||
        {"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("uint")},
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ using namespace std;
 | 
			
		||||
using namespace util::config;
 | 
			
		||||
using namespace web::dosguard;
 | 
			
		||||
 | 
			
		||||
struct DOSGuardTest : NoLoggerFixture {
 | 
			
		||||
struct DOSGuardTest : public virtual ::testing::Test {
 | 
			
		||||
    static constexpr auto kJSON_DATA = R"JSON({
 | 
			
		||||
        "dos_guard": {
 | 
			
		||||
            "max_fetches": 100,
 | 
			
		||||
 
 | 
			
		||||
@@ -39,7 +39,7 @@ using namespace util;
 | 
			
		||||
using namespace util::config;
 | 
			
		||||
using namespace web::dosguard;
 | 
			
		||||
 | 
			
		||||
struct WhitelistHandlerTest : NoLoggerFixture {};
 | 
			
		||||
struct WhitelistHandlerTest : public virtual ::testing::Test {};
 | 
			
		||||
 | 
			
		||||
inline static ClioConfigDefinition
 | 
			
		||||
getParseWhitelistHandlerConfig(boost::json::value val)
 | 
			
		||||
 
 | 
			
		||||
@@ -41,7 +41,7 @@ using namespace web::impl;
 | 
			
		||||
using namespace web;
 | 
			
		||||
using namespace util::config;
 | 
			
		||||
 | 
			
		||||
struct ErrorHandlingTests : NoLoggerFixture {
 | 
			
		||||
struct ErrorHandlingTests : public virtual ::testing::Test {
 | 
			
		||||
protected:
 | 
			
		||||
    util::TagDecoratorFactory tagFactory_{ClioConfigDefinition{
 | 
			
		||||
        {"log.tag_style", ConfigValue{ConfigType::String}.defaultValue("uint")},
 | 
			
		||||
 
 | 
			
		||||
@@ -73,9 +73,7 @@ struct MakeServerTestBundle {
 | 
			
		||||
    bool expectSuccess;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MakeServerTest : util::prometheus::WithPrometheus,
 | 
			
		||||
                        NoLoggerFixture,
 | 
			
		||||
                        testing::WithParamInterface<MakeServerTestBundle> {
 | 
			
		||||
struct MakeServerTest : util::prometheus::WithPrometheus, testing::WithParamInterface<MakeServerTestBundle> {
 | 
			
		||||
protected:
 | 
			
		||||
    boost::asio::io_context ioContext_;
 | 
			
		||||
};
 | 
			
		||||
 
 | 
			
		||||
@@ -43,7 +43,7 @@ using namespace web::ng;
 | 
			
		||||
 | 
			
		||||
namespace http = boost::beast::http;
 | 
			
		||||
 | 
			
		||||
struct NgErrorHandlingTests : NoLoggerFixture {
 | 
			
		||||
struct NgErrorHandlingTests : public virtual ::testing::Test {
 | 
			
		||||
    static Request
 | 
			
		||||
    makeRequest(bool isHttp, std::optional<std::string> body = std::nullopt)
 | 
			
		||||
    {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user