540 lines
16 KiB
C++
540 lines
16 KiB
C++
#include <gtest/gtest.h>
|
|
#include <thread>
|
|
#include <chrono>
|
|
#include <atomic>
|
|
#include <condition_variable>
|
|
#include <mutex>
|
|
#include <filesystem>
|
|
#include <fstream>
|
|
|
|
#include "process_monitor.h"
|
|
#include "process_types.h"
|
|
|
|
using namespace alicho;
|
|
|
|
// ============================================================================
|
|
// 测试辅助工具
|
|
// ============================================================================
|
|
|
|
// 监控回调计数器
|
|
struct monitor_callback_counter {
|
|
std::atomic<int> state_change_count{0};
|
|
std::atomic<int> resource_update_count{0};
|
|
std::atomic<int> error_count{0};
|
|
|
|
std::mutex mutex;
|
|
std::condition_variable cv;
|
|
|
|
process_state last_state{process_state::UNKNOWN};
|
|
process_error last_error{process_error::SUCCESS};
|
|
std::string last_error_message;
|
|
process_resource_usage last_resource_usage;
|
|
|
|
void reset() {
|
|
state_change_count = 0;
|
|
resource_update_count = 0;
|
|
error_count = 0;
|
|
last_state = process_state::UNKNOWN;
|
|
last_error = process_error::SUCCESS;
|
|
last_error_message.clear();
|
|
last_resource_usage = {};
|
|
}
|
|
|
|
bool wait_for_state_change(int expected_count, std::chrono::milliseconds timeout = std::chrono::milliseconds(5000)) {
|
|
std::unique_lock<std::mutex> lock(mutex);
|
|
return cv.wait_for(lock, timeout, [this, expected_count]() {
|
|
return state_change_count >= expected_count;
|
|
});
|
|
}
|
|
|
|
bool wait_for_resource_update(int expected_count, std::chrono::milliseconds timeout = std::chrono::milliseconds(5000)) {
|
|
std::unique_lock<std::mutex> lock(mutex);
|
|
return cv.wait_for(lock, timeout, [this, expected_count]() {
|
|
return resource_update_count >= expected_count;
|
|
});
|
|
}
|
|
|
|
bool wait_for_error(int expected_count, std::chrono::milliseconds timeout = std::chrono::milliseconds(5000)) {
|
|
std::unique_lock<std::mutex> lock(mutex);
|
|
return cv.wait_for(lock, timeout, [this, expected_count]() {
|
|
return error_count >= expected_count;
|
|
});
|
|
}
|
|
};
|
|
|
|
// 全局监控回调计数器
|
|
static monitor_callback_counter g_monitor_counter;
|
|
|
|
// 监控回调函数
|
|
void monitor_state_change_callback(const process_info& info, process_state new_state) {
|
|
std::lock_guard<std::mutex> lock(g_monitor_counter.mutex);
|
|
g_monitor_counter.state_change_count++;
|
|
g_monitor_counter.last_state = new_state;
|
|
g_monitor_counter.cv.notify_all();
|
|
}
|
|
|
|
void monitor_resource_callback(const process_info& info, const process_resource_usage& usage) {
|
|
std::lock_guard<std::mutex> lock(g_monitor_counter.mutex);
|
|
g_monitor_counter.resource_update_count++;
|
|
g_monitor_counter.last_resource_usage = usage;
|
|
g_monitor_counter.cv.notify_all();
|
|
}
|
|
|
|
void monitor_error_callback(const process_info& info, process_error error, const std::string& message) {
|
|
std::lock_guard<std::mutex> lock(g_monitor_counter.mutex);
|
|
g_monitor_counter.error_count++;
|
|
g_monitor_counter.last_error = error;
|
|
g_monitor_counter.last_error_message = message;
|
|
g_monitor_counter.cv.notify_all();
|
|
}
|
|
|
|
// 创建一个简单的测试可执行文件
|
|
std::string create_monitor_test_executable() {
|
|
std::string exe_path;
|
|
|
|
#ifdef _WIN32
|
|
exe_path = "monitor_test_process.bat";
|
|
std::ofstream bat_file(exe_path);
|
|
bat_file << "@echo off\n";
|
|
bat_file << "timeout /t 3 /nobreak > nul\n"; // 运行3秒然后退出
|
|
bat_file << "exit 0\n";
|
|
bat_file.close();
|
|
#else
|
|
exe_path = "./monitor_test_process.sh";
|
|
std::ofstream script_file(exe_path);
|
|
script_file << "#!/bin/bash\n";
|
|
script_file << "sleep 3\n"; // 运行3秒然后退出
|
|
script_file << "exit 0\n";
|
|
script_file.close();
|
|
|
|
// 设置执行权限
|
|
std::filesystem::permissions(exe_path, std::filesystem::perms::owner_exec, std::filesystem::perm_options::add);
|
|
#endif
|
|
|
|
return exe_path;
|
|
}
|
|
|
|
// 创建一个长时间运行的测试可执行文件
|
|
std::string create_long_running_executable() {
|
|
std::string exe_path;
|
|
|
|
#ifdef _WIN32
|
|
exe_path = "long_running_test.bat";
|
|
std::ofstream bat_file(exe_path);
|
|
bat_file << "@echo off\n";
|
|
bat_file << "timeout /t 10 /nobreak > nul\n"; // 运行10秒
|
|
bat_file << "exit 0\n";
|
|
bat_file.close();
|
|
#else
|
|
exe_path = "./long_running_test.sh";
|
|
std::ofstream script_file(exe_path);
|
|
script_file << "#!/bin/bash\n";
|
|
script_file << "sleep 10\n"; // 运行10秒
|
|
script_file << "exit 0\n";
|
|
script_file.close();
|
|
|
|
// 设置执行权限
|
|
std::filesystem::permissions(exe_path, std::filesystem::perms::owner_exec, std::filesystem::perm_options::add);
|
|
#endif
|
|
|
|
return exe_path;
|
|
}
|
|
|
|
// 创建一个模拟进程信息的辅助函数
|
|
std::unique_ptr<process_info> create_mock_process_info(const std::string& executable_path) {
|
|
auto info = std::make_unique<process_info>();
|
|
info->id = 1001;
|
|
info->name = "mock_process";
|
|
info->executable_path = executable_path;
|
|
info->type = sandbox_type::HOST;
|
|
info->state = process_state::STARTING;
|
|
info->start_time = std::chrono::system_clock::now();
|
|
return info;
|
|
}
|
|
|
|
// ============================================================================
|
|
// 基础功能测试
|
|
// ============================================================================
|
|
|
|
class ProcessMonitorTest : public ::testing::Test {
|
|
protected:
|
|
void SetUp() override {
|
|
// 重置回调计数器
|
|
g_monitor_counter.reset();
|
|
|
|
// 创建测试可执行文件
|
|
test_executable_ = create_monitor_test_executable();
|
|
long_running_executable_ = create_long_running_executable();
|
|
}
|
|
|
|
void TearDown() override {
|
|
// 清理测试文件
|
|
try {
|
|
if (std::filesystem::exists(test_executable_)) {
|
|
std::filesystem::remove(test_executable_);
|
|
}
|
|
if (std::filesystem::exists(long_running_executable_)) {
|
|
std::filesystem::remove(long_running_executable_);
|
|
}
|
|
} catch (...) {
|
|
// 忽略清理错误
|
|
}
|
|
}
|
|
|
|
std::string test_executable_;
|
|
std::string long_running_executable_;
|
|
};
|
|
|
|
/**
|
|
* @brief 测试进程监控器的创建
|
|
*/
|
|
TEST_F(ProcessMonitorTest, MonitorCreation) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
|
|
// 创建监控器
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 初始状态应该是未运行
|
|
EXPECT_FALSE(monitor.is_running());
|
|
}
|
|
|
|
/**
|
|
* @brief 测试监控器启动和停止
|
|
*/
|
|
TEST_F(ProcessMonitorTest, StartStopMonitor) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 启动监控器
|
|
auto start_result = monitor.start();
|
|
EXPECT_EQ(start_result, process_error::SUCCESS);
|
|
EXPECT_TRUE(monitor.is_running());
|
|
|
|
// 等待一段时间确保监控器运行
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
|
|
|
// 停止监控器
|
|
auto stop_result = monitor.stop();
|
|
EXPECT_EQ(stop_result, process_error::SUCCESS);
|
|
EXPECT_FALSE(monitor.is_running());
|
|
}
|
|
|
|
/**
|
|
* @brief 测试重复启动监控器
|
|
*/
|
|
TEST_F(ProcessMonitorTest, DuplicateStart) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 第一次启动
|
|
auto result1 = monitor.start();
|
|
EXPECT_EQ(result1, process_error::SUCCESS);
|
|
EXPECT_TRUE(monitor.is_running());
|
|
|
|
// 尝试重复启动
|
|
auto result2 = monitor.start();
|
|
EXPECT_EQ(result2, process_error::PROCESS_ALREADY_RUNNING);
|
|
|
|
// 清理
|
|
monitor.stop();
|
|
}
|
|
|
|
/**
|
|
* @brief 测试停止未运行的监控器
|
|
*/
|
|
TEST_F(ProcessMonitorTest, StopNotRunningMonitor) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 尝试停止未运行的监控器
|
|
auto result = monitor.stop();
|
|
EXPECT_EQ(result, process_error::PROCESS_NOT_RUNNING);
|
|
}
|
|
|
|
/**
|
|
* @brief 测试设置监控间隔
|
|
*/
|
|
TEST_F(ProcessMonitorTest, SetMonitorInterval) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 设置监控间隔
|
|
auto new_interval = std::chrono::milliseconds(500);
|
|
monitor.set_monitor_interval(new_interval);
|
|
|
|
// 启动监控器
|
|
auto result = monitor.start();
|
|
EXPECT_EQ(result, process_error::SUCCESS);
|
|
|
|
// 等待一段时间
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
}
|
|
|
|
// ============================================================================
|
|
// 回调功能测试
|
|
// ============================================================================
|
|
|
|
/**
|
|
* @brief 测试状态变化回调
|
|
*/
|
|
TEST_F(ProcessMonitorTest, StateChangeCallback) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 设置状态变化回调
|
|
monitor.set_state_change_callback(monitor_state_change_callback);
|
|
|
|
// 启动监控器
|
|
monitor.start();
|
|
|
|
// 手动更新状态
|
|
auto update_result = monitor.update_status();
|
|
EXPECT_EQ(update_result, process_error::SUCCESS);
|
|
|
|
// 等待一段时间让回调被触发
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
|
|
// 注意:由于没有真实进程,状态变化回调可能不会被触发
|
|
// 这里主要测试回调设置是否正常工作
|
|
}
|
|
|
|
/**
|
|
* @brief 测试资源使用回调
|
|
*/
|
|
TEST_F(ProcessMonitorTest, ResourceCallback) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 设置资源使用回调
|
|
monitor.set_resource_callback(monitor_resource_callback);
|
|
|
|
// 启动监控器
|
|
monitor.start();
|
|
|
|
// 等待一段时间
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
|
|
// 注意:由于没有真实进程,资源回调可能不会被触发
|
|
// 这里主要测试回调设置是否正常工作
|
|
}
|
|
|
|
/**
|
|
* @brief 测试错误回调
|
|
*/
|
|
TEST_F(ProcessMonitorTest, ErrorCallback) {
|
|
auto process_info = create_mock_process_info("non_existent_executable.exe");
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 设置错误回调
|
|
monitor.set_error_callback(monitor_error_callback);
|
|
|
|
// 启动监控器
|
|
monitor.start();
|
|
|
|
// 手动更新状态(应该会检测到进程不存在)
|
|
monitor.update_status();
|
|
|
|
// 等待错误回调
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
|
|
// 验证错误是否被检测到(虽然可能没有真实的进程错误)
|
|
}
|
|
|
|
/**
|
|
* @brief 测试所有回调同时设置
|
|
*/
|
|
TEST_F(ProcessMonitorTest, AllCallbacks) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 设置所有回调
|
|
monitor.set_state_change_callback(monitor_state_change_callback);
|
|
monitor.set_resource_callback(monitor_resource_callback);
|
|
monitor.set_error_callback(monitor_error_callback);
|
|
|
|
// 启动监控器
|
|
auto result = monitor.start();
|
|
EXPECT_EQ(result, process_error::SUCCESS);
|
|
|
|
// 等待一段时间
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
|
|
|
// 手动更新状态
|
|
monitor.update_status();
|
|
|
|
// 等待更多时间
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(300));
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
}
|
|
|
|
// ============================================================================
|
|
// 监控功能测试
|
|
// ============================================================================
|
|
|
|
/**
|
|
* @brief 测试手动状态更新
|
|
*/
|
|
TEST_F(ProcessMonitorTest, ManualStatusUpdate) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 设置回调
|
|
monitor.set_state_change_callback(monitor_state_change_callback);
|
|
|
|
// 启动监控器
|
|
monitor.start();
|
|
|
|
// 手动更新状态
|
|
auto result = monitor.update_status();
|
|
EXPECT_EQ(result, process_error::SUCCESS);
|
|
|
|
// 等待一段时间
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
}
|
|
|
|
/**
|
|
* @brief 测试进程资源使用监控
|
|
*/
|
|
TEST_F(ProcessMonitorTest, ResourceUsageMonitoring) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 设置资源回调
|
|
monitor.set_resource_callback(monitor_resource_callback);
|
|
|
|
// 启动监控器
|
|
monitor.start();
|
|
|
|
// 等待资源更新
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
|
|
// 注意:由于没有真实进程,资源统计可能为零
|
|
// 这里主要测试监控机制是否正常工作
|
|
}
|
|
|
|
/**
|
|
* @brief 测试监控器析构函数
|
|
*/
|
|
TEST_F(ProcessMonitorTest, MonitorDestructor) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
|
|
{
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 启动监控器
|
|
monitor.start();
|
|
EXPECT_TRUE(monitor.is_running());
|
|
|
|
// 监控器会在析构时自动停止
|
|
}
|
|
|
|
// 监控器已经析构,应该已经停止
|
|
// 我们无法直接验证,但这测试了析构函数不会崩溃
|
|
SUCCEED();
|
|
}
|
|
|
|
// ============================================================================
|
|
// 异常情况测试
|
|
// ============================================================================
|
|
|
|
/**
|
|
* @brief 测试空进程信息的监控
|
|
*/
|
|
TEST_F(ProcessMonitorTest, NullProcessMonitoring) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
|
|
// 清空进程对象(模拟无效进程)
|
|
process_info->process.reset();
|
|
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 启动监控器
|
|
auto result = monitor.start();
|
|
EXPECT_EQ(result, process_error::SUCCESS);
|
|
|
|
// 更新状态(应该能处理空进程对象)
|
|
auto update_result = monitor.update_status();
|
|
EXPECT_EQ(update_result, process_error::SUCCESS);
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
}
|
|
|
|
/**
|
|
* @brief 测试监控频率设置
|
|
*/
|
|
TEST_F(ProcessMonitorTest, MonitoringFrequency) {
|
|
auto process_info = create_mock_process_info(test_executable_);
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 设置较高的监控频率
|
|
monitor.set_monitor_interval(std::chrono::milliseconds(100));
|
|
|
|
// 设置回调
|
|
monitor.set_state_change_callback(monitor_state_change_callback);
|
|
|
|
// 启动监控器
|
|
monitor.start();
|
|
|
|
// 运行一段时间
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
|
|
// 验证监控器正常运行
|
|
SUCCEED();
|
|
}
|
|
|
|
/**
|
|
* @brief 测试监控器异常处理
|
|
*/
|
|
TEST_F(ProcessMonitorTest, ExceptionHandling) {
|
|
auto process_info = create_mock_process_info("invalid_path/non_existent.exe");
|
|
process_monitor monitor(*process_info);
|
|
|
|
// 设置错误回调
|
|
monitor.set_error_callback(monitor_error_callback);
|
|
|
|
// 启动监控器
|
|
auto result = monitor.start();
|
|
EXPECT_EQ(result, process_error::SUCCESS);
|
|
|
|
// 等待一段时间让监控器检测到问题
|
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
|
|
|
// 停止监控器
|
|
monitor.stop();
|
|
|
|
// 监控器应该能够处理异常情况而不崩溃
|
|
SUCCEED();
|
|
}
|
|
|
|
// ============================================================================
|
|
// 测试主入口
|
|
// ============================================================================
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
} |