Files
Alicho/tests/unit/plugin_host/sandbox_resource_test.cpp
2025-10-28 10:27:49 +08:00

583 lines
21 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// ================================================================================================
// Audio Backend - 沙盒资源管理测试
// ================================================================================================
#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include "plugin_host/sandbox/sandbox_interface.h"
#include "tests/common/test_fixtures.h"
#include <thread>
#include <chrono>
#include <atomic>
using namespace audio_backend;
using namespace audio_backend::plugin_host;
using namespace std::chrono_literals;
// 创建资源管理测试用的沙盒实现
class ResourceTestingSandbox : public SandboxBase {
public:
explicit ResourceTestingSandbox() : SandboxBase(SandboxType::ProcessLevelIsolation) {}
~ResourceTestingSandbox() override = default;
// 基本方法实现
common::ErrorCode do_initialize() override { return common::ErrorCode::Success; }
common::ErrorCode do_shutdown() override { return common::ErrorCode::Success; }
common::ErrorCode do_start_process(
const std::string& executable_path,
const std::vector<std::string>& arguments,
ProcessId& out_process_id) override {
out_process_id = next_pid_++;
register_process(out_process_id, executable_path);
return common::ErrorCode::Success;
}
common::ErrorCode do_stop_process(ProcessId process_id, bool force) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
unregister_process(process_id);
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
// 接口方法实现
common::ErrorCode suspend_process(ProcessId process_id) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
process_info->state = PluginState::Suspended;
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
common::ErrorCode resume_process(ProcessId process_id) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
process_info->state = PluginState::Running;
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
common::ErrorCode restart_process(ProcessId process_id) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
process_info->state = PluginState::Running;
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
common::ErrorCode wait_for_process(
ProcessId process_id,
std::chrono::milliseconds timeout,
int& exit_code) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
exit_code = 0;
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
// 资源管理重点方法
common::ErrorCode set_resource_limits(
ProcessId process_id,
const ResourceLimits& limits) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
process_limits_[process_id] = limits;
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
common::ErrorCode get_resource_usage(
ProcessId process_id,
PerformanceMetrics& metrics) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
metrics = process_info->metrics;
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
common::ErrorCode enforce_resource_limits(ProcessId process_id) override {
auto* process_info = find_process_info(process_id);
if (process_info) {
// 检查是否设置了资源限制
auto it = process_limits_.find(process_id);
if (it == process_limits_.end()) {
return common::ErrorCode::InvalidOperation;
}
const ResourceLimits& limits = it->second;
// 检查内存限制
if (process_info->current_memory_usage > limits.max_memory_mb * 1024 * 1024) {
notify_resource_limit_exceeded(process_id, "Memory");
if (limits.kill_on_limit) {
notify_process_exited(process_id, -9);
unregister_process(process_id);
}
return common::ErrorCode::ResourceLimitExceeded;
}
// 检查CPU限制
if (process_info->current_cpu_usage > limits.max_cpu_percent) {
notify_resource_limit_exceeded(process_id, "CPU");
if (limits.throttle_on_limit) {
// 模拟CPU限流
process_info->current_cpu_usage = limits.max_cpu_percent;
}
return common::ErrorCode::ResourceLimitExceeded;
}
// 检查线程限制
if (limits.max_threads > 0 && process_info->current_thread_count > limits.max_threads) {
notify_resource_limit_exceeded(process_id, "Threads");
return common::ErrorCode::ResourceLimitExceeded;
}
// 检查文件句柄限制
if (limits.max_file_handles > 0 && process_info->current_file_handle_count > limits.max_file_handles) {
notify_resource_limit_exceeded(process_id, "FileHandles");
return common::ErrorCode::ResourceLimitExceeded;
}
return common::ErrorCode::Success;
}
return common::ErrorCode::InvalidArgument;
}
// 安全管理方法
common::ErrorCode apply_security_settings(
ProcessId process_id,
const SecuritySettings& settings) override {
return common::ErrorCode::Success;
}
bool is_path_accessible(
ProcessId process_id,
const std::string& path) const override {
return true;
}
bool is_network_accessible(ProcessId process_id) const override {
return true;
}
common::ErrorCode execute_platform_specific_operation(
const std::string& operation_name,
const std::vector<std::string>& parameters,
std::string& result) override {
return common::ErrorCode::Success;
}
// 模拟资源使用更新的方法
void set_memory_usage(ProcessId process_id, size_t memory_usage_mb) {
auto* process_info = find_process_info(process_id);
if (process_info) {
process_info->current_memory_usage = memory_usage_mb * 1024 * 1024;
process_info->metrics.memory_usage_mb = memory_usage_mb;
}
}
void set_cpu_usage(ProcessId process_id, double cpu_usage_percent) {
auto* process_info = find_process_info(process_id);
if (process_info) {
process_info->current_cpu_usage = cpu_usage_percent;
process_info->metrics.cpu_usage_percent = cpu_usage_percent;
}
}
void set_thread_count(ProcessId process_id, uint32_t thread_count) {
auto* process_info = find_process_info(process_id);
if (process_info) {
process_info->current_thread_count = thread_count;
process_info->metrics.thread_count = thread_count;
}
}
void set_file_handle_count(ProcessId process_id, uint32_t file_handle_count) {
auto* process_info = find_process_info(process_id);
if (process_info) {
process_info->current_file_handle_count = file_handle_count;
process_info->metrics.file_handle_count = file_handle_count;
}
}
// 设置性能指标
void update_performance_metrics(ProcessId process_id, const PerformanceMetrics& metrics) {
auto* process_info = find_process_info(process_id);
if (process_info) {
process_info->metrics = metrics;
process_info->current_memory_usage = metrics.memory_usage_mb * 1024 * 1024;
process_info->current_cpu_usage = metrics.cpu_usage_percent;
process_info->current_thread_count = metrics.thread_count;
process_info->current_file_handle_count = metrics.file_handle_count;
}
}
// 获取为进程设置的资源限制
ResourceLimits get_process_limits(ProcessId process_id) const {
auto it = process_limits_.find(process_id);
if (it != process_limits_.end()) {
return it->second;
}
return ResourceLimits();
}
private:
std::atomic<ProcessId> next_pid_{1000};
std::map<ProcessId, ResourceLimits> process_limits_;
};
// 沙盒资源管理测试固定装置
class SandboxResourceTest : public test::PluginSandboxTest {
protected:
void SetUp() override {
test::PluginSandboxTest::SetUp();
// 创建沙盒
sandbox_ = std::make_unique<ResourceTestingSandbox>();
// 创建事件回调
callback_ = std::make_shared<::testing::NiceMock<MockSandboxEventCallback>>();
// 初始化沙盒
SandboxConfig config;
config.sandbox_type = SandboxType::ProcessLevelIsolation;
config.enable_resource_monitoring = true;
config.resource_monitoring_interval_ms = 1000;
config.enable_heartbeat = false;
ASSERT_EQ(sandbox_->initialize(config), common::ErrorCode::Success);
// 设置事件回调
sandbox_->set_event_callback(callback_);
}
void TearDown() override {
if (sandbox_->is_initialized()) {
sandbox_->shutdown();
}
sandbox_.reset();
callback_.reset();
test::PluginSandboxTest::TearDown();
}
// 创建默认资源限制
ResourceLimits create_default_limits() {
ResourceLimits limits;
limits.max_memory_mb = 100;
limits.max_cpu_percent = 50.0;
limits.max_threads = 10;
limits.max_file_handles = 100;
limits.max_execution_time_ms = 60000;
limits.kill_on_limit = false;
limits.throttle_on_limit = true;
limits.priority = ProcessPriority::Normal;
return limits;
}
protected:
std::unique_ptr<ResourceTestingSandbox> sandbox_;
std::shared_ptr<MockSandboxEventCallback> callback_;
};
// 测试设置资源限制
TEST_F(SandboxResourceTest, SetResourceLimits) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 创建资源限制
ResourceLimits limits = create_default_limits();
// 设置资源限制
ASSERT_EQ(sandbox_->set_resource_limits(pid, limits), common::ErrorCode::Success);
// 验证资源限制已设置
ResourceLimits actual_limits = sandbox_->get_process_limits(pid);
EXPECT_EQ(actual_limits.max_memory_mb, limits.max_memory_mb);
EXPECT_EQ(actual_limits.max_cpu_percent, limits.max_cpu_percent);
EXPECT_EQ(actual_limits.max_threads, limits.max_threads);
EXPECT_EQ(actual_limits.max_file_handles, limits.max_file_handles);
// 测试无效的进程ID
EXPECT_NE(sandbox_->set_resource_limits(999999, limits), common::ErrorCode::Success);
}
// 测试获取资源使用情况
TEST_F(SandboxResourceTest, GetResourceUsage) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 设置模拟资源使用
PerformanceMetrics metrics;
metrics.memory_usage_mb = 50;
metrics.cpu_usage_percent = 25.0;
metrics.thread_count = 5;
metrics.file_handle_count = 20;
metrics.gpu_usage_percent = 10.0;
metrics.disk_read_bytes_per_sec = 1024 * 1024;
metrics.disk_write_bytes_per_sec = 512 * 1024;
metrics.network_bytes_sent = 10000;
metrics.network_bytes_received = 20000;
sandbox_->update_performance_metrics(pid, metrics);
// 获取资源使用
PerformanceMetrics actual_metrics;
ASSERT_EQ(sandbox_->get_resource_usage(pid, actual_metrics), common::ErrorCode::Success);
// 验证资源使用
EXPECT_EQ(actual_metrics.memory_usage_mb, metrics.memory_usage_mb);
EXPECT_EQ(actual_metrics.cpu_usage_percent, metrics.cpu_usage_percent);
EXPECT_EQ(actual_metrics.thread_count, metrics.thread_count);
EXPECT_EQ(actual_metrics.file_handle_count, metrics.file_handle_count);
EXPECT_EQ(actual_metrics.gpu_usage_percent, metrics.gpu_usage_percent);
EXPECT_EQ(actual_metrics.disk_read_bytes_per_sec, metrics.disk_read_bytes_per_sec);
EXPECT_EQ(actual_metrics.disk_write_bytes_per_sec, metrics.disk_write_bytes_per_sec);
EXPECT_EQ(actual_metrics.network_bytes_sent, metrics.network_bytes_sent);
EXPECT_EQ(actual_metrics.network_bytes_received, metrics.network_bytes_received);
// 测试无效的进程ID
EXPECT_NE(sandbox_->get_resource_usage(999999, actual_metrics), common::ErrorCode::Success);
}
// 测试内存限制执行
TEST_F(SandboxResourceTest, EnforceMemoryLimit) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 设置资源限制
ResourceLimits limits = create_default_limits();
limits.max_memory_mb = 100;
limits.kill_on_limit = true;
ASSERT_EQ(sandbox_->set_resource_limits(pid, limits), common::ErrorCode::Success);
// 设置正常内存使用
sandbox_->set_memory_usage(pid, 50); // 50MB, 低于限制
// 检查资源使用没有超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::Success);
// 验证进程仍然存在
EXPECT_TRUE(sandbox_->is_process_running(pid));
// 设置监控事件调用期望
EXPECT_CALL(*callback_, on_resource_limit_exceeded(pid, "Memory"))
.Times(1);
// 模拟内存使用超过限制
sandbox_->set_memory_usage(pid, 200); // 200MB, 超过限制
// 检查资源使用超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::ResourceLimitExceeded);
// 进程应该已经被终止因为设置了kill_on_limit
EXPECT_FALSE(sandbox_->is_process_running(pid));
}
// 测试CPU限制执行
TEST_F(SandboxResourceTest, EnforceCpuLimit) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 设置资源限制
ResourceLimits limits = create_default_limits();
limits.max_cpu_percent = 50.0;
limits.throttle_on_limit = true;
limits.kill_on_limit = false;
ASSERT_EQ(sandbox_->set_resource_limits(pid, limits), common::ErrorCode::Success);
// 设置正常CPU使用
sandbox_->set_cpu_usage(pid, 25.0); // 25%, 低于限制
// 检查资源使用没有超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::Success);
// 设置监控事件调用期望
EXPECT_CALL(*callback_, on_resource_limit_exceeded(pid, "CPU"))
.Times(1);
// 模拟CPU使用超过限制
sandbox_->set_cpu_usage(pid, 75.0); // 75%, 超过限制
// 检查资源使用超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::ResourceLimitExceeded);
// 验证进程被限流因为设置了throttle_on_limit
PerformanceMetrics metrics;
sandbox_->get_resource_usage(pid, metrics);
EXPECT_EQ(metrics.cpu_usage_percent, 50.0); // 应该被限制在最大值
// 进程应该仍然在运行因为没有设置kill_on_limit
EXPECT_TRUE(sandbox_->is_process_running(pid));
}
// 测试线程限制执行
TEST_F(SandboxResourceTest, EnforceThreadLimit) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 设置资源限制
ResourceLimits limits = create_default_limits();
limits.max_threads = 10;
ASSERT_EQ(sandbox_->set_resource_limits(pid, limits), common::ErrorCode::Success);
// 设置正常线程使用
sandbox_->set_thread_count(pid, 5); // 5线程, 低于限制
// 检查资源使用没有超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::Success);
// 设置监控事件调用期望
EXPECT_CALL(*callback_, on_resource_limit_exceeded(pid, "Threads"))
.Times(1);
// 模拟线程使用超过限制
sandbox_->set_thread_count(pid, 15); // 15线程, 超过限制
// 检查资源使用超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::ResourceLimitExceeded);
}
// 测试文件句柄限制执行
TEST_F(SandboxResourceTest, EnforceFileHandleLimit) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 设置资源限制
ResourceLimits limits = create_default_limits();
limits.max_file_handles = 100;
ASSERT_EQ(sandbox_->set_resource_limits(pid, limits), common::ErrorCode::Success);
// 设置正常文件句柄使用
sandbox_->set_file_handle_count(pid, 50); // 50文件句柄, 低于限制
// 检查资源使用没有超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::Success);
// 设置监控事件调用期望
EXPECT_CALL(*callback_, on_resource_limit_exceeded(pid, "FileHandles"))
.Times(1);
// 模拟文件句柄使用超过限制
sandbox_->set_file_handle_count(pid, 150); // 150文件句柄, 超过限制
// 检查资源使用超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::ResourceLimitExceeded);
}
// 测试多进程资源管理
TEST_F(SandboxResourceTest, MultiProcessResourceManagement) {
// 启动多个进程
ProcessId pid1 = 0, pid2 = 0;
ASSERT_EQ(sandbox_->start_process("process1.exe", {}, pid1), common::ErrorCode::Success);
ASSERT_EQ(sandbox_->start_process("process2.exe", {}, pid2), common::ErrorCode::Success);
// 设置不同的资源限制
ResourceLimits limits1 = create_default_limits();
limits1.max_memory_mb = 100;
limits1.max_cpu_percent = 30.0;
ResourceLimits limits2 = create_default_limits();
limits2.max_memory_mb = 200;
limits2.max_cpu_percent = 70.0;
ASSERT_EQ(sandbox_->set_resource_limits(pid1, limits1), common::ErrorCode::Success);
ASSERT_EQ(sandbox_->set_resource_limits(pid2, limits2), common::ErrorCode::Success);
// 设置资源使用
sandbox_->set_memory_usage(pid1, 90); // 接近但未超过限制
sandbox_->set_cpu_usage(pid1, 20.0); // 低于限制
sandbox_->set_memory_usage(pid2, 150); // 低于限制
sandbox_->set_cpu_usage(pid2, 80.0); // 超过限制
// 设置监控事件调用期望
EXPECT_CALL(*callback_, on_resource_limit_exceeded(pid1, ::testing::_))
.Times(0); // pid1没有超限
EXPECT_CALL(*callback_, on_resource_limit_exceeded(pid2, "CPU"))
.Times(1); // pid2的CPU超限
// 执行资源限制检查
EXPECT_EQ(sandbox_->enforce_resource_limits(pid1), common::ErrorCode::Success);
EXPECT_EQ(sandbox_->enforce_resource_limits(pid2), common::ErrorCode::ResourceLimitExceeded);
}
// 测试资源限制更新
TEST_F(SandboxResourceTest, UpdateResourceLimits) {
// 启动进程
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 设置初始资源限制
ResourceLimits limits = create_default_limits();
limits.max_memory_mb = 100;
ASSERT_EQ(sandbox_->set_resource_limits(pid, limits), common::ErrorCode::Success);
// 设置内存使用到90MB接近但未超过初始限制
sandbox_->set_memory_usage(pid, 90);
// 检查资源使用没有超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::Success);
// 更新资源限制为更严格的限制
limits.max_memory_mb = 50; // 新的限制比当前使用量低
ASSERT_EQ(sandbox_->set_resource_limits(pid, limits), common::ErrorCode::Success);
// 设置监控事件调用期望
EXPECT_CALL(*callback_, on_resource_limit_exceeded(pid, "Memory"))
.Times(1);
// 现在应该超过限制
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::ResourceLimitExceeded);
}
// 测试未设置资源限制的情况
TEST_F(SandboxResourceTest, NoResourceLimits) {
// 启动进程,但不设置资源限制
ProcessId pid = 0;
ASSERT_EQ(sandbox_->start_process("test.exe", {}, pid), common::ErrorCode::Success);
// 设置较高的资源使用
sandbox_->set_memory_usage(pid, 1000); // 1GB
sandbox_->set_cpu_usage(pid, 90.0); // 90%
// 尝试执行资源限制检查应该返回错误
EXPECT_EQ(sandbox_->enforce_resource_limits(pid), common::ErrorCode::InvalidOperation);
// 不应该触发任何资源超限事件
EXPECT_CALL(*callback_, on_resource_limit_exceeded(::testing::_, ::testing::_))
.Times(0);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}