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>
115 lines
4.1 KiB
Go
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)
|
|
}
|
|
}
|