02.05.08 — filter_tests_by_ids#
Fichier source :
src/ocarina/dsl/testing/filter_tests_by_ids.pyUtilisé par
TestSuite.__init__pour appliquer les flags CLI--only <ids>et--exclude <ids>. Mutex : on ne peut pas passer les deux.
Code#
def filter_tests_by_ids[Driver](
tests: Sequence[Test[Driver]],
*,
only: Iterable[str] = (),
exclude: Iterable[str] = (),
logger: ILogger,
) -> Sequence[Test[Driver]]:
only_set = set(only)
exclude_set = set(exclude)
if only_set and exclude_set:
raise ValueError("--only and --exclude cannot be used together")
known_ids = {test.test_id for test in tests}
if only_set:
matched = only_set & known_ids
if matched:
joined = ", ".join(sorted(matched))
logger.info(f"--only: matched test IDs: {joined}")
return [test for test in tests if test.test_id in only_set]
if exclude_set:
matched = exclude_set & known_ids
if matched:
joined = ", ".join(sorted(matched))
logger.info(f"--exclude: matched test IDs: {joined}")
return [test for test in tests if test.test_id not in exclude_set]
return testsQuatre garanties#
1. Mutex --only / --exclude#
if only_set and exclude_set:
raise ValueError("--only and --exclude cannot be used together")Tenter de passer les deux est une erreur runtime (pas une erreur mypy). Sémantiquement, ça n’aurait pas de sens : « ne garder que A, B » ET « exclure C, D » ? Qu’est-ce que c’est que ces putains de conneries (à l’échelle d’une CLI) ? Le mutex évite l’ambiguïté.
Cette contrainte est formalisée côté CLI dans _create_validate_only_exclude_mutex_effect (cf. ../11-opinionated/03-selenium-cli.md). Donc l’utilisateur voit le message d’erreur avant que la suite ne soit construite.
2. Silent ignore des IDs inconnus#
Si l’utilisateur passe --only test_login,test_typo et que test_typo n’existe pas (typo dans le nom), Ocarina ignore silencieusement test_typo :
return [test for test in tests if test.test_id in only_set]Aucun match pour test_typo → il n’apparaît tout simplement pas. Pas d’erreur, pas de warning.
L’argument explicité dans le docstring :
Unknown IDs (not matching any test.test_id) are silently ignored, so a typo in a CI script does not break the run.
→ C’est un choix pragmatique : une CI qui « ne casse pas pour une typo » est plus robuste qu’une CI qui exige des IDs parfaits.
3. Log des IDs matchés#
matched = only_set & known_ids
if matched:
joined = ", ".join(sorted(matched))
logger.info(f"--only: matched test IDs: {joined}")Login happy paths: filtering tests... --only: matched test IDs: login_no_otp, login_otpTriées, séparées par ,. Au cas où l’utilisateur passe 20 IDs, c’est lisible.
4. Si ni only ni exclude → on retourne tests tel quel#
return testsTestSuite(... only_ids=(), exclude_ids=()) n’introduit aucune copie ni aucun overhead. C’est le cas par défaut.
Logger préfixé#
logger=create_logger().set_prefix(lambda: f"{self.name}: filtering tests...")→ Le log devient Login happy paths: filtering tests... --only: .... Le préfixe est paresseux (Thunk[str]), recalculé à chaque log. Voir ../09-ports.md, section ILogger.set_prefix.
Intégration dans TestSuite.__init__#
# in TestSuite.__init__
self._tests = filter_tests_by_ids(
tests,
only=only_ids,
exclude=exclude_ids,
logger=create_logger().set_prefix(
lambda: f"{self.name}: filtering tests..."
),
)Le filtrage est fait à la construction de la suite, pas à l’exécution.
- Les invariants
validate_test_runners_ids/validate_test_runners_namessont appliqués surself._tests(donc post-filter). - Si la saturation est activée et qu’il ne reste qu’un test, on clone ce test jusqu’à
max_workers.
Cas particulier du smoke#
L’utilisateur peut décider de filtrer avec --only qui s’applique à toutes les suites.
- Si aucun test du smoke ne matche
--only, le smoke a une suite vide →campaign_has_failedretourneFalse→ main runs, smoke bypassed. - Si tous les tests du main ne matchent pas non plus, on a juste les
_resultsvides.
--only est un filtre, pas un sélecteur de hiérarchie. On peut filtrer transversalement par ID.
Schéma#
┌────────────────────────────────┐
│ filter_tests_by_ids(tests, │
│ only=..., exclude=...) │
└──────────────┬─────────────────┘
▼
┌────────────────────────────────┐
│ only_set && exclude_set ? │── True ─► raise ValueError
└──────────────┬─────────────────┘
▼
┌────────────────────────────────┐
│ only_set non vide ? │── True ─► log matched IDs
└──────────────┬─────────────────┘ return [test for test in tests if test.test_id in only_set]
▼
┌────────────────────────────────┐
│ exclude_set non vide ? │── True ─► log matched IDs
└──────────────┬─────────────────┘ return [test for test in tests if test.test_id not in exclude_set]
▼
return tests