Skip to content
quarry Artifact [e58bc9fbee]
Login

Artifact [e58bc9fbee]

Artifact e58bc9fbee16fee478fe98f3c5f734bae39066f5a839d97672b3a92380dd43e1:


package web

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

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

// The page behind a landing email's Accept button: signed out, it sends
// the reader to sign in and back; signed in, it asks one question with
// one button, which arms the landing at the tip the email named. The GET
// writes nothing, because mail scanners open links.
func TestTheApprovePageArmsAtTheEmailedTip(t *testing.T) {
	type getIn struct {
		Repo string `json:"repo"`
		ID   string `json:"id"`
	}
	type row struct {
		ID     string `json:"id"`
		Number int    `json:"number"`
		Branch string `json:"branch"`
		Target string `json:"target"`
		Title  string `json:"title"`
		State  string `json:"state"`
	}
	type getOut struct {
		Landing   row      `json:"landing"`
		Unmet     []string `json:"unmet"`
		CanAccept bool     `json:"canAccept"`
	}
	writes := 0
	r := ops.NewRegistry()
	if err := ops.Register(r, ops.Op[getIn, getOut]{
		Name: "landing.get", Doc: "test stub", Kind: ops.Query, Auth: ops.Anonymous,
		Route: "GET /api/v1/r/{repo}/landing/{id}",
		Run: func(context.Context, getIn) (getOut, error) {
			return getOut{Landing: row{ID: "aaaa1111", Number: 7, Branch: "feature-x", Target: "trunk", Title: "Add x", State: "open"},
				Unmet: []string{"ci/quarry.json"}, CanAccept: true}, nil
		},
	}); err != nil {
		t.Fatal(err)
	}
	if err := ops.Register(r, ops.Op[getIn, struct{}]{
		Name: "landing.auto", Doc: "test stub", Kind: ops.Command, Auth: ops.Token,
		Route: "POST /api/v1/r/{repo}/landing/{id}/auto",
		Run:   func(context.Context, getIn) (struct{}, error) { writes++; return struct{}{}, nil },
	}); err != nil {
		t.Fatal(err)
	}
	type ver struct {
		Version string `json:"version"`
	}
	if err := ops.Register(r, ops.Op[struct{}, ver]{
		Name: "meta.version", Doc: "test stub", Kind: ops.Query, Auth: ops.Anonymous, Route: "GET /api/v1/version",
		Run: func(context.Context, struct{}) (ver, error) { return ver{Version: "t"}, nil },
	}); err != nil {
		t.Fatal(err)
	}
	verify := Verify(func(repo, user, pass string, need ops.Auth) api.Decision { return api.Allowed })
	h := HandlerWith(r, nil, nil, []Option{WithSessions(fakeSessions{user: "dan", roles: map[string]ops.Auth{"alpha": ops.Admin}})}, verify)
	srv := httptest.NewServer(h)
	t.Cleanup(srv.Close)
	client := &http.Client{CheckRedirect: func(*http.Request, []*http.Request) error { return http.ErrUseLastResponse }}
	get := func(signedIn bool, q string) (*http.Response, string) {
		req, _ := http.NewRequest("GET", srv.URL+"/r/alpha/landing/aaaa1111/approve"+q, nil)
		if signedIn {
			req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "good"})
		}
		resp, err := client.Do(req)
		if err != nil {
			t.Fatal(err)
		}
		b, _ := io.ReadAll(resp.Body)
		resp.Body.Close()
		return resp, string(b)
	}
	resp, _ := get(false, "?tip=abcdef012345")
	if resp.StatusCode != http.StatusSeeOther || !strings.HasPrefix(resp.Header.Get("Location"), "/login?next=") ||
		!strings.Contains(resp.Header.Get("Location"), "approve%3Ftip%3Dabcdef012345") {
		t.Fatalf("FAIL: signed out, the page answered %d to %q", resp.StatusCode, resp.Header.Get("Location"))
	}
	resp, body := get(true, "?tip=abcdef012345")
	if resp.StatusCode != http.StatusOK {
		t.Fatalf("FAIL: signed in, the page answered %d:\n%s", resp.StatusCode, body)
	}
	for _, want := range []string{
		`data-hook="landing-approve"`,
		`action="/r/alpha/landing/aaaa1111/auto"`,
		`name="tip" value="abcdef012345"`,
		`name="on" value="true"`,
		`data-hook="approve-accept"`,
		`href="/r/alpha/landing/aaaa1111"`,
	} {
		if !strings.Contains(body, want) {
			t.Errorf("FAIL: the approve page lacks %q", want)
		}
	}
	if _, body := get(true, "?tip=not-a-tip"); strings.Contains(body, `data-hook="approve-accept"`) {
		t.Error("FAIL: a link naming no tip still offered to accept")
	}
	if writes != 0 {
		t.Errorf("FAIL: opening the page wrote %d time(s)", writes)
	}
	t.Log("ok: the approve page asks once, signed in, and arms at the emailed tip")
}