SPB Git forge

spb/api-ka

Public

API-KA — plateforme centrale : collecte quotidienne des 8 services KA, historisation append-only et API publique sur www.api-ka.com

48commits 1branches 0releases
5.9 MBsize
maindefault branch
19 days agolast push
Python 60.9% HTML 21% TypeScript 7.3% JavaScript 5.2% CSS 4.8% Shell 0.8%

fix: pg_dump en chemin absolu (cron 03:30) + isolation des logs sous pytest

- backup.py : PG_DUMP = shutil.which ou /opt/homebrew/bin/pg_dump — le cron
  de 03:30 (PATH minimal /usr/bin:/bin) échouait en [Errno 2] depuis le 17/08,
  backups ET purge 90 j jamais exécutés. Testé : 8/8 dumps + purge OK sous
  env cron simulé.
- tests/conftest.py : fixture session isolated_logs_dir — redirige logs_dir
  (alerts.log/apika.log) vers le tmp de test ; pytest écrivait de fausses
  alertes [louka] 2026-08-03 dans le vrai logs/alerts.log de prod.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Simon-Pierre Boucher committed 1 mo ago (Aug 18, 2026) parent aee9aac

2 changed files +28 −1

modified src/utils/backup.py +7 −1
@@ -29,6 +29,12 @@ from src.database.db import session_scope
29 29 from src.database.models import DATA_MODELS
30 30 from src.utils.logger import alert, get_logger
31 31
32 +# Chemin absolu de pg_dump : le cron de 03:30 tourne avec un PATH minimal
33 +# (/usr/bin:/bin) qui ne contient pas /opt/homebrew/bin — un appel nu à
34 +# "pg_dump" y échoue en [Errno 2] FileNotFoundError. On résout via le PATH
35 +# courant quand c'est possible, sinon on retombe sur l'installation Homebrew.
36 +PG_DUMP = shutil.which("pg_dump") or "/opt/homebrew/bin/pg_dump"
37 +
32 38
33 39 def _day_dir(date_key: datetime.date) -> Path:
34 40 day_dir = get_settings().backups_dir / date_key.isoformat()
@@ -69,7 +75,7 @@ def backup_service(service: str, date_key: datetime.date | None = None) -> Path:
69 75 out_path = day_dir / f"{table}_{timestamp}.sql.gz"
70 76 result = subprocess.run(
71 77 [
72 − "pg_dump",
78 + PG_DUMP,
73 79 "--dbname",
74 80 _libpq_url(settings.database_url),
75 81 "--table",
modified tests/conftest.py +21 −0
@@ -15,8 +15,10 @@ valeurs dès le premier appel.
15 15
16 16 from __future__ import annotations
17 17
18 +import dataclasses
18 19 import os
19 20 import tempfile
21 +from pathlib import Path
20 22
21 23 _TMP_DIR = tempfile.mkdtemp(prefix="apika-tests-")
22 24 os.environ["APP_ENV"] = "test"
@@ -49,3 +51,22 @@ def no_backup(monkeypatch: pytest.MonkeyPatch):
49 51 monkeypatch.setattr(
50 52 "src.collectors.base_collector.backup_service", lambda *args, **kwargs: None
51 53 )
54 +
55 +
56 +@pytest.fixture(scope="session", autouse=True)
57 +def isolated_logs_dir():
58 + """Redirige les logs (alerts.log, apika.log) vers le tmp de test.
59 +
60 + ``logs_dir`` est codé en dur sur ``BASE_DIR/logs`` dans ``get_settings()`` :
61 + sans cette fixture, les collectes échouées simulées par les tests
62 + (ex. ``test_run_failure_after_retries``) écriraient de fausses alertes
63 + dans le vrai ``logs/alerts.log`` de production du node.
64 + """
65 + test_logs = Path(_TMP_DIR) / "logs"
66 + test_logs.mkdir(parents=True, exist_ok=True)
67 + test_settings = dataclasses.replace(get_settings(), logs_dir=test_logs)
68 + mp = pytest.MonkeyPatch()
69 + # alert() et get_logger() résolvent get_settings via src.utils.logger.
70 + mp.setattr("src.utils.logger.get_settings", lambda: test_settings)
71 + yield test_logs
72 + mp.undo()
52 73