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

489 lines
16 KiB
C++
Raw Permalink 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/core/plugin_interface.h"
#include "plugin_host/core/plugin_metadata.h"
#include "plugin_host/manager/plugin_host_manager.h"
#include "tests/common/test_fixtures.h"
#include <filesystem>
#include <thread>
#include <chrono>
using namespace audio_backend;
using namespace audio_backend::plugin_host;
using namespace std::chrono_literals;
// 创建测试插件实现
class TestPlugin : public IPlugin {
public:
TestPlugin(PluginInfo info) : info_(std::move(info)) {}
virtual ~TestPlugin() = default;
// 实现插件接口
bool initialize(const PluginInitParams& params) override {
initialized_ = true;
params_ = params;
return true;
}
bool terminate() override {
initialized_ = false;
return true;
}
bool activate() override {
active_ = true;
return true;
}
bool deactivate() override {
active_ = false;
return true;
}
PluginProcessStatus process(const ProcessContext& context) override {
last_context_ = context;
return PluginProcessStatus::Success;
}
PluginInfo get_info() const override {
return info_;
}
ParameterInfo get_parameter_info(ParameterId param_id) const override {
auto it = parameters_.find(param_id);
if (it != parameters_.end()) {
return it->second.info;
}
return ParameterInfo();
}
float get_parameter(ParameterId param_id) const override {
auto it = parameters_.find(param_id);
if (it != parameters_.end()) {
return it->second.value;
}
return 0.0f;
}
bool set_parameter(ParameterId param_id, float value) override {
auto it = parameters_.find(param_id);
if (it != parameters_.end()) {
it->second.value = value;
return true;
}
return false;
}
bool handle_event(const PluginEvent& event) override {
last_event_ = event;
return true;
}
const PluginStatistics& get_statistics() const override {
return stats_;
}
void reset_statistics() override {
stats_ = PluginStatistics();
}
// 测试辅助方法
void add_parameter(ParameterId id, const ParameterInfo& info, float default_value) {
parameters_[id] = {info, default_value};
}
bool is_initialized() const { return initialized_; }
bool is_active() const { return active_; }
const PluginInitParams& get_params() const { return params_; }
const ProcessContext& get_last_context() const { return last_context_; }
const PluginEvent& get_last_event() const { return last_event_; }
private:
PluginInfo info_;
bool initialized_ = false;
bool active_ = false;
PluginInitParams params_;
ProcessContext last_context_;
PluginEvent last_event_;
PluginStatistics stats_;
struct Parameter {
ParameterInfo info;
float value;
};
std::map<ParameterId, Parameter> parameters_;
};
// 创建模拟插件工厂
class MockPluginFactory {
public:
static std::unique_ptr<IPlugin> create_test_plugin(
const std::string& id,
const std::string& name,
const std::string& version) {
PluginInfo info;
info.id = id;
info.name = name;
info.version = version;
info.vendor = "Test Vendor";
info.category = "Test";
info.description = "Test plugin for unit tests";
info.num_inputs = 2;
info.num_outputs = 2;
return std::make_unique<TestPlugin>(info);
}
};
// 创建模拟插件加载器
class MockPluginLoader : public IPluginLoader {
public:
MockPluginLoader() = default;
~MockPluginLoader() override = default;
// 实现加载器接口
PluginLoadResult load_plugin(
const std::string& plugin_path,
PluginInstanceId instance_id,
const PluginLoadConfig& config) override {
// 检查路径是否在已加载插件表中
auto it = plugins_.find(plugin_path);
if (it != plugins_.end()) {
return {PluginLoadStatus::AlreadyLoaded, nullptr,
"Plugin already loaded with instance ID " + std::to_string(it->second.instance_id)};
}
// 创建测试插件
auto plugin = MockPluginFactory::create_test_plugin(
plugin_path, // 使用路径作为ID
std::filesystem::path(plugin_path).filename().string(), // 使用文件名作为名称
"1.0.0" // 默认版本
);
if (!plugin) {
return {PluginLoadStatus::LoadError, nullptr, "Failed to create plugin"};
}
// 初始化插件
PluginInitParams params;
params.sample_rate = config.sample_rate;
params.max_block_size = config.block_size;
params.plugin_path = plugin_path;
params.host_api_version = HOST_API_VERSION;
if (!plugin->initialize(params)) {
return {PluginLoadStatus::InitError, nullptr, "Failed to initialize plugin"};
}
// 存储插件信息
plugins_[plugin_path] = {instance_id, plugin.get()};
// 返回成功结果
return {PluginLoadStatus::Success, std::move(plugin), ""};
}
bool unload_plugin(PluginInstanceId instance_id) override {
// 查找插件
for (auto it = plugins_.begin(); it != plugins_.end(); ++it) {
if (it->second.instance_id == instance_id) {
plugins_.erase(it);
return true;
}
}
return false;
}
// 测试辅助方法
size_t get_loaded_plugin_count() const {
return plugins_.size();
}
private:
struct PluginEntry {
PluginInstanceId instance_id;
IPlugin* plugin_ptr; // 仅用于测试,不拥有对象
};
std::map<std::string, PluginEntry> plugins_;
};
// 插件加载测试固定装置
class PluginLoadTest : public test::PluginSandboxTest {
protected:
void SetUp() override {
test::PluginSandboxTest::SetUp();
// 创建插件加载器
loader_ = std::make_shared<MockPluginLoader>();
// 创建插件宿主管理器
manager_ = std::make_unique<PluginHostManager>();
// 初始化管理器
PluginHostConfig config;
config.default_sample_rate = 48000;
config.default_block_size = 512;
config.enable_sandbox = false; // 禁用沙盒进行单元测试
config.plugin_search_paths = {"./plugins", "./effects"};
config.cache_loaded_plugins = true;
ASSERT_EQ(manager_->initialize(config), common::ErrorCode::Success);
// 注册加载器
manager_->register_plugin_loader(loader_);
}
void TearDown() override {
if (manager_->is_initialized()) {
manager_->shutdown();
}
manager_.reset();
loader_.reset();
test::PluginSandboxTest::TearDown();
}
// 创建测试插件加载配置
PluginLoadConfig create_load_config() {
PluginLoadConfig config;
config.sample_rate = 48000;
config.block_size = 512;
config.enable_sandbox = false;
return config;
}
protected:
std::shared_ptr<MockPluginLoader> loader_;
std::unique_ptr<PluginHostManager> manager_;
};
// 测试插件加载
TEST_F(PluginLoadTest, LoadPlugin) {
// 创建加载配置
PluginLoadConfig config = create_load_config();
// 加载插件
PluginInstanceId instance_id = 0;
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
// 验证插件ID
EXPECT_NE(instance_id, 0);
// 验证插件已加载
EXPECT_TRUE(manager_->is_plugin_loaded(instance_id));
EXPECT_EQ(loader_->get_loaded_plugin_count(), 1);
// 获取插件信息
PluginInstanceInfo info;
ASSERT_EQ(manager_->get_plugin_info(instance_id, info), common::ErrorCode::Success);
// 验证插件信息
EXPECT_EQ(info.plugin_id, "./plugins/test_plugin.dll");
EXPECT_EQ(info.instance_id, instance_id);
EXPECT_EQ(info.state, PluginState::Initialized);
}
// 测试插件激活和停用
TEST_F(PluginLoadTest, ActivateDeactivatePlugin) {
// 加载插件
PluginInstanceId instance_id = 0;
PluginLoadConfig config = create_load_config();
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
// 验证初始状态
PluginInstanceInfo info;
ASSERT_EQ(manager_->get_plugin_info(instance_id, info), common::ErrorCode::Success);
EXPECT_EQ(info.state, PluginState::Initialized);
// 激活插件
ASSERT_EQ(manager_->activate_plugin(instance_id), common::ErrorCode::Success);
// 验证激活状态
ASSERT_EQ(manager_->get_plugin_info(instance_id, info), common::ErrorCode::Success);
EXPECT_EQ(info.state, PluginState::Active);
// 停用插件
ASSERT_EQ(manager_->deactivate_plugin(instance_id), common::ErrorCode::Success);
// 验证停用状态
ASSERT_EQ(manager_->get_plugin_info(instance_id, info), common::ErrorCode::Success);
EXPECT_EQ(info.state, PluginState::Initialized);
}
// 测试插件卸载
TEST_F(PluginLoadTest, UnloadPlugin) {
// 加载插件
PluginInstanceId instance_id = 0;
PluginLoadConfig config = create_load_config();
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
// 验证插件已加载
EXPECT_TRUE(manager_->is_plugin_loaded(instance_id));
// 卸载插件
ASSERT_EQ(manager_->unload_plugin(instance_id), common::ErrorCode::Success);
// 验证插件已卸载
EXPECT_FALSE(manager_->is_plugin_loaded(instance_id));
EXPECT_EQ(loader_->get_loaded_plugin_count(), 0);
}
// 测试加载多个插件
TEST_F(PluginLoadTest, LoadMultiplePlugins) {
// 加载第一个插件
PluginInstanceId id1 = 0;
PluginLoadConfig config = create_load_config();
ASSERT_EQ(manager_->load_plugin("./plugins/plugin1.dll", id1, config), common::ErrorCode::Success);
// 加载第二个插件
PluginInstanceId id2 = 0;
ASSERT_EQ(manager_->load_plugin("./plugins/plugin2.dll", id2, config), common::ErrorCode::Success);
// 加载第三个插件
PluginInstanceId id3 = 0;
ASSERT_EQ(manager_->load_plugin("./plugins/plugin3.dll", id3, config), common::ErrorCode::Success);
// 验证插件已加载
EXPECT_TRUE(manager_->is_plugin_loaded(id1));
EXPECT_TRUE(manager_->is_plugin_loaded(id2));
EXPECT_TRUE(manager_->is_plugin_loaded(id3));
EXPECT_EQ(loader_->get_loaded_plugin_count(), 3);
// 验证ID不同
EXPECT_NE(id1, id2);
EXPECT_NE(id1, id3);
EXPECT_NE(id2, id3);
// 获取所有插件ID
std::vector<PluginInstanceId> ids;
ASSERT_EQ(manager_->get_all_plugin_instances(ids), common::ErrorCode::Success);
// 验证ID列表
EXPECT_EQ(ids.size(), 3);
EXPECT_TRUE(std::find(ids.begin(), ids.end(), id1) != ids.end());
EXPECT_TRUE(std::find(ids.begin(), ids.end(), id2) != ids.end());
EXPECT_TRUE(std::find(ids.begin(), ids.end(), id3) != ids.end());
}
// 测试重复加载
TEST_F(PluginLoadTest, LoadDuplicatePlugin) {
// 加载插件
PluginInstanceId id1 = 0;
PluginLoadConfig config = create_load_config();
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", id1, config), common::ErrorCode::Success);
// 尝试再次加载同一个插件
PluginInstanceId id2 = 0;
auto result = manager_->load_plugin("./plugins/test_plugin.dll", id2, config);
// 应该返回错误
EXPECT_NE(result, common::ErrorCode::Success);
// 验证只有一个插件加载
EXPECT_EQ(loader_->get_loaded_plugin_count(), 1);
}
// 测试参数操作
TEST_F(PluginLoadTest, ParameterOperations) {
// 加载插件
PluginInstanceId instance_id = 0;
PluginLoadConfig config = create_load_config();
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
// 获取插件实例
auto plugin = manager_->get_plugin(instance_id);
ASSERT_NE(plugin, nullptr);
// 添加测试参数使用TestPlugin的特定方法
auto* test_plugin = dynamic_cast<TestPlugin*>(plugin.get());
ASSERT_NE(test_plugin, nullptr);
ParameterInfo gain_param;
gain_param.id = 1;
gain_param.name = "Gain";
gain_param.default_value = 0.5f;
gain_param.min_value = 0.0f;
gain_param.max_value = 1.0f;
test_plugin->add_parameter(1, gain_param, 0.5f);
// 获取参数信息
ParameterInfo info;
ASSERT_EQ(manager_->get_parameter_info(instance_id, 1, info), common::ErrorCode::Success);
// 验证参数信息
EXPECT_EQ(info.id, 1);
EXPECT_EQ(info.name, "Gain");
EXPECT_FLOAT_EQ(info.default_value, 0.5f);
EXPECT_FLOAT_EQ(info.min_value, 0.0f);
EXPECT_FLOAT_EQ(info.max_value, 1.0f);
// 获取参数值
float value = 0.0f;
ASSERT_EQ(manager_->get_parameter_value(instance_id, 1, value), common::ErrorCode::Success);
EXPECT_FLOAT_EQ(value, 0.5f);
// 设置参数值
ASSERT_EQ(manager_->set_parameter_value(instance_id, 1, 0.8f), common::ErrorCode::Success);
// 再次获取参数值
ASSERT_EQ(manager_->get_parameter_value(instance_id, 1, value), common::ErrorCode::Success);
EXPECT_FLOAT_EQ(value, 0.8f);
// 尝试获取不存在的参数
EXPECT_NE(manager_->get_parameter_value(instance_id, 999, value), common::ErrorCode::Success);
}
// 测试批量处理操作
TEST_F(PluginLoadTest, ProcessOperations) {
// 加载插件
PluginInstanceId instance_id = 0;
PluginLoadConfig config = create_load_config();
ASSERT_EQ(manager_->load_plugin("./plugins/test_plugin.dll", instance_id, config), common::ErrorCode::Success);
// 激活插件
ASSERT_EQ(manager_->activate_plugin(instance_id), common::ErrorCode::Success);
// 准备处理上下文
ProcessContext context;
context.input_buffer = std::make_shared<AudioBuffer>(512, 2, AudioFormat::FLOAT32);
context.output_buffer = std::make_shared<AudioBuffer>(512, 2, AudioFormat::FLOAT32);
context.time_info.sample_position = 0;
context.time_info.sample_rate = 48000;
context.time_info.tempo = 120.0;
// 填充输入缓冲区
float* input_data = context.input_buffer->interleaved_data<float>();
for (size_t i = 0; i < 512 * 2; ++i) {
input_data[i] = 0.5f;
}
// 处理音频
ASSERT_EQ(manager_->process_audio(instance_id, context), common::ErrorCode::Success);
// 验证输出缓冲区具体处理结果取决于TestPlugin的实现
// 在这个测试中TestPlugin没有实际处理音频只是记录上下文
// 所以我们验证上下文已被正确传递
auto plugin = manager_->get_plugin(instance_id);
auto* test_plugin = dynamic_cast<TestPlugin*>(plugin.get());
ASSERT_NE(test_plugin, nullptr);
const auto& last_context = test_plugin->get_last_context();
EXPECT_EQ(last_context.time_info.sample_rate, context.time_info.sample_rate);
EXPECT_EQ(last_context.time_info.tempo, context.time_info.tempo);
}
int main(int argc, char** argv) {
::testing::InitGoogleTest(&argc, argv);
return RUN_ALL_TESTS();
}