400 lines
19 KiB
Go
400 lines
19 KiB
Go
//go:build integration
|
|
|
|
package builder
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestTheThrowawayStoreFlushesNothing(t *testing.T) {
|
|
said := strings.Join(StoreSettings, " ")
|
|
for _, want := range []string{"-c fsync=off", "-c synchronous_commit=off", "-c full_page_writes=off"} {
|
|
if !strings.Contains(said, want) {
|
|
t.Errorf("the store is raised with %q, not %q", said, want)
|
|
}
|
|
}
|
|
if os.Getenv("MESH_TEST_DOCKER") != "1" {
|
|
t.Skip("MESH_TEST_DOCKER=1: the settings are proven on a raised store")
|
|
}
|
|
id := fmt.Sprintf("check-store-%d", time.Now().UnixNano())
|
|
labelledRun := Labelled(Command, id)
|
|
t.Cleanup(func() { _, _ = RemoveContainersOf(context.Background(), Command, id) })
|
|
if _, err := throwaway(t.Context(), labelledRun, Command, id+"-store", StoreImage("17.11"), 5432,
|
|
[]string{"-e", "POSTGRES_PASSWORD=check"}, StoreSettings); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := waitFor(t.Context(), Command, id+"-store", []string{"pg_isready", "-U", "postgres"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for setting, want := range map[string]string{"fsync": "off", "synchronous_commit": "off", "full_page_writes": "off"} {
|
|
var got string
|
|
for try := 0; try < 10; try++ {
|
|
out, err := exec.Command("docker", "exec", id+"-store", "psql", "-U", "postgres", "-tAc", "SHOW "+setting).CombinedOutput()
|
|
if got = strings.TrimSpace(string(out)); err == nil {
|
|
break
|
|
}
|
|
time.Sleep(500 * time.Millisecond)
|
|
}
|
|
if got != want {
|
|
t.Errorf("%s is %q on the raised store", setting, got)
|
|
}
|
|
}
|
|
}
|
|
|
|
func aCheckedRepository(t *testing.T, files map[string]string) (string, string) {
|
|
t.Helper()
|
|
dir := t.TempDir()
|
|
git := func(args ...string) string {
|
|
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))
|
|
}
|
|
git("init", "--quiet", "-b", "main")
|
|
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)
|
|
}
|
|
}
|
|
git("add", "-A")
|
|
git("commit", "--quiet", "-m", "x")
|
|
return dir, git("rev-parse", "HEAD")
|
|
}
|
|
|
|
func labelled(id string) []string {
|
|
out, _ := exec.Command("docker", "ps", "-aq", "--filter", "label="+BuildLabel+"="+id).Output()
|
|
return strings.Fields(string(out))
|
|
}
|
|
|
|
func TestACheckRunsTheRepositorysOwnScriptBesideTheMeshsVersionsAndLeavesNothing(t *testing.T) {
|
|
registry := checkEnvironment(t)
|
|
// The script proves what it was given: the facts, a store that answers, a bus that answers — and no
|
|
// container runtime socket.
|
|
script := `set -e
|
|
test -s "$MESH_FACTS"
|
|
grep -q '"bus": "2.11.17"' "$MESH_FACTS" || grep -q '"bus":"2.11.17"' "$MESH_FACTS"
|
|
case "$MESH_TEST_POSTGRES" in postgres://*127.0.0.1:*) ;; *) echo "no store: $MESH_TEST_POSTGRES"; exit 1;; esac
|
|
case "$MESH_TEST_NATS" in nats://127.0.0.1:*) ;; *) echo "no bus: $MESH_TEST_NATS"; exit 1;; esac
|
|
test "$MESH_CHECK_REPOSITORY" = "novox/hq"
|
|
test "$MESH_CHECK_CHANGED" = "a.go,b.go"
|
|
test ! -S /var/run/docker.sock || { echo "the check holds the container runtime's socket"; exit 1; }
|
|
echo checked
|
|
`
|
|
repo, head := aCheckedRepository(t, map[string]string{CheckScript: script})
|
|
id := fmt.Sprintf("check-test-%d", time.Now().UnixNano())
|
|
v, err := Check(t.Context(), Command, CheckSpec{ID: id, Repository: repo, Ref: head, Owner: "novox",
|
|
Repo: "hq", Number: 7, Paths: []string{"a.go", "b.go"}, Toolchain: goToolchain}, t.TempDir(), registry, GitCredential{}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
// Nothing of the graph touched: the gate a pass that says so, the repository's own check run.
|
|
if v.Gate == nil || v.Gate.Verdict != "pass" || v.Gate.Summary != noModule {
|
|
t.Errorf("the gate answered %+v", v.Gate)
|
|
}
|
|
if v.Repo == nil || v.Repo.Verdict != "pass" || !strings.Contains(v.Report, "checked") {
|
|
t.Fatalf("the repository's check answered %+v\n%s", v.Repo, v.Report)
|
|
}
|
|
if left := labelled(id); len(left) > 0 {
|
|
t.Errorf("the check left %d container(s) behind", len(left))
|
|
}
|
|
}
|
|
|
|
func TestAFailingCheckFailsAndOneThatCannotRunIsNeverAPass(t *testing.T) {
|
|
registry := checkEnvironment(t)
|
|
repo, head := aCheckedRepository(t, map[string]string{CheckScript: "echo 'resource \"x.service\": refused'; exit 3\n"})
|
|
v, err := Check(t.Context(), Command, CheckSpec{ID: fmt.Sprintf("check-fail-%d", time.Now().UnixNano()),
|
|
Repository: repo, Ref: head, Owner: "novox", Repo: "hq", Toolchain: goToolchain}, t.TempDir(), registry, GitCredential{}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v.Repo == nil || v.Repo.Verdict != "fail" || !strings.Contains(v.Repo.Summary, "refused") {
|
|
t.Fatalf("a failing script answered %+v", v.Repo)
|
|
}
|
|
|
|
// A script in a toolchain the mesh does not hold: an error, never a pass.
|
|
repo, head = aCheckedRepository(t, map[string]string{CheckScript: "# mesh-check-toolchain: cobol\nexit 0\n"})
|
|
v, err = Check(t.Context(), Command, CheckSpec{ID: fmt.Sprintf("check-cobol-%d", time.Now().UnixNano()),
|
|
Repository: repo, Ref: head, Owner: "novox", Repo: "hq", Toolchain: goToolchain}, t.TempDir(), registry, GitCredential{}, nil)
|
|
if err != nil || v.Repo == nil || v.Repo.Verdict != "error" {
|
|
t.Fatalf("a script in a toolchain nobody holds answered %+v, %v", v.Repo, err)
|
|
}
|
|
|
|
// Past its bound: an error, not a pass.
|
|
was := CheckTimeout
|
|
CheckTimeout = 25 * time.Second
|
|
t.Cleanup(func() { CheckTimeout = was })
|
|
repo, head = aCheckedRepository(t, map[string]string{CheckScript: "sleep 120\n"})
|
|
v, err = Check(context.Background(), Command, CheckSpec{ID: fmt.Sprintf("check-slow-%d", time.Now().UnixNano()),
|
|
Repository: repo, Ref: head, Owner: "novox", Repo: "hq", Toolchain: goToolchain}, t.TempDir(), registry, GitCredential{}, nil)
|
|
if err == nil && (v.Repo == nil || v.Repo.Verdict != "error") {
|
|
t.Fatalf("a check past its bound answered %+v", v.Repo)
|
|
}
|
|
|
|
// No facts: it cannot run, and says so.
|
|
repo, head = aCheckedRepository(t, map[string]string{CheckScript: "exit 0\n"})
|
|
_, err = Check(t.Context(), Command, CheckSpec{ID: "check-nofacts", Repository: repo, Ref: head, Owner: "novox",
|
|
Repo: "hq", Toolchain: goToolchain}, t.TempDir(), "127.0.0.1:1", GitCredential{}, nil)
|
|
if err == nil || !strings.Contains(err.Error(), "facts snapshot") {
|
|
t.Fatalf("a check with no facts said %v", err)
|
|
}
|
|
}
|
|
|
|
func TestACheckWithNothingToRunSaysSo(t *testing.T) {
|
|
repo, head := aCheckedRepository(t, map[string]string{"README.md": "x"})
|
|
v, err := Check(t.Context(), Command, CheckSpec{ID: "check-nothing", Repository: repo, Ref: head, Owner: "novox",
|
|
Repo: "hq"}, t.TempDir(), "", GitCredential{}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v.Gate == nil || v.Gate.Verdict != "pass" || v.Repo == nil || v.Repo.Verdict != "warning" ||
|
|
!strings.Contains(v.Repo.Summary, CheckScript) {
|
|
t.Fatalf("a check with nothing to run said %+v / %+v", v.Gate, v.Repo)
|
|
}
|
|
// A gated change never takes that path: with no store to read the facts from, it cannot run.
|
|
_, err = Check(t.Context(), Command, CheckSpec{ID: "check-gated", Repository: repo, Ref: head, Owner: "novox",
|
|
Repo: "mesh-catalog", Modules: []string{"gitea"}}, t.TempDir(), "", GitCredential{}, nil)
|
|
if err == nil {
|
|
t.Fatal("a change touching a module ran nothing and was not refused")
|
|
}
|
|
}
|
|
|
|
func TestTheGateRunsWhenTheGraphIsTouchedBesideTheRepositorysOwnCheck(t *testing.T) {
|
|
registry := checkEnvironment(t)
|
|
judgeRepo, judgeHead := aCheckedRepository(t, aJudge)
|
|
beside := map[string]Beside{"mesh-controller": {Repository: judgeRepo, Ref: judgeHead}}
|
|
check := func(files map[string]string, judge string) CheckVerdict {
|
|
t.Helper()
|
|
repo, head := aCheckedRepository(t, files)
|
|
id := fmt.Sprintf("check-gate-%d", time.Now().UnixNano())
|
|
v, err := Check(t.Context(), Command, CheckSpec{ID: id, Repository: repo, Ref: head, Owner: "novox",
|
|
Repo: "mesh-catalog", Number: 9, Paths: []string{"modules/gitea/index.ts"}, Beside: beside,
|
|
Modules: []string{"gitea"}, Manifests: []string{"modules/gitea/module.json"}, Judge: judge,
|
|
Toolchain: goToolchain}, t.TempDir(), registry, GitCredential{}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if left := labelled(id); len(left) > 0 {
|
|
t.Errorf("the check left %d container(s) behind", len(left))
|
|
}
|
|
return v
|
|
}
|
|
v := check(map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`, CheckScript: "echo own; exit 0\n"}, "")
|
|
if v.Gate == nil || v.Gate.Verdict != "warning" || v.Gate.Summary != "a merge rebuilds 14 module(s)" ||
|
|
strings.Join(v.Gate.Modules, ",") != "gitea" || v.Verdict != "warning" {
|
|
t.Fatalf("the gate answered %+v\n%s", v.Gate, v.Report)
|
|
}
|
|
if v.Repo == nil || v.Repo.Verdict != "pass" {
|
|
t.Fatalf("its own check answered %+v", v.Repo)
|
|
}
|
|
|
|
v = check(map[string]string{"modules/gitea/module.json": `{"module":"gitea","broken":true}`}, "")
|
|
if v.Gate.Verdict != "fail" || !strings.Contains(v.Gate.Summary, "module check") || v.Repo.Verdict != "warning" {
|
|
t.Fatalf("a manifest the judge refuses answered %+v / %+v\n%s", v.Gate, v.Repo, v.Report)
|
|
}
|
|
|
|
// A fault the base branch already had is said and fails nothing; one the change brings fails.
|
|
repo, _ := aCheckedRepository(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea","broken":true}`})
|
|
git := func(args ...string) string {
|
|
cmd := exec.Command("git", args...)
|
|
cmd.Dir = repo
|
|
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))
|
|
}
|
|
git("checkout", "--quiet", "-b", "change")
|
|
if err := os.WriteFile(filepath.Join(repo, "modules/gitea/index.ts"), []byte("x"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
git("add", "-A")
|
|
git("commit", "--quiet", "-m", "y")
|
|
id := fmt.Sprintf("check-base-%d", time.Now().UnixNano())
|
|
v, err := Check(t.Context(), Command, CheckSpec{ID: id, Repository: repo, Ref: git("rev-parse", "HEAD"), Owner: "novox",
|
|
Repo: "mesh-catalog", Base: "main", Paths: []string{"modules/gitea/index.ts"}, Beside: beside,
|
|
Modules: []string{"gitea"}, Manifests: []string{"modules/gitea/module.json"}, Toolchain: goToolchain},
|
|
t.TempDir(), registry, GitCredential{}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v.Gate.Verdict != "warning" || !strings.Contains(v.Report, "already") {
|
|
t.Fatalf("a fault the base already had failed the change: %+v\n%s", v.Gate, v.Report)
|
|
}
|
|
|
|
// A delivery group (novox/hq ADR 0239): the other heads cloned beside it at their heads and handed to the
|
|
// gate to compose with this one; the repository's own check is each pull request's, not the group's.
|
|
app, appHead := aCheckedRepository(t, map[string]string{"module.json": `{"module":"app"}`})
|
|
repo2, head2 := aCheckedRepository(t, map[string]string{"modules/gitea/module.json": `{"module":"gitea"}`,
|
|
CheckScript: "exit 1\n"})
|
|
gid := fmt.Sprintf("check-group-%d", time.Now().UnixNano())
|
|
v, err = Check(t.Context(), Command, CheckSpec{ID: gid, Repository: repo2, Ref: head2, Owner: "novox",
|
|
Repo: "mesh-catalog", Paths: []string{"modules/gitea/module.json"}, Beside: beside, Modules: []string{"gitea"},
|
|
Manifests: []string{"modules/gitea/module.json"}, Toolchain: goToolchain,
|
|
Group: []GroupHead{{Owner: "novox", Repo: "app", Repository: app, Ref: appHead, Paths: []string{"module.json"}}}},
|
|
t.TempDir(), registry, GitCredential{}, nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if v.Gate.Verdict != "pass" || v.Gate.Summary != "composed with novox/app" {
|
|
t.Fatalf("the group's other head was not composed: %+v\n%s", v.Gate, v.Report)
|
|
}
|
|
if v.Repo == nil || v.Repo.Verdict != "pass" || !strings.Contains(v.Repo.Summary, "group") {
|
|
t.Fatalf("a group's check ran a member's own script: %+v", v.Repo)
|
|
}
|
|
|
|
// A change to the controller judges itself: one that does not build fails its own gate.
|
|
v = check(map[string]string{"go.mod": "module x\n\ngo 1.22\n", "cmd/mesh-controller/main.go": "package main\nfunc main() { nope }\n",
|
|
"modules/gitea/module.json": "{}"}, "self")
|
|
if v.Gate.Verdict != "fail" || !strings.Contains(v.Gate.Summary, "does not build") {
|
|
t.Fatalf("a controller that does not build judged itself %+v", v.Gate)
|
|
}
|
|
}
|
|
|
|
func TestABuildSaysWhetherItsCommitIsOnTheTrunk(t *testing.T) {
|
|
repo, onMain := aCheckedRepository(t, map[string]string{"module.json": `{"module":"x","version":"1"}`})
|
|
git := func(dir string, args ...string) string {
|
|
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))
|
|
}
|
|
git(repo, "checkout", "--quiet", "-b", "feature")
|
|
if err := os.WriteFile(filepath.Join(repo, "x"), []byte("x"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
git(repo, "add", "-A")
|
|
git(repo, "commit", "--quiet", "-m", "off the trunk")
|
|
offMain := git(repo, "rev-parse", "HEAD")
|
|
git(repo, "checkout", "--quiet", "main")
|
|
|
|
clone := filepath.Join(t.TempDir(), "clone")
|
|
git(filepath.Dir(clone), "clone", "--quiet", repo, clone)
|
|
if trunk, on := trunkOf(t.Context(), Command, clone, onMain); trunk != "main" || !on {
|
|
t.Errorf("a commit on main reads as on %q: %v", trunk, on)
|
|
}
|
|
if trunk, on := trunkOf(t.Context(), Command, clone, offMain); trunk != "main" || on {
|
|
t.Errorf("a feature branch's commit reads as on %q: %v", trunk, on)
|
|
}
|
|
if got := strings.Join(branchesHolding(t.Context(), Command, clone, offMain), ","); got != "feature" {
|
|
t.Errorf("the feature branch's commit is said to be on %q", got)
|
|
}
|
|
if got := strings.Join(branchesHolding(t.Context(), Command, clone, onMain), ","); got != "feature,main" {
|
|
t.Errorf("main's commit is said to be on %q", got)
|
|
}
|
|
// A tree that says no trunk is not known — never read as on it.
|
|
if trunk, on := trunkOf(t.Context(), Command, repo, onMain); trunk != "" || on {
|
|
t.Errorf("a repository with no origin reads as trunk %q, on %v", trunk, on)
|
|
}
|
|
}
|
|
|
|
func TestARedeliveredCheckRemovesWhatItsEarlierDeliveryLeft(t *testing.T) {
|
|
registry := checkEnvironment(t)
|
|
repo, head := aCheckedRepository(t, map[string]string{CheckScript: "echo checked\n"})
|
|
id := fmt.Sprintf("check-again-%d", time.Now().UnixNano())
|
|
if out, err := exec.Command("docker", "run", "-d", "--rm", "--label", BuildLabel+"="+id, "--name", id+"-store",
|
|
"postgres:17-alpine", "sleep", "300").CombinedOutput(); err != nil {
|
|
t.Skipf("no container for the earlier delivery: %v %s", err, out)
|
|
}
|
|
v, err := Check(t.Context(), Command, CheckSpec{ID: id, Repository: repo, Ref: head, Owner: "novox",
|
|
Repo: "hq", Number: 7, Toolchain: goToolchain}, t.TempDir(), registry, GitCredential{}, nil)
|
|
if err != nil {
|
|
t.Fatalf("a redelivered check could not run: %v", err)
|
|
}
|
|
if v.Repo == nil || v.Repo.Verdict != "pass" {
|
|
t.Errorf("the repository's check answered %+v", v.Repo)
|
|
}
|
|
if left := labelled(id); len(left) > 0 {
|
|
t.Errorf("the check left %d container(s) behind", len(left))
|
|
}
|
|
}
|
|
|
|
func TestARepositoryInTwoLanguagesIsCheckedInBoth(t *testing.T) {
|
|
script := "#!/bin/sh\n# mesh-check-toolchain: typescript\n# mesh-check-also: go replays/merge-check.sh\nnpm test\n"
|
|
parts := ScriptParts([]byte(script))
|
|
if len(parts) != 2 || parts[0] != (ScriptPart{"typescript", CheckScript}) ||
|
|
parts[1] != (ScriptPart{"go", "replays/merge-check.sh"}) {
|
|
t.Fatalf("the parts read as %+v", parts)
|
|
}
|
|
if got := ScriptParts([]byte("#!/bin/sh\nset -eu\n")); len(got) != 1 || got[0] != (ScriptPart{"go", CheckScript}) {
|
|
t.Fatalf("a script declaring nothing reads as %+v", got)
|
|
}
|
|
|
|
// Each part run where its toolchain is: here, the image the part was given is what the command says.
|
|
held := CheckSpec{Toolchain: "go-image", Toolchains: map[string]string{"typescript": "ts-image", "go": "go-image"}}
|
|
run := func(t *testing.T, spec CheckSpec, files map[string]string, parts []ScriptPart) (*Layer, []string) {
|
|
t.Helper()
|
|
tree := t.TempDir()
|
|
for name, body := range files {
|
|
if err := os.MkdirAll(filepath.Dir(filepath.Join(tree, name)), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(filepath.Join(tree, name), []byte(body), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
var images []string
|
|
var out tail
|
|
layer := ownCheck(t.Context(), spec, parts, tree, &out, func() bool { return false },
|
|
func(image, script string) *exec.Cmd {
|
|
images = append(images, image+" "+script)
|
|
cmd := exec.CommandContext(t.Context(), "sh", script)
|
|
cmd.Dir = tree
|
|
return cmd
|
|
}, func(string, string, ...any) {})
|
|
return layer, images
|
|
}
|
|
twoParts := []ScriptPart{{"typescript", CheckScript}, {"go", "replays/merge-check.sh"}}
|
|
|
|
layer, images := run(t, held, map[string]string{CheckScript: "exit 0\n", "replays/merge-check.sh": "exit 0\n"}, twoParts)
|
|
if layer.Verdict != "pass" || !strings.Contains(layer.Summary, "replays/merge-check.sh (go)") ||
|
|
strings.Join(images, ", ") != "ts-image merge-check.sh, go-image replays/merge-check.sh" {
|
|
t.Errorf("both parts passing answered %+v, ran %v", layer, images)
|
|
}
|
|
layer, _ = run(t, held, map[string]string{CheckScript: "exit 0\n",
|
|
"replays/merge-check.sh": "echo 'not gofmt'\"'\"'d:'; echo register.go; exit 1\n"}, twoParts)
|
|
if layer.Verdict != "fail" || !strings.Contains(layer.Summary, "replays/merge-check.sh failed") ||
|
|
!strings.Contains(layer.Summary, "register.go") || !strings.Contains(layer.Summary, "merge-check.sh (typescript) passed") {
|
|
t.Errorf("a failing Go part answered %+v", layer)
|
|
}
|
|
layer, images = run(t, held, map[string]string{CheckScript: "exit 2\n", "replays/merge-check.sh": "exit 0\n"}, twoParts)
|
|
if layer.Verdict != "fail" || len(images) != 1 {
|
|
t.Errorf("a failing first part answered %+v and ran %v", layer, images)
|
|
}
|
|
layer, _ = run(t, held, map[string]string{CheckScript: "exit 0\n"}, twoParts)
|
|
if layer.Verdict != "fail" || !strings.Contains(layer.Summary, "does not hold") {
|
|
t.Errorf("a declared part the repository lacks answered %+v", layer)
|
|
}
|
|
layer, _ = run(t, held, map[string]string{CheckScript: "exit 0\n"}, []ScriptPart{{"typescript", CheckScript},
|
|
{"go", "../elsewhere.sh"}})
|
|
if layer.Verdict != "fail" || !strings.Contains(layer.Summary, "not a path inside") {
|
|
t.Errorf("a part outside the repository answered %+v", layer)
|
|
}
|
|
layer, _ = run(t, CheckSpec{Toolchains: map[string]string{"typescript": "ts-image"}},
|
|
map[string]string{CheckScript: "exit 0\n", "replays/merge-check.sh": "exit 0\n"}, twoParts)
|
|
if layer.Verdict != "error" || !strings.Contains(layer.Summary, "go toolchain") {
|
|
t.Errorf("a part in a toolchain the mesh does not hold answered %+v — never a pass", layer)
|
|
}
|
|
}
|