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