package webdav import ( "context" "errors" "testing" "aether/internal/files" ) // Ein abgebrochener Upload darf nichts hinterlassen. x/net/webdav ruft Close // per defer auf – auch nach einem Fehler in io.Copy. Ohne die Sperre in Close // landete der halb gefüllte Puffer als vollständige Datei in Cloud und // Datenbank: der Client meldet einen Fehler, die Datei ist trotzdem da, nur // abgeschnitten – und die Prüfsumme passt zum Torso, fällt also nie auf. // // fileStore und storage sind hier absichtlich nil: greift Close doch darauf // zu, paniert der Test statt still durchzulaufen. func TestWriteFileCloseDiscardsAbortedUpload(t *testing.T) { t.Run("quota exceeded during write", func(t *testing.T) { f := &davWriteFile{ ctx: context.Background(), name: "big.bin", expected: -1, written: 31, writeErr: files.ErrQuotaExceeded, } if err := f.Close(); !errors.Is(err, files.ErrQuotaExceeded) { t.Fatalf("Close() = %v, want ErrQuotaExceeded", err) } }) t.Run("connection dropped mid-upload", func(t *testing.T) { f := &davWriteFile{ ctx: context.Background(), name: "abort.bin", expected: 4096, written: 14, } if err := f.Close(); err == nil { t.Fatal("Close() = nil, want error for incomplete upload") } }) } // Chunked Uploads kündigen keine Größe an (Content-Length -1). Dann kann Close // die Vollständigkeit nicht prüfen und darf deshalb nicht blockieren – sonst // wäre jeder chunked Upload kaputt. func TestWriteFileCloseAcceptsUnknownLength(t *testing.T) { f := &davWriteFile{ ctx: context.Background(), name: "chunked.bin", expected: -1, written: 12, } // Kommt bis zum Store durch – der ist nil, also panic statt Fehler. defer func() { if recover() == nil { t.Fatal("Close() should have proceeded to the store, but returned early") } }() _ = f.Close() }