Files
nexarch/dms/internal/export/limits_test.go
T
patrickandClaude Sonnet 5 79c4458618 DOC-18: obergrenze fuer gesamtgroesse/anzahl bei archiv-buendelung
Enqueue prueft konfigurierbare Obergrenzen (Dokumentanzahl, Gesamtgroesse)
VOR dem Anlegen des Auftrags/Einreihen des Jobs und lehnt Ueberschreitungen
mit konkreter Fehlermeldung ab, statt den Job-Worker-Pool zu belasten.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-18 00:55:36 +02:00

115 lines
4.1 KiB
Go

package export
import (
"context"
"testing"
)
// Akzeptanzkriterium 1 / Pflichtpruefung 1: eine Anfrage mit zu grosser
// Dokumentanzahl wird VOR Jobstart abgelehnt, kein Job wird gestartet.
func TestEnqueue_RejectsTooManyDocuments(t *testing.T) {
env, userID := setupTest(t)
ctx := context.Background()
docA := createDocument(t, env, userID, "a.txt", "x")
docB := createDocument(t, env, userID, "b.txt", "y")
docC := createDocument(t, env, userID, "c.txt", "z")
_, err := Enqueue(ctx, env.pool, env.queue, userID, []string{docA, docB, docC}, Limits{MaxDocuments: 2})
tooMany, ok := err.(*ErrTooManyDocuments)
if !ok {
t.Fatalf("erwartet ErrTooManyDocuments, habe: %v", err)
}
if tooMany.Requested != 3 || tooMany.MaxAllowed != 2 {
t.Fatalf("fehlerdetails falsch: %+v", tooMany)
}
var count int
if err := env.pool.QueryRow(ctx, `SELECT count(*) FROM document_exports`).Scan(&count); err != nil {
t.Fatalf("zaehlen: %v", err)
}
if count != 0 {
t.Fatalf("erwartet 0 angelegte export-auftraege bei abgelehnter anfrage, habe %d", count)
}
var jobCount int
if err := env.pool.QueryRow(ctx, `SELECT count(*) FROM processing_jobs WHERE job_type = $1`, JobType).Scan(&jobCount); err != nil {
t.Fatalf("jobs zaehlen: %v", err)
}
if jobCount != 0 {
t.Fatalf("erwartet 0 eingereihte jobs bei abgelehnter anfrage, habe %d", jobCount)
}
}
// Akzeptanzkriterium 1 / Pflichtpruefung 1: eine Anfrage mit zu grosser
// Gesamtgroesse wird VOR Jobstart abgelehnt.
func TestEnqueue_RejectsTotalSizeAboveLimit(t *testing.T) {
env, userID := setupTest(t)
ctx := context.Background()
// createDocument legt echten, verschluesselten Inhalt ab - dessen
// tatsaechliche (verschluesselte) Groesse steht in size_bytes.
docA := createDocument(t, env, userID, "gross-a.txt", "0123456789")
docB := createDocument(t, env, userID, "gross-b.txt", "0123456789")
var totalSize int64
if err := env.pool.QueryRow(ctx, `
SELECT SUM(fr.size_bytes) FROM documents d JOIN file_revisions fr ON fr.id = d.current_revision_id WHERE d.id = ANY($1)
`, []string{docA, docB}).Scan(&totalSize); err != nil {
t.Fatalf("gesamtgroesse ermitteln: %v", err)
}
_, err := Enqueue(ctx, env.pool, env.queue, userID, []string{docA, docB}, Limits{MaxTotalSizeBytes: totalSize - 1})
tooLarge, ok := err.(*ErrTotalSizeTooLarge)
if !ok {
t.Fatalf("erwartet ErrTotalSizeTooLarge, habe: %v", err)
}
if tooLarge.MaxAllowedBytes != totalSize-1 {
t.Fatalf("fehlerdetails falsch: %+v", tooLarge)
}
var count int
if err := env.pool.QueryRow(ctx, `SELECT count(*) FROM document_exports`).Scan(&count); err != nil {
t.Fatalf("zaehlen: %v", err)
}
if count != 0 {
t.Fatalf("erwartet 0 angelegte export-auftraege bei abgelehnter anfrage, habe %d", count)
}
}
// Akzeptanzkriterium 2 / Pflichtpruefung 2: innerhalb der Obergrenze
// funktioniert die Buendelung aus DOC-08 unveraendert.
func TestEnqueue_WithinLimitsProcessesNormally(t *testing.T) {
env, userID := setupTest(t)
ctx := context.Background()
docA := createDocument(t, env, userID, "a.txt", "inhalt a")
docB := createDocument(t, env, userID, "b.txt", "inhalt b")
exportID, err := Enqueue(ctx, env.pool, env.queue, userID, []string{docA, docB}, Limits{MaxDocuments: 10, MaxTotalSizeBytes: 1_000_000})
if err != nil {
t.Fatalf("Enqueue innerhalb der obergrenze haette erfolgreich sein sollen: %v", err)
}
env.worker.RunOnce(ctx)
exp, err := Get(ctx, env.pool, exportID)
if err != nil {
t.Fatalf("Get: %v", err)
}
if exp.Status != StatusReady {
t.Fatalf("status = %q, want ready, fehler=%v", exp.Status, exp.Error)
}
}
// Akzeptanzkriterium 3: die Obergrenzen sind konfigurierbar (Limits{} mit
// Nullwert = keine Grenze), nicht hart im Code verankert — derselbe Aufruf
// verhaelt sich je nach uebergebenem Limits-Wert unterschiedlich.
func TestEnqueue_ZeroLimitMeansUnbounded(t *testing.T) {
env, userID := setupTest(t)
ctx := context.Background()
docs := make([]string, 5)
for i := range docs {
docs[i] = createDocument(t, env, userID, "d.txt", "x")
}
if _, err := Enqueue(ctx, env.pool, env.queue, userID, docs, Limits{MaxDocuments: 0}); err != nil {
t.Fatalf("MaxDocuments=0 haette als 'keine grenze' behandelt werden sollen: %v", err)
}
}