#include #include #include #include #include "pipeline/output/output_manager.hpp" #include "pipeline/common/logger.hpp" namespace fs = std::filesystem; namespace pipeline { class OutputManagerTest : public ::testing::Test { protected: void SetUp() override { // 创建测试目录 test_dir_ = "/tmp/test_output_manager"; if (fs::exists(test_dir_)) { fs::remove_all(test_dir_); } fs::create_directories(test_dir_); // 创建测试帧 test_frame_ = cv::Mat(480, 640, CV_8UC3, cv::Scalar(0, 0, 0)); } void TearDown() override { if (fs::exists(test_dir_)) { fs::remove_all(test_dir_); } } // 创建视频输出配置 OutputTargetConfig createVideoConfig(const std::string& name) { OutputTargetConfig config; config.type = "video"; config.name = name; config.path = test_dir_ + "/" + name + ".mp4"; config.fps = 30; config.codec = "h264"; config.bitrate = 4000000; return config; } // 创建RTSP输出配置 OutputTargetConfig createRtspConfig(const std::string& name) { OutputTargetConfig config; config.type = "rtsp"; config.name = name; config.path = "rtsp://localhost:8554/" + name; config.fps = 30; config.codec = "h264"; config.bitrate = 4000000; return config; } std::string test_dir_; cv::Mat test_frame_; }; // 测试基本功能 TEST_F(OutputManagerTest, BasicFunctionality) { OutputManager manager; // 添加输出目标 auto video_config = createVideoConfig("test_video"); EXPECT_TRUE(manager.addTarget(video_config)); auto rtsp_config = createRtspConfig("test_rtsp"); EXPECT_TRUE(manager.addTarget(rtsp_config)); // 验证目标数量 EXPECT_EQ(manager.getTargetCount(), 2); // 验证目标名称 auto names = manager.getTargetNames(); EXPECT_EQ(names.size(), 2); EXPECT_TRUE(std::find(names.begin(), names.end(), "test_video") != names.end()); EXPECT_TRUE(std::find(names.begin(), names.end(), "test_rtsp") != names.end()); } // 测试输入源到输出目标的映射 TEST_F(OutputManagerTest, SourceTargetMapping) { OutputManager manager; // 添加视频输出目标 OutputTargetConfig video_config; video_config.type = "video"; video_config.name = "test_video_map"; video_config.path = "/tmp/test_output_manager/test_video_map.mp4"; ASSERT_TRUE(manager.addTarget(video_config)); // 添加源到目标的映射 ASSERT_TRUE(manager.addSourceTargetMapping("source1", {"test_video_map"})); // 写入帧 ASSERT_TRUE(manager.writeFrames("source1", test_frame_)); // 验证输出文件存在 ASSERT_TRUE(fs::exists(video_config.path)); } // 测试错误处理 TEST_F(OutputManagerTest, ErrorHandling) { OutputManager manager; // 测试添加重复目标 auto video_config = createVideoConfig("test_video_error"); EXPECT_TRUE(manager.addTarget(video_config)); EXPECT_FALSE(manager.addTarget(video_config)); // 测试无效的映射 std::vector targets = {"non_existent_target"}; EXPECT_FALSE(manager.addSourceTargetMapping("source", targets)); // 测试写入不存在的源 EXPECT_FALSE(manager.writeFrames("non_existent_source", test_frame_)); // 测试空帧 cv::Mat empty_frame; EXPECT_FALSE(manager.writeFrames("source", empty_frame)); } // 测试资源管理 TEST_F(OutputManagerTest, ResourceManagement) { OutputManager manager; // 添加多个目标 auto video_config = createVideoConfig("test_video_resource"); EXPECT_TRUE(manager.addTarget(video_config)); auto rtsp_config = createRtspConfig("test_rtsp_resource"); EXPECT_TRUE(manager.addTarget(rtsp_config)); // 添加映射 std::vector targets = {"test_video_resource", "test_rtsp_resource"}; EXPECT_TRUE(manager.addSourceTargetMapping("source", targets)); // 移除映射 EXPECT_TRUE(manager.removeSourceMapping("source")); EXPECT_FALSE(manager.writeFrames("source", test_frame_)); // 移除目标 EXPECT_TRUE(manager.removeTarget("test_video_resource")); EXPECT_EQ(manager.getTargetCount(), 1); // 清理所有资源 manager.cleanup(); EXPECT_EQ(manager.getTargetCount(), 0); } // 测试并发写入 TEST_F(OutputManagerTest, ConcurrentWrite) { OutputManager manager; // 添加两个视频输出目标 auto video_config1 = createVideoConfig("test_video_concurrent1"); ASSERT_TRUE(manager.addTarget(video_config1)); auto video_config2 = createVideoConfig("test_video_concurrent2"); ASSERT_TRUE(manager.addTarget(video_config2)); // 添加源到目标的映射 ASSERT_TRUE(manager.addSourceTargetMapping("source1", {"test_video_concurrent1"})); ASSERT_TRUE(manager.addSourceTargetMapping("source2", {"test_video_concurrent2"})); // 创建两个线程同时写入不同的输出目标 std::thread t1([&]() { for (int i = 0; i < 10; ++i) { EXPECT_TRUE(manager.writeFrames("source1", test_frame_)); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } }); std::thread t2([&]() { for (int i = 0; i < 10; ++i) { EXPECT_TRUE(manager.writeFrames("source2", test_frame_)); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } }); // 等待线程完成 t1.join(); t2.join(); // 验证输出文件存在 ASSERT_TRUE(fs::exists(video_config1.path)); ASSERT_TRUE(fs::exists(video_config2.path)); } // 测试一个输入源映射到多个输出目标 TEST_F(OutputManagerTest, MultipleTargetsMapping) { OutputManager manager; // 添加多个输出目标 auto video_config1 = createVideoConfig("test_video_multi1"); ASSERT_TRUE(manager.addTarget(video_config1)); auto video_config2 = createVideoConfig("test_video_multi2"); ASSERT_TRUE(manager.addTarget(video_config2)); auto video_config3 = createVideoConfig("test_video_multi3"); ASSERT_TRUE(manager.addTarget(video_config3)); // 将一个输入源映射到多个输出目标 std::vector targets = { "test_video_multi1", "test_video_multi2", "test_video_multi3" }; ASSERT_TRUE(manager.addSourceTargetMapping("source_multi", targets)); // 写入帧到所有映射的目标 ASSERT_TRUE(manager.writeFrames("source_multi", test_frame_)); // 验证所有输出文件都存在 ASSERT_TRUE(fs::exists(video_config1.path)); ASSERT_TRUE(fs::exists(video_config2.path)); ASSERT_TRUE(fs::exists(video_config3.path)); } // 测试FPS参数边界值 TEST_F(OutputManagerTest, FpsBoundaryTest) { OutputManager manager; // 测试FPS为0 auto config_fps_zero = createVideoConfig("test_video_fps_zero"); config_fps_zero.fps = 0; EXPECT_FALSE(manager.addTarget(config_fps_zero)); // 测试FPS为负数 auto config_fps_negative = createVideoConfig("test_video_fps_negative"); config_fps_negative.fps = -30; EXPECT_FALSE(manager.addTarget(config_fps_negative)); // 测试FPS为最小有效值 auto config_fps_min = createVideoConfig("test_video_fps_min"); config_fps_min.fps = 1; EXPECT_TRUE(manager.addTarget(config_fps_min)); // 测试FPS为正常值 auto config_fps_normal = createVideoConfig("test_video_fps_normal"); config_fps_normal.fps = 60; EXPECT_TRUE(manager.addTarget(config_fps_normal)); // 验证正常FPS的输出是否工作 ASSERT_TRUE(manager.addSourceTargetMapping("source_fps", {"test_video_fps_normal"})); ASSERT_TRUE(manager.writeFrames("source_fps", test_frame_)); ASSERT_TRUE(fs::exists(config_fps_normal.path)); } } // namespace pipeline