488 lines
18 KiB
C++
488 lines
18 KiB
C++
// ================================================================================================
|
||
// Audio Backend - 引擎通信集成测试
|
||
// ================================================================================================
|
||
// 描述: 测试音频引擎与通信系统的集成
|
||
// ================================================================================================
|
||
|
||
#include "fixtures/integration_test_fixtures.h"
|
||
#include "communication/communication.h"
|
||
#include "engine/audio_buffer.h"
|
||
#include <thread>
|
||
#include <chrono>
|
||
#include <atomic>
|
||
#include <mutex>
|
||
#include <condition_variable>
|
||
|
||
using namespace audio_backend;
|
||
using namespace audio_backend::test;
|
||
using namespace std::chrono_literals;
|
||
|
||
// 测试消息类型
|
||
class TestAudioMessage : public communication::Message {
|
||
public:
|
||
TestAudioMessage(uint32_t sequence_number = 0, const std::string& content = "")
|
||
: communication::Message("TestAudioMessage"),
|
||
sequence_number_(sequence_number),
|
||
content_(content) {}
|
||
|
||
TestAudioMessage(const TestAudioMessage& other)
|
||
: communication::Message(other),
|
||
sequence_number_(other.sequence_number_),
|
||
content_(other.content_) {}
|
||
|
||
uint32_t sequence_number() const { return sequence_number_; }
|
||
const std::string& content() const { return content_; }
|
||
|
||
// 实现虚函数
|
||
size_t estimated_size() const override { return sizeof(*this) + content_.size(); }
|
||
Priority priority() const override { return Priority::Normal; }
|
||
TransportChannel preferred_channel() const override { return TransportChannel::ZeroMQ; }
|
||
|
||
std::unique_ptr<communication::IMessage> clone() const override {
|
||
return std::make_unique<TestAudioMessage>(*this);
|
||
}
|
||
|
||
private:
|
||
uint32_t sequence_number_;
|
||
std::string content_;
|
||
};
|
||
|
||
// 音频数据消息类型
|
||
class AudioBufferMessage : public communication::Message {
|
||
public:
|
||
AudioBufferMessage()
|
||
: communication::Message("AudioBufferMessage") {}
|
||
|
||
AudioBufferMessage(const engine::AudioBuffer& buffer)
|
||
: communication::Message("AudioBufferMessage"), buffer_(buffer) {}
|
||
|
||
AudioBufferMessage(const AudioBufferMessage& other)
|
||
: communication::Message(other), buffer_(other.buffer_) {}
|
||
|
||
const engine::AudioBuffer& buffer() const { return buffer_; }
|
||
|
||
// 实现虚函数
|
||
size_t estimated_size() const override {
|
||
return sizeof(*this) + buffer_.total_bytes();
|
||
}
|
||
|
||
Priority priority() const override { return Priority::High; }
|
||
|
||
TransportChannel preferred_channel() const override {
|
||
// 小缓冲区使用ZeroMQ,大缓冲区使用共享内存
|
||
return buffer_.total_bytes() > 32 * 1024
|
||
? TransportChannel::SharedMemory
|
||
: TransportChannel::ZeroMQ;
|
||
}
|
||
|
||
std::unique_ptr<communication::IMessage> clone() const override {
|
||
return std::make_unique<AudioBufferMessage>(*this);
|
||
}
|
||
|
||
private:
|
||
engine::AudioBuffer buffer_;
|
||
};
|
||
|
||
// 引擎通信测试类
|
||
class EngineCommunicationIntegrationTest : public EngineCommunicationTest {
|
||
protected:
|
||
void initialize_communication() override {
|
||
// 创建通信配置
|
||
communication::CommunicationConfig config;
|
||
config.process_name = "engine_comm_test";
|
||
config.routing_strategy = communication::RoutingStrategy::Auto;
|
||
config.enable_zmq = true;
|
||
config.enable_shm = true;
|
||
|
||
// ZeroMQ配置
|
||
communication::ZmqConfig zmq_config;
|
||
zmq_config.endpoint = comm_endpoint_;
|
||
zmq_config.socket_type = ZMQ_REP;
|
||
zmq_config.bind_instead_of_connect = true;
|
||
config.zmq_configs.push_back(zmq_config);
|
||
|
||
// 共享内存配置
|
||
config.shm_config.segment_name = shm_segment_;
|
||
config.shm_config.segment_size = 1024 * 1024 * 10; // 10MB
|
||
config.shm_config.create_if_not_exists = true;
|
||
|
||
// 创建通信管理器
|
||
comm_manager_ = std::make_unique<communication::CommunicationManager>(config);
|
||
|
||
// 注册消息类型
|
||
message_factory_.register_message<TestAudioMessage>("TestAudioMessage");
|
||
message_factory_.register_message<AudioBufferMessage>("AudioBufferMessage");
|
||
|
||
// 初始化通信管理器
|
||
ASSERT_EQ(comm_manager_->initialize(), common::ErrorCode::Success);
|
||
|
||
// 注册消息处理器
|
||
comm_manager_->register_message_handler("TestAudioMessage",
|
||
[this](std::unique_ptr<communication::IMessage> message) {
|
||
auto* test_message = dynamic_cast<TestAudioMessage*>(message.get());
|
||
if (test_message) {
|
||
handle_test_message(*test_message);
|
||
}
|
||
});
|
||
|
||
comm_manager_->register_message_handler("AudioBufferMessage",
|
||
[this](std::unique_ptr<communication::IMessage> message) {
|
||
auto* buffer_message = dynamic_cast<AudioBufferMessage*>(message.get());
|
||
if (buffer_message) {
|
||
handle_audio_buffer_message(*buffer_message);
|
||
}
|
||
});
|
||
}
|
||
|
||
void shutdown_communication() override {
|
||
if (comm_manager_) {
|
||
ASSERT_EQ(comm_manager_->shutdown(), common::ErrorCode::Success);
|
||
}
|
||
}
|
||
|
||
void initialize_engine() override {
|
||
// 在实际系统中,这里会初始化音频引擎组件
|
||
// 但在此测试中,我们主要测试通信部分,因此创建模拟音频缓冲区
|
||
test_buffer_ = create_test_audio_buffer(1024, 2, engine::AudioFormat::FLOAT32, true);
|
||
}
|
||
|
||
void shutdown_engine() override {
|
||
// 清理资源
|
||
}
|
||
|
||
// 处理测试消息
|
||
void handle_test_message(const TestAudioMessage& message) {
|
||
std::lock_guard<std::mutex> lock(mutex_);
|
||
received_messages_.push_back(message.sequence_number());
|
||
|
||
// 发送响应
|
||
auto response = std::make_unique<TestAudioMessage>(
|
||
message.sequence_number(), "响应: " + message.content());
|
||
|
||
comm_manager_->send_message(*response);
|
||
cv_.notify_one();
|
||
}
|
||
|
||
// 处理音频缓冲区消息
|
||
void handle_audio_buffer_message(const AudioBufferMessage& message) {
|
||
std::lock_guard<std::mutex> lock(mutex_);
|
||
received_buffers_++;
|
||
|
||
// 比较接收的缓冲区与测试缓冲区
|
||
if (compare_audio_buffers(message.buffer(), test_buffer_)) {
|
||
matching_buffers_++;
|
||
}
|
||
|
||
// 创建处理后的响应缓冲区
|
||
engine::AudioBuffer processed_buffer = message.buffer();
|
||
|
||
// 执行一些简单的处理 - 增益调整
|
||
float gain = 0.8f;
|
||
if (processed_buffer.format() == engine::AudioFormat::FLOAT32) {
|
||
float* data = processed_buffer.interleaved_data<float>();
|
||
for (size_t i = 0; i < processed_buffer.num_frames() * processed_buffer.num_channels(); ++i) {
|
||
data[i] *= gain;
|
||
}
|
||
}
|
||
|
||
// 发送处理后的响应
|
||
auto response = std::make_unique<AudioBufferMessage>(processed_buffer);
|
||
comm_manager_->send_message(*response);
|
||
|
||
cv_.notify_one();
|
||
}
|
||
|
||
// 等待特定数量的消息
|
||
bool wait_for_message_count(size_t count, std::chrono::milliseconds timeout = 5s) {
|
||
std::unique_lock<std::mutex> lock(mutex_);
|
||
return cv_.wait_for(lock, timeout, [this, count] {
|
||
return received_messages_.size() >= count;
|
||
});
|
||
}
|
||
|
||
// 等待特定数量的缓冲区
|
||
bool wait_for_buffer_count(size_t count, std::chrono::milliseconds timeout = 5s) {
|
||
std::unique_lock<std::mutex> lock(mutex_);
|
||
return cv_.wait_for(lock, timeout, [this, count] {
|
||
return received_buffers_ >= count;
|
||
});
|
||
}
|
||
|
||
protected:
|
||
communication::MessageFactory message_factory_;
|
||
engine::AudioBuffer test_buffer_;
|
||
|
||
// 同步变量
|
||
std::mutex mutex_;
|
||
std::condition_variable cv_;
|
||
std::vector<uint32_t> received_messages_;
|
||
size_t received_buffers_ = 0;
|
||
size_t matching_buffers_ = 0;
|
||
};
|
||
|
||
// ================================================================================================
|
||
// 基本通信测试
|
||
// ================================================================================================
|
||
TEST_F(EngineCommunicationIntegrationTest, BasicCommunication) {
|
||
// 创建客户端配置
|
||
communication::CommunicationConfig client_config;
|
||
client_config.process_name = "test_client";
|
||
client_config.routing_strategy = communication::RoutingStrategy::Auto;
|
||
client_config.enable_zmq = true;
|
||
|
||
// ZeroMQ配置
|
||
communication::ZmqConfig zmq_config;
|
||
zmq_config.endpoint = comm_endpoint_;
|
||
zmq_config.socket_type = ZMQ_REQ;
|
||
zmq_config.bind_instead_of_connect = false;
|
||
client_config.zmq_configs.push_back(zmq_config);
|
||
|
||
// 创建客户端管理器
|
||
auto client_manager = std::make_unique<communication::CommunicationManager>(
|
||
client_config, message_factory_);
|
||
|
||
// 初始化客户端
|
||
ASSERT_EQ(client_manager->initialize(), common::ErrorCode::Success);
|
||
|
||
// 创建测试消息
|
||
auto message = std::make_unique<TestAudioMessage>(1, "测试消息");
|
||
|
||
// 发送消息
|
||
ASSERT_EQ(client_manager->send_message(*message), common::ErrorCode::Success);
|
||
|
||
// 等待接收消息
|
||
ASSERT_TRUE(wait_for_message_count(1));
|
||
|
||
// 验证消息已收到
|
||
EXPECT_EQ(received_messages_.size(), 1);
|
||
EXPECT_EQ(received_messages_[0], 1);
|
||
|
||
// 接收响应
|
||
std::unique_ptr<communication::IMessage> response;
|
||
auto result = client_manager->receive_message(response, 1000);
|
||
|
||
// 验证响应
|
||
ASSERT_EQ(result, common::ErrorCode::Success);
|
||
ASSERT_NE(response, nullptr);
|
||
EXPECT_EQ(response->message_type(), "TestAudioMessage");
|
||
|
||
auto* typed_response = dynamic_cast<TestAudioMessage*>(response.get());
|
||
ASSERT_NE(typed_response, nullptr);
|
||
EXPECT_EQ(typed_response->sequence_number(), 1);
|
||
EXPECT_EQ(typed_response->content(), "响应: 测试消息");
|
||
|
||
// 关闭客户端
|
||
client_manager->shutdown();
|
||
}
|
||
|
||
// ================================================================================================
|
||
// 音频缓冲区传输测试
|
||
// ================================================================================================
|
||
TEST_F(EngineCommunicationIntegrationTest, AudioBufferTransfer) {
|
||
// 创建客户端配置,启用共享内存
|
||
communication::CommunicationConfig client_config;
|
||
client_config.process_name = "audio_client";
|
||
client_config.routing_strategy = communication::RoutingStrategy::Auto;
|
||
client_config.enable_zmq = true;
|
||
client_config.enable_shm = true;
|
||
|
||
// ZeroMQ配置
|
||
communication::ZmqConfig zmq_config;
|
||
zmq_config.endpoint = comm_endpoint_;
|
||
zmq_config.socket_type = ZMQ_REQ;
|
||
zmq_config.bind_instead_of_connect = false;
|
||
client_config.zmq_configs.push_back(zmq_config);
|
||
|
||
// 共享内存配置
|
||
client_config.shm_config.segment_name = shm_segment_;
|
||
client_config.shm_config.create_if_not_exists = false;
|
||
|
||
// 创建客户端管理器
|
||
auto client_manager = std::make_unique<communication::CommunicationManager>(
|
||
client_config, message_factory_);
|
||
|
||
// 初始化客户端
|
||
ASSERT_EQ(client_manager->initialize(), common::ErrorCode::Success);
|
||
|
||
// 创建测试音频缓冲区消息
|
||
auto message = std::make_unique<AudioBufferMessage>(test_buffer_);
|
||
|
||
// 发送缓冲区
|
||
ASSERT_EQ(client_manager->send_message(*message), common::ErrorCode::Success);
|
||
|
||
// 等待接收缓冲区
|
||
ASSERT_TRUE(wait_for_buffer_count(1));
|
||
|
||
// 验证缓冲区已收到且匹配
|
||
EXPECT_EQ(received_buffers_, 1);
|
||
EXPECT_EQ(matching_buffers_, 1);
|
||
|
||
// 接收响应
|
||
std::unique_ptr<communication::IMessage> response;
|
||
auto result = client_manager->receive_message(response, 1000);
|
||
|
||
// 验证响应
|
||
ASSERT_EQ(result, common::ErrorCode::Success);
|
||
ASSERT_NE(response, nullptr);
|
||
EXPECT_EQ(response->message_type(), "AudioBufferMessage");
|
||
|
||
auto* typed_response = dynamic_cast<AudioBufferMessage*>(response.get());
|
||
ASSERT_NE(typed_response, nullptr);
|
||
|
||
// 验证处理后的缓冲区 - 应该已应用0.8的增益
|
||
const auto& processed_buffer = typed_response->buffer();
|
||
EXPECT_EQ(processed_buffer.num_frames(), test_buffer_.num_frames());
|
||
EXPECT_EQ(processed_buffer.num_channels(), test_buffer_.num_channels());
|
||
EXPECT_EQ(processed_buffer.format(), test_buffer_.format());
|
||
|
||
// 检查增益是否正确应用
|
||
if (processed_buffer.format() == engine::AudioFormat::FLOAT32) {
|
||
const float* original_data = test_buffer_.interleaved_data<float>();
|
||
const float* processed_data = processed_buffer.interleaved_data<float>();
|
||
|
||
for (size_t i = 0; i < processed_buffer.num_frames() * processed_buffer.num_channels(); i += 100) {
|
||
EXPECT_NEAR(processed_data[i], original_data[i] * 0.8f, 0.0001f);
|
||
}
|
||
}
|
||
|
||
// 关闭客户端
|
||
client_manager->shutdown();
|
||
}
|
||
|
||
// ================================================================================================
|
||
// 大量消息传输测试
|
||
// ================================================================================================
|
||
TEST_F(EngineCommunicationIntegrationTest, HighVolumeMessageTransfer) {
|
||
// 创建客户端配置
|
||
communication::CommunicationConfig client_config;
|
||
client_config.process_name = "high_volume_client";
|
||
client_config.routing_strategy = communication::RoutingStrategy::Auto;
|
||
client_config.enable_zmq = true;
|
||
|
||
// ZeroMQ配置
|
||
communication::ZmqConfig zmq_config;
|
||
zmq_config.endpoint = comm_endpoint_;
|
||
zmq_config.socket_type = ZMQ_REQ;
|
||
zmq_config.bind_instead_of_connect = false;
|
||
client_config.zmq_configs.push_back(zmq_config);
|
||
|
||
// 创建客户端管理器
|
||
auto client_manager = std::make_unique<communication::CommunicationManager>(
|
||
client_config, message_factory_);
|
||
|
||
// 初始化客户端
|
||
ASSERT_EQ(client_manager->initialize(), common::ErrorCode::Success);
|
||
|
||
// 发送多个消息
|
||
const int message_count = 20;
|
||
|
||
for (int i = 0; i < message_count; ++i) {
|
||
// 创建测试消息
|
||
auto message = std::make_unique<TestAudioMessage>(i, "批量测试消息 " + std::to_string(i));
|
||
|
||
// 发送消息
|
||
ASSERT_EQ(client_manager->send_message(*message), common::ErrorCode::Success);
|
||
|
||
// 接收响应
|
||
std::unique_ptr<communication::IMessage> response;
|
||
auto result = client_manager->receive_message(response, 1000);
|
||
|
||
// 验证响应
|
||
ASSERT_EQ(result, common::ErrorCode::Success);
|
||
ASSERT_NE(response, nullptr);
|
||
|
||
auto* typed_response = dynamic_cast<TestAudioMessage*>(response.get());
|
||
ASSERT_NE(typed_response, nullptr);
|
||
EXPECT_EQ(typed_response->sequence_number(), i);
|
||
}
|
||
|
||
// 等待所有消息处理完成
|
||
std::this_thread::sleep_for(100ms);
|
||
|
||
// 验证接收到的消息数量
|
||
EXPECT_EQ(received_messages_.size(), message_count);
|
||
|
||
// 关闭客户端
|
||
client_manager->shutdown();
|
||
}
|
||
|
||
// ================================================================================================
|
||
// 并发通信测试
|
||
// ================================================================================================
|
||
TEST_F(EngineCommunicationIntegrationTest, ConcurrentCommunication) {
|
||
// 创建多个客户端管理器
|
||
const int client_count = 5;
|
||
std::vector<std::unique_ptr<communication::CommunicationManager>> clients;
|
||
|
||
for (int i = 0; i < client_count; ++i) {
|
||
// 创建客户端配置
|
||
communication::CommunicationConfig client_config;
|
||
client_config.process_name = "concurrent_client_" + std::to_string(i);
|
||
client_config.routing_strategy = communication::RoutingStrategy::Auto;
|
||
client_config.enable_zmq = true;
|
||
|
||
// ZeroMQ配置
|
||
communication::ZmqConfig zmq_config;
|
||
zmq_config.endpoint = comm_endpoint_;
|
||
zmq_config.socket_type = ZMQ_REQ;
|
||
zmq_config.bind_instead_of_connect = false;
|
||
client_config.zmq_configs.push_back(zmq_config);
|
||
|
||
// 创建客户端管理器
|
||
auto client = std::make_unique<communication::CommunicationManager>(
|
||
client_config, message_factory_);
|
||
|
||
// 初始化客户端
|
||
ASSERT_EQ(client->initialize(), common::ErrorCode::Success);
|
||
|
||
clients.push_back(std::move(client));
|
||
}
|
||
|
||
// 使用多线程同时发送消息
|
||
std::vector<std::thread> threads;
|
||
std::atomic<int> successful_messages(0);
|
||
|
||
for (int i = 0; i < client_count; ++i) {
|
||
threads.emplace_back([&, i]() {
|
||
// 每个客户端发送5条消息
|
||
for (int j = 0; j < 5; ++j) {
|
||
// 创建测试消息
|
||
auto message = std::make_unique<TestAudioMessage>(
|
||
i * 100 + j,
|
||
"并发客户端 " + std::to_string(i) + " 消息 " + std::to_string(j));
|
||
|
||
// 发送消息
|
||
if (clients[i]->send_message(*message) == common::ErrorCode::Success) {
|
||
// 接收响应
|
||
std::unique_ptr<communication::IMessage> response;
|
||
auto result = clients[i]->receive_message(response, 1000);
|
||
|
||
if (result == common::ErrorCode::Success && response) {
|
||
successful_messages++;
|
||
}
|
||
}
|
||
|
||
// 随机延迟
|
||
std::this_thread::sleep_for(std::chrono::milliseconds(rand() % 50));
|
||
}
|
||
});
|
||
}
|
||
|
||
// 等待所有线程完成
|
||
for (auto& thread : threads) {
|
||
thread.join();
|
||
}
|
||
|
||
// 验证成功消息数
|
||
EXPECT_EQ(successful_messages, client_count * 5);
|
||
|
||
// 关闭所有客户端
|
||
for (auto& client : clients) {
|
||
client->shutdown();
|
||
}
|
||
}
|
||
|
||
int main(int argc, char** argv) {
|
||
::testing::InitGoogleTest(&argc, argv);
|
||
return RUN_ALL_TESTS();
|
||
} |