Skip to content
quarry Artifact [17b090f874]
Login

Artifact [17b090f874]

Artifact 17b090f8745003151a0d12290e6ec2a2e388579cc6194a32bbe7300d3070c451:


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")
	for _, want := range []string{
		`"archives":      {strconv.FormatBool(req.FormValue("archives") != "")}`,
		`"deleteObjects": {strconv.FormatBool(req.FormValue("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)
		}
	}
}