Files
clio/tests/unit/cluster/CacheLoaderDeciderTests.cpp
Alex Kremer 4e85398aed chore: Remove more copyrights from code (#3012)
More copyrights detected following #2975
2026-03-24 15:33:12 +00:00

205 lines
7.1 KiB
C++

#include "cluster/Backend.hpp"
#include "cluster/CacheLoaderDecider.hpp"
#include "cluster/ClioNode.hpp"
#include "util/MockLedgerCacheLoadingState.hpp"
#include <boost/asio/thread_pool.hpp>
#include <boost/uuid/uuid.hpp>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <algorithm>
#include <chrono>
#include <cstdint>
#include <memory>
#include <string>
#include <utility>
#include <vector>
using namespace cluster;
enum class CacheLoaderExpectedAction { AllowLoading, NoAction };
struct CacheLoaderNodeParams {
uint8_t uuidValue;
bool cacheIsFull = false;
bool cacheIsCurrentlyLoading = false;
};
struct CacheLoaderDeciderTestParams {
std::string testName;
uint8_t selfUuidValue;
std::vector<CacheLoaderNodeParams> nodes;
CacheLoaderExpectedAction expectedAction;
bool useEmptyClusterData = false;
};
struct CacheLoaderDeciderTest : testing::TestWithParam<CacheLoaderDeciderTestParams> {
~CacheLoaderDeciderTest() override
{
ctx.stop();
ctx.join();
}
boost::asio::thread_pool ctx{1};
std::unique_ptr<MockLedgerCacheLoadingState> cacheLoadingState =
std::make_unique<MockLedgerCacheLoadingState>();
MockLedgerCacheLoadingState& cacheLoadingStateRef = *cacheLoadingState;
static ClioNode
makeNode(boost::uuids::uuid const& uuid, bool cacheIsFull, bool cacheIsCurrentlyLoading)
{
return ClioNode{
.uuid = std::make_shared<boost::uuids::uuid>(uuid),
.updateTime = std::chrono::system_clock::now(),
.dbRole = ClioNode::DbRole::NotWriter,
.etlStarted = true,
.cacheIsFull = cacheIsFull,
.cacheIsCurrentlyLoading = cacheIsCurrentlyLoading,
};
}
static boost::uuids::uuid
makeUuid(uint8_t value)
{
boost::uuids::uuid uuid{};
std::ranges::fill(uuid, value);
return uuid;
}
};
TEST_P(CacheLoaderDeciderTest, CacheLoaderSelection)
{
auto const& params = GetParam();
auto const selfUuid = makeUuid(params.selfUuidValue);
CacheLoaderDecider decider{ctx, std::move(cacheLoadingState)};
auto clonedState = std::make_unique<MockLedgerCacheLoadingState>();
switch (params.expectedAction) {
case CacheLoaderExpectedAction::AllowLoading:
EXPECT_CALL(*clonedState, allowLoading());
EXPECT_CALL(cacheLoadingStateRef, clone())
.WillOnce(testing::Return(testing::ByMove(std::move(clonedState))));
break;
case CacheLoaderExpectedAction::NoAction:
if (not params.useEmptyClusterData) {
EXPECT_CALL(cacheLoadingStateRef, clone())
.WillOnce(testing::Return(testing::ByMove(std::move(clonedState))));
}
break;
}
std::shared_ptr<Backend::ClusterData> clusterData;
ClioNode::CUuid selfIdPtr;
if (params.useEmptyClusterData) {
clusterData = std::make_shared<Backend::ClusterData>(
std::unexpected(std::string("Communication failed"))
);
selfIdPtr = std::make_shared<boost::uuids::uuid>(selfUuid);
} else {
std::vector<ClioNode> nodes;
nodes.reserve(params.nodes.size());
for (auto const& nodeParam : params.nodes) {
auto node = makeNode(
makeUuid(nodeParam.uuidValue),
nodeParam.cacheIsFull,
nodeParam.cacheIsCurrentlyLoading
);
if (nodeParam.uuidValue == params.selfUuidValue) {
selfIdPtr = node.uuid;
}
nodes.push_back(std::move(node));
}
clusterData = std::make_shared<Backend::ClusterData>(std::move(nodes));
}
decider.onNewState(selfIdPtr, clusterData);
ctx.join();
}
INSTANTIATE_TEST_SUITE_P(
CacheLoaderDeciderTests,
CacheLoaderDeciderTest,
testing::Values(
CacheLoaderDeciderTestParams{
.testName = "SelfCacheIsFullNoAction",
.selfUuidValue = 0x01,
.nodes =
{{.uuidValue = 0x01, .cacheIsFull = true},
{.uuidValue = 0x02, .cacheIsFull = false}},
.expectedAction = CacheLoaderExpectedAction::NoAction
},
CacheLoaderDeciderTestParams{
.testName = "SelfIsFirstNotFullByUuid_AllowLoading",
.selfUuidValue = 0x01,
.nodes =
{{.uuidValue = 0x01, .cacheIsFull = false},
{.uuidValue = 0x02, .cacheIsFull = false}},
.expectedAction = CacheLoaderExpectedAction::AllowLoading
},
CacheLoaderDeciderTestParams{
.testName = "OtherNodeIsFirstNotFullByUuid_NoAction",
.selfUuidValue = 0x02,
.nodes =
{{.uuidValue = 0x01, .cacheIsFull = false},
{.uuidValue = 0x02, .cacheIsFull = false}},
.expectedAction = CacheLoaderExpectedAction::NoAction
},
CacheLoaderDeciderTestParams{
.testName = "ShuffledNodes_SelfIsFirstNotFull_AllowLoading",
.selfUuidValue = 0x02,
.nodes =
{{.uuidValue = 0x04, .cacheIsFull = false},
{.uuidValue = 0x02, .cacheIsFull = false},
{.uuidValue = 0x03, .cacheIsFull = true}},
.expectedAction = CacheLoaderExpectedAction::AllowLoading
},
CacheLoaderDeciderTestParams{
.testName = "FullNodesExcludedFromElection",
.selfUuidValue = 0x03,
.nodes =
{{.uuidValue = 0x01, .cacheIsFull = true},
{.uuidValue = 0x02, .cacheIsFull = true},
{.uuidValue = 0x03, .cacheIsFull = false}},
.expectedAction = CacheLoaderExpectedAction::AllowLoading
},
CacheLoaderDeciderTestParams{
.testName = "SomeoneIsCurrentlyLoading_NoAction",
.selfUuidValue = 0x01,
.nodes =
{{.uuidValue = 0x01, .cacheIsFull = false, .cacheIsCurrentlyLoading = false},
{.uuidValue = 0x02, .cacheIsFull = false, .cacheIsCurrentlyLoading = true}},
.expectedAction = CacheLoaderExpectedAction::NoAction
},
CacheLoaderDeciderTestParams{
.testName = "SelfIsCurrentlyLoading_NoAction",
.selfUuidValue = 0x01,
.nodes =
{{.uuidValue = 0x01, .cacheIsFull = false, .cacheIsCurrentlyLoading = true},
{.uuidValue = 0x02, .cacheIsFull = false, .cacheIsCurrentlyLoading = false}},
.expectedAction = CacheLoaderExpectedAction::NoAction
},
CacheLoaderDeciderTestParams{
.testName = "SingleNodeCluster_SelfAllowLoading",
.selfUuidValue = 0x01,
.nodes = {{.uuidValue = 0x01, .cacheIsFull = false}},
.expectedAction = CacheLoaderExpectedAction::AllowLoading
},
CacheLoaderDeciderTestParams{
.testName = "EmptyClusterData_NoAction",
.selfUuidValue = 0x01,
.nodes = {},
.expectedAction = CacheLoaderExpectedAction::NoAction,
.useEmptyClusterData = true
}
),
[](testing::TestParamInfo<CacheLoaderDeciderTestParams> const& info) {
return info.param.testName;
}
);