package builder import ( "context" "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 rm -f 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) != 2 || !reflect.DeepEqual(ran[1], []string{"docker", "rm", "-f", "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) } }