mesh/merge-gate building on ace since 00:57
mesh/delivery superseded: a newer head of the same pull request
mesh/check failed: integration: github.com/novox/mesh-controller/internal/identity.TestACertificateChainsToTheMeshsOwnAuthority: authority_test.go:45:…
167 lines
6.5 KiB
Go
167 lines
6.5 KiB
Go
package builder
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"reflect"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// A build killed by hand (novox/hq ADR 0219) ends every command it started: the context's end kills
|
|
// the command's whole process group, not the one process the context knows about.
|
|
|
|
// Every `docker run` a build starts carries its id as a label; nothing else is touched.
|
|
func TestEveryContainerABuildStartsCarriesItsID(t *testing.T) {
|
|
got := LabelledArgs("docker", []string{"run", "--rm", "img", "sh"}, "build-1")
|
|
if want := []string{"run", "--label", "mesh.build=build-1", "--rm", "img", "sh"}; !reflect.DeepEqual(got, want) {
|
|
t.Errorf("docker run became %v", got)
|
|
}
|
|
for _, c := range []struct {
|
|
name string
|
|
args []string
|
|
}{{"docker", []string{"build", "."}}, {"git", []string{"run"}}, {"docker", nil}} {
|
|
if got := LabelledArgs(c.name, c.args, "build-1"); !reflect.DeepEqual(got, c.args) {
|
|
t.Errorf("%s %v became %v", c.name, c.args, got)
|
|
}
|
|
}
|
|
var ran [][]string
|
|
run := Labelled(func(_ context.Context, _ string, name string, args ...string) (string, error) {
|
|
ran = append(ran, append([]string{name}, args...))
|
|
return "", nil
|
|
}, "build-2")
|
|
_, _ = run(context.Background(), "", "docker", "run", "img")
|
|
if want := [][]string{{"docker", "run", "--label", "mesh.build=build-2", "img"}}; !reflect.DeepEqual(ran, want) {
|
|
t.Errorf("ran %v", ran)
|
|
}
|
|
}
|
|
|
|
// What a kill removes is found by the label, and only what it finds.
|
|
func TestAKillRemovesTheContainersLabelledWithTheBuild(t *testing.T) {
|
|
var ran []string
|
|
run := func(_ context.Context, _ string, name string, args ...string) (string, error) {
|
|
ran = append(ran, name+" "+strings.Join(args, " "))
|
|
if args[0] == "ps" {
|
|
return "c1\nc2\n", nil
|
|
}
|
|
return "", nil
|
|
}
|
|
n, err := RemoveContainersOf(context.Background(), run, "build-3")
|
|
if err != nil || n != 2 {
|
|
t.Fatalf("%d %v", n, err)
|
|
}
|
|
if want := []string{"docker ps -aq --filter label=mesh.build=build-3", "docker inspect --format " + MountedVolumes + " c1 c2",
|
|
"docker rm -f -v c1 c2"}; !reflect.DeepEqual(ran, want) {
|
|
t.Errorf("ran %v", ran)
|
|
}
|
|
}
|
|
|
|
// **Issue 306**: a holder starting removes what earlier holders on its machine left — every container
|
|
// labelled with an ask of the seat — and nothing labelled otherwise.
|
|
func TestAStartingHolderRemovesWhatEarlierHoldersLeftAndNothingElse(t *testing.T) {
|
|
var ran [][]string
|
|
run := func(_ context.Context, _ string, name string, args ...string) (string, error) {
|
|
ran = append(ran, append([]string{name}, args...))
|
|
if args[0] == "ps" {
|
|
return "c1 build-1791418000320743455\nc2 build-1791418000320743455\n" +
|
|
"c3 check-here-1791418000320743455\nc4 check-test-17\nc5 build-x\nc6 build-\n\nc7 build-1791319895953076871\n", nil
|
|
}
|
|
return "", nil
|
|
}
|
|
n, err := RemoveLeftBehind(context.Background(), run)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if n != 3 {
|
|
t.Errorf("removed %d", n)
|
|
}
|
|
if len(ran) != 3 || !reflect.DeepEqual(ran[2], []string{"docker", "rm", "-f", "-v", "c1", "c2", "c7"}) {
|
|
t.Fatalf("ran %v", ran)
|
|
}
|
|
if !strings.Contains(strings.Join(ran[0], " "), "--filter label=mesh.build") {
|
|
t.Errorf("listed with %v", ran[0])
|
|
}
|
|
|
|
// Nothing left behind: nothing removed, and no rm asked.
|
|
ran = nil
|
|
quiet := func(_ context.Context, _ string, name string, args ...string) (string, error) {
|
|
ran = append(ran, append([]string{name}, args...))
|
|
return "c3 check-here-1\n", nil
|
|
}
|
|
if n, err := RemoveLeftBehind(context.Background(), quiet); err != nil || n != 0 || len(ran) != 1 {
|
|
t.Errorf("with nothing of the seat's: %d %v %v", n, err, ran)
|
|
}
|
|
}
|
|
|
|
// **Issue 1772**: a throwaway store declares its data directory a VOLUME, so docker makes an anonymous volume for
|
|
// it, and `docker rm -f` without -v leaves that volume behind (1,629 of them, 107 GB, on one build node). Every
|
|
// container a build or check removes is removed with its anonymous volumes (-v), and any volume the container
|
|
// mounted that is still there afterwards is removed by name — those, and only those, never a named volume.
|
|
func TestARemovedContainerTakesItsAnonymousVolumesWithIt(t *testing.T) {
|
|
anon := strings.Repeat("a", 64)
|
|
other := strings.Repeat("b", 64)
|
|
var ran []string
|
|
run := func(_ context.Context, _ string, name string, args ...string) (string, error) {
|
|
ran = append(ran, name+" "+strings.Join(args, " "))
|
|
switch args[0] {
|
|
case "ps":
|
|
return "c1\n", nil
|
|
case "inspect":
|
|
return anon + "\n" + "compose_data\n" + other + "\n", nil
|
|
}
|
|
return "", nil
|
|
}
|
|
if n, err := RemoveContainersOf(context.Background(), run, "build-4"); err != nil || n != 1 {
|
|
t.Fatalf("%d %v", n, err)
|
|
}
|
|
last := ran[len(ran)-1]
|
|
if want := "docker volume rm " + anon + " " + other; last != want {
|
|
t.Errorf("last command %q, want %q", last, want)
|
|
}
|
|
if !strings.Contains(strings.Join(ran, "\n"), "docker rm -f -v c1") {
|
|
t.Errorf("ran %v", ran)
|
|
}
|
|
if strings.Contains(last, "compose_data") {
|
|
t.Errorf("a named volume was removed: %q", last)
|
|
}
|
|
}
|
|
|
|
// A volume already gone when the sweep looks (rm -v took it) is no failure.
|
|
func TestAVolumeAlreadyGoneIsNoFailure(t *testing.T) {
|
|
run := func(_ context.Context, _ string, name string, args ...string) (string, error) {
|
|
switch args[0] {
|
|
case "ps":
|
|
return "c1\n", nil
|
|
case "inspect":
|
|
return strings.Repeat("c", 64) + "\n", nil
|
|
case "volume":
|
|
return "", errors.New("no such volume")
|
|
}
|
|
return "", nil
|
|
}
|
|
if n, err := RemoveContainersOf(context.Background(), run, "build-5"); err != nil || n != 1 {
|
|
t.Fatalf("%d %v", n, err)
|
|
}
|
|
}
|
|
|
|
// A node's build slice limits everything a build or check starts (novox/hq issue 1798): with a parent
|
|
// set, every `docker run` joins it, so the node's CPU and IO weights and memory cap bind the container;
|
|
// with none set the arguments are as they always were.
|
|
func TestEveryContainerJoinsTheNodesBuildSlice(t *testing.T) {
|
|
was := CgroupParent
|
|
defer func() { CgroupParent = was }()
|
|
CgroupParent = "meshbuild.slice"
|
|
got := LabelledArgs("docker", []string{"run", "--rm", "img", "sh"}, "build-1")
|
|
want := []string{"run", "--label", "mesh.build=build-1", "--cgroup-parent", "meshbuild.slice", "--rm", "img", "sh"}
|
|
if !reflect.DeepEqual(got, want) {
|
|
t.Errorf("1798/AC1: docker run became %v", got)
|
|
}
|
|
if got := LabelledArgs("docker", []string{"build", "."}, "build-1"); !reflect.DeepEqual(got, []string{"build", "."}) {
|
|
t.Errorf("a docker build became %v", got)
|
|
}
|
|
CgroupParent = ""
|
|
if got := LabelledArgs("docker", []string{"run", "img"}, "build-1"); !reflect.DeepEqual(got, []string{"run", "--label", "mesh.build=build-1", "img"}) {
|
|
t.Errorf("1798/AC1: with no slice, docker run became %v", got)
|
|
}
|
|
}
|