mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
Improve online_delete configuration and DB tuning:
* Document delete_batch, back_off_milliseconds, age_threshold_seconds. * Convert those time values to chrono types. * Fix bug that ignored age_threshold_seconds. * Add a "recovery buffer" to the config that gives the node a chance to recover before aborting online delete. * Add begin/end log messages around the SQL queries. * Add a new configuration section: [sqlite] to allow tuning the sqlite database operations. Ignored on full/large history servers. * Update documentation of [node_db] and [sqlite] in the rippled-example.cfg file. Resolves #3321
This commit is contained in:
committed by
Nik Bougalis
parent
00702f28c2
commit
4702c8b591
@@ -27,6 +27,7 @@
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/CheckMessageLogs.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
@@ -34,56 +35,6 @@ namespace test {
|
||||
class LedgerHistory_test : public beast::unit_test::suite
|
||||
{
|
||||
public:
|
||||
/** Log manager that searches for a specific message substring
|
||||
*/
|
||||
class CheckMessageLogs : public Logs
|
||||
{
|
||||
std::string msg_;
|
||||
bool& found_;
|
||||
|
||||
class CheckMessageSink : public beast::Journal::Sink
|
||||
{
|
||||
CheckMessageLogs& owner_;
|
||||
|
||||
public:
|
||||
CheckMessageSink(
|
||||
beast::severities::Severity threshold,
|
||||
CheckMessageLogs& owner)
|
||||
: beast::Journal::Sink(threshold, false), owner_(owner)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override
|
||||
{
|
||||
if (text.find(owner_.msg_) != std::string::npos)
|
||||
owner_.found_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
|
||||
@param msg The message string to search for
|
||||
@param found The variable to set to true if the message is found
|
||||
*/
|
||||
CheckMessageLogs(std::string msg, bool& found)
|
||||
: Logs{beast::severities::kDebug}
|
||||
, msg_{std::move(msg)}
|
||||
, found_{found}
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<beast::Journal::Sink>
|
||||
makeSink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity threshold) override
|
||||
{
|
||||
return std::make_unique<CheckMessageSink>(threshold, *this);
|
||||
}
|
||||
};
|
||||
|
||||
/** Generate a new ledger by hand, applying a specific close time offset
|
||||
and optionally inserting a transaction.
|
||||
|
||||
@@ -149,7 +100,7 @@ public:
|
||||
Env env{
|
||||
*this,
|
||||
envconfig(),
|
||||
std::make_unique<CheckMessageLogs>("MISMATCH ", found)};
|
||||
std::make_unique<CheckMessageLogs>("MISMATCH ", &found)};
|
||||
LedgerHistory lh{beast::insight::NullCollector::New(), env.app()};
|
||||
auto const genesis = makeLedger({}, env, lh, 0s);
|
||||
uint256 const dummyTxHash{1};
|
||||
@@ -166,7 +117,7 @@ public:
|
||||
*this,
|
||||
envconfig(),
|
||||
std::make_unique<CheckMessageLogs>(
|
||||
"MISMATCH on close time", found)};
|
||||
"MISMATCH on close time", &found)};
|
||||
LedgerHistory lh{beast::insight::NullCollector::New(), env.app()};
|
||||
auto const genesis = makeLedger({}, env, lh, 0s);
|
||||
auto const ledgerA = makeLedger(genesis, env, lh, 4s);
|
||||
@@ -186,7 +137,7 @@ public:
|
||||
*this,
|
||||
envconfig(),
|
||||
std::make_unique<CheckMessageLogs>(
|
||||
"MISMATCH on prior ledger", found)};
|
||||
"MISMATCH on prior ledger", &found)};
|
||||
LedgerHistory lh{beast::insight::NullCollector::New(), env.app()};
|
||||
auto const genesis = makeLedger({}, env, lh, 0s);
|
||||
auto const ledgerA = makeLedger(genesis, env, lh, 4s);
|
||||
@@ -212,7 +163,7 @@ public:
|
||||
Env env{
|
||||
*this,
|
||||
envconfig(),
|
||||
std::make_unique<CheckMessageLogs>(msg, found)};
|
||||
std::make_unique<CheckMessageLogs>(msg, &found)};
|
||||
LedgerHistory lh{beast::insight::NullCollector::New(), env.app()};
|
||||
|
||||
Account alice{"A1"};
|
||||
|
||||
@@ -256,6 +256,7 @@ public:
|
||||
{
|
||||
DatabaseCon::Setup setup;
|
||||
setup.dataDir = getDatabasePath();
|
||||
BEAST_EXPECT(!setup.useGlobalPragma);
|
||||
DatabaseCon dbCon(
|
||||
setup,
|
||||
dbName.data(),
|
||||
|
||||
80
src/test/jtx/CaptureLogs.h
Normal file
80
src/test/jtx/CaptureLogs.h
Normal file
@@ -0,0 +1,80 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2020 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
/**
|
||||
* @brief Log manager for CaptureSinks. This class holds the stream
|
||||
* instance that is written to by the sinks. Upon destruction, all
|
||||
* contents of the stream are assigned to the string specified in the
|
||||
* ctor
|
||||
*/
|
||||
class CaptureLogs : public Logs
|
||||
{
|
||||
std::stringstream strm_;
|
||||
std::string* pResult_;
|
||||
|
||||
/**
|
||||
* @brief sink for writing all log messages to a stringstream
|
||||
*/
|
||||
class CaptureSink : public beast::Journal::Sink
|
||||
{
|
||||
std::stringstream& strm_;
|
||||
|
||||
public:
|
||||
CaptureSink(
|
||||
beast::severities::Severity threshold,
|
||||
std::stringstream& strm)
|
||||
: beast::Journal::Sink(threshold, false), strm_(strm)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override
|
||||
{
|
||||
strm_ << text;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
explicit CaptureLogs(std::string* pResult)
|
||||
: Logs(beast::severities::kInfo), pResult_(pResult)
|
||||
{
|
||||
}
|
||||
|
||||
~CaptureLogs() override
|
||||
{
|
||||
*pResult_ = strm_.str();
|
||||
}
|
||||
|
||||
std::unique_ptr<beast::Journal::Sink>
|
||||
makeSink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity threshold) override
|
||||
{
|
||||
return std::make_unique<CaptureSink>(threshold, strm_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
75
src/test/jtx/CheckMessageLogs.h
Normal file
75
src/test/jtx/CheckMessageLogs.h
Normal file
@@ -0,0 +1,75 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2020 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or 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.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/basics/Log.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace test {
|
||||
|
||||
/** Log manager that searches for a specific message substring
|
||||
*/
|
||||
class CheckMessageLogs : public Logs
|
||||
{
|
||||
std::string msg_;
|
||||
bool* pFound_;
|
||||
|
||||
class CheckMessageSink : public beast::Journal::Sink
|
||||
{
|
||||
CheckMessageLogs& owner_;
|
||||
|
||||
public:
|
||||
CheckMessageSink(
|
||||
beast::severities::Severity threshold,
|
||||
CheckMessageLogs& owner)
|
||||
: beast::Journal::Sink(threshold, false), owner_(owner)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override
|
||||
{
|
||||
if (text.find(owner_.msg_) != std::string::npos)
|
||||
*owner_.pFound_ = true;
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
/** Constructor
|
||||
|
||||
@param msg The message string to search for
|
||||
@param pFound Pointer to the variable to set to true if the message is
|
||||
found
|
||||
*/
|
||||
CheckMessageLogs(std::string msg, bool* pFound)
|
||||
: Logs{beast::severities::kDebug}, msg_{std::move(msg)}, pFound_{pFound}
|
||||
{
|
||||
}
|
||||
|
||||
std::unique_ptr<beast::Journal::Sink>
|
||||
makeSink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity threshold) override
|
||||
{
|
||||
return std::make_unique<CheckMessageSink>(threshold, *this);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace test
|
||||
} // namespace ripple
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <ripple/basics/Log.h>
|
||||
#include <ripple/basics/chrono.h>
|
||||
#include <ripple/beast/cxx17/type_traits.h> // <type_traits>
|
||||
#include <ripple/beast/utility/Journal.h>
|
||||
#include <ripple/core/Config.h>
|
||||
#include <ripple/json/json_value.h>
|
||||
#include <ripple/json/to_string.h>
|
||||
@@ -131,7 +132,8 @@ private:
|
||||
AppBundle(
|
||||
beast::unit_test::suite& suite,
|
||||
std::unique_ptr<Config> config,
|
||||
std::unique_ptr<Logs> logs);
|
||||
std::unique_ptr<Logs> logs,
|
||||
beast::severities::Severity thresh);
|
||||
~AppBundle();
|
||||
};
|
||||
|
||||
@@ -163,12 +165,10 @@ public:
|
||||
Env(beast::unit_test::suite& suite_,
|
||||
std::unique_ptr<Config> config,
|
||||
FeatureBitset features,
|
||||
std::unique_ptr<Logs> logs = nullptr)
|
||||
std::unique_ptr<Logs> logs = nullptr,
|
||||
beast::severities::Severity thresh = beast::severities::kError)
|
||||
: test(suite_)
|
||||
, bundle_(
|
||||
suite_,
|
||||
std::move(config),
|
||||
logs ? std::move(logs) : std::make_unique<SuiteLogs>(suite_))
|
||||
, bundle_(suite_, std::move(config), std::move(logs), thresh)
|
||||
, journal{bundle_.app->journal("Env")}
|
||||
{
|
||||
memoize(Account::master);
|
||||
@@ -211,11 +211,13 @@ public:
|
||||
*/
|
||||
Env(beast::unit_test::suite& suite_,
|
||||
std::unique_ptr<Config> config,
|
||||
std::unique_ptr<Logs> logs = nullptr)
|
||||
std::unique_ptr<Logs> logs = nullptr,
|
||||
beast::severities::Severity thresh = beast::severities::kError)
|
||||
: Env(suite_,
|
||||
std::move(config),
|
||||
supported_amendments(),
|
||||
std::move(logs))
|
||||
std::move(logs),
|
||||
thresh)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -59,12 +59,22 @@ namespace jtx {
|
||||
Env::AppBundle::AppBundle(
|
||||
beast::unit_test::suite& suite,
|
||||
std::unique_ptr<Config> config,
|
||||
std::unique_ptr<Logs> logs)
|
||||
std::unique_ptr<Logs> logs,
|
||||
beast::severities::Severity thresh)
|
||||
: AppBundle()
|
||||
{
|
||||
using namespace beast::severities;
|
||||
// Use kFatal threshold to reduce noise from STObject.
|
||||
setDebugLogSink(std::make_unique<SuiteJournalSink>("Debug", kFatal, suite));
|
||||
if (logs)
|
||||
{
|
||||
setDebugLogSink(logs->makeSink("Debug", kFatal));
|
||||
}
|
||||
else
|
||||
{
|
||||
logs = std::make_unique<SuiteLogs>(suite);
|
||||
// Use kFatal threshold to reduce noise from STObject.
|
||||
setDebugLogSink(
|
||||
std::make_unique<SuiteJournalSink>("Debug", kFatal, suite));
|
||||
}
|
||||
auto timeKeeper_ = std::make_unique<ManualTimeKeeper>();
|
||||
timeKeeper = timeKeeper_.get();
|
||||
// Hack so we don't have to call Config::setup
|
||||
@@ -72,7 +82,7 @@ Env::AppBundle::AppBundle(
|
||||
owned = make_Application(
|
||||
std::move(config), std::move(logs), std::move(timeKeeper_));
|
||||
app = owned.get();
|
||||
app->logs().threshold(kError);
|
||||
app->logs().threshold(thresh);
|
||||
if (!app->setup())
|
||||
Throw<std::runtime_error>("Env::AppBundle: setup failed");
|
||||
timeKeeper->set(app->getLedgerMaster().getClosedLedger()->info().closeTime);
|
||||
|
||||
@@ -18,8 +18,12 @@
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/beast/utility/temp_dir.h>
|
||||
#include <ripple/core/DatabaseCon.h>
|
||||
#include <ripple/nodestore/DummyScheduler.h>
|
||||
#include <ripple/nodestore/Manager.h>
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/CheckMessageLogs.h>
|
||||
#include <test/jtx/envconfig.h>
|
||||
#include <test/nodestore/TestBase.h>
|
||||
#include <test/unit_test/SuiteJournal.h>
|
||||
|
||||
@@ -35,6 +39,409 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
testConfig()
|
||||
{
|
||||
testcase("Config");
|
||||
|
||||
using namespace ripple::test;
|
||||
using namespace ripple::test::jtx;
|
||||
|
||||
auto const integrityWarning =
|
||||
"reducing the data integrity guarantees from the "
|
||||
"default [sqlite] behavior is not recommended for "
|
||||
"nodes storing large amounts of history, because of the "
|
||||
"difficulty inherent in rebuilding corrupted data.";
|
||||
{
|
||||
// defaults
|
||||
Env env(*this);
|
||||
|
||||
auto const s = setup_DatabaseCon(env.app().config());
|
||||
|
||||
if (BEAST_EXPECT(s.globalPragma->size() == 3))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(0) == "PRAGMA journal_mode=wal;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(1) == "PRAGMA synchronous=normal;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(2) == "PRAGMA temp_store=file;");
|
||||
}
|
||||
}
|
||||
{
|
||||
// High safety level
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
|
||||
bool found = false;
|
||||
Env env = [&]() {
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("safety_level", "high");
|
||||
}
|
||||
p->LEDGER_HISTORY = 100'000'000;
|
||||
|
||||
return Env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(
|
||||
integrityWarning, &found),
|
||||
beast::severities::kWarning);
|
||||
}();
|
||||
|
||||
BEAST_EXPECT(!found);
|
||||
auto const s = setup_DatabaseCon(env.app().config());
|
||||
if (BEAST_EXPECT(s.globalPragma->size() == 3))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(0) == "PRAGMA journal_mode=wal;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(1) == "PRAGMA synchronous=normal;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(2) == "PRAGMA temp_store=file;");
|
||||
}
|
||||
}
|
||||
{
|
||||
// Low safety level
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
|
||||
bool found = false;
|
||||
Env env = [&]() {
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("safety_level", "low");
|
||||
}
|
||||
p->LEDGER_HISTORY = 100'000'000;
|
||||
|
||||
return Env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(
|
||||
integrityWarning, &found),
|
||||
beast::severities::kWarning);
|
||||
}();
|
||||
|
||||
BEAST_EXPECT(found);
|
||||
auto const s = setup_DatabaseCon(env.app().config());
|
||||
if (BEAST_EXPECT(s.globalPragma->size() == 3))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(0) == "PRAGMA journal_mode=memory;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(1) == "PRAGMA synchronous=off;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(2) == "PRAGMA temp_store=memory;");
|
||||
}
|
||||
}
|
||||
{
|
||||
// Override individual settings
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
|
||||
bool found = false;
|
||||
Env env = [&]() {
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("journal_mode", "off");
|
||||
section.set("synchronous", "extra");
|
||||
section.set("temp_store", "default");
|
||||
}
|
||||
|
||||
return Env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(
|
||||
integrityWarning, &found),
|
||||
beast::severities::kWarning);
|
||||
}();
|
||||
|
||||
// No warning, even though higher risk settings were used because
|
||||
// LEDGER_HISTORY is small
|
||||
BEAST_EXPECT(!found);
|
||||
auto const s = setup_DatabaseCon(env.app().config());
|
||||
if (BEAST_EXPECT(s.globalPragma->size() == 3))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(0) == "PRAGMA journal_mode=off;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(1) == "PRAGMA synchronous=extra;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(2) == "PRAGMA temp_store=default;");
|
||||
}
|
||||
}
|
||||
{
|
||||
// Override individual settings with large history
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
|
||||
bool found = false;
|
||||
Env env = [&]() {
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("journal_mode", "off");
|
||||
section.set("synchronous", "extra");
|
||||
section.set("temp_store", "default");
|
||||
}
|
||||
p->LEDGER_HISTORY = 50'000'000;
|
||||
|
||||
return Env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(
|
||||
integrityWarning, &found),
|
||||
beast::severities::kWarning);
|
||||
}();
|
||||
|
||||
// No warning, even though higher risk settings were used because
|
||||
// LEDGER_HISTORY is small
|
||||
BEAST_EXPECT(found);
|
||||
auto const s = setup_DatabaseCon(env.app().config());
|
||||
if (BEAST_EXPECT(s.globalPragma->size() == 3))
|
||||
{
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(0) == "PRAGMA journal_mode=off;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(1) == "PRAGMA synchronous=extra;");
|
||||
BEAST_EXPECT(
|
||||
s.globalPragma->at(2) == "PRAGMA temp_store=default;");
|
||||
}
|
||||
}
|
||||
{
|
||||
// Error: Mix safety_level and individual settings
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
auto const expected =
|
||||
"Failed to initialize SQLite databases: "
|
||||
"Configuration file may not define both \"safety_level\" and "
|
||||
"\"journal_mode\"";
|
||||
bool found = false;
|
||||
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("safety_level", "low");
|
||||
section.set("journal_mode", "off");
|
||||
section.set("synchronous", "extra");
|
||||
section.set("temp_store", "default");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Env env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(expected, &found),
|
||||
beast::severities::kWarning);
|
||||
fail();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BEAST_EXPECT(found);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Error: Mix safety_level and one setting (gotta catch 'em all)
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
auto const expected =
|
||||
"Failed to initialize SQLite databases: Configuration file may "
|
||||
"not define both \"safety_level\" and \"journal_mode\"";
|
||||
bool found = false;
|
||||
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("safety_level", "high");
|
||||
section.set("journal_mode", "off");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Env env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(expected, &found),
|
||||
beast::severities::kWarning);
|
||||
fail();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BEAST_EXPECT(found);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Error: Mix safety_level and one setting (gotta catch 'em all)
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
auto const expected =
|
||||
"Failed to initialize SQLite databases: Configuration file may "
|
||||
"not define both \"safety_level\" and \"synchronous\"";
|
||||
bool found = false;
|
||||
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("safety_level", "low");
|
||||
section.set("synchronous", "extra");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Env env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(expected, &found),
|
||||
beast::severities::kWarning);
|
||||
fail();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BEAST_EXPECT(found);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Error: Mix safety_level and one setting (gotta catch 'em all)
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
auto const expected =
|
||||
"Failed to initialize SQLite databases: Configuration file may "
|
||||
"not define both \"safety_level\" and \"temp_store\"";
|
||||
bool found = false;
|
||||
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("safety_level", "high");
|
||||
section.set("temp_store", "default");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Env env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(expected, &found),
|
||||
beast::severities::kWarning);
|
||||
fail();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BEAST_EXPECT(found);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Error: Invalid value
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
auto const expected =
|
||||
"Failed to initialize SQLite databases: Invalid safety_level "
|
||||
"value: slow";
|
||||
bool found = false;
|
||||
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("safety_level", "slow");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Env env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(expected, &found),
|
||||
beast::severities::kWarning);
|
||||
fail();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BEAST_EXPECT(found);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Error: Invalid value
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
auto const expected =
|
||||
"Failed to initialize SQLite databases: Invalid journal_mode "
|
||||
"value: fast";
|
||||
bool found = false;
|
||||
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("journal_mode", "fast");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Env env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(expected, &found),
|
||||
beast::severities::kWarning);
|
||||
fail();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BEAST_EXPECT(found);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Error: Invalid value
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
auto const expected =
|
||||
"Failed to initialize SQLite databases: Invalid synchronous "
|
||||
"value: instant";
|
||||
bool found = false;
|
||||
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("synchronous", "instant");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Env env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(expected, &found),
|
||||
beast::severities::kWarning);
|
||||
fail();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BEAST_EXPECT(found);
|
||||
}
|
||||
}
|
||||
{
|
||||
// Error: Invalid value
|
||||
DatabaseCon::Setup::globalPragma.reset();
|
||||
auto const expected =
|
||||
"Failed to initialize SQLite databases: Invalid temp_store "
|
||||
"value: network";
|
||||
bool found = false;
|
||||
|
||||
auto p = test::jtx::envconfig();
|
||||
{
|
||||
auto& section = p->section("sqlite");
|
||||
section.set("temp_store", "network");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Env env(
|
||||
*this,
|
||||
std::move(p),
|
||||
std::make_unique<CheckMessageLogs>(expected, &found),
|
||||
beast::severities::kWarning);
|
||||
fail();
|
||||
}
|
||||
catch (...)
|
||||
{
|
||||
BEAST_EXPECT(found);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
void
|
||||
testImport(
|
||||
std::string const& destBackendType,
|
||||
@@ -221,6 +628,8 @@ public:
|
||||
{
|
||||
std::int64_t const seedValue = 50;
|
||||
|
||||
testConfig();
|
||||
|
||||
testNodeStore("memory", false, seedValue);
|
||||
|
||||
// Persistent backend tests
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include <chrono>
|
||||
#include <stdexcept>
|
||||
#include <test/jtx.h>
|
||||
#include <test/jtx/CaptureLogs.h>
|
||||
#include <test/jtx/envconfig.h>
|
||||
#include <test/unit_test/SuiteJournal.h>
|
||||
#include <thread>
|
||||
@@ -375,60 +376,6 @@ public:
|
||||
pass();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief sink for writing all log messages to a stringstream
|
||||
*/
|
||||
class CaptureSink : public beast::Journal::Sink
|
||||
{
|
||||
std::stringstream& strm_;
|
||||
|
||||
public:
|
||||
CaptureSink(
|
||||
beast::severities::Severity threshold,
|
||||
std::stringstream& strm)
|
||||
: beast::Journal::Sink(threshold, false), strm_(strm)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override
|
||||
{
|
||||
strm_ << text;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Log manager for CaptureSinks. This class holds the stream
|
||||
* instance that is written to by the sinks. Upon destruction, all
|
||||
* contents of the stream are assigned to the string specified in the
|
||||
* ctor
|
||||
*/
|
||||
class CaptureLogs : public Logs
|
||||
{
|
||||
std::stringstream strm_;
|
||||
std::string& result_;
|
||||
|
||||
public:
|
||||
explicit CaptureLogs(std::string& result)
|
||||
: Logs(beast::severities::kInfo), result_(result)
|
||||
{
|
||||
}
|
||||
|
||||
~CaptureLogs() override
|
||||
{
|
||||
result_ = strm_.str();
|
||||
}
|
||||
|
||||
std::unique_ptr<beast::Journal::Sink>
|
||||
makeSink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity threshold) override
|
||||
{
|
||||
return std::make_unique<CaptureSink>(threshold, strm_);
|
||||
}
|
||||
};
|
||||
|
||||
void
|
||||
testBadConfig()
|
||||
{
|
||||
@@ -444,7 +391,7 @@ public:
|
||||
(*cfg).deprecatedClearSection("port_rpc");
|
||||
return cfg;
|
||||
}),
|
||||
std::make_unique<CaptureLogs>(messages)};
|
||||
std::make_unique<CaptureLogs>(&messages)};
|
||||
});
|
||||
BEAST_EXPECT(
|
||||
messages.find("Missing 'ip' in [port_rpc]") != std::string::npos);
|
||||
@@ -457,7 +404,7 @@ public:
|
||||
(*cfg)["port_rpc"].set("ip", getEnvLocalhostAddr());
|
||||
return cfg;
|
||||
}),
|
||||
std::make_unique<CaptureLogs>(messages)};
|
||||
std::make_unique<CaptureLogs>(&messages)};
|
||||
});
|
||||
BEAST_EXPECT(
|
||||
messages.find("Missing 'port' in [port_rpc]") != std::string::npos);
|
||||
@@ -471,7 +418,7 @@ public:
|
||||
(*cfg)["port_rpc"].set("port", "0");
|
||||
return cfg;
|
||||
}),
|
||||
std::make_unique<CaptureLogs>(messages)};
|
||||
std::make_unique<CaptureLogs>(&messages)};
|
||||
});
|
||||
BEAST_EXPECT(
|
||||
messages.find("Invalid value '0' for key 'port' in [port_rpc]") !=
|
||||
@@ -487,7 +434,7 @@ public:
|
||||
(*cfg)["port_rpc"].set("protocol", "");
|
||||
return cfg;
|
||||
}),
|
||||
std::make_unique<CaptureLogs>(messages)};
|
||||
std::make_unique<CaptureLogs>(&messages)};
|
||||
});
|
||||
BEAST_EXPECT(
|
||||
messages.find("Missing 'protocol' in [port_rpc]") !=
|
||||
@@ -522,7 +469,7 @@ public:
|
||||
(*cfg)["port_ws"].set("admin", getEnvLocalhostAddr());
|
||||
return cfg;
|
||||
}),
|
||||
std::make_unique<CaptureLogs>(messages)};
|
||||
std::make_unique<CaptureLogs>(&messages)};
|
||||
});
|
||||
BEAST_EXPECT(
|
||||
messages.find("Required section [server] is missing") !=
|
||||
@@ -548,7 +495,7 @@ public:
|
||||
(*cfg)["server"].append("port_ws");
|
||||
return cfg;
|
||||
}),
|
||||
std::make_unique<CaptureLogs>(messages)};
|
||||
std::make_unique<CaptureLogs>(&messages)};
|
||||
});
|
||||
BEAST_EXPECT(
|
||||
messages.find("Missing section: [port_peer]") != std::string::npos);
|
||||
|
||||
Reference in New Issue
Block a user