test(documents): die drei stillen Zustaende der OCR-Warteschlange

internal/documents hatte null Tests -- und ist das Paket, dessen Versagen am
teuersten ist, weil es **still** ist: Die Volltextsuche findet dann einfach
nichts, und das sieht aus wie "steht nicht drin".

Acht Tests, nicht auf Abdeckung gezielt, sondern auf die Zustaende, in denen
die Schlange haengenbleiben kann, ohne dass es auffaellt: ein Auftrag, der
nie aufgibt; ein Auftrag, der nach hartem Abbruch fuer immer auf 'running'
steht; ein Text nach alter Regel, der nie erneuert wird. Dazu geloeschte
Dateien, erneuter Upload und Complete als Einheit.

scripts/db-tests.sh baut eine Wegwerf-Datenbank, spielt die Migrationen ein
und laesst die Tests laufen. Ohne das haetten sie sich mangels TEST_DSN
immer nur uebersprungen -- Dekoration, genau wie vitest es war.

**Gegengeprueft an absichtlich kaputtem Code, und der zweite Versuch blieb
gruen:** maxAttempts von 3 auf 9999 gesetzt -- alle Tests weiter in Ordnung,
nur die Laufzeit stieg von 0,2 auf 27 Sekunden. Sie schleiften ueber die
Konstante und setzten die Zahl voraus, statt sie zu pruefen. So verschwindet
eine Entscheidung unbemerkt aus einer Anwendung. Jetzt haelt ein eigener
Test die Zahl fest und sagt, wo die Begruendung hingehoert.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
marcandClaude Opus 5 committed 2026-09-12 22:32:28 +02:00
1 parent 2cc02941b9
commit 76176a45bc
4 files changed
+456 -7

No files matched your search

+51
View File
@@ -232,6 +232,57 @@ Eine Prüfung, die ohne Daten besteht, prüft nichts. Jetzt liegen die Testtermi
relativ zum heutigen Tag, der Zeitraum wird ausdrücklich mitgegeben, und eine
Zeile davor stellt sicher, dass überhaupt etwas in der Liste steht.
## Go-Tests mit Datenbank
Einige Go-Tests brauchen ein echtes Postgres – die Warteschlange der
Texterkennung etwa lässt sich ohne nicht prüfen. Sie überspringen sich selbst,
wenn `TEST_DSN` fehlt, damit `go test ./...` überall grün bleibt.
**Der Preis dieser Freundlichkeit: Sie laufen dann nie.** Und ein Test, der nie
läuft, ist Dekoration – genau wie `vitest` es war, bevor es auffiel. Deshalb:
./scripts/db-tests.sh # alle
./scripts/db-tests.sh ./internal/documents/
Das Skript baut eine Wegwerf-Datenbank, spielt alle Migrationen ein, lässt die
Tests laufen und räumt sie wieder weg. Die Entwicklungsdatenbank bleibt
unberührt.
### Texterkennung: die drei stillen Zustände
`internal/documents` ist das Paket, dessen Versagen am teuersten ist, weil es
**still** ist: Die Volltextsuche findet dann einfach nichts, und das sieht
genauso aus wie „steht nicht drin". Geprüft werden deshalb nicht die Abfragen,
sondern die drei Zustände, in denen die Schlange hängenbleiben kann, ohne dass
es auffällt:
1. **Ein Auftrag, der nie aufgibt.** Ein kaputtes oder passwortgeschütztes PDF
besetzte sonst für immer den Arbeiter, und die übrigen Dateien kämen nie
dran – während nach außen „die Erkennung läuft".
2. **Ein Auftrag, der nach einem harten Abbruch auf `running` stehen bleibt.**
Nähme `Claim` nur `pending`, wäre diese Datei für immer verloren, und die
Zahl der offenen Aufträge sähe dabei gesund aus.
3. **Ein Text nach alter Regel, der nie erneuert wird.** Auffindbar, aber im
Betrachter nicht auf der richtigen Seite – und nichts zeigt, dass diese
Dateien anders sind.
Dazu: gelöschte Dateien werden nicht mehr genommen, ein erneuter Upload gibt
eine neue Chance, und `Complete` schreibt Text und Auftragsende zusammen.
### Was der Mutationsversuch gezeigt hat
Die Tests wurden gegen **absichtlich kaputten Code** gegengeprüft – sonst weiß
man nicht, ob sie überhaupt etwas fangen.
* `'running'` aus `Claim` entfernt → zwei Tests wurden rot. Gut.
* `maxAttempts` von 3 auf 9999 gesetzt → **alle blieben grün.** Sie schleifen
über die Konstante, prüfen die Zahl also nicht, sondern setzen sie voraus.
Auffällig war nur die Laufzeit: 27 statt 0,2 Sekunden.
Genau so verschwindet eine Entscheidung unbemerkt aus einer Anwendung. Dagegen
steht jetzt ein Test, der die Zahl selbst festhält und sagt, wo die Begründung
hingehört, falls sie sich ändert.
## Notfall: Migration hängt fest ("Dirty database version")
Betrifft jede künftige Migration, nicht nur eine bestimmte. Nachgestellt und