mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-19 18:45:52 +00:00
313 lines
11 KiB
C++
313 lines
11 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
This file is part of rippled: https://github.com/ripple/rippled
|
|
Copyright (c) 2012-2015 Ripple Labs Inc.
|
|
|
|
Permission to use, copy, modify, and/or distribute this software for any
|
|
purpose with or without fee is hereby granted, provided that the above
|
|
copyright notice and this permission notice appear in all copies.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
*/
|
|
//==============================================================================
|
|
|
|
#include <BeastConfig.h>
|
|
|
|
#include <ripple/app/data/SociDB.h>
|
|
#include <ripple/core/ConfigSections.h>
|
|
#include <ripple/basics/TestSuite.h>
|
|
#include <ripple/basics/BasicConfig.h>
|
|
#include <boost/filesystem.hpp>
|
|
#include <boost/algorithm/string.hpp>
|
|
|
|
namespace ripple {
|
|
class SociDB_test final : public TestSuite
|
|
{
|
|
private:
|
|
static void setupSQLiteConfig (BasicConfig& config,
|
|
boost::filesystem::path const& dbPath)
|
|
{
|
|
config.overwrite ("sqdb", "backend", "sqlite");
|
|
auto value = dbPath.string ();
|
|
if (!value.empty ())
|
|
config.legacy ("database_path", value);
|
|
}
|
|
|
|
static void cleanupDatabaseDir (boost::filesystem::path const& dbPath)
|
|
{
|
|
using namespace boost::filesystem;
|
|
if (!exists (dbPath) || !is_directory (dbPath) || !is_empty (dbPath))
|
|
return;
|
|
remove (dbPath);
|
|
}
|
|
|
|
static void setupDatabaseDir (boost::filesystem::path const& dbPath)
|
|
{
|
|
using namespace boost::filesystem;
|
|
if (!exists (dbPath))
|
|
{
|
|
create_directory (dbPath);
|
|
return;
|
|
}
|
|
|
|
if (!is_directory (dbPath))
|
|
{
|
|
// someone created a file where we want to put out directory
|
|
throw std::runtime_error ("Cannot create directory: " +
|
|
dbPath.string ());
|
|
}
|
|
}
|
|
static boost::filesystem::path getDatabasePath ()
|
|
{
|
|
return boost::filesystem::current_path () / "socidb_test_databases";
|
|
}
|
|
|
|
public:
|
|
SociDB_test ()
|
|
{
|
|
try
|
|
{
|
|
setupDatabaseDir (getDatabasePath ());
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
}
|
|
~SociDB_test ()
|
|
{
|
|
try
|
|
{
|
|
cleanupDatabaseDir (getDatabasePath ());
|
|
}
|
|
catch (...)
|
|
{
|
|
}
|
|
}
|
|
void testSQLiteFileNames ()
|
|
{
|
|
// confirm that files are given the correct exensions
|
|
testcase ("sqliteFileNames");
|
|
BasicConfig c;
|
|
setupSQLiteConfig (c, getDatabasePath ());
|
|
std::vector<std::pair<std::string, std::string>> const d (
|
|
{{"peerfinder", ".sqlite"},
|
|
{"state", ".db"},
|
|
{"random", ".db"},
|
|
{"validators", ".sqlite"}});
|
|
|
|
for (auto const& i : d)
|
|
{
|
|
SociConfig sc (c, i.first);
|
|
expect (boost::ends_with (sc.connectionString (),
|
|
i.first + i.second));
|
|
}
|
|
}
|
|
void testSQLiteSession ()
|
|
{
|
|
testcase ("open");
|
|
BasicConfig c;
|
|
setupSQLiteConfig (c, getDatabasePath ());
|
|
SociConfig sc (c, "SociTestDB");
|
|
std::vector<std::string> const stringData (
|
|
{"String1", "String2", "String3"});
|
|
std::vector<int> const intData ({1, 2, 3});
|
|
auto checkValues = [this, &stringData, &intData](soci::session& s)
|
|
{
|
|
// Check values in db
|
|
std::vector<std::string> stringResult (20 * stringData.size ());
|
|
std::vector<int> intResult (20 * intData.size ());
|
|
s << "SELECT StringData, IntData FROM SociTestTable;",
|
|
soci::into (stringResult), soci::into (intResult);
|
|
expect (stringResult.size () == stringData.size () &&
|
|
intResult.size () == intData.size ());
|
|
for (int i = 0; i < stringResult.size (); ++i)
|
|
{
|
|
auto si = std::distance (stringData.begin (),
|
|
std::find (stringData.begin (),
|
|
stringData.end (),
|
|
stringResult[i]));
|
|
auto ii = std::distance (
|
|
intData.begin (),
|
|
std::find (intData.begin (), intData.end (), intResult[i]));
|
|
expect (si == ii && si < stringResult.size ());
|
|
}
|
|
};
|
|
|
|
{
|
|
soci::session s;
|
|
sc.open (s);
|
|
s << "CREATE TABLE IF NOT EXISTS SociTestTable ("
|
|
" Key INTEGER PRIMARY KEY,"
|
|
" StringData TEXT,"
|
|
" IntData INTEGER"
|
|
");";
|
|
|
|
s << "INSERT INTO SociTestTable (StringData, IntData) VALUES "
|
|
"(:stringData, :intData);",
|
|
soci::use (stringData), soci::use (intData);
|
|
checkValues (s);
|
|
}
|
|
{
|
|
// Check values in db after session was closed
|
|
soci::session s;
|
|
sc.open (s);
|
|
checkValues (s);
|
|
}
|
|
{
|
|
using namespace boost::filesystem;
|
|
// Remove the database
|
|
path dbPath (sc.connectionString ());
|
|
if (is_regular_file (dbPath))
|
|
remove (dbPath);
|
|
}
|
|
}
|
|
|
|
void testSQLiteSelect ()
|
|
{
|
|
testcase ("select");
|
|
BasicConfig c;
|
|
setupSQLiteConfig (c, getDatabasePath ());
|
|
SociConfig sc (c, "SociTestDB");
|
|
std::vector<std::uint64_t> const ubid (
|
|
{(std::uint64_t)std::numeric_limits<std::int64_t>::max (), 20, 30});
|
|
std::vector<std::int64_t> const bid ({-10, -20, -30});
|
|
std::vector<std::uint32_t> const uid (
|
|
{std::numeric_limits<std::uint32_t>::max (), 2, 3});
|
|
std::vector<std::int32_t> const id ({-1, -2, -3});
|
|
|
|
{
|
|
soci::session s;
|
|
sc.open (s);
|
|
|
|
s << "DROP TABLE IF EXISTS STT;";
|
|
|
|
s << "CREATE TABLE STT ("
|
|
" I INTEGER,"
|
|
" UI INTEGER UNSIGNED,"
|
|
" BI BIGINT,"
|
|
" UBI BIGINT UNSIGNED"
|
|
");";
|
|
|
|
s << "INSERT INTO STT (I, UI, BI, UBI) VALUES "
|
|
"(:id, :idu, :bid, :bidu);",
|
|
soci::use (id), soci::use (uid), soci::use (bid),
|
|
soci::use (ubid);
|
|
|
|
try
|
|
{
|
|
std::int32_t ig = 0;
|
|
std::uint32_t uig = 0;
|
|
std::int64_t big = 0;
|
|
std::uint64_t ubig = 0;
|
|
s << "SELECT I, UI, BI, UBI from STT;", soci::into (ig),
|
|
soci::into (uig), soci::into (big), soci::into (ubig);
|
|
expect (ig == id[0] && uig == uid[0] && big == bid[0] &&
|
|
ubig == ubid[0]);
|
|
}
|
|
catch (std::exception&)
|
|
{
|
|
fail ();
|
|
}
|
|
try
|
|
{
|
|
boost::optional<std::int32_t> ig;
|
|
boost::optional<std::uint32_t> uig;
|
|
boost::optional<std::int64_t> big;
|
|
boost::optional<std::uint64_t> ubig;
|
|
s << "SELECT I, UI, BI, UBI from STT;", soci::into (ig),
|
|
soci::into (uig), soci::into (big), soci::into (ubig);
|
|
expect (*ig == id[0] && *uig == uid[0] && *big == bid[0] &&
|
|
*ubig == ubid[0]);
|
|
}
|
|
catch (std::exception&)
|
|
{
|
|
fail ();
|
|
}
|
|
// There are too many issues when working with soci::row and boost::tuple. DO NOT USE
|
|
// soci row! I had a set of workarounds to make soci row less error prone, I'm keeping
|
|
// these tests in case I try to add soci::row and boost::tuple back into soci.
|
|
#if 0
|
|
try
|
|
{
|
|
std::int32_t ig = 0;
|
|
std::uint32_t uig = 0;
|
|
std::int64_t big = 0;
|
|
std::uint64_t ubig = 0;
|
|
soci::row r;
|
|
s << "SELECT I, UI, BI, UBI from STT", soci::into (r);
|
|
ig = r.get<std::int32_t>(0);
|
|
uig = r.get<std::uint32_t>(1);
|
|
big = r.get<std::int64_t>(2);
|
|
ubig = r.get<std::uint64_t>(3);
|
|
expect (ig == id[0] && uig == uid[0] && big == bid[0] &&
|
|
ubig == ubid[0]);
|
|
}
|
|
catch (std::exception&)
|
|
{
|
|
fail ();
|
|
}
|
|
try
|
|
{
|
|
std::int32_t ig = 0;
|
|
std::uint32_t uig = 0;
|
|
std::int64_t big = 0;
|
|
std::uint64_t ubig = 0;
|
|
soci::row r;
|
|
s << "SELECT I, UI, BI, UBI from STT", soci::into (r);
|
|
ig = r.get<std::int32_t>("I");
|
|
uig = r.get<std::uint32_t>("UI");
|
|
big = r.get<std::int64_t>("BI");
|
|
ubig = r.get<std::uint64_t>("UBI");
|
|
expect (ig == id[0] && uig == uid[0] && big == bid[0] &&
|
|
ubig == ubid[0]);
|
|
}
|
|
catch (std::exception&)
|
|
{
|
|
fail ();
|
|
}
|
|
try
|
|
{
|
|
boost::tuple<std::int32_t,
|
|
std::uint32_t,
|
|
std::int64_t,
|
|
std::uint64_t> d;
|
|
s << "SELECT I, UI, BI, UBI from STT", soci::into (d);
|
|
expect (get<0>(d) == id[0] && get<1>(d) == uid[0] &&
|
|
get<2>(d) == bid[0] && get<3>(d) == ubid[0]);
|
|
}
|
|
catch (std::exception&)
|
|
{
|
|
fail ();
|
|
}
|
|
#endif
|
|
}
|
|
{
|
|
using namespace boost::filesystem;
|
|
// Remove the database
|
|
path dbPath (sc.connectionString ());
|
|
if (is_regular_file (dbPath))
|
|
remove (dbPath);
|
|
}
|
|
}
|
|
void testSQLite ()
|
|
{
|
|
testSQLiteFileNames ();
|
|
testSQLiteSession ();
|
|
testSQLiteSelect ();
|
|
}
|
|
void run ()
|
|
{
|
|
testSQLite ();
|
|
}
|
|
};
|
|
|
|
BEAST_DEFINE_TESTSUITE (SociDB, app, ripple);
|
|
|
|
} // ripple
|