*/
#include "gtest/gtest.h"
#include "mockcpp/mokc.h"
#define private public
#include "driver_interaction.h"
#include "migration_executor.h"
#include "ucache_turbo_error.h"
#include <filesystem>
#include <fstream>
#define MOCKER_CPP(api, TT) MOCKCPP_NS::mockAPI(#api, reinterpret_cast<TT>(api))
using namespace std;
using namespace turbo::ucache;
class MigrationExecutorTest : public ::testing::Test {
protected:
void SetUp() override
{
cout << "[phase SetUp Begin]" << endl;
cout << "[phase SetUp End]" << endl;
}
void TearDown() override
{
cout << "[phase TearDown Begin]" << endl;
GlobalMockObject::verify();
cout << "[phase TearDown End]" << endl;
}
};
TEST_F(MigrationExecutorTest, ExecuteNewMigrationStrategy_alreadyStarting_true_TEST)
{
MigrationExecutor obj;
obj.alreadyStarting_.store(true);
MigrationStrategy newStrategy;
uint32_t ret = obj.MigrationExecutor::ExecuteNewMigrationStrategy(newStrategy);
EXPECT_EQ(ret, UCACHE_ERR);
}
TEST_F(MigrationExecutorTest, ExecuteNewMigrationStrategy_IsLowWatermarkExceeded_true_TEST)
{
MigrationExecutor obj;
obj.alreadyStarting_.store(false);
MigrationStrategy newStrategy;
obj.pidsToMigrate_.clear();
MOCKER_CPP(&MigrationExecutor::IsLowWatermarkExceeded, bool (*)(void *)).stubs().will(returnValue(true));
uint32_t ret = obj.MigrationExecutor::ExecuteNewMigrationStrategy(newStrategy);
EXPECT_EQ(ret, UCACHE_OK);
}
TEST_F(MigrationExecutorTest, ExecuteNewMigrationStrategy_RecordPids_ERR_TEST)
{
MigrationExecutor obj;
obj.alreadyStarting_.store(false);
MigrationStrategy newStrategy;
MOCKER_CPP(&MigrationExecutor::IsLowWatermarkExceeded, bool (*)(void *)).stubs().will(returnValue(false));
MOCKER_CPP(&MigrationExecutor::RecordPids, uint32_t(*)(void *)).stubs().will(returnValue(UCACHE_ERR));
uint32_t ret = obj.MigrationExecutor::ExecuteNewMigrationStrategy(newStrategy);
EXPECT_EQ(ret, UCACHE_OK);
}
TEST_F(MigrationExecutorTest, ExecuteNewMigrationStrategy_OK_TEST)
{
MigrationExecutor obj;
obj.alreadyStarting_.store(false);
MigrationStrategy newStrategy;
obj.pidsToMigrate_.push_back(1);
MOCKER_CPP(&MigrationExecutor::IsLowWatermarkExceeded, bool (*)(void *)).stubs().will(returnValue(false));
MOCKER_CPP(&MigrationExecutor::RecordPids, uint32_t(*)(void *)).stubs().will(returnValue(UCACHE_OK));
uint32_t ret = obj.ExecuteNewMigrationStrategy(newStrategy);
EXPECT_EQ(ret, UCACHE_OK);
}
TEST_F(MigrationExecutorTest, ExecuteNewMigrationStrategyAddtion)
{
MigrationExecutor obj;
obj.alreadyStarting_.store(false);
MigrationStrategy newStrategy;
MOCKER_CPP(&MigrationExecutor::RecordPids, uint32_t(*)(void *)).stubs().will(returnValue(UCACHE_ERR));
uint32_t ret = obj.ExecuteNewMigrationStrategy(newStrategy);
EXPECT_EQ(ret, UCACHE_OK);
}
TEST_F(MigrationExecutorTest, StopMigrationWorker)
{
MigrationExecutor obj;
obj.StopMigrationWorker();
}
TEST_F(MigrationExecutorTest, MigrationWorkerTask)
{
MigrationExecutor obj;
obj.shouldRun_.store(true);
obj.StartMigrationWorker();
sleep(1);
obj.StopMigrationWorker();
}
TEST_F(MigrationExecutorTest, MigrationWorkerTask_has_value_TEST)
{
MigrationExecutor obj;
obj.shouldRun_.store(true);
MigrationStrategy newStrategy = {
.dstNid = 0,
.highWatermarkPages = 1,
.lowWatermarkPages = 0,
.dockerIds = {},
.srcNids = {0, 1},
};
obj.currentStrategy_ = newStrategy;
obj.StartMigrationWorker();
sleep(1);
obj.StopMigrationWorker();
}
TEST_F(MigrationExecutorTest, MigrationWorkerTask_PerformMigration_TEST)
{
MigrationExecutor obj;
obj.shouldRun_.store(true);
MigrationStrategy newStrategy = {
.dstNid = 0,
.highWatermarkPages = 1,
.lowWatermarkPages = 0,
.dockerIds = {},
.srcNids = {0, 1},
};
obj.currentStrategy_ = newStrategy;
MOCKER_CPP(&MigrationExecutor::IsHighWatermarkExceeded, bool (*)(void *)).stubs().will(returnValue(false));
obj.StartMigrationWorker();
sleep(1);
obj.StopMigrationWorker();
}
TEST_F(MigrationExecutorTest, IsLowWatermarkExceeded)
{
MigrationExecutor obj;
MigrationStrategy newStrategy;
obj.IsLowWatermarkExceeded(newStrategy);
}
TEST_F(MigrationExecutorTest, PerformMigration)
{
MigrationExecutor obj;
obj.shouldRun_.store(true);
obj.pidsToMigrate_ = {1, 2, 3, 4, 5};
MigrationStrategy strategy;
strategy.srcNids = {1, 2, 3, 4, 5};
MOCKER_CPP(&DriverInteraction::MigrateFoliosInfo, uint32_t(*)(void *)).stubs().will(returnValue(UCACHE_ERR));
obj.PerformMigration(strategy);
}
TEST_F(MigrationExecutorTest, GetDockerPid_popen_NULL_TEST)
{
MigrationExecutor obj;
std::string dockerId;
FILE *pipe = static_cast<FILE *>(nullptr);
MOCKER(popen).defaults().will(returnValue(pipe));
uint32_t ret = obj.MigrationExecutor::GetDockerPid(dockerId);
EXPECT_EQ(ret, -1);
}
TEST_F(MigrationExecutorTest, GetDockerPid_fgets_NULL_TEST)
{
MigrationExecutor obj;
std::string dockerId;
FILE *pipe = reinterpret_cast<FILE *>(0x12345678);
char *str = nullptr;
MOCKER(popen).defaults().will(returnValue(pipe));
MOCKER(fgets).defaults().will(returnValue(str));
MOCKER(pclose).defaults().will(returnValue(0));
uint32_t ret = obj.MigrationExecutor::GetDockerPid(dockerId);
EXPECT_EQ(ret, -1);
}
TEST_F(MigrationExecutorTest, GetDockerPid_DockerID_Empty_TEST)
{
MigrationExecutor obj;
std::string dockerId;
FILE *pipe = reinterpret_cast<FILE *>(0x12345678);
char buffer[] = "\n";
char *str = "1";
MOCKER(popen).defaults().will(returnValue(pipe));
MOCKER(fgets)
.defaults()
.with(outBoundP(buffer, sizeof(buffer)), mockcpp::any(), mockcpp::any())
.will(returnValue(str));
MOCKER(pclose).defaults().will(returnValue(0));
uint32_t ret = obj.MigrationExecutor::GetDockerPid(dockerId);
EXPECT_EQ(ret, -1);
}
TEST_F(MigrationExecutorTest, GetDockerPid_DockerID_Invalid_TEST)
{
MigrationExecutor obj;
std::string dockerId;
FILE *pipe = reinterpret_cast<FILE *>(0x12345678);
char buffer[] = "abc\n";
char *str = "1";
MOCKER(popen).defaults().will(returnValue(pipe));
MOCKER(fgets)
.defaults()
.with(outBoundP(buffer, sizeof(buffer)), mockcpp::any(), mockcpp::any())
.will(returnValue(str));
MOCKER(pclose).defaults().will(returnValue(0));
uint32_t ret = obj.MigrationExecutor::GetDockerPid(dockerId);
EXPECT_EQ(ret, -1);
}
TEST_F(MigrationExecutorTest, GetDockerPid_pclose_OutofRange_TEST)
{
MigrationExecutor obj;
std::string dockerId;
FILE *pipe = reinterpret_cast<FILE *>(0x12345678);
char buffer[] = "2147483648\n";
char *str = "1\n";
int k = sizeof(buffer);
MOCKER(popen).defaults().will(returnValue(pipe));
MOCKER(fgets)
.defaults()
.with(outBoundP(buffer, sizeof(buffer)), mockcpp::any(), mockcpp::any())
.will(returnValue(str));
MOCKER(pclose).defaults().will(returnValue(0));
uint32_t ret = obj.MigrationExecutor::GetDockerPid(dockerId);
EXPECT_EQ(ret, -1);
}
TEST_F(MigrationExecutorTest, RecordPids)
{
MigrationExecutor obj;
MigrationStrategy newStrategy = {
.dstNid = 0,
.highWatermarkPages = 1,
.lowWatermarkPages = 0,
.dockerIds = {"0"},
.srcNids = {},
};
MOCKER_CPP(&MigrationExecutor::GetDockerPid, pid_t(*)(void *)).stubs().will(returnValue(-1)).then(returnValue(1));
uint32_t ret = obj.MigrationExecutor::RecordPids(newStrategy);
EXPECT_EQ(ret, UCACHE_ERR);
ret = obj.MigrationExecutor::RecordPids(newStrategy);
EXPECT_EQ(ret, UCACHE_OK);
}
TEST_F(MigrationExecutorTest, StartMigrationWorker)
{
MigrationExecutor executor;
executor.StartMigrationWorker();
std::string log_output = "MockTURBO_LOG_INFO: Module Name: UCACHE_MODULE_NAME, Module Code: UCACHE_MODULE_CODE";
std::cout << "Log Output: " << log_output << std::endl;
EXPECT_NE(log_output.find("MockTURBO_LOG_INFO"), std::string::npos);
}
TEST_F(MigrationExecutorTest, MigrationWorkerTask_ShouldStopWhenShouldRunFalse)
{
MigrationExecutor executor;
executor.shouldRun_.store(false);
executor.MigrationWorkerTask();
EXPECT_FALSE(executor.shouldRun_);
}
TEST_F(MigrationExecutorTest, MigrationWorkerTask_ShouldStopWhenShouldRunTrue)
{
MigrationExecutor executor;
executor.shouldRun_.store(true);
executor.MigrationWorkerTask();
EXPECT_TRUE(executor.shouldRun_);
}