rippled
Loading...
Searching...
No Matches
SociDB_test.cpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of rippled: https://github.com/ripple/rippled
4 Copyright (c) 2012-2015 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 <test/jtx/TestSuite.h>
21#include <xrpld/core/ConfigSections.h>
22#include <xrpld/core/SociDB.h>
23#include <xrpl/basics/BasicConfig.h>
24#include <xrpl/basics/contract.h>
25#include <boost/algorithm/string.hpp>
26#include <boost/filesystem.hpp>
27
28namespace ripple {
29class SociDB_test final : public TestSuite
30{
31private:
32 static void
34 BasicConfig& config,
35 boost::filesystem::path const& dbPath)
36 {
37 config.overwrite("sqdb", "backend", "sqlite");
38 auto value = dbPath.string();
39 if (!value.empty())
40 config.legacy("database_path", value);
41 }
42
43 static void
44 cleanupDatabaseDir(boost::filesystem::path const& dbPath)
45 {
46 using namespace boost::filesystem;
47 if (!exists(dbPath) || !is_directory(dbPath) || !is_empty(dbPath))
48 return;
49 remove(dbPath);
50 }
51
52 static void
53 setupDatabaseDir(boost::filesystem::path const& dbPath)
54 {
55 using namespace boost::filesystem;
56 if (!exists(dbPath))
57 {
58 create_directory(dbPath);
59 return;
60 }
61
62 if (!is_directory(dbPath))
63 {
64 // someone created a file where we want to put out directory
65 Throw<std::runtime_error>(
66 "Cannot create directory: " + dbPath.string());
67 }
68 }
69 static boost::filesystem::path
71 {
72 return boost::filesystem::current_path() / "socidb_test_databases";
73 }
74
75public:
77 {
78 try
79 {
81 }
82 catch (std::exception const&)
83 {
84 }
85 }
87 {
88 try
89 {
91 }
92 catch (std::exception const&)
93 {
94 }
95 }
96 void
98 {
99 // confirm that files are given the correct exensions
100 testcase("sqliteFileNames");
101 BasicConfig c;
104 {{"peerfinder", ".sqlite"},
105 {"state", ".db"},
106 {"random", ".db"},
107 {"validators", ".sqlite"}});
108
109 for (auto const& i : d)
110 {
111 DBConfig sc(c, i.first);
112 BEAST_EXPECT(
113 boost::ends_with(sc.connectionString(), i.first + i.second));
114 }
115 }
116 void
118 {
119 testcase("open");
120 BasicConfig c;
122 DBConfig sc(c, "SociTestDB");
123 std::vector<std::string> const stringData(
124 {"String1", "String2", "String3"});
125 std::vector<int> const intData({1, 2, 3});
126 auto checkValues = [this, &stringData, &intData](soci::session& s) {
127 // Check values in db
128 std::vector<std::string> stringResult(20 * stringData.size());
129 std::vector<int> intResult(20 * intData.size());
130 s << "SELECT StringData, IntData FROM SociTestTable;",
131 soci::into(stringResult), soci::into(intResult);
132 BEAST_EXPECT(
133 stringResult.size() == stringData.size() &&
134 intResult.size() == intData.size());
135 for (int i = 0; i < stringResult.size(); ++i)
136 {
137 auto si = std::distance(
138 stringData.begin(),
139 std::find(
140 stringData.begin(), stringData.end(), stringResult[i]));
141 auto ii = std::distance(
142 intData.begin(),
143 std::find(intData.begin(), intData.end(), intResult[i]));
144 BEAST_EXPECT(si == ii && si < stringResult.size());
145 }
146 };
147
148 {
149 soci::session s;
150 sc.open(s);
151 s << "CREATE TABLE IF NOT EXISTS SociTestTable ("
152 " Key INTEGER PRIMARY KEY,"
153 " StringData TEXT,"
154 " IntData INTEGER"
155 ");";
156
157 s << "INSERT INTO SociTestTable (StringData, IntData) VALUES "
158 "(:stringData, :intData);",
159 soci::use(stringData), soci::use(intData);
160 checkValues(s);
161 }
162 {
163 // Check values in db after session was closed
164 soci::session s;
165 sc.open(s);
166 checkValues(s);
167 }
168 {
169 namespace bfs = boost::filesystem;
170 // Remove the database
171 bfs::path dbPath(sc.connectionString());
172 if (bfs::is_regular_file(dbPath))
173 bfs::remove(dbPath);
174 }
175 }
176
177 void
179 {
180 testcase("select");
181 BasicConfig c;
183 DBConfig sc(c, "SociTestDB");
186 std::vector<std::int64_t> const bid({-10, -20, -30});
189 std::vector<std::int32_t> const id({-1, -2, -3});
190
191 {
192 soci::session s;
193 sc.open(s);
194
195 s << "DROP TABLE IF EXISTS STT;";
196
197 s << "CREATE TABLE STT ("
198 " I INTEGER,"
199 " UI INTEGER UNSIGNED,"
200 " BI BIGINT,"
201 " UBI BIGINT UNSIGNED"
202 ");";
203
204 s << "INSERT INTO STT (I, UI, BI, UBI) VALUES "
205 "(:id, :idu, :bid, :bidu);",
206 soci::use(id), soci::use(uid), soci::use(bid), soci::use(ubid);
207
208 try
209 {
210 std::int32_t ig = 0;
211 std::uint32_t uig = 0;
212 std::int64_t big = 0;
213 std::uint64_t ubig = 0;
214 s << "SELECT I, UI, BI, UBI from STT;", soci::into(ig),
215 soci::into(uig), soci::into(big), soci::into(ubig);
216 BEAST_EXPECT(
217 ig == id[0] && uig == uid[0] && big == bid[0] &&
218 ubig == ubid[0]);
219 }
220 catch (std::exception&)
221 {
222 fail();
223 }
224 try
225 {
226 // SOCI requires boost::optional (not std::optional) as
227 // parameters.
228 boost::optional<std::int32_t> ig;
229 // Known bug: https://github.com/SOCI/soci/issues/926
230 // boost::optional<std::uint32_t> uig;
231 uint32_t uig = 0;
232 boost::optional<std::int64_t> big;
233 boost::optional<std::uint64_t> ubig;
234 s << "SELECT I, UI, BI, UBI from STT;", soci::into(ig),
235 soci::into(uig), soci::into(big), soci::into(ubig);
236 BEAST_EXPECT(
237 *ig == id[0] && uig == uid[0] && *big == bid[0] &&
238 *ubig == ubid[0]);
239 }
240 catch (std::exception&)
241 {
242 fail();
243 }
244 // There are too many issues when working with soci::row and
245 // boost::tuple. DO NOT USE soci row! I had a set of workarounds to
246 // make soci row less error prone, I'm keeping these tests in case I
247 // try to add soci::row and boost::tuple back into soci.
248#if 0
249 try
250 {
251 std::int32_t ig = 0;
252 std::uint32_t uig = 0;
253 std::int64_t big = 0;
254 std::uint64_t ubig = 0;
255 soci::row r;
256 s << "SELECT I, UI, BI, UBI from STT", soci::into (r);
257 ig = r.get<std::int32_t>(0);
258 uig = r.get<std::uint32_t>(1);
259 big = r.get<std::int64_t>(2);
260 ubig = r.get<std::uint64_t>(3);
261 BEAST_EXPECT(ig == id[0] && uig == uid[0] && big == bid[0] &&
262 ubig == ubid[0]);
263 }
264 catch (std::exception&)
265 {
266 fail ();
267 }
268 try
269 {
270 std::int32_t ig = 0;
271 std::uint32_t uig = 0;
272 std::int64_t big = 0;
273 std::uint64_t ubig = 0;
274 soci::row r;
275 s << "SELECT I, UI, BI, UBI from STT", soci::into (r);
276 ig = r.get<std::int32_t>("I");
277 uig = r.get<std::uint32_t>("UI");
278 big = r.get<std::int64_t>("BI");
279 ubig = r.get<std::uint64_t>("UBI");
280 BEAST_EXPECT(ig == id[0] && uig == uid[0] && big == bid[0] &&
281 ubig == ubid[0]);
282 }
283 catch (std::exception&)
284 {
285 fail ();
286 }
287 try
288 {
289 boost::tuple<std::int32_t,
292 std::uint64_t> d;
293 s << "SELECT I, UI, BI, UBI from STT", soci::into (d);
294 BEAST_EXPECT(get<0>(d) == id[0] && get<1>(d) == uid[0] &&
295 get<2>(d) == bid[0] && get<3>(d) == ubid[0]);
296 }
297 catch (std::exception&)
298 {
299 fail ();
300 }
301#endif
302 }
303 {
304 namespace bfs = boost::filesystem;
305 // Remove the database
306 bfs::path dbPath(sc.connectionString());
307 if (bfs::is_regular_file(dbPath))
308 bfs::remove(dbPath);
309 }
310 }
311 void
313 {
314 testcase("deleteWithSubselect");
315 BasicConfig c;
317 DBConfig sc(c, "SociTestDB");
318 {
319 soci::session s;
320 sc.open(s);
321 const char* dbInit[] = {
322 "BEGIN TRANSACTION;",
323 "CREATE TABLE Ledgers ( \
324 LedgerHash CHARACTER(64) PRIMARY KEY, \
325 LedgerSeq BIGINT UNSIGNED \
326 );",
327 "CREATE INDEX SeqLedger ON Ledgers(LedgerSeq);"};
328 for (auto const c : dbInit)
329 s << c;
330 char lh[65];
331 memset(lh, 'a', 64);
332 lh[64] = '\0';
333 int toIncIndex = 63;
334 int const numRows = 16;
335 std::vector<std::string> ledgerHashes;
336 std::vector<int> ledgerIndexes;
337 ledgerHashes.reserve(numRows);
338 ledgerIndexes.reserve(numRows);
339 for (int i = 0; i < numRows; ++i)
340 {
341 ++lh[toIncIndex];
342 if (lh[toIncIndex] == 'z')
343 --toIncIndex;
344 ledgerHashes.emplace_back(lh);
345 ledgerIndexes.emplace_back(i);
346 }
347 s << "INSERT INTO Ledgers (LedgerHash, LedgerSeq) VALUES "
348 "(:lh, :li);",
349 soci::use(ledgerHashes), soci::use(ledgerIndexes);
350
351 std::vector<int> ledgersLS(numRows * 2);
352 s << "SELECT LedgerSeq FROM Ledgers;", soci::into(ledgersLS);
353 BEAST_EXPECT(ledgersLS.size() == numRows);
354 }
355 namespace bfs = boost::filesystem;
356 // Remove the database
357 bfs::path dbPath(sc.connectionString());
358 if (bfs::is_regular_file(dbPath))
359 bfs::remove(dbPath);
360 }
361 void
362 run() override
363 {
368 }
369};
370
371BEAST_DEFINE_TESTSUITE(SociDB, core, ripple);
372
373} // namespace ripple
testcase_t testcase
Memberspace for declaring test cases.
Definition: suite.h:153
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition: suite.h:531
Holds unparsed configuration information.
Definition: BasicConfig.h:219
void overwrite(std::string const &section, std::string const &key, std::string const &value)
Overwrite a key/value pair with a command line argument If the section does not exist it is created.
void legacy(std::string const &section, std::string value)
Set a value that is not a key/value pair.
DBConfig is used when a client wants to delay opening a soci::session after parsing the config parame...
Definition: SociDB.h:58
void open(soci::session &s) const
Definition: SociDB.cpp:92
std::string connectionString() const
Definition: SociDB.cpp:86
static void setupDatabaseDir(boost::filesystem::path const &dbPath)
Definition: SociDB_test.cpp:53
static void setupSQLiteConfig(BasicConfig &config, boost::filesystem::path const &dbPath)
Definition: SociDB_test.cpp:33
void run() override
Runs the suite.
static boost::filesystem::path getDatabasePath()
Definition: SociDB_test.cpp:70
static void cleanupDatabaseDir(boost::filesystem::path const &dbPath)
Definition: SociDB_test.cpp:44
void testSQLiteDeleteWithSubselect()
T distance(T... args)
T emplace_back(T... args)
T find(T... args)
T max(T... args)
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition: algorithm.h:26
T reserve(T... args)
T size(T... args)