xrpld
Loading...
Searching...
No Matches
tests/libxrpl/nodestore/Database.cpp
1#include <xrpl/nodestore/Database.h>
2
3#include <xrpl/basics/ByteUtilities.h>
4#include <xrpl/basics/FileUtilities.h>
5#include <xrpl/beast/utility/Journal.h>
6#include <xrpl/beast/xor_shift_engine.h>
7#include <xrpl/config/BasicConfig.h>
8#include <xrpl/nodestore/DummyScheduler.h>
9#include <xrpl/nodestore/Manager.h>
10#include <xrpl/nodestore/Types.h>
11#include <xrpl/protocol/SystemParameters.h>
12
13#include <gtest/gtest.h>
14#include <helpers/TestSink.h>
15#include <nodestore/TestBase.h>
16
17#include <algorithm>
18#include <memory>
19#include <stdexcept>
20#include <string>
21#include <vector>
22
23namespace xrpl::node_store {
24
25namespace {
26
27std::vector<std::string>
28allBackends()
29{
30#if XRPL_ROCKSDB_AVAILABLE
31 return {"memory", "nudb", "rocksdb"};
32#else
33 return {"memory", "nudb"};
34#endif
35}
36
37std::vector<std::string>
38persistentBackends()
39{
40 std::vector<std::string> types{"nudb"};
41#if XRPL_ROCKSDB_AVAILABLE
42 types.emplace_back("rocksdb");
43#endif
44 return types;
45}
46
47std::vector<std::string>
48importBackends()
49{
50 std::vector<std::string> types{"nudb"};
51#if XRPL_ROCKSDB_AVAILABLE
52 types.emplace_back("rocksdb");
53#endif
54#ifdef XRPL_ENABLE_SQLITE_BACKEND_TESTS
55 types.emplace_back("sqlite");
56#endif
57 return types;
58}
59
60} // namespace
61
62// Shared setup for the parameterized Database tests: builds the node params,
63// journal and a predictable batch per test, mirroring Backend.cpp's fixture.
64class NodeStoreDatabaseTestBase : public ::testing::TestWithParam<std::string>
65{
66protected:
67 void
68 SetUp() override
69 {
70 nodeParams_.set("type", GetParam());
71 nodeParams_.set("path", nodeDb_.path());
72
75 }
76
82
88};
89
93
97
99{
100 auto db = makeDatabase();
101
102 storeBatch(*db, batch_);
103
104 {
105 SCOPED_TRACE("read in original order");
106 auto const copy = fetchCopyOfBatch(*db, batch_);
107 EXPECT_EQ(batch_, copy);
108 }
109
110 {
111 SCOPED_TRACE("read in shuffled order");
113 std::shuffle(batch_.begin(), batch_.end(), rng);
114 auto const copy = fetchCopyOfBatch(*db, batch_);
115 EXPECT_EQ(batch_, copy);
116 }
117}
118
120{
121 {
122 auto db = makeDatabase();
123 storeBatch(*db, batch_);
124 }
125
126 // re-open without the ephemeral db
127 auto db = makeDatabase();
128
129 auto copy = fetchCopyOfBatch(*db, batch_);
130 std::ranges::sort(batch_, LessThan{});
132 EXPECT_EQ(batch_, copy);
133}
134
135// missing-key path at the Database layer. Mirrors Backend's fetch_missing —
136// fetching keys that were never stored must return nullptr (NotFound).
138{
139 auto db = makeDatabase();
140
141 // never store: every key must be absent
142 fetchMissing(*db, batch_);
143}
144
146 NodeStoreBackends,
148 ::testing::ValuesIn(allBackends()),
149 [](::testing::TestParamInfo<std::string> const& info) { return info.param; });
150
152 PersistentBackends,
154 ::testing::ValuesIn(persistentBackends()),
155 [](::testing::TestParamInfo<std::string> const& info) { return info.param; });
156
157TEST(NodeStoreDatabase, memory_earliest_seq)
158{
159 DummyScheduler scheduler;
160 TempDir const nodeDb;
161 Section nodeParams;
162 nodeParams.set("type", "memory");
163 nodeParams.set("path", nodeDb.path());
164
165 beast::Journal const journal(TestSink::instance());
166
167 // default earliest ledger sequence
168 {
169 auto db = Manager::instance().makeDatabase(megabytes(4), scheduler, 2, nodeParams, journal);
170 EXPECT_EQ(db->earliestLedgerSeq(), kXrpLedgerEarliestSeq);
171 }
172
173 // invalid earliest_seq value
174 {
175 nodeParams.set("earliest_seq", "0");
176 try
177 {
178 auto db =
179 Manager::instance().makeDatabase(megabytes(4), scheduler, 2, nodeParams, journal);
180 FAIL() << "expected runtime_error for earliest_seq=0";
181 }
182 catch (std::runtime_error const& e)
183 {
184 EXPECT_STREQ(e.what(), "Invalid earliest_seq");
185 }
186 }
187
188 // valid earliest_seq value
189 {
190 nodeParams.set("earliest_seq", "1");
191 auto db = Manager::instance().makeDatabase(megabytes(4), scheduler, 2, nodeParams, journal);
192 EXPECT_EQ(db->earliestLedgerSeq(), 1u);
193 }
194}
195
196class DatabaseImportTest : public ::testing::TestWithParam<std::string>
197{
198};
199
201{
202 auto const type = GetParam();
203
204 DummyScheduler scheduler;
205 beast::Journal const journal(TestSink::instance());
206
207 TempDir const srcDir;
208 Section srcParams;
209 srcParams.set("type", type);
210 srcParams.set("path", srcDir.path());
211
213
214 // write to source db
215 {
216 auto src = Manager::instance().makeDatabase(megabytes(4), scheduler, 2, srcParams, journal);
217 storeBatch(*src, batch);
218 }
219
220 Batch copy;
221 {
222 // re-open source and import into a fresh destination
223 auto src = Manager::instance().makeDatabase(megabytes(4), scheduler, 2, srcParams, journal);
224
225 TempDir const destDir;
226 Section destParams;
227 destParams.set("type", type);
228 destParams.set("path", destDir.path());
229
230 auto dest =
231 Manager::instance().makeDatabase(megabytes(4), scheduler, 2, destParams, journal);
232
233 dest->importDatabase(*src);
234 copy = fetchCopyOfBatch(*dest, batch);
235 }
236
237 std::ranges::sort(batch, LessThan{});
239 EXPECT_EQ(batch, copy);
240}
241
243 ImportBackends,
245 ::testing::ValuesIn(importBackends()),
246 [](::testing::TestParamInfo<std::string> const& info) { return info.param; });
247
248} // namespace xrpl::node_store
A generic endpoint for log messages.
Definition Journal.h:44
Holds a collection of configuration values.
Definition BasicConfig.h:29
void set(std::string const &key, std::string const &value)
Set a key/value pair.
RAII temporary directory.
std::string path() const
Get the native path for the temporary directory.
static TestSink & instance()
Definition TestSink.h:12
Simple NodeStore Scheduler that just performs the tasks synchronously.
virtual std::unique_ptr< Database > makeDatabase(std::size_t burstSize, Scheduler &scheduler, int readThreads, Section const &backendParameters, beast::Journal journal)=0
Construct a NodeStore database.
static Manager & instance()
Returns the instance of the manager singleton.
T emplace_back(T... args)
detail::XorShiftEngine<> xor_shift_engine
XOR-shift Generator.
constexpr std::uint64_t kSeedValue
Definition TestBase.h:28
TEST_P(BackendTypeTest, store_and_fetch)
INSTANTIATE_TEST_SUITE_P(BackendTypes, BackendTypeTest, ::testing::ValuesIn(backendTypes()), [](::testing::TestParamInfo< std::string > const &info) { return info.param;})
TEST(NodeStoreBasics, predictable_batches)
Definition Basics.cpp:14
std::vector< std::shared_ptr< NodeObject > > Batch
A batch of NodeObjects to write at once.
Batch createPredictableBatch(std::size_t numObjects, std::uint64_t seed)
Definition TestBase.h:48
constexpr int kNumObjects
Definition TestBase.h:27
void storeBatch(Backend &backend, Batch const &batch)
Definition TestBase.h:85
void fetchMissing(Backend &backend, Batch const &batch)
Definition TestBase.h:113
Batch fetchCopyOfBatch(Backend &backend, Batch const &batch)
Definition TestBase.h:92
constexpr auto megabytes(T value) noexcept
static constexpr std::uint32_t kXrpLedgerEarliestSeq
The XRP ledger network's earliest allowed sequence.
T shuffle(T... args)
T sort(T... args)
T what(T... args)