Chapitre 02.05 — Orchestration#
Chaîne
Test → TestSuite → TestCampaign → TestCycle: comment chaque niveau s’articule, qui gère la parallélisation, qui gère les rejeux, qui décide du skip, et où vivent les invariants pré-exécution.
Plan#
| # | Fichier | Sujet |
|---|---|---|
| 01 | 01-test.md | La classe Test[Driver] — spawn, fragments pre/post, skip. |
| 02 | 02-test-executor.md | TestExecutor — exécution d’une tentative, ordre : setup → watchers.start → chain → watchers.stop → teardown. |
| 03 | 03-test-flow-retries.md | TestFlow — boucle de rejeu (1+max_retries), backoff linéaire, gestion des setup-failures. |
| 04 | 04-test-suite.md | TestSuite — parallélisation avec ThreadPoolExecutor, filtrage IDs, garde-fous. |
| 05 | 05-saturation.md | Saturation des workers : clonage aléatoire [COPY N]. Pourquoi et comment. |
| 06 | 06-test-campaign.md | TestCampaign — séquence de suites, campaign_has_failed. |
| 07 | 07-test-cycle-modes.md | TestCycle — smoke + main, modes fail-fast vs wait-for-all, has_test_cycle_failed. |
| 08 | 08-filter-tests-by-ids.md | filter_tests_by_ids — --only/--exclude, mutex, ignore les unknown IDs. |
Schéma#
┌────────────────────────────────────────────────┐
│ TestCycle │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ smoke_tests_campaigns │ │ ◄── 1er, gate
│ │ └─ TestCampaign │ │ mode : fail-fast |
│ │ └─ TestSuite │ │ wait-for-all
│ │ └─ Test │ │
│ └──────────────────────────────────────────┘ │
│ │
│ ┌──────────────────────────────────────────┐ │
│ │ campaigns (main) │ │ ◄── skippées si
│ │ └─ TestCampaign │ │ un smoke fail
│ │ └─ TestSuite │ │
│ │ └─ Test │ │
│ └──────────────────────────────────────────┘ │
└────────────────────────────────────────────────┘Qui fait quoi ?#
| Niveau | Responsabilité unique | Concurrence | Hors périmètre |
|---|---|---|---|
Test | Métadonnées + spawn(driver, logger) | aucune | exécution |
TestExecutor | Une tentative | aucune | rejeu, acquisition de driver |
TestFlow | Boucle de rejeu | aucune | parallélisation, agrégation |
TestSuite | Parallélisation + saturation + filtrage IDs | N threads | séquence inter-suites |
TestCampaign | Séquence de suites | suite-level | smoke vs main |
TestCycle | Smoke + main + mode | campaign-level | bootstrap / plugins post-exec |
Cette séparation stricte est délibérée : TestExecutor ne sait rien des retries, TestFlow ne sait rien de la concurrence, TestSuite ne sait rien de l’agrégation campaign-level. Chaque classe a un seul axe de responsabilité.
Tableau des invariants pré-exécution#
| Quand | Invariant | Source |
|---|---|---|
Construction TestSuite | validate_test_runners_ids(tests).execute() | oc_test_suite.py#_guards_on_invoke |
Avant exécution TestSuite.run (mode single) | validate_test_runners_names(tests).execute() (post-saturation aussi) | oc_test_suite.py#_guards_with_mounted_tests |
Avant exécution TestSuite.run (mode parallèle) | validate_test_runners_names(tests).execute() | id. |
Avant exécution TestSuite.run | validate_workers_amount(max_workers).execute() | id. |
Construction TestCampaign | validate_test_suites_names(suites).execute() | oc_test_campaign.py |
Construction TestCycle | chain_validations(validate_test_cycle_name, validate_campaigns_names, validate_test_suites_names, validate_test_runners_names).execute() | oc_test_cycle.py |
Tous ces invariants sont écrits avec validate(...) et lèvent un AggregateInvariantViolationError.