mirror of
https://github.com/falk-werner/webfused
synced 2024-10-27 20:44:08 +00:00
log config errors
This commit is contained in:
parent
03dc713649
commit
ad01f90bea
@ -105,6 +105,7 @@ include(GoogleTest)
|
|||||||
pkg_check_modules(GMOCK gmock)
|
pkg_check_modules(GMOCK gmock)
|
||||||
|
|
||||||
add_executable(alltests
|
add_executable(alltests
|
||||||
|
test/mock_logger.cc
|
||||||
test/test_config.cc
|
test/test_config.cc
|
||||||
test/test_log.cc
|
test/test_log.cc
|
||||||
)
|
)
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#include "webfused/config/factory.h"
|
#include "webfused/config/factory.h"
|
||||||
#include "webfused/config/config_intern.h"
|
#include "webfused/config/config_intern.h"
|
||||||
#include "webfused/config/config.h"
|
#include "webfused/config/config.h"
|
||||||
|
#include "webfused/log/log.h"
|
||||||
|
|
||||||
#include <libconfig.h>
|
#include <libconfig.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@ -23,13 +24,15 @@ wfd_config_check_version(
|
|||||||
int rc = config_lookup_int(config, "version.major", &version_major);
|
int rc = config_lookup_int(config, "version.major", &version_major);
|
||||||
if (CONFIG_TRUE != rc)
|
if (CONFIG_TRUE != rc)
|
||||||
{
|
{
|
||||||
// error: missing major version
|
WFD_ERROR("failed to load config: missing version.major");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WFD_CONFIG_VERSION_MAJOR != version_major)
|
if (WFD_CONFIG_VERSION_MAJOR != version_major)
|
||||||
{
|
{
|
||||||
// error: incompatible version, expected WFD_CONFIG_VERSION_MAJOR
|
WFD_ERROR("failed to load config: "
|
||||||
|
"incompatible versions: expected %d, but war %d",
|
||||||
|
WFD_CONFIG_VERSION_MAJOR, version_major);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -37,17 +40,17 @@ wfd_config_check_version(
|
|||||||
rc = config_lookup_int(config, "version.minor", &version_minor);
|
rc = config_lookup_int(config, "version.minor", &version_minor);
|
||||||
if (CONFIG_TRUE != rc)
|
if (CONFIG_TRUE != rc)
|
||||||
{
|
{
|
||||||
// error: missing minor version
|
WFD_ERROR("failed to load config: missing version.minor");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (WFD_CONFIG_VERSION_MINOR < version_minor)
|
if (WFD_CONFIG_VERSION_MINOR < version_minor)
|
||||||
{
|
{
|
||||||
// warn: some features might be disabled
|
WFD_WARN("newer config detected: some features might be disabled");
|
||||||
}
|
}
|
||||||
else if (WFD_CONFIG_VERSION_MINOR > version_minor)
|
else if (WFD_CONFIG_VERSION_MINOR > version_minor)
|
||||||
{
|
{
|
||||||
// info: use default values
|
WFD_INFO("old config detected: some features might use default values");
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
58
test/mock_logger.cc
Normal file
58
test/mock_logger.cc
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
#include "mock_logger.hpp"
|
||||||
|
#include "webfused/log/logger.h"
|
||||||
|
#include "webfused/log/log.h"
|
||||||
|
|
||||||
|
namespace webfused_test
|
||||||
|
{
|
||||||
|
|
||||||
|
MockLogger::MockLogger(bool omit_init)
|
||||||
|
: close_on_destruct(!omit_init)
|
||||||
|
{
|
||||||
|
if (!omit_init)
|
||||||
|
{
|
||||||
|
wfd_logger_init(
|
||||||
|
WFD_LOGLEVEL_ALL,
|
||||||
|
&wfd_MockLogger_log,
|
||||||
|
&wfd_MockLogger_onclose,
|
||||||
|
getUserData());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MockLogger::~MockLogger()
|
||||||
|
{
|
||||||
|
if (close_on_destruct)
|
||||||
|
{
|
||||||
|
wfd_logger_close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void * MockLogger::getUserData()
|
||||||
|
{
|
||||||
|
ILogger * logger = this;
|
||||||
|
return reinterpret_cast<void*>(logger);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
using webfused_test::ILogger;
|
||||||
|
|
||||||
|
void wfd_MockLogger_log(
|
||||||
|
void * user_data,
|
||||||
|
int level,
|
||||||
|
char const * format,
|
||||||
|
va_list args)
|
||||||
|
{
|
||||||
|
ILogger * logger = reinterpret_cast<ILogger*>(user_data);
|
||||||
|
logger->log(level, format, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
void wfd_MockLogger_onclose(
|
||||||
|
void * user_data)
|
||||||
|
{
|
||||||
|
ILogger * logger = reinterpret_cast<ILogger*>(user_data);
|
||||||
|
logger->onclose();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
47
test/mock_logger.hpp
Normal file
47
test/mock_logger.hpp
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef WFD_MOCK_LOGGER_HPP
|
||||||
|
#define WFD_MOCK_LOGGER_HPP
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <cstdarg>
|
||||||
|
|
||||||
|
namespace webfused_test
|
||||||
|
{
|
||||||
|
|
||||||
|
class ILogger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~ILogger() = default;
|
||||||
|
virtual void log(int level, char const * format, va_list args) = 0;
|
||||||
|
virtual void onclose() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
class MockLogger: public ILogger
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit MockLogger(bool omit_init = false);
|
||||||
|
~MockLogger() override;
|
||||||
|
MOCK_METHOD3(log, void(int level, char const * format, va_list args));
|
||||||
|
MOCK_METHOD0(onclose, void(void));
|
||||||
|
|
||||||
|
void * getUserData();
|
||||||
|
private:
|
||||||
|
bool close_on_destruct;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C"
|
||||||
|
{
|
||||||
|
|
||||||
|
extern void wfd_MockLogger_log(
|
||||||
|
void * user_data,
|
||||||
|
int level,
|
||||||
|
char const * format,
|
||||||
|
va_list args);
|
||||||
|
|
||||||
|
extern void wfd_MockLogger_onclose(
|
||||||
|
void * user_data);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
#include "webfused/config/factory.h"
|
#include "webfused/config/factory.h"
|
||||||
#include "webfused/config/config.h"
|
#include "webfused/config/config.h"
|
||||||
|
#include "webfused/log/logger.h"
|
||||||
|
#include "webfused/log/log.h"
|
||||||
|
#include "mock_logger.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
using ::testing::_;
|
||||||
|
using ::webfused_test::MockLogger;
|
||||||
|
|
||||||
TEST(config, is_loadable)
|
TEST(config, is_loadable)
|
||||||
{
|
{
|
||||||
@ -13,6 +20,10 @@ TEST(config, is_loadable)
|
|||||||
|
|
||||||
TEST(config, minimal_config)
|
TEST(config, minimal_config)
|
||||||
{
|
{
|
||||||
|
MockLogger logger;
|
||||||
|
EXPECT_CALL(logger, log(_, _, _)).Times(0);
|
||||||
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
char const minimal[] = "version = { major = 1, minor = 0 }\n";
|
char const minimal[] = "version = { major = 1, minor = 0 }\n";
|
||||||
struct wfd_config * config = wfd_config_load_string(minimal);
|
struct wfd_config * config = wfd_config_load_string(minimal);
|
||||||
ASSERT_NE(nullptr, config);
|
ASSERT_NE(nullptr, config);
|
||||||
@ -22,6 +33,10 @@ TEST(config, minimal_config)
|
|||||||
|
|
||||||
TEST(config, invalid_major_version_too_low)
|
TEST(config, invalid_major_version_too_low)
|
||||||
{
|
{
|
||||||
|
MockLogger logger;
|
||||||
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
|
||||||
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
char const too_low[] = "version = { major = 0, minor = 0 }\n";
|
char const too_low[] = "version = { major = 0, minor = 0 }\n";
|
||||||
|
|
||||||
struct wfd_config * config = wfd_config_load_string(too_low);
|
struct wfd_config * config = wfd_config_load_string(too_low);
|
||||||
@ -30,14 +45,46 @@ TEST(config, invalid_major_version_too_low)
|
|||||||
|
|
||||||
TEST(config, invalid_major_version_too_high)
|
TEST(config, invalid_major_version_too_high)
|
||||||
{
|
{
|
||||||
|
MockLogger logger;
|
||||||
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
|
||||||
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
char const too_high[] = "version = { major = 2, minor = 0 }\n";
|
char const too_high[] = "version = { major = 2, minor = 0 }\n";
|
||||||
|
|
||||||
struct wfd_config * config = wfd_config_load_string(too_high);
|
struct wfd_config * config = wfd_config_load_string(too_high);
|
||||||
ASSERT_EQ(nullptr, config);
|
ASSERT_EQ(nullptr, config);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(config, invalid_missing_major_version)
|
||||||
|
{
|
||||||
|
MockLogger logger;
|
||||||
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
|
||||||
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
|
char const too_high[] = "version = { minor = 0 }\n";
|
||||||
|
|
||||||
|
struct wfd_config * config = wfd_config_load_string(too_high);
|
||||||
|
ASSERT_EQ(nullptr, config);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(config, invalid_missing_minor_version)
|
||||||
|
{
|
||||||
|
MockLogger logger;
|
||||||
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, _, _)).Times(1);
|
||||||
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
|
char const too_high[] = "version = { major = 1 }\n";
|
||||||
|
|
||||||
|
struct wfd_config * config = wfd_config_load_string(too_high);
|
||||||
|
ASSERT_EQ(nullptr, config);
|
||||||
|
}
|
||||||
|
|
||||||
TEST(config, valid_older_minor)
|
TEST(config, valid_older_minor)
|
||||||
{
|
{
|
||||||
|
MockLogger logger;
|
||||||
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_INFO, _, _)).Times(1);
|
||||||
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
char const valid[] = "version = { major = 1, minor = -1 }\n";
|
char const valid[] = "version = { major = 1, minor = -1 }\n";
|
||||||
|
|
||||||
struct wfd_config * config = wfd_config_load_string(valid);
|
struct wfd_config * config = wfd_config_load_string(valid);
|
||||||
@ -48,6 +95,10 @@ TEST(config, valid_older_minor)
|
|||||||
|
|
||||||
TEST(config, valid_newer_minor)
|
TEST(config, valid_newer_minor)
|
||||||
{
|
{
|
||||||
|
MockLogger logger;
|
||||||
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, _, _)).Times(1);
|
||||||
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
char const valid[] = "version = { major = 1, minor = 1 }\n";
|
char const valid[] = "version = { major = 1, minor = 1 }\n";
|
||||||
|
|
||||||
struct wfd_config * config = wfd_config_load_string(valid);
|
struct wfd_config * config = wfd_config_load_string(valid);
|
||||||
|
@ -3,150 +3,104 @@
|
|||||||
|
|
||||||
#include "webfused/log/logger.h"
|
#include "webfused/log/logger.h"
|
||||||
#include "webfused/log/log.h"
|
#include "webfused/log/log.h"
|
||||||
|
#include "mock_logger.hpp"
|
||||||
|
|
||||||
using ::testing::_;
|
using ::testing::_;
|
||||||
using ::testing::StrEq;
|
using ::testing::StrEq;
|
||||||
|
using ::webfused_test::MockLogger;
|
||||||
namespace
|
|
||||||
{
|
|
||||||
|
|
||||||
class ILogger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
virtual ~ILogger() = default;
|
|
||||||
virtual void log(int level, char const * format, va_list args) = 0;
|
|
||||||
virtual void onclose() = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
class MockLogger: public ILogger
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
MOCK_METHOD3(log, void(int level, char const * format, va_list args));
|
|
||||||
MOCK_METHOD0(onclose, void(void));
|
|
||||||
|
|
||||||
void * getUserData()
|
|
||||||
{
|
|
||||||
ILogger * logger = this;
|
|
||||||
return reinterpret_cast<void*>(logger);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
|
|
||||||
static void MockLogger_log(
|
|
||||||
void * user_data,
|
|
||||||
int level,
|
|
||||||
char const * format,
|
|
||||||
va_list args)
|
|
||||||
{
|
|
||||||
ILogger * logger = reinterpret_cast<ILogger*>(user_data);
|
|
||||||
logger->log(level, format, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void MockLogger_onclose(
|
|
||||||
void * user_data)
|
|
||||||
{
|
|
||||||
ILogger * logger = reinterpret_cast<ILogger*>(user_data);
|
|
||||||
logger->onclose();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(log, fatal)
|
TEST(log, fatal)
|
||||||
{
|
{
|
||||||
MockLogger logger;
|
MockLogger logger(true);
|
||||||
|
|
||||||
EXPECT_CALL(logger, log(WFD_LOGLEVEL_FATAL, StrEq("too bad"), _)).Times(1);
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_FATAL, StrEq("too bad"), _)).Times(1);
|
||||||
EXPECT_CALL(logger, onclose()).Times(1);
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
wfd_logger_init(WFD_LOGLEVEL_ALL, &MockLogger_log, &MockLogger_onclose, logger.getUserData());
|
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
|
||||||
WFD_FATAL("too bad");
|
WFD_FATAL("too bad");
|
||||||
wfd_logger_close();
|
wfd_logger_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(log, error)
|
TEST(log, error)
|
||||||
{
|
{
|
||||||
MockLogger logger;
|
MockLogger logger(true);
|
||||||
|
|
||||||
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, StrEq("too bad"), _)).Times(1);
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_ERROR, StrEq("too bad"), _)).Times(1);
|
||||||
EXPECT_CALL(logger, onclose()).Times(1);
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
wfd_logger_init(WFD_LOGLEVEL_ALL, &MockLogger_log, &MockLogger_onclose, logger.getUserData());
|
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
|
||||||
WFD_ERROR("too bad");
|
WFD_ERROR("too bad");
|
||||||
wfd_logger_close();
|
wfd_logger_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(log, warn)
|
TEST(log, warn)
|
||||||
{
|
{
|
||||||
MockLogger logger;
|
MockLogger logger(true);
|
||||||
|
|
||||||
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
|
||||||
EXPECT_CALL(logger, onclose()).Times(1);
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
wfd_logger_init(WFD_LOGLEVEL_ALL, &MockLogger_log, &MockLogger_onclose, logger.getUserData());
|
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
|
||||||
WFD_WARN("too bad");
|
WFD_WARN("too bad");
|
||||||
wfd_logger_close();
|
wfd_logger_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(log, info)
|
TEST(log, info)
|
||||||
{
|
{
|
||||||
MockLogger logger;
|
MockLogger logger(true);
|
||||||
|
|
||||||
EXPECT_CALL(logger, log(WFD_LOGLEVEL_INFO, StrEq("too bad"), _)).Times(1);
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_INFO, StrEq("too bad"), _)).Times(1);
|
||||||
EXPECT_CALL(logger, onclose()).Times(1);
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
wfd_logger_init(WFD_LOGLEVEL_ALL, &MockLogger_log, &MockLogger_onclose, logger.getUserData());
|
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
|
||||||
WFD_INFO("too bad");
|
WFD_INFO("too bad");
|
||||||
wfd_logger_close();
|
wfd_logger_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(log, debug)
|
TEST(log, debug)
|
||||||
{
|
{
|
||||||
MockLogger logger;
|
MockLogger logger(true);
|
||||||
|
|
||||||
EXPECT_CALL(logger, log(WFD_LOGLEVEL_DEBUG, StrEq("too bad"), _)).Times(1);
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_DEBUG, StrEq("too bad"), _)).Times(1);
|
||||||
EXPECT_CALL(logger, onclose()).Times(1);
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
wfd_logger_init(WFD_LOGLEVEL_ALL, &MockLogger_log, &MockLogger_onclose, logger.getUserData());
|
wfd_logger_init(WFD_LOGLEVEL_ALL, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
|
||||||
WFD_DEBUG("too bad");
|
WFD_DEBUG("too bad");
|
||||||
wfd_logger_close();
|
wfd_logger_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(log, respect_loglevel)
|
TEST(log, respect_loglevel)
|
||||||
{
|
{
|
||||||
MockLogger logger;
|
MockLogger logger(true);
|
||||||
|
|
||||||
EXPECT_CALL(logger, log(_, _, _)).Times(0);
|
EXPECT_CALL(logger, log(_, _, _)).Times(0);
|
||||||
EXPECT_CALL(logger, onclose()).Times(1);
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
wfd_logger_init(WFD_LOGLEVEL_WARN, &MockLogger_log, &MockLogger_onclose, logger.getUserData());
|
wfd_logger_init(WFD_LOGLEVEL_WARN, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
|
||||||
WFD_DEBUG("too bad");
|
WFD_DEBUG("too bad");
|
||||||
wfd_logger_close();
|
wfd_logger_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(log, log_same_loglevel)
|
TEST(log, log_same_loglevel)
|
||||||
{
|
{
|
||||||
MockLogger logger;
|
MockLogger logger(true);
|
||||||
|
|
||||||
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
|
||||||
EXPECT_CALL(logger, onclose()).Times(1);
|
EXPECT_CALL(logger, onclose()).Times(1);
|
||||||
|
|
||||||
wfd_logger_init(WFD_LOGLEVEL_WARN, &MockLogger_log, &MockLogger_onclose, logger.getUserData());
|
wfd_logger_init(WFD_LOGLEVEL_WARN, &wfd_MockLogger_log, &wfd_MockLogger_onclose, logger.getUserData());
|
||||||
WFD_WARN("too bad");
|
WFD_WARN("too bad");
|
||||||
wfd_logger_close();
|
wfd_logger_close();
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(log, omit_onclose_if_nullptr)
|
TEST(log, omit_onclose_if_nullptr)
|
||||||
{
|
{
|
||||||
MockLogger logger;
|
MockLogger logger(true);
|
||||||
|
|
||||||
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
|
EXPECT_CALL(logger, log(WFD_LOGLEVEL_WARN, StrEq("too bad"), _)).Times(1);
|
||||||
EXPECT_CALL(logger, onclose()).Times(0);
|
EXPECT_CALL(logger, onclose()).Times(0);
|
||||||
|
|
||||||
wfd_logger_init(WFD_LOGLEVEL_WARN, &MockLogger_log, nullptr, logger.getUserData());
|
wfd_logger_init(WFD_LOGLEVEL_WARN, &wfd_MockLogger_log, nullptr, logger.getUserData());
|
||||||
WFD_WARN("too bad");
|
WFD_WARN("too bad");
|
||||||
wfd_logger_close();
|
wfd_logger_close();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user