rippled
Database_test.cpp
1 //------------------------------------------------------------------------------
2 /*
3  This file is part of rippled: https://github.com/ripple/rippled
4  Copyright (c) 2012, 2013 Ripple Labs Inc.
5 
6  Permission to use, copy, modify, and/or distribute this software for any
7  purpose with or without fee is hereby granted, provided that the above
8  copyright notice and this permission notice appear in all copies.
9 
10  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18 //==============================================================================
19 
20 #include <ripple/beast/utility/temp_dir.h>
21 #include <ripple/nodestore/DummyScheduler.h>
22 #include <ripple/nodestore/Manager.h>
23 #include <test/nodestore/TestBase.h>
24 #include <test/unit_test/SuiteJournal.h>
25 
26 namespace ripple {
27 namespace NodeStore {
28 
29 class Database_test : public TestBase
30 {
32 
33 public:
34  Database_test() : journal_("Database_test", *this)
35  {
36  }
37 
38  void
40  std::string const& destBackendType,
41  std::string const& srcBackendType,
42  std::int64_t seedValue)
43  {
44  DummyScheduler scheduler;
45  RootStoppable parent("TestRootStoppable");
46 
47  beast::temp_dir node_db;
48  Section srcParams;
49  srcParams.set("type", srcBackendType);
50  srcParams.set("path", node_db.path());
51 
52  // Create a batch
53  auto batch = createPredictableBatch(numObjectsToTest, seedValue);
54 
55  // Write to source db
56  {
58  "test", scheduler, 2, parent, srcParams, journal_);
59  storeBatch(*src, batch);
60  }
61 
62  Batch copy;
63 
64  {
65  // Re-open the db
67  "test", scheduler, 2, parent, srcParams, journal_);
68 
69  // Set up the destination database
70  beast::temp_dir dest_db;
71  Section destParams;
72  destParams.set("type", destBackendType);
73  destParams.set("path", dest_db.path());
74 
76  "test", scheduler, 2, parent, destParams, journal_);
77 
78  testcase(
79  "import into '" + destBackendType + "' from '" +
80  srcBackendType + "'");
81 
82  // Do the import
83  dest->import(*src);
84 
85  // Get the results of the import
86  fetchCopyOfBatch(*dest, &copy, batch);
87  }
88 
89  // Canonicalize the source and destination batches
90  std::sort(batch.begin(), batch.end(), LessThan{});
91  std::sort(copy.begin(), copy.end(), LessThan{});
92  BEAST_EXPECT(areBatchesEqual(batch, copy));
93  }
94 
95  //--------------------------------------------------------------------------
96 
97  void
99  std::string const& type,
100  bool const testPersistence,
101  std::int64_t const seedValue,
102  int numObjsToTest = 2000)
103  {
104  DummyScheduler scheduler;
105  RootStoppable parent("TestRootStoppable");
106 
107  std::string s = "NodeStore backend '" + type + "'";
108 
109  testcase(s);
110 
111  beast::temp_dir node_db;
112  Section nodeParams;
113  nodeParams.set("type", type);
114  nodeParams.set("path", node_db.path());
115 
116  beast::xor_shift_engine rng(seedValue);
117 
118  // Create a batch
119  auto batch = createPredictableBatch(numObjsToTest, rng());
120 
121  {
122  // Open the database
124  "test", scheduler, 2, parent, nodeParams, journal_);
125 
126  // Write the batch
127  storeBatch(*db, batch);
128 
129  {
130  // Read it back in
131  Batch copy;
132  fetchCopyOfBatch(*db, &copy, batch);
133  BEAST_EXPECT(areBatchesEqual(batch, copy));
134  }
135 
136  {
137  // Reorder and read the copy again
138  std::shuffle(batch.begin(), batch.end(), rng);
139  Batch copy;
140  fetchCopyOfBatch(*db, &copy, batch);
141  BEAST_EXPECT(areBatchesEqual(batch, copy));
142  }
143  }
144 
145  if (testPersistence)
146  {
147  // Re-open the database without the ephemeral DB
149  "test", scheduler, 2, parent, nodeParams, journal_);
150 
151  // Read it back in
152  Batch copy;
153  fetchCopyOfBatch(*db, &copy, batch);
154 
155  // Canonicalize the source and destination batches
156  std::sort(batch.begin(), batch.end(), LessThan{});
157  std::sort(copy.begin(), copy.end(), LessThan{});
158  BEAST_EXPECT(areBatchesEqual(batch, copy));
159  }
160 
161  if (type == "memory")
162  {
163  // Earliest ledger sequence tests
164  {
165  // Verify default earliest ledger sequence
168  "test", scheduler, 2, parent, nodeParams, journal_);
169  BEAST_EXPECT(
170  db->earliestLedgerSeq() == XRP_LEDGER_EARLIEST_SEQ);
171  }
172 
173  // Set an invalid earliest ledger sequence
174  try
175  {
176  nodeParams.set("earliest_seq", "0");
179  "test", scheduler, 2, parent, nodeParams, journal_);
180  }
181  catch (std::runtime_error const& e)
182  {
183  BEAST_EXPECT(
184  std::strcmp(e.what(), "Invalid earliest_seq") == 0);
185  }
186 
187  {
188  // Set a valid earliest ledger sequence
189  nodeParams.set("earliest_seq", "1");
192  "test", scheduler, 2, parent, nodeParams, journal_);
193 
194  // Verify database uses the earliest ledger sequence setting
195  BEAST_EXPECT(db->earliestLedgerSeq() == 1);
196  }
197 
198  // Create another database that attempts to set the value again
199  try
200  {
201  // Set to default earliest ledger sequence
202  nodeParams.set(
203  "earliest_seq", std::to_string(XRP_LEDGER_EARLIEST_SEQ));
206  "test", scheduler, 2, parent, nodeParams, journal_);
207  }
208  catch (std::runtime_error const& e)
209  {
210  BEAST_EXPECT(
211  std::strcmp(e.what(), "earliest_seq set more than once") ==
212  0);
213  }
214  }
215  }
216 
217  //--------------------------------------------------------------------------
218 
219  void
220  run() override
221  {
222  std::int64_t const seedValue = 50;
223 
224  testNodeStore("memory", false, seedValue);
225 
226  // Persistent backend tests
227  {
228  testNodeStore("nudb", true, seedValue);
229 
230 #if RIPPLE_ROCKSDB_AVAILABLE
231  testNodeStore("rocksdb", true, seedValue);
232 #endif
233  }
234 
235  // Import tests
236  {
237  testImport("nudb", "nudb", seedValue);
238 
239 #if RIPPLE_ROCKSDB_AVAILABLE
240  testImport("rocksdb", "rocksdb", seedValue);
241 #endif
242 
243 #if RIPPLE_ENABLE_SQLITE_BACKEND_TESTS
244  testImport("sqlite", "sqlite", seedValue);
245 #endif
246  }
247  }
248 };
249 
250 BEAST_DEFINE_TESTSUITE(Database, NodeStore, ripple);
251 
252 } // namespace NodeStore
253 } // namespace ripple
ripple::NodeStore::DummyScheduler
Simple NodeStore Scheduler that just peforms the tasks synchronously.
Definition: DummyScheduler.h:29
ripple::Section
Holds a collection of configuration values.
Definition: BasicConfig.h:43
std::strcmp
T strcmp(T... args)
ripple::NodeStore::TestBase
Definition: TestBase.h:68
std::string
STL class.
ripple::NodeStore::Database_test::Database_test
Database_test()
Definition: Database_test.cpp:34
std::vector< std::shared_ptr< NodeObject > >
ripple::NodeStore::LessThan
Binary function that satisfies the strict-weak-ordering requirement.
Definition: TestBase.h:44
ripple::NodeStore::Database_test::testNodeStore
void testNodeStore(std::string const &type, bool const testPersistence, std::int64_t const seedValue, int numObjsToTest=2000)
Definition: Database_test.cpp:98
ripple::NodeStore::Database_test::testImport
void testImport(std::string const &destBackendType, std::string const &srcBackendType, std::int64_t seedValue)
Definition: Database_test.cpp:39
ripple::NodeStore::Database_test::run
void run() override
Definition: Database_test.cpp:220
std::sort
T sort(T... args)
ripple::NodeStore::TestBase::areBatchesEqual
static bool areBatchesEqual(Batch const &lhs, Batch const &rhs)
Definition: TestBase.h:122
ripple::NodeStore::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(Backend, ripple_core, ripple)
ripple::RootStoppable
Definition: Stoppable.h:352
ripple::NodeStore::TestBase::fetchCopyOfBatch
void fetchCopyOfBatch(Backend &backend, Batch *pCopy, Batch const &batch)
Definition: TestBase.h:157
std::to_string
T to_string(T... args)
std::runtime_error
STL class.
std::int64_t
ripple::test::SuiteJournal
Definition: SuiteJournal.h:88
beast::temp_dir::path
std::string path() const
Get the native path for the temporary directory.
Definition: temp_dir.h:66
ripple::NodeStore::TestBase::numObjectsToTest
static const int numObjectsToTest
Definition: TestBase.h:75
ripple::NodeStore::TestBase::createPredictableBatch
static Batch createPredictableBatch(int numObjects, std::uint64_t seed)
Definition: TestBase.h:80
ripple
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: RCLCensorshipDetector.h:29
ripple::NodeStore::Database_test::journal_
test::SuiteJournal journal_
Definition: Database_test.cpp:31
ripple::Section::set
void set(std::string const &key, std::string const &value)
Set a key/value pair.
Definition: BasicConfig.cpp:32
ripple::XRP_LEDGER_EARLIEST_SEQ
static constexpr std::uint32_t XRP_LEDGER_EARLIEST_SEQ
The XRP ledger network's earliest allowed sequence.
Definition: SystemParameters.h:60
beast::detail::xor_shift_engine
Definition: xor_shift_engine.h:32
ripple::NodeStore::TestBase::storeBatch
void storeBatch(Backend &backend, Batch const &batch)
Definition: TestBase.h:147
ripple::NodeStore::Manager::make_Database
virtual std::unique_ptr< Database > make_Database(std::string const &name, Scheduler &scheduler, int readThreads, Stoppable &parent, Section const &backendParameters, beast::Journal journal)=0
Construct a NodeStore database.
ripple::NodeStore::Manager::instance
static Manager & instance()
Returns the instance of the manager singleton.
Definition: ManagerImp.cpp:117
std::unique_ptr
STL class.
std::shuffle
T shuffle(T... args)
beast::temp_dir
RAII temporary directory.
Definition: temp_dir.h:33
std::runtime_error::what
T what(T... args)
ripple::NodeStore::Database_test
Definition: Database_test.cpp:29