21#include <test/jtx/envconfig.h>
22#include <xrpld/app/main/Application.h>
23#include <xrpld/app/main/NodeStoreScheduler.h>
24#include <xrpld/app/misc/SHAMapStore.h>
25#include <xrpld/app/rdb/backend/SQLiteDatabase.h>
26#include <xrpld/core/ConfigSections.h>
27#include <xrpld/nodestore/detail/DatabaseRotatingImp.h>
28#include <xrpl/protocol/jss.h>
61 auto good =
json.isMember(jss::result) &&
63 json[jss::result][jss::ledger][jss::ledger_index] == ledgerID;
64 if (!good || !checkDB)
67 auto const seq =
json[jss::result][jss::ledger_index].asUInt();
89 auto const& ledger =
json[jss::result][jss::ledger];
90 return outHash == ledger[jss::ledger_hash].asString() &&
92 outParentHash == ledger[jss::parent_hash].asString() &&
93 outDrops == ledger[jss::total_coins].asString() &&
94 outCloseTime == ledger[jss::close_time].asUInt() &&
95 outParentCloseTime == ledger[jss::parent_close_time].asUInt() &&
96 outCloseTimeResolution ==
97 ledger[jss::close_time_resolution].asUInt() &&
98 outCloseFlags == ledger[jss::close_flags].asUInt() &&
99 outAccountHash == ledger[jss::account_hash].asString() &&
100 outTxHash == ledger[jss::transaction_hash].asString();
106 return json.isMember(jss::result) &&
108 json[jss::result][jss::error_code] == error;
115 json.isMember(jss::result) &&
116 json[jss::result].isMember(jss::ledger) &&
117 json[jss::result][jss::ledger].isMember(jss::ledger_hash) &&
118 json[jss::result][jss::ledger][jss::ledger_hash].isString());
119 return json[jss::result][jss::ledger][jss::ledger_hash].asString();
125 const auto [actualRows, actualFirst, actualLast] =
127 ->getLedgerCountMinMax();
129 BEAST_EXPECT(actualRows == rows);
130 BEAST_EXPECT(actualFirst == first);
131 BEAST_EXPECT(actualLast == first + rows - 1);
153 using namespace std::chrono_literals;
159 BEAST_EXPECT(!store.getLastRotated());
164 auto ledger = env.
rpc(
"ledger",
"validated");
167 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
175 using namespace std::chrono_literals;
191 auto ledgerTmp = env.
rpc(
"ledger",
"0");
192 BEAST_EXPECT(
bad(ledgerTmp));
195 BEAST_EXPECT(
goodLedger(env, ledgers[1],
"1"));
198 BEAST_EXPECT(
goodLedger(env, ledgers[2],
"2"));
200 ledgerTmp = env.
rpc(
"ledger",
"current");
201 BEAST_EXPECT(
goodLedger(env, ledgerTmp,
"3"));
203 ledgerTmp = env.
rpc(
"ledger",
"4");
204 BEAST_EXPECT(
bad(ledgerTmp));
206 ledgerTmp = env.
rpc(
"ledger",
"100");
207 BEAST_EXPECT(
bad(ledgerTmp));
210 auto lastRotated = firstSeq - 1;
217 ledgerTmp = env.
rpc(
"ledger",
"current");
220 BEAST_EXPECT(store.getLastRotated() == lastRotated);
239 auto ledger = env.
rpc(
"ledger",
"current");
247 lastRotated = store.getLastRotated();
248 BEAST_EXPECT(lastRotated == 11);
256 for (
auto i = lastRotated - 1; i < lastRotated +
deleteInterval - 1;
261 ledgerTmp = env.
rpc(
"ledger",
"current");
267 store.getLastRotated() == lastRotated ||
276 BEAST_EXPECT(store.getLastRotated() ==
deleteInterval + lastRotated);
286 testcase(
"automatic online_delete");
288 using namespace std::chrono_literals;
294 auto lastRotated = ledgerSeq - 1;
295 BEAST_EXPECT(store.getLastRotated() == lastRotated);
296 BEAST_EXPECT(lastRotated != 2);
300 auto const canDelete = env.
rpc(
"can_delete");
308 auto ledger = env.
rpc(
"ledger",
"validated");
318 BEAST_EXPECT(lastRotated == store.getLastRotated());
324 auto ledger = env.
rpc(
"ledger",
"validated");
331 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
332 BEAST_EXPECT(lastRotated != store.getLastRotated());
334 lastRotated = store.getLastRotated();
341 auto ledger = env.
rpc(
"ledger",
"validated");
349 BEAST_EXPECT(lastRotated != store.getLastRotated());
355 testcase(
"online_delete with advisory_delete");
357 using namespace std::chrono_literals;
364 auto lastRotated = ledgerSeq - 1;
365 BEAST_EXPECT(store.getLastRotated() == lastRotated);
366 BEAST_EXPECT(lastRotated != 2);
368 auto canDelete = env.
rpc(
"can_delete");
370 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == 0);
372 canDelete = env.
rpc(
"can_delete",
"never");
374 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == 0);
377 for (; ledgerSeq < firstBatch; ++ledgerSeq)
381 auto ledger = env.
rpc(
"ledger",
"validated");
389 BEAST_EXPECT(lastRotated == store.getLastRotated());
396 canDelete[jss::result][jss::can_delete] ==
402 BEAST_EXPECT(store.getLastRotated() == lastRotated);
408 auto ledger = env.
rpc(
"ledger",
"validated");
415 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
417 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
418 lastRotated = ledgerSeq - 1;
425 auto ledger = env.
rpc(
"ledger",
"validated");
432 BEAST_EXPECT(store.getLastRotated() == lastRotated);
438 auto ledger = env.
rpc(
"ledger",
"validated");
445 ledgerCheck(env, ledgerSeq - firstBatch, firstBatch);
447 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
448 lastRotated = ledgerSeq - 1;
451 canDelete = env.
rpc(
"can_delete",
"always");
454 canDelete[jss::result][jss::can_delete] ==
462 auto ledger = env.
rpc(
"ledger",
"validated");
469 BEAST_EXPECT(store.getLastRotated() == lastRotated);
475 auto ledger = env.
rpc(
"ledger",
"validated");
482 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
484 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
485 lastRotated = ledgerSeq - 1;
488 canDelete = env.
rpc(
"can_delete",
"now");
490 BEAST_EXPECT(canDelete[jss::result][jss::can_delete] == ledgerSeq - 1);
497 auto ledger = env.
rpc(
"ledger",
"validated");
504 BEAST_EXPECT(store.getLastRotated() == lastRotated);
510 auto ledger = env.
rpc(
"ledger",
"validated");
517 ledgerCheck(env, ledgerSeq - lastRotated, lastRotated);
519 BEAST_EXPECT(store.getLastRotated() == ledgerSeq - 1);
520 lastRotated = ledgerSeq - 1;
531 boost::filesystem::path newPath;
533 if (!BEAST_EXPECT(
path.size()))
536 section.set(
"path", newPath.string());
553 testcase(
"rotate with lock contention");
564 if (!nscfg.exists(
"cache_size"))
570 if (!nscfg.exists(
"cache_age"))
585 constexpr int readThreads = 4;
586 auto dbr = std::make_unique<NodeStore::DatabaseRotatingImp>(
589 std::move(writableBackend),
590 std::move(archiveBackend),
596 using namespace std::chrono_literals;
603 auto const cb = [&](
std::string const& writableName,
605 BEAST_EXPECT(writableName ==
"1");
606 BEAST_EXPECT(archiveName ==
"write");
609 BEAST_EXPECT(dbr->getName() ==
"1");
612 dbr->rotate(std::move(newBackend), cb);
614 BEAST_EXPECT(threadNum == 1);
615 BEAST_EXPECT(dbr->getName() ==
"1");
620 auto const cb = [&](
std::string const& writableName,
622 BEAST_EXPECT(writableName ==
"3");
623 BEAST_EXPECT(archiveName ==
"2");
626 BEAST_EXPECT(dbr->getName() ==
"3");
628 auto const cbReentrant = [&](
std::string const& writableName,
630 BEAST_EXPECT(writableName ==
"2");
631 BEAST_EXPECT(archiveName ==
"1");
635 dbr->rotate(std::move(newBackend), cb);
639 dbr->rotate(std::move(newBackend), cbReentrant);
642 BEAST_EXPECT(threadNum == 3);
643 BEAST_EXPECT(dbr->getName() ==
"3");
testcase_t testcase
Memberspace for declaring test cases.
virtual Config & config()=0
virtual SHAMapStore & getSHAMapStore()=0
virtual JobQueue & getJobQueue()=0
virtual RelationalDatabase & getRelationalDatabase()=0
Section & section(std::string const &name)
Returns the section with the given name.
int getValueFor(SizedItem item, std::optional< std::size_t > node=std::nullopt) const
Retrieve the default value for the item at the specified node size.
beast::Journal journal(std::string const &name)
A NodeStore::Scheduler which uses the JobQueue.
virtual std::unique_ptr< Backend > make_Backend(Section const ¶meters, std::size_t burstSize, Scheduler &scheduler, beast::Journal journal)=0
Create a backend.
static Manager & instance()
Returns the instance of the manager singleton.
virtual std::optional< LedgerInfo > getLedgerInfoByIndex(LedgerIndex ledgerSeq)=0
getLedgerInfoByIndex Returns a ledger by its sequence.
class to create database, launch online delete thread, and related SQLite database
virtual void rendezvous() const =0
virtual std::size_t getAccountTransactionCount()=0
getAccountTransactionCount Returns the number of account transactions.
virtual std::size_t getTransactionCount()=0
getTransactionCount Returns the number of transactions.
Holds a collection of configuration values.
void set(std::string const &key, std::string const &value)
Set a key/value pair.
void ledgerCheck(jtx::Env &env, int const rows, int const first)
std::string getHash(Json::Value const &json)
static auto advisoryDelete(std::unique_ptr< Config > cfg)
int waitForReady(jtx::Env &env)
bool bad(Json::Value const &json, error_code_i error=rpcLGR_NOT_FOUND)
void run() override
Runs the suite.
void accountTransactionCheck(jtx::Env &env, int const rows)
static auto onlineDelete(std::unique_ptr< Config > cfg)
std::unique_ptr< NodeStore::Backend > makeBackendRotating(jtx::Env &env, NodeStoreScheduler &scheduler, std::string path)
void transactionCheck(jtx::Env &env, int const rows)
static auto const deleteInterval
bool goodLedger(jtx::Env &env, Json::Value const &json, std::string ledgerID, bool checkDB=false)
A transaction testing environment.
bool close(NetClock::time_point closeTime, std::optional< std::chrono::milliseconds > consensusDelay=std::nullopt)
Close and advance the ledger.
Json::Value rpc(unsigned apiVersion, std::unordered_map< std::string, std::string > const &headers, std::string const &cmd, Args &&... args)
Execute an RPC command.
void fund(bool setDefaultRipple, STAmount const &amount, Account const &account)
bool contains_error(Json::Value const &json)
Returns true if the json contains an rpc error specification.
std::unique_ptr< Config > envconfig()
creates and initializes a default configuration for jtx::Env
XRP_t const XRP
Converts to XRP Issue or STAmount.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
constexpr auto megabytes(T value) noexcept
std::string to_string(base_uint< Bits, Tag > const &a)
static std::string nodeDatabase()
Set the sequence number on a JTx.
T time_since_epoch(T... args)