479 lines
16 KiB
C++
479 lines
16 KiB
C++
// ================================================================================================
|
|
// Audio Backend - 共享内存测试
|
|
// ================================================================================================
|
|
|
|
#include <gtest/gtest.h>
|
|
#include <gmock/gmock.h>
|
|
#include "communication/shm/shared_memory.h"
|
|
#include "tests/common/test_fixtures.h"
|
|
#include <thread>
|
|
#include <chrono>
|
|
#include <vector>
|
|
#include <string>
|
|
#include <mutex>
|
|
#include <condition_variable>
|
|
#include <atomic>
|
|
|
|
using namespace audio_backend;
|
|
using namespace audio_backend::communication;
|
|
using namespace std::chrono_literals;
|
|
|
|
// 共享内存测试固定装置
|
|
class SharedMemoryTest : public test::CommunicationTest {
|
|
protected:
|
|
void SetUp() override {
|
|
test::CommunicationTest::SetUp();
|
|
|
|
// 创建基本配置
|
|
base_config_.segment_name = "audio_backend_test_shm";
|
|
base_config_.segment_size = 1024 * 1024; // 1MB
|
|
base_config_.create_if_not_exists = true;
|
|
base_config_.remove_on_destroy = true;
|
|
}
|
|
|
|
void TearDown() override {
|
|
// 确保共享内存管理器被销毁
|
|
shm_manager_.reset();
|
|
|
|
test::CommunicationTest::TearDown();
|
|
}
|
|
|
|
// 创建共享内存管理器
|
|
std::unique_ptr<SharedMemoryManager> create_shm_manager(bool creating = true) {
|
|
ShmConfig config = base_config_;
|
|
|
|
// 如果不是创建者,就不要移除共享内存
|
|
if (!creating) {
|
|
config.remove_on_destroy = false;
|
|
}
|
|
|
|
return std::make_unique<SharedMemoryManager>(config);
|
|
}
|
|
|
|
protected:
|
|
ShmConfig base_config_;
|
|
std::unique_ptr<SharedMemoryManager> shm_manager_;
|
|
};
|
|
|
|
// 测试创建和初始化
|
|
TEST_F(SharedMemoryTest, CreateAndInitialize) {
|
|
// 创建共享内存管理器
|
|
shm_manager_ = create_shm_manager();
|
|
|
|
// 验证创建状态
|
|
EXPECT_FALSE(shm_manager_->is_initialized());
|
|
|
|
// 验证配置
|
|
const auto& config = shm_manager_->get_config();
|
|
EXPECT_EQ(config.segment_name, base_config_.segment_name);
|
|
EXPECT_EQ(config.segment_size, base_config_.segment_size);
|
|
EXPECT_TRUE(config.create_if_not_exists);
|
|
EXPECT_TRUE(config.remove_on_destroy);
|
|
|
|
// 初始化
|
|
EXPECT_EQ(shm_manager_->initialize(), ShmError::Success);
|
|
EXPECT_TRUE(shm_manager_->is_initialized());
|
|
|
|
// 获取统计信息
|
|
const auto& stats = shm_manager_->get_statistics();
|
|
EXPECT_EQ(stats.total_size, base_config_.segment_size);
|
|
EXPECT_GT(stats.used_size, 0); // 至少有一些元数据
|
|
EXPECT_LT(stats.used_size, stats.total_size); // 但不会全部用完
|
|
EXPECT_EQ(stats.allocation_count, 0); // 还没有分配任何对象
|
|
}
|
|
|
|
// 测试对象分配和释放
|
|
TEST_F(SharedMemoryTest, AllocateAndDeallocate) {
|
|
// 创建和初始化共享内存管理器
|
|
shm_manager_ = create_shm_manager();
|
|
ASSERT_EQ(shm_manager_->initialize(), ShmError::Success);
|
|
|
|
// 分配简单对象
|
|
int* test_int = shm_manager_->allocate_object<int>("test_int");
|
|
ASSERT_NE(test_int, nullptr);
|
|
|
|
// 设置值
|
|
*test_int = 42;
|
|
|
|
// 查找对象
|
|
int* found_int = shm_manager_->find_object<int>("test_int");
|
|
ASSERT_NE(found_int, nullptr);
|
|
EXPECT_EQ(*found_int, 42);
|
|
|
|
// 验证统计信息
|
|
const auto& stats_after_alloc = shm_manager_->get_statistics();
|
|
EXPECT_EQ(stats_after_alloc.allocation_count, 1);
|
|
EXPECT_GT(stats_after_alloc.used_size, sizeof(int)); // 包括元数据和对象
|
|
|
|
// 修改值并验证共享状态
|
|
*test_int = 100;
|
|
EXPECT_EQ(*found_int, 100);
|
|
|
|
// 释放对象
|
|
bool deallocated = shm_manager_->deallocate_object<int>("test_int");
|
|
EXPECT_TRUE(deallocated);
|
|
|
|
// 释放后应找不到对象
|
|
int* not_found = shm_manager_->find_object<int>("test_int");
|
|
EXPECT_EQ(not_found, nullptr);
|
|
|
|
// 验证统计信息
|
|
const auto& stats_after_dealloc = shm_manager_->get_statistics();
|
|
EXPECT_EQ(stats_after_dealloc.allocation_count, 0);
|
|
EXPECT_EQ(stats_after_dealloc.used_size, stats_after_dealloc.used_size); // 应该回到初始状态
|
|
}
|
|
|
|
// 测试多个共享内存管理器访问相同的共享内存段
|
|
TEST_F(SharedMemoryTest, MultipleManagers) {
|
|
// 创建第一个管理器(创建共享内存段)
|
|
auto manager1 = create_shm_manager(true); // 创建者
|
|
ASSERT_EQ(manager1->initialize(), ShmError::Success);
|
|
|
|
// 分配一些对象
|
|
int* int_obj = manager1->allocate_object<int>("shared_int");
|
|
ASSERT_NE(int_obj, nullptr);
|
|
*int_obj = 42;
|
|
|
|
float* float_obj = manager1->allocate_object<float>("shared_float");
|
|
ASSERT_NE(float_obj, nullptr);
|
|
*float_obj = 3.14159f;
|
|
|
|
// 创建第二个管理器(访问现有共享内存段)
|
|
auto manager2 = create_shm_manager(false); // 非创建者
|
|
ASSERT_EQ(manager2->initialize(), ShmError::Success);
|
|
|
|
// 查找和验证对象
|
|
int* found_int = manager2->find_object<int>("shared_int");
|
|
ASSERT_NE(found_int, nullptr);
|
|
EXPECT_EQ(*found_int, 42);
|
|
|
|
float* found_float = manager2->find_object<float>("shared_float");
|
|
ASSERT_NE(found_float, nullptr);
|
|
EXPECT_FLOAT_EQ(*found_float, 3.14159f);
|
|
|
|
// 通过第二个管理器修改值
|
|
*found_int = 100;
|
|
*found_float = 2.71828f;
|
|
|
|
// 验证第一个管理器是否看到更改
|
|
EXPECT_EQ(*int_obj, 100);
|
|
EXPECT_FLOAT_EQ(*float_obj, 2.71828f);
|
|
}
|
|
|
|
// 测试复杂对象和结构体
|
|
TEST_F(SharedMemoryTest, ComplexStructures) {
|
|
// 创建和初始化共享内存管理器
|
|
shm_manager_ = create_shm_manager();
|
|
ASSERT_EQ(shm_manager_->initialize(), ShmError::Success);
|
|
|
|
// 定义复杂结构
|
|
struct ComplexStruct {
|
|
int id;
|
|
float values[10];
|
|
double ratio;
|
|
char name[64];
|
|
};
|
|
|
|
// 分配结构
|
|
ComplexStruct* complex_obj = shm_manager_->allocate_object<ComplexStruct>("complex_struct");
|
|
ASSERT_NE(complex_obj, nullptr);
|
|
|
|
// 初始化结构
|
|
complex_obj->id = 123;
|
|
for (int i = 0; i < 10; i++) {
|
|
complex_obj->values[i] = i * 1.5f;
|
|
}
|
|
complex_obj->ratio = 16.0 / 9.0;
|
|
strcpy(complex_obj->name, "音频后端测试结构");
|
|
|
|
// 查找和验证
|
|
ComplexStruct* found_struct = shm_manager_->find_object<ComplexStruct>("complex_struct");
|
|
ASSERT_NE(found_struct, nullptr);
|
|
EXPECT_EQ(found_struct->id, 123);
|
|
for (int i = 0; i < 10; i++) {
|
|
EXPECT_FLOAT_EQ(found_struct->values[i], i * 1.5f);
|
|
}
|
|
EXPECT_DOUBLE_EQ(found_struct->ratio, 16.0 / 9.0);
|
|
EXPECT_STREQ(found_struct->name, "音频后端测试结构");
|
|
}
|
|
|
|
// 测试环形缓冲区
|
|
TEST_F(SharedMemoryTest, RingBufferTest) {
|
|
// 创建和初始化共享内存管理器
|
|
shm_manager_ = create_shm_manager();
|
|
ASSERT_EQ(shm_manager_->initialize(), ShmError::Success);
|
|
|
|
// 创建环形缓冲区
|
|
const size_t buffer_capacity = 1024;
|
|
RingBuffer<float> ring_buffer(*shm_manager_, "audio_samples", buffer_capacity);
|
|
|
|
// 验证初始状态
|
|
EXPECT_TRUE(ring_buffer.empty());
|
|
EXPECT_FALSE(ring_buffer.full());
|
|
EXPECT_EQ(ring_buffer.capacity(), buffer_capacity);
|
|
EXPECT_EQ(ring_buffer.available(), 0);
|
|
|
|
// 测试单个元素推入和弹出
|
|
float test_sample = 0.5f;
|
|
EXPECT_TRUE(ring_buffer.write(&test_sample, 1));
|
|
EXPECT_FALSE(ring_buffer.empty());
|
|
EXPECT_EQ(ring_buffer.available(), 1);
|
|
|
|
float output_sample;
|
|
EXPECT_TRUE(ring_buffer.read(&output_sample, 1));
|
|
EXPECT_FLOAT_EQ(output_sample, test_sample);
|
|
EXPECT_TRUE(ring_buffer.empty());
|
|
|
|
// 测试批量操作
|
|
std::vector<float> input_samples(100);
|
|
for (size_t i = 0; i < input_samples.size(); ++i) {
|
|
input_samples[i] = static_cast<float>(i) / 100.0f;
|
|
}
|
|
|
|
size_t pushed = ring_buffer.write(input_samples.data(), input_samples.size());
|
|
EXPECT_EQ(pushed, input_samples.size());
|
|
EXPECT_EQ(ring_buffer.available(), input_samples.size());
|
|
|
|
std::vector<float> output_samples(input_samples.size());
|
|
size_t popped = ring_buffer.read(output_samples.data(), output_samples.size());
|
|
EXPECT_EQ(popped, input_samples.size());
|
|
|
|
for (size_t i = 0; i < input_samples.size(); ++i) {
|
|
EXPECT_FLOAT_EQ(output_samples[i], input_samples[i]);
|
|
}
|
|
}
|
|
|
|
// 测试三缓冲机制
|
|
TEST_F(SharedMemoryTest, TripleBufferTest) {
|
|
// 创建和初始化共享内存管理器
|
|
shm_manager_ = create_shm_manager();
|
|
ASSERT_EQ(shm_manager_->initialize(), ShmError::Success);
|
|
|
|
// 创建三缓冲
|
|
TripleBuffer<std::array<float, 512>> triple_buffer(*shm_manager_, "audio_frames");
|
|
|
|
// 验证初始状态
|
|
EXPECT_FALSE(triple_buffer.has_new_data());
|
|
|
|
// 生产者写入数据
|
|
auto* write_buffer = triple_buffer.get_write_buffer();
|
|
ASSERT_NE(write_buffer, nullptr);
|
|
|
|
// 填充测试数据
|
|
for (size_t i = 0; i < write_buffer->size(); ++i) {
|
|
(*write_buffer)[i] = static_cast<float>(i) / 512.0f;
|
|
}
|
|
|
|
// 提交写入
|
|
triple_buffer.commit_write();
|
|
EXPECT_TRUE(triple_buffer.has_new_data());
|
|
|
|
// 消费者读取数据
|
|
const auto* read_buffer = triple_buffer.get_read_buffer();
|
|
ASSERT_NE(read_buffer, nullptr);
|
|
|
|
// 验证数据
|
|
for (size_t i = 0; i < read_buffer->size(); ++i) {
|
|
EXPECT_FLOAT_EQ((*read_buffer)[i], static_cast<float>(i) / 512.0f);
|
|
}
|
|
|
|
// 提交读取
|
|
triple_buffer.commit_read();
|
|
EXPECT_FALSE(triple_buffer.has_new_data());
|
|
}
|
|
|
|
// 测试共享内存的并发安全性
|
|
TEST_F(SharedMemoryTest, ConcurrentAccess) {
|
|
// 创建和初始化共享内存管理器
|
|
shm_manager_ = create_shm_manager();
|
|
ASSERT_EQ(shm_manager_->initialize(), ShmError::Success);
|
|
|
|
// 创建环形缓冲区
|
|
const size_t buffer_capacity = 1024;
|
|
RingBuffer<int> ring_buffer(*shm_manager_, "concurrent_test", buffer_capacity);
|
|
|
|
// 创建多个线程同时访问
|
|
const int num_producers = 4;
|
|
const int num_consumers = 4;
|
|
const int items_per_producer = 1000;
|
|
|
|
std::atomic<int> total_produced(0);
|
|
std::atomic<int> total_consumed(0);
|
|
|
|
// 创建生产者
|
|
std::vector<std::thread> producers;
|
|
for (int p = 0; p < num_producers; ++p) {
|
|
producers.emplace_back([&, p]() {
|
|
for (int i = 0; i < items_per_producer; ++i) {
|
|
int value = p * items_per_producer + i;
|
|
while (!ring_buffer.write(&value, 1)) {
|
|
// 缓冲区满,等待一下
|
|
std::this_thread::yield();
|
|
}
|
|
total_produced++;
|
|
}
|
|
});
|
|
}
|
|
|
|
// 创建消费者
|
|
std::vector<std::thread> consumers;
|
|
std::vector<std::set<int>> consumed_values(num_consumers);
|
|
|
|
for (int c = 0; c < num_consumers; ++c) {
|
|
consumers.emplace_back([&, c]() {
|
|
while (total_consumed < num_producers * items_per_producer) {
|
|
int value;
|
|
if (ring_buffer.read(&value, 1)) {
|
|
consumed_values[c].insert(value);
|
|
total_consumed++;
|
|
} else {
|
|
// 缓冲区空,等待一下
|
|
std::this_thread::yield();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// 等待所有生产者完成
|
|
for (auto& t : producers) {
|
|
t.join();
|
|
}
|
|
|
|
// 等待所有消费者完成
|
|
for (auto& t : consumers) {
|
|
t.join();
|
|
}
|
|
|
|
// 验证所有的项都被消费了
|
|
EXPECT_EQ(total_produced.load(), num_producers * items_per_producer);
|
|
EXPECT_EQ(total_consumed.load(), num_producers * items_per_producer);
|
|
|
|
// 合并所有消费者的集合
|
|
std::set<int> all_consumed;
|
|
for (const auto& set : consumed_values) {
|
|
all_consumed.insert(set.begin(), set.end());
|
|
}
|
|
|
|
// 验证每个项只被消费了一次
|
|
EXPECT_EQ(all_consumed.size(), num_producers * items_per_producer);
|
|
|
|
// 验证所有项都被消费了
|
|
for (int p = 0; p < num_producers; ++p) {
|
|
for (int i = 0; i < items_per_producer; ++i) {
|
|
int value = p * items_per_producer + i;
|
|
EXPECT_TRUE(all_consumed.find(value) != all_consumed.end());
|
|
}
|
|
}
|
|
}
|
|
|
|
// 测试错误处理
|
|
TEST_F(SharedMemoryTest, ErrorHandling) {
|
|
// 创建配置,但不创建共享内存
|
|
ShmConfig config = base_config_;
|
|
config.create_if_not_exists = false; // 不创建新的
|
|
|
|
// 尝试访问不存在的共享内存
|
|
auto manager = std::make_unique<SharedMemoryManager>(config);
|
|
EXPECT_NE(manager->initialize(), ShmError::Success);
|
|
|
|
// 正确初始化
|
|
shm_manager_ = create_shm_manager();
|
|
ASSERT_EQ(shm_manager_->initialize(), ShmError::Success);
|
|
|
|
// 尝试查找不存在的对象
|
|
int* not_found = shm_manager_->find_object<int>("non_existent_object");
|
|
EXPECT_EQ(not_found, nullptr);
|
|
|
|
// 尝试释放不存在的对象
|
|
bool deallocated = shm_manager_->deallocate_object<int>("non_existent_object");
|
|
EXPECT_FALSE(deallocated);
|
|
|
|
// 创建对象然后分配同名对象(应失败)
|
|
int* obj1 = shm_manager_->allocate_object<int>("duplicate");
|
|
ASSERT_NE(obj1, nullptr);
|
|
*obj1 = 42;
|
|
|
|
int* obj2 = shm_manager_->allocate_object<int>("duplicate");
|
|
EXPECT_EQ(obj2, nullptr);
|
|
|
|
// 检查第一个对象是否还完好
|
|
int* check = shm_manager_->find_object<int>("duplicate");
|
|
ASSERT_NE(check, nullptr);
|
|
EXPECT_EQ(*check, 42);
|
|
}
|
|
|
|
// 测试性能和资源利用
|
|
TEST_F(SharedMemoryTest, PerformanceAndResource) {
|
|
// 创建更大的共享内存段
|
|
ShmConfig large_config = base_config_;
|
|
large_config.segment_size = 10 * 1024 * 1024; // 10MB
|
|
|
|
auto large_manager = std::make_unique<SharedMemoryManager>(large_config);
|
|
ASSERT_EQ(large_manager->initialize(), ShmError::Success);
|
|
|
|
// 获取初始统计信息
|
|
const auto& initial_stats = large_manager->get_statistics();
|
|
|
|
// 分配大量小对象
|
|
const int num_objects = 1000;
|
|
std::vector<int*> objects;
|
|
|
|
for (int i = 0; i < num_objects; ++i) {
|
|
std::string name = "obj_" + std::to_string(i);
|
|
int* obj = large_manager->allocate_object<int>(name);
|
|
ASSERT_NE(obj, nullptr);
|
|
*obj = i;
|
|
objects.push_back(obj);
|
|
}
|
|
|
|
// 验证统计信息
|
|
const auto& after_alloc_stats = large_manager->get_statistics();
|
|
EXPECT_EQ(after_alloc_stats.allocation_count, num_objects);
|
|
EXPECT_GT(after_alloc_stats.used_size, initial_stats.used_size);
|
|
|
|
// 验证所有对象的值
|
|
for (int i = 0; i < num_objects; ++i) {
|
|
EXPECT_EQ(*objects[i], i);
|
|
}
|
|
|
|
// 释放一半对象
|
|
for (int i = 0; i < num_objects / 2; ++i) {
|
|
std::string name = "obj_" + std::to_string(i);
|
|
bool deallocated = large_manager->deallocate_object<int>(name);
|
|
EXPECT_TRUE(deallocated);
|
|
}
|
|
|
|
// 验证统计信息
|
|
const auto& after_dealloc_stats = large_manager->get_statistics();
|
|
EXPECT_EQ(after_dealloc_stats.allocation_count, num_objects / 2);
|
|
EXPECT_LT(after_dealloc_stats.used_size, after_alloc_stats.used_size);
|
|
|
|
// 确保我们可以再次分配这些对象
|
|
for (int i = 0; i < num_objects / 2; ++i) {
|
|
std::string name = "obj_" + std::to_string(i);
|
|
int* obj = large_manager->allocate_object<int>(name);
|
|
ASSERT_NE(obj, nullptr);
|
|
*obj = i + 1000; // 使用不同的值
|
|
}
|
|
|
|
// 验证所有对象的值
|
|
for (int i = 0; i < num_objects / 2; ++i) {
|
|
std::string name = "obj_" + std::to_string(i);
|
|
int* obj = large_manager->find_object<int>(name);
|
|
ASSERT_NE(obj, nullptr);
|
|
EXPECT_EQ(*obj, i + 1000);
|
|
}
|
|
|
|
// 验证另一半对象的值
|
|
for (int i = num_objects / 2; i < num_objects; ++i) {
|
|
std::string name = "obj_" + std::to_string(i);
|
|
int* obj = large_manager->find_object<int>(name);
|
|
ASSERT_NE(obj, nullptr);
|
|
EXPECT_EQ(*obj, i);
|
|
}
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
::testing::InitGoogleTest(&argc, argv);
|
|
return RUN_ALL_TESTS();
|
|
} |