mirror of
https://github.com/XRPLF/clio.git
synced 2026-04-29 15:37:53 +00:00
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -118,7 +118,7 @@ jobs:
|
||||
- name: Run Test
|
||||
run: |
|
||||
cd clio/build
|
||||
./clio_tests --gtest_filter="-BackendCassandraBaseTest*:BackendCassandraTest*"
|
||||
./clio_tests --gtest_filter="-BackendCassandraBaseTest*:BackendCassandraTest*:BackendCassandraFactoryTestWithDB*"
|
||||
|
||||
test_clio:
|
||||
name: Test Clio
|
||||
@@ -174,7 +174,7 @@ jobs:
|
||||
run: |
|
||||
export BOOST_ROOT=$(pwd)/boost
|
||||
cd clio
|
||||
cmake -B build -DCODE_COVERAGE=on -DTEST_PARAMETER='--gtest_filter="-BackendCassandraBaseTest*:BackendCassandraTest*"'
|
||||
cmake -B build -DCODE_COVERAGE=on -DTEST_PARAMETER='--gtest_filter="-BackendCassandraBaseTest*:BackendCassandraTest*:BackendCassandraFactoryTestWithDB*"'
|
||||
if ! cmake --build build -j$(nproc); then
|
||||
echo '# 🔥Ubuntu build🔥 failed!💥' >> $GITHUB_STEP_SUMMARY
|
||||
exit 1
|
||||
|
||||
@@ -17,4 +17,6 @@ enable_testing()
|
||||
|
||||
include(GoogleTest)
|
||||
|
||||
gtest_discover_tests(clio_tests)
|
||||
#increase timeout for tests discovery to 10 seconds, by default it is 5s. As more unittests added, we start to hit this issue
|
||||
#https://github.com/google/googletest/issues/3475
|
||||
gtest_discover_tests(clio_tests DISCOVERY_TIMEOUT 10)
|
||||
|
||||
@@ -156,6 +156,7 @@ if(BUILD_TESTS)
|
||||
unittests/rpc/handlers/BookChangesTest.cpp
|
||||
unittests/rpc/handlers/LedgerTest.cpp
|
||||
# Backend
|
||||
unittests/backend/BackendFactoryTest.cpp
|
||||
unittests/backend/cassandra/BaseTests.cpp
|
||||
unittests/backend/cassandra/BackendTests.cpp
|
||||
unittests/backend/cassandra/RetryPolicyTests.cpp
|
||||
|
||||
@@ -33,23 +33,23 @@ make_Backend(boost::asio::io_context& ioc, clio::Config const& config)
|
||||
static clio::Logger log{"Backend"};
|
||||
log.info() << "Constructing BackendInterface";
|
||||
|
||||
// TODO: use readOnly in new backend to prevent creation of schema at startup
|
||||
// auto readOnly = config.valueOr("read_only", false);
|
||||
auto const readOnly = config.valueOr("read_only", false);
|
||||
|
||||
auto type = config.value<std::string>("database.type");
|
||||
auto const type = config.value<std::string>("database.type");
|
||||
std::shared_ptr<BackendInterface> backend = nullptr;
|
||||
|
||||
// TODO: retire `cassandra-new` by next release after 2.0
|
||||
if (boost::iequals(type, "cassandra") or boost::iequals(type, "cassandra-new"))
|
||||
{
|
||||
auto cfg = config.section("database." + type);
|
||||
backend = std::make_shared<Backend::Cassandra::CassandraBackend>(Backend::Cassandra::SettingsProvider{cfg});
|
||||
backend =
|
||||
std::make_shared<Backend::Cassandra::CassandraBackend>(Backend::Cassandra::SettingsProvider{cfg}, readOnly);
|
||||
}
|
||||
|
||||
if (!backend)
|
||||
throw std::runtime_error("Invalid database type");
|
||||
|
||||
auto rng = backend->hardFetchLedgerRangeNoThrow();
|
||||
auto const rng = backend->hardFetchLedgerRangeNoThrow();
|
||||
if (rng)
|
||||
{
|
||||
backend->updateRange(rng->minSequence);
|
||||
|
||||
@@ -63,7 +63,7 @@ public:
|
||||
*
|
||||
* @param settingsProvider
|
||||
*/
|
||||
BasicCassandraBackend(SettingsProviderType settingsProvider)
|
||||
BasicCassandraBackend(SettingsProviderType settingsProvider, bool readOnly)
|
||||
: settingsProvider_{std::move(settingsProvider)}
|
||||
, schema_{settingsProvider_}
|
||||
, handle_{settingsProvider_.getSettings()}
|
||||
@@ -72,18 +72,30 @@ public:
|
||||
if (auto const res = handle_.connect(); not res)
|
||||
throw std::runtime_error("Could not connect to Cassandra: " + res.error());
|
||||
|
||||
if (auto const res = handle_.execute(schema_.createKeyspace); not res)
|
||||
if (not readOnly)
|
||||
{
|
||||
// on datastax, creation of keyspaces can be configured to only be done thru the admin interface.
|
||||
// this does not mean that the keyspace does not already exist tho.
|
||||
if (res.error().code() != CASS_ERROR_SERVER_UNAUTHORIZED)
|
||||
throw std::runtime_error("Could not create keyspace: " + res.error());
|
||||
if (auto const res = handle_.execute(schema_.createKeyspace); not res)
|
||||
{
|
||||
// on datastax, creation of keyspaces can be configured to only be done thru the admin interface.
|
||||
// this does not mean that the keyspace does not already exist tho.
|
||||
if (res.error().code() != CASS_ERROR_SERVER_UNAUTHORIZED)
|
||||
throw std::runtime_error("Could not create keyspace: " + res.error());
|
||||
}
|
||||
|
||||
if (auto const res = handle_.executeEach(schema_.createSchema); not res)
|
||||
throw std::runtime_error("Could not create schema: " + res.error());
|
||||
}
|
||||
|
||||
if (auto const res = handle_.executeEach(schema_.createSchema); not res)
|
||||
throw std::runtime_error("Could not create schema: " + res.error());
|
||||
try
|
||||
{
|
||||
schema_.prepareStatements(handle_);
|
||||
}
|
||||
catch (std::runtime_error const& ex)
|
||||
{
|
||||
log_.error() << "Failed to prepare the statements: " << ex.what() << "; readOnly: " << readOnly;
|
||||
throw;
|
||||
}
|
||||
|
||||
schema_.prepareStatements(handle_);
|
||||
log_.info() << "Created (revamped) CassandraBackend";
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ If you wish to test the backend component you will need to have access to a **lo
|
||||
## Running
|
||||
To run the unit tests, first build Clio as normal, then execute `./clio_tests` to run all unit tests.
|
||||
|
||||
**Note:** If you don't want to test the Cassandra backend code, the relevant tests can be disabled like this: `./clio_tests --gtest_filter="-BackendCassandraBaseTest*:BackendCassandraTest*"`
|
||||
**Note:** If you don't want to test the Cassandra backend code, the relevant tests can be disabled like this: `./clio_tests --gtest_filter="-BackendCassandraBaseTest*:BackendCassandraTest*:BackendCassandraFactoryTestWithDB*"`
|
||||
|
||||
# Adding Unit Tests
|
||||
To add unit tests, please create a separate file for the component you are trying to cover (unless it already exists) and use any other existing unit test file as an example.
|
||||
|
||||
190
unittests/backend/BackendFactoryTest.cpp
Normal file
190
unittests/backend/BackendFactoryTest.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of clio: https://github.com/XRPLF/clio
|
||||
Copyright (c) 2023, the clio developers.
|
||||
|
||||
Permission to use, copy, modify, and 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 <backend/BackendFactory.h>
|
||||
#include <util/Fixtures.h>
|
||||
|
||||
#include <boost/json.hpp>
|
||||
#include <fmt/core.h>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace {
|
||||
constexpr static auto contactPoints = "127.0.0.1";
|
||||
constexpr static auto keyspace = "factory_test";
|
||||
} // namespace
|
||||
|
||||
class BackendCassandraFactoryTest : public SyncAsioContextTest
|
||||
{
|
||||
protected:
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
SyncAsioContextTest::SetUp();
|
||||
}
|
||||
|
||||
void
|
||||
TearDown() override
|
||||
{
|
||||
SyncAsioContextTest::TearDown();
|
||||
}
|
||||
};
|
||||
|
||||
class BackendCassandraFactoryTestWithDB : public BackendCassandraFactoryTest
|
||||
{
|
||||
protected:
|
||||
void
|
||||
SetUp() override
|
||||
{
|
||||
BackendCassandraFactoryTest::SetUp();
|
||||
}
|
||||
|
||||
void
|
||||
TearDown() override
|
||||
{
|
||||
BackendCassandraFactoryTest::TearDown();
|
||||
// drop the keyspace for next test
|
||||
Backend::Cassandra::Handle handle{contactPoints};
|
||||
EXPECT_TRUE(handle.connect());
|
||||
handle.execute("DROP KEYSPACE " + std::string{keyspace});
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(BackendCassandraFactoryTest, NoSuchBackend)
|
||||
{
|
||||
clio::Config cfg{boost::json::parse(
|
||||
R"({
|
||||
"database":
|
||||
{
|
||||
"type":"unknown"
|
||||
}
|
||||
})")};
|
||||
EXPECT_THROW(make_Backend(ctx, cfg), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_F(BackendCassandraFactoryTest, CreateCassandraBackendDBDisconnect)
|
||||
{
|
||||
clio::Config cfg{boost::json::parse(fmt::format(
|
||||
R"({{
|
||||
"database":
|
||||
{{
|
||||
"type" : "cassandra",
|
||||
"cassandra" : {{
|
||||
"contact_points": "{}",
|
||||
"keyspace": "{}",
|
||||
"replication_factor": 1,
|
||||
"connect_timeout": 2
|
||||
}}
|
||||
}}
|
||||
}})",
|
||||
"127.0.0.2",
|
||||
keyspace))};
|
||||
EXPECT_THROW(make_Backend(ctx, cfg), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_F(BackendCassandraFactoryTestWithDB, CreateCassandraBackend)
|
||||
{
|
||||
clio::Config cfg{boost::json::parse(fmt::format(
|
||||
R"({{
|
||||
"database":
|
||||
{{
|
||||
"type" : "cassandra",
|
||||
"cassandra" : {{
|
||||
"contact_points": "{}",
|
||||
"keyspace": "{}",
|
||||
"replication_factor": 1
|
||||
}}
|
||||
}}
|
||||
}})",
|
||||
contactPoints,
|
||||
keyspace))};
|
||||
auto backend = make_Backend(ctx, cfg);
|
||||
EXPECT_TRUE(backend);
|
||||
// empty db does not have ledger range
|
||||
EXPECT_FALSE(backend->fetchLedgerRange());
|
||||
|
||||
// insert range table
|
||||
Backend::Cassandra::Handle handle{contactPoints};
|
||||
EXPECT_TRUE(handle.connect());
|
||||
handle.execute(fmt::format("INSERT INTO {}.ledger_range (is_latest, sequence) VALUES (False, 100)", keyspace));
|
||||
handle.execute(fmt::format("INSERT INTO {}.ledger_range (is_latest, sequence) VALUES (True, 500)", keyspace));
|
||||
|
||||
backend = make_Backend(ctx, cfg);
|
||||
EXPECT_TRUE(backend);
|
||||
auto const range = backend->fetchLedgerRange();
|
||||
EXPECT_EQ(range->minSequence, 100);
|
||||
EXPECT_EQ(range->maxSequence, 500);
|
||||
}
|
||||
|
||||
TEST_F(BackendCassandraFactoryTestWithDB, CreateCassandraBackendReadOnlyWithEmptyDB)
|
||||
{
|
||||
clio::Config cfg{boost::json::parse(fmt::format(
|
||||
R"({{
|
||||
"read_only": true,
|
||||
"database":
|
||||
{{
|
||||
"type" : "cassandra",
|
||||
"cassandra" : {{
|
||||
"contact_points": "{}",
|
||||
"keyspace": "{}",
|
||||
"replication_factor": 1
|
||||
}}
|
||||
}}
|
||||
}})",
|
||||
contactPoints,
|
||||
keyspace))};
|
||||
EXPECT_THROW(make_Backend(ctx, cfg), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_F(BackendCassandraFactoryTestWithDB, CreateCassandraBackendReadOnlyWithDBReady)
|
||||
{
|
||||
clio::Config cfgReadOnly{boost::json::parse(fmt::format(
|
||||
R"({{
|
||||
"read_only": true,
|
||||
"database":
|
||||
{{
|
||||
"type" : "cassandra",
|
||||
"cassandra" : {{
|
||||
"contact_points": "{}",
|
||||
"keyspace": "{}",
|
||||
"replication_factor": 1
|
||||
}}
|
||||
}}
|
||||
}})",
|
||||
contactPoints,
|
||||
keyspace))};
|
||||
|
||||
clio::Config cfgWrite{boost::json::parse(fmt::format(
|
||||
R"({{
|
||||
"read_only": false,
|
||||
"database":
|
||||
{{
|
||||
"type" : "cassandra",
|
||||
"cassandra" : {{
|
||||
"contact_points": "{}",
|
||||
"keyspace": "{}",
|
||||
"replication_factor": 1
|
||||
}}
|
||||
}}
|
||||
}})",
|
||||
contactPoints,
|
||||
keyspace))};
|
||||
|
||||
EXPECT_TRUE(make_Backend(ctx, cfgWrite));
|
||||
EXPECT_TRUE(make_Backend(ctx, cfgReadOnly));
|
||||
}
|
||||
@@ -61,7 +61,7 @@ protected:
|
||||
SetUp() override
|
||||
{
|
||||
SyncAsioContextTest::SetUp();
|
||||
backend = std::make_unique<CassandraBackend>(settingsProvider);
|
||||
backend = std::make_unique<CassandraBackend>(settingsProvider, false);
|
||||
}
|
||||
void
|
||||
TearDown() override
|
||||
|
||||
Reference in New Issue
Block a user