Files
pdf-ocr-hotfolder/tests/test_incoming_non_pdf.py
techadmin cd803a3dfe feat: stille Datenverlust-Pfade geschlossen, gemeinsame Shell-Lib (v0.7.0)
Vor dem Rollout durchgesehen und die verbliebenen Stellen geschlossen, an
denen etwas schiefgehen konnte, ohne dass es irgendwo sichtbar wurde.

Datenverlust:
- veraPDF: das in [verapdf].binary konfigurierte Programm wird im Preflight
  geprueft. Bisher galt bei falschem Pfad JEDE Datei als "nicht konform" —
  Ergebnis nach error/, Original geloescht (Default delete). run_verapdf()
  trennt jetzt ausserdem ein echtes FAIL-Urteil von einer Stoerung
  (VeraPdfUnavailable: nicht startbar, abgestuerzt, kein PASS/FAIL in der
  Ausgabe). Bei Stoerung wandern Original UND Ergebnis nach error/, das
  Original wird nicht entsorgt.
- Gleichnamige Dateien wurden in outgoing/, error/ und beim Ordner-Upload
  mit abweichendem target kommentarlos ueberschrieben. Jetzt Zeitstempel
  daneben, mit Warnung; ProcessResult.output traegt den echten Pfad.

Robustheit:
- Kaputtes oder nicht lesbares TOML beim Start: Exit 2 statt Traceback.
- RestartPreventExitStatus=2 in der Unit — Exit 2 (Config/Preflight) laeuft
  nicht mehr endlos neu, die Instanz bleibt sichtbar failed stehen.
- Toter watchdog-Observer wird erkannt: Exit 3, systemd setzt den Watch neu
  auf. Vorher blieb die Unit "active" und verarbeitete nichts mehr.
- Relative Pfade in [paths]/archive_dir/target sind ein Config-Fehler statt
  still unter /opt zu landen.
- Fehler beim Archivieren entwertet den Durchlauf nicht mehr: Upload und
  Mail laufen, Sichtbarkeit ueber log.error + "OK mit Warnung"-Mail.
- Nicht-PDFs in incoming/ werden beim Start-Scan gesammelt gemeldet.
- Logging explizit nach stdout (die Doku versprach das schon).

Struktur:
- Neue lib/common.sh, von install.sh und update.sh gesourct. Die doppelte
  venv_is_healthy() gibt es nur noch einmal, in der gruendlichen Fassung —
  die schlanke in install.sh haette eine nach einem Distro-Sprung kaputte
  venv als gesund durchgewunken (nachgewiesen).
- install.sh warnt in Containern, wenn systemd-journald nicht laeuft.

Doku: Dateisystem-Festlegung (ext4/xfs/zfs, kein CIFS/NFS wegen inotify),
Debian 13 in LXC auf Proxmox scheitert an journald (243/CREDENTIALS,
AppArmor blockiert sd-mkdcreds) inkl. Abhilfe, echte Speicher-Messwerte,
Exit-Code-Tabelle.

254 Tests gruen (vorher 152).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-23 00:59:17 +02:00

89 lines
2.9 KiB
Python

"""Punkt 6: Fremddateien in incoming/ verschwinden nicht mehr lautlos.
Alles ohne .pdf-Endung wurde kommentarlos ignoriert und sammelte sich an.
Jetzt gibt es beim Start-Scan genau EINE Sammelmeldung — kein Spam im
laufenden Betrieb, keine Zeile pro Datei.
"""
from __future__ import annotations
import logging
from unittest.mock import patch
from pdf_ocr_hotfolder.service import HotfolderService
LOGGER = "pdf_ocr_hotfolder.service"
def _scan(tmp_config, caplog) -> str:
service = HotfolderService(tmp_config)
try:
with caplog.at_level(logging.WARNING, logger=LOGGER), \
patch.object(HotfolderService, "enqueue"):
service._scan_existing()
finally:
service._executor.shutdown(wait=False)
return caplog.text
def test_non_pdf_files_are_reported(tmp_config, caplog) -> None:
(tmp_config.paths.incoming / "notizen.txt").write_text("x")
(tmp_config.paths.incoming / "bild.jpg").write_bytes(b"x")
(tmp_config.paths.incoming / "scan.pdf").write_bytes(b"%PDF-1.4\n")
text = _scan(tmp_config, caplog)
assert "2 Datei(en) ohne .pdf-Endung" in text
assert "notizen.txt" in text
assert "bild.jpg" in text
assert "scan.pdf" not in text
def test_single_aggregate_line(tmp_config, caplog) -> None:
"""Eine Sammelmeldung, nicht eine pro Datei."""
for i in range(7):
(tmp_config.paths.incoming / f"datei{i}.txt").write_text("x")
text = _scan(tmp_config, caplog)
assert text.count("ohne .pdf-Endung") == 1
assert "7 Datei(en)" in text
# Nur die ersten drei werden namentlich genannt
assert "+4 weitere" in text
def test_no_message_without_foreign_files(tmp_config, caplog) -> None:
(tmp_config.paths.incoming / "scan.pdf").write_bytes(b"%PDF-1.4\n")
assert "ohne .pdf-Endung" not in _scan(tmp_config, caplog)
def test_empty_incoming_is_quiet(tmp_config, caplog) -> None:
assert "ohne .pdf-Endung" not in _scan(tmp_config, caplog)
def test_directories_are_not_counted(tmp_config, caplog) -> None:
"""Ein Unterverzeichnis ist keine liegengebliebene Fremddatei."""
(tmp_config.paths.incoming / "unterordner").mkdir()
assert "ohne .pdf-Endung" not in _scan(tmp_config, caplog)
def test_uppercase_pdf_is_not_foreign(tmp_config, caplog) -> None:
"""`_is_pdf()` ist case-insensitiv — SCAN.PDF ist eine PDF."""
(tmp_config.paths.incoming / "SCAN.PDF").write_bytes(b"%PDF-1.4\n")
assert "ohne .pdf-Endung" not in _scan(tmp_config, caplog)
def test_no_spam_during_runtime(tmp_config, caplog) -> None:
"""Im laufenden Betrieb bleibt enqueue() für Fremddateien stumm."""
fremd = tmp_config.paths.incoming / "notizen.txt"
fremd.write_text("x")
service = HotfolderService(tmp_config)
try:
with caplog.at_level(logging.DEBUG, logger=LOGGER):
for _ in range(5):
service.enqueue(fremd)
finally:
service._executor.shutdown(wait=False)
assert caplog.text == ""