#include "ChaosModule.h" #include "grove/JsonDataNode.h" #include #include #include namespace grove { void ChaosModule::setConfiguration(const IDataNode& configNode, IIO* io, ITaskScheduler* scheduler) { // Logger logger = spdlog::get("ChaosModule"); if (!logger) { logger = spdlog::stdout_color_mt("ChaosModule"); } logger->set_level(spdlog::level::debug); // Clone config const auto* jsonConfigNode = dynamic_cast(&configNode); if (jsonConfigNode) { config = std::make_unique("config", jsonConfigNode->getJsonData()); } else { config = std::make_unique("config"); } // Lire config int seed = configNode.getInt("seed", 42); hotReloadProbability = static_cast(configNode.getDouble("hotReloadProbability", 0.30)); crashProbability = static_cast(configNode.getDouble("crashProbability", 0.10)); corruptionProbability = static_cast(configNode.getDouble("corruptionProbability", 0.10)); invalidConfigProbability = static_cast(configNode.getDouble("invalidConfigProbability", 0.05)); // Initialiser RNG rng.seed(seed); logger->info("Initializing ChaosModule"); logger->info(" Seed: {}", seed); logger->info(" Hot-reload probability: {}", hotReloadProbability); logger->info(" Crash probability: {}", crashProbability); logger->info(" Corruption probability: {}", corruptionProbability); logger->info(" Invalid config probability: {}", invalidConfigProbability); frameCount = 0; crashCount = 0; corruptionCount = 0; hotReloadCount = 0; } const IDataNode& ChaosModule::getConfiguration() { return *config; } void ChaosModule::process(const IDataNode& input) { isProcessing = true; frameCount++; // VRAI CHAOS: Tire aléatoirement À CHAQUE FRAME // Pas de "toutes les 60 frames", on peut crasher N'IMPORTE QUAND std::uniform_real_distribution dist(0.0f, 1.0f); float roll = dist(rng); // Crash aléatoire (10% par frame = crash très fréquent) if (roll < crashProbability) { triggerChaosEvent(); } // Si état corrompu, on DOIT crasher if (isCorrupted) { logger->error("❌ FATAL: State is corrupted! Module cannot continue."); throw std::runtime_error("FATAL: State corrupted - module is in invalid state"); } isProcessing = false; } void ChaosModule::triggerChaosEvent() { crashCount++; // Plusieurs TYPES de crashes différents pour tester la robustesse std::uniform_int_distribution crashTypeDist(0, 4); int crashType = crashTypeDist(rng); switch (crashType) { case 0: logger->warn("💥 Chaos: CRASH - runtime_error"); throw std::runtime_error("CRASH: Simulated runtime error at frame " + std::to_string(frameCount)); case 1: logger->warn("💥 Chaos: CRASH - logic_error"); throw std::logic_error("CRASH: Logic error - invalid state transition at frame " + std::to_string(frameCount)); case 2: logger->warn("💥 Chaos: CRASH - out_of_range"); throw std::out_of_range("CRASH: Out of range access at frame " + std::to_string(frameCount)); case 3: logger->warn("💥 Chaos: CRASH - domain_error"); throw std::domain_error("CRASH: Domain error in computation at frame " + std::to_string(frameCount)); case 4: // STATE CORRUPTION (plus vicieux - l'état devient invalide) logger->warn("☠️ Chaos: STATE CORRUPTION - module will fail on next frame"); corruptionCount++; isCorrupted = true; // Pas de throw ici - on va crasher à la PROCHAINE frame break; } } std::unique_ptr ChaosModule::getHealthStatus() { nlohmann::json healthJson; healthJson["status"] = isCorrupted ? "corrupted" : "healthy"; healthJson["frameCount"] = frameCount; healthJson["crashCount"] = crashCount; healthJson["corruptionCount"] = corruptionCount; healthJson["hotReloadCount"] = hotReloadCount; return std::make_unique("health", healthJson); } void ChaosModule::shutdown() { logger->info("Shutting down ChaosModule"); logger->info(" Total frames: {}", frameCount); logger->info(" Crashes: {}", crashCount); logger->info(" Corruptions: {}", corruptionCount); logger->info(" Hot-reloads: {}", hotReloadCount); } std::string ChaosModule::getType() const { return "chaos"; } std::unique_ptr ChaosModule::getState() { nlohmann::json json; json["frameCount"] = frameCount; json["crashCount"] = crashCount; json["corruptionCount"] = corruptionCount; json["hotReloadCount"] = hotReloadCount; json["isCorrupted"] = isCorrupted; json["seed"] = 42; // Pour reproductibilité return std::make_unique("state", json); } void ChaosModule::setState(const IDataNode& state) { const auto* jsonNode = dynamic_cast(&state); if (!jsonNode) { if (logger) { logger->error("setState: Invalid state (not JsonDataNode)"); } return; } const auto& json = jsonNode->getJsonData(); // Ensure logger is initialized (needed after hot-reload) if (!logger) { logger = spdlog::get("ChaosModule"); if (!logger) { logger = spdlog::stdout_color_mt("ChaosModule"); } } // Ensure config is initialized (needed after hot-reload) if (!config) { config = std::make_unique("config"); } // VALIDATION CRITIQUE: Refuser l'état corrompu bool wasCorrupted = json.value("isCorrupted", false); if (wasCorrupted) { logger->error("🚫 REJECTED: Cannot restore corrupted state!"); logger->error(" The module was corrupted before hot-reload."); logger->error(" Resetting to clean state instead."); // Reset à un état propre au lieu de restaurer la corruption frameCount = 0; crashCount = 0; corruptionCount = 0; hotReloadCount = 0; isCorrupted = false; int seed = json.value("seed", 42); rng.seed(seed); logger->warn("⚠️ State reset due to corruption - module continues with fresh state"); return; } // Restaurer state sain frameCount = json.value("frameCount", 0); crashCount = json.value("crashCount", 0); corruptionCount = json.value("corruptionCount", 0); hotReloadCount = json.value("hotReloadCount", 0); isCorrupted = false; // Toujours false après validation int seed = json.value("seed", 42); rng.seed(seed); logger->info("State restored: frame {}, crashes {}, corruptions {}, hotReloads {}", frameCount, crashCount, corruptionCount, hotReloadCount); } } // namespace grove // Export symbols extern "C" { grove::IModule* createModule() { return new grove::ChaosModule(); } void destroyModule(grove::IModule* module) { delete module; } }