package api
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"craftdesign.group/quarry/internal/ops"
)
// The multipart receiver's wildcard must not swallow the ops mounted
// on literal names beside it.
//
// G-148 (jva): POST .../attachments/{target...} claimed vouch, reject
// and remove, which are reached through the router mounted at "/api/" —
// a prefix match, which loses to a deeper pattern. All three answered
// "expected a multipart form with a file", to administrators included,
// so no API client could moderate an attachment at all, while the
// OpenAPI went on describing them as ordinary JSON ops.
//
// The question here is ROUTING and nothing else, so it is asked of the
// mux rather than by serving: which pattern does this path match? What
// the op then does with the request is that op's own test.
func TestTheUploadWildcardDoesNotSwallowItsNeighbours(t *testing.T) {
r := ops.NewRegistry()
if err := RegisterAll(r, Deps{Version: "v"}); err != nil {
t.Fatal(err)
}
router := http.HandlerFunc(func(http.ResponseWriter, *http.Request) {})
mux := http.NewServeMux()
MountUploadReceiver(mux, Deps{Version: "v"}, r, nil, nil, router)
const claimed = "/api/v1/r/{repo}/attachments/"
matched := func(path string) string {
_, pattern := mux.Handler(httptest.NewRequest("POST", path, strings.NewReader("{}")))
return pattern
}
// Every POST op the registry mounts under the claimed prefix, taken
// from the registry rather than listed here: one added tomorrow is
// covered the day it is written.
var names []string
for _, op := range r.All() {
if op.Method == http.MethodPost && strings.HasPrefix(op.Pattern, claimed) &&
!strings.ContainsAny(op.Pattern[len(claimed):], "{}/") {
names = append(names, op.Pattern[len(claimed):])
}
}
if len(names) == 0 {
t.Fatal("FAIL: no op is mounted under the claimed prefix; this test has lost its subject")
}
for _, name := range names {
want := "POST " + claimed + name
if got := matched("/api/v1/r/test/attachments/" + name); got != want {
t.Errorf("FAIL: %s matches %q, not its own op route", name, got)
continue
}
t.Logf("ok: %s reaches its op", name)
}
// The wildcard keeps its own job: a real target, slashes and all.
want := "POST " + claimed + "{target...}"
if got := matched("/api/v1/r/test/attachments/wiki/Some%20Page"); got != want {
t.Errorf("FAIL: an upload target matches %q, not the receiver", got)
}
t.Log("ok: a real upload target still reaches the receiver")
}