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#

#FichierSujet
0101-test.mdLa classe Test[Driver] — spawn, fragments pre/post, skip.
0202-test-executor.mdTestExecutor — exécution d’une tentative, ordre : setup → watchers.start → chain → watchers.stop → teardown.
0303-test-flow-retries.mdTestFlow — boucle de rejeu (1+max_retries), backoff linéaire, gestion des setup-failures.
0404-test-suite.mdTestSuite — parallélisation avec ThreadPoolExecutor, filtrage IDs, garde-fous.
0505-saturation.mdSaturation des workers : clonage aléatoire [COPY N]. Pourquoi et comment.
0606-test-campaign.mdTestCampaign — séquence de suites, campaign_has_failed.
0707-test-cycle-modes.mdTestCycle — smoke + main, modes fail-fast vs wait-for-all, has_test_cycle_failed.
0808-filter-tests-by-ids.mdfilter_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 ?#

NiveauResponsabilité uniqueConcurrenceHors périmètre
TestMétadonnées + spawn(driver, logger)aucuneexécution
TestExecutorUne tentativeaucunerejeu, acquisition de driver
TestFlowBoucle de rejeuaucuneparallélisation, agrégation
TestSuiteParallélisation + saturation + filtrage IDsN threadsséquence inter-suites
TestCampaignSéquence de suitessuite-levelsmoke vs main
TestCycleSmoke + main + modecampaign-levelbootstrap / 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#

QuandInvariantSource
Construction TestSuitevalidate_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.runvalidate_workers_amount(max_workers).execute()id.
Construction TestCampaignvalidate_test_suites_names(suites).execute()oc_test_campaign.py
Construction TestCyclechain_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.