Implémentation complète d'un système de tests d'intégration modulaire pour valider AISSIA en conditions réelles. Architecture "Un module = Un test": - Chaque test est un module GroveEngine (.so) chargé dynamiquement - TestRunnerModule orchestre l'exécution de tous les tests - Rapports console + JSON avec détails complets - Exit codes appropriés pour CI/CD (0=success, 1=failure) Infrastructure: - ITestModule: Interface de base pour tous les tests - TestRunnerModule: Orchestrateur qui découvre/charge/exécute les tests - Configuration globale: config/test_runner.json - Flag --run-tests pour lancer les tests Tests implémentés (8/8 passing): Phase 1 - Tests MCP: ✅ IT_001_GetCurrentTime: Test tool get_current_time via AI ✅ IT_002_FileSystemWrite: Test tool filesystem_write ✅ IT_003_FileSystemRead: Test tool filesystem_read ✅ IT_004_MCPToolsList: Vérification inventaire tools (≥5) Phase 2 - Tests Flux: ✅ IT_005_VoiceToAI: Communication Voice → AI ✅ IT_006_AIToLLM: Requête AI → Claude API (réelle) ✅ IT_007_StorageWrite: AI → Storage (sauvegarde note) ✅ IT_008_StorageRead: AI → Storage (lecture note) Avantages: 🔥 Hot-reload ready: Tests modifiables sans recompiler 🌐 Conditions réelles: Vraies requêtes Claude API, vrais fichiers 🎯 Isolation: Chaque test indépendant, cleanup automatique 📊 Rapports complets: Console + JSON avec détails par test ✅ CI/CD ready: Exit codes, JSON output, automation-friendly Usage: cmake --build build --target integration_tests cd build && ./aissia --run-tests 🤖 Generated with Claude Code Co-Authored-By: Claude <noreply@anthropic.com>
26 KiB
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 :
class TestRunnerModule : public grove::IModule {
public:
void setConfiguration(...) override;
void process(...) override;
std::unique_ptr<IDataNode> 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<std::string> m_testPaths;
std::vector<TestResult> m_results;
};
Configuration : config/test_runner.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
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)
-
IT_001_GetCurrentTime :
tests/integration/IT_001_GetCurrentTime.cpp- Appelle tool
get_current_timevia AI - Vérifie réponse contient timestamp valide
- ~100 lignes
- Appelle tool
-
IT_002_FileSystemWrite :
tests/integration/IT_002_FileSystemWrite.cpp- Appelle tool
filesystem_write→ créertest_output.md - Vérifie fichier créé avec bon contenu
- ~120 lignes
- Appelle tool
-
IT_003_FileSystemRead :
tests/integration/IT_003_FileSystemRead.cpp- Appelle tool
filesystem_readsur fichier existant - Vérifie contenu retourné correct
- ~120 lignes
- Appelle tool
-
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)
-
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
- Simule transcription voice →
-
IT_006_AIToLLM :
tests/integration/IT_006_AIToLLM.cpp- Publie
ai:queryavec vraie question - Vérifie
llm:responsereçue de Claude API - Vérifie réponse cohérente (non vide, pas d'erreur)
- ~150 lignes
- Publie
-
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
- Demande AI d'écrire note via tool
-
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
- Demande AI de lire note via tool
-
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)
-
IT_010_SchedulerHyperfocus :
tests/integration/IT_010_SchedulerHyperfocus.cpp- Simule session longue (>120min)
- Vérifie
scheduler:hyperfocus_detectedpublié - ~100 lignes
-
IT_011_NotificationAlert :
tests/integration/IT_011_NotificationAlert.cpp- Publie
notification:alert - Vérifie message affiché (check logs)
- ~100 lignes
- Publie
-
IT_012_MonitoringActivity :
tests/integration/IT_012_MonitoringActivity.cpp- Simule
platform:window_changed - Vérifie Monitoring track correctement
- ~100 lignes
- Simule
-
IT_013_WebRequest :
tests/integration/IT_013_WebRequest.cpp- Publie
web:requestvers https://api.github.com - Vérifie
web:responseavec statusCode 200 - ~100 lignes
- Publie
4. Protocole de Test
4.1 Structure d'un Test Module
Exemple : IT_001_GetCurrentTime.cpp
#include "shared/testing/ITestModule.h"
#include <grove/IIO.h>
#include <grove/JsonDataNode.h>
#include <chrono>
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<grove::JsonDataNode>("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<std::chrono::milliseconds>(
end - start).count();
return result;
}
private:
std::unique_ptr<grove::IDataNode> 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::milliseconds>(
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
{
"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 :
{
"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
-
ITestModule interface (
src/shared/testing/ITestModule.h)- Définir interface commune
- Structure TestResult
-
TestRunnerModule (
src/modules/TestRunnerModule.{h,cpp})- Découverte de tests
- Chargement dynamique
- Collecte résultats
- Génération rapport
-
Configuration
config/test_runner.jsonconfig/integration/(dossier pour configs de tests)
-
Intégration main.cpp
- Argument
--run-tests - Mode test vs mode normal
- Argument
Phase 2 : Tests MCP (3h)
Objectif : Valider les tools MCP
- IT_001_GetCurrentTime - Test simple de tool
- IT_002_FileSystemWrite - Écriture fichier .md
- IT_003_FileSystemRead - Lecture fichier .md
- IT_004_MCPToolsList - Inventaire complet des tools
Phase 3 : Tests Flux (3h)
Objectif : Valider les communications inter-modules
- IT_005_VoiceToAI - Voice → AI
- IT_006_AIToLLM - AI → LLM (Claude API réelle)
- IT_007_StorageWrite - AI → Storage (sauvegarder note)
- IT_008_StorageRead - AI → Storage (lire note)
Phase 4 : Test Complet (2h)
Objectif : Valider le flux end-to-end
- IT_009_FullConversationLoop - Boucle complète Voice→AI→LLM→Storage→LLM→Voice
Phase 5 : Tests Modules (1h)
Objectif : Valider modules individuels
- IT_010_SchedulerHyperfocus
- IT_011_NotificationAlert
- IT_012_MonitoringActivity
- IT_013_WebRequest
Phase 6 : Finition (1h)
- Documentation
- Validation complète
- Git commit
Total estimé : ~12h
7. CMakeLists.txt
# ============================================================================
# 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
# 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
# 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
#!/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.