# Plan Complet : Système de Tests d'Intégration avec Modules Dynamiques **Objectif** : Créer un système de tests d'intégration qui valide le fonctionnement complet d'AISSIA en conditions réelles, en utilisant l'architecture modulaire de GroveEngine pour rendre chaque test isolé, extensible et hot-reloadable. **Date** : 2025-11-28 **Auteur** : Claude Code --- ## 1. Vision et Objectifs ### 1.1 But Principal Valider automatiquement qu'AISSIA fonctionne correctement en **conditions réelles** : - Communication inter-modules via IIO - Services infrastructure (LLM, Storage, Platform, Voice) - MCP tools (17 tools internes + externes) - Flux complets end-to-end (Voice → AI → LLM → Storage → Voice) ### 1.2 Philosophie **"Un module = Un test"** Chaque test d'intégration est un module GroveEngine indépendant : - Chargé dynamiquement par le TestRunner - Exécute un scénario spécifique - Retourne un résultat (pass/fail + détails) - Peut être modifié et hot-reload sans tout recompiler ### 1.3 Avantages ✅ **Isolation** : Chaque test ne pollue pas les autres ✅ **Extensibilité** : Ajouter un test = ajouter un fichier .cpp + .so ✅ **Debugging** : Logs clairs par test, facile à identifier les problèmes ✅ **Hot-Reload** : Modifier un test sans redémarrer tout le système ✅ **Démo GroveEngine** : Montre la puissance du module system ✅ **CI/CD Ready** : Exit code, JSON output, automation-friendly --- ## 2. Architecture Globale ### 2.1 Vue d'Ensemble ``` ┌─────────────────────────────────────────────────────┐ │ AISSIA --run-tests │ │ │ │ ┌────────────────────────────────────────────┐ │ │ │ TestRunnerModule │ │ │ │ (Orchestrateur de tests) │ │ │ │ │ │ │ │ 1. Charge config/test_runner.json │ │ │ │ 2. Découvre tests/ IT_*.so │ │ │ │ 3. Pour chaque test: │ │ │ │ - Charge le module dynamiquement │ │ │ │ - Execute via process() │ │ │ │ - Collecte résultat │ │ │ │ - Unload module │ │ │ │ 4. Génère rapport final │ │ │ │ 5. Exit avec code approprié │ │ │ └────────────────────────────────────────────┘ │ │ ▼ │ │ ┌────────────────────────────────────────────┐ │ │ │ Modules de Test (IT_*.so) │ │ │ ├────────────────────────────────────────────┤ │ │ │ IT_001_GetCurrentTime │ │ │ │ IT_002_FileSystemWrite │ │ │ │ IT_003_MCPToolsList │ │ │ │ IT_004_VoiceToAI │ │ │ │ IT_005_AIToLLM │ │ │ │ IT_006_StorageWrite │ │ │ │ IT_007_StorageRead │ │ │ │ IT_008_FullConversationLoop │ │ │ └────────────────────────────────────────────┘ │ │ ▼ │ │ ┌────────────────────────────────────────────┐ │ │ │ Modules AISSIA (testés) │ │ │ │ Scheduler, Notification, Monitoring, │ │ │ │ AI, Voice, Storage, Web │ │ │ └────────────────────────────────────────────┘ │ │ ▼ │ │ ┌────────────────────────────────────────────┐ │ │ │ Services Infrastructure │ │ │ │ LLMService (Claude API réelle) │ │ │ │ StorageService (fichiers .md) │ │ │ │ VoiceService (TTS/STT) │ │ │ │ PlatformService │ │ │ └────────────────────────────────────────────┘ │ └─────────────────────────────────────────────────────┘ ``` ### 2.2 Flux d'Exécution ``` 1. User: ./build/aissia --run-tests 2. AISSIA démarre en mode test 3. Charge TestRunnerModule (au lieu des modules normaux) 4. TestRunnerModule: a. Lit config/test_runner.json b. Scan tests/integration/ pour IT_*.so c. Pour chaque test module: - ModuleLoader::load("tests/integration/IT_001.so") - testModule->setConfiguration(config, io, scheduler) - testModule->process() // Execute le test - result = testModule->getHealthStatus() // Récupère résultat - ModuleLoader::unload() d. Agrège tous les résultats e. Affiche rapport (console + JSON) f. Exit(0) si tous passent, Exit(1) sinon ``` --- ## 3. Composants à Créer ### 3.1 TestRunnerModule (Orchestrateur) **Fichier** : `src/modules/TestRunnerModule.{h,cpp}` **Taille** : ~250 lignes **Responsabilités** : - Charger la configuration des tests - Découvrir les modules de test (scan `tests/integration/`) - Charger/exécuter/décharger chaque test séquentiellement - Collecter les résultats - Générer le rapport final - Gérer le timeout global **Interface** : ```cpp class TestRunnerModule : public grove::IModule { public: void setConfiguration(...) override; void process(...) override; std::unique_ptr getHealthStatus() override; private: struct TestResult { std::string testName; bool passed; std::string message; int durationMs; }; void discoverTests(); TestResult runTest(const std::string& testPath); void generateReport(); std::vector m_testPaths; std::vector m_results; }; ``` **Configuration** : `config/test_runner.json` ```json { "enabled": true, "testDirectory": "tests/integration", "globalTimeoutMs": 300000, "stopOnFirstFailure": false, "verboseOutput": true, "outputFormats": ["console", "json"], "jsonOutputPath": "test-results.json" } ``` ### 3.2 ITestModule (Interface de Base) **Fichier** : `src/shared/testing/ITestModule.h` **Taille** : ~50 lignes **But** : Interface commune pour tous les modules de test ```cpp namespace aissia::testing { struct TestResult { bool passed = false; std::string testName; std::string message; int durationMs = 0; nlohmann::json details; // Données custom du test }; class ITestModule : public grove::IModule { public: virtual TestResult execute() = 0; virtual std::string getTestName() const = 0; virtual std::string getDescription() const = 0; }; } // namespace aissia::testing ``` ### 3.3 Modules de Test Individuels Chaque test est un module indépendant qui hérite de `ITestModule`. **Liste des tests à créer** : #### Tests MCP (Priorité HAUTE) 1. **IT_001_GetCurrentTime** : `tests/integration/IT_001_GetCurrentTime.cpp` - Appelle tool `get_current_time` via AI - Vérifie réponse contient timestamp valide - ~100 lignes 2. **IT_002_FileSystemWrite** : `tests/integration/IT_002_FileSystemWrite.cpp` - Appelle tool `filesystem_write` → créer `test_output.md` - Vérifie fichier créé avec bon contenu - ~120 lignes 3. **IT_003_FileSystemRead** : `tests/integration/IT_003_FileSystemRead.cpp` - Appelle tool `filesystem_read` sur fichier existant - Vérifie contenu retourné correct - ~120 lignes 4. **IT_004_MCPToolsList** : `tests/integration/IT_004_MCPToolsList.cpp` - Requête AI : "Liste tous tes tools disponibles" - Vérifie que LLM retourne les 17+ tools - Parse JSON et compte les tools - ~150 lignes #### Tests Flux Complets (Priorité HAUTE) 5. **IT_005_VoiceToAI** : `tests/integration/IT_005_VoiceToAI.cpp` - Simule transcription voice → `voice:transcription` - Vérifie AI reçoit et publie `llm:request` - ~120 lignes 6. **IT_006_AIToLLM** : `tests/integration/IT_006_AIToLLM.cpp` - Publie `ai:query` avec vraie question - Vérifie `llm:response` reçue de Claude API - Vérifie réponse cohérente (non vide, pas d'erreur) - ~150 lignes 7. **IT_007_StorageWrite** : `tests/integration/IT_007_StorageWrite.cpp` - Demande AI d'écrire note via tool `storage_save_note` - Vérifie fichier .md créé dans `data/notes/` - ~130 lignes 8. **IT_008_StorageRead** : `tests/integration/IT_008_StorageRead.cpp` - Demande AI de lire note via tool `storage_query_notes` - Vérifie contenu retourné correct - ~130 lignes 9. **IT_009_FullConversationLoop** : `tests/integration/IT_009_FullConversationLoop.cpp` - Flux complet : Voice → AI → LLM (écrit note) → Storage → LLM (lit note) → Voice - Scénario : "Prends note que j'aime le C++" → "Qu'est-ce que j'aime ?" - Vérifie chaque étape du flux - ~250 lignes #### Tests Modules de Base (Priorité MOYENNE) 10. **IT_010_SchedulerHyperfocus** : `tests/integration/IT_010_SchedulerHyperfocus.cpp` - Simule session longue (>120min) - Vérifie `scheduler:hyperfocus_detected` publié - ~100 lignes 11. **IT_011_NotificationAlert** : `tests/integration/IT_011_NotificationAlert.cpp` - Publie `notification:alert` - Vérifie message affiché (check logs) - ~100 lignes 12. **IT_012_MonitoringActivity** : `tests/integration/IT_012_MonitoringActivity.cpp` - Simule `platform:window_changed` - Vérifie Monitoring track correctement - ~100 lignes 13. **IT_013_WebRequest** : `tests/integration/IT_013_WebRequest.cpp` - Publie `web:request` vers https://api.github.com - Vérifie `web:response` avec statusCode 200 - ~100 lignes --- ## 4. Protocole de Test ### 4.1 Structure d'un Test Module Exemple : `IT_001_GetCurrentTime.cpp` ```cpp #include "shared/testing/ITestModule.h" #include #include #include namespace aissia::testing { class IT_001_GetCurrentTime : public ITestModule { public: std::string getTestName() const override { return "IT_001_GetCurrentTime"; } std::string getDescription() const override { return "Test MCP tool get_current_time via AI"; } void setConfiguration(const grove::IDataNode& config, grove::IIO* io, grove::ITaskScheduler* scheduler) override { m_io = io; m_timeout = config.getInt("timeoutMs", 10000); // Subscribe to responses grove::SubscriptionConfig subConfig; m_io->subscribe("llm:response", subConfig); } TestResult execute() override { auto start = std::chrono::steady_clock::now(); TestResult result; result.testName = getTestName(); try { // 1. Envoyer requête AI pour appeler tool auto request = std::make_unique("request"); request->setString("query", "Quelle heure est-il ?"); request->setString("conversationId", "test-001"); m_io->publish("ai:query", std::move(request)); // 2. Attendre réponse (avec timeout) auto response = waitForResponse("llm:response", m_timeout); if (!response) { result.passed = false; result.message = "Timeout waiting for llm:response"; return result; } // 3. Valider réponse contient timestamp std::string text = response->getString("text", ""); if (text.empty()) { result.passed = false; result.message = "Empty response from LLM"; return result; } // 4. Parse pour vérifier format heure (simple regex) bool hasTimestamp = (text.find(":") != std::string::npos) && (text.find("20") != std::string::npos); // Year 2025 result.passed = hasTimestamp; result.message = hasTimestamp ? "✅ Tool returned valid time" : "❌ No valid timestamp in response"; result.details["response"] = text; } catch (const std::exception& e) { result.passed = false; result.message = std::string("Exception: ") + e.what(); } auto end = std::chrono::steady_clock::now(); result.durationMs = std::chrono::duration_cast( end - start).count(); return result; } private: std::unique_ptr waitForResponse( const std::string& topic, int timeoutMs) { // Polling avec timeout auto start = std::chrono::steady_clock::now(); while (true) { if (m_io->hasMessages() > 0) { auto msg = m_io->pullMessage(); if (msg.topic == topic && msg.data) { return std::move(msg.data); } } auto elapsed = std::chrono::duration_cast( std::chrono::steady_clock::now() - start).count(); if (elapsed > timeoutMs) { return nullptr; } std::this_thread::sleep_for(std::chrono::milliseconds(100)); } } grove::IIO* m_io = nullptr; int m_timeout = 10000; }; } // namespace aissia::testing // Factory functions extern "C" { grove::IModule* createModule() { return new aissia::testing::IT_001_GetCurrentTime(); } void destroyModule(grove::IModule* module) { delete module; } } ``` ### 4.2 Configuration par Test Chaque test a son JSON : `config/integration/IT_001.json` ```json { "enabled": true, "timeoutMs": 10000, "retryCount": 0, "description": "Test MCP tool get_current_time", "tags": ["mcp", "tools", "quick"] } ``` --- ## 5. Format des Résultats ### 5.1 Console Output ``` ======================================== AISSIA Integration Tests Running 13 tests... ======================================== [1/13] IT_001_GetCurrentTime..................... ✅ PASS (1.2s) Tool returned valid time [2/13] IT_002_FileSystemWrite.................... ✅ PASS (0.8s) File created: data/test_output.md [3/13] IT_003_FileSystemRead..................... ✅ PASS (0.5s) Content matches expected [4/13] IT_004_MCPToolsList....................... ✅ PASS (2.3s) Found 17 tools available [5/13] IT_005_VoiceToAI.......................... ✅ PASS (0.3s) AI received transcription [6/13] IT_006_AIToLLM............................ ✅ PASS (3.5s) LLM response received (234 tokens) [7/13] IT_007_StorageWrite....................... ✅ PASS (1.1s) Note saved to data/notes/test-note.md [8/13] IT_008_StorageRead........................ ✅ PASS (0.9s) Note retrieved successfully [9/13] IT_009_FullConversationLoop............... ✅ PASS (8.7s) Complete loop: Voice→AI→LLM→Storage→Voice [10/13] IT_010_SchedulerHyperfocus............... ✅ PASS (0.2s) Hyperfocus detected correctly [11/13] IT_011_NotificationAlert................. ✅ PASS (0.1s) Alert published [12/13] IT_012_MonitoringActivity................ ❌ FAIL (5.0s) Timeout waiting for monitoring:activity_classified [13/13] IT_013_WebRequest........................ ✅ PASS (0.6s) HTTP 200 from api.github.com ======================================== Results: 12/13 passed (92.3%) Total time: 25.2s Failed tests: - IT_012_MonitoringActivity: Timeout waiting for monitoring:activity_classified ======================================== Exit code: 1 ``` ### 5.2 JSON Output `test-results.json` : ```json { "summary": { "total": 13, "passed": 12, "failed": 1, "skipped": 0, "successRate": 92.3, "totalDurationMs": 25200 }, "tests": [ { "name": "IT_001_GetCurrentTime", "passed": true, "message": "Tool returned valid time", "durationMs": 1200, "details": { "response": "Il est actuellement 17:45:23 le 28 novembre 2025." } }, { "name": "IT_012_MonitoringActivity", "passed": false, "message": "Timeout waiting for monitoring:activity_classified", "durationMs": 5000, "details": { "expectedTopic": "monitoring:activity_classified", "timeout": 5000 } } ], "timestamp": "2025-11-28T17:45:30Z", "environment": { "platform": "linux", "modules": ["Scheduler", "Notification", "Monitoring", "AI", "Voice", "Storage", "Web"], "llmProvider": "claude-sonnet-4" } } ``` --- ## 6. Implémentation par Phases ### Phase 1 : Infrastructure (2h) **Objectif** : Créer le système de base 1. **ITestModule interface** (`src/shared/testing/ITestModule.h`) - Définir interface commune - Structure TestResult 2. **TestRunnerModule** (`src/modules/TestRunnerModule.{h,cpp}`) - Découverte de tests - Chargement dynamique - Collecte résultats - Génération rapport 3. **Configuration** - `config/test_runner.json` - `config/integration/` (dossier pour configs de tests) 4. **Intégration main.cpp** - Argument `--run-tests` - Mode test vs mode normal ### Phase 2 : Tests MCP (3h) **Objectif** : Valider les tools MCP 5. **IT_001_GetCurrentTime** - Test simple de tool 6. **IT_002_FileSystemWrite** - Écriture fichier .md 7. **IT_003_FileSystemRead** - Lecture fichier .md 8. **IT_004_MCPToolsList** - Inventaire complet des tools ### Phase 3 : Tests Flux (3h) **Objectif** : Valider les communications inter-modules 9. **IT_005_VoiceToAI** - Voice → AI 10. **IT_006_AIToLLM** - AI → LLM (Claude API réelle) 11. **IT_007_StorageWrite** - AI → Storage (sauvegarder note) 12. **IT_008_StorageRead** - AI → Storage (lire note) ### Phase 4 : Test Complet (2h) **Objectif** : Valider le flux end-to-end 13. **IT_009_FullConversationLoop** - Boucle complète Voice→AI→LLM→Storage→LLM→Voice ### Phase 5 : Tests Modules (1h) **Objectif** : Valider modules individuels 14. **IT_010_SchedulerHyperfocus** 15. **IT_011_NotificationAlert** 16. **IT_012_MonitoringActivity** 17. **IT_013_WebRequest** ### Phase 6 : Finition (1h) 18. Documentation 19. Validation complète 20. Git commit **Total estimé : ~12h** --- ## 7. CMakeLists.txt ```cmake # ============================================================================ # Integration Test Modules # ============================================================================ # Test Runner Module (orchestrator) add_library(TestRunnerModule SHARED src/modules/TestRunnerModule.cpp ) target_link_libraries(TestRunnerModule PRIVATE GroveEngine::impl spdlog::spdlog ) set_target_properties(TestRunnerModule PROPERTIES PREFIX "lib" LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/modules ) # Individual test modules set(INTEGRATION_TESTS IT_001_GetCurrentTime IT_002_FileSystemWrite IT_003_FileSystemRead IT_004_MCPToolsList IT_005_VoiceToAI IT_006_AIToLLM IT_007_StorageWrite IT_008_StorageRead IT_009_FullConversationLoop IT_010_SchedulerHyperfocus IT_011_NotificationAlert IT_012_MonitoringActivity IT_013_WebRequest ) foreach(TEST_NAME ${INTEGRATION_TESTS}) add_library(${TEST_NAME} SHARED tests/integration/${TEST_NAME}.cpp ) target_include_directories(${TEST_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/src ) target_link_libraries(${TEST_NAME} PRIVATE GroveEngine::impl spdlog::spdlog ) set_target_properties(${TEST_NAME} PROPERTIES PREFIX "" LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/tests/integration ) endforeach() # Custom target to build all integration tests add_custom_target(integration_tests DEPENDS TestRunnerModule ${INTEGRATION_TESTS} COMMENT "Building all integration test modules" ) ``` --- ## 8. Utilisation ### 8.1 Build ```bash # Build tous les tests cmake --build build --target integration_tests -j4 # Vérifier modules créés ls build/tests/integration/ # IT_001_GetCurrentTime.so # IT_002_FileSystemWrite.so # ... ``` ### 8.2 Exécution ```bash # Lancer tous les tests ./build/aissia --run-tests # Avec config custom ./build/aissia --run-tests --test-config config/my_tests.json # Verbose mode ./build/aissia --run-tests --verbose # Sauvegarder résultats JSON ./build/aissia --run-tests --json-output results.json ``` ### 8.3 CI/CD ```bash #!/bin/bash # ci-test.sh set -e # Build cmake -B build -DBUILD_TESTING=ON cmake --build build --target integration_tests -j4 # Run tests ./build/aissia --run-tests --json-output test-results.json # Exit code: 0 = success, 1 = failure if [ $? -eq 0 ]; then echo "✅ All tests passed!" exit 0 else echo "❌ Some tests failed" cat test-results.json exit 1 fi ``` --- ## 9. Critères de Succès ### 9.1 Tests Unitaires (Catch2) ✅ **120/120 tests passent** (déjà fait) ### 9.2 Tests d'Intégration ✅ **13/13 tests passent** en conditions réelles : - MCP tools fonctionnent - LLM Claude API répond - Storage écrit/lit fichiers .md - Flux complets Voice→AI→LLM→Storage→Voice ### 9.3 Performance ✅ **Suite complète < 60s** (temps total) ✅ **Chaque test < 10s** (sauf FullConversationLoop < 15s) ### 9.4 Fiabilité ✅ **Tests reproductibles** (pas de flakiness) ✅ **Isolation** : Un test qui fail ne bloque pas les autres ✅ **Cleanup** : Fichiers .md de test nettoyés après exécution --- ## 10. Extensions Futures (Optionnel) ### Phase 7+ : Features Avancées - **IT_014_HotReload** : Test du hot-reload pendant exécution - **IT_015_ConcurrentRequests** : Test charge (multiple AI queries) - **IT_016_ErrorRecovery** : Test résilience (LLM down → fallback) - **IT_017_MCPExternalServer** : Test MCP server externe - **IT_018_MultimodalInput** : Test image + texte ### Monitoring - Dashboard web pour visualiser résultats - Historique des runs (trend analysis) - Alertes si taux de succès < 90% --- ## 11. Checklist de Validation Avant de considérer le travail terminé : - [ ] TestRunnerModule compile et charge - [ ] Au moins 3 tests MCP passent - [ ] Au moins 1 flux complet passe (IT_009) - [ ] Rapport console clair et lisible - [ ] JSON output valide et parsable - [ ] Exit code correct (0/1) - [ ] Documentation à jour - [ ] Commit avec message clair --- ## 12. Fichiers Affectés ### Nouveaux fichiers ``` src/shared/testing/ITestModule.h src/modules/TestRunnerModule.h src/modules/TestRunnerModule.cpp config/test_runner.json config/integration/IT_001.json config/integration/IT_002.json ... tests/integration/IT_001_GetCurrentTime.cpp tests/integration/IT_002_FileSystemWrite.cpp tests/integration/IT_003_FileSystemRead.cpp tests/integration/IT_004_MCPToolsList.cpp tests/integration/IT_005_VoiceToAI.cpp tests/integration/IT_006_AIToLLM.cpp tests/integration/IT_007_StorageWrite.cpp tests/integration/IT_008_StorageRead.cpp tests/integration/IT_009_FullConversationLoop.cpp tests/integration/IT_010_SchedulerHyperfocus.cpp tests/integration/IT_011_NotificationAlert.cpp tests/integration/IT_012_MonitoringActivity.cpp tests/integration/IT_013_WebRequest.cpp plans/integration-tests-plan.md (ce fichier) ``` ### Fichiers modifiés ``` CMakeLists.txt # Ajouter integration_tests target src/main.cpp # Ajouter --run-tests flag README.md # Documenter système de tests ``` --- **Plan prêt pour implémentation** 🚀 Ce plan détaille un système de tests d'intégration innovant qui utilise l'architecture modulaire de GroveEngine pour rendre chaque test isolé, extensible et hot-reloadable. L'approche "un module = un test" démontre la puissance du système tout en fournissant une validation complète d'AISSIA en conditions réelles.