Skip to content
quarry Artifact [c67cfacf6a]
Login

Artifact [c67cfacf6a]

Artifact c67cfacf6a1836f466bd73571b0d79dde6647cc1884cb140966821e92b67b61b:


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")
}