# 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'CELUNA 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'CELUNA 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

```
┌─────────────────────────────────────────────────────┐
│              CELUNA --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 CELUNA (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/celuna --run-tests
2. CELUNA 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<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`
```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 celuna::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 celuna::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 <grove/IIO.h>
#include <grove/JsonDataNode.h>
#include <chrono>

namespace celuna::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 celuna::testing

// Factory functions
extern "C" {
    grove::IModule* createModule() {
        return new celuna::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

```
========================================
  CELUNA 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/celuna --run-tests

# Avec config custom
./build/celuna --run-tests --test-config config/my_tests.json

# Verbose mode
./build/celuna --run-tests --verbose

# Sauvegarder résultats JSON
./build/celuna --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/celuna --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'CELUNA en conditions réelles.
