* Copyright (c) Huawei Technologies Co., Ltd. 2025-2025. All rights reserved.
*/
#include <filesystem>
#include <fstream>
#include <iostream>
#include <string>
#include <gtest/gtest.h>
#include <mockcpp/GlobalMockObject.h>
#include <mockcpp/mockcpp.hpp>
#include "cmd_executor.h"
#include "optimizer/tuner/vcpu_isolate_tuner.h"
TEST(VCPUIsolTunerTest, GetName)
{
VCPUIsolTuner tuner;
EXPECT_EQ(tuner.name(), "Exclusive vCPU");
}
TEST(VCPUIsolTunerTest, GetCategory)
{
VCPUIsolTuner tuner;
EXPECT_EQ(tuner.category(), "CPU BOUND");
}
TEST(VCPUIsolTunerTest, GetPrinciple)
{
VCPUIsolTuner tuner;
EXPECT_EQ(tuner.principle(), "Frequent preemption of the physical machine's processes on the CPU allocated to "
"the virtual machine leads to CPU-side bubbles or slow execution.");
}
TEST(VCPUIsolTunerTest, GetAdvice)
{
VCPUIsolTuner tuner;
EXPECT_EQ(tuner.advice(),
"Enable Exclusive vCPU. The vCPU can only be scheduled within the allocated virtual machine.");
}
TEST(VCPUIsolTunerTest, ApplyAdvice)
{
testing::internal::CaptureStdout();
VCPUIsolTuner tuner;
tuner.apply();
std::string output = testing::internal::GetCapturedStdout();
EXPECT_NE(output.find("Enable Exclusive vCPU"), std::string::npos);
}
TEST(VCPUIsolTunerTest, OpenNonExistentFile)
{
VCPUIsolTuner tuner;
try {
tuner.openDataFile("non_existent.json");
FAIL() << "Expected exception not thrown";
} catch (const std::exception &e) {
}
}
TEST(VCPUIsolTunerTest, ParseInvalidJson)
{
const std::string invalidJson = {"invalid_key"};
VCPUIsolTuner tuner;
EXPECT_THROW(tuner.parseHostData(invalidJson), std::runtime_error);
}
TEST(VCPUIsolTunerTest, ParseValidJsonCase1)
{
const std::string validJson = R"({
"guest_name": "test",
"data_table": {
"qemu_migration_count": 10
},
"interval": 100
})";
VCPUIsolTuner tuner;
EXPECT_NO_THROW(tuner.parseHostData(validJson));
}
TEST(VCPUIsolTunerTest, ParseValidJsonCase2)
{
const std::string validJson = R"({
"guest_name": "test",
"data_table": {
"qemu_migration_count": 10
},
"interval": -1
})";
VCPUIsolTuner tuner;
EXPECT_THROW(tuner.parseHostData(validJson), std::runtime_error);
}
TEST(VCPUIsolTunerTest, ParseInvalidJsonCaseWithoutGuestname)
{
const std::string validJson = R"({
"data_table": {
"host_preempt_vmcore_count": 10
},
"interval": 100
})";
VCPUIsolTuner tuner;
EXPECT_THROW(tuner.parseHostData(validJson), std::runtime_error);
}
TEST(VCPUIsolTunerTest, ParseInvalidJsonWithoutInterval)
{
const std::string validJson = R"({
"guest_name": "test",
"data_table": {
"host_preempt_vmcore_count": 10
}
})";
VCPUIsolTuner tuner;
EXPECT_THROW(tuner.parseHostData(validJson), std::runtime_error);
}
TEST(VCPUIsolTunerTest, ParseValidJsonWithStrInterval)
{
const std::string validJson = R"({
"guest_name": "test",
"data_table": {
"host_preempt_vmcore_count": 10
},
"interval": "100"
})";
VCPUIsolTuner tuner;
EXPECT_THROW(tuner.parseHostData(validJson), std::runtime_error);
}
TEST(VCPUIsolTunerTest, ParseValidJsonWithIntervalIsZero)
{
const std::string validJson = R"({
"guest_name": "test",
"data_table": {
"host_preempt_vmcore_count": 10
},
"interval": 0
})";
VCPUIsolTuner tuner;
EXPECT_THROW(tuner.parseHostData(validJson), std::runtime_error);
}
TEST(VCPUIsolTunerTest, TestFindLastInferCase1)
{
char ret_vcpu[] = "abc";
char *cur_vcpu = ret_vcpu;
MOCKER(realpath).stubs().with(any()).will(returnValue(cur_vcpu));
VCPUIsolTuner tuner;
EXPECT_NO_THROW(tuner.findLastInfer());
mockcpp::GlobalMockObject::verify();
mockcpp::GlobalMockObject::reset();
}
TEST(VCPUIsolTunerTest, CheckCase1)
{
VCPUIsolTuner tuner;
std::string cmdOutput = "";
MOCKER(&CmdExecutor::runCommand).stubs().with(any()).will(returnValue(std::make_pair(false, cmdOutput)));
EXPECT_TRUE(tuner.check());
mockcpp::GlobalMockObject::verify();
mockcpp::GlobalMockObject::reset();
}
TEST(VCPUIsolTunerTest, CheckCase2)
{
std::string filename = "/var/ubs-opt/data/data.json";
std::ofstream outfile(filename);
outfile << "{\"timestamp\":123,\"guest_name\":\"\",\"interval\":30,"
"\"data_table\": {\"host_preempt_vmcore_count\":200, \"ipi_interrupt\":{\"ipi_count\":0,"
"\"transmission_delay\":12,\"processing_delay\":11},\"host_preempt_vmcore_count\":8}}"
<< std::endl;
outfile.close();
VCPUIsolTuner tuner;
std::string cmdOutput = "isolcpus=1, nohz_full=2";
MOCKER(&CmdExecutor::runCommand).stubs().with(any()).will(returnValue(std::make_pair(true, cmdOutput)));
EXPECT_TRUE(tuner.check());
mockcpp::GlobalMockObject::verify();
mockcpp::GlobalMockObject::reset();
}
TEST(VCPUIsolTunerTest, CheckWithValidCmdOutput)
{
VCPUIsolTuner tuner;
std::string cmdOutput = "isolcpus=1, nohz_full=2, rcu_nocbs=3";
MOCKER(&CmdExecutor::runCommand).stubs().with(any()).will(returnValue(std::make_pair(true, cmdOutput)));
EXPECT_FALSE(tuner.check());
mockcpp::GlobalMockObject::verify();
mockcpp::GlobalMockObject::reset();
}