xrpld
Toggle main menu visibility
Loading...
Searching...
No Matches
test
core
SociDB_test.cpp
1
#include <test/jtx/TestSuite.h>
2
3
#include <xrpl/basics/contract.h>
4
#include <xrpl/beast/unit_test/suite.h>
5
#include <xrpl/config/BasicConfig.h>
6
#include <xrpl/config/Constants.h>
7
#include <xrpl/rdb/SociDB.h>
8
9
#include <boost/optional/optional.hpp>
// IWYU pragma: keep
10
11
#include <soci/boost-optional.h>
// IWYU pragma: keep
12
#include <soci/into.h>
13
#include <soci/session.h>
14
#include <soci/use.h>
15
16
#include <
algorithm
>
17
#include <
cstdint
>
18
#include <
cstring
>
19
#include <
exception
>
20
#include <
filesystem
>
21
#include <
iterator
>
22
#include <
limits
>
23
#include <
stdexcept
>
24
#include <
string_view
>
25
#include <
utility
>
26
#include <
vector
>
27
28
namespace
xrpl
{
29
class
SociDB_test
final :
public
TestSuite
30
{
31
private
:
32
static
void
33
setupSQLiteConfig
(
BasicConfig
& config,
std::filesystem::path
const
& dbPath)
34
{
35
config.
overwrite
(
Sections::kSqdb
,
Keys::kBackend
,
"sqlite"
);
36
auto
value = dbPath.
string
();
37
if
(!value.empty())
38
config.
legacy
(
Sections::kDatabasePath
, value);
39
}
40
41
static
void
42
cleanupDatabaseDir
(
std::filesystem::path
const
& dbPath)
43
{
44
using namespace
std::filesystem
;
45
if
(!
exists
(dbPath) || !
is_directory
(dbPath) || !
is_empty
(dbPath))
46
return
;
47
remove
(dbPath);
48
}
49
50
static
void
51
setupDatabaseDir
(
std::filesystem::path
const
& dbPath)
52
{
53
using namespace
std::filesystem
;
54
if
(!
exists
(dbPath))
55
{
56
create_directory
(dbPath);
57
return
;
58
}
59
60
if
(!
is_directory
(dbPath))
61
{
62
// someone created a file where we want to put out directory
63
Throw<std::runtime_error>
(
"Cannot create directory: "
+ dbPath.
string
());
64
}
65
}
66
static
std::filesystem::path
67
getDatabasePath
()
68
{
69
return
std::filesystem::current_path
() /
"socidb_test_databases"
;
70
}
71
72
public
:
73
SociDB_test
()
74
{
75
try
76
{
77
setupDatabaseDir
(
getDatabasePath
());
78
}
79
catch
(
std::exception
const
&)
// NOLINT(bugprone-empty-catch)
80
{
81
}
82
}
83
~SociDB_test
()
override
84
{
85
try
86
{
87
cleanupDatabaseDir
(
getDatabasePath
());
88
}
89
catch
(
std::exception
const
&)
// NOLINT(bugprone-empty-catch)
90
{
91
}
92
}
93
void
94
testSQLiteFileNames
()
95
{
96
// confirm that files are given the correct extensions
97
testcase
(
"sqliteFileNames"
);
98
BasicConfig
c;
99
setupSQLiteConfig
(c,
getDatabasePath
());
100
std::vector<std::pair<std::string, std::string>
>
const
d(
101
{{
"peerfinder"
,
".sqlite"
},
102
{
"state"
,
".db"
},
103
{
"random"
,
".db"
},
104
{
"validators"
,
".sqlite"
}});
105
106
for
(
auto
const
& i : d)
107
{
108
DBConfig
const
sc(c, i.first);
109
BEAST_EXPECT(sc.
connectionString
().
ends_with
(i.first + i.second));
110
}
111
}
112
void
113
testSQLiteSession
()
114
{
115
testcase
(
"open"
);
116
BasicConfig
c;
117
setupSQLiteConfig
(c,
getDatabasePath
());
118
DBConfig
const
sc(c,
"SociTestDB"
);
119
std::vector<std::string>
const
stringData({
"String1"
,
"String2"
,
"String3"
});
120
std::vector<int>
const
intData({1, 2, 3});
121
auto
checkValues = [
this
, &stringData, &intData](soci::session& s) {
122
// Check values in db
123
std::vector<std::string>
stringResult(20 * stringData.size());
124
std::vector<int>
intResult(20 * intData.size());
125
s <<
"SELECT StringData, IntData FROM SociTestTable;"
, soci::into(stringResult),
126
soci::into(intResult);
127
BEAST_EXPECT(
128
stringResult.
size
() == stringData.size() && intResult.
size
() == intData.size());
129
for
(
int
i = 0; i < stringResult.
size
(); ++i)
130
{
131
auto
si =
std::distance
(
132
stringData.begin(),
std::ranges::find
(stringData, stringResult[i]));
133
auto
ii =
std::distance
(intData.begin(),
std::ranges::find
(intData, intResult[i]));
134
BEAST_EXPECT(si == ii && si < stringResult.
size
());
135
}
136
};
137
138
{
139
soci::session s;
140
sc.
open
(s);
141
s <<
"CREATE TABLE IF NOT EXISTS SociTestTable ("
142
" Key INTEGER PRIMARY KEY,"
143
" StringData TEXT,"
144
" IntData INTEGER"
145
");"
;
146
147
s <<
"INSERT INTO SociTestTable (StringData, IntData) VALUES "
148
"(:stringData, :intData);"
,
149
soci::use(stringData), soci::use(intData);
150
checkValues(s);
151
}
152
{
153
// Check values in db after session was closed
154
soci::session s;
155
sc.
open
(s);
156
checkValues(s);
157
}
158
{
159
namespace
bfs =
std::filesystem
;
160
// Remove the database
161
bfs::path
const
dbPath(sc.
connectionString
());
162
if
(bfs::is_regular_file(dbPath))
163
bfs::remove(dbPath);
164
}
165
}
166
167
void
168
testSQLiteSelect
()
169
{
170
testcase
(
"select"
);
171
BasicConfig
c;
172
setupSQLiteConfig
(c,
getDatabasePath
());
173
DBConfig
const
sc(c,
"SociTestDB"
);
174
std::vector<std::uint64_t>
const
ubid(
175
{(
std::uint64_t
)
std::numeric_limits<std::int64_t>::max
(), 20, 30});
176
std::vector<std::int64_t>
const
bid({-10, -20, -30});
177
std::vector<std::uint32_t>
const
uid({
std::numeric_limits<std::uint32_t>::max
(), 2, 3});
178
std::vector<std::int32_t>
const
id({-1, -2, -3});
179
180
{
181
soci::session s;
182
sc.
open
(s);
183
184
s <<
"DROP TABLE IF EXISTS STT;"
;
185
186
s <<
"CREATE TABLE STT ("
187
" I INTEGER,"
188
" UI INTEGER UNSIGNED,"
189
" BI BIGINT,"
190
" UBI BIGINT UNSIGNED"
191
");"
;
192
193
s <<
"INSERT INTO STT (I, UI, BI, UBI) VALUES "
194
"(:id, :idu, :bid, :bidu);"
,
195
soci::use(
id
), soci::use(uid), soci::use(bid), soci::use(ubid);
196
197
try
198
{
199
std::int32_t
ig = 0;
200
std::uint32_t
uig = 0;
201
std::int64_t
big = 0;
202
std::uint64_t
ubig = 0;
203
s <<
"SELECT I, UI, BI, UBI from STT;"
, soci::into(ig), soci::into(uig),
204
soci::into(big), soci::into(ubig);
205
BEAST_EXPECT(ig ==
id
[0] && uig == uid[0] && big == bid[0] && ubig == ubid[0]);
206
}
207
catch
(
std::exception
&)
208
{
209
fail
();
210
}
211
try
212
{
213
// SOCI requires boost::optional (not std::optional) as
214
// parameters.
215
boost::optional<std::int32_t> ig;
216
// Known bug: https://github.com/SOCI/soci/issues/926
217
// boost::optional<std::uint32_t> uig;
218
uint32_t
uig = 0;
219
boost::optional<std::int64_t> big;
220
boost::optional<std::uint64_t> ubig;
221
s <<
"SELECT I, UI, BI, UBI from STT;"
, soci::into(ig), soci::into(uig),
222
soci::into(big), soci::into(ubig);
223
BEAST_EXPECT(*ig ==
id
[0] && uig == uid[0] && *big == bid[0] && *ubig == ubid[0]);
224
}
225
catch
(
std::exception
&)
226
{
227
fail
();
228
}
229
// There are too many issues when working with soci::row and
230
// boost::tuple. DO NOT USE soci row!
231
}
232
{
233
namespace
bfs =
std::filesystem
;
234
// Remove the database
235
bfs::path
const
dbPath(sc.
connectionString
());
236
if
(bfs::is_regular_file(dbPath))
237
bfs::remove(dbPath);
238
}
239
}
240
void
241
testSQLiteDeleteWithSubselect
()
242
{
243
testcase
(
"deleteWithSubselect"
);
244
BasicConfig
c;
245
setupSQLiteConfig
(c,
getDatabasePath
());
246
DBConfig
const
sc(c,
"SociTestDB"
);
247
{
248
soci::session s;
249
sc.
open
(s);
250
251
std::string_view
const
dbInit[] = {
252
"BEGIN TRANSACTION;"
,
253
"CREATE TABLE Ledgers ( \
254
LedgerHash CHARACTER(64) PRIMARY KEY, \
255
LedgerSeq BIGINT UNSIGNED \
256
);"
,
257
"CREATE INDEX SeqLedger ON Ledgers(LedgerSeq);"
};
258
for
(
auto
const
c : dbInit)
259
s << c;
260
char
lh[65];
261
memset
(lh,
'a'
, 64);
262
lh[64] =
'\0'
;
263
int
toIncIndex = 63;
264
int
const
numRows = 16;
265
std::vector<std::string>
ledgerHashes;
266
std::vector<int>
ledgerIndexes;
267
ledgerHashes.
reserve
(numRows);
268
ledgerIndexes.
reserve
(numRows);
269
for
(
int
i = 0; i < numRows; ++i)
270
{
271
++lh[toIncIndex];
272
if
(lh[toIncIndex] ==
'z'
)
273
--toIncIndex;
274
ledgerHashes.
emplace_back
(lh);
275
ledgerIndexes.
emplace_back
(i);
276
}
277
s <<
"INSERT INTO Ledgers (LedgerHash, LedgerSeq) VALUES "
278
"(:lh, :li);"
,
279
soci::use(ledgerHashes), soci::use(ledgerIndexes);
280
281
std::vector<int>
ledgersLS(numRows * 2);
282
s <<
"SELECT LedgerSeq FROM Ledgers;"
, soci::into(ledgersLS);
283
BEAST_EXPECT(ledgersLS.
size
() == numRows);
284
}
285
namespace
bfs =
std::filesystem
;
286
// Remove the database
287
bfs::path
const
dbPath(sc.
connectionString
());
288
if
(bfs::is_regular_file(dbPath))
289
bfs::remove(dbPath);
290
}
291
void
292
run
()
override
293
{
294
testSQLiteFileNames
();
295
testSQLiteSession
();
296
testSQLiteSelect
();
297
testSQLiteDeleteWithSubselect
();
298
}
299
};
300
301
BEAST_DEFINE_TESTSUITE
(SociDB, core,
xrpl
);
302
303
}
// namespace xrpl
algorithm
std::string_view
beast::unit_test::Suite::fail
void fail(String const &reason, char const *file, int line)
Record a failure.
Definition
suite.h:554
beast::unit_test::Suite::testcase
TestcaseT testcase
Memberspace for declaring test cases.
Definition
suite.h:155
xrpl::BasicConfig
Holds unparsed configuration information.
Definition
BasicConfig.h:222
xrpl::BasicConfig::overwrite
void overwrite(std::string const §ion, 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.
Definition
BasicConfig.cpp:137
xrpl::BasicConfig::legacy
void legacy(std::string const §ion, std::string value)
Set a value that is not a key/value pair.
Definition
BasicConfig.cpp:153
xrpl::DBConfig
DBConfig is used when a client wants to delay opening a soci::session after parsing the config parame...
Definition
SociDB.h:44
xrpl::DBConfig::open
void open(soci::session &s) const
Definition
SociDB.cpp:85
xrpl::DBConfig::connectionString
std::string connectionString() const
Definition
SociDB.cpp:79
xrpl::SociDB_test::setupDatabaseDir
static void setupDatabaseDir(std::filesystem::path const &dbPath)
Definition
SociDB_test.cpp:51
xrpl::SociDB_test::cleanupDatabaseDir
static void cleanupDatabaseDir(std::filesystem::path const &dbPath)
Definition
SociDB_test.cpp:42
xrpl::SociDB_test::testSQLiteSelect
void testSQLiteSelect()
Definition
SociDB_test.cpp:168
xrpl::SociDB_test::testSQLiteFileNames
void testSQLiteFileNames()
Definition
SociDB_test.cpp:94
xrpl::SociDB_test::testSQLiteSession
void testSQLiteSession()
Definition
SociDB_test.cpp:113
xrpl::SociDB_test::getDatabasePath
static std::filesystem::path getDatabasePath()
Definition
SociDB_test.cpp:67
xrpl::SociDB_test::testSQLiteDeleteWithSubselect
void testSQLiteDeleteWithSubselect()
Definition
SociDB_test.cpp:241
xrpl::SociDB_test::SociDB_test
SociDB_test()
Definition
SociDB_test.cpp:73
xrpl::SociDB_test::setupSQLiteConfig
static void setupSQLiteConfig(BasicConfig &config, std::filesystem::path const &dbPath)
Definition
SociDB_test.cpp:33
xrpl::SociDB_test::~SociDB_test
~SociDB_test() override
Definition
SociDB_test.cpp:83
xrpl::SociDB_test::run
void run() override
Runs the suite.
Definition
SociDB_test.cpp:292
xrpl::TestSuite
Definition
TestSuite.h:12
std::filesystem::create_directory
T create_directory(T... args)
cstdint
cstring
std::filesystem::current_path
T current_path(T... args)
std::distance
T distance(T... args)
std::vector::emplace_back
T emplace_back(T... args)
std::string::ends_with
T ends_with(T... args)
exception
std::filesystem::exists
T exists(T... args)
filesystem
std::ranges::find
T find(T... args)
std::uint64_t
std::filesystem::is_directory
T is_directory(T... args)
std::filesystem::is_empty
T is_empty(T... args)
iterator
limits
std::numeric_limits::max
T max(T... args)
std::memset
T memset(T... args)
std::filesystem
xrpl
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition
algorithm.h:5
xrpl::BEAST_DEFINE_TESTSUITE
BEAST_DEFINE_TESTSUITE(AccountTxPaging, app, xrpl)
xrpl::Throw
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition
contract.h:52
std::filesystem::path
std::filesystem::remove
T remove(T... args)
std::vector::reserve
T reserve(T... args)
std::vector::size
T size(T... args)
stdexcept
std::filesystem::path::string
T string(T... args)
string_view
xrpl::Keys::kBackend
static constexpr auto kBackend
Definition
Constants.h:93
xrpl::Sections::kSqdb
static constexpr auto kSqdb
Definition
Constants.h:60
xrpl::Sections::kDatabasePath
static constexpr auto kDatabasePath
Definition
Constants.h:13
utility
vector
Generated by
1.17.0