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>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
"""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 == ""
|
||||
Reference in New Issue
Block a user