Skip to content
quarry Artifact [8cb63e5d6a]
Login

Artifact [8cb63e5d6a]

Artifact 8cb63e5d6ac0c61b407d7ce6e799060fcb085556c96e74aba29ec229ce85a965:


package web

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

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

// A forge-only binding draws no composer.
//
// bucket.get used to answer bound:true for the forge fallback, so this
// composer re-derived "bound and not forge" itself, and a source-text
// test pinned that workaround. The API now answers the uploader's
// question (bucket.get is bound:false for the fallback, with the reason
// in note), so the composer reads Bound and nothing else — and what
// this test pins is the BEHAVIOUR the workaround protected: a
// repository with only the forge's binding offers no upload control,
// and tells an admin what to do; a repository with its own bucket
// offers one.
func TestAForgeOnlyBindingDrawsNoComposer(t *testing.T) {
	buckets := webBuckets{
		oltp.ForgeBucket: {Endpoint: "https://s3.example", Bucket: "forge", Region: "auto", AccessKey: "k", Secret: "s", LimitBytes: 1 << 20},
		"own":            {Endpoint: "https://s3.example", Bucket: "mine", Region: "auto", AccessKey: "k2", Secret: "s2", LimitBytes: 2 << 20, CorsOK: true},
	}
	r := ops.NewRegistry()
	if err := api.RegisterAll(r, api.Deps{Version: "v",
		Repos:   api.NewRepos(map[string]*api.Repo{"own": {}, "inherit": {}}),
		Buckets: buckets}); err != nil {
		t.Fatal(err)
	}
	// An admin who may attach: letters b (upload) and a (bind).
	caps, sess := stubCaps{letters: "ba"}, fakeSessions{user: "dan"}
	for repo, want := range map[string]bool{"own": true, "inherit": false} {
		req := httptest.NewRequest("GET", "/r/"+repo+"/ticket/t1", nil)
		req.AddCookie(&http.Cookie{Name: sessionCookie, Value: "good"})
		w := attachWriteFor(r, caps, nil, sess, repo, "ticket", req)
		if w.CanAttach != want {
			t.Errorf("FAIL %s: composer drawn = %v, want %v — %s", repo, w.CanAttach, want,
				map[bool]string{true: "a bucket of its own must offer an upload", false: "the forge's binding is not this repository's to upload into"}[want])
		} else {
			t.Logf("ok %s: composer drawn = %v", repo, want)
		}
		if !want && !w.Unbound {
			t.Errorf("FAIL %s: an admin on a repository with no bucket of its own is not told to bind one", repo)
		}
	}
}

// And the words a reader gets are the actionable ones.
func TestTheUnboundNoteNamesTheSettingsPage(t *testing.T) {
	var out strings.Builder
	c := attachCtx{Repo: "alpha", Target: "t", Write: &attachWrite{Unbound: true}}
	if err := attachFragPage.ExecuteTemplate(&out, "attachments", c); err != nil {
		t.Fatal(err)
	}
	body := out.String()
	if !strings.Contains(body, "settings#attachments") {
		t.Error("FAIL: the unbound note does not link the settings page")
	}
	if !strings.Contains(body, "No bucket is bound") {
		t.Error("FAIL: the unbound note does not say what is wrong")
	}
	// A reader who cannot bind one is told nothing they cannot act on.
	var reader strings.Builder
	rc := attachCtx{Repo: "alpha", Target: "t", Write: &attachWrite{}}
	if err := attachFragPage.ExecuteTemplate(&reader, "attachments", rc); err != nil {
		t.Fatal(err)
	}
	if strings.Contains(reader.String(), "No bucket is bound") {
		t.Error("FAIL: a reader who cannot bind a bucket is told to bind one")
	}
}