Restrict wildcard evict to <dir>/*, return 503 on lock contention, surface S3 list errors
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful

This commit is contained in:
2026-10-04 16:06:54 +11:00
parent c1c5ff987c
commit e67629cb2d
5 changed files with 221 additions and 32 deletions
+27
View File
@@ -4,11 +4,15 @@ import (
"bytes"
"context"
"io"
"net/http"
"net/http/httptest"
"os"
"strings"
"testing"
"time"
"github.com/minio/minio-go/v7"
"git.unkin.net/unkin/artifactapi/internal/testsupport"
)
@@ -158,3 +162,26 @@ func TestCASStore(t *testing.T) {
t.Errorf("stored content mismatch: %q", got)
}
}
// The fake endpoint fails every list but accepts every delete, as an S3 that
// tolerates deleting an empty key would.
func TestDeletePrefixReturnsListError(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodPost {
_, _ = io.WriteString(w, `<DeleteResult></DeleteResult>`)
return
}
w.WriteHeader(http.StatusInternalServerError)
_, _ = io.WriteString(w, `<Error><Code>InternalError</Code><Message>list failed</Message></Error>`)
}))
defer srv.Close()
client, err := minio.New(strings.TrimPrefix(srv.URL, "http://"), &minio.Options{Region: "us-east-1", MaxRetries: 1})
if err != nil {
t.Fatal(err)
}
s := &S3{client: client, bucket: "bucket"}
err = s.DeletePrefix(context.Background(), "indexes/r/")
if err == nil {
t.Fatal("DeletePrefix on a failing list returned nil")
}
}