Skip to content
quarry Artifact [a510da6bfa]
Login

Artifact [a510da6bfa]

Artifact a510da6bfa14d92c52448f34f27805192bde5432622136f00d2fb19ec7110965:


package web

import (
	"io"
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

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

type stubCaps struct{ letters string }

func (s stubCaps) CapsOf(string, string) CapSet { return s }
func (s stubCaps) HasAny(letters string) bool   { return strings.ContainsAny(letters, s.letters) }

// stubPolicy protects trunk for alice; dan holds `i` and owns nothing.
type stubPolicy struct{ owner string }

func (p stubPolicy) MayJoin(_, user, branch string) bool { return branch != "trunk" || user == p.owner }
func (p stubPolicy) Protections(string) ([]oltp.Protection, error) {
	return []oltp.Protection{{Branch: "trunk", Owners: []string{p.owner}}}, nil
}

func protectedLandingServer(t *testing.T, ix *index.Index, owner string) *httptest.Server {
	t.Helper()
	r := ops.NewRegistry()
	if err := api.RegisterAll(r, api.Deps{Version: "v",
		Repos:   api.NewRepos(map[string]*api.Repo{"alpha": {Index: ix}}),
		Protect: stubPolicy{owner: owner}}); err != nil {
		t.Fatal(err)
	}
	srv := httptest.NewServer(HandlerWith(r, nil, nil,
		[]Option{WithSessions(fakeSessions{user: "dan"}), WithCaps(stubCaps{letters: "i"})}))
	t.Cleanup(srv.Close)
	return srv
}

func asDan(t *testing.T, srv *httptest.Server, path string) string {
	t.Helper()
	req, _ := http.NewRequest("GET", srv.URL+path, nil)
	req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "good"})
	resp, err := srv.Client().Do(req)
	if err != nil {
		t.Fatal(err)
	}
	defer resp.Body.Close()
	b, _ := io.ReadAll(resp.Body)
	return string(b)
}

// RFC 0007 §Testing, "non-owner with i / forge accept / control
// disabled". A control that would fail is not offered
// (docs/landings.md); one that names why is better than none — and it
// says forge policy, never a capability.
func TestProtectedTargetDisablesAcceptWithTheReason(t *testing.T) {
	srv := protectedLandingServer(t, landingIndex(t, false), "alice")
	html := asDan(t, srv, "/r/alpha/landing/"+strings.Repeat("a1", 6))
	if !strings.Contains(html, `disabled title="trunk is protected; owners: alice"`) {
		t.Fatalf("no disabled control with the reason:\n%.800s", html)
	}
	if strings.Contains(html, `formaction="/r/alpha/landing/a1a1a1a1a1a1/accept"`) {
		t.Error("an enabled accept was drawn for a non-owner")
	}
	if !strings.Contains(html, "is protected on this forge") {
		t.Error("the page does not say this is the forge's policy")
	}
}

// ...and for the owner, protection is not the reason for anything.
// Whether the control is offered is mergeability's call (unknowable
// without a store behind the index, and unknowable must not read as
// clean); what this proves is that an owner is never shown the
// non-owner's refusal.
func TestOwnerIsNotRefused(t *testing.T) {
	srv := protectedLandingServer(t, landingIndex(t, false), "dan")
	html := asDan(t, srv, "/r/alpha/landing/"+strings.Repeat("a1", 6))
	if strings.Contains(html, "is protected on this forge") ||
		strings.Contains(html, `title="trunk is protected`) {
		t.Fatalf("the owner is shown the non-owner's reason:\n%.800s", html)
	}
}