Skip to content
quarry Artifact [38b114007a]
Login

Artifact [38b114007a]

Artifact 38b114007ab0b057479622bd54d3b7bea3af3b687f7a8c2af593256d56caaeb1:


package web

import (
	"net/http"
	"net/http/httptest"
	"testing"
)

// place stands in for the registry: where each repository appears, and
// whether a name is a repository at all.
func place(m map[string]string) func(string) (string, bool) {
	return func(name string) (string, bool) {
		ns, ok := m[name]
		return ns, ok
	}
}

func servedPath(t *testing.T, h http.Handler, method, path string) (status int, served string, location string) {
	t.Helper()
	inner := http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
		served = req.URL.Path
	})
	w := httptest.NewRecorder()
	namespaced(inner).ServeHTTP(w, httptest.NewRequest(method, path, nil))
	return w.Code, served, w.Header().Get("Location")
}

func TestNamespacedPaths(t *testing.T) {
	old := repoPlace
	t.Cleanup(func() { repoPlace = old })
	// "quarry" is a repository AND, in the last case, the name of a
	// team — the collision the ordering exists to survive.
	repoPlace = place(map[string]string{
		"quarry":  "dmestas",
		"zit":     "quarry",
		"fossil":  "",
		"orchard": "grove",
	})

	for _, tc := range []struct {
		name, method, path string
		wantStatus         int
		wantServed         string
		wantLocation       string
	}{
		{"a namespaced path reaches the repository", "GET", "/r/grove/orchard/tree",
			200, "/r/orchard/tree", ""},
		{"a namespaced path with no tail", "GET", "/r/dmestas/quarry",
			200, "/r/quarry", ""},
		{"a flat path is sent to where the repository appears", "GET", "/r/orchard",
			302, "", "/r/grove/orchard"},
		{"a forge-held repository stays flat", "GET", "/r/fossil/tree",
			200, "/r/fossil/tree", ""},
		{"a repository name wins over a namespace of the same name", "GET", "/r/quarry/zit",
			302, "", "/r/dmestas/quarry/zit"},
		{"a post is served, never redirected", "POST", "/r/orchard/settings",
			200, "/r/orchard/settings", ""},
		{"an unknown first segment is left alone", "GET", "/r/nosuch/thing",
			200, "/r/nosuch/thing", ""},
		{"paths outside /r/ are untouched", "GET", "/t/grove",
			200, "/t/grove", ""},
	} {
		status, served, loc := servedPath(t, nil, tc.method, tc.path)
		if status != tc.wantStatus {
			t.Errorf("FAIL: %s: status %d, want %d", tc.name, status, tc.wantStatus)
			continue
		}
		if tc.wantServed != "" && served != tc.wantServed {
			t.Errorf("FAIL: %s: served %q, want %q", tc.name, served, tc.wantServed)
			continue
		}
		if tc.wantLocation != "" && loc != tc.wantLocation {
			t.Errorf("FAIL: %s: Location %q, want %q", tc.name, loc, tc.wantLocation)
			continue
		}
		t.Logf("ok: %s", tc.name)
	}
}

// The redirect must not be cached: where a repository appears changes
// when a team takes it, when a team is dissolved, and when the deed is
// handed on.
func TestTheCanonicalRedirectIsNotPermanent(t *testing.T) {
	old := repoPlace
	t.Cleanup(func() { repoPlace = old })
	repoPlace = place(map[string]string{"orchard": "grove"})
	status, _, _ := servedPath(t, nil, "GET", "/r/orchard")
	if status == http.StatusMovedPermanently {
		t.Fatal("FAIL: a permanent redirect to a target that moves is cached against the truth")
	}
	if status != http.StatusFound {
		t.Fatalf("FAIL: status %d, want 302", status)
	}
	t.Log("ok: the canonical redirect is temporary")
}

// Unwired, the forge serves flat paths exactly as it did.
func TestWithoutTheSeamPathsAreUntouched(t *testing.T) {
	old := repoPlace
	t.Cleanup(func() { repoPlace = old })
	repoPlace = nil
	status, served, _ := servedPath(t, nil, "GET", "/r/orchard/tree")
	if status != 200 || served != "/r/orchard/tree" {
		t.Fatalf("FAIL: status %d served %q, want 200 and the path unchanged", status, served)
	}
	t.Log("ok: no seam, no rewriting")
}