Skip to content

test(handlers): tests fuer dokumentenliste und streaming-downloads - #32

Merged
strausmann merged 2 commits into
mainfrom
test/handlers-documents-coverage
Aug 6, 2026
Merged

test(handlers): tests fuer dokumentenliste und streaming-downloads#32
strausmann merged 2 commits into
mainfrom
test/handlers-documents-coverage

Conversation

@strausmann

Copy link
Copy Markdown
Owner

Löst ein im Repo selbst dokumentiertes Provisorium ab. .github/workflows/test.yml begründete die Coverage-Schwelle 50 für handlers_documents.go so:

handlers_documents.go hat mehrere 0%-Handler ohne eigenen Test — z.B. handleListDocuments, decodeCursor, handleDownloadDocumentPDF, handleDownloadPageImage — Schwelle bewusst niedrig statt der Business-Logic-Zieltabelle 80%, bis eigene Tests nachgezogen sind.

Genau diese vier Handler bekommen jetzt Tests.

Abgedeckt

handleListDocuments, beide Zweige. Der Query-Zweig prüft das bewusst in Kauf genommene N+1-Muster: Documents.Search liefert nur Treffer-IDs, der Handler hydriert jede per Documents.Get. Der Test hält das fest, damit ein späteres Umbauen auffällt.

Der Sync-Zweig läuft über Documents.Diff und gibt einen codierten Folge-Cursor zurück. Der Test dekodiert das Token wieder und prüft, dass es die id/version aus der Diff-Antwort trägt — damit ist die Runde encodeCursordecodeCursor als Ganzes abgedeckt, nicht nur „irgendein nicht-leerer String".

decodeCursor, beide Sonderfälle. Leerer String liefert einen frischen Cursor mit documentCursorEntityType (Voll-Sync von vorn, der Normalfall beim ersten Aufruf). Ungültiges Base64 liefert 400 invalid_cursor, nicht 500 — der Wert kommt vom Client, das ist keine Server-Fehlfunktion.

Beide Streaming-Downloads. Body kommt unverändert durch, Content-Type stimmt (application/pdf bzw. image/jpeg), und ein Upstream-404 wird vor dem Streaming erkannt — der Handler darf keinen leeren 200-Stream aufmachen.

uploadDuplicateError. Error() und GetStatus() direkt, da beide über das huma.StatusError-Interface aufgerufen werden und bisher nur indirekt liefen.

Coverage

vorher nachher
handlers_documents.go gesamt 59,9 % 90,5 %
handleListDocuments 0 % 83,3 %
decodeCursor 0 % 100 %
handleDownloadDocumentPDF 0 % 81,8 %
handleDownloadPageImage 0 % 81,8 %
Error (uploadDuplicateError) 0 % 100 %

Keine 0%-Funktion mehr in der Datei.

Die Gate-Schwelle geht von 50 auf 80 — dieselbe Floor-Logik wie bei allen übrigen Einträgen (Sicherheitsabstand unter dem gemessenen Wert, kein aspirationaler Zielwert, siehe „GOLDENE REGEL" im Kommentar). Damit erreicht die Datei die Business-Logic-Zieltabelle, und die Übergangsbegründung im Kommentar ist durch die neue ersetzt.

Verifikation

  • Vollständiges Gate lokal mit der CI-Argumentliste gefahren: alle 16 Dateien OK
  • go vet, go test ./... -race -count=1, Doc-Coverage (0 undokumentierte exportierte Symbole), gofmt -l . grün
  • Kein Produktivcode angefasst — die Änderung besteht aus Tests plus der Schwelle in test.yml

🤖 Generated with Claude Code

.github/workflows/test.yml nannte die Schwelle 50 fuer handlers_documents.go
ausdruecklich als Provisorium: "mehrere 0%-Handler ohne eigenen Test [...]
Schwelle bewusst niedrig [...] bis eigene Tests nachgezogen sind". Genau diese
vier Handler bekommen jetzt Tests.

Abgedeckt:
- handleListDocuments, Query-Zweig: Search liefert nur IDs, der Handler hydriert
  jede per Get (das bewusste N+1-Muster ist damit festgehalten)
- handleListDocuments, Sync-Zweig: Diff plus Folge-Cursor, der im Test wieder
  dekodiert und gegen id/version der Diff-Antwort geprueft wird - damit ist die
  Runde encodeCursor/decodeCursor als Ganzes abgedeckt
- decodeCursor: leerer String liefert frischen Cursor, ungueltiges Base64 gibt
  400 invalid_cursor statt 500
- handleDownloadDocumentPDF und handleDownloadPageImage: Body kommt unveraendert
  durch, Content-Type stimmt, Upstream-404 wird VOR dem Streaming erkannt
- uploadDuplicateError.Error/GetStatus direkt

handlers_documents.go steigt damit von 59.9% auf 90.5%, keine 0%-Funktion mehr
in der Datei. Die Gate-Schwelle geht von 50 auf 80 - dieselbe Floor-Logik wie
bei den uebrigen Eintraegen (Sicherheitsabstand unter dem gemessenen Wert), und
die Datei erreicht damit die Business-Logic-Zieltabelle. Der Kommentar, der die
Uebergangsschwelle begruendete, ist entsprechend ersetzt.
Copilot AI lite review requested due to automatic review settings August 6, 2026 13:19

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds missing test coverage for the document list/sync endpoint and the two streaming download handlers, and then raises the CI coverage gate for handlers_documents.go to match the project’s business-logic threshold.

Changes:

  • Added handler tests for /v1/documents (query + diff/cursor paths), decodeCursor, and both streaming download endpoints (PDF + page image).
  • Added direct tests for uploadDuplicateError’s error / huma.StatusError behavior.
  • Updated the coverage gate in CI to raise cmd/fileee-server/handlers_documents.go from 50% to 80% and refreshed the rationale comment.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
cmd/fileee-server/handlers_test.go Adds tests for document list/sync cursor behavior and streaming downloads, plus uploadDuplicateError interface methods.
.github/workflows/test.yml Raises the coverage gate threshold for handlers_documents.go and updates the explanatory comment.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +2891 to +2908
// TestListDocuments_InvalidCursorReturns400 prüft den Fehlerpfad von decodeCursor: ein Cursor, der
// kein Base64-URL ist, muss 400 invalid_cursor liefern — NICHT 500. Der Wert kommt vom Client und
// ist damit keine Server-Fehlfunktion.
func TestListDocuments_InvalidCursorReturns400(t *testing.T) {
_, ts := newTestServer(t, nil)

req := newAuthedRequest(t, http.MethodGet, ts.URL+"/v1/documents?cursor=%21kein-base64", nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
t.Fatalf("GET /v1/documents?cursor=...: %v", err)
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusBadRequest {
body, _ := io.ReadAll(resp.Body)
t.Fatalf("status = %d, want 400, body=%s", resp.StatusCode, body)
}
}
Review-Feedback aus PR #32: Der Test behauptete im Kommentar "400
invalid_cursor", pruefte aber nur den HTTP-Status. Ein Wechsel des
maschinenlesbaren "code" bei weiterhin 400 waere unbemerkt geblieben - genau
das ist aber die Zusage an Aufrufer, die den Fehler programmatisch auswerten.
Der Test dekodiert den Body jetzt und prueft code und error.
@strausmann

Copy link
Copy Markdown
Owner Author

Zutreffend, behoben.

Der Test behauptete im Kommentar „400 invalid_cursor", prüfte aber nur den HTTP-Status. Der maschinenlesbare code ist genau die Zusage an Aufrufer, die den Fehler programmatisch auswerten (statusError.ErrorCode, errors.go) — ein Wechsel darauf bei weiterhin 400 wäre eine stille API-Änderung gewesen und unbemerkt geblieben.

Der Test dekodiert den Fehler-Body jetzt und prüft beide Felder:

if errBody.Code != "invalid_cursor" { ... }
if errBody.Error != "invalid cursor parameter" { ... }

Der Decode-Aufruf selbst ist dabei die dritte Zusicherung: ein leerer oder nicht-JSON-Body lässt den Test jetzt ebenfalls fehlschlagen, statt stillschweigend durchzulaufen.

@strausmann
strausmann merged commit 7d6149e into main Aug 6, 2026
4 checks passed
@strausmann
strausmann deleted the test/handlers-documents-coverage branch August 6, 2026 13:47
strausmann added a commit that referenced this pull request Aug 6, 2026
)

Zieht die letzten testbaren 0%-Stellen nach, nachdem #32 dasselbe fuer
handlers_documents.go getan hat.

- handleListBoxes / handleGetBox: die beiden Box-Leserouten waren die einzigen
  Box-Handler ohne Test, Ein- und Ausheften hatten schon welche. Der List-Test
  laesst die Diff-Antwort bewusst ein abweichendes totalRows tragen, damit
  auffiele, wenn der Handler es durchreicht statt len(boxes) zu nehmen.
- statusError.Error / GetStatus: beide werden sonst nur indirekt ueber Huma
  aufgerufen, die mapError-Tests pruefen die Felder statt der Methoden. Der Test
  prueft zusaetzlich die JSON-Form und haelt damit fest, dass der Status bewusst
  NICHT im Body steht - er ist bereits der HTTP-Status-Code.

handlers_entities.go 78.0% -> 98.0%, errors.go 80.0% -> 100.0%. Die Schwellen
gehen entsprechend auf 90.

Ausserhalb von main.go gibt es damit keine 0%-Funktion mehr. Die dortigen fuenf
(main, fatal, execFileeeServer, runInfisicalCommand, infisicalVersionCommand)
kapseln os.Exit, syscall.Exec und exec.Command und bleiben bewusst ungetestet -
der Kommentar im Gate haelt das jetzt fest, statt es offen zu lassen.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants