mirror of
https://github.com/XRPLF/clio.git
synced 2025-11-20 03:35:55 +00:00
feat: Block clio if migration is blocking (#1834)
Add: - Block server if migration is blocking - Initialise the migration related table when server starts against empty DB Add MigrationInspectorInterface. server uses inspector to check the migrators status.
This commit is contained in:
@@ -26,6 +26,7 @@
|
|||||||
#include "etl/LoadBalancer.hpp"
|
#include "etl/LoadBalancer.hpp"
|
||||||
#include "etl/NetworkValidatedLedgers.hpp"
|
#include "etl/NetworkValidatedLedgers.hpp"
|
||||||
#include "feed/SubscriptionManager.hpp"
|
#include "feed/SubscriptionManager.hpp"
|
||||||
|
#include "migration/MigrationInspectorFactory.hpp"
|
||||||
#include "rpc/Counters.hpp"
|
#include "rpc/Counters.hpp"
|
||||||
#include "rpc/RPCEngine.hpp"
|
#include "rpc/RPCEngine.hpp"
|
||||||
#include "rpc/WorkQueue.hpp"
|
#include "rpc/WorkQueue.hpp"
|
||||||
@@ -103,6 +104,16 @@ ClioApplication::run(bool const useNgWebServer)
|
|||||||
// Interface to the database
|
// Interface to the database
|
||||||
auto backend = data::makeBackend(config_);
|
auto backend = data::makeBackend(config_);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto const migrationInspector = migration::makeMigrationInspector(config_, backend);
|
||||||
|
// Check if any migration is blocking Clio server starting.
|
||||||
|
if (migrationInspector->isBlockingClio() and backend->hardFetchLedgerRangeNoThrow()) {
|
||||||
|
LOG(util::LogService::error())
|
||||||
|
<< "Existing Migration is blocking Clio, Please complete the database migration first.";
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Manages clients subscribed to streams
|
// Manages clients subscribed to streams
|
||||||
auto subscriptions = feed::SubscriptionManager::makeSubscriptionManager(config_, backend);
|
auto subscriptions = feed::SubscriptionManager::makeSubscriptionManager(config_, backend);
|
||||||
|
|
||||||
|
|||||||
@@ -5,4 +5,4 @@ target_sources(
|
|||||||
cassandra/impl/ObjectsAdapter.cpp cassandra/impl/TransactionsAdapter.cpp
|
cassandra/impl/ObjectsAdapter.cpp cassandra/impl/TransactionsAdapter.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(clio_migration PRIVATE clio_util clio_etl)
|
target_link_libraries(clio_migration PRIVATE clio_util clio_data)
|
||||||
|
|||||||
65
src/migration/MigrationInspectorFactory.hpp
Normal file
65
src/migration/MigrationInspectorFactory.hpp
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of clio: https://github.com/XRPLF/clio
|
||||||
|
Copyright (c) 2025, 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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "data/BackendInterface.hpp"
|
||||||
|
#include "migration/MigrationInspectorInterface.hpp"
|
||||||
|
#include "migration/MigratiorStatus.hpp"
|
||||||
|
#include "migration/cassandra/CassandraMigrationManager.hpp"
|
||||||
|
#include "util/Assert.hpp"
|
||||||
|
#include "util/log/Logger.hpp"
|
||||||
|
#include "util/newconfig/ConfigDefinition.hpp"
|
||||||
|
|
||||||
|
#include <boost/algorithm/string.hpp>
|
||||||
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace migration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief A factory function that creates migration inspector instance and initializes the migration table if needed.
|
||||||
|
*
|
||||||
|
* @param config The config.
|
||||||
|
* @param backend The backend instance. It should be initialized before calling this function.
|
||||||
|
* @return A shared_ptr<MigrationInspectorInterface> instance
|
||||||
|
*/
|
||||||
|
inline std::shared_ptr<MigrationInspectorInterface>
|
||||||
|
makeMigrationInspector(
|
||||||
|
util::config::ClioConfigDefinition const& config,
|
||||||
|
std::shared_ptr<BackendInterface> const& backend
|
||||||
|
)
|
||||||
|
{
|
||||||
|
ASSERT(backend != nullptr, "Backend is not initialized");
|
||||||
|
|
||||||
|
auto inspector = std::make_shared<migration::cassandra::CassandraMigrationInspector>(backend);
|
||||||
|
|
||||||
|
// Database is empty, we need to initialize the migration table if it is a writeable backend
|
||||||
|
if (not config.get<bool>("read_only") and not backend->hardFetchLedgerRangeNoThrow()) {
|
||||||
|
migration::MigratorStatus migrated(migration::MigratorStatus::Migrated);
|
||||||
|
for (auto const& name : inspector->allMigratorsNames()) {
|
||||||
|
backend->writeMigratorStatus(name, migrated.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return inspector;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace migration
|
||||||
79
src/migration/MigrationInspectorInterface.hpp
Normal file
79
src/migration/MigrationInspectorInterface.hpp
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of clio: https://github.com/XRPLF/clio
|
||||||
|
Copyright (c) 2025, 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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "migration/MigratiorStatus.hpp"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace migration {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The interface for the migration inspector.The Clio server application will use this interface to inspect
|
||||||
|
* the migration status.
|
||||||
|
*/
|
||||||
|
struct MigrationInspectorInterface {
|
||||||
|
virtual ~MigrationInspectorInterface() = default;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the status of all the migrators
|
||||||
|
* @return A vector of tuple, the first element is the migrator's name, the second element is the status of the
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::tuple<std::string, MigratorStatus>>
|
||||||
|
allMigratorsStatusPairs() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get all registered migrators' names
|
||||||
|
*
|
||||||
|
* @return A vector of migrators' names
|
||||||
|
*/
|
||||||
|
virtual std::vector<std::string>
|
||||||
|
allMigratorsNames() const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the status of a migrator by its name
|
||||||
|
*
|
||||||
|
* @param name The migrator's name
|
||||||
|
* @return The status of the migrator
|
||||||
|
*/
|
||||||
|
virtual MigratorStatus
|
||||||
|
getMigratorStatusByName(std::string const& name) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the description of a migrator by its name
|
||||||
|
*
|
||||||
|
* @param name The migrator's name
|
||||||
|
* @return The description of the migrator
|
||||||
|
*/
|
||||||
|
virtual std::string
|
||||||
|
getMigratorDescriptionByName(std::string const& name) const = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return if Clio server is blocked
|
||||||
|
*
|
||||||
|
* @return True if Clio server is blocked by migration, false otherwise
|
||||||
|
*/
|
||||||
|
virtual bool
|
||||||
|
isBlockingClio() const = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace migration
|
||||||
@@ -19,59 +19,23 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "migration/MigratiorStatus.hpp"
|
#include "migration/MigrationInspectorInterface.hpp"
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace migration {
|
namespace migration {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The interface for the migration manager. This interface is tend to be implemented for specific database. The
|
* @brief The interface for the migration manager. The migration application layer will use this interface to run the
|
||||||
* application layer will use this interface to run the migrations.
|
* migrations. Unlike the MigrationInspectorInterface which only provides the status of migration, this interface
|
||||||
|
* contains the acutal migration running method.
|
||||||
*/
|
*/
|
||||||
struct MigrationManagerInterface {
|
struct MigrationManagerInterface : virtual public MigrationInspectorInterface {
|
||||||
virtual ~MigrationManagerInterface() = default;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Run the the migration according to the given migrator's name
|
* @brief Run the the migration according to the given migrator's name
|
||||||
*/
|
*/
|
||||||
virtual void
|
virtual void
|
||||||
runMigration(std::string const&) = 0;
|
runMigration(std::string const&) = 0;
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the status of all the migrators
|
|
||||||
* @return A vector of tuple, the first element is the migrator's name, the second element is the status of the
|
|
||||||
*/
|
|
||||||
virtual std::vector<std::tuple<std::string, MigratorStatus>>
|
|
||||||
allMigratorsStatusPairs() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get all registered migrators' names
|
|
||||||
*
|
|
||||||
* @return A vector of migrators' names
|
|
||||||
*/
|
|
||||||
virtual std::vector<std::string>
|
|
||||||
allMigratorsNames() const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the status of a migrator by its name
|
|
||||||
*
|
|
||||||
* @param name The migrator's name
|
|
||||||
* @return The status of the migrator
|
|
||||||
*/
|
|
||||||
virtual MigratorStatus
|
|
||||||
getMigratorStatusByName(std::string const& name) const = 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the description of a migrator by its name
|
|
||||||
*
|
|
||||||
* @param name The migrator's name
|
|
||||||
* @return The description of the migrator
|
|
||||||
*/
|
|
||||||
virtual std::string
|
|
||||||
getMigratorDescriptionByName(std::string const& name) const = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace migration
|
} // namespace migration
|
||||||
|
|||||||
@@ -40,9 +40,11 @@ A migrator satisfies the `MigratorSpec`(impl/Spec.hpp) concept.
|
|||||||
|
|
||||||
It contains:
|
It contains:
|
||||||
|
|
||||||
- A `name` which will be used to identify the migrator. User will refer this migrator in command-line tool by this name. The name needs to be different with other migrators, otherwise a compilation error will be raised.
|
- A `kNAME` which will be used to identify the migrator. User will refer this migrator in command-line tool by this name. The name needs to be different with other migrators, otherwise a compilation error will be raised.
|
||||||
|
|
||||||
- A `description` which is the detail information of the migrator.
|
- A `kDESCRIPTION` which is the detail information of the migrator.
|
||||||
|
|
||||||
|
- An optional `kCAN_BLOCK_CLIO` which indicates whether the migrator can block the Clio server. If it's absent, the migrator can't block server. If there is a blocking migrator not completed, the Clio server will fail to start.
|
||||||
|
|
||||||
- A static function `runMigration`, it will be called when user run `--migrate name`. It accepts two parameters: backend, which provides the DB operations interface, and cfg, which provides migration-related configuration. Each migrator can have its own configuration under `.migration` session.
|
- A static function `runMigration`, it will be called when user run `--migrate name`. It accepts two parameters: backend, which provides the DB operations interface, and cfg, which provides migration-related configuration. Each migrator can have its own configuration under `.migration` session.
|
||||||
|
|
||||||
@@ -65,8 +67,8 @@ Most indexes are based on either ledger states or transactions. We provide the `
|
|||||||
If you need to do full scan against other table, you can follow below steps:
|
If you need to do full scan against other table, you can follow below steps:
|
||||||
- Describe the table which needs full scan in a struct. It has to satisfy the `TableSpec`(cassandra/Spec.hpp) concept, containing static member:
|
- Describe the table which needs full scan in a struct. It has to satisfy the `TableSpec`(cassandra/Spec.hpp) concept, containing static member:
|
||||||
- Tuple type `Row`, it's the type of each field in a row. The order of types should match what database will return in a row. Key types should come first, followed by other field types sorted in alphabetical order.
|
- Tuple type `Row`, it's the type of each field in a row. The order of types should match what database will return in a row. Key types should come first, followed by other field types sorted in alphabetical order.
|
||||||
- `PARTITION_KEY`, it's the name of the partition key of the table.
|
- `kPARTITION_KEY`, it's the name of the partition key of the table.
|
||||||
- `TABLE_NAME`
|
- `kTABLE_NAME`
|
||||||
|
|
||||||
- Inherent from `FullTableScannerAdapterBase`.
|
- Inherent from `FullTableScannerAdapterBase`.
|
||||||
- Implement `onRowRead`, its parameter is the `Row` we defined. It's the callback function when a row is read.
|
- Implement `onRowRead`, its parameter is the `Row` we defined. It's the callback function when a row is read.
|
||||||
|
|||||||
@@ -19,20 +19,32 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "data/BackendInterface.hpp"
|
||||||
#include "migration/cassandra/CassandraMigrationBackend.hpp"
|
#include "migration/cassandra/CassandraMigrationBackend.hpp"
|
||||||
|
#include "migration/impl/MigrationInspectorBase.hpp"
|
||||||
#include "migration/impl/MigrationManagerBase.hpp"
|
#include "migration/impl/MigrationManagerBase.hpp"
|
||||||
#include "migration/impl/MigratorsRegister.hpp"
|
#include "migration/impl/MigratorsRegister.hpp"
|
||||||
|
|
||||||
namespace migration::cassandra {
|
namespace {
|
||||||
|
|
||||||
// Register migrators here
|
// Register migrators here
|
||||||
// MigratorsRegister<BackendType, ExampleMigrator>
|
// MigratorsRegister<BackendType, ExampleMigrator>
|
||||||
template <typename BackendType>
|
template <typename BackendType>
|
||||||
using CassandraSupportedMigrators = migration::impl::MigratorsRegister<BackendType>;
|
using CassandraSupportedMigrators = migration::impl::MigratorsRegister<BackendType>;
|
||||||
|
|
||||||
// Register with MigrationBackend which proceeds the migration
|
// Instantiates with the backend which supports actual migration running
|
||||||
using MigrationProcesser = CassandraSupportedMigrators<CassandraMigrationBackend>;
|
using MigrationProcesser = CassandraSupportedMigrators<migration::cassandra::CassandraMigrationBackend>;
|
||||||
|
|
||||||
|
// Instantiates with backend interface, it doesn't support actual migration. But it can be used to inspect the migrators
|
||||||
|
// status
|
||||||
|
using MigrationQuerier = CassandraSupportedMigrators<data::BackendInterface>;
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
namespace migration::cassandra {
|
||||||
|
|
||||||
|
using CassandraMigrationInspector = migration::impl::MigrationInspectorBase<MigrationQuerier>;
|
||||||
|
|
||||||
// The Cassandra migration manager
|
|
||||||
using CassandraMigrationManager = migration::impl::MigrationManagerBase<MigrationProcesser>;
|
using CassandraMigrationManager = migration::impl::MigrationManagerBase<MigrationProcesser>;
|
||||||
|
|
||||||
} // namespace migration::cassandra
|
} // namespace migration::cassandra
|
||||||
|
|||||||
121
src/migration/impl/MigrationInspectorBase.hpp
Normal file
121
src/migration/impl/MigrationInspectorBase.hpp
Normal file
@@ -0,0 +1,121 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of clio: https://github.com/XRPLF/clio
|
||||||
|
Copyright (c) 2025, 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.
|
||||||
|
*/
|
||||||
|
//==============================================================================
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "migration/MigrationInspectorInterface.hpp"
|
||||||
|
#include "migration/MigratiorStatus.hpp"
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <ranges>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
namespace migration::impl {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief The migration inspector implementation for Cassandra. It will report the migration status for Cassandra
|
||||||
|
* database.
|
||||||
|
*
|
||||||
|
* @tparam SupportedMigrators The migrators resgister that contains all the migrators
|
||||||
|
*/
|
||||||
|
template <typename SupportedMigrators>
|
||||||
|
class MigrationInspectorBase : virtual public MigrationInspectorInterface {
|
||||||
|
protected:
|
||||||
|
SupportedMigrators migrators_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Construct a new Cassandra Migration Inspector object
|
||||||
|
*
|
||||||
|
* @param backend The backend of the Cassandra database
|
||||||
|
*/
|
||||||
|
explicit MigrationInspectorBase(std::shared_ptr<typename SupportedMigrators::BackendType> backend)
|
||||||
|
: migrators_{std::move(backend)}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the status of all the migrators
|
||||||
|
*
|
||||||
|
* @return A vector of tuple, the first element is the migrator's name, the second element is the status of the
|
||||||
|
* migrator
|
||||||
|
*/
|
||||||
|
std::vector<std::tuple<std::string, MigratorStatus>>
|
||||||
|
allMigratorsStatusPairs() const override
|
||||||
|
{
|
||||||
|
return migrators_.getMigratorsStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the status of a migrator by its name
|
||||||
|
*
|
||||||
|
* @param name The name of the migrator
|
||||||
|
* @return The status of the migrator
|
||||||
|
*/
|
||||||
|
MigratorStatus
|
||||||
|
getMigratorStatusByName(std::string const& name) const override
|
||||||
|
{
|
||||||
|
return migrators_.getMigratorStatus(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get all registered migrators' names
|
||||||
|
*
|
||||||
|
* @return A vector of string, the names of all the migrators
|
||||||
|
*/
|
||||||
|
std::vector<std::string>
|
||||||
|
allMigratorsNames() const override
|
||||||
|
{
|
||||||
|
auto const names = migrators_.getMigratorNames();
|
||||||
|
return std::vector<std::string>{names.begin(), names.end()};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the description of a migrator by its name
|
||||||
|
*
|
||||||
|
* @param name The name of the migrator
|
||||||
|
* @return The description of the migrator
|
||||||
|
*/
|
||||||
|
std::string
|
||||||
|
getMigratorDescriptionByName(std::string const& name) const override
|
||||||
|
{
|
||||||
|
return migrators_.getMigratorDescription(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return if there is uncomplete migrator blocking the server
|
||||||
|
*
|
||||||
|
* @return True if server is blocked, false otherwise
|
||||||
|
*/
|
||||||
|
bool
|
||||||
|
isBlockingClio() const override
|
||||||
|
{
|
||||||
|
return std::ranges::any_of(migrators_.getMigratorNames(), [&](auto const& migrator) {
|
||||||
|
if (auto canBlock = migrators_.canMigratorBlockClio(migrator); canBlock.has_value() and *canBlock and
|
||||||
|
migrators_.getMigratorStatus(std::string(migrator)) == MigratorStatus::Status::NotMigrated) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace migration::impl
|
||||||
@@ -20,14 +20,12 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "migration/MigrationManagerInterface.hpp"
|
#include "migration/MigrationManagerInterface.hpp"
|
||||||
#include "migration/MigratiorStatus.hpp"
|
#include "migration/impl/MigrationInspectorBase.hpp"
|
||||||
#include "util/newconfig/ObjectView.hpp"
|
#include "util/newconfig/ObjectView.hpp"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <tuple>
|
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
namespace migration::impl {
|
namespace migration::impl {
|
||||||
|
|
||||||
@@ -38,8 +36,7 @@ namespace migration::impl {
|
|||||||
* @tparam SupportedMigrators The migrators resgister that contains all the migrators
|
* @tparam SupportedMigrators The migrators resgister that contains all the migrators
|
||||||
*/
|
*/
|
||||||
template <typename SupportedMigrators>
|
template <typename SupportedMigrators>
|
||||||
class MigrationManagerBase : public MigrationManagerInterface {
|
class MigrationManagerBase : public MigrationManagerInterface, public MigrationInspectorBase<SupportedMigrators> {
|
||||||
SupportedMigrators migrators_;
|
|
||||||
// contains only migration related settings
|
// contains only migration related settings
|
||||||
util::config::ObjectView config_;
|
util::config::ObjectView config_;
|
||||||
|
|
||||||
@@ -54,7 +51,7 @@ public:
|
|||||||
std::shared_ptr<typename SupportedMigrators::BackendType> backend,
|
std::shared_ptr<typename SupportedMigrators::BackendType> backend,
|
||||||
util::config::ObjectView config
|
util::config::ObjectView config
|
||||||
)
|
)
|
||||||
: migrators_{backend}, config_{std::move(config)}
|
: MigrationInspectorBase<SupportedMigrators>{std::move(backend)}, config_{std::move(config)}
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,55 +63,7 @@ public:
|
|||||||
void
|
void
|
||||||
runMigration(std::string const& name) override
|
runMigration(std::string const& name) override
|
||||||
{
|
{
|
||||||
migrators_.runMigrator(name, config_);
|
this->migrators_.runMigrator(name, config_);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the status of all the migrators
|
|
||||||
*
|
|
||||||
* @return A vector of tuple, the first element is the migrator's name, the second element is the status of the
|
|
||||||
* migrator
|
|
||||||
*/
|
|
||||||
std::vector<std::tuple<std::string, MigratorStatus>>
|
|
||||||
allMigratorsStatusPairs() const override
|
|
||||||
{
|
|
||||||
return migrators_.getMigratorsStatus();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the status of a migrator by its name
|
|
||||||
*
|
|
||||||
* @param name The name of the migrator
|
|
||||||
* @return The status of the migrator
|
|
||||||
*/
|
|
||||||
MigratorStatus
|
|
||||||
getMigratorStatusByName(std::string const& name) const override
|
|
||||||
{
|
|
||||||
return migrators_.getMigratorStatus(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get all registered migrators' names
|
|
||||||
*
|
|
||||||
* @return A vector of string, the names of all the migrators
|
|
||||||
*/
|
|
||||||
std::vector<std::string>
|
|
||||||
allMigratorsNames() const override
|
|
||||||
{
|
|
||||||
auto const names = migrators_.getMigratorNames();
|
|
||||||
return std::vector<std::string>{names.begin(), names.end()};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Get the description of a migrator by its name
|
|
||||||
*
|
|
||||||
* @param name The name of the migrator
|
|
||||||
* @return The description of the migrator
|
|
||||||
*/
|
|
||||||
std::string
|
|
||||||
getMigratorDescriptionByName(std::string const& name) const override
|
|
||||||
{
|
|
||||||
return migrators_.getMigratorDescription(name);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include "data/BackendInterface.hpp"
|
#include "data/BackendInterface.hpp"
|
||||||
#include "migration/MigratiorStatus.hpp"
|
#include "migration/MigratiorStatus.hpp"
|
||||||
#include "migration/impl/Spec.hpp"
|
#include "migration/impl/Spec.hpp"
|
||||||
|
#include "util/Assert.hpp"
|
||||||
#include "util/Concepts.hpp"
|
#include "util/Concepts.hpp"
|
||||||
#include "util/log/Logger.hpp"
|
#include "util/log/Logger.hpp"
|
||||||
#include "util/newconfig/ObjectView.hpp"
|
#include "util/newconfig/ObjectView.hpp"
|
||||||
@@ -30,10 +31,12 @@
|
|||||||
#include <array>
|
#include <array>
|
||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <optional>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace migration::impl {
|
namespace migration::impl {
|
||||||
@@ -47,6 +50,11 @@ concept MigrationBackend = requires { requires std::same_as<typename MigratorTyp
|
|||||||
template <typename Backend, typename... MigratorType>
|
template <typename Backend, typename... MigratorType>
|
||||||
concept BackendMatchAllMigrators = (MigrationBackend<Backend, MigratorType> && ...);
|
concept BackendMatchAllMigrators = (MigrationBackend<Backend, MigratorType> && ...);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept HasCanBlockClio = requires(T t) {
|
||||||
|
{ t.kCAN_BLOCK_CLIO };
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*@brief The register of migrators. It will dispatch the migration to the corresponding migrator. It also
|
*@brief The register of migrators. It will dispatch the migration to the corresponding migrator. It also
|
||||||
*hold the shared pointer of backend, which is used by the migrators.
|
*hold the shared pointer of backend, which is used by the migrators.
|
||||||
@@ -81,6 +89,23 @@ class MigratorsRegister {
|
|||||||
return (T::kNAME == targetName) ? T::kDESCRIPTION : "";
|
return (T::kNAME == targetName) ? T::kDESCRIPTION : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename First, typename... Rest>
|
||||||
|
static constexpr bool
|
||||||
|
canBlockClioHelper(std::string_view targetName)
|
||||||
|
{
|
||||||
|
if (targetName == First::kNAME) {
|
||||||
|
if constexpr (HasCanBlockClio<First>) {
|
||||||
|
return First::kCAN_BLOCK_CLIO;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if constexpr (sizeof...(Rest) > 0) {
|
||||||
|
return canBlockClioHelper<Rest...>(targetName);
|
||||||
|
}
|
||||||
|
ASSERT(false, "The migrator name is not found");
|
||||||
|
std::unreachable();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* @brief The backend type which is used by the migrators
|
* @brief The backend type which is used by the migrators
|
||||||
@@ -179,6 +204,27 @@ public:
|
|||||||
return result.empty() ? "No Description" : result;
|
return result.empty() ? "No Description" : result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Return if the given migrator can block Clio server
|
||||||
|
*
|
||||||
|
* @param name The migrator's name
|
||||||
|
* @return std::nullopt if the migrator name is not found, or a boolean value indicating whether the migrator is
|
||||||
|
* blocking Clio server.
|
||||||
|
*/
|
||||||
|
std::optional<bool>
|
||||||
|
canMigratorBlockClio(std::string_view name) const
|
||||||
|
{
|
||||||
|
if constexpr (sizeof...(MigratorType) == 0) {
|
||||||
|
return std::nullopt;
|
||||||
|
} else {
|
||||||
|
auto const migratiors = getMigratorNames();
|
||||||
|
if (std::ranges::find(migratiors, name) == migratiors.end())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
return canBlockClioHelper<MigratorType...>(name);
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace migration::impl
|
} // namespace migration::impl
|
||||||
|
|||||||
@@ -26,13 +26,10 @@ struct SimpleTestMigrator {
|
|||||||
using Backend = MockMigrationBackend;
|
using Backend = MockMigrationBackend;
|
||||||
static constexpr auto kNAME = "SimpleTestMigrator";
|
static constexpr auto kNAME = "SimpleTestMigrator";
|
||||||
static constexpr auto kDESCRIPTION = "The migrator for version 0 -> 1";
|
static constexpr auto kDESCRIPTION = "The migrator for version 0 -> 1";
|
||||||
static void
|
static constexpr auto kCAN_BLOCK_CLIO = true;
|
||||||
runMigration(std::shared_ptr<MockMigrationBackend>, util::config::ObjectView const&)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reset()
|
runMigration(std::shared_ptr<MockMigrationBackend>, util::config::ObjectView const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -45,9 +42,16 @@ struct SimpleTestMigrator2 {
|
|||||||
runMigration(std::shared_ptr<MockMigrationBackend>, util::config::ObjectView const&)
|
runMigration(std::shared_ptr<MockMigrationBackend>, util::config::ObjectView const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SimpleTestMigrator3 {
|
||||||
|
using Backend = MockMigrationBackend;
|
||||||
|
static constexpr auto kNAME = "SimpleTestMigrator3";
|
||||||
|
static constexpr auto kDESCRIPTION = "The migrator for version 3 -> 4";
|
||||||
|
static constexpr auto kCAN_BLOCK_CLIO = false;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
reset()
|
runMigration(std::shared_ptr<MockMigrationBackend>, util::config::ObjectView const&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -60,6 +60,8 @@ target_sources(
|
|||||||
migration/cassandra/SpecTests.cpp
|
migration/cassandra/SpecTests.cpp
|
||||||
migration/MigratorRegisterTests.cpp
|
migration/MigratorRegisterTests.cpp
|
||||||
migration/MigratorStatusTests.cpp
|
migration/MigratorStatusTests.cpp
|
||||||
|
migration/MigrationInspectorFactoryTests.cpp
|
||||||
|
migration/MigrationInspectorBaseTests.cpp
|
||||||
migration/MigrationManagerBaseTests.cpp
|
migration/MigrationManagerBaseTests.cpp
|
||||||
migration/MigrationManagerFactoryTests.cpp
|
migration/MigrationManagerFactoryTests.cpp
|
||||||
migration/SpecTests.cpp
|
migration/SpecTests.cpp
|
||||||
|
|||||||
130
tests/unit/migration/MigrationInspectorBaseTests.cpp
Normal file
130
tests/unit/migration/MigrationInspectorBaseTests.cpp
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of clio: https://github.com/XRPLF/clio
|
||||||
|
Copyright (c) 2025, 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 "data/BackendInterface.hpp"
|
||||||
|
#include "migration/MigratiorStatus.hpp"
|
||||||
|
#include "migration/TestMigrators.hpp"
|
||||||
|
#include "migration/impl/MigrationManagerBase.hpp"
|
||||||
|
#include "migration/impl/MigratorsRegister.hpp"
|
||||||
|
#include "util/MockBackendTestFixture.hpp"
|
||||||
|
#include "util/MockPrometheus.hpp"
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <tuple>
|
||||||
|
|
||||||
|
using TestMigratorRegister =
|
||||||
|
migration::impl::MigratorsRegister<data::BackendInterface, SimpleTestMigrator, SimpleTestMigrator2>;
|
||||||
|
|
||||||
|
using TestCassandramigrationInspector = migration::impl::MigrationInspectorBase<TestMigratorRegister>;
|
||||||
|
|
||||||
|
struct MigrationInspectorBaseTest : public util::prometheus::WithMockPrometheus, public MockBackendTest {
|
||||||
|
MigrationInspectorBaseTest()
|
||||||
|
{
|
||||||
|
migrationInspector_ = std::make_shared<TestCassandramigrationInspector>(backend_);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::shared_ptr<TestCassandramigrationInspector> migrationInspector_;
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorBaseTest, AllStatus)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator", testing::_)).WillOnce(testing::Return("Migrated"));
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator2", testing::_))
|
||||||
|
.WillOnce(testing::Return("NotMigrated"));
|
||||||
|
auto const status = migrationInspector_->allMigratorsStatusPairs();
|
||||||
|
EXPECT_EQ(status.size(), 2);
|
||||||
|
EXPECT_TRUE(
|
||||||
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator", migration::MigratorStatus::Migrated)) !=
|
||||||
|
status.end()
|
||||||
|
);
|
||||||
|
EXPECT_TRUE(
|
||||||
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator2", migration::MigratorStatus::NotMigrated)) !=
|
||||||
|
status.end()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorBaseTest, AllNames)
|
||||||
|
{
|
||||||
|
auto const names = migrationInspector_->allMigratorsNames();
|
||||||
|
EXPECT_EQ(names.size(), 2);
|
||||||
|
EXPECT_EQ(names[0], "SimpleTestMigrator");
|
||||||
|
EXPECT_EQ(names[1], "SimpleTestMigrator2");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorBaseTest, Description)
|
||||||
|
{
|
||||||
|
EXPECT_EQ(migrationInspector_->getMigratorDescriptionByName("unknown"), "No Description");
|
||||||
|
EXPECT_EQ(
|
||||||
|
migrationInspector_->getMigratorDescriptionByName("SimpleTestMigrator"), "The migrator for version 0 -> 1"
|
||||||
|
);
|
||||||
|
EXPECT_EQ(
|
||||||
|
migrationInspector_->getMigratorDescriptionByName("SimpleTestMigrator2"), "The migrator for version 1 -> 2"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorBaseTest, getMigratorStatusByName)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator", testing::_)).WillOnce(testing::Return("Migrated"));
|
||||||
|
EXPECT_EQ(migrationInspector_->getMigratorStatusByName("SimpleTestMigrator"), migration::MigratorStatus::Migrated);
|
||||||
|
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator2", testing::_))
|
||||||
|
.WillOnce(testing::Return("NotMigrated"));
|
||||||
|
EXPECT_EQ(
|
||||||
|
migrationInspector_->getMigratorStatusByName("SimpleTestMigrator2"), migration::MigratorStatus::NotMigrated
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorBaseTest, oneMigratorBlockingClio)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator", testing::_))
|
||||||
|
.WillOnce(testing::Return("NotMigrated"));
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator2", testing::_)).Times(0);
|
||||||
|
|
||||||
|
EXPECT_TRUE(migrationInspector_->isBlockingClio());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorBaseTest, oneMigratorBlockingClioGetMigrated)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator", testing::_)).WillOnce(testing::Return("Migrated"));
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator2", testing::_)).Times(0);
|
||||||
|
EXPECT_FALSE(migrationInspector_->isBlockingClio());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorBaseTest, noMigratorBlockingClio)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus).Times(0);
|
||||||
|
|
||||||
|
auto const migrations = migration::impl::MigrationInspectorBase<
|
||||||
|
migration::impl::MigratorsRegister<data::BackendInterface, SimpleTestMigrator2, SimpleTestMigrator3>>(backend_);
|
||||||
|
EXPECT_FALSE(migrations.isBlockingClio());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorBaseTest, isBlockingClioWhenNoMigrator)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus).Times(0);
|
||||||
|
|
||||||
|
auto const migrations =
|
||||||
|
migration::impl::MigrationInspectorBase<migration::impl::MigratorsRegister<data::BackendInterface>>(backend_);
|
||||||
|
EXPECT_FALSE(migrations.isBlockingClio());
|
||||||
|
}
|
||||||
75
tests/unit/migration/MigrationInspectorFactoryTests.cpp
Normal file
75
tests/unit/migration/MigrationInspectorFactoryTests.cpp
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
//------------------------------------------------------------------------------
|
||||||
|
/*
|
||||||
|
This file is part of clio: https://github.com/XRPLF/clio
|
||||||
|
Copyright (c) 2025, 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 "data/Types.hpp"
|
||||||
|
#include "migration/MigrationInspectorFactory.hpp"
|
||||||
|
#include "util/MockBackendTestFixture.hpp"
|
||||||
|
#include "util/MockPrometheus.hpp"
|
||||||
|
#include "util/newconfig/ConfigDefinition.hpp"
|
||||||
|
#include "util/newconfig/ConfigValue.hpp"
|
||||||
|
#include "util/newconfig/Types.hpp"
|
||||||
|
|
||||||
|
#include <gmock/gmock.h>
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
using namespace testing;
|
||||||
|
|
||||||
|
struct MigrationInspectorFactoryTests : public util::prometheus::WithPrometheus, public MockBackendTest {
|
||||||
|
protected:
|
||||||
|
util::config::ClioConfigDefinition const readerConfig_ = util::config::ClioConfigDefinition{
|
||||||
|
{"read_only", util::config::ConfigValue{util::config::ConfigType::Boolean}.defaultValue(true)}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct MigrationInspectorFactoryTestsDeathTest : public MigrationInspectorFactoryTests {};
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorFactoryTestsDeathTest, NullBackend)
|
||||||
|
{
|
||||||
|
EXPECT_DEATH(migration::makeMigrationInspector(readerConfig_, nullptr), ".*");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorFactoryTests, NotInitMigrationTableIfReader)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*backend_, hardFetchLedgerRange).Times(0);
|
||||||
|
|
||||||
|
EXPECT_NE(migration::makeMigrationInspector(readerConfig_, backend_), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorFactoryTests, BackendIsWriterAndDBEmpty)
|
||||||
|
{
|
||||||
|
EXPECT_CALL(*backend_, hardFetchLedgerRange).WillOnce(Return(std::nullopt));
|
||||||
|
|
||||||
|
util::config::ClioConfigDefinition const writerConfig = util::config::ClioConfigDefinition{
|
||||||
|
{"read_only", util::config::ConfigValue{util::config::ConfigType::Boolean}.defaultValue(false)}
|
||||||
|
};
|
||||||
|
EXPECT_NE(migration::makeMigrationInspector(writerConfig, backend_), nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(MigrationInspectorFactoryTests, BackendIsWriterAndDBNotEmpty)
|
||||||
|
{
|
||||||
|
LedgerRange const range{.minSequence = 1, .maxSequence = 5};
|
||||||
|
EXPECT_CALL(*backend_, hardFetchLedgerRange).WillOnce(Return(range));
|
||||||
|
|
||||||
|
util::config::ClioConfigDefinition const writerConfig = util::config::ClioConfigDefinition{
|
||||||
|
{"read_only", util::config::ConfigValue{util::config::ConfigType::Boolean}.defaultValue(false)}
|
||||||
|
};
|
||||||
|
EXPECT_NE(migration::makeMigrationInspector(writerConfig, backend_), nullptr);
|
||||||
|
}
|
||||||
@@ -54,7 +54,6 @@ struct MigrationManagerBaseTest : public util::prometheus::WithMockPrometheus, p
|
|||||||
MigrationManagerBaseTest()
|
MigrationManagerBaseTest()
|
||||||
{
|
{
|
||||||
auto mockBackendPtr = backend_.operator std::shared_ptr<MockMigrationBackend>();
|
auto mockBackendPtr = backend_.operator std::shared_ptr<MockMigrationBackend>();
|
||||||
TestMigratorRegister const migratorRegister(mockBackendPtr);
|
|
||||||
migrationManager = std::make_shared<TestCassandraMigrationManager>(mockBackendPtr, cfg.getObject("migration"));
|
migrationManager = std::make_shared<TestCassandraMigrationManager>(mockBackendPtr, cfg.getObject("migration"));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -67,8 +67,8 @@ TEST_F(MigratorRegisterTests, EmptyMigratorRegister)
|
|||||||
EXPECT_EQ(migratorRegister.getMigratorDescription("unknown"), "No Description");
|
EXPECT_EQ(migratorRegister.getMigratorDescription("unknown"), "No Description");
|
||||||
}
|
}
|
||||||
|
|
||||||
using MultipleMigratorRegister =
|
using MultipleMigratorRegister = migration::impl::
|
||||||
migration::impl::MigratorsRegister<MockMigrationBackend, SimpleTestMigrator, SimpleTestMigrator2>;
|
MigratorsRegister<MockMigrationBackend, SimpleTestMigrator, SimpleTestMigrator2, SimpleTestMigrator3>;
|
||||||
|
|
||||||
struct MultipleMigratorRegisterTests : public util::prometheus::WithMockPrometheus, public MockMigrationBackendTest {
|
struct MultipleMigratorRegisterTests : public util::prometheus::WithMockPrometheus, public MockMigrationBackendTest {
|
||||||
std::optional<MultipleMigratorRegister> migratorRegister;
|
std::optional<MultipleMigratorRegister> migratorRegister;
|
||||||
@@ -82,11 +82,11 @@ struct MultipleMigratorRegisterTests : public util::prometheus::WithMockPromethe
|
|||||||
TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenError)
|
TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenError)
|
||||||
{
|
{
|
||||||
EXPECT_CALL(*backend_, fetchMigratorStatus(testing::_, testing::_))
|
EXPECT_CALL(*backend_, fetchMigratorStatus(testing::_, testing::_))
|
||||||
.Times(2)
|
.Times(3)
|
||||||
.WillRepeatedly(testing::Return(std::nullopt));
|
.WillRepeatedly(testing::Return(std::nullopt));
|
||||||
|
|
||||||
auto const status = migratorRegister->getMigratorsStatus();
|
auto const status = migratorRegister->getMigratorsStatus();
|
||||||
EXPECT_EQ(status.size(), 2);
|
EXPECT_EQ(status.size(), 3);
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
std::ranges::find(status, std::make_tuple("SimpleTestMigrator", migration::MigratorStatus::NotMigrated)) !=
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator", migration::MigratorStatus::NotMigrated)) !=
|
||||||
status.end()
|
status.end()
|
||||||
@@ -95,16 +95,20 @@ TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenError)
|
|||||||
std::ranges::find(status, std::make_tuple("SimpleTestMigrator2", migration::MigratorStatus::NotMigrated)) !=
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator2", migration::MigratorStatus::NotMigrated)) !=
|
||||||
status.end()
|
status.end()
|
||||||
);
|
);
|
||||||
|
EXPECT_TRUE(
|
||||||
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator3", migration::MigratorStatus::NotMigrated)) !=
|
||||||
|
status.end()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenReturnInvalidStatus)
|
TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenReturnInvalidStatus)
|
||||||
{
|
{
|
||||||
EXPECT_CALL(*backend_, fetchMigratorStatus(testing::_, testing::_))
|
EXPECT_CALL(*backend_, fetchMigratorStatus(testing::_, testing::_))
|
||||||
.Times(2)
|
.Times(3)
|
||||||
.WillRepeatedly(testing::Return("Invalid"));
|
.WillRepeatedly(testing::Return("Invalid"));
|
||||||
|
|
||||||
auto const status = migratorRegister->getMigratorsStatus();
|
auto const status = migratorRegister->getMigratorsStatus();
|
||||||
EXPECT_EQ(status.size(), 2);
|
EXPECT_EQ(status.size(), 3);
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
std::ranges::find(status, std::make_tuple("SimpleTestMigrator", migration::MigratorStatus::NotMigrated)) !=
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator", migration::MigratorStatus::NotMigrated)) !=
|
||||||
status.end()
|
status.end()
|
||||||
@@ -113,6 +117,10 @@ TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenReturnInvalidStatus)
|
|||||||
std::ranges::find(status, std::make_tuple("SimpleTestMigrator2", migration::MigratorStatus::NotMigrated)) !=
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator2", migration::MigratorStatus::NotMigrated)) !=
|
||||||
status.end()
|
status.end()
|
||||||
);
|
);
|
||||||
|
EXPECT_TRUE(
|
||||||
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator3", migration::MigratorStatus::NotMigrated)) !=
|
||||||
|
status.end()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenOneMigrated)
|
TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenOneMigrated)
|
||||||
@@ -120,9 +128,11 @@ TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenOneMigrated)
|
|||||||
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator", testing::_)).WillOnce(testing::Return("Migrated"));
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator", testing::_)).WillOnce(testing::Return("Migrated"));
|
||||||
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator2", testing::_))
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator2", testing::_))
|
||||||
.WillOnce(testing::Return("NotMigrated"));
|
.WillOnce(testing::Return("NotMigrated"));
|
||||||
|
EXPECT_CALL(*backend_, fetchMigratorStatus("SimpleTestMigrator3", testing::_))
|
||||||
|
.WillOnce(testing::Return("NotMigrated"));
|
||||||
|
|
||||||
auto const status = migratorRegister->getMigratorsStatus();
|
auto const status = migratorRegister->getMigratorsStatus();
|
||||||
EXPECT_EQ(status.size(), 2);
|
EXPECT_EQ(status.size(), 3);
|
||||||
EXPECT_TRUE(
|
EXPECT_TRUE(
|
||||||
std::ranges::find(status, std::make_tuple("SimpleTestMigrator", migration::MigratorStatus::Migrated)) !=
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator", migration::MigratorStatus::Migrated)) !=
|
||||||
status.end()
|
status.end()
|
||||||
@@ -131,6 +141,10 @@ TEST_F(MultipleMigratorRegisterTests, GetMigratorsStatusWhenOneMigrated)
|
|||||||
std::ranges::find(status, std::make_tuple("SimpleTestMigrator2", migration::MigratorStatus::NotMigrated)) !=
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator2", migration::MigratorStatus::NotMigrated)) !=
|
||||||
status.end()
|
status.end()
|
||||||
);
|
);
|
||||||
|
EXPECT_TRUE(
|
||||||
|
std::ranges::find(status, std::make_tuple("SimpleTestMigrator3", migration::MigratorStatus::NotMigrated)) !=
|
||||||
|
status.end()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MultipleMigratorRegisterTests, GetMigratorStatus)
|
TEST_F(MultipleMigratorRegisterTests, GetMigratorStatus)
|
||||||
@@ -158,9 +172,10 @@ TEST_F(MultipleMigratorRegisterTests, GetMigratorStatusWhenError)
|
|||||||
TEST_F(MultipleMigratorRegisterTests, Names)
|
TEST_F(MultipleMigratorRegisterTests, Names)
|
||||||
{
|
{
|
||||||
auto names = migratorRegister->getMigratorNames();
|
auto names = migratorRegister->getMigratorNames();
|
||||||
EXPECT_EQ(names.size(), 2);
|
EXPECT_EQ(names.size(), 3);
|
||||||
EXPECT_TRUE(std::ranges::find(names, "SimpleTestMigrator") != names.end());
|
EXPECT_TRUE(std::ranges::find(names, "SimpleTestMigrator") != names.end());
|
||||||
EXPECT_TRUE(std::ranges::find(names, "SimpleTestMigrator2") != names.end());
|
EXPECT_TRUE(std::ranges::find(names, "SimpleTestMigrator2") != names.end());
|
||||||
|
EXPECT_TRUE(std::ranges::find(names, "SimpleTestMigrator3") != names.end());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_F(MultipleMigratorRegisterTests, Description)
|
TEST_F(MultipleMigratorRegisterTests, Description)
|
||||||
@@ -181,3 +196,21 @@ TEST_F(MultipleMigratorRegisterTests, MigrateNormalMigrator)
|
|||||||
EXPECT_CALL(*backend_, writeMigratorStatus("SimpleTestMigrator", "Migrated")).Times(1);
|
EXPECT_CALL(*backend_, writeMigratorStatus("SimpleTestMigrator", "Migrated")).Times(1);
|
||||||
EXPECT_NO_THROW(migratorRegister->runMigrator("SimpleTestMigrator", gCfg.getObject("migration")));
|
EXPECT_NO_THROW(migratorRegister->runMigrator("SimpleTestMigrator", gCfg.getObject("migration")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_F(MultipleMigratorRegisterTests, canBlock)
|
||||||
|
{
|
||||||
|
auto canBlock = migratorRegister->canMigratorBlockClio("SimpleTestMigrator");
|
||||||
|
EXPECT_TRUE(canBlock);
|
||||||
|
EXPECT_TRUE(*canBlock);
|
||||||
|
|
||||||
|
canBlock = migratorRegister->canMigratorBlockClio("SimpleTestMigrator2");
|
||||||
|
EXPECT_TRUE(canBlock);
|
||||||
|
EXPECT_FALSE(*canBlock);
|
||||||
|
|
||||||
|
canBlock = migratorRegister->canMigratorBlockClio("SimpleTestMigrator3");
|
||||||
|
EXPECT_TRUE(canBlock);
|
||||||
|
EXPECT_FALSE(*canBlock);
|
||||||
|
|
||||||
|
canBlock = migratorRegister->canMigratorBlockClio("NotAMigrator");
|
||||||
|
EXPECT_FALSE(canBlock);
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user