Skip to content
quarry Artifact [7968e6e41e]
Login

Artifact [7968e6e41e]

Artifact 7968e6e41e96003ab13165a120f8566a3e24094c9195b49b88cff0b287914112:


package api

import (
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"testing"

	"craftdesign.group/quarry/internal/zitcli"
)

func zrun(t *testing.T, dir string, args ...string) string {
	t.Helper()
	cmd := exec.Command("zit", args...)
	cmd.Dir = dir
	out, err := cmd.CombinedOutput()
	if err != nil {
		t.Fatalf("zit %v: %v\n%s", args, err, out)
	}
	return string(out)
}

func zwrite(t *testing.T, dir, name, body string) {
	t.Helper()
	if err := os.WriteFile(filepath.Join(dir, name), []byte(body), 0o644); err != nil {
		t.Fatal(err)
	}
}

func ztip(t *testing.T, dir, branch string) string {
	t.Helper()
	out := zrun(t, dir, "branch", "info", branch)
	for _, line := range strings.Split(out, "\n") {
		for _, f := range strings.Fields(line) {
			if len(f) == 64 && strings.Trim(f, "0123456789abcdef") == "" {
				return f
			}
		}
	}
	t.Fatalf("no tip hash in `zit branch info %s`:\n%s", branch, out)
	return ""
}

// landedStore builds a store with two branches: one whose work was
// merged into trunk and LEFT OPEN, and one with work genuinely
// outstanding. The first is the case four cheap questions cannot tell
// from the second.
func landedStore(t *testing.T) (dir, trunkTip, landedTip, strandedTip string) {
	t.Helper()
	if _, err := exec.LookPath("zit"); err != nil {
		t.Skip("zit not on PATH")
	}
	dir = t.TempDir()
	zrun(t, dir, "init", ".")
	zwrite(t, dir, "f.txt", "root\n")
	zrun(t, dir, "add", "f.txt")
	zrun(t, dir, "commit", "-m", "root", "--user", "u")

	// The branch that lands and stays open.
	zwrite(t, dir, "f.txt", "root\nlanded\n")
	zrun(t, dir, "commit", "-m", "landed work", "--branch", "went-in", "--user", "u")
	landedTip = ztip(t, dir, "went-in")
	zrun(t, dir, "update", "trunk")
	zrun(t, dir, "merge", "went-in")
	zrun(t, dir, "commit", "-m", "merge went-in", "--user", "u")
	trunkTip = ztip(t, dir, "trunk")

	// The branch with work nobody has taken.
	zwrite(t, dir, "g.txt", "outstanding\n")
	zrun(t, dir, "add", "g.txt")
	zrun(t, dir, "commit", "-m", "real work", "--branch", "stranded", "--user", "u")
	strandedTip = ztip(t, dir, "stranded")
	return dir, trunkTip, landedTip, strandedTip
}

// The four cheap questions are not the question. Landing a branch
// normally closes it, so the open test covers the usual case — but a
// branch landed and left OPEN still got the offer, and accepting it
// opened a record that said "merges up-to-date" on arrival.
func TestABranchWhoseWorkLandedIsNotOfferedAgain(t *testing.T) {
	dir, trunkTip, landedTip, strandedTip := landedStore(t)
	repo := &Repo{Zit: zitcli.New(dir)}

	if !alreadyLanded(repo, landedTip, trunkTip) {
		t.Error("FAIL: a branch merged into trunk still reads as having work to propose")
	}
	if alreadyLanded(repo, strandedTip, trunkTip) {
		t.Error("FAIL: real stranded work reads as already landed — the offer would be withheld")
	}
}

// The unproposed list drops the landed rows and keeps the stranded one.
func TestTheUnproposedListDropsWorkThatLanded(t *testing.T) {
	dir, trunkTip, landedTip, strandedTip := landedStore(t)
	repo := &Repo{Zit: zitcli.New(dir)}
	got := dropLandedRows(repo, []unproposedRow{
		{Branch: "went-in", Tip: landedTip},
		{Branch: "stranded", Tip: strandedTip},
	}, trunkTip)
	if len(got) != 1 || got[0].Branch != "stranded" {
		t.Errorf("FAIL: the list kept %+v, want only stranded", got)
	}
}

// A probe that cannot run answers NOT LANDED. This check exists to
// withhold an offer, and withholding one because a subprocess failed
// would hide real stranded work behind an infrastructure fault.
func TestAProbeThatCannotRunKeepsTheOldBehaviour(t *testing.T) {
	for _, tc := range []struct {
		name string
		repo *Repo
	}{
		{"no repository", nil},
		{"no store handle", &Repo{}},
	} {
		if alreadyLanded(tc.repo, "aaaa", "bbbb") {
			t.Errorf("FAIL: %s answered landed; the safe default is not landed", tc.name)
		}
	}
	// And an unanswerable target leaves every row in place rather than
	// dropping rows nobody checked.
	rows := []unproposedRow{{Branch: "a", Tip: "t1"}, {Branch: "b", Tip: "t2"}}
	if got := dropLandedRows(&Repo{}, rows, ""); len(got) != 2 {
		t.Errorf("FAIL: an unknown target dropped rows: %+v", got)
	}
}

// Past the cap the rows are reported UNPROBED — the behaviour that
// existed before this check. Degrading to the old answer beats
// degrading to a slow page, and beats silently dropping rows.
func TestPastTheCapRowsSurviveUnprobed(t *testing.T) {
	dir, trunkTip, landedTip, _ := landedStore(t)
	repo := &Repo{Zit: zitcli.New(dir)}
	var rows []unproposedRow
	for i := 0; i < landedProbeCap+3; i++ {
		rows = append(rows, unproposedRow{Branch: "went-in", Tip: landedTip})
	}
	got := dropLandedRows(repo, rows, trunkTip)
	// Every row is the same landed branch, so the probed ones all go and
	// exactly the overflow survives.
	if len(got) != 3 {
		t.Errorf("FAIL: %d rows survived, want the 3 past the cap of %d", len(got), landedProbeCap)
	}
}