Files
mesh-controller/internal/builder/release_branch_test.go
T
jschoubben 3ec4473b29
mesh/merge-gate head 3ec4473b29b2 merged into trunk df8c1ccf1fff — pass: builds build-agent, mesh-controller → ace, g14, novox, shanks; no bus step; every …
mesh/repo-check head 3ec4473b29b2 merged into trunk df8c1ccf1fff — pass: THE CHANGE ALTERS ITS OWN CHECK (merge-check.sh): main's version judged it; the ch…
mesh/delivery delivered
Run the slow test packages in shards and stop compiling the standard library per judge test (hq issue 717)
The controller's check spent 3-5 minutes in cmd/mesh-controller, whose few hundred store tests run one
after another, while most packages end in seconds. merge-check.sh now compiles each slow package once and
deals its tests round-robin into processes that run beside each other and beside the rest of the suite;
every test still runs once, under the race detector, through its package's TestMain. The listed store
tests run beside the suite instead of after it.

internal/builder's judge tests ran a real go build with a fresh Go cache each, compiling the standard
library every time: half the suite's CPU. The fake runtime fills an empty cache from one warmed per
process. The lease tests run in parallel. The link test of slow work now sets its one-second window after
the serving loop asserted the controller's thirty-second one, so it proves the heartbeat (it passed
without it) in half the time.
2026-10-14 20:38:35 +02:00

871 lines
44 KiB
Go

package builder
import (
"fmt"
"net"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
)
// **A pull request into a release branch is judged by the controller of that branch** (novox/hq ADR 0358, issue
// 704): the build seat's check builds the judge from mesh-controller read at the release branch — with mesh-host's
// validator of that branch when mesh-host has one — reads every repository beside it at that branch where it has one
// and at its trunk otherwise, and names the branch, the judge's commit and each repository read with its commit.
const releaseBranch = "feat/57-config-and-provisioning"
// gitInRepo runs git in a repository made for a test.
func gitInRepo(t *testing.T, dir string, args ...string) string {
t.Helper()
cmd := exec.Command("git", args...)
cmd.Dir = dir
cmd.Env = append(os.Environ(), "GIT_AUTHOR_NAME=t", "GIT_AUTHOR_EMAIL=t@example.org",
"GIT_COMMITTER_NAME=t", "GIT_COMMITTER_EMAIL=t@example.org")
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("git %v: %v\n%s", args, err, out)
}
return strings.TrimSpace(string(out))
}
// commitFiles writes files into a repository and commits them on the branch checked out.
func commitFiles(t *testing.T, dir string, files map[string]string) string {
t.Helper()
for name, body := range files {
if err := os.MkdirAll(filepath.Dir(filepath.Join(dir, name)), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, name), []byte(body), 0o755); err != nil {
t.Fatal(err)
}
}
gitInRepo(t, dir, "add", "-A")
gitInRepo(t, dir, "commit", "--quiet", "-m", "x")
return gitInRepo(t, dir, "rev-parse", "HEAD")
}
// aRepositoryWithARelease is a repository whose main holds mainFiles and, when releaseFiles is not nil, a release
// branch over them holding releaseFiles. It answers the repository, main's head and the release branch's head.
func aRepositoryWithARelease(t *testing.T, mainFiles, releaseFiles map[string]string) (string, string, string) {
t.Helper()
dir := t.TempDir()
gitInRepo(t, dir, "init", "--quiet", "-b", "main")
main := commitFiles(t, dir, mainFiles)
if releaseFiles == nil {
return dir, main, ""
}
gitInRepo(t, dir, "checkout", "--quiet", "-b", releaseBranch)
head := commitFiles(t, dir, releaseFiles)
gitInRepo(t, dir, "checkout", "--quiet", "main")
return dir, main, head
}
// aJudgeOf is a controller that judges as told: its gate passes, saying who it is and the word of the node-engine
// validator it vendors — the one it was built with.
func aJudgeOf(who string) map[string]string {
return map[string]string{
"go.mod": "module example.org/judge\n\ngo 1.22\n\nrequire github.com/novox/mesh-host v0.0.0\n",
"vendor/modules.txt": "# github.com/novox/mesh-host v0.0.0\n## explicit; go 1.22\ngithub.com/novox/mesh-host/validate\n",
"vendor/github.com/novox/mesh-host/validate/v.go": "package validate\n\nconst Word = \"the vendored validator\"\n",
"vendor/github.com/novox/mesh-host/internal/declaration/d.go": "package declaration\n",
"cmd/mesh-controller/main.go": `package main
import (
"fmt"
"os"
"github.com/novox/mesh-host/validate"
)
func main() {
if len(os.Args) == 2 && os.Args[1] == "merge-gate" {
fmt.Println("usage: merge-gate --facts <file> --store <postgres>")
os.Exit(2)
}
fmt.Printf("{\"verdict\":\"pass\",\"summary\":\"%s with %s\"}\n", "` + who + `", validate.Word)
}
`,
}
}
// aHostSaying is the node-engine's validator, saying a word.
func aHostSaying(word string) map[string]string {
return map[string]string{
"validate/v.go": "package validate\n\nconst Word = \"" + word + "\"\n",
"internal/declaration/d.go": "package declaration\n",
"validate/v_test.go": "package validate\n",
"internal/declaration/x_test.go": "package declaration\n",
}
}
// aRuntimeThatBuildsTheJudge puts a container runtime on PATH that runs every container's command on this machine,
// in the directory and with the environment the check gives it — the judge's build too — and a store and a bus that
// answer. It answers the file each `go` the check runs is written to.
func aRuntimeThatBuildsTheJudge(t *testing.T) string {
t.Helper()
if _, err := exec.LookPath("go"); err != nil {
t.Skip("no Go toolchain on this machine to build a judge with")
}
bus, err := net.Listen("tcp", "127.0.0.1:0")
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { bus.Close() })
go func() {
for {
c, err := bus.Accept()
if err != nil {
return
}
c.Close()
}
}()
dir := t.TempDir()
built := filepath.Join(dir, "built")
runtime := `#!/bin/sh
cmd="$1"; shift
case "$cmd" in
ps|rm|exec) exit 0 ;;
volume)
if [ -n "$VOLUMES" ]; then echo "$*" >> "$VOLUMES"; fi
exit 0 ;;
port) echo "` + bus.Addr().String() + `"; exit 0 ;;
run)
if [ -n "$RUNS" ]; then echo "$*" >> "$RUNS"; fi
workdir=""; detached=""
while [ $# -gt 0 ]; do
case "$1" in
-d) detached=1; shift ;;
--rm) shift ;;
--workdir) workdir="$2"; shift 2 ;;
--env) export "$2"; shift 2 ;;
--network|--volume|--user|--label|--name|-p|-e) shift 2 ;;
*) break ;;
esac
done
if [ -n "$detached" ]; then echo a-container; exit 0; fi
shift
if [ "$1" = go ]; then echo "GOCACHE=$GOCACHE GOENV=$GOENV $*" >> "` + built + `"; fi
if [ "$1" = go ] && [ "$2" = build ] && [ -n "$JUDGE_HOMES" ]; then echo "$HOME" >> "$JUDGE_HOMES"; fi
if [ "$1" = go ] && [ "$2" = test ] && [ -n "$REPLAYS_CANNOT_START" ]; then
echo "docker: Error response from daemon: invalid mount config for type bind" >&2; exit 125
fi
if [ "$1" = go ] && [ "$2" = test ] && [ -n "$REPLAYS" ]; then
echo "HOME=$HOME GOCACHE=$GOCACHE GOMODCACHE=$GOMODCACHE GOENV=$GOENV GOFLAGS=$GOFLAGS DIR=$workdir" >> "$REPLAYS"
fi
if [ "$1" = go ] && [ -n "$WARM_GO_CACHE" ] && [ -n "$GOCACHE" ] && [ -z "$(ls -A "$GOCACHE" 2>/dev/null)" ]; then
mkdir -p "$GOCACHE" && cp -R "$WARM_GO_CACHE/." "$GOCACHE/"
fi
cd "$workdir" && exec "$@" ;;
esac
exit 1
`
if err := os.WriteFile(filepath.Join(dir, "docker"), []byte(runtime), 0o755); err != nil {
t.Fatal(err)
}
t.Setenv("PATH", dir+string(os.PathListSeparator)+os.Getenv("PATH"))
t.Setenv("GOTOOLCHAIN", "local")
// An empty Go cache the check names is filled from a warm one before `go` runs (warm_go_cache_test.go).
t.Setenv("WARM_GO_CACHE", warmGoCache(t))
return built
}
// builds is how many times the check ran go to build a judge.
func builds(t *testing.T, file string) int {
t.Helper()
body, err := os.ReadFile(file)
if err != nil {
return 0
}
return strings.Count(string(body), "go build")
}
// theReleasedMesh is the core beside a release-branch check: a controller whose main and release branch judge
// differently, a node-engine with a validator of each, and a lab with no release branch.
func theReleasedMesh(t *testing.T) (map[string]Beside, string, string, string) {
t.Helper()
controller, _, controllerRelease := aRepositoryWithARelease(t, aJudgeOf("main's controller"),
aJudgeOf("the release branch's controller"))
host, _, hostRelease := aRepositoryWithARelease(t, aHostSaying("main's validator"),
aHostSaying("the release branch's validator"))
lab, labMain, _ := aRepositoryWithARelease(t, map[string]string{"README": "the lab"}, nil)
return map[string]Beside{
"mesh-controller": {Repository: controller, Ref: releaseBranch},
"mesh-controller-main": {Repository: controller, Ref: "main"},
"mesh-host": {Repository: host, Ref: releaseBranch, Else: "main"},
"mesh-lab": {Repository: lab, Ref: releaseBranch, Else: "main"},
}, controllerRelease, hostRelease, labMain
}
// aPullRequestInto is a repository whose pull request's head is cut from base, with a change.
func aPullRequestInto(t *testing.T, files map[string]string, base string, change map[string]string) (string, string) {
t.Helper()
repo, _, _ := aRepositoryWithARelease(t, files, map[string]string{"released": "r"})
gitInRepo(t, repo, "checkout", "--quiet", "-b", "change", base)
head := commitFiles(t, repo, change)
gitInRepo(t, repo, "checkout", "--quiet", "main")
return repo, head
}
func TestACataloguePullRequestIntoAReleaseBranchIsJudgedByThatBranchsController(t *testing.T) {
built := aRuntimeThatBuildsTheJudge(t)
registry := aFactsRegistry(t)
beside, controllerRelease, hostRelease, labMain := theReleasedMesh(t)
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "true\n"}, releaseBranch, map[string]string{"modules/gitea/index.ts": "x"})
cache := t.TempDir()
check := func(id string) CheckVerdict {
t.Helper()
v, err := Check(t.Context(), Command, CheckSpec{ID: id, Repository: catalogue, Ref: head, Owner: "novox",
Repo: "mesh-catalog", Number: 286, Base: releaseBranch, Release: releaseBranch, JudgeCache: cache,
Paths: []string{"modules/gitea/index.ts"}, Modules: []string{"gitea"}, Beside: beside, Toolchain: "golang"},
t.TempDir(), registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
return v
}
v := check("check-704-catalogue")
// The release branch's controller judged, with mesh-host's validator of the release branch.
if v.Gate == nil || v.Gate.Verdict != "pass" ||
!strings.HasSuffix(v.Gate.Summary, "the release branch's controller with the release branch's validator") {
t.Fatalf("the gate was not judged by the release branch's controller with its node-engine's validator: %+v\n%s",
v.Gate, v.Report)
}
// It names the release branch, the judge's commit, and each repository read beside it at its branch and commit.
mark := "[release " + releaseBranch + ", judged by its controller " + controllerRelease[:12] + "] "
if !strings.HasPrefix(v.Gate.Summary, mark) || !strings.HasPrefix(v.Repo.Summary, mark) {
t.Fatalf("the statuses do not name the release branch and its judge first:\n%s\n%s", v.Gate.Summary, v.Repo.Summary)
}
if v.Release != releaseBranch || v.JudgedBy != controllerRelease[:12] {
t.Fatalf("the verdict names release %q judged by %q, not %s by %s", v.Release, v.JudgedBy, releaseBranch,
controllerRelease[:12])
}
if v.BesideAt["mesh-host"] != releaseBranch || v.Beside["mesh-host"] != hostRelease[:12] {
t.Fatalf("mesh-host was read at %q (%s), not its release branch at %s", v.BesideAt["mesh-host"],
v.Beside["mesh-host"], hostRelease[:12])
}
// A repository with no release branch is read at its trunk, and says so.
if v.BesideAt["mesh-lab"] != "main" || v.Beside["mesh-lab"] != labMain[:12] {
t.Fatalf("the lab, with no release branch, was read at %q (%s), not main at %s", v.BesideAt["mesh-lab"],
v.Beside["mesh-lab"], labMain[:12])
}
if !strings.Contains(v.Report, "read beside it: ") || !strings.Contains(v.Report, "mesh-host "+releaseBranch+" at "+hostRelease[:12]) {
t.Fatalf("the report does not say what was read beside it:\n%s", v.Report)
}
// It says which validator judged: mesh-host's of the release branch, with its commit.
if want := "mesh-host's validator of " + releaseBranch + " at " + hostRelease[:12]; v.Validator != want ||
!strings.Contains(v.Report, want) {
t.Fatalf("the verdict says the validator was %q, not %q:\n%s", v.Validator, want, v.Report)
}
// Each repository read beside it is named with the branch and the commit read.
for dir := range beside {
if v.BesideAt[dir] == "" || v.Beside[dir] == "" ||
!strings.Contains(v.Report, dir+" "+v.BesideAt[dir]+" at "+v.Beside[dir]) {
t.Fatalf("%s is not named with its branch and commit: at %q, commit %q\n%s", dir, v.BesideAt[dir],
v.Beside[dir], v.Report)
}
}
if n := builds(t, built); n != 1 {
t.Fatalf("the judge was built %d times for one check", n)
}
// **The judge is built with the judge cache's Go cache** (ADR 0358 §6), which no check's container mounts, and no
// Go environment file.
said, _ := os.ReadFile(built)
if !strings.Contains(string(said), "GOCACHE="+filepath.Join(cache, "go-cache")+" GOENV=off go build") {
t.Fatalf("the release judge was not built with the judge cache's Go cache:\n%s", said)
}
// **Clause 5**: the head was merged onto the release branch's head, which the verdict names as its trunk commit,
// so the release branch's move puts it out of date as a trunk's move does (ADR 0323 §4, the forge's holder).
if releaseHead := gitInRepo(t, catalogue, "rev-parse", releaseBranch); v.Trunk != releaseHead[:12] {
t.Fatalf("the verdict names trunk %q, not the release branch's head %s", v.Trunk, releaseHead[:12])
}
// **Built once per release-branch head**: a second check while that head stands takes the judge kept.
v = check("check-704-catalogue-again")
if !strings.HasSuffix(v.Gate.Summary, "the release branch's controller with the release branch's validator") {
t.Fatalf("the kept judge did not judge: %+v\n%s", v.Gate, v.Report)
}
if n := builds(t, built); n != 1 {
t.Fatalf("the judge of the same release-branch head was built again: %d builds", n)
}
}
func TestAControllerPullRequestIntoAReleaseBranchReadsTheNodeEngineAtThatBranch(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
registry := aFactsRegistry(t)
beside, _, hostRelease, _ := theReleasedMesh(t)
delete(beside, "mesh-controller")
controller, head := aPullRequestInto(t, aJudgeOf("the change's controller"), releaseBranch,
map[string]string{"cmd/x.txt": "x"})
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-704-controller", Repository: controller, Ref: head,
Owner: "novox", Repo: "mesh-controller", Number: 315, Base: releaseBranch, Release: releaseBranch,
JudgeCache: t.TempDir(), Paths: []string{"cmd/x.txt"}, Modules: []string{"mesh-controller"}, Judge: "self",
Beside: beside, Toolchain: "golang"}, t.TempDir(), registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || !strings.HasSuffix(v.Gate.Summary, "the change's controller with the vendored validator") {
t.Fatalf("a controller change into a release branch did not judge itself: %+v\n%s", v.Gate, v.Report)
}
if v.BesideAt["mesh-host"] != releaseBranch || v.Beside["mesh-host"] != hostRelease[:12] {
t.Fatalf("mesh-host was read beside it at %q (%s), not at the release branch's %s", v.BesideAt["mesh-host"],
v.Beside["mesh-host"], hostRelease[:12])
}
if v.Release != releaseBranch || v.JudgedBy == "" || v.JudgedBy != v.Merge[:12] {
t.Fatalf("the verdict names release %q judged by %q, not its own merge %s", v.Release, v.JudgedBy, v.Merge)
}
}
func TestAPullRequestIntoTheTrunkIsJudgedAsBefore(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
registry := aFactsRegistry(t)
controller, controllerMain, _ := aRepositoryWithARelease(t, aJudgeOf("main's controller"),
aJudgeOf("the release branch's controller"))
host, hostMain, _ := aRepositoryWithARelease(t, aHostSaying("main's validator"),
aHostSaying("the release branch's validator"))
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "true\n"}, "main", map[string]string{"modules/gitea/index.ts": "x"})
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-704-trunk", Repository: catalogue, Ref: head,
Owner: "novox", Repo: "mesh-catalog", Number: 1, Base: "main", JudgeCache: t.TempDir(),
Paths: []string{"modules/gitea/index.ts"}, Modules: []string{"gitea"}, Toolchain: "golang",
Beside: map[string]Beside{"mesh-controller": {Repository: controller, Ref: controllerMain},
"mesh-host": {Repository: host, Ref: hostMain}}}, t.TempDir(), registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || v.Gate.Summary != "main's controller with the vendored validator" {
t.Fatalf("a trunk pull request was not judged by the controller beside it as before: %+v\n%s", v.Gate, v.Report)
}
if v.Release != "" || v.JudgedBy != "" || v.BesideAt != nil || strings.Contains(v.Report, "release branch") {
t.Fatalf("a trunk pull request's verdict speaks of a release branch: %q %q %v", v.Release, v.JudgedBy, v.BesideAt)
}
if v.Beside["mesh-host"] != hostMain[:12] {
t.Fatalf("mesh-host was read at %s, not the commit asked %s", v.Beside["mesh-host"], hostMain[:12])
}
}
// **Without mesh-host's release branch, the release branch's controller keeps the validator it vendors** (ADR 0358
// §2), and the verdict says so.
func TestWithoutTheNodeEnginesReleaseBranchTheJudgeKeepsItsVendoredValidator(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
registry := aFactsRegistry(t)
beside, controllerRelease, _, _ := theReleasedMesh(t)
host, hostMain, _ := aRepositoryWithARelease(t, aHostSaying("main's validator"), nil)
beside["mesh-host"] = Beside{Repository: host, Ref: releaseBranch, Else: "main"}
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "true\n"}, releaseBranch, map[string]string{"modules/gitea/index.ts": "x"})
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-704-vendored", Repository: catalogue, Ref: head,
Owner: "novox", Repo: "mesh-catalog", Number: 286, Base: releaseBranch, Release: releaseBranch,
JudgeCache: t.TempDir(), Paths: []string{"modules/gitea/index.ts"}, Modules: []string{"gitea"}, Beside: beside,
Toolchain: "golang"}, t.TempDir(), registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || !strings.HasSuffix(v.Gate.Summary, "the release branch's controller with the vendored validator") {
t.Fatalf("without mesh-host's release branch the judge did not keep its vendored validator: %+v\n%s", v.Gate, v.Report)
}
if v.JudgedBy != controllerRelease[:12] || v.BesideAt["mesh-host"] != "main" || v.Beside["mesh-host"] != hostMain[:12] {
t.Fatalf("judged by %q, mesh-host read at %q (%s)", v.JudgedBy, v.BesideAt["mesh-host"], v.Beside["mesh-host"])
}
if !strings.Contains(v.Validator, "controller vendors") || !strings.Contains(v.Report, v.Validator) {
t.Fatalf("the verdict does not say the vendored validator judged: %q\n%s", v.Validator, v.Report)
}
}
// **Clause 7** (ADR 0358 §7): a release branch's own pull request into its trunk is checked as any pull request into a
// trunk — by the controller beside it as the mesh runs it, the repositories at what a trunk check reads — and its
// verdict names no release branch.
func TestAReleaseBranchsPullRequestIntoItsTrunkIsJudgedByTheControllerTheMeshRuns(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
registry := aFactsRegistry(t)
controller, controllerMain, _ := aRepositoryWithARelease(t, aJudgeOf("the controller the mesh runs"),
aJudgeOf("the release branch's controller"))
host, hostMain, _ := aRepositoryWithARelease(t, aHostSaying("main's validator"),
aHostSaying("the release branch's validator"))
catalogue, _, releaseHead := aRepositoryWithARelease(t, map[string]string{
"modules/gitea/module.json": `{"module":"gitea"}`, CheckScript: "true\n"},
map[string]string{"modules/gitea/index.ts": "released"})
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-704-release-into-trunk", Repository: catalogue,
Ref: releaseHead, Owner: "novox", Repo: "mesh-catalog", Number: 300, Base: "main", JudgeCache: t.TempDir(),
Paths: []string{"modules/gitea/index.ts"}, Modules: []string{"gitea"}, Toolchain: "golang",
Beside: map[string]Beside{"mesh-controller": {Repository: controller, Ref: controllerMain},
"mesh-host": {Repository: host, Ref: hostMain}}}, t.TempDir(), registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || v.Gate.Summary != "the controller the mesh runs with the vendored validator" {
t.Fatalf("the release branch's pull request into its trunk was not judged by the controller the mesh runs: %+v\n%s",
v.Gate, v.Report)
}
if v.Release != "" || v.JudgedBy != "" || v.BesideAt != nil || v.Validator != "" ||
strings.Contains(v.Report, "release branch") || strings.Contains(v.Gate.Summary, "[release") {
t.Fatalf("its verdict names a release branch: %q %q %v %q", v.Release, v.JudgedBy, v.BesideAt, v.Validator)
}
if v.Beside["mesh-host"] != hostMain[:12] || v.Beside["mesh-controller"] != controllerMain[:12] {
t.Fatalf("beside it were read %v, not the trunk's %s and %s", v.Beside, controllerMain[:12], hostMain[:12])
}
}
// **mesh-lab is read at its trunk, always** (ADR 0358): its replays run with the container runtime's socket, so a
// branch of the release's name in mesh-lab — which anyone may create — is never what a check reads.
func TestAReleaseBranchCheckReadsMeshLabAtItsTrunkEvenWhenItHasThatBranch(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
registry := aFactsRegistry(t)
beside, _, _, _ := theReleasedMesh(t)
lab, labMain, labRelease := aRepositoryWithARelease(t, map[string]string{"README": "the lab"},
map[string]string{"README": "a branch anyone could push"})
beside["mesh-lab"] = Beside{Repository: lab, Ref: releaseBranch, Else: "main"}
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "true\n"}, releaseBranch, map[string]string{"modules/gitea/index.ts": "x"})
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-704-lab", Repository: catalogue, Ref: head,
Owner: "novox", Repo: "mesh-catalog", Number: 286, Base: releaseBranch, Release: releaseBranch,
JudgeCache: t.TempDir(), Paths: []string{"modules/gitea/index.ts"}, Modules: []string{"gitea"}, Beside: beside,
Toolchain: "golang"}, t.TempDir(), registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.BesideAt["mesh-lab"] != "main" || v.Beside["mesh-lab"] != labMain[:12] || v.Beside["mesh-lab"] == labRelease[:12] {
t.Fatalf("mesh-lab was read at %q (%s), not its trunk main at %s", v.BesideAt["mesh-lab"], v.Beside["mesh-lab"],
labMain[:12])
}
}
// aPlantedWorkspace is a workspace a pull request's own script has written into, as it can: a git configuration in its
// HOME whose fsmonitor hook says each directory git runs in, a git configuration under XDG_CONFIG_HOME doing the same,
// and a Go environment file that would hand the judge's build a tool of its own. It answers the workspace and the
// file the hook writes to.
func aPlantedWorkspace(t *testing.T) (string, string) {
t.Helper()
workspace, logs := t.TempDir(), t.TempDir()
ran := filepath.Join(logs, "hook-ran")
hook := filepath.Join(workspace, "hook.sh")
files := map[string]string{
hook: "#!/bin/sh\necho \"$PWD\" >> " + ran + "\n",
filepath.Join(workspace, ".gitconfig"): "[core]\n\tfsmonitor = " + hook + "\n",
filepath.Join(workspace, ".config", "git", "config"): "[core]\n\tfsmonitor = " + hook + "\n",
filepath.Join(workspace, ".config", "go", "env"): "GOFLAGS=-toolexec=" + hook + "\n",
}
for name, body := range files {
if err := os.MkdirAll(filepath.Dir(name), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(name, []byte(body), 0o755); err != nil {
t.Fatal(err)
}
}
return workspace, ran
}
// judgeRanTheHook says whether the planted hook ran in a judge's tree: the controller beside the check, or the
// change's own when it judges itself.
func judgeRanTheHook(t *testing.T, ran string) string {
t.Helper()
body, _ := os.ReadFile(ran)
for _, line := range strings.Split(string(body), "\n") {
if strings.HasSuffix(line, "/check/mesh-controller") {
return string(body)
}
}
return ""
}
// **Every judge is built where no pull request reaches** (issue 482, ADR 0358 review): a git configuration with a
// hook, and a Go environment file, planted in the workspace by an earlier pull request's script, do not run during
// the release judge's build — while the pull request's own script, in the workspace, still meets them.
func TestAHookPlantedInTheWorkspaceDoesNotRunDuringTheReleaseJudgesBuild(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
homes := filepath.Join(t.TempDir(), "homes")
t.Setenv("JUDGE_HOMES", homes)
registry := aFactsRegistry(t)
workspace, ran := aPlantedWorkspace(t)
beside, _, _, _ := theReleasedMesh(t)
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "git status >/dev/null 2>&1; true\n"}, releaseBranch, map[string]string{"modules/gitea/index.ts": "x"})
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-704-planted", Repository: catalogue, Ref: head,
Owner: "novox", Repo: "mesh-catalog", Number: 286, Base: releaseBranch, Release: releaseBranch,
JudgeCache: t.TempDir(), Paths: []string{"modules/gitea/index.ts"}, Modules: []string{"gitea"}, Beside: beside,
Toolchain: "golang"}, workspace, registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || v.Gate.Verdict != "pass" {
t.Fatalf("the check did not judge: %+v\n%s", v.Gate, v.Report)
}
if body, _ := os.ReadFile(ran); !strings.Contains(string(body), "/check/mesh-catalog") {
t.Fatalf("the planted hook never ran, so this test proves nothing: %q", body)
}
if said := judgeRanTheHook(t, ran); said != "" {
t.Fatalf("the hook planted in the workspace ran during the judge's build:\n%s", said)
}
if body, _ := os.ReadFile(homes); len(body) == 0 || strings.Contains(string(body), workspace) {
t.Fatalf("the judge was built with a HOME in the workspace: %q", body)
}
}
// The same for the judge built with a node-engine change's own validator, into a release branch (ADR 0358 §2).
func TestAHookPlantedInTheWorkspaceDoesNotRunDuringTheValidatorJudgesBuild(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
homes := filepath.Join(t.TempDir(), "homes")
t.Setenv("JUDGE_HOMES", homes)
registry := aFactsRegistry(t)
workspace, ran := aPlantedWorkspace(t)
beside, _, _, _ := theReleasedMesh(t)
delete(beside, "mesh-host")
files := aHostSaying("the release branch's validator")
files["module.json"] = `{"module":"mesh-host"}`
files[CheckScript] = "git status >/dev/null 2>&1; true\n"
host, head := aPullRequestInto(t, files, releaseBranch, aHostSaying("this change's validator"))
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-704-planted-validator", Repository: host, Ref: head,
Owner: "novox", Repo: "mesh-host", Number: 111, Base: releaseBranch, Release: releaseBranch, Judge: "validator",
JudgeCache: t.TempDir(), Paths: []string{"validate/v.go"}, Modules: []string{"mesh-host"}, Beside: beside,
Toolchain: "golang"}, workspace, registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || !strings.HasSuffix(v.Gate.Summary, "the release branch's controller with this change's validator") {
t.Fatalf("a node-engine change into a release branch was not judged by that branch's controller with its own "+
"validator: %+v\n%s", v.Gate, v.Report)
}
if body, _ := os.ReadFile(ran); !strings.Contains(string(body), "/check/mesh-host") {
t.Fatalf("the planted hook never ran, so this test proves nothing: %q", body)
}
if said := judgeRanTheHook(t, ran); said != "" {
t.Fatalf("the hook planted in the workspace ran during a judge's build:\n%s", said)
}
if body, _ := os.ReadFile(homes); strings.Count(string(body), "\n") != 2 || strings.Contains(string(body), workspace) {
t.Fatalf("the judges were not both built with a HOME outside the workspace: %q", body)
}
}
// **mesh-lab is never read at a release branch**, asked with a fallback or without (ADR 0358).
func TestTheBuildSeatNeverReadsMeshLabAtAReleaseBranch(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
registry := aFactsRegistry(t)
lab, labMain, _ := aRepositoryWithARelease(t, map[string]string{"README": "the lab"},
map[string]string{"README": "a branch anyone could push"})
for _, asked := range []Beside{{Repository: lab, Ref: releaseBranch}, {Repository: lab, Ref: releaseBranch, Else: "main"}} {
beside, _, _, _ := theReleasedMesh(t)
beside["mesh-lab"] = asked
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "true\n"}, releaseBranch, map[string]string{"modules/gitea/index.ts": "x"})
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-704-lab-asked", Repository: catalogue, Ref: head,
Owner: "novox", Repo: "mesh-catalog", Number: 286, Base: releaseBranch, Release: releaseBranch,
JudgeCache: t.TempDir(), Paths: []string{"modules/gitea/index.ts"}, Modules: []string{"gitea"}, Beside: beside,
Toolchain: "golang"}, t.TempDir(), registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.BesideAt["mesh-lab"] != "main" || v.Beside["mesh-lab"] != labMain[:12] {
t.Fatalf("mesh-lab asked as %+v was read at %q (%s), not main at %s", asked, v.BesideAt["mesh-lab"],
v.Beside["mesh-lab"], labMain[:12])
}
}
}
// **Judges are built warm and where no pull request reaches** (ADR 0358 §6): every judge build uses the judge cache's
// one Go cache, kept between checks; its home is made fresh under the judge cache and removed after; nothing is left in
// a temporary directory of the host; and no container a check runs for the pull request mounts the judge cache.
func TestJudgesAreBuiltWarmFromAJudgeCacheNoCheckContainerMounts(t *testing.T) {
built := aRuntimeThatBuildsTheJudge(t)
// Not filled from the test's warm cache: what the first judge's build leaves in the judge cache is what is proved.
t.Setenv("WARM_GO_CACHE", "")
runs := filepath.Join(t.TempDir(), "runs")
t.Setenv("RUNS", runs)
tmp := t.TempDir()
t.Setenv("TMPDIR", tmp)
registry := aFactsRegistry(t)
cache := t.TempDir()
controller, controllerMain, _ := aRepositoryWithARelease(t, aJudgeOf("the controller the mesh runs"), nil)
beside := map[string]Beside{"mesh-controller": {Repository: controller, Ref: controllerMain}}
for i := range 2 {
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "true\n"}, "main", map[string]string{"modules/gitea/index.ts": fmt.Sprint(i)})
v, err := Check(t.Context(), Command, CheckSpec{ID: fmt.Sprintf("check-704-warm-%d", i), Repository: catalogue,
Ref: head, Owner: "novox", Repo: "mesh-catalog", Number: 1, Base: "main", JudgeCache: cache,
Paths: []string{"modules/gitea/index.ts"}, Modules: []string{"gitea"}, Toolchain: "golang", Beside: beside},
t.TempDir(), registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || v.Gate.Summary != "the controller the mesh runs with the vendored validator" {
t.Fatalf("check %d was not judged: %+v\n%s", i, v.Gate, v.Report)
}
if i == 0 {
if entries, _ := os.ReadDir(filepath.Join(cache, "go-cache")); len(entries) == 0 {
t.Fatal("the judge's build left nothing in the judge cache's Go cache to build the next judge warm")
}
}
}
// Both judges built with the one Go cache of the judge cache.
said, _ := os.ReadFile(built)
if n := strings.Count(string(said), "GOCACHE="+filepath.Join(cache, "go-cache")+" GOENV=off go build"); n != 2 {
t.Fatalf("%d of 2 judge builds used the judge cache's Go cache:\n%s", n, said)
}
// Nothing left behind: no home under the judge cache, nothing in the host's temporary directory.
if left, _ := os.ReadDir(filepath.Join(cache, "homes")); len(left) != 0 {
t.Fatalf("judge builds left %d home(s) under the judge cache", len(left))
}
if left, _ := os.ReadDir(tmp); len(left) != 0 {
t.Fatalf("a check left %d entr(ies) in the temporary directory, e.g. %s", len(left), left[0].Name())
}
// Only a judge build mounts the judge cache: no container the check runs for the pull request does.
body, _ := os.ReadFile(runs)
judgeBuilds := 0
for _, line := range strings.Split(strings.TrimSpace(string(body)), "\n") {
judging := strings.Contains(line, " go build ")
if judging {
judgeBuilds++
if !strings.Contains(line, "--volume "+filepath.Join(cache, "go-cache")+":") {
t.Fatalf("a judge build did not mount the judge cache's Go cache: %s", line)
}
continue
}
if strings.Contains(line, cache) {
t.Fatalf("a container the check runs for the pull request names the judge cache: %s", line)
}
}
if judgeBuilds != 2 {
t.Fatalf("%d judge builds were run, not 2", judgeBuilds)
}
}
// Without a judge cache, a judge is built cold under the check's own root — never in a temporary directory of the
// host — and a judge cache inside the workspace is refused.
func TestWithoutAJudgeCacheAJudgeIsBuiltColdUnderTheChecksRoot(t *testing.T) {
built := aRuntimeThatBuildsTheJudge(t)
tmp := t.TempDir()
t.Setenv("TMPDIR", tmp)
registry := aFactsRegistry(t)
controller, controllerMain, _ := aRepositoryWithARelease(t, aJudgeOf("the controller the mesh runs"), nil)
beside := map[string]Beside{"mesh-controller": {Repository: controller, Ref: controllerMain}}
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "true\n"}, "main", map[string]string{"modules/gitea/index.ts": "x"})
workspace := t.TempDir()
spec := CheckSpec{ID: "check-704-cold", Repository: catalogue, Ref: head, Owner: "novox", Repo: "mesh-catalog",
Number: 1, Base: "main", Paths: []string{"modules/gitea/index.ts"}, Modules: []string{"gitea"},
Toolchain: "golang", Beside: beside}
v, err := Check(t.Context(), Command, spec, workspace, registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || v.Gate.Verdict != "pass" {
t.Fatalf("the check was not judged: %+v\n%s", v.Gate, v.Report)
}
said, _ := os.ReadFile(built)
if !strings.Contains(string(said), "GOCACHE="+filepath.Join(workspace, "check", "judge-go-cache")+" GOENV=off go build") {
t.Fatalf("without a judge cache the judge was not built under the check's root:\n%s", said)
}
if left, _ := os.ReadDir(tmp); len(left) != 0 {
t.Fatalf("a check left %d entr(ies) in the temporary directory", len(left))
}
spec.JudgeCache = filepath.Join(workspace, "judge-cache")
if _, err := Check(t.Context(), Command, spec, workspace, registry, GitCredential{}, nil); err == nil ||
!strings.Contains(err.Error(), "inside the workspace") {
t.Fatalf("a judge cache inside the workspace was taken: %v", err)
}
}
// aLabWithReplays is mesh-lab with replays: a Go module of its own whose one test passes, needing nothing fetched.
func aLabWithReplays(t *testing.T) (string, string) {
t.Helper()
lab, labMain, _ := aRepositoryWithARelease(t, map[string]string{
"replays/go.mod": "module example.org/replays\n\ngo 1.22\n",
"replays/replay_test.go": "package replays\n\nimport \"testing\"\n\nfunc TestAReplay(t *testing.T) {}\n",
}, nil)
return lab, labMain
}
// **mesh-lab's replays run where no pull request reaches** (novox/hq issue 709, ADR 0358 §6): they hold the container
// runtime's socket, so a Go environment file with a -toolexec hook and a Go cache and module cache planted in the
// workspace by a pull request's script are neither run nor read — the replays run from a copy of mesh-lab outside
// the workspace with a fresh home and the judge cache's caches, all removed or kept outside every check container.
func TestTheReplaysRunWhereNoPullRequestReaches(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
replays := filepath.Join(t.TempDir(), "replays")
t.Setenv("REPLAYS", replays)
registry := aFactsRegistry(t)
workspace, ran := aPlantedWorkspace(t)
for _, poisoned := range []string{filepath.Join(workspace, "go-cache", "README"),
filepath.Join(workspace, "go-modules", "cache", "download", "planted")} {
if err := os.MkdirAll(filepath.Dir(poisoned), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(poisoned, []byte("planted by a pull request"), 0o644); err != nil {
t.Fatal(err)
}
}
cache := t.TempDir()
controller, controllerMain, _ := aRepositoryWithARelease(t, aJudgeOf("the controller the mesh runs"), nil)
lab, labMain := aLabWithReplays(t)
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "true\n"}, "main", map[string]string{"modules/gitea/index.ts": "x"})
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-709", Repository: catalogue, Ref: head, Owner: "novox",
Repo: "mesh-catalog", Number: 1, Base: "main", JudgeCache: cache, Paths: []string{"modules/gitea/index.ts"},
Modules: []string{"gitea"}, Toolchain: "golang", Beside: map[string]Beside{
"mesh-controller": {Repository: controller, Ref: controllerMain}, "mesh-lab": {Repository: lab, Ref: labMain}}},
workspace, registry, GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || v.Gate.Verdict != "pass" || !strings.Contains(v.Report, "--- the replays") {
t.Fatalf("the replays did not run and pass: %+v\n%s", v.Gate, v.Report)
}
body, _ := os.ReadFile(replays)
said := strings.TrimSpace(string(body))
if said == "" || strings.Count(said, "\n") != 0 {
t.Fatalf("the replays ran %q, not once", said)
}
for _, want := range []string{"GOCACHE=" + filepath.Join(cache, "go-cache") + " ",
"GOMODCACHE=" + filepath.Join(cache, "go-modules") + " ", "GOENV=off ", "GOFLAGS=-buildvcs=false ",
"HOME=" + filepath.Join(cache, "homes", "check-709-replays", "home") + " ",
"DIR=" + filepath.Join(cache, "homes", "check-709-replays", "mesh-lab", "replays")} {
if !strings.Contains(said, want) {
t.Fatalf("the replays did not run with %q: %s", want, said)
}
}
if strings.Contains(said, workspace) {
t.Fatalf("the replays ran with something of the workspace: %s", said)
}
if body, _ := os.ReadFile(ran); strings.Contains(string(body), "replays") || strings.Contains(string(body), "mesh-lab") {
t.Fatalf("a hook planted in the workspace ran during the replays:\n%s", body)
}
if left, _ := os.ReadDir(filepath.Join(cache, "homes")); len(left) != 0 {
t.Fatalf("the replays left %d entr(ies) under the judge cache's homes", len(left))
}
}
// aSelfJudgingControllerThatWritesIntoTheReplays is a controller pull request whose own judge, while the gate runs it,
// writes a test into the replays beside the check — the reviewer's case for issue 709: code of the pull request's,
// run before the replays, reaching what they run.
func aSelfJudgingControllerThatWritesIntoTheReplays(t *testing.T, marker string) (string, string) {
t.Helper()
files := aJudgeOf("the change's controller")
evil := "package replays\n\nimport (\n\t\"os\"\n\t\"testing\"\n)\n\nfunc TestEvil(t *testing.T) {\n\t_ = os.WriteFile(" +
fmt.Sprintf("%q", marker) + ", []byte(\"ran\"), 0o644)\n}\n"
files["cmd/mesh-controller/main.go"] = strings.Replace(files["cmd/mesh-controller/main.go"], "func main() {",
"func main() {\n\tif len(os.Args) > 2 && os.Args[1] == \"merge-gate\" {\n\t\t_ = os.WriteFile(os.Getenv(\"MESH_CHECK_BESIDE\")+"+
"\"/mesh-lab/replays/evil_test.go\", []byte("+fmt.Sprintf("%q", evil)+"), 0o644)\n\t\t_ = os.WriteFile("+
fmt.Sprintf("%q", marker+".wrote")+", nil, 0o644)\n\t}", 1)
return aPullRequestInto(t, files, "main", map[string]string{"cmd/x.txt": "x"})
}
// **The replays never read what a pull request wrote** (issue 709, reviews 12303 and 12308): with a judge cache they
// run from a copy under it, and a self-judging controller pull request writing a test into the replays beside the
// check, a planted GOFLAGS hook and a poisoned cache entry in the workspace neither run nor are read. Without one the
// replays are refused — the gate an error that says why, never a pass, never the workspace — they never start, and
// nothing is made on the host.
func TestTheReplaysNeverReadWhatAPullRequestWroteAndNeedAJudgeCache(t *testing.T) {
for _, withCache := range []bool{true, false} {
t.Run(fmt.Sprintf("judge cache %v", withCache), func(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
replays, volumes := filepath.Join(t.TempDir(), "replays"), filepath.Join(t.TempDir(), "volumes")
t.Setenv("REPLAYS", replays)
t.Setenv("VOLUMES", volumes)
tmp := t.TempDir()
t.Setenv("TMPDIR", tmp)
registry := aFactsRegistry(t)
workspace, ran := aPlantedWorkspace(t)
if err := os.MkdirAll(filepath.Join(workspace, "go-cache"), 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(workspace, "go-cache", "README"), []byte("planted"), 0o644); err != nil {
t.Fatal(err)
}
evilRan := filepath.Join(t.TempDir(), "evil-ran")
controller, head := aSelfJudgingControllerThatWritesIntoTheReplays(t, evilRan)
lab, labMain := aLabWithReplays(t)
cache := ""
if withCache {
cache = t.TempDir()
}
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-709-self", Repository: controller, Ref: head,
Owner: "novox", Repo: "mesh-controller", Number: 330, Base: "main", Judge: "self", JudgeCache: cache,
Paths: []string{"cmd/x.txt"}, Modules: []string{"mesh-controller"}, Toolchain: "golang",
Beside: map[string]Beside{"mesh-lab": {Repository: lab, Ref: labMain}}}, workspace, registry,
GitCredential{}, nil)
if err != nil {
t.Fatal(err)
}
if _, err := os.Stat(evilRan + ".wrote"); err != nil {
t.Fatalf("the self-judging pull request did not write into the replays beside it, so this proves nothing: %v", err)
}
if _, err := os.Stat(evilRan); err == nil {
t.Fatal("the test the pull request wrote into the replays ran with the socket")
}
if body, _ := os.ReadFile(ran); strings.Contains(string(body), "replays") || strings.Contains(string(body), "mesh-lab") {
t.Fatalf("a hook planted in the workspace ran during the replays:\n%s", body)
}
body, _ := os.ReadFile(replays)
said := strings.TrimSpace(string(body))
if vols, _ := os.ReadFile(volumes); len(vols) != 0 {
t.Fatalf("the check made a container volume: %q", vols)
}
if left, _ := os.ReadDir(tmp); len(left) != 0 {
t.Fatalf("a check left %d entr(ies) in the temporary directory", len(left))
}
if !withCache {
if v.Gate == nil || v.Gate.Verdict != "error" || !strings.Contains(v.Gate.Summary, replaysNeedTheJudgeCache) ||
v.Verdict != "error" {
t.Fatalf("without a judge cache the gate said %+v, not an error saying the replays need it", v.Gate)
}
if said != "" {
t.Fatalf("without a judge cache the replays started: %s", said)
}
return
}
if v.Gate == nil || v.Gate.Verdict != "pass" || !strings.Contains(v.Report, "--- the replays") {
t.Fatalf("the replays did not run and pass: %+v\n%s", v.Gate, v.Report)
}
base := filepath.Join(cache, "homes", "check-709-self-replays")
if said == "" || strings.Contains(said, workspace) || !strings.Contains(said, "GOENV=off ") ||
!strings.Contains(said, "DIR="+filepath.Join(base, "mesh-lab", "replays")) {
t.Fatalf("the replays did not run from the copy under %s, apart from the workspace: %q", base, said)
}
if _, err := os.Stat(base); err == nil {
t.Fatalf("the replays' place %s was left after the check", base)
}
})
}
}
// **Replays the container runtime could not start are the check's error, never the change's failure**, said in the
// build's log (review 12308); and a check whose id cannot name a place in the judge cache is refused, never given a
// shared one.
func TestReplaysThatCannotStartAreAnErrorAndAnUnsafeIDIsRefused(t *testing.T) {
aRuntimeThatBuildsTheJudge(t)
t.Setenv("REPLAYS_CANNOT_START", "1")
registry := aFactsRegistry(t)
controller, controllerMain, _ := aRepositoryWithARelease(t, aJudgeOf("the controller the mesh runs"), nil)
lab, labMain := aLabWithReplays(t)
catalogue, head := aPullRequestInto(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
CheckScript: "true\n"}, "main", map[string]string{"modules/gitea/index.ts": "x"})
spec := CheckSpec{ID: "check-709-start", Repository: catalogue, Ref: head, Owner: "novox", Repo: "mesh-catalog",
Number: 1, Base: "main", JudgeCache: t.TempDir(), Paths: []string{"modules/gitea/index.ts"},
Modules: []string{"gitea"}, Toolchain: "golang", Beside: map[string]Beside{
"mesh-controller": {Repository: controller, Ref: controllerMain}, "mesh-lab": {Repository: lab, Ref: labMain}}}
var logged []string
v, err := Check(t.Context(), Command, spec, t.TempDir(), registry, GitCredential{}, func(step, message string) {
logged = append(logged, message)
})
if err != nil {
t.Fatal(err)
}
if v.Gate == nil || v.Gate.Verdict != "error" || !strings.Contains(v.Gate.Summary, "could not be started") ||
!strings.Contains(v.Gate.Summary, "invalid mount config") {
t.Fatalf("replays that could not start were said %+v, not an error naming why", v.Gate)
}
if !strings.Contains(strings.Join(logged, "\n"), "the replays could not be started") {
t.Fatalf("the build's log does not say what failed:\n%s", strings.Join(logged, "\n"))
}
spec.ID = "Check 1/../../x"
if _, err := Check(t.Context(), Command, spec, t.TempDir(), registry, GitCredential{}, nil); err == nil ||
!strings.Contains(err.Error(), "cannot name its place in the judge cache") {
t.Fatalf("a check with an unsafe id was taken: %v", err)
}
}