// Catch2 tests for Compression Monitor // Migrated from GTest: compression_monitor_test.cpp #include #include #include #include #include #include #include #include using namespace yams::compression; using namespace std::chrono_literals; namespace { struct CompressionMonitorFixture { CompressionMonitorFixture() { // Reset global stats before each test to avoid cross-test interference MonitorConfig testConfig; testConfig.metricsInterval = std::chrono::seconds(1); testConfig.historyRetention = std::chrono::seconds(10); monitor_ = std::make_unique(testConfig); auto& stats = CompressionMonitor::getGlobalStats(); auto& mutex = CompressionMonitor::getGlobalStatsMutex(); std::lock_guard lock(mutex); stats = CompressionStats{}; } ~CompressionMonitorFixture() { if (monitor_ && monitor_->isRunning()) { monitor_->stop(); } } std::unique_ptr monitor_; }; } // namespace TEST_CASE_METHOD(CompressionMonitorFixture, "CompressionMonitor - StartStop", "[compression][monitor][catch2]") { CHECK_FALSE(monitor_->isRunning()); auto result = monitor_->start(); REQUIRE(result.has_value()); CHECK(monitor_->isRunning()); monitor_->stop(); CHECK_FALSE(monitor_->isRunning()); } TEST_CASE_METHOD(CompressionMonitorFixture, "CompressionMonitor - ConfigurationUpdate", "[compression][monitor][catch2]") { MonitorConfig config; config.metricsInterval = 5s; config.compressionRatioThreshold = 0.2; config.errorRateThreshold = 0.1; monitor_->updateConfig(config); auto retrieved = monitor_->getConfig(); CHECK(retrieved.metricsInterval == 5s); CHECK(retrieved.compressionRatioThreshold == 0.2); CHECK(retrieved.errorRateThreshold == 0.1); } TEST_CASE_METHOD(CompressionMonitorFixture, "CompressionMonitor - AlertCallback", "[compression][monitor][catch2]") { std::atomic alertCount{0}; Alert lastAlert; monitor_->registerAlertCallback([&alertCount, &lastAlert](const Alert& alert) { alertCount++; lastAlert = alert; }); // Configure to trigger alerts MonitorConfig config; config.compressionRatioThreshold = 10.0; // Impossible ratio monitor_->updateConfig(config); // Simulate some compression operations { CompressionTracker tracker(CompressionAlgorithm::Zstandard, 1000); CompressionResult result; result.originalSize = 1000; result.compressedSize = 900; // 1.11 ratio (below 10.0) result.algorithm = CompressionAlgorithm::Zstandard; result.duration = 10ms; tracker.complete(result); } // Manually trigger metric check monitor_->checkMetrics(); monitor_->checkAlgorithmHealth(CompressionAlgorithm::Zstandard); // Wait a bit for alert processing std::this_thread::sleep_for(100ms); CHECK(alertCount.load() > 0); // Allow either compression ratio or performance alert depending on platform timing CHECK((lastAlert.type == AlertType::LowCompressionRatio || lastAlert.type == AlertType::SlowPerformance)); } TEST_CASE_METHOD(CompressionMonitorFixture, "CompressionMonitor - TrackingOperations", "[compression][monitor][catch2]") { auto stats1 = monitor_->getCurrentStats(); auto initialCompressed = stats1.totalCompressedFiles.load(); // Track successful compression { CompressionTracker tracker(CompressionAlgorithm::Zstandard, 1000); CompressionResult result; result.originalSize = 1000; result.compressedSize = 500; result.algorithm = CompressionAlgorithm::Zstandard; result.duration = 5ms; tracker.complete(result); } auto stats2 = monitor_->getCurrentStats(); CHECK(stats2.totalCompressedFiles.load() == initialCompressed + 1); CHECK(stats2.totalSpaceSaved.load() == 500u); // Prime the LZMA entry { CompressionTracker tracker(CompressionAlgorithm::LZMA, 2000); CompressionResult result; result.originalSize = 2000; result.compressedSize = 1500; result.algorithm = CompressionAlgorithm::LZMA; result.duration = 5ms; tracker.complete(result); } // Track failed compression { CompressionTracker tracker(CompressionAlgorithm::LZMA, 2000); tracker.failed(); } auto stats3 = monitor_->getCurrentStats(); CHECK(stats3.algorithmStats[CompressionAlgorithm::LZMA].compressionErrors.load() > 0u); } TEST_CASE_METHOD(CompressionMonitorFixture, "CompressionMonitor - DecompressionTracking", "[compression][monitor][catch2]") { // Track decompression { DecompressionTracker tracker(CompressionAlgorithm::Zstandard, 500); tracker.complete(1000); } auto stats = monitor_->getCurrentStats(); CHECK(stats.algorithmStats[CompressionAlgorithm::Zstandard].filesDecompressed.load() > 0u); } TEST_CASE_METHOD(CompressionMonitorFixture, "CompressionMonitor - ExportFormats", "[compression][monitor][catch2]") { // Add some data { CompressionTracker tracker(CompressionAlgorithm::Zstandard, 1000); CompressionResult result; result.originalSize = 1000; result.compressedSize = 400; result.algorithm = CompressionAlgorithm::Zstandard; result.duration = 5ms; tracker.complete(result); } SECTION("Report export") { auto report = monitor_->exportReport(); CHECK_FALSE(report.empty()); CHECK(report.find("Compression Statistics") != std::string::npos); } SECTION("JSON export") { auto json = monitor_->exportJSON(); CHECK_FALSE(json.empty()); CHECK(json.find("totalCompressedFiles") != std::string::npos); CHECK(json.find("Zstandard") != std::string::npos); } } TEST_CASE_METHOD(CompressionMonitorFixture, "CompressionMonitor - MetricsHistory", "[compression][monitor][catch2]") { MonitorConfig config = monitor_->getConfig(); config.metricsInterval = std::chrono::seconds(1); config.historyRetention = std::chrono::seconds(10); monitor_->updateConfig(config); auto result = monitor_->start(); REQUIRE(result.has_value()); // Manually record a few snapshots monitor_->checkMetrics(); monitor_->checkMetrics(); auto history = monitor_->getHistory(std::chrono::seconds(2)); CHECK(history.size() >= 2u); } TEST_CASE_METHOD(CompressionMonitorFixture, "CompressionMonitor - ConcurrentOperations", "[compression][monitor][concurrent][catch2][.]") { const int numThreads = 4; const int operationsPerThread = 100; std::vector threads; for (int t = 0; t < numThreads; ++t) { threads.emplace_back([t]() { for (int i = 0; i < operationsPerThread; ++i) { CompressionTracker tracker(t % 2 == 0 ? CompressionAlgorithm::Zstandard : CompressionAlgorithm::LZMA, static_cast(1000 + i)); CompressionResult result; result.originalSize = static_cast(1000 + i); result.compressedSize = static_cast(500 + i / 2); result.algorithm = t % 2 == 0 ? CompressionAlgorithm::Zstandard : CompressionAlgorithm::LZMA; result.duration = std::chrono::milliseconds(1); tracker.complete(result); } }); } for (auto& thread : threads) { thread.join(); } auto stats = monitor_->getCurrentStats(); CHECK(stats.totalCompressedFiles.load() >= static_cast(numThreads * operationsPerThread)); } TEST_CASE_METHOD(CompressionMonitorFixture, "CompressionMonitor - CustomMetricCollector", "[compression][monitor][catch2]") { std::atomic collectorCalls{0}; monitor_->setMetricCollector([&collectorCalls](MetricsSnapshot& snapshot) { collectorCalls++; snapshot.cpuUsage = 50.0; snapshot.memoryUsage = 1024 * 1024; snapshot.activeThreads = 4; }); monitor_->checkMetrics(); CHECK(collectorCalls.load() > 0); }