Skip to content
quarry Artifact [c15752527f]
Login

Artifact [c15752527f]

Artifact c15752527feeec1e3cfcc8494db07c17f94e222b38779ab528f07d3497887ac2:


package api

import (
	"os"
	"strings"
	"testing"
)

func srcOf(t *testing.T, name string) string {
	t.Helper()
	b, err := os.ReadFile(name)
	if err != nil {
		t.Fatal(err)
	}
	return string(b)
}

// An omitted switch is unchanged, not off.
//
// bucketPolicyIn carried plain bools and SetBucketPolicy was handed
// them directly, so a caller who sent {"archives": true} and omitted
// the other switch turned delete-on-removal OFF without asking, and an
// empty body turned both off and answered 200. That is dc748de1's
// shape — a partial write clearing what it was not told about — which
// repo.update had already been fixed for with pointers and this op had
// not.
//
// Found while checking that a bucket can be bound through the API at
// all: the probe for "is this op even reachable" was an empty POST to
// it, and the empty POST succeeded.
//
// Asserted in source because the defect is structural and the harness
// binds no bucket: the input must carry POINTERS, and the Run must
// read the current binding before applying what it was told.
func TestThePolicyOpReadsBeforeItWrites(t *testing.T) {
	src := srcOf(t, "attachwrite.go")
	for _, want := range []string{
		"Archives      *bool `json:\"archives\"`",
		"DeleteObjects *bool `json:\"deleteObjects\"`",
		"archives, deleteObjects := cur.Archives, cur.DeleteObjects",
		"if in.Archives != nil {",
		"if in.DeleteObjects != nil {",
	} {
		if !strings.Contains(src, want) {
			t.Errorf("FAIL: bucket.policy is missing %q; an omitted switch will be written "+
				"as false and clear what the caller never mentioned", want)
		}
	}
	if strings.Contains(src, "SetBucketPolicy(in.Repo, in.Archives, in.DeleteObjects)") {
		t.Error("FAIL: bucket.policy still passes its input straight through, so an empty " +
			"body clears both switches")
	}
}

// And the HTML form still names BOTH switches, which is correct and is
// what makes the pointers safe.
//
// A form knows its whole state, so it sends every switch and an
// unchecked box is an explicit false. An API caller may know only one
// field, so it may name only one. If the form ever stopped sending
// both, an unchecked box would read as "unchanged" and a switch could
// never be turned off from the page.
func TestTheSettingsFormStillNamesBothSwitches(t *testing.T) {
	src := srcOf(t, "../web/web.go")
	// A drawn box that is unticked is an explicit false (its paired
	// `has` field says it was drawn); an undrawn one is absent, which
	// the op reads as unchanged (quarry#424).
	for _, want := range []string{
		`for _, f := range []string{"archives", "deleteObjects"} {`,
		`form.Set(f, strconv.FormatBool(req.PostForm.Get(f) != ""))`,
		`<input type="hidden" name="has" value="archives">`,
		`<input type="hidden" name="has" value="deleteObjects">`,
	} {
		if !strings.Contains(src, want) {
			t.Errorf("FAIL: the settings form no longer sends %s explicitly; with pointers "+
				"an unchecked box would read as unchanged and the switch could not be "+
				"turned off from the page", want)
		}
	}
}