| package build |
| |
| import ( |
| "archive/tar" |
| "bytes" |
| "context" |
| "encoding/json" |
| "io" |
| "strings" |
| "testing" |
| |
| "github.com/docker/docker/api/types" |
| "github.com/docker/docker/api/types/filters" |
| "github.com/docker/docker/integration/util/request" |
| "github.com/docker/docker/pkg/jsonmessage" |
| "github.com/stretchr/testify/require" |
| ) |
| |
| func TestBuildWithRemoveAndForceRemove(t *testing.T) { |
| defer setupTest(t)() |
| t.Parallel() |
| cases := []struct { |
| name string |
| dockerfile string |
| numberOfIntermediateContainers int |
| rm bool |
| forceRm bool |
| }{ |
| { |
| name: "successful build with no removal", |
| dockerfile: `FROM busybox |
| RUN exit 0 |
| RUN exit 0`, |
| numberOfIntermediateContainers: 2, |
| rm: false, |
| forceRm: false, |
| }, |
| { |
| name: "successful build with remove", |
| dockerfile: `FROM busybox |
| RUN exit 0 |
| RUN exit 0`, |
| numberOfIntermediateContainers: 0, |
| rm: true, |
| forceRm: false, |
| }, |
| { |
| name: "successful build with remove and force remove", |
| dockerfile: `FROM busybox |
| RUN exit 0 |
| RUN exit 0`, |
| numberOfIntermediateContainers: 0, |
| rm: true, |
| forceRm: true, |
| }, |
| { |
| name: "failed build with no removal", |
| dockerfile: `FROM busybox |
| RUN exit 0 |
| RUN exit 1`, |
| numberOfIntermediateContainers: 2, |
| rm: false, |
| forceRm: false, |
| }, |
| { |
| name: "failed build with remove", |
| dockerfile: `FROM busybox |
| RUN exit 0 |
| RUN exit 1`, |
| numberOfIntermediateContainers: 1, |
| rm: true, |
| forceRm: false, |
| }, |
| { |
| name: "failed build with remove and force remove", |
| dockerfile: `FROM busybox |
| RUN exit 0 |
| RUN exit 1`, |
| numberOfIntermediateContainers: 0, |
| rm: true, |
| forceRm: true, |
| }, |
| } |
| |
| client := request.NewAPIClient(t) |
| ctx := context.Background() |
| for _, c := range cases { |
| t.Run(c.name, func(t *testing.T) { |
| t.Parallel() |
| dockerfile := []byte(c.dockerfile) |
| |
| buff := bytes.NewBuffer(nil) |
| tw := tar.NewWriter(buff) |
| require.NoError(t, tw.WriteHeader(&tar.Header{ |
| Name: "Dockerfile", |
| Size: int64(len(dockerfile)), |
| })) |
| _, err := tw.Write(dockerfile) |
| require.NoError(t, err) |
| require.NoError(t, tw.Close()) |
| resp, err := client.ImageBuild(ctx, buff, types.ImageBuildOptions{Remove: c.rm, ForceRemove: c.forceRm, NoCache: true}) |
| require.NoError(t, err) |
| defer resp.Body.Close() |
| filter, err := buildContainerIdsFilter(resp.Body) |
| require.NoError(t, err) |
| remainingContainers, err := client.ContainerList(ctx, types.ContainerListOptions{Filters: filter, All: true}) |
| require.NoError(t, err) |
| require.Equal(t, c.numberOfIntermediateContainers, len(remainingContainers), "Expected %v remaining intermediate containers, got %v", c.numberOfIntermediateContainers, len(remainingContainers)) |
| }) |
| } |
| } |
| |
| func buildContainerIdsFilter(buildOutput io.Reader) (filters.Args, error) { |
| const intermediateContainerPrefix = " ---> Running in " |
| filter := filters.NewArgs() |
| |
| dec := json.NewDecoder(buildOutput) |
| for { |
| m := jsonmessage.JSONMessage{} |
| err := dec.Decode(&m) |
| if err == io.EOF { |
| return filter, nil |
| } |
| if err != nil { |
| return filter, err |
| } |
| if ix := strings.Index(m.Stream, intermediateContainerPrefix); ix != -1 { |
| filter.Add("id", strings.TrimSpace(m.Stream[ix+len(intermediateContainerPrefix):])) |
| } |
| } |
| } |