Skip to content
quarry Artifact [9f4b1e787c]
Login

Artifact [9f4b1e787c]

Artifact 9f4b1e787cc3282097995195674718edc08912267f467061ac2f3522be2a5c92:


package main

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

	"craftdesign.group/quarry/internal/api"
	"craftdesign.group/quarry/internal/events"
	"craftdesign.group/quarry/internal/index"
	"craftdesign.group/quarry/internal/ingest"
	"craftdesign.group/quarry/internal/lease"
	"craftdesign.group/quarry/internal/oltp"
	"craftdesign.group/quarry/internal/zitcli"
)

type premergeRequired struct{}

func (premergeRequired) RequiredChecks(string, string) []string { return []string{"ci"} }
func (premergeRequired) PremergeMode(string, string) bool       { return true }

// greenPairs reports every premerge pair as passed.
type greenPairs struct{}

func (greenPairs) CIRuns(string, int) ([]api.CIRun, error)          { return nil, nil }
func (greenPairs) CIRunsPage(string, int, int) ([]api.CIRun, error) { return nil, nil }
func (greenPairs) CIRunsFor(string, string) ([]api.CIRun, error)    { return nil, nil }
func (greenPairs) CIRunsForPair(_, pair string) ([]api.CIRun, error) {
	return []api.CIRun{{Checkin: pair, Workflow: "ci", Pipeline: "ci", Status: "success"}}, nil
}

func zitIn(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)
}

// acceptedLanding is a real store where feat landed on trunk through
// an accepted landing, folded into a real index: the merge the
// carry-forward writes a verdict onto.
func acceptedLanding(t *testing.T) (dir string, ix *index.Index) {
	t.Helper()
	if _, err := exec.LookPath("zit"); err != nil {
		t.Skip("zit not on PATH")
	}
	dir = t.TempDir()
	zitIn(t, dir, "init", ".")
	for _, step := range [][2]string{{"f.txt", "trunk"}, {"g.txt", "feat"}} {
		if err := os.WriteFile(filepath.Join(dir, step[0]), []byte(step[1]+"\n"), 0o644); err != nil {
			t.Fatal(err)
		}
		zitIn(t, dir, "add", step[0])
		args := []string{"commit", "-m", step[1], "--user", "u"}
		if step[1] == "feat" {
			args = append(args, "--branch", "feat")
		}
		zitIn(t, dir, args...)
	}
	cli := zitcli.New(dir)
	tok := lease.Unguarded("test: scratch store, no coordinator")
	id, err := cli.LandingOpen(tok, "dan", "feat", "trunk", "land feat", "")
	if err != nil {
		t.Fatal(err)
	}
	tip := strings.Fields(zitIn(t, dir, "info", "-R", filepath.Join(dir, ".zit"), "--", "feat"))[0]
	if _, err := cli.LandingAccept(tok, id, "dan", "", "", tip); err != nil {
		t.Fatal(err)
	}
	ev, err := events.Start(filepath.Join(t.TempDir(), "nats"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(ev.Close)
	ix, err = index.Open(filepath.Join(t.TempDir(), "index.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { ix.Close() })
	if _, err := ingest.NewPipeline(cli, ev, ix, "test", "n1").Sync(); err != nil {
		t.Fatal(err)
	}
	return dir, ix
}

// The carried verdict is written and only the ingest after it fails.
// The tag exists; the next pass, with the index still behind, must not
// append a second one.
func TestACarriedVerdictWrittenButNotIndexedIsNeverWrittenAgain(t *testing.T) {
	dir, ix := acceptedLanding(t)
	db, err := oltp.Open(filepath.Join(t.TempDir(), "o.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { db.Close() })
	writes := 0
	repos := api.NewRepos(map[string]*api.Repo{"test": {
		Index: ix, Zit: zitcli.New(dir),
		Guard: func(func(lease.Token) error) error { writes++; return nil },
		Sync:  func() (int, error) { return 0, errors.New("ingest round failed") },
	}})
	rg := &registrar{odb: db, ciTagsDefault: true,
		deps: &api.Deps{Repos: repos, Checks: premergeRequired{}, CI: greenPairs{}}}
	rg.carryForward("test", ix)
	if writes != 1 {
		t.Fatalf("the first pass wrote %d verdicts, want 1: the fixture carries nothing", writes)
	}
	rg.carryForward("test", ix)
	if writes != 1 {
		t.Fatalf("FAIL: %d verdicts written across two passes, want 1", writes)
	}
	t.Log("ok: two passes, one carried verdict")
}

// A fork and its source share check-in hashes, so the same merge can
// need a verdict in two repositories. Carrying it in one must not make
// the other skip it.
func TestACarriedVerdictInOneRepoDoesNotSkipTheSameMergeInAnother(t *testing.T) {
	dir, ix := acceptedLanding(t)
	db, err := oltp.Open(filepath.Join(t.TempDir(), "o.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { db.Close() })
	writes := map[string]int{}
	repo := func(name string) *api.Repo {
		return &api.Repo{Index: ix, Zit: zitcli.New(dir),
			Guard: func(func(lease.Token) error) error { writes[name]++; return nil },
			Sync:  func() (int, error) { return 0, errors.New("ingest round failed") }}
	}
	rg := &registrar{odb: db, ciTagsDefault: true, deps: &api.Deps{
		Repos:  api.NewRepos(map[string]*api.Repo{"source": repo("source"), "fork": repo("fork")}),
		Checks: premergeRequired{}, CI: greenPairs{}}}
	rg.carryForward("source", ix)
	rg.carryForward("fork", ix)
	if writes["source"] != 1 || writes["fork"] != 1 {
		t.Fatalf("FAIL: verdicts written source=%d fork=%d, want one each", writes["source"], writes["fork"])
	}
	t.Log("ok: the same merge carried once in each repository")
}

// A restarted forge has no memory of what it carried, and the index is
// still behind the store. The verdict is in the store, so nothing is
// written again.
func TestACarriedVerdictTheStoreHoldsIsNotWrittenAgainAfterARestart(t *testing.T) {
	dir, ix := acceptedLanding(t)
	merge := strings.Fields(zitIn(t, dir, "info", "-R", filepath.Join(dir, ".zit"), "--", "trunk"))[0]
	zitIn(t, dir, "tag", "add", "--raw", "ci-pass", merge, "premerge", "-R", filepath.Join(dir, ".zit"))
	db, err := oltp.Open(filepath.Join(t.TempDir(), "o.db"))
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { db.Close() })
	writes := 0
	rg := &registrar{odb: db, ciTagsDefault: true, deps: &api.Deps{
		Repos: api.NewRepos(map[string]*api.Repo{"test": {Index: ix, Zit: zitcli.New(dir),
			Guard: func(func(lease.Token) error) error { writes++; return nil }}}),
		Checks: premergeRequired{}, CI: greenPairs{}}}
	rg.carryForward("test", ix)
	if writes != 0 {
		t.Fatalf("FAIL: %d verdicts written onto a merge the store already holds one on", writes)
	}
	t.Log("ok: the store's verdict stands; nothing written")
}