Files
Alicho/tests/integration/plugin_sandbox_integration_test.cpp
2025-10-28 10:27:49 +08:00

576 lines
22 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 "fixtures/integration_test_fixtures.h"
#include "plugin_host/sandbox/sandbox_interface.h"
#include "plugin_host/core/plugin_interface.h"
#include "plugin_host/manager/plugin_host_manager.h"
#include <thread>
#include <chrono>
#include <atomic>
#include <mutex>
#include <condition_variable>
#include <filesystem>
using namespace audio_backend;
using namespace audio_backend::test;
using namespace audio_backend::plugin_host;
using namespace std::chrono_literals;
// 沙盒事件监听器
class TestSandboxEventListener : public ISandboxEventCallback {
public:
void on_process_started(ProcessId pid, const std::string& process_name) override {
std::lock_guard<std::mutex> lock(mutex_);
process_started_count_++;
last_process_id_ = pid;
last_process_name_ = process_name;
events_.push_back("进程启动: " + process_name + " (PID: " + std::to_string(pid) + ")");
cv_.notify_all();
}
void on_process_exited(ProcessId pid, int exit_code) override {
std::lock_guard<std::mutex> lock(mutex_);
process_exited_count_++;
last_exit_code_ = exit_code;
events_.push_back("进程退出: PID " + std::to_string(pid) +
" (退出码: " + std::to_string(exit_code) + ")");
cv_.notify_all();
}
void on_process_crashed(ProcessId pid, const std::string& reason) override {
std::lock_guard<std::mutex> lock(mutex_);
process_crashed_count_++;
last_crash_reason_ = reason;
events_.push_back("进程崩溃: PID " + std::to_string(pid) +
" (原因: " + reason + ")");
cv_.notify_all();
}
void on_resource_limit_exceeded(ProcessId pid, const std::string& resource_name) override {
std::lock_guard<std::mutex> lock(mutex_);
resource_limit_exceeded_count_++;
last_resource_name_ = resource_name;
events_.push_back("资源超限: PID " + std::to_string(pid) +
" (资源: " + resource_name + ")");
cv_.notify_all();
}
void on_security_violation(ProcessId pid, const std::string& violation_type) override {
std::lock_guard<std::mutex> lock(mutex_);
security_violation_count_++;
last_violation_type_ = violation_type;
events_.push_back("安全违规: PID " + std::to_string(pid) +
" (类型: " + violation_type + ")");
cv_.notify_all();
}
void on_heartbeat_timeout(ProcessId pid) override {
std::lock_guard<std::mutex> lock(mutex_);
heartbeat_timeout_count_++;
events_.push_back("心跳超时: PID " + std::to_string(pid));
cv_.notify_all();
}
void on_performance_warning(ProcessId pid, const std::string& warning) override {
std::lock_guard<std::mutex> lock(mutex_);
performance_warning_count_++;
last_warning_ = warning;
events_.push_back("性能警告: PID " + std::to_string(pid) +
" (警告: " + warning + ")");
cv_.notify_all();
}
// 等待特定事件发生
bool wait_for_event(const std::string& event_type,
std::chrono::milliseconds timeout = 5s) {
std::unique_lock<std::mutex> lock(mutex_);
return cv_.wait_for(lock, timeout, [this, &event_type]() {
for (const auto& event : events_) {
if (event.find(event_type) != std::string::npos) {
return true;
}
}
return false;
});
}
// 等待事件计数达到指定值
template<typename CountGetter>
bool wait_for_count(CountGetter count_getter,
size_t target_count,
std::chrono::milliseconds timeout = 5s) {
std::unique_lock<std::mutex> lock(mutex_);
return cv_.wait_for(lock, timeout, [this, &count_getter, target_count]() {
return (this->*count_getter)() >= target_count;
});
}
// 获取统计信息
size_t process_started_count() const { return process_started_count_; }
size_t process_exited_count() const { return process_exited_count_; }
size_t process_crashed_count() const { return process_crashed_count_; }
size_t resource_limit_exceeded_count() const { return resource_limit_exceeded_count_; }
size_t security_violation_count() const { return security_violation_count_; }
size_t heartbeat_timeout_count() const { return heartbeat_timeout_count_; }
size_t performance_warning_count() const { return performance_warning_count_; }
// 获取最后事件信息
ProcessId last_process_id() const { return last_process_id_; }
const std::string& last_process_name() const { return last_process_name_; }
int last_exit_code() const { return last_exit_code_; }
const std::string& last_crash_reason() const { return last_crash_reason_; }
const std::string& last_resource_name() const { return last_resource_name_; }
const std::string& last_violation_type() const { return last_violation_type_; }
const std::string& last_warning() const { return last_warning_; }
// 清除事件历史
void clear_events() {
std::lock_guard<std::mutex> lock(mutex_);
events_.clear();
}
// 重置所有计数器
void reset_counters() {
std::lock_guard<std::mutex> lock(mutex_);
process_started_count_ = 0;
process_exited_count_ = 0;
process_crashed_count_ = 0;
resource_limit_exceeded_count_ = 0;
security_violation_count_ = 0;
heartbeat_timeout_count_ = 0;
performance_warning_count_ = 0;
}
private:
std::mutex mutex_;
std::condition_variable cv_;
std::vector<std::string> events_;
// 事件计数
size_t process_started_count_ = 0;
size_t process_exited_count_ = 0;
size_t process_crashed_count_ = 0;
size_t resource_limit_exceeded_count_ = 0;
size_t security_violation_count_ = 0;
size_t heartbeat_timeout_count_ = 0;
size_t performance_warning_count_ = 0;
// 最后事件信息
ProcessId last_process_id_ = 0;
std::string last_process_name_;
int last_exit_code_ = 0;
std::string last_crash_reason_;
std::string last_resource_name_;
std::string last_violation_type_;
std::string last_warning_;
};
// 插件沙盒测试类
class PluginSandboxIntegrationTestImpl : public PluginSandboxIntegrationTest {
protected:
void initialize_sandbox() override {
// 创建沙盒配置
SandboxConfig sandbox_config;
sandbox_config.sandbox_type = SandboxType::ProcessLevelIsolation;
sandbox_config.process_creation_timeout = 5000;
sandbox_config.enable_heartbeat = true;
sandbox_config.heartbeat_interval_ms = 1000;
sandbox_config.heartbeat_timeout_ms = 5000;
sandbox_config.enable_resource_monitoring = true;
sandbox_config.resource_monitoring_interval_ms = 1000;
// 使用工厂创建平台特定沙盒
sandbox_ = SandboxFactory::create_platform_sandbox(sandbox_config);
ASSERT_NE(sandbox_, nullptr);
// 初始化沙盒
ASSERT_EQ(sandbox_->initialize(sandbox_config), common::ErrorCode::Success);
// 添加事件监听器
sandbox_event_listener_ = std::make_shared<TestSandboxEventListener>();
sandbox_->set_event_callback(sandbox_event_listener_);
// 创建插件宿主管理器配置
PluginHostConfig host_config;
host_config.default_sample_rate = DEFAULT_SAMPLE_RATE;
host_config.default_block_size = DEFAULT_BUFFER_SIZE;
host_config.enable_sandbox = true;
host_config.plugin_search_paths = {TEST_PLUGINS_DIR};
host_config.cache_loaded_plugins = true;
// 创建插件宿主管理器
plugin_manager_ = std::make_unique<PluginHostManager>();
ASSERT_NE(plugin_manager_, nullptr);
// 初始化插件宿主管理器
ASSERT_EQ(plugin_manager_->initialize(host_config), common::ErrorCode::Success);
}
void shutdown_sandbox() override {
// 关闭插件宿主管理器
if (plugin_manager_) {
plugin_manager_->shutdown();
}
// 移除事件监听器
if (sandbox_) {
sandbox_->remove_event_callback();
// 关闭沙盒
sandbox_->shutdown();
}
}
void initialize_test_plugins() override {
// 确保测试插件目录存在
std::filesystem::create_directories(TEST_PLUGINS_DIR);
// 这里可以准备测试插件文件
// 在实际测试中我们假设测试插件已经在resources目录中
}
void shutdown_test_plugins() override {
// 卸载所有已加载的插件
for (auto id : loaded_plugins_) {
plugin_manager_->unload_plugin(id);
}
loaded_plugins_.clear();
}
PluginInstanceId load_test_plugin(const std::string& plugin_path) override {
// 构建完整插件路径
std::string full_path = test_plugins_dir_ + "/" + plugin_path;
// 创建插件加载配置
PluginLoadConfig config;
config.sample_rate = DEFAULT_SAMPLE_RATE;
config.block_size = DEFAULT_BUFFER_SIZE;
config.enable_sandbox = true;
// 加载插件
PluginInstanceId instance_id;
auto result = plugin_manager_->load_plugin(full_path, instance_id, config);
// 如果加载成功记录插件ID
if (result == common::ErrorCode::Success) {
loaded_plugins_.push_back(instance_id);
}
return instance_id;
}
// 创建资源限制
ResourceLimits create_resource_limits(bool strict = false) {
ResourceLimits limits;
if (strict) {
// 严格限制
limits.max_memory_mb = 10; // 只允许10MB内存
limits.max_cpu_percent = 10.0; // 最多10%的CPU
limits.max_threads = 2; // 最多2个线程
limits.max_file_handles = 5; // 最多5个文件句柄
limits.max_execution_time_ms = 5000; // 最多执行5秒
} else {
// 宽松限制
limits.max_memory_mb = 256; // 256MB内存
limits.max_cpu_percent = 50.0; // 最多50%的CPU
limits.max_threads = 8; // 最多8个线程
limits.max_file_handles = 100; // 最多100个文件句柄
limits.max_execution_time_ms = 60000; // 最多执行60秒
}
limits.kill_on_limit = strict; // 严格模式下超限直接终止
limits.throttle_on_limit = true; // 超限时限流
return limits;
}
// 创建安全设置
SecuritySettings create_security_settings(bool restrictive = false) {
SecuritySettings settings;
// 基本权限
settings.allow_file_access = true;
settings.allow_network_access = false;
settings.allow_process_creation = false;
settings.allow_system_operations = false;
if (restrictive) {
// 限制性设置
settings.allow_file_access = false;
settings.allowed_paths.clear();
settings.denied_paths = {"/*"}; // 禁止访问所有路径
} else {
// 普通设置
settings.allowed_paths = {
TEST_TEMP_DIR, // 允许访问临时目录
TEST_RESOURCES_DIR + "/data" // 允许访问数据目录
};
settings.denied_paths = {
"/system",
"/bin",
"/etc",
"C:\\Windows"
};
}
return settings;
}
protected:
std::shared_ptr<ISandbox> sandbox_;
std::shared_ptr<TestSandboxEventListener> sandbox_event_listener_;
};
// ================================================================================================
// 沙盒基本功能测试
// ================================================================================================
TEST_F(PluginSandboxIntegrationTestImpl, SandboxBasicFunctionality) {
// 验证沙盒已初始化
ASSERT_NE(sandbox_, nullptr);
EXPECT_TRUE(sandbox_->is_initialized());
// 获取沙盒类型
SandboxType type = sandbox_->get_sandbox_type();
EXPECT_NE(type, SandboxType::Unknown);
// 获取沙盒配置
const SandboxConfig& config = sandbox_->get_config();
EXPECT_EQ(config.sandbox_type, type);
EXPECT_TRUE(config.enable_heartbeat);
EXPECT_TRUE(config.enable_resource_monitoring);
// 检查平台支持的沙盒类型
auto supported_types = SandboxFactory::get_supported_sandbox_types();
EXPECT_FALSE(supported_types.empty());
// 验证当前使用的沙盒类型受支持
EXPECT_TRUE(SandboxFactory::is_sandbox_type_supported(type));
}
// ================================================================================================
// 插件加载和卸载测试
// ================================================================================================
TEST_F(PluginSandboxIntegrationTestImpl, PluginLoadingAndUnloading) {
// 这个测试需要实际的插件文件,在测试环境中可能需要跳过
if (!std::filesystem::exists(TEST_PLUGINS_DIR + "/test_plugin.dll") &&
!std::filesystem::exists(TEST_PLUGINS_DIR + "/test_plugin.so")) {
GTEST_SKIP() << "测试插件文件不存在,跳过测试";
}
// 设置事件监听器预期
sandbox_event_listener_->reset_counters();
// 加载测试插件
std::string plugin_path = "test_plugin.dll"; // Windows上使用.dll其他平台使用.so
#ifdef __linux__
plugin_path = "test_plugin.so";
#elif defined(__APPLE__)
plugin_path = "test_plugin.so";
#endif
PluginInstanceId plugin_id = load_test_plugin(plugin_path);
// 验证插件加载成功
EXPECT_NE(plugin_id, 0);
EXPECT_TRUE(plugin_manager_->is_plugin_loaded(plugin_id));
// 等待进程启动事件
EXPECT_TRUE(sandbox_event_listener_->wait_for_event("进程启动"));
EXPECT_GE(sandbox_event_listener_->process_started_count(), 1);
// 获取插件信息
PluginInstanceInfo info;
EXPECT_EQ(plugin_manager_->get_plugin_info(plugin_id, info), common::ErrorCode::Success);
// 验证插件信息
EXPECT_EQ(info.instance_id, plugin_id);
EXPECT_EQ(info.plugin_id, TEST_PLUGINS_DIR + "/" + plugin_path);
EXPECT_EQ(info.state, PluginState::Initialized);
// 激活插件
EXPECT_EQ(plugin_manager_->activate_plugin(plugin_id), common::ErrorCode::Success);
// 验证插件状态
EXPECT_EQ(plugin_manager_->get_plugin_info(plugin_id, info), common::ErrorCode::Success);
EXPECT_EQ(info.state, PluginState::Active);
// 停用插件
EXPECT_EQ(plugin_manager_->deactivate_plugin(plugin_id), common::ErrorCode::Success);
// 验证插件状态
EXPECT_EQ(plugin_manager_->get_plugin_info(plugin_id, info), common::ErrorCode::Success);
EXPECT_EQ(info.state, PluginState::Initialized);
// 卸载插件
EXPECT_EQ(plugin_manager_->unload_plugin(plugin_id), common::ErrorCode::Success);
// 等待进程退出事件
EXPECT_TRUE(sandbox_event_listener_->wait_for_event("进程退出"));
EXPECT_GE(sandbox_event_listener_->process_exited_count(), 1);
// 验证插件已卸载
EXPECT_FALSE(plugin_manager_->is_plugin_loaded(plugin_id));
}
// ================================================================================================
// 资源限制测试
// ================================================================================================
TEST_F(PluginSandboxIntegrationTestImpl, ResourceLimits) {
// 这个测试需要实际的插件文件,在测试环境中可能需要跳过
if (!std::filesystem::exists(TEST_PLUGINS_DIR + "/memory_intensive_plugin.dll") &&
!std::filesystem::exists(TEST_PLUGINS_DIR + "/memory_intensive_plugin.so")) {
GTEST_SKIP() << "内存密集型测试插件文件不存在,跳过测试";
}
// 设置事件监听器预期
sandbox_event_listener_->reset_counters();
// 加载内存密集型测试插件
std::string plugin_path = "memory_intensive_plugin.dll";
#ifdef __linux__
plugin_path = "memory_intensive_plugin.so";
#elif defined(__APPLE__)
plugin_path = "memory_intensive_plugin.so";
#endif
PluginInstanceId plugin_id = load_test_plugin(plugin_path);
// 验证插件加载成功
EXPECT_NE(plugin_id, 0);
EXPECT_TRUE(plugin_manager_->is_plugin_loaded(plugin_id));
// 等待进程启动事件
EXPECT_TRUE(sandbox_event_listener_->wait_for_event("进程启动"));
// 获取插件进程信息
PluginInstanceInfo info;
EXPECT_EQ(plugin_manager_->get_plugin_info(plugin_id, info), common::ErrorCode::Success);
ProcessId pid = info.process_id;
// 获取沙盒进程信息
SandboxProcessInfo process_info = sandbox_->get_process_info(pid);
EXPECT_EQ(process_info.process_id, pid);
// 设置严格的资源限制
ResourceLimits strict_limits = create_resource_limits(true);
EXPECT_EQ(sandbox_->set_resource_limits(pid, strict_limits), common::ErrorCode::Success);
// 激活插件 - 这会触发内存密集型操作
EXPECT_EQ(plugin_manager_->activate_plugin(plugin_id), common::ErrorCode::Success);
// 等待资源超限事件
EXPECT_TRUE(sandbox_event_listener_->wait_for_event("资源超限"));
EXPECT_GE(sandbox_event_listener_->resource_limit_exceeded_count(), 1);
// 验证进程状态(可能已被终止或限流)
process_info = sandbox_->get_process_info(pid);
// 卸载插件
plugin_manager_->unload_plugin(plugin_id);
}
// ================================================================================================
// 安全隔离测试
// ================================================================================================
TEST_F(PluginSandboxIntegrationTestImpl, SecurityIsolation) {
// 这个测试需要实际的插件文件,在测试环境中可能需要跳过
if (!std::filesystem::exists(TEST_PLUGINS_DIR + "/security_test_plugin.dll") &&
!std::filesystem::exists(TEST_PLUGINS_DIR + "/security_test_plugin.so")) {
GTEST_SKIP() << "安全测试插件文件不存在,跳过测试";
}
// 设置事件监听器预期
sandbox_event_listener_->reset_counters();
// 加载安全测试插件
std::string plugin_path = "security_test_plugin.dll";
#ifdef __linux__
plugin_path = "security_test_plugin.so";
#elif defined(__APPLE__)
plugin_path = "security_test_plugin.so";
#endif
PluginInstanceId plugin_id = load_test_plugin(plugin_path);
// 验证插件加载成功
EXPECT_NE(plugin_id, 0);
EXPECT_TRUE(plugin_manager_->is_plugin_loaded(plugin_id));
// 等待进程启动事件
EXPECT_TRUE(sandbox_event_listener_->wait_for_event("进程启动"));
// 获取插件进程信息
PluginInstanceInfo info;
EXPECT_EQ(plugin_manager_->get_plugin_info(plugin_id, info), common::ErrorCode::Success);
ProcessId pid = info.process_id;
// 应用限制性安全设置
SecuritySettings restrictive_settings = create_security_settings(true);
EXPECT_EQ(sandbox_->apply_security_settings(pid, restrictive_settings), common::ErrorCode::Success);
// 激活插件 - 这会触发安全测试操作
EXPECT_EQ(plugin_manager_->activate_plugin(plugin_id), common::ErrorCode::Success);
// 等待安全违规事件
EXPECT_TRUE(sandbox_event_listener_->wait_for_event("安全违规"));
EXPECT_GE(sandbox_event_listener_->security_violation_count(), 1);
// 卸载插件
plugin_manager_->unload_plugin(plugin_id);
}
// ================================================================================================
// 崩溃恢复测试
// ================================================================================================
TEST_F(PluginSandboxIntegrationTestImpl, CrashRecovery) {
// 这个测试需要实际的插件文件,在测试环境中可能需要跳过
if (!std::filesystem::exists(TEST_PLUGINS_DIR + "/crash_plugin.dll") &&
!std::filesystem::exists(TEST_PLUGINS_DIR + "/crash_plugin.so")) {
GTEST_SKIP() << "崩溃测试插件文件不存在,跳过测试";
}
// 设置事件监听器预期
sandbox_event_listener_->reset_counters();
// 加载崩溃测试插件
std::string plugin_path = "crash_plugin.dll";
#ifdef __linux__
plugin_path = "crash_plugin.so";
#elif defined(__APPLE__)
plugin_path = "crash_plugin.so";
#endif
PluginInstanceId plugin_id = load_test_plugin(plugin_path);
// 验证插件加载成功
EXPECT_NE(plugin_id, 0);
EXPECT_TRUE(plugin_manager_->is_plugin_loaded(plugin_id));
// 等待进程启动事件
EXPECT_TRUE(sandbox_event_listener_->wait_for_event("进程启动"));
// 激活插件 - 这会触发崩溃
EXPECT_EQ(plugin_manager_->activate_plugin(plugin_id), common::ErrorCode::Success);
// 等待进程崩溃事件
EXPECT_TRUE(sandbox_event_listener_->wait_for_event("进程崩溃"));
EXPECT_GE(sandbox_event_listener_->process_crashed_count(), 1);
// 验证插件状态
PluginInstanceInfo info;
EXPECT_EQ(plugin_manager_->get_plugin_info(plugin_id, info), common::ErrorCode::Success);
EXPECT_EQ(info.state, PluginState::Error);
// 卸载插件
plugin_manager_->unload_plugin(plugin_id);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}