at
This commit is contained in:
488
tests/integration/engine_communication_test.cpp
Normal file
488
tests/integration/engine_communication_test.cpp
Normal file
@@ -0,0 +1,488 @@
|
||||
// ================================================================================================
|
||||
// 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();
|
||||
}
|
||||
Reference in New Issue
Block a user