Skip to content
quarry Artifact [212d88f771]
Login

Artifact [212d88f771]

Artifact 212d88f7717ff3aab1b6995a72f89909c8f05be3b7d6ed660fe630daeb5daa0f:


package web

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

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/ops"
)

// Building a handler must not write anything a handler already serving
// reads. The parallel tests build handlers while others serve, and a
// forge that ever builds a second one (a reload, a test harness) would
// otherwise hand a request half of one configuration and half of the
// other. Meaningful under -race, which is how the gate runs it.
func TestBuildingAHandlerDoesNotRaceOneServing(t *testing.T) {
	r := ops.NewRegistry()
	if err := api.RegisterAll(r, api.Deps{Version: "v", Repos: api.NewRepos(map[string]*api.Repo{})}); err != nil {
		t.Fatal(err)
	}
	opts := func() []Option {
		return []Option{
			WithNamespaces(place(map[string]string{"orchard": "grove"})),
			WithNamespaceHistory(func(string, string) bool { return false }),
			WithMarks(func(string, string) (string, bool) { return "", false }),
			WithMarksChanged(func() {}),
			WithAgents(func(string) string { return "" }),
		}
	}
	serving := HandlerWith(r, nil, nil, opts())
	var wg sync.WaitGroup
	for i := 0; i < 4; i++ {
		wg.Add(2)
		go func() {
			defer wg.Done()
			for _, path := range []string{"/r/orchard", "/r/grove/orchard", "/"} {
				serving.ServeHTTP(httptest.NewRecorder(), httptest.NewRequest("GET", path, nil))
			}
		}()
		go func() {
			defer wg.Done()
			HandlerWith(r, nil, nil, opts())
		}()
	}
	wg.Wait()
	// The first handler still answers by its own configuration.
	rec := httptest.NewRecorder()
	serving.ServeHTTP(rec, httptest.NewRequest("GET", "/r/orchard", nil))
	if rec.Code != 302 || rec.Header().Get("Location") != "/r/grove/orchard" {
		t.Errorf("FAIL: a flat path answered %d %q, want 302 to /r/grove/orchard", rec.Code, rec.Header().Get("Location"))
	}
}

// drawWith has the page templates draw with h until the test ends.
func drawWith(t *testing.T, h handlerHooks) {
	t.Helper()
	was := drawn.Load()
	t.Cleanup(func() { drawn.Store(was) })
	drawn.Store(&h)
}