Spaces:
Sleeping
fix(ci): unblock CI hang — exclude live tests + cap codecov upload
Browse filesCause racine de la CI bloquée 6h+ et annulée à 52min :
1. Marker live non enregistré dans pyproject.toml et non exclu
par addopts. Conséquence : tous les tests
tests/integration/live/ étaient COLLECTÉS et exécutés en CI :
- test_tesseract_live.py s'exécutait, échouait sur
/custom/bin/tesseract polluté par un mock unit-test précédent.
- test_llm_live.py se contentait de skip module-level via
pytest.importorskip.
Les 4 'deselected' visibles dans l'output CI ne couvraient que
le marker network.
2. Codecov upload step codecov/codecov-action@v4 sans
timeout-minutes. L'action a déjà bloqué 50+ min en attendant
un upload qui n'aboutissait pas (CODECOV_TOKEN expirée, DNS lent,
TLS handshake bloqué). Couplé à fail_ci_if_error: true, le
job entier hangait jusqu'au timeout du runner GitHub.
Fix
===
- pyproject.toml : live ajouté à markers et inclus dans
l'exclusion par défaut de addopts (-m 'not network and
not live'). Opt-in local via pytest -m live.
- ci.yml : timeout-minutes: 15 sur le step Run tests et
timeout-minutes: 5 sur Upload coverage to Codecov ;
fail_ci_if_error: false sur codecov pour qu'un échec
d'upload n'invalide pas un run de tests valide.
Vérification locale :
- collection : 5022 collected / 8 deselected (5 live + 3 network).
- pytest -m live : 5 tests skippés gracieusement (env vars
absentes), pas d'exécution erronée.
- ruff clean.
- .github/workflows/ci.yml +10 -1
- pyproject.toml +6 -3
|
@@ -85,10 +85,14 @@ jobs:
|
|
| 85 |
# ── Tests ───────────────────────────────────────────────────
|
| 86 |
# Sprint A1 : --cov-fail-under=85 (baseline mesuré 87 %, marge 2 pts).
|
| 87 |
# pytest-timeout est configuré dans pyproject.toml [tool.pytest.ini_options].
|
|
|
|
|
|
|
|
|
|
| 88 |
- name: Run tests
|
| 89 |
# Sur Python 3.13, on continue malgré une erreur pour ne pas bloquer
|
| 90 |
# le merge pendant la fenêtre informationnelle de 6 mois (m-8).
|
| 91 |
continue-on-error: ${{ matrix.python-version == '3.13' }}
|
|
|
|
| 92 |
shell: bash
|
| 93 |
run: |
|
| 94 |
pytest tests/ -q --tb=short --no-header \
|
|
@@ -99,15 +103,20 @@ jobs:
|
|
| 99 |
PYTHONUTF8: "1"
|
| 100 |
|
| 101 |
# ── Couverture ──────────────────────────────────────────────
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
- name: Upload coverage to Codecov
|
| 103 |
if: runner.os == 'Linux' && matrix.python-version == '3.11' && env.CODECOV_TOKEN != ''
|
|
|
|
| 104 |
uses: codecov/codecov-action@v4
|
| 105 |
with:
|
| 106 |
token: ${{ secrets.CODECOV_TOKEN }}
|
| 107 |
files: coverage.xml
|
| 108 |
flags: unittests
|
| 109 |
name: picarones-coverage
|
| 110 |
-
fail_ci_if_error:
|
| 111 |
env:
|
| 112 |
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
| 113 |
|
|
|
|
| 85 |
# ── Tests ───────────────────────────────────────────────────
|
| 86 |
# Sprint A1 : --cov-fail-under=85 (baseline mesuré 87 %, marge 2 pts).
|
| 87 |
# pytest-timeout est configuré dans pyproject.toml [tool.pytest.ini_options].
|
| 88 |
+
# ``timeout-minutes`` au niveau step : le job ne hang JAMAIS plus de
|
| 89 |
+
# 15 min sur les tests, même si pytest-timeout (par-test) échoue à
|
| 90 |
+
# cleanup un thread daemon.
|
| 91 |
- name: Run tests
|
| 92 |
# Sur Python 3.13, on continue malgré une erreur pour ne pas bloquer
|
| 93 |
# le merge pendant la fenêtre informationnelle de 6 mois (m-8).
|
| 94 |
continue-on-error: ${{ matrix.python-version == '3.13' }}
|
| 95 |
+
timeout-minutes: 15
|
| 96 |
shell: bash
|
| 97 |
run: |
|
| 98 |
pytest tests/ -q --tb=short --no-header \
|
|
|
|
| 103 |
PYTHONUTF8: "1"
|
| 104 |
|
| 105 |
# ── Couverture ──────────────────────────────────────────────
|
| 106 |
+
# ``timeout-minutes: 5`` : codecov-action v4 a déjà bloqué la CI
|
| 107 |
+
# 50+ min en attendant un upload qui n'aboutissait pas.
|
| 108 |
+
# ``fail_ci_if_error: false`` : un échec d'upload n'invalide pas
|
| 109 |
+
# le run de tests qui vient de passer.
|
| 110 |
- name: Upload coverage to Codecov
|
| 111 |
if: runner.os == 'Linux' && matrix.python-version == '3.11' && env.CODECOV_TOKEN != ''
|
| 112 |
+
timeout-minutes: 5
|
| 113 |
uses: codecov/codecov-action@v4
|
| 114 |
with:
|
| 115 |
token: ${{ secrets.CODECOV_TOKEN }}
|
| 116 |
files: coverage.xml
|
| 117 |
flags: unittests
|
| 118 |
name: picarones-coverage
|
| 119 |
+
fail_ci_if_error: false
|
| 120 |
env:
|
| 121 |
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
| 122 |
|
|
@@ -156,9 +156,11 @@ testpaths = ["tests"]
|
|
| 156 |
# Windows) — utilisé par les tests CLI E2E qui résolvent leurs mock
|
| 157 |
# adapters via dotted path (``importlib.import_module("tests.fixtures.…")``).
|
| 158 |
pythonpath = ["."]
|
| 159 |
-
# Exclusion par défaut :
|
| 160 |
-
#
|
| 161 |
-
|
|
|
|
|
|
|
| 162 |
# Sprint A1 (M-15) : aucun test individuel ne doit dépasser 5 minutes.
|
| 163 |
# Mode "thread" car certains tests utilisent ProcessPoolExecutor qui est
|
| 164 |
# incompatible avec le timeout en mode "signal" sur certaines plateformes.
|
|
@@ -176,6 +178,7 @@ timeout_method = "thread"
|
|
| 176 |
markers = [
|
| 177 |
"slow: tests longs (corpus de référence, intégration cloud) ; non bloquants en dev local",
|
| 178 |
"network: tests qui hit le réseau réel ; exclus par défaut",
|
|
|
|
| 179 |
]
|
| 180 |
|
| 181 |
# ──────────────────────────────────────────────────────────────────
|
|
|
|
| 156 |
# Windows) — utilisé par les tests CLI E2E qui résolvent leurs mock
|
| 157 |
# adapters via dotted path (``importlib.import_module("tests.fixtures.…")``).
|
| 158 |
pythonpath = ["."]
|
| 159 |
+
# Exclusion par défaut : markers ``network`` et ``live`` non
|
| 160 |
+
# sélectionnés. Override en local via ``pytest -m network`` ou
|
| 161 |
+
# ``pytest -m live`` (avec env vars / binaires correctement
|
| 162 |
+
# configurés). ``-m ""`` pour tout exécuter.
|
| 163 |
+
addopts = "-v --tb=short -m 'not network and not live'"
|
| 164 |
# Sprint A1 (M-15) : aucun test individuel ne doit dépasser 5 minutes.
|
| 165 |
# Mode "thread" car certains tests utilisent ProcessPoolExecutor qui est
|
| 166 |
# incompatible avec le timeout en mode "signal" sur certaines plateformes.
|
|
|
|
| 178 |
markers = [
|
| 179 |
"slow: tests longs (corpus de référence, intégration cloud) ; non bloquants en dev local",
|
| 180 |
"network: tests qui hit le réseau réel ; exclus par défaut",
|
| 181 |
+
"live: tests d'intégration contre vraie API/binaire (Tesseract, Anthropic, OpenAI, Mistral) ; exclus par défaut, opt-in en local via 'pytest -m live'",
|
| 182 |
]
|
| 183 |
|
| 184 |
# ──────────────────────────────────────────────────────────────────
|