integration-cli/docker_cli_build_test.go
6db32fde
 package main
 
 import (
24c00c85
 	"archive/tar"
29be7b43
 	"bytes"
4e74cd49
 	"encoding/json"
6db32fde
 	"fmt"
24c00c85
 	"io/ioutil"
f5b1afae
 	"os"
6db32fde
 	"os/exec"
 	"path/filepath"
fa753e67
 	"reflect"
1150c163
 	"regexp"
d0dc14e5
 	"runtime"
29be7b43
 	"strconv"
f5b1afae
 	"strings"
29be7b43
 	"text/template"
1ce5457d
 	"time"
edcb4145
 
f41230b9
 	"github.com/docker/docker/builder/dockerfile/command"
30d5a42c
 	"github.com/docker/docker/pkg/archive"
47da59f7
 	"github.com/docker/docker/pkg/integration/checker"
b80fae73
 	"github.com/docker/docker/pkg/stringutils"
dc944ea7
 	"github.com/go-check/check"
6db32fde
 )
 
dc944ea7
 func (s *DockerSuite) TestBuildJSONEmptyRun(c *check.C) {
39343b86
 	name := "testbuildjsonemptyrun"
 
 	_, err := buildImage(
 		name,
 		`
     FROM busybox
     RUN []
     `,
 		true)
 
 	if err != nil {
dc944ea7
 		c.Fatal("error when dealing with a RUN statement with empty JSON array")
39343b86
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildShCmdJSONEntrypoint(c *check.C) {
24545c18
 	name := "testbuildshcmdjsonentrypoint"
 
 	_, err := buildImage(
 		name,
 		`
     FROM busybox
563a4d1b
     ENTRYPOINT ["echo"]
24545c18
     CMD echo test
     `,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
24545c18
 	}
 
5c295460
 	out, _ := dockerCmd(c, "run", "--rm", name)
24545c18
 
563a4d1b
 	if daemonPlatform == "windows" {
 		if !strings.Contains(out, "cmd /S /C echo test") {
 			c.Fatalf("CMD did not contain cmd /S /C echo test : %q", out)
 		}
 	} else {
 		if strings.TrimSpace(out) != "/bin/sh -c echo test" {
 			c.Fatalf("CMD did not contain /bin/sh -c : %q", out)
 		}
24545c18
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementUser(c *check.C) {
563a4d1b
 	// Windows does not support FROM scratch or the USER command
f9a3558a
 	testRequires(c, DaemonIsLinux)
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
 	_, err := buildImage(name, `
   FROM scratch
   ENV user foo
   USER ${user}
   `, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.User")
4e74cd49
 
 	if res != `"foo"` {
dc944ea7
 		c.Fatal("User foo from environment not in Config.User on image")
4e74cd49
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementVolume(c *check.C) {
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
96c52216
 	var volumePath string
563a4d1b
 
 	if daemonPlatform == "windows" {
 		volumePath = "c:/quux"
 	} else {
 		volumePath = "/quux"
 	}
 
4e74cd49
 	_, err := buildImage(name, `
96c52216
   FROM `+minimalBaseImage()+`
563a4d1b
   ENV volume `+volumePath+`
4e74cd49
   VOLUME ${volume}
   `, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Volumes")
4e74cd49
 
 	var volumes map[string]interface{}
 
 	if err := json.Unmarshal([]byte(res), &volumes); err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
 
563a4d1b
 	if _, ok := volumes[volumePath]; !ok {
 		c.Fatal("Volume " + volumePath + " from environment not in Config.Volumes on image")
4e74cd49
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementExpose(c *check.C) {
563a4d1b
 	// Windows does not support FROM scratch or the EXPOSE command
f9a3558a
 	testRequires(c, DaemonIsLinux)
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
 	_, err := buildImage(name, `
   FROM scratch
   ENV port 80
   EXPOSE ${port}
6990f8c6
   ENV ports "  99   100 "
   EXPOSE ${ports}
4e74cd49
   `, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.ExposedPorts")
4e74cd49
 
 	var exposedPorts map[string]interface{}
 
 	if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
 
6990f8c6
 	exp := []int{80, 99, 100}
 
 	for _, p := range exp {
 		tmp := fmt.Sprintf("%d/tcp", p)
 		if _, ok := exposedPorts[tmp]; !ok {
 			c.Fatalf("Exposed port %d from environment not in Config.ExposedPorts on image", p)
 		}
4e74cd49
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementWorkdir(c *check.C) {
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
 	_, err := buildImage(name, `
   FROM busybox
   ENV MYWORKDIR /work
   RUN mkdir ${MYWORKDIR}
   WORKDIR ${MYWORKDIR}
   `, true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementAddCopy(c *check.C) {
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
 	ctx, err := fakeContext(`
96c52216
   FROM `+minimalBaseImage()+`
4e74cd49
   ENV baz foo
   ENV quux bar
   ENV dot .
39908fc6
   ENV fee fff
   ENV gee ggg
4e74cd49
 
   ADD ${baz} ${dot}
   COPY ${quux} ${dot}
39908fc6
   ADD ${zzz:-${fee}} ${dot}
   COPY ${zzz:-${gee}} ${dot}
4e74cd49
   `,
 		map[string]string{
 			"foo": "test1",
 			"bar": "test2",
39908fc6
 			"fff": "test3",
 			"ggg": "test4",
4e74cd49
 		})
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
db7fded1
 	defer ctx.Close()
4e74cd49
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvironmentReplacementEnv(c *check.C) {
563a4d1b
 	// ENV expansions work differently in Windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
4e74cd49
 	name := "testbuildenvironmentreplacement"
 
 	_, err := buildImage(name,
 		`
6d66e3e7
   FROM busybox
   ENV foo zzz
4e74cd49
   ENV bar ${foo}
6d66e3e7
   ENV abc1='$foo'
   ENV env1=$foo env2=${foo} env3="$foo" env4="${foo}"
   RUN [ "$abc1" = '$foo' ] && (echo "$abc1" | grep -q foo)
   ENV abc2="\$foo"
   RUN [ "$abc2" = '$foo' ] && (echo "$abc2" | grep -q foo)
   ENV abc3 '$foo'
   RUN [ "$abc3" = '$foo' ] && (echo "$abc3" | grep -q foo)
   ENV abc4 "\$foo"
   RUN [ "$abc4" = '$foo' ] && (echo "$abc4" | grep -q foo)
4e74cd49
   `, true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Env")
4e74cd49
 
 	envResult := []string{}
 
 	if err = unmarshalJSON([]byte(res), &envResult); err != nil {
dc944ea7
 		c.Fatal(err)
4e74cd49
 	}
 
 	found := false
6d66e3e7
 	envCount := 0
4e74cd49
 
 	for _, env := range envResult {
 		parts := strings.SplitN(env, "=", 2)
 		if parts[0] == "bar" {
 			found = true
6d66e3e7
 			if parts[1] != "zzz" {
dc944ea7
 				c.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1])
6d66e3e7
 			}
 		} else if strings.HasPrefix(parts[0], "env") {
 			envCount++
 			if parts[1] != "zzz" {
dc944ea7
 				c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
4e74cd49
 			}
39908fc6
 		} else if strings.HasPrefix(parts[0], "env") {
 			envCount++
 			if parts[1] != "foo" {
dc944ea7
 				c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
39908fc6
 			}
4e74cd49
 		}
 	}
 
 	if !found {
dc944ea7
 		c.Fatal("Never found the `bar` env variable")
4e74cd49
 	}
 
6d66e3e7
 	if envCount != 4 {
dc944ea7
 		c.Fatalf("Didn't find all env vars - only saw %d\n%s", envCount, envResult)
6d66e3e7
 	}
 
4e74cd49
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildHandleEscapes(c *check.C) {
563a4d1b
 	// The volume paths used in this test are invalid on Windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
be49867c
 	name := "testbuildhandleescapes"
 
 	_, err := buildImage(name,
 		`
   FROM scratch
   ENV FOO bar
   VOLUME ${FOO}
   `, true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
be49867c
 	}
 
 	var result map[string]map[string]struct{}
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Volumes")
be49867c
 
 	if err = unmarshalJSON([]byte(res), &result); err != nil {
dc944ea7
 		c.Fatal(err)
be49867c
 	}
 
 	if _, ok := result["bar"]; !ok {
dc944ea7
 		c.Fatal("Could not find volume bar set from env foo in volumes table")
be49867c
 	}
 
da3d3b97
 	deleteImages(name)
 
be49867c
 	_, err = buildImage(name,
 		`
   FROM scratch
   ENV FOO bar
   VOLUME \${FOO}
   `, true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
be49867c
 	}
 
62a856e9
 	res = inspectFieldJSON(c, name, "Config.Volumes")
be49867c
 
 	if err = unmarshalJSON([]byte(res), &result); err != nil {
dc944ea7
 		c.Fatal(err)
be49867c
 	}
 
 	if _, ok := result["${FOO}"]; !ok {
dc944ea7
 		c.Fatal("Could not find volume ${FOO} set from env foo in volumes table")
be49867c
 	}
 
da3d3b97
 	deleteImages(name)
 
be49867c
 	// this test in particular provides *7* backslashes and expects 6 to come back.
 	// Like above, the first escape is swallowed and the rest are treated as
 	// literals, this one is just less obvious because of all the character noise.
 
 	_, err = buildImage(name,
 		`
   FROM scratch
   ENV FOO bar
   VOLUME \\\\\\\${FOO}
   `, true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
be49867c
 	}
 
62a856e9
 	res = inspectFieldJSON(c, name, "Config.Volumes")
be49867c
 
 	if err = unmarshalJSON([]byte(res), &result); err != nil {
dc944ea7
 		c.Fatal(err)
be49867c
 	}
 
6d66e3e7
 	if _, ok := result[`\\\${FOO}`]; !ok {
dc944ea7
 		c.Fatal(`Could not find volume \\\${FOO} set from env foo in volumes table`, result)
be49867c
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildLowercase(c *check.C) {
a34831f0
 	name := "testbuildonbuildlowercase"
 	name2 := "testbuildonbuildlowercase2"
 
 	_, err := buildImage(name,
 		`
   FROM busybox
   onbuild run echo quux
   `, true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
a34831f0
 	}
 
 	_, out, err := buildImageWithOut(name2, fmt.Sprintf(`
   FROM %s
   `, name), true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
a34831f0
 	}
 
 	if !strings.Contains(out, "quux") {
dc944ea7
 		c.Fatalf("Did not receive the expected echo text, got %s", out)
a34831f0
 	}
 
 	if strings.Contains(out, "ONBUILD ONBUILD") {
dc944ea7
 		c.Fatalf("Got an ONBUILD ONBUILD error with no error: got %s", out)
a34831f0
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvEscapes(c *check.C) {
563a4d1b
 	// ENV expansions work differently in Windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
df0e0c76
 	name := "testbuildenvescapes"
 	_, err := buildImage(name,
 		`
     FROM busybox
     ENV TEST foo
     CMD echo \$
     `,
 		true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
df0e0c76
 	}
 
5c295460
 	out, _ := dockerCmd(c, "run", "-t", name)
 
df0e0c76
 	if strings.TrimSpace(out) != "$" {
dc944ea7
 		c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
df0e0c76
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvOverwrite(c *check.C) {
563a4d1b
 	// ENV expansions work differently in Windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
df0e0c76
 	name := "testbuildenvoverwrite"
 
 	_, err := buildImage(name,
 		`
     FROM busybox
     ENV TEST foo
4e74cd49
     CMD echo ${TEST}
df0e0c76
     `,
 		true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
df0e0c76
 	}
 
5c295460
 	out, _ := dockerCmd(c, "run", "-e", "TEST=bar", "-t", name)
df0e0c76
 
 	if strings.TrimSpace(out) != "bar" {
dc944ea7
 		c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
df0e0c76
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildForbiddenMaintainerInSourceImage(c *check.C) {
1150c163
 	name := "testbuildonbuildforbiddenmaintainerinsourceimage"
da3d3b97
 
5c295460
 	out, _ := dockerCmd(c, "create", "busybox", "true")
1150c163
 
475c6531
 	cleanedContainerID := strings.TrimSpace(out)
1150c163
 
5c295460
 	dockerCmd(c, "commit", "--run", "{\"OnBuild\":[\"MAINTAINER docker.io\"]}", cleanedContainerID, "onbuild")
1150c163
 
5c295460
 	_, err := buildImage(name,
1150c163
 		`FROM onbuild`,
 		true)
 	if err != nil {
 		if !strings.Contains(err.Error(), "maintainer isn't allowed as an ONBUILD trigger") {
dc944ea7
 			c.Fatalf("Wrong error %v, must be about MAINTAINER and ONBUILD in source image", err)
1150c163
 		}
 	} else {
dc944ea7
 		c.Fatal("Error must not be nil")
1150c163
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildForbiddenFromInSourceImage(c *check.C) {
1150c163
 	name := "testbuildonbuildforbiddenfrominsourceimage"
da3d3b97
 
5c295460
 	out, _ := dockerCmd(c, "create", "busybox", "true")
1150c163
 
475c6531
 	cleanedContainerID := strings.TrimSpace(out)
1150c163
 
5c295460
 	dockerCmd(c, "commit", "--run", "{\"OnBuild\":[\"FROM busybox\"]}", cleanedContainerID, "onbuild")
1150c163
 
5c295460
 	_, err := buildImage(name,
1150c163
 		`FROM onbuild`,
 		true)
 	if err != nil {
 		if !strings.Contains(err.Error(), "from isn't allowed as an ONBUILD trigger") {
dc944ea7
 			c.Fatalf("Wrong error %v, must be about FROM and ONBUILD in source image", err)
1150c163
 		}
 	} else {
dc944ea7
 		c.Fatal("Error must not be nil")
1150c163
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildForbiddenChainedInSourceImage(c *check.C) {
1150c163
 	name := "testbuildonbuildforbiddenchainedinsourceimage"
da3d3b97
 
5c295460
 	out, _ := dockerCmd(c, "create", "busybox", "true")
1150c163
 
475c6531
 	cleanedContainerID := strings.TrimSpace(out)
1150c163
 
5c295460
 	dockerCmd(c, "commit", "--run", "{\"OnBuild\":[\"ONBUILD RUN ls\"]}", cleanedContainerID, "onbuild")
1150c163
 
5c295460
 	_, err := buildImage(name,
1150c163
 		`FROM onbuild`,
 		true)
 	if err != nil {
 		if !strings.Contains(err.Error(), "Chaining ONBUILD via `ONBUILD ONBUILD` isn't allowed") {
dc944ea7
 			c.Fatalf("Wrong error %v, must be about chaining ONBUILD in source image", err)
1150c163
 		}
 	} else {
dc944ea7
 		c.Fatal("Error must not be nil")
1150c163
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildCmdEntrypointJSON(c *check.C) {
1150c163
 	name1 := "onbuildcmd"
 	name2 := "onbuildgenerated"
 
 	_, err := buildImage(name1, `
 FROM busybox
 ONBUILD CMD ["hello world"]
 ONBUILD ENTRYPOINT ["echo"]
 ONBUILD RUN ["true"]`,
 		false)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1150c163
 	}
 
 	_, err = buildImage(name2, fmt.Sprintf(`FROM %s`, name1), false)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1150c163
 	}
 
2b95f012
 	out, _ := dockerCmd(c, "run", name2)
1150c163
 
 	if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) {
2b95f012
 		c.Fatalf("did not get echo output from onbuild. Got: %q", out)
1150c163
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildEntrypointJSON(c *check.C) {
1150c163
 	name1 := "onbuildcmd"
 	name2 := "onbuildgenerated"
 
 	_, err := buildImage(name1, `
 FROM busybox
 ONBUILD ENTRYPOINT ["echo"]`,
 		false)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1150c163
 	}
 
 	_, err = buildImage(name2, fmt.Sprintf("FROM %s\nCMD [\"hello world\"]\n", name1), false)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1150c163
 	}
 
2b95f012
 	out, _ := dockerCmd(c, "run", name2)
1150c163
 
 	if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) {
dc944ea7
 		c.Fatal("got malformed output from onbuild", out)
1150c163
 	}
 
 }
 
ab121345
 func (s *DockerSuite) TestBuildCacheAdd(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
075e1bc1
 	name := "testbuildtwoimageswithadd"
 	server, err := fakeStorage(map[string]string{
 		"robots.txt": "hello",
 		"index.html": "world",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
03a109e4
 	}
075e1bc1
 	defer server.Close()
2e95bb5f
 
075e1bc1
 	if _, err := buildImage(name,
 		fmt.Sprintf(`FROM scratch
2e95bb5f
 		ADD %s/robots.txt /`, server.URL()),
075e1bc1
 		true); err != nil {
dc944ea7
 		c.Fatal(err)
075e1bc1
 	}
da3d3b97
 	if err != nil {
dc944ea7
 		c.Fatal(err)
da3d3b97
 	}
 	deleteImages(name)
21dff8cb
 	_, out, err := buildImageWithOut(name,
075e1bc1
 		fmt.Sprintf(`FROM scratch
2e95bb5f
 		ADD %s/index.html /`, server.URL()),
075e1bc1
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
03a109e4
 	}
 	if strings.Contains(out, "Using cache") {
dc944ea7
 		c.Fatal("2nd build used cache on ADD, it shouldn't")
03a109e4
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildLastModified(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
5c05b5c9
 	name := "testbuildlastmodified"
 
 	server, err := fakeStorage(map[string]string{
 		"file": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
5c05b5c9
 	}
 	defer server.Close()
 
 	var out, out2 string
 
 	dFmt := `FROM busybox
 ADD %s/file /
 RUN ls -le /file`
 
40c8e787
 	dockerfile := fmt.Sprintf(dFmt, server.URL())
5c05b5c9
 
 	if _, out, err = buildImageWithOut(name, dockerfile, false); err != nil {
dc944ea7
 		c.Fatal(err)
5c05b5c9
 	}
 
 	originMTime := regexp.MustCompile(`root.*/file.*\n`).FindString(out)
 	// Make sure our regexp is correct
 	if strings.Index(originMTime, "/file") < 0 {
dc944ea7
 		c.Fatalf("Missing ls info on 'file':\n%s", out)
5c05b5c9
 	}
 
 	// Build it again and make sure the mtime of the file didn't change.
 	// Wait a few seconds to make sure the time changed enough to notice
 	time.Sleep(2 * time.Second)
 
 	if _, out2, err = buildImageWithOut(name, dockerfile, false); err != nil {
dc944ea7
 		c.Fatal(err)
5c05b5c9
 	}
 
 	newMTime := regexp.MustCompile(`root.*/file.*\n`).FindString(out2)
 	if newMTime != originMTime {
dc944ea7
 		c.Fatalf("MTime changed:\nOrigin:%s\nNew:%s", originMTime, newMTime)
5c05b5c9
 	}
 
 	// Now 'touch' the file and make sure the timestamp DID change this time
 	// Create a new fakeStorage instead of just using Add() to help windows
 	server, err = fakeStorage(map[string]string{
 		"file": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
5c05b5c9
 	}
 	defer server.Close()
 
40c8e787
 	dockerfile = fmt.Sprintf(dFmt, server.URL())
5c05b5c9
 
 	if _, out2, err = buildImageWithOut(name, dockerfile, false); err != nil {
dc944ea7
 		c.Fatal(err)
5c05b5c9
 	}
 
 	newMTime = regexp.MustCompile(`root.*/file.*\n`).FindString(out2)
 	if newMTime == originMTime {
dc944ea7
 		c.Fatalf("MTime didn't change:\nOrigin:%s\nNew:%s", originMTime, newMTime)
5c05b5c9
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildSixtySteps(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // TODO Windows: This test passes on Windows,
 	// but currently adds a disproportionate amount of time for the value it has.
 	// Removing it from Windows CI for now, but this will be revisited in the
 	// TP5 timeframe when perf is better.
3824ec62
 	name := "foobuildsixtysteps"
2b95f012
 
96c52216
 	ctx, err := fakeContext("FROM "+minimalBaseImage()+"\n"+strings.Repeat("ADD foo /\n", 60),
3824ec62
 		map[string]string{
 			"foo": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
3824ec62
 	}
db7fded1
 	defer ctx.Close()
 
3824ec62
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
6db32fde
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddSingleFileToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
682fbe01
 	name := "testaddimg"
1a22418f
 	ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
682fbe01
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio /exists
 ADD test_file /
 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
1a22418f
 RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ]
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod),
682fbe01
 		map[string]string{
 			"test_file": "test1",
 		})
bb431a71
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bb431a71
 	}
db7fded1
 	defer ctx.Close()
 
682fbe01
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
91b7d8eb
 	}
 }
 
1ce5457d
 // Issue #3960: "ADD src ." hangs
dc944ea7
 func (s *DockerSuite) TestBuildAddSingleFileToWorkdir(c *check.C) {
5e2ea696
 	name := "testaddsinglefiletoworkdir"
 	ctx, err := fakeContext(`FROM busybox
 ADD test_file .`,
 		map[string]string{
 			"test_file": "test1",
 		})
1ce5457d
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1ce5457d
 	}
db7fded1
 	defer ctx.Close()
 
4203230c
 	errChan := make(chan error)
5e2ea696
 	go func() {
4203230c
 		_, err := buildImageFromContext(name, ctx, true)
 		errChan <- err
 		close(errChan)
5e2ea696
 	}()
 	select {
88c1bc10
 	case <-time.After(15 * time.Second):
dc944ea7
 		c.Fatal("Build with adding to workdir timed out")
4203230c
 	case err := <-errChan:
 		c.Assert(err, check.IsNil)
1ce5457d
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddSingleFileToExistDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
6bb44b6d
 	name := "testaddsinglefiletoexistdir"
 	ctx, err := fakeContext(`FROM busybox
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 ADD test_file /exists/
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
 		map[string]string{
 			"test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
6bb44b6d
 	}
db7fded1
 	defer ctx.Close()
 
6bb44b6d
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
91b7d8eb
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyAddMultipleFiles(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
17b6583a
 	server, err := fakeStorage(map[string]string{
 		"robots.txt": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
17b6583a
 	}
 	defer server.Close()
 
e45c9215
 	name := "testcopymultiplefilestofile"
17b6583a
 	ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
e45c9215
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 COPY test_file1 test_file2 /exists/
17b6583a
 ADD test_file3 test_file4 %s/robots.txt /exists/
e45c9215
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/test_file1 | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/test_file2 | awk '{print $3":"$4}') = 'root:root' ]
05b8a1eb
 
e45c9215
 RUN [ $(ls -l /exists/test_file3 | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/test_file4 | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/robots.txt | awk '{print $3":"$4}') = 'root:root' ]
05b8a1eb
 
e45c9215
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
2e95bb5f
 `, server.URL()),
e45c9215
 		map[string]string{
 			"test_file1": "test1",
 			"test_file2": "test2",
 			"test_file3": "test3",
 			"test_file4": "test4",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
e45c9215
 	}
04ef69a1
 	defer ctx.Close()
e45c9215
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
e45c9215
 	}
05b8a1eb
 }
 
06d95003
 // This test is mainly for user namespaces to verify that new directories
 // are created as the remapped root uid/gid pair
 func (s *DockerSuite) TestBuildAddToNewDestination(c *check.C) {
 	testRequires(c, DaemonIsLinux) // Linux specific test
 	name := "testaddtonewdest"
 	ctx, err := fakeContext(`FROM busybox
 ADD . /new_dir
 RUN ls -l /
 RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'root:root' ]`,
 		map[string]string{
 			"test_dir/test_file": "test file",
 		})
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
 		c.Fatal(err)
 	}
 }
 
 // This test is mainly for user namespaces to verify that new directories
 // are created as the remapped root uid/gid pair
7a61b9ae
 func (s *DockerSuite) TestBuildCopyToNewParentDirectory(c *check.C) {
 	testRequires(c, DaemonIsLinux) // Linux specific test
 	name := "testcopytonewdir"
 	ctx, err := fakeContext(`FROM busybox
 COPY test_dir /new_dir
06d95003
 RUN ls -l /new_dir
 RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'root:root' ]`,
7a61b9ae
 		map[string]string{
 			"test_dir/test_file": "test file",
 		})
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
 		c.Fatal(err)
 	}
 }
 
06d95003
 // This test is mainly for user namespaces to verify that new directories
 // are created as the remapped root uid/gid pair
799a6b94
 func (s *DockerSuite) TestBuildWorkdirIsContainerRoot(c *check.C) {
 	testRequires(c, DaemonIsLinux) // Linux specific test
 	name := "testworkdirownership"
 	if _, err := buildImage(name, `FROM busybox
 WORKDIR /new_dir
 RUN ls -l /
 RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'root:root' ]`, true); err != nil {
 		c.Fatal(err)
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddFileWithWhitespace(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Not currently passing on Windows
abfb7138
 	name := "testaddfilewithwhitespace"
 	ctx, err := fakeContext(`FROM busybox
 RUN mkdir "/test dir"
 RUN mkdir "/test_dir"
 ADD [ "test file1", "/test_file1" ]
 ADD [ "test_file2", "/test file2" ]
 ADD [ "test file3", "/test file3" ]
 ADD [ "test dir/test_file4", "/test_dir/test_file4" ]
 ADD [ "test_dir/test_file5", "/test dir/test_file5" ]
 ADD [ "test dir/test_file6", "/test dir/test_file6" ]
 RUN [ $(cat "/test_file1") = 'test1' ]
 RUN [ $(cat "/test file2") = 'test2' ]
 RUN [ $(cat "/test file3") = 'test3' ]
 RUN [ $(cat "/test_dir/test_file4") = 'test4' ]
 RUN [ $(cat "/test dir/test_file5") = 'test5' ]
 RUN [ $(cat "/test dir/test_file6") = 'test6' ]`,
 		map[string]string{
 			"test file1":          "test1",
 			"test_file2":          "test2",
 			"test file3":          "test3",
 			"test dir/test_file4": "test4",
 			"test_dir/test_file5": "test5",
 			"test dir/test_file6": "test6",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
abfb7138
 	}
04ef69a1
 	defer ctx.Close()
abfb7138
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
abfb7138
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyFileWithWhitespace(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Not currently passing on Windows
abfb7138
 	name := "testcopyfilewithwhitespace"
 	ctx, err := fakeContext(`FROM busybox
 RUN mkdir "/test dir"
 RUN mkdir "/test_dir"
 COPY [ "test file1", "/test_file1" ]
 COPY [ "test_file2", "/test file2" ]
 COPY [ "test file3", "/test file3" ]
 COPY [ "test dir/test_file4", "/test_dir/test_file4" ]
 COPY [ "test_dir/test_file5", "/test dir/test_file5" ]
 COPY [ "test dir/test_file6", "/test dir/test_file6" ]
 RUN [ $(cat "/test_file1") = 'test1' ]
 RUN [ $(cat "/test file2") = 'test2' ]
 RUN [ $(cat "/test file3") = 'test3' ]
 RUN [ $(cat "/test_dir/test_file4") = 'test4' ]
 RUN [ $(cat "/test dir/test_file5") = 'test5' ]
 RUN [ $(cat "/test dir/test_file6") = 'test6' ]`,
 		map[string]string{
 			"test file1":          "test1",
 			"test_file2":          "test2",
 			"test file3":          "test3",
 			"test dir/test_file4": "test4",
 			"test_dir/test_file5": "test5",
 			"test dir/test_file6": "test6",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
abfb7138
 	}
04ef69a1
 	defer ctx.Close()
abfb7138
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
abfb7138
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyWildcard(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
acd40d50
 	name := "testcopywildcard"
 	server, err := fakeStorage(map[string]string{
 		"robots.txt": "hello",
 		"index.html": "world",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
acd40d50
 	}
 	defer server.Close()
2e95bb5f
 
acd40d50
 	ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
 	COPY file*.txt /tmp/
 	RUN ls /tmp/file1.txt /tmp/file2.txt
 	RUN mkdir /tmp1
 	COPY dir* /tmp1/
 	RUN ls /tmp1/dirt /tmp1/nested_file /tmp1/nested_dir/nest_nest_file
 	RUN mkdir /tmp2
         ADD dir/*dir %s/robots.txt /tmp2/
 	RUN ls /tmp2/nest_nest_file /tmp2/robots.txt
2e95bb5f
 	`, server.URL()),
acd40d50
 		map[string]string{
 			"file1.txt":                     "test1",
 			"file2.txt":                     "test2",
 			"dir/nested_file":               "nested file",
 			"dir/nested_dir/nest_nest_file": "2 times nested",
 			"dirt": "dirty",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
acd40d50
 	}
82daa438
 	defer ctx.Close()
acd40d50
 
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
acd40d50
 	}
 
 	// Now make sure we use a cache the 2nd time
 	id2, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
acd40d50
 	}
 
 	if id1 != id2 {
dc944ea7
 		c.Fatal("didn't use the cache")
acd40d50
 	}
 
 }
 
82daa438
 func (s *DockerSuite) TestBuildCopyWildcardInName(c *check.C) {
 	name := "testcopywildcardinname"
 	ctx, err := fakeContext(`FROM busybox
 	COPY *.txt /tmp/
 	RUN [ "$(cat /tmp/\*.txt)" = 'hi there' ]
 	`, map[string]string{"*.txt": "hi there"})
 
 	if err != nil {
 		// Normally we would do c.Fatal(err) here but given that
 		// the odds of this failing are so rare, it must be because
 		// the OS we're running the client on doesn't support * in
 		// filenames (like windows).  So, instead of failing the test
 		// just let it pass. Then we don't need to explicitly
 		// say which OSs this works on or not.
 		return
 	}
 	defer ctx.Close()
 
 	_, err = buildImageFromContext(name, ctx, true)
 	if err != nil {
 		c.Fatalf("should have built: %q", err)
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyWildcardCache(c *check.C) {
acd40d50
 	name := "testcopywildcardcache"
 	ctx, err := fakeContext(`FROM busybox
8b3fbac1
 	COPY file1.txt /tmp/`,
acd40d50
 		map[string]string{
 			"file1.txt": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
acd40d50
 	}
04ef69a1
 	defer ctx.Close()
acd40d50
 
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
acd40d50
 	}
 
8b3fbac1
 	// Now make sure we use a cache the 2nd time even with wild cards.
 	// Use the same context so the file is the same and the checksum will match
 	ctx.Add("Dockerfile", `FROM busybox
 	COPY file*.txt /tmp/`)
acd40d50
 
8b3fbac1
 	id2, err := buildImageFromContext(name, ctx, true)
acd40d50
 	if err != nil {
dc944ea7
 		c.Fatal(err)
acd40d50
 	}
 
 	if id1 != id2 {
dc944ea7
 		c.Fatal("didn't use the cache")
acd40d50
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddSingleFileToNonExistingDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
fcfe80f6
 	name := "testaddsinglefiletononexistingdir"
139b6ed3
 	ctx, err := fakeContext(`FROM busybox
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio /exists
 ADD test_file /test_dir/
 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
 		map[string]string{
 			"test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
139b6ed3
 	}
db7fded1
 	defer ctx.Close()
 
139b6ed3
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
91b7d8eb
 	}
fbaa41b5
 
91b7d8eb
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddDirContentToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
2d802d7f
 	name := "testadddircontenttoroot"
 	ctx, err := fakeContext(`FROM busybox
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio exists
 ADD test_dir /
 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
 		map[string]string{
 			"test_dir/test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2d802d7f
 	}
db7fded1
 	defer ctx.Close()
 
2d802d7f
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
91b7d8eb
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddDirContentToExistingDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
fcfe80f6
 	name := "testadddircontenttoexistingdir"
c58391bb
 	ctx, err := fakeContext(`FROM busybox
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 ADD test_dir/ /exists/
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`,
 		map[string]string{
 			"test_dir/test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
c58391bb
 	}
db7fded1
 	defer ctx.Close()
 
c58391bb
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
91b7d8eb
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddWholeDirToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
0c899cef
 	name := "testaddwholedirtoroot"
1a22418f
 	ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
0c899cef
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio exists
 ADD test_dir /test_dir
 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ]
 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
1a22418f
 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ]
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod),
0c899cef
 		map[string]string{
 			"test_dir/test_file": "test1",
 		})
be924087
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bb431a71
 	}
db7fded1
 	defer ctx.Close()
 
0c899cef
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
bb431a71
 	}
91b7d8eb
 }
 
570f1153
 // Testing #5941
dc944ea7
 func (s *DockerSuite) TestBuildAddEtcToRoot(c *check.C) {
570f1153
 	name := "testaddetctoroot"
2b95f012
 
96c52216
 	ctx, err := fakeContext(`FROM `+minimalBaseImage()+`
570f1153
 ADD . /`,
 		map[string]string{
 			"etc/test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
570f1153
 	}
db7fded1
 	defer ctx.Close()
 
570f1153
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
56a53c72
 	}
 }
 
f3cedce3
 // Testing #9401
dc944ea7
 func (s *DockerSuite) TestBuildAddPreservesFilesSpecialBits(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
f3cedce3
 	name := "testaddpreservesfilesspecialbits"
 	ctx, err := fakeContext(`FROM busybox
 ADD suidbin /usr/bin/suidbin
 RUN chmod 4755 /usr/bin/suidbin
 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]
 ADD ./data/ /
 RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]`,
 		map[string]string{
 			"suidbin":             "suidbin",
 			"/data/usr/test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
f3cedce3
 	}
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
f3cedce3
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopySingleFileToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
83c5dced
 	name := "testcopysinglefiletoroot"
1a22418f
 	ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
83c5dced
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio /exists
 COPY test_file /
 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
1a22418f
 RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ]
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod),
83c5dced
 		map[string]string{
 			"test_file": "test1",
 		})
180c2a67
 	if err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
db7fded1
 	defer ctx.Close()
 
83c5dced
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
 }
 
 // Issue #3960: "ADD src ." hangs - adapted for COPY
dc944ea7
 func (s *DockerSuite) TestBuildCopySingleFileToWorkdir(c *check.C) {
d41cba6a
 	name := "testcopysinglefiletoworkdir"
 	ctx, err := fakeContext(`FROM busybox
 COPY test_file .`,
 		map[string]string{
 			"test_file": "test1",
 		})
180c2a67
 	if err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
db7fded1
 	defer ctx.Close()
 
4203230c
 	errChan := make(chan error)
d41cba6a
 	go func() {
4203230c
 		_, err := buildImageFromContext(name, ctx, true)
 		errChan <- err
 		close(errChan)
d41cba6a
 	}()
 	select {
88c1bc10
 	case <-time.After(15 * time.Second):
dc944ea7
 		c.Fatal("Build with adding to workdir timed out")
4203230c
 	case err := <-errChan:
 		c.Assert(err, check.IsNil)
180c2a67
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopySingleFileToExistDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
2248109f
 	name := "testcopysinglefiletoexistdir"
 	ctx, err := fakeContext(`FROM busybox
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 COPY test_file /exists/
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
 		map[string]string{
 			"test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2248109f
 	}
db7fded1
 	defer ctx.Close()
 
2248109f
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopySingleFileToNonExistDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
24d83afd
 	name := "testcopysinglefiletononexistdir"
 	ctx, err := fakeContext(`FROM busybox
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio /exists
 COPY test_file /test_dir/
 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
 		map[string]string{
 			"test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
24d83afd
 	}
db7fded1
 	defer ctx.Close()
 
24d83afd
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyDirContentToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
832618af
 	name := "testcopydircontenttoroot"
 	ctx, err := fakeContext(`FROM busybox
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio exists
 COPY test_dir /
 RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`,
 		map[string]string{
 			"test_dir/test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
832618af
 	}
db7fded1
 	defer ctx.Close()
 
832618af
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyDirContentToExistDir(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
4a029259
 	name := "testcopydircontenttoexistdir"
 	ctx, err := fakeContext(`FROM busybox
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN mkdir /exists
 RUN touch /exists/exists_file
 RUN chown -R dockerio.dockerio /exists
 COPY test_dir/ /exists/
 RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
 RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`,
 		map[string]string{
 			"test_dir/test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
4a029259
 	}
db7fded1
 	defer ctx.Close()
 
4a029259
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyWholeDirToRoot(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Linux specific test
6582ea57
 	name := "testcopywholedirtoroot"
1a22418f
 	ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
6582ea57
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 RUN echo 'dockerio:x:1001:' >> /etc/group
 RUN touch /exists
 RUN chown dockerio.dockerio exists
 COPY test_dir /test_dir
 RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
 RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ]
 RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
1a22418f
 RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ]
 RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod),
6582ea57
 		map[string]string{
 			"test_dir/test_file": "test1",
 		})
be924087
 	if err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
db7fded1
 	defer ctx.Close()
 
6582ea57
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyEtcToRoot(c *check.C) {
c8a5d56f
 	name := "testcopyetctoroot"
2b95f012
 
96c52216
 	ctx, err := fakeContext(`FROM `+minimalBaseImage()+`
c8a5d56f
 COPY . /`,
 		map[string]string{
 			"etc/test_file": "test1",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
c8a5d56f
 	}
db7fded1
 	defer ctx.Close()
 
c8a5d56f
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
180c2a67
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddBadLinks(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // Not currently working on Windows
 
 	dockerfile := `
 		FROM scratch
 		ADD links.tar /
 		ADD foo.txt /symlink/
 		`
 	targetFile := "foo.txt"
7496cbbc
 	var (
 		name = "test-link-absolute"
 	)
 	ctx, err := fakeContext(dockerfile, nil)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 	defer ctx.Close()
 
 	tempDir, err := ioutil.TempDir("", "test-link-absolute-temp-")
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to create temporary directory: %s", tempDir)
7496cbbc
 	}
 	defer os.RemoveAll(tempDir)
 
d0dc14e5
 	var symlinkTarget string
 	if runtime.GOOS == "windows" {
 		var driveLetter string
 		if abs, err := filepath.Abs(tempDir); err != nil {
dc944ea7
 			c.Fatal(err)
d0dc14e5
 		} else {
 			driveLetter = abs[:1]
 		}
 		tempDirWithoutDrive := tempDir[2:]
 		symlinkTarget = fmt.Sprintf(`%s:\..\..\..\..\..\..\..\..\..\..\..\..%s`, driveLetter, tempDirWithoutDrive)
 	} else {
 		symlinkTarget = fmt.Sprintf("/../../../../../../../../../../../..%s", tempDir)
 	}
 
7496cbbc
 	tarPath := filepath.Join(ctx.Dir, "links.tar")
 	nonExistingFile := filepath.Join(tempDir, targetFile)
 	fooPath := filepath.Join(ctx.Dir, targetFile)
 
 	tarOut, err := os.Create(tarPath)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 
 	tarWriter := tar.NewWriter(tarOut)
 
 	header := &tar.Header{
 		Name:     "symlink",
 		Typeflag: tar.TypeSymlink,
 		Linkname: symlinkTarget,
 		Mode:     0755,
 		Uid:      0,
 		Gid:      0,
 	}
 
 	err = tarWriter.WriteHeader(header)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 
 	tarWriter.Close()
 	tarOut.Close()
 
 	foo, err := os.Create(fooPath)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 	defer foo.Close()
 
 	if _, err := foo.WriteString("test"); err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
7496cbbc
 	}
 
 	if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
dc944ea7
 		c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
7496cbbc
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddBadLinksVolume(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux) // ln not implemented on Windows busybox
a57eee22
 	const (
 		dockerfileTemplate = `
 		FROM busybox
 		RUN ln -s /../../../../../../../../%s /x
 		VOLUME /x
 		ADD foo.txt /x/`
 		targetFile = "foo.txt"
 	)
 	var (
 		name       = "test-link-absolute-volume"
 		dockerfile = ""
 	)
 
 	tempDir, err := ioutil.TempDir("", "test-link-absolute-volume-temp-")
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to create temporary directory: %s", tempDir)
a57eee22
 	}
 	defer os.RemoveAll(tempDir)
 
 	dockerfile = fmt.Sprintf(dockerfileTemplate, tempDir)
 	nonExistingFile := filepath.Join(tempDir, targetFile)
 
 	ctx, err := fakeContext(dockerfile, nil)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
a57eee22
 	}
 	defer ctx.Close()
 	fooPath := filepath.Join(ctx.Dir, targetFile)
 
 	foo, err := os.Create(fooPath)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
a57eee22
 	}
 	defer foo.Close()
 
 	if _, err := foo.WriteString("test"); err != nil {
dc944ea7
 		c.Fatal(err)
a57eee22
 	}
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
a57eee22
 	}
 
 	if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
dc944ea7
 		c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
a57eee22
 	}
 
 }
 
f5b1afae
 // Issue #5270 - ensure we throw a better error than "unexpected EOF"
 // when we can't access files in the context.
dc944ea7
 func (s *DockerSuite) TestBuildWithInaccessibleFilesInContext(c *check.C) {
2b95f012
 	testRequires(c, DaemonIsLinux, UnixCli) // test uses chown/chmod: not available on windows
492a58f0
 
f5b1afae
 	{
51a56399
 		name := "testbuildinaccessiblefiles"
 		ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"fileWithoutReadAccess": "foo"})
 		if err != nil {
dc944ea7
 			c.Fatal(err)
51a56399
 		}
 		defer ctx.Close()
f5b1afae
 		// This is used to ensure we detect inaccessible files early during build in the cli client
51a56399
 		pathToFileWithoutReadAccess := filepath.Join(ctx.Dir, "fileWithoutReadAccess")
f5b1afae
 
b1e3c9e9
 		if err = os.Chown(pathToFileWithoutReadAccess, 0, 0); err != nil {
dc944ea7
 			c.Fatalf("failed to chown file to root: %s", err)
b1e3c9e9
 		}
 		if err = os.Chmod(pathToFileWithoutReadAccess, 0700); err != nil {
dc944ea7
 			c.Fatalf("failed to chmod file to 700: %s", err)
b1e3c9e9
 		}
51a56399
 		buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name))
 		buildCmd.Dir = ctx.Dir
b1e3c9e9
 		out, _, err := runCommandWithOutput(buildCmd)
 		if err == nil {
dc944ea7
 			c.Fatalf("build should have failed: %s %s", err, out)
f5b1afae
 		}
 
 		// check if we've detected the failure before we started building
 		if !strings.Contains(out, "no permission to read from ") {
dc944ea7
 			c.Fatalf("output should've contained the string: no permission to read from but contained: %s", out)
f5b1afae
 		}
 
82ea6ed2
 		if !strings.Contains(out, "Error checking context") {
 			c.Fatalf("output should've contained the string: Error checking context")
f5b1afae
 		}
 	}
 	{
51a56399
 		name := "testbuildinaccessibledirectory"
 		ctx, err := fakeContext("FROM scratch\nADD . /foo/", map[string]string{"directoryWeCantStat/bar": "foo"})
 		if err != nil {
dc944ea7
 			c.Fatal(err)
51a56399
 		}
 		defer ctx.Close()
f5b1afae
 		// This is used to ensure we detect inaccessible directories early during build in the cli client
51a56399
 		pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat")
f5b1afae
 		pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
 
b1e3c9e9
 		if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
dc944ea7
 			c.Fatalf("failed to chown directory to root: %s", err)
b1e3c9e9
 		}
 		if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
dc944ea7
 			c.Fatalf("failed to chmod directory to 444: %s", err)
b1e3c9e9
 		}
 		if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
dc944ea7
 			c.Fatalf("failed to chmod file to 700: %s", err)
b1e3c9e9
 		}
f5b1afae
 
51a56399
 		buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name))
 		buildCmd.Dir = ctx.Dir
b1e3c9e9
 		out, _, err := runCommandWithOutput(buildCmd)
 		if err == nil {
dc944ea7
 			c.Fatalf("build should have failed: %s %s", err, out)
f5b1afae
 		}
 
 		// check if we've detected the failure before we started building
 		if !strings.Contains(out, "can't stat") {
dc944ea7
 			c.Fatalf("output should've contained the string: can't access %s", out)
f5b1afae
 		}
 
82ea6ed2
 		if !strings.Contains(out, "Error checking context") {
 			c.Fatalf("output should've contained the string: Error checking context\ngot:%s", out)
f5b1afae
 		}
 
 	}
 	{
51a56399
 		name := "testlinksok"
 		ctx, err := fakeContext("FROM scratch\nADD . /foo/", nil)
 		if err != nil {
dc944ea7
 			c.Fatal(err)
51a56399
 		}
 		defer ctx.Close()
da3d3b97
 
 		target := "../../../../../../../../../../../../../../../../../../../azA"
 		if err := os.Symlink(filepath.Join(ctx.Dir, "g"), target); err != nil {
dc944ea7
 			c.Fatal(err)
51a56399
 		}
da3d3b97
 		defer os.Remove(target)
f5b1afae
 		// This is used to ensure we don't follow links when checking if everything in the context is accessible
 		// This test doesn't require that we run commands as an unprivileged user
51a56399
 		if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 			c.Fatal(err)
f5b1afae
 		}
 	}
27cca4c7
 	{
51a56399
 		name := "testbuildignoredinaccessible"
 		ctx, err := fakeContext("FROM scratch\nADD . /foo/",
 			map[string]string{
 				"directoryWeCantStat/bar": "foo",
 				".dockerignore":           "directoryWeCantStat",
 			})
 		if err != nil {
dc944ea7
 			c.Fatal(err)
51a56399
 		}
 		defer ctx.Close()
27cca4c7
 		// This is used to ensure we don't try to add inaccessible files when they are ignored by a .dockerignore pattern
51a56399
 		pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat")
27cca4c7
 		pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
b1e3c9e9
 		if err = os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
dc944ea7
 			c.Fatalf("failed to chown directory to root: %s", err)
b1e3c9e9
 		}
 		if err = os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
dc944ea7
 			c.Fatalf("failed to chmod directory to 755: %s", err)
b1e3c9e9
 		}
 		if err = os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
dc944ea7
 			c.Fatalf("failed to chmod file to 444: %s", err)
b1e3c9e9
 		}
27cca4c7
 
51a56399
 		buildCmd := exec.Command("su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name))
 		buildCmd.Dir = ctx.Dir
b1e3c9e9
 		if out, _, err := runCommandWithOutput(buildCmd); err != nil {
dc944ea7
 			c.Fatalf("build should have worked: %s %s", err, out)
27cca4c7
 		}
 
 	}
f5b1afae
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildForceRm(c *check.C) {
69dcf767
 	containerCountBefore, err := getContainerCount()
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to get the container count: %s", err)
69dcf767
 	}
1625cbfc
 	name := "testbuildforcerm"
4603a725
 
 	ctx, err := fakeContext(`FROM `+minimalBaseImage()+`
 	RUN true
 	RUN thiswillfail`, nil)
1625cbfc
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1625cbfc
 	}
 	defer ctx.Close()
69dcf767
 
5c295460
 	dockerCmdInDir(c, ctx.Dir, "build", "-t", name, "--force-rm", ".")
69dcf767
 
 	containerCountAfter, err := getContainerCount()
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to get the container count: %s", err)
69dcf767
 	}
 
 	if containerCountBefore != containerCountAfter {
dc944ea7
 		c.Fatalf("--force-rm shouldn't have left containers behind")
69dcf767
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildRm(c *check.C) {
52cf3312
 	name := "testbuildrm"
4603a725
 
 	ctx, err := fakeContext(`FROM `+minimalBaseImage()+`
 	ADD foo /
 	ADD foo /`, map[string]string{"foo": "bar"})
52cf3312
 	if err != nil {
dc944ea7
 		c.Fatal(err)
52cf3312
 	}
 	defer ctx.Close()
a691fcb2
 	{
 		containerCountBefore, err := getContainerCount()
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to get the container count: %s", err)
a691fcb2
 		}
 
dc944ea7
 		out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--rm", "-t", name, ".")
a691fcb2
 
b1e3c9e9
 		if err != nil {
dc944ea7
 			c.Fatal("failed to build the image", out)
a691fcb2
 		}
 
 		containerCountAfter, err := getContainerCount()
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to get the container count: %s", err)
a691fcb2
 		}
 
 		if containerCountBefore != containerCountAfter {
dc944ea7
 			c.Fatalf("-rm shouldn't have left containers behind")
a691fcb2
 		}
52cf3312
 		deleteImages(name)
a691fcb2
 	}
 
 	{
 		containerCountBefore, err := getContainerCount()
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to get the container count: %s", err)
a691fcb2
 		}
 
dc944ea7
 		out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name, ".")
a691fcb2
 
b1e3c9e9
 		if err != nil {
dc944ea7
 			c.Fatal("failed to build the image", out)
a691fcb2
 		}
 
 		containerCountAfter, err := getContainerCount()
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to get the container count: %s", err)
a691fcb2
 		}
 
 		if containerCountBefore != containerCountAfter {
dc944ea7
 			c.Fatalf("--rm shouldn't have left containers behind")
a691fcb2
 		}
52cf3312
 		deleteImages(name)
a691fcb2
 	}
 
 	{
 		containerCountBefore, err := getContainerCount()
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to get the container count: %s", err)
a691fcb2
 		}
 
dc944ea7
 		out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--rm=false", "-t", name, ".")
a691fcb2
 
b1e3c9e9
 		if err != nil {
dc944ea7
 			c.Fatal("failed to build the image", out)
a691fcb2
 		}
 
 		containerCountAfter, err := getContainerCount()
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to get the container count: %s", err)
a691fcb2
 		}
 
 		if containerCountBefore == containerCountAfter {
dc944ea7
 			c.Fatalf("--rm=false should have left containers behind")
a691fcb2
 		}
52cf3312
 		deleteImages(name)
a691fcb2
 
 	}
 
 }
a5729879
 
dc944ea7
 func (s *DockerSuite) TestBuildWithVolumes(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Invalid volume paths on Windows
68bb56a4
 	var (
 		result   map[string]map[string]struct{}
 		name     = "testbuildvolumes"
 		emptyMap = make(map[string]struct{})
a5ca549a
 		expected = map[string]map[string]struct{}{
 			"/test1":  emptyMap,
 			"/test2":  emptyMap,
 			"/test3":  emptyMap,
 			"/test4":  emptyMap,
 			"/test5":  emptyMap,
 			"/test6":  emptyMap,
 			"[/test7": emptyMap,
 			"/test8]": emptyMap,
 		}
68bb56a4
 	)
bf4d9070
 	_, err := buildImage(name,
 		`FROM scratch
 		VOLUME /test1
a5ca549a
 		VOLUME /test2
     VOLUME /test3 /test4
     VOLUME ["/test5", "/test6"]
     VOLUME [/test7 /test8]
     `,
bf4d9070
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bf4d9070
 	}
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Volumes")
68bb56a4
 
 	err = unmarshalJSON([]byte(res), &result)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bf4d9070
 	}
68bb56a4
 
fa753e67
 	equal := reflect.DeepEqual(&result, &expected)
68bb56a4
 
 	if !equal {
dc944ea7
 		c.Fatalf("Volumes %s, expected %s", result, expected)
68bb56a4
 	}
 
11f7f0bf
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildMaintainer(c *check.C) {
bf4d9070
 	name := "testbuildmaintainer"
4603a725
 
bf4d9070
 	expected := "dockerio"
 	_, err := buildImage(name,
4603a725
 		`FROM `+minimalBaseImage()+`
bf4d9070
         MAINTAINER dockerio`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bf4d9070
 	}
62a856e9
 	res := inspectField(c, name, "Author")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Maintainer %s, expected %s", res, expected)
bf4d9070
 	}
3dd4c5f4
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildUser(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
bf4d9070
 	name := "testbuilduser"
 	expected := "dockerio"
 	_, err := buildImage(name,
 		`FROM busybox
360fb3d4
 		RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
 		USER dockerio
bf4d9070
 		RUN [ $(whoami) = 'dockerio' ]`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bf4d9070
 	}
62a856e9
 	res := inspectField(c, name, "Config.User")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("User %s, expected %s", res, expected)
bf4d9070
 	}
360fb3d4
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildRelativeWorkdir(c *check.C) {
bf4d9070
 	name := "testbuildrelativeworkdir"
4603a725
 
 	var (
 		expected1     string
 		expected2     string
 		expected3     string
 		expected4     string
 		expectedFinal string
 	)
04338010
 
4603a725
 	if daemonPlatform == "windows" {
c2d18342
 		expected1 = `C:/`
4603a725
 		expected2 = `C:/test1`
 		expected3 = `C:/test2`
 		expected4 = `C:/test2/test3`
04338010
 		expectedFinal = `C:\test2\test3` // Note inspect is going to return Windows paths, as it's not in busybox
4603a725
 	} else {
 		expected1 = `/`
 		expected2 = `/test1`
 		expected3 = `/test2`
 		expected4 = `/test2/test3`
 		expectedFinal = `/test2/test3`
 	}
 
bf4d9070
 	_, err := buildImage(name,
 		`FROM busybox
c2d18342
 		RUN sh -c "[ "$PWD" = "`+expected1+`" ]"
40630ce4
 		WORKDIR test1
c2d18342
 		RUN sh -c "[ "$PWD" = "`+expected2+`" ]"
40630ce4
 		WORKDIR /test2
c2d18342
 		RUN sh -c "[ "$PWD" = "`+expected3+`" ]"
40630ce4
 		WORKDIR test3
c2d18342
 		RUN sh -c "[ "$PWD" = "`+expected4+`" ]"`,
bf4d9070
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bf4d9070
 	}
62a856e9
 	res := inspectField(c, name, "Config.WorkingDir")
4603a725
 	if res != expectedFinal {
 		c.Fatalf("Workdir %s, expected %s", res, expectedFinal)
bf4d9070
 	}
40630ce4
 }
 
faab7170
 // #22181 Regression test. Single end-to-end test of using
 // Windows semantics. Most path handling verifications are in unit tests
04338010
 func (s *DockerSuite) TestBuildWindowsWorkdirProcessing(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildwindowsworkdirprocessing"
 	_, err := buildImage(name,
 		`FROM busybox
faab7170
 		WORKDIR C:\\foo
04338010
 		WORKDIR bar
 		RUN sh -c "[ "$PWD" = "C:/foo/bar" ]"
 		`,
 		true)
 	if err != nil {
 		c.Fatal(err)
 	}
 }
 
faab7170
 // #22181 Regression test. Most paths handling verifications are in unit test.
 // One functional test for end-to-end
04338010
 func (s *DockerSuite) TestBuildWindowsAddCopyPathProcessing(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildwindowsaddcopypathprocessing"
 	// TODO Windows (@jhowardmsft). Needs a follow-up PR to 22181 to
 	// support backslash such as .\\ being equivalent to ./ and c:\\ being
 	// equivalent to c:/. This is not currently (nor ever has been) supported
 	// by docker on the Windows platform.
 	dockerfile := `
 		FROM busybox
faab7170
 			# No trailing slash on COPY/ADD
04338010
 			# Results in dir being changed to a file
 			WORKDIR /wc1
 			COPY wc1 c:/wc1
 			WORKDIR /wc2
 			ADD wc2 c:/wc2
 			WORKDIR c:/
 			RUN sh -c "[ $(cat c:/wc1) = 'hellowc1' ]"
 			RUN sh -c "[ $(cat c:/wc2) = 'worldwc2' ]"			
 
 			# Trailing slash on COPY/ADD, Windows-style path. 
 			WORKDIR /wd1
 			COPY wd1 c:/wd1/
 			WORKDIR /wd2
 			ADD wd2 c:/wd2/
 			RUN sh -c "[ $(cat c:/wd1/wd1) = 'hellowd1' ]"
 			RUN sh -c "[ $(cat c:/wd2/wd2) = 'worldwd2' ]"
 			`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"wc1": "hellowc1",
 		"wc2": "worldwc2",
 		"wd1": "hellowd1",
 		"wd2": "worldwd2",
 	})
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer ctx.Close()
 	_, err = buildImageFromContext(name, ctx, false)
 	if err != nil {
 		c.Fatal(err)
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildWorkdirWithEnvVariables(c *check.C) {
2c5b5cfc
 	name := "testbuildworkdirwithenvvariables"
4603a725
 
 	var expected string
 	if daemonPlatform == "windows" {
04338010
 		expected = `C:\test1\test2`
4603a725
 	} else {
 		expected = `/test1/test2`
 	}
 
2c5b5cfc
 	_, err := buildImage(name,
 		`FROM busybox
 		ENV DIRPATH /test1
 		ENV SUBDIRNAME test2
 		WORKDIR $DIRPATH
 		WORKDIR $SUBDIRNAME/$MISSING_VAR`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2c5b5cfc
 	}
62a856e9
 	res := inspectField(c, name, "Config.WorkingDir")
2c5b5cfc
 	if res != expected {
dc944ea7
 		c.Fatalf("Workdir %s, expected %s", res, expected)
2c5b5cfc
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildRelativeCopy(c *check.C) {
ea3afdad
 	// cat /test1/test2/foo gets permission denied for the user
 	testRequires(c, NotUserNamespace)
4603a725
 
 	var expected string
 	if daemonPlatform == "windows" {
 		expected = `C:/test1/test2`
 	} else {
 		expected = `/test1/test2`
 	}
 
f21f9f85
 	name := "testbuildrelativecopy"
 	dockerfile := `
 		FROM busybox
 			WORKDIR /test1
 			WORKDIR test2
4603a725
 			RUN sh -c "[ "$PWD" = '` + expected + `' ]"
f21f9f85
 			COPY foo ./
4603a725
 			RUN sh -c "[ $(cat /test1/test2/foo) = 'hello' ]"
f21f9f85
 			ADD foo ./bar/baz
4603a725
 			RUN sh -c "[ $(cat /test1/test2/bar/baz) = 'hello' ]"
f21f9f85
 			COPY foo ./bar/baz2
4603a725
 			RUN sh -c "[ $(cat /test1/test2/bar/baz2) = 'hello' ]"
f21f9f85
 			WORKDIR ..
 			COPY foo ./
4603a725
 			RUN sh -c "[ $(cat /test1/foo) = 'hello' ]"
f21f9f85
 			COPY foo /test3/
4603a725
 			RUN sh -c "[ $(cat /test3/foo) = 'hello' ]"
f21f9f85
 			WORKDIR /test4
 			COPY . .
4603a725
 			RUN sh -c "[ $(cat /test4/foo) = 'hello' ]"
f21f9f85
 			WORKDIR /test5/test6
 			COPY foo ../
4603a725
 			RUN sh -c "[ $(cat /test5/foo) = 'hello' ]"
f21f9f85
 			`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"foo": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
f21f9f85
 	}
04ef69a1
 	defer ctx.Close()
f21f9f85
 	_, err = buildImageFromContext(name, ctx, false)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
f21f9f85
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnv(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // ENV expansion is different in Windows
bf4d9070
 	name := "testbuildenv"
cb51681a
 	expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]"
bf4d9070
 	_, err := buildImage(name,
 		`FROM busybox
cb51681a
 		ENV PATH /test:$PATH
5febba93
         ENV PORT 2375
 		RUN [ $(env | grep PORT) = 'PORT=2375' ]`,
bf4d9070
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bf4d9070
 	}
62a856e9
 	res := inspectField(c, name, "Config.Env")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Env %s, expected %s", res, expected)
bf4d9070
 	}
b05be686
 }
 
d3ea7e80
 func (s *DockerSuite) TestBuildPATH(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // ENV expansion is different in Windows
d3ea7e80
 
 	defPath := "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
 
 	fn := func(dockerfile string, exp string) {
 		_, err := buildImage("testbldpath", dockerfile, true)
 		c.Assert(err, check.IsNil)
 
62a856e9
 		res := inspectField(c, "testbldpath", "Config.Env")
d3ea7e80
 
 		if res != exp {
 			c.Fatalf("Env %q, expected %q for dockerfile:%q", res, exp, dockerfile)
 		}
 	}
 
 	tests := []struct{ dockerfile, exp string }{
 		{"FROM scratch\nMAINTAINER me", "[PATH=" + defPath + "]"},
 		{"FROM busybox\nMAINTAINER me", "[PATH=" + defPath + "]"},
 		{"FROM scratch\nENV FOO=bar", "[PATH=" + defPath + " FOO=bar]"},
 		{"FROM busybox\nENV FOO=bar", "[PATH=" + defPath + " FOO=bar]"},
 		{"FROM scratch\nENV PATH=/test", "[PATH=/test]"},
 		{"FROM busybox\nENV PATH=/test", "[PATH=/test]"},
 		{"FROM scratch\nENV PATH=''", "[PATH=]"},
 		{"FROM busybox\nENV PATH=''", "[PATH=]"},
 	}
 
 	for _, test := range tests {
 		fn(test.dockerfile, test.exp)
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildContextCleanup(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
dc944ea7
 	testRequires(c, SameHostDaemon)
b686b65c
 
18587469
 	name := "testbuildcontextcleanup"
442b4562
 	entries, err := ioutil.ReadDir(filepath.Join(dockerBasePath, "tmp"))
18587469
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to list contents of tmp dir: %s", err)
18587469
 	}
 	_, err = buildImage(name,
 		`FROM scratch
         ENTRYPOINT ["/bin/echo"]`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
18587469
 	}
442b4562
 	entriesFinal, err := ioutil.ReadDir(filepath.Join(dockerBasePath, "tmp"))
18587469
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to list contents of tmp dir: %s", err)
18587469
 	}
 	if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
dc944ea7
 		c.Fatalf("context should have been deleted, but wasn't")
18587469
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
dc944ea7
 	testRequires(c, SameHostDaemon)
b686b65c
 
31c00390
 	name := "testbuildcontextcleanup"
442b4562
 	entries, err := ioutil.ReadDir(filepath.Join(dockerBasePath, "tmp"))
31c00390
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to list contents of tmp dir: %s", err)
31c00390
 	}
 	_, err = buildImage(name,
 		`FROM scratch
 	RUN /non/existing/command`,
 		true)
 	if err == nil {
dc944ea7
 		c.Fatalf("expected build to fail, but it didn't")
31c00390
 	}
442b4562
 	entriesFinal, err := ioutil.ReadDir(filepath.Join(dockerBasePath, "tmp"))
31c00390
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to list contents of tmp dir: %s", err)
31c00390
 	}
 	if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
dc944ea7
 		c.Fatalf("context should have been deleted, but wasn't")
31c00390
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCmd(c *check.C) {
bf4d9070
 	name := "testbuildcmd"
4603a725
 
53b0d626
 	expected := "[/bin/echo Hello World]"
bf4d9070
 	_, err := buildImage(name,
4603a725
 		`FROM `+minimalBaseImage()+`
bf4d9070
         CMD ["/bin/echo", "Hello World"]`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bf4d9070
 	}
62a856e9
 	res := inspectField(c, name, "Config.Cmd")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Cmd %s, expected %s", res, expected)
bf4d9070
 	}
c58991f3
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildExpose(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
bf4d9070
 	name := "testbuildexpose"
231d362d
 	expected := "map[2375/tcp:{}]"
bf4d9070
 	_, err := buildImage(name,
 		`FROM scratch
5febba93
         EXPOSE 2375`,
bf4d9070
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bf4d9070
 	}
62a856e9
 	res := inspectField(c, name, "Config.ExposedPorts")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Exposed ports %s, expected %s", res, expected)
bf4d9070
 	}
81d16411
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildExposeMorePorts(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
29be7b43
 	// start building docker file with a large number of ports
 	portList := make([]string, 50)
 	line := make([]string, 100)
 	expectedPorts := make([]int, len(portList)*len(line))
 	for i := 0; i < len(portList); i++ {
 		for j := 0; j < len(line); j++ {
 			p := i*len(line) + j + 1
 			line[j] = strconv.Itoa(p)
 			expectedPorts[p-1] = p
 		}
 		if i == len(portList)-1 {
 			portList[i] = strings.Join(line, " ")
 		} else {
 			portList[i] = strings.Join(line, " ") + ` \`
 		}
 	}
 
 	dockerfile := `FROM scratch
 	EXPOSE {{range .}} {{.}}
 	{{end}}`
 	tmpl := template.Must(template.New("dockerfile").Parse(dockerfile))
 	buf := bytes.NewBuffer(nil)
 	tmpl.Execute(buf, portList)
 
 	name := "testbuildexpose"
 	_, err := buildImage(name, buf.String(), true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
29be7b43
 	}
 
 	// check if all the ports are saved inside Config.ExposedPorts
62a856e9
 	res := inspectFieldJSON(c, name, "Config.ExposedPorts")
29be7b43
 	var exposedPorts map[string]interface{}
 	if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil {
dc944ea7
 		c.Fatal(err)
29be7b43
 	}
 
 	for _, p := range expectedPorts {
 		ep := fmt.Sprintf("%d/tcp", p)
 		if _, ok := exposedPorts[ep]; !ok {
dc944ea7
 			c.Errorf("Port(%s) is not exposed", ep)
29be7b43
 		} else {
 			delete(exposedPorts, ep)
 		}
 	}
 	if len(exposedPorts) != 0 {
dc944ea7
 		c.Errorf("Unexpected extra exposed ports %v", exposedPorts)
29be7b43
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildExposeOrder(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
1e7ba09b
 	buildID := func(name, exposed string) string {
 		_, err := buildImage(name, fmt.Sprintf(`FROM scratch
 		EXPOSE %s`, exposed), true)
 		if err != nil {
dc944ea7
 			c.Fatal(err)
1e7ba09b
 		}
62a856e9
 		id := inspectField(c, name, "Id")
1e7ba09b
 		return id
 	}
 
 	id1 := buildID("testbuildexpose1", "80 2375")
 	id2 := buildID("testbuildexpose2", "2375 80")
 	if id1 != id2 {
dc944ea7
 		c.Errorf("EXPOSE should invalidate the cache only when ports actually changed")
1e7ba09b
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
0552f1a0
 	name := "testbuildexposeuppercaseproto"
231d362d
 	expected := "map[5678/udp:{}]"
0552f1a0
 	_, err := buildImage(name,
 		`FROM scratch
         EXPOSE 5678/UDP`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
0552f1a0
 	}
62a856e9
 	res := inspectField(c, name, "Config.ExposedPorts")
0552f1a0
 	if res != expected {
dc944ea7
 		c.Fatalf("Exposed ports %s, expected %s", res, expected)
0552f1a0
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) {
cdd6e979
 	name := "testbuildentrypointinheritance"
 	name2 := "testbuildentrypointinheritance2"
 
 	_, err := buildImage(name,
 		`FROM busybox
         ENTRYPOINT ["/bin/echo"]`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
cdd6e979
 	}
62a856e9
 	res := inspectField(c, name, "Config.Entrypoint")
cdd6e979
 
53b0d626
 	expected := "[/bin/echo]"
cdd6e979
 	if res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
cdd6e979
 	}
 
 	_, err = buildImage(name2,
 		fmt.Sprintf(`FROM %s
         ENTRYPOINT []`, name),
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
cdd6e979
 	}
62a856e9
 	res = inspectField(c, name2, "Config.Entrypoint")
cdd6e979
 
53b0d626
 	expected = "[]"
cdd6e979
 
 	if res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
cdd6e979
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) {
bf4d9070
 	name := "testbuildentrypoint"
53b0d626
 	expected := "[]"
576416c9
 
bf4d9070
 	_, err := buildImage(name,
576416c9
 		`FROM busybox
         ENTRYPOINT []`,
bf4d9070
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
bf4d9070
 	}
62a856e9
 	res := inspectField(c, name, "Config.Entrypoint")
bf4d9070
 	if res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
bf4d9070
 	}
78a847a4
 
576416c9
 }
78a847a4
 
dc944ea7
 func (s *DockerSuite) TestBuildEntrypoint(c *check.C) {
576416c9
 	name := "testbuildentrypoint"
4603a725
 
53b0d626
 	expected := "[/bin/echo]"
576416c9
 	_, err := buildImage(name,
4603a725
 		`FROM `+minimalBaseImage()+`
576416c9
         ENTRYPOINT ["/bin/echo"]`,
78a847a4
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
78a847a4
 	}
62a856e9
 	res := inspectField(c, name, "Config.Entrypoint")
78a847a4
 	if res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
78a847a4
 	}
 
b25a9b71
 }
 
a5729879
 // #6445 ensure ONBUILD triggers aren't committed to grandchildren
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildLimitedInheritence(c *check.C) {
372f9bb5
 	var (
 		out2, out3 string
 	)
 	{
 		name1 := "testonbuildtrigger1"
 		dockerfile1 := `
a5729879
 		FROM busybox
 		RUN echo "GRANDPARENT"
 		ONBUILD RUN echo "ONBUILD PARENT"
372f9bb5
 		`
 		ctx, err := fakeContext(dockerfile1, nil)
 		if err != nil {
dc944ea7
 			c.Fatal(err)
372f9bb5
 		}
db7fded1
 		defer ctx.Close()
a5729879
 
dc944ea7
 		out1, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", name1, ".")
b1e3c9e9
 		if err != nil {
dc944ea7
 			c.Fatalf("build failed to complete: %s, %v", out1, err)
b1e3c9e9
 		}
a5729879
 	}
372f9bb5
 	{
 		name2 := "testonbuildtrigger2"
 		dockerfile2 := `
 		FROM testonbuildtrigger1
 		`
 		ctx, err := fakeContext(dockerfile2, nil)
 		if err != nil {
dc944ea7
 			c.Fatal(err)
372f9bb5
 		}
db7fded1
 		defer ctx.Close()
a5729879
 
dc944ea7
 		out2, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name2, ".")
b1e3c9e9
 		if err != nil {
dc944ea7
 			c.Fatalf("build failed to complete: %s, %v", out2, err)
b1e3c9e9
 		}
a5729879
 	}
372f9bb5
 	{
 		name3 := "testonbuildtrigger3"
 		dockerfile3 := `
 		FROM testonbuildtrigger2
 		`
 		ctx, err := fakeContext(dockerfile3, nil)
 		if err != nil {
dc944ea7
 			c.Fatal(err)
372f9bb5
 		}
db7fded1
 		defer ctx.Close()
a5729879
 
dc944ea7
 		out3, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-t", name3, ".")
b1e3c9e9
 		if err != nil {
dc944ea7
 			c.Fatalf("build failed to complete: %s, %v", out3, err)
b1e3c9e9
 		}
 
372f9bb5
 	}
a5729879
 
 	// ONBUILD should be run in second build.
 	if !strings.Contains(out2, "ONBUILD PARENT") {
dc944ea7
 		c.Fatalf("ONBUILD instruction did not run in child of ONBUILD parent")
a5729879
 	}
 
 	// ONBUILD should *not* be run in third build.
 	if strings.Contains(out3, "ONBUILD PARENT") {
dc944ea7
 		c.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent")
a5729879
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildWithCache(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
ae128437
 	name := "testbuildwithcache"
 	id1, err := buildImage(name,
 		`FROM scratch
 		MAINTAINER dockerio
 		EXPOSE 5432
         ENTRYPOINT ["/bin/echo"]`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	id2, err := buildImage(name,
 		`FROM scratch
 		MAINTAINER dockerio
 		EXPOSE 5432
         ENTRYPOINT ["/bin/echo"]`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
ae128437
 	}
 }
6db32fde
 
dc944ea7
 func (s *DockerSuite) TestBuildWithoutCache(c *check.C) {
4603a725
 	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
ae128437
 	name := "testbuildwithoutcache"
da3d3b97
 	name2 := "testbuildwithoutcache2"
ae128437
 	id1, err := buildImage(name,
 		`FROM scratch
 		MAINTAINER dockerio
 		EXPOSE 5432
         ENTRYPOINT ["/bin/echo"]`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
da3d3b97
 
 	id2, err := buildImage(name2,
ae128437
 		`FROM scratch
 		MAINTAINER dockerio
 		EXPOSE 5432
         ENTRYPOINT ["/bin/echo"]`,
 		false)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 == id2 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildConditionalCache(c *check.C) {
6f20b957
 	name := "testbuildconditionalcache"
 
 	dockerfile := `
 		FROM busybox
         ADD foo /tmp/`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"foo": "hello",
 	})
f6e95ef3
 	if err != nil {
dc944ea7
 		c.Fatal(err)
f6e95ef3
 	}
 	defer ctx.Close()
6f20b957
 
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatalf("Error building #1: %s", err)
6f20b957
 	}
 
 	if err := ctx.Add("foo", "bye"); err != nil {
dc944ea7
 		c.Fatalf("Error modifying foo: %s", err)
6f20b957
 	}
 
 	id2, err := buildImageFromContext(name, ctx, false)
 	if err != nil {
dc944ea7
 		c.Fatalf("Error building #2: %s", err)
6f20b957
 	}
 	if id2 == id1 {
dc944ea7
 		c.Fatal("Should not have used the cache")
6f20b957
 	}
 
 	id3, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatalf("Error building #3: %s", err)
6f20b957
 	}
 	if id3 != id2 {
dc944ea7
 		c.Fatal("Should have used the cache")
6f20b957
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddLocalFileWithCache(c *check.C) {
ea3afdad
 	// local files are not owned by the correct user
 	testRequires(c, NotUserNamespace)
ae128437
 	name := "testbuildaddlocalfilewithcache"
da3d3b97
 	name2 := "testbuildaddlocalfilewithcache2"
ae128437
 	dockerfile := `
 		FROM busybox
         MAINTAINER dockerio
         ADD foo /usr/lib/bla/bar
4603a725
 		RUN sh -c "[ $(cat /usr/lib/bla/bar) = "hello" ]"`
ae128437
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"foo": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
04ef69a1
 	defer ctx.Close()
ae128437
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
da3d3b97
 	id2, err := buildImageFromContext(name2, ctx, true)
ae128437
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
ae128437
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddMultipleLocalFileWithCache(c *check.C) {
05b8a1eb
 	name := "testbuildaddmultiplelocalfilewithcache"
da3d3b97
 	name2 := "testbuildaddmultiplelocalfilewithcache2"
05b8a1eb
 	dockerfile := `
 		FROM busybox
         MAINTAINER dockerio
         ADD foo Dockerfile /usr/lib/bla/
4603a725
 		RUN sh -c "[ $(cat /usr/lib/bla/foo) = "hello" ]"`
05b8a1eb
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"foo": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
05b8a1eb
 	}
04ef69a1
 	defer ctx.Close()
05b8a1eb
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
05b8a1eb
 	}
da3d3b97
 	id2, err := buildImageFromContext(name2, ctx, true)
05b8a1eb
 	if err != nil {
dc944ea7
 		c.Fatal(err)
05b8a1eb
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
05b8a1eb
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddLocalFileWithoutCache(c *check.C) {
ea3afdad
 	// local files are not owned by the correct user
 	testRequires(c, NotUserNamespace)
ae128437
 	name := "testbuildaddlocalfilewithoutcache"
da3d3b97
 	name2 := "testbuildaddlocalfilewithoutcache2"
ae128437
 	dockerfile := `
 		FROM busybox
         MAINTAINER dockerio
         ADD foo /usr/lib/bla/bar
4603a725
 		RUN sh -c "[ $(cat /usr/lib/bla/bar) = "hello" ]"`
ae128437
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"foo": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
04ef69a1
 	defer ctx.Close()
ae128437
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
da3d3b97
 	id2, err := buildImageFromContext(name2, ctx, false)
ae128437
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 == id2 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCopyDirButNotFile(c *check.C) {
cd329d06
 	name := "testbuildcopydirbutnotfile"
da3d3b97
 	name2 := "testbuildcopydirbutnotfile2"
4603a725
 
cd329d06
 	dockerfile := `
4603a725
         FROM ` + minimalBaseImage() + `
cd329d06
         COPY dir /tmp/`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"dir/foo": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
cd329d06
 	}
04ef69a1
 	defer ctx.Close()
cd329d06
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
cd329d06
 	}
 	// Check that adding file with similar name doesn't mess with cache
 	if err := ctx.Add("dir_file", "hello2"); err != nil {
dc944ea7
 		c.Fatal(err)
cd329d06
 	}
da3d3b97
 	id2, err := buildImageFromContext(name2, ctx, true)
cd329d06
 	if err != nil {
dc944ea7
 		c.Fatal(err)
cd329d06
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but wasn't")
cd329d06
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddCurrentDirWithCache(c *check.C) {
ae128437
 	name := "testbuildaddcurrentdirwithcache"
da3d3b97
 	name2 := name + "2"
 	name3 := name + "3"
 	name4 := name + "4"
ae128437
 	dockerfile := `
eed648ac
         FROM ` + minimalBaseImage() + `
ae128437
         MAINTAINER dockerio
         ADD . /usr/lib/bla`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"foo": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
04ef69a1
 	defer ctx.Close()
ae128437
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	// Check that adding file invalidate cache of "ADD ."
 	if err := ctx.Add("bar", "hello2"); err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
da3d3b97
 	id2, err := buildImageFromContext(name2, ctx, true)
ae128437
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 == id2 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 	// Check that changing file invalidate cache of "ADD ."
 	if err := ctx.Add("foo", "hello1"); err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
da3d3b97
 	id3, err := buildImageFromContext(name3, ctx, true)
ae128437
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id2 == id3 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
0e10507a
 	// Check that changing file to same content with different mtime does not
 	// invalidate cache of "ADD ."
ae128437
 	time.Sleep(1 * time.Second) // wait second because of mtime precision
 	if err := ctx.Add("foo", "hello1"); err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
da3d3b97
 	id4, err := buildImageFromContext(name4, ctx, true)
ae128437
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
0e10507a
 	if id3 != id4 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
ae128437
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddCurrentDirWithoutCache(c *check.C) {
ae128437
 	name := "testbuildaddcurrentdirwithoutcache"
da3d3b97
 	name2 := "testbuildaddcurrentdirwithoutcache2"
ae128437
 	dockerfile := `
eed648ac
         FROM ` + minimalBaseImage() + `
ae128437
         MAINTAINER dockerio
         ADD . /usr/lib/bla`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"foo": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
04ef69a1
 	defer ctx.Close()
ae128437
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
da3d3b97
 	id2, err := buildImageFromContext(name2, ctx, false)
ae128437
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 == id2 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddRemoteFileWithCache(c *check.C) {
eed648ac
 	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
ae128437
 	name := "testbuildaddremotefilewithcache"
 	server, err := fakeStorage(map[string]string{
 		"baz": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	defer server.Close()
2e95bb5f
 
ae128437
 	id1, err := buildImage(name,
 		fmt.Sprintf(`FROM scratch
         MAINTAINER dockerio
2e95bb5f
         ADD %s/baz /usr/lib/baz/quux`, server.URL()),
ae128437
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	id2, err := buildImage(name,
 		fmt.Sprintf(`FROM scratch
         MAINTAINER dockerio
2e95bb5f
         ADD %s/baz /usr/lib/baz/quux`, server.URL()),
ae128437
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
ae128437
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddRemoteFileWithoutCache(c *check.C) {
eed648ac
 	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
ae128437
 	name := "testbuildaddremotefilewithoutcache"
da3d3b97
 	name2 := "testbuildaddremotefilewithoutcache2"
ae128437
 	server, err := fakeStorage(map[string]string{
 		"baz": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	defer server.Close()
2e95bb5f
 
ae128437
 	id1, err := buildImage(name,
 		fmt.Sprintf(`FROM scratch
         MAINTAINER dockerio
2e95bb5f
         ADD %s/baz /usr/lib/baz/quux`, server.URL()),
ae128437
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
da3d3b97
 	id2, err := buildImage(name2,
ae128437
 		fmt.Sprintf(`FROM scratch
         MAINTAINER dockerio
2e95bb5f
         ADD %s/baz /usr/lib/baz/quux`, server.URL()),
ae128437
 		false)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 == id2 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddRemoteFileMTime(c *check.C) {
eed648ac
 	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
2e482c86
 	name := "testbuildaddremotefilemtime"
da3d3b97
 	name2 := name + "2"
 	name3 := name + "3"
 
2e95bb5f
 	files := map[string]string{"baz": "hello"}
 	server, err := fakeStorage(files)
2e482c86
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2e482c86
 	}
 	defer server.Close()
 
 	ctx, err := fakeContext(fmt.Sprintf(`FROM scratch
         MAINTAINER dockerio
2e95bb5f
         ADD %s/baz /usr/lib/baz/quux`, server.URL()), nil)
2e482c86
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2e482c86
 	}
 	defer ctx.Close()
 
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2e482c86
 	}
 
da3d3b97
 	id2, err := buildImageFromContext(name2, ctx, true)
2e482c86
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2e482c86
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but wasn't - #1")
2e482c86
 	}
 
0e10507a
 	// Now create a different server with same contents (causes different mtime)
 	// The cache should still be used
2e95bb5f
 
 	// allow some time for clock to pass as mtime precision is only 1s
 	time.Sleep(2 * time.Second)
 
 	server2, err := fakeStorage(files)
2e482c86
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2e482c86
 	}
2e95bb5f
 	defer server2.Close()
2e482c86
 
2e95bb5f
 	ctx2, err := fakeContext(fmt.Sprintf(`FROM scratch
         MAINTAINER dockerio
         ADD %s/baz /usr/lib/baz/quux`, server2.URL()), nil)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2e95bb5f
 	}
 	defer ctx2.Close()
 	id3, err := buildImageFromContext(name3, ctx2, true)
2e482c86
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2e482c86
 	}
0e10507a
 	if id1 != id3 {
 		c.Fatal("The cache should have been used but wasn't")
2e482c86
 	}
 }
 
ab121345
 func (s *DockerSuite) TestBuildAddLocalAndRemoteFilesWithCache(c *check.C) {
eed648ac
 	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
ae128437
 	name := "testbuildaddlocalandremotefilewithcache"
 	server, err := fakeStorage(map[string]string{
 		"baz": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	defer server.Close()
2e95bb5f
 
ae128437
 	ctx, err := fakeContext(fmt.Sprintf(`FROM scratch
         MAINTAINER dockerio
         ADD foo /usr/lib/bla/bar
2e95bb5f
         ADD %s/baz /usr/lib/baz/quux`, server.URL()),
ae128437
 		map[string]string{
 			"foo": "hello world",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	defer ctx.Close()
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	id2, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatal("The cache should have been used but hasn't.")
ae128437
 	}
 }
 
dc944ea7
 func testContextTar(c *check.C, compression archive.Compression) {
d302d929
 	ctx, err := fakeContext(
 		`FROM busybox
 ADD foo /foo
 CMD ["cat", "/foo"]`,
 		map[string]string{
 			"foo": "bar",
 		},
 	)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
d302d929
 	}
04ef69a1
 	defer ctx.Close()
d302d929
 	context, err := archive.Tar(ctx.Dir, compression)
edcb4145
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to build context tar: %v", err)
edcb4145
 	}
d302d929
 	name := "contexttar"
 	buildCmd := exec.Command(dockerBinary, "build", "-t", name, "-")
edcb4145
 	buildCmd.Stdin = context
 
b1e3c9e9
 	if out, _, err := runCommandWithOutput(buildCmd); err != nil {
dc944ea7
 		c.Fatalf("build failed to complete: %v %v", out, err)
edcb4145
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildContextTarGzip(c *check.C) {
 	testContextTar(c, archive.Gzip)
edcb4145
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildContextTarNoCompression(c *check.C) {
 	testContextTar(c, archive.Uncompressed)
edcb4145
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildNoContext(c *check.C) {
edcb4145
 	buildCmd := exec.Command(dockerBinary, "build", "-t", "nocontext", "-")
eed648ac
 	buildCmd.Stdin = strings.NewReader(
 		`FROM busybox
 		CMD ["echo", "ok"]`)
edcb4145
 
b1e3c9e9
 	if out, _, err := runCommandWithOutput(buildCmd); err != nil {
dc944ea7
 		c.Fatalf("build failed to complete: %v %v", out, err)
edcb4145
 	}
 
dc944ea7
 	if out, _ := dockerCmd(c, "run", "--rm", "nocontext"); out != "ok\n" {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, "ok")
edcb4145
 	}
 }
 
c024c9bd
 // TODO: TestCaching
ab121345
 func (s *DockerSuite) TestBuildAddLocalAndRemoteFilesWithoutCache(c *check.C) {
eed648ac
 	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
ae128437
 	name := "testbuildaddlocalandremotefilewithoutcache"
da3d3b97
 	name2 := "testbuildaddlocalandremotefilewithoutcache2"
ae128437
 	server, err := fakeStorage(map[string]string{
 		"baz": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	defer server.Close()
2e95bb5f
 
ae128437
 	ctx, err := fakeContext(fmt.Sprintf(`FROM scratch
         MAINTAINER dockerio
         ADD foo /usr/lib/bla/bar
2e95bb5f
         ADD %s/baz /usr/lib/baz/quux`, server.URL()),
ae128437
 		map[string]string{
 			"foo": "hello world",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	defer ctx.Close()
 	id1, err := buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
da3d3b97
 	id2, err := buildImageFromContext(name2, ctx, false)
ae128437
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ae128437
 	}
 	if id1 == id2 {
dc944ea7
 		c.Fatal("The cache should have been invalided but hasn't.")
ae128437
 	}
 }
c024c9bd
 
dc944ea7
 func (s *DockerSuite) TestBuildWithVolumeOwnership(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
c024c9bd
 	name := "testbuildimg"
 
 	_, err := buildImage(name,
 		`FROM busybox:latest
         RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test
         VOLUME /test`,
 		true)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
c024c9bd
 	}
 
5c295460
 	out, _ := dockerCmd(c, "run", "--rm", "testbuildimg", "ls", "-la", "/test")
c024c9bd
 
 	if expected := "drw-------"; !strings.Contains(out, expected) {
dc944ea7
 		c.Fatalf("expected %s received %s", expected, out)
c024c9bd
 	}
 
 	if expected := "daemon   daemon"; !strings.Contains(out, expected) {
dc944ea7
 		c.Fatalf("expected %s received %s", expected, out)
c024c9bd
 	}
 
 }
c5b82f5e
 
 // testing #1405 - config.Cmd does not get cleaned up if
 // utilizing cache
dc944ea7
 func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) {
c5b82f5e
 	name := "testbuildcmdcleanup"
 	if _, err := buildImage(name,
 		`FROM busybox
         RUN echo "hello"`,
 		true); err != nil {
dc944ea7
 		c.Fatal(err)
c5b82f5e
 	}
 
 	ctx, err := fakeContext(`FROM busybox
         RUN echo "hello"
         ADD foo /foo
         ENTRYPOINT ["/bin/echo"]`,
 		map[string]string{
 			"foo": "hello",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
c5b82f5e
 	}
04ef69a1
 	defer ctx.Close()
c5b82f5e
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
c5b82f5e
 	}
62a856e9
 	res := inspectField(c, name, "Config.Cmd")
1b6546b8
 	// Cmd must be cleaned up
53b0d626
 	if res != "[]" {
231d362d
 		c.Fatalf("Cmd %s, expected nil", res)
c5b82f5e
 	}
 }
686786f1
 
ab121345
 func (s *DockerSuite) TestBuildAddFileNotFound(c *check.C) {
62d97afa
 	name := "testbuildaddnotfound"
eed648ac
 	expected := "foo: no such file or directory"
 
 	if daemonPlatform == "windows" {
 		expected = "foo: The system cannot find the file specified"
 	}
 
 	ctx, err := fakeContext(`FROM `+minimalBaseImage()+`
62d97afa
         ADD foo /usr/local/bar`,
 		map[string]string{"bar": "hello"})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
62d97afa
 	}
04ef69a1
 	defer ctx.Close()
62d97afa
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
eed648ac
 		if !strings.Contains(err.Error(), expected) {
dc944ea7
 			c.Fatalf("Wrong error %v, must be about missing foo file or directory", err)
62d97afa
 		}
 	} else {
dc944ea7
 		c.Fatal("Error must not be nil")
62d97afa
 	}
 }
f1d7ed35
 
dc944ea7
 func (s *DockerSuite) TestBuildInheritance(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
f1d7ed35
 	name := "testbuildinheritance"
 
 	_, err := buildImage(name,
 		`FROM scratch
 		EXPOSE 2375`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
f1d7ed35
 	}
62a856e9
 	ports1 := inspectField(c, name, "Config.ExposedPorts")
f1d7ed35
 
 	_, err = buildImage(name,
 		fmt.Sprintf(`FROM %s
 		ENTRYPOINT ["/bin/echo"]`, name),
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
f1d7ed35
 	}
 
62a856e9
 	res := inspectField(c, name, "Config.Entrypoint")
53b0d626
 	if expected := "[/bin/echo]"; res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
f1d7ed35
 	}
62a856e9
 	ports2 := inspectField(c, name, "Config.ExposedPorts")
f1d7ed35
 	if ports1 != ports2 {
dc944ea7
 		c.Fatalf("Ports must be same: %s != %s", ports1, ports2)
f1d7ed35
 	}
 }
d3023f25
 
dc944ea7
 func (s *DockerSuite) TestBuildFails(c *check.C) {
d3023f25
 	name := "testbuildfails"
 	_, err := buildImage(name,
 		`FROM busybox
 		RUN sh -c "exit 23"`,
 		true)
 	if err != nil {
 		if !strings.Contains(err.Error(), "returned a non-zero code: 23") {
dc944ea7
 			c.Fatalf("Wrong error %v, must be about non-zero code 23", err)
d3023f25
 		}
 	} else {
dc944ea7
 		c.Fatal("Error must not be nil")
d3023f25
 	}
 }
08a10f93
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuild(c *check.C) {
2629e2ec
 	name := "testbuildonbuild"
 	_, err := buildImage(name,
 		`FROM busybox
 		ONBUILD RUN touch foobar`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2629e2ec
 	}
 	_, err = buildImage(name,
 		fmt.Sprintf(`FROM %s
 		RUN [ -f foobar ]`, name),
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
2629e2ec
 	}
 }
1e0e8636
 
cc42eeac
 // gh #2446
dc944ea7
 func (s *DockerSuite) TestBuildAddToSymlinkDest(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
cc42eeac
 	name := "testbuildaddtosymlinkdest"
 	ctx, err := fakeContext(`FROM busybox
         RUN mkdir /foo
         RUN ln -s /foo /bar
         ADD foo /bar/
         RUN [ -f /bar/foo ]
         RUN [ -f /foo/foo ]`,
 		map[string]string{
 			"foo": "hello",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
cc42eeac
 	}
 	defer ctx.Close()
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
cc42eeac
 	}
 }
03c5c193
 
dc944ea7
 func (s *DockerSuite) TestBuildEscapeWhitespace(c *check.C) {
e8e3dd32
 	name := "testbuildescapewhitespace"
03c5c193
 
 	_, err := buildImage(name, `
e8e3dd32
   # ESCAPE=\
03c5c193
   FROM busybox
   MAINTAINER "Docker \
 IO <io@\
 docker.com>"
   `, true)
5c295460
 	if err != nil {
 		c.Fatal(err)
 	}
03c5c193
 
62a856e9
 	res := inspectField(c, name, "Author")
03c5c193
 
d942c59b
 	if res != "\"Docker IO <io@docker.com>\"" {
dc944ea7
 		c.Fatalf("Parsed string did not match the escaped string. Got: %q", res)
03c5c193
 	}
 
 }
9189db3a
 
dc944ea7
 func (s *DockerSuite) TestBuildVerifyIntString(c *check.C) {
d942c59b
 	// Verify that strings that look like ints are still passed as strings
 	name := "testbuildstringing"
 
 	_, err := buildImage(name, `
   FROM busybox
   MAINTAINER 123
   `, true)
 
5c295460
 	if err != nil {
 		c.Fatal(err)
d942c59b
 	}
 
5c295460
 	out, _ := dockerCmd(c, "inspect", name)
 
d942c59b
 	if !strings.Contains(out, "\"123\"") {
dc944ea7
 		c.Fatalf("Output does not contain the int as a string:\n%s", out)
d942c59b
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignore(c *check.C) {
eed648ac
 	testRequires(c, DaemonIsLinux) // TODO Windows: This test passes on Windows,
 	// but currently adds a disproportionate amount of time for the value it has.
 	// Removing it from Windows CI for now, but this will be revisited in the
 	// TP5 timeframe when perf is better.
9189db3a
 	name := "testbuilddockerignore"
 	dockerfile := `
         FROM busybox
         ADD . /bla
eed648ac
 		RUN sh -c "[[ -f /bla/src/x.go ]]"
 		RUN sh -c "[[ -f /bla/Makefile ]]"
 		RUN sh -c "[[ ! -e /bla/src/_vendor ]]"
 		RUN sh -c "[[ ! -e /bla/.gitignore ]]"
 		RUN sh -c "[[ ! -e /bla/README.md ]]"
 		RUN sh -c "[[ ! -e /bla/dir/foo ]]"
 		RUN sh -c "[[ ! -e /bla/foo ]]"
 		RUN sh -c "[[ ! -e /bla/.git ]]"
 		RUN sh -c "[[ ! -e v.cc ]]"
 		RUN sh -c "[[ ! -e src/v.cc ]]"
 		RUN sh -c "[[ ! -e src/_vendor/v.cc ]]"`
9189db3a
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Makefile":         "all:",
 		".git/HEAD":        "ref: foo",
 		"src/x.go":         "package main",
 		"src/_vendor/v.go": "package main",
eddb14a4
 		"src/_vendor/v.cc": "package main",
 		"src/v.cc":         "package main",
 		"v.cc":             "package main",
6fd8e485
 		"dir/foo":          "",
9189db3a
 		".gitignore":       "",
 		"README.md":        "readme",
6fd8e485
 		".dockerignore": `
 .git
 pkg
 .gitignore
 src/_vendor
 *.md
eddb14a4
 **/*.cc
6fd8e485
 dir`,
9189db3a
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
9189db3a
 	}
6fd8e485
 	defer ctx.Close()
9189db3a
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
9189db3a
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoreCleanPaths(c *check.C) {
c0f0f5c9
 	name := "testbuilddockerignorecleanpaths"
 	dockerfile := `
         FROM busybox
         ADD . /tmp/
eed648ac
         RUN sh -c "(! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)"`
c0f0f5c9
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"foo":           "foo",
 		"foo2":          "foo2",
 		"dir1/foo":      "foo in dir1",
 		".dockerignore": "./foo\ndir1//foo\n./dir1/../foo2",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
c0f0f5c9
 	}
 	defer ctx.Close()
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
c0f0f5c9
 	}
 }
 
6fd8e485
 func (s *DockerSuite) TestBuildDockerignoreExceptions(c *check.C) {
eed648ac
 	testRequires(c, DaemonIsLinux) // TODO Windows: This test passes on Windows,
 	// but currently adds a disproportionate amount of time for the value it has.
 	// Removing it from Windows CI for now, but this will be revisited in the
 	// TP5 timeframe when perf is better.
6fd8e485
 	name := "testbuilddockerignoreexceptions"
 	dockerfile := `
         FROM busybox
         ADD . /bla
eed648ac
 		RUN sh -c "[[ -f /bla/src/x.go ]]"
 		RUN sh -c "[[ -f /bla/Makefile ]]"
 		RUN sh -c "[[ ! -e /bla/src/_vendor ]]"
 		RUN sh -c "[[ ! -e /bla/.gitignore ]]"
 		RUN sh -c "[[ ! -e /bla/README.md ]]"
 		RUN sh -c "[[  -e /bla/dir/dir/foo ]]"
 		RUN sh -c "[[ ! -e /bla/dir/foo1 ]]"
 		RUN sh -c "[[ -f /bla/dir/e ]]"
 		RUN sh -c "[[ -f /bla/dir/e-dir/foo ]]"
 		RUN sh -c "[[ ! -e /bla/foo ]]"
 		RUN sh -c "[[ ! -e /bla/.git ]]"
 		RUN sh -c "[[ -e /bla/dir/a.cc ]]"`
6fd8e485
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Makefile":         "all:",
 		".git/HEAD":        "ref: foo",
 		"src/x.go":         "package main",
 		"src/_vendor/v.go": "package main",
 		"dir/foo":          "",
 		"dir/foo1":         "",
 		"dir/dir/f1":       "",
 		"dir/dir/foo":      "",
 		"dir/e":            "",
 		"dir/e-dir/foo":    "",
 		".gitignore":       "",
 		"README.md":        "readme",
eddb14a4
 		"dir/a.cc":         "hello",
6fd8e485
 		".dockerignore": `
 .git
 pkg
 .gitignore
 src/_vendor
 *.md
 dir
 !dir/e*
eddb14a4
 !dir/dir/foo
 **/*.cc
 !**/*.cc`,
6fd8e485
 	})
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer ctx.Close()
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
 		c.Fatal(err)
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) {
9189db3a
 	name := "testbuilddockerignoredockerfile"
 	dockerfile := `
6d801a3c
         FROM busybox
 		ADD . /tmp/
eed648ac
 		RUN sh -c "! ls /tmp/Dockerfile"
6d801a3c
 		RUN ls /tmp/.dockerignore`
9189db3a
 	ctx, err := fakeContext(dockerfile, map[string]string{
6d801a3c
 		"Dockerfile":    dockerfile,
9189db3a
 		".dockerignore": "Dockerfile\n",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
9189db3a
 	}
f6e95ef3
 	defer ctx.Close()
 
6d801a3c
 	if _, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("Didn't ignore Dockerfile correctly:%s", err)
9189db3a
 	}
c0f0f5c9
 
 	// now try it with ./Dockerfile
 	ctx.Add(".dockerignore", "./Dockerfile\n")
6d801a3c
 	if _, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("Didn't ignore ./Dockerfile correctly:%s", err)
c0f0f5c9
 	}
 
9189db3a
 }
1d4862b7
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) {
eb3ea3b4
 	name := "testbuilddockerignoredockerfile"
 	dockerfile := `
         FROM busybox
 		ADD . /tmp/
 		RUN ls /tmp/Dockerfile
eed648ac
 		RUN sh -c "! ls /tmp/MyDockerfile"
eb3ea3b4
 		RUN ls /tmp/.dockerignore`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Dockerfile":    "Should not use me",
 		"MyDockerfile":  dockerfile,
 		".dockerignore": "MyDockerfile\n",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
eb3ea3b4
 	}
f6e95ef3
 	defer ctx.Close()
 
eb3ea3b4
 	if _, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("Didn't ignore MyDockerfile correctly:%s", err)
eb3ea3b4
 	}
 
 	// now try it with ./MyDockerfile
 	ctx.Add(".dockerignore", "./MyDockerfile\n")
 	if _, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("Didn't ignore ./MyDockerfile correctly:%s", err)
eb3ea3b4
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoringDockerignore(c *check.C) {
6d801a3c
 	name := "testbuilddockerignoredockerignore"
 	dockerfile := `
         FROM busybox
 		ADD . /tmp/
eed648ac
 		RUN sh -c "! ls /tmp/.dockerignore"
6d801a3c
 		RUN ls /tmp/Dockerfile`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Dockerfile":    dockerfile,
 		".dockerignore": ".dockerignore\n",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
6d801a3c
 	}
04ef69a1
 	defer ctx.Close()
6d801a3c
 	if _, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("Didn't ignore .dockerignore correctly:%s", err)
6d801a3c
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoreTouchDockerfile(c *check.C) {
6d801a3c
 	var id1 string
 	var id2 string
 
 	name := "testbuilddockerignoretouchdockerfile"
 	dockerfile := `
         FROM busybox
 		ADD . /tmp/`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Dockerfile":    dockerfile,
 		".dockerignore": "Dockerfile\n",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
6d801a3c
 	}
04ef69a1
 	defer ctx.Close()
6d801a3c
 
 	if id1, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("Didn't build it correctly:%s", err)
6d801a3c
 	}
 
 	if id2, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("Didn't build it correctly:%s", err)
6d801a3c
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatalf("Didn't use the cache - 1")
6d801a3c
 	}
 
 	// Now make sure touching Dockerfile doesn't invalidate the cache
 	if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
dc944ea7
 		c.Fatalf("Didn't add Dockerfile: %s", err)
6d801a3c
 	}
 	if id2, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("Didn't build it correctly:%s", err)
6d801a3c
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatalf("Didn't use the cache - 2")
6d801a3c
 	}
 
 	// One more time but just 'touch' it instead of changing the content
 	if err = ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
dc944ea7
 		c.Fatalf("Didn't add Dockerfile: %s", err)
6d801a3c
 	}
 	if id2, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("Didn't build it correctly:%s", err)
6d801a3c
 	}
 	if id1 != id2 {
dc944ea7
 		c.Fatalf("Didn't use the cache - 3")
6d801a3c
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerignoringWholeDir(c *check.C) {
7d97a5f4
 	name := "testbuilddockerignorewholedir"
 	dockerfile := `
         FROM busybox
 		COPY . /
eed648ac
 		RUN sh -c "[[ ! -e /.gitignore ]]"
 		RUN sh -c "[[ -f /Makefile ]]"`
7d97a5f4
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Dockerfile":    "FROM scratch",
 		"Makefile":      "all:",
6fd8e485
 		".gitignore":    "",
7d97a5f4
 		".dockerignore": ".*\n",
 	})
82ea6ed2
 	c.Assert(err, check.IsNil)
7d97a5f4
 	defer ctx.Close()
82ea6ed2
 	if _, err = buildImageFromContext(name, ctx, true); err != nil {
 		c.Fatal(err)
 	}
 
 	c.Assert(ctx.Add(".dockerfile", "*"), check.IsNil)
 	if _, err = buildImageFromContext(name, ctx, true); err != nil {
 		c.Fatal(err)
 	}
 
 	c.Assert(ctx.Add(".dockerfile", "."), check.IsNil)
 	if _, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
7d97a5f4
 	}
82ea6ed2
 
 	c.Assert(ctx.Add(".dockerfile", "?"), check.IsNil)
7d97a5f4
 	if _, err = buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
7d97a5f4
 	}
 }
 
82ea6ed2
 func (s *DockerSuite) TestBuildDockerignoringBadExclusion(c *check.C) {
eddb14a4
 	name := "testbuilddockerignorebadexclusion"
82ea6ed2
 	dockerfile := `
         FROM busybox
 		COPY . /
eed648ac
 		RUN sh -c "[[ ! -e /.gitignore ]]"
 		RUN sh -c "[[ -f /Makefile ]]"`
82ea6ed2
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Dockerfile":    "FROM scratch",
 		"Makefile":      "all:",
 		".gitignore":    "",
 		".dockerignore": "!\n",
 	})
 	c.Assert(err, check.IsNil)
 	defer ctx.Close()
 	if _, err = buildImageFromContext(name, ctx, true); err == nil {
 		c.Fatalf("Build was supposed to fail but didn't")
 	}
 
 	if err.Error() != "failed to build the image: Error checking context: 'Illegal exclusion pattern: !'.\n" {
 		c.Fatalf("Incorrect output, got:%q", err.Error())
 	}
 }
 
eddb14a4
 func (s *DockerSuite) TestBuildDockerignoringWildTopDir(c *check.C) {
 	dockerfile := `
         FROM busybox
 		COPY . /
eed648ac
 		RUN sh -c "[[ ! -e /.dockerignore ]]"
 		RUN sh -c "[[ ! -e /Dockerfile ]]"
 		RUN sh -c "[[ ! -e /file1 ]]"
 		RUN sh -c "[[ ! -e /dir ]]"`
eddb14a4
 
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Dockerfile": "FROM scratch",
 		"file1":      "",
 		"dir/dfile1": "",
 	})
 	c.Assert(err, check.IsNil)
 	defer ctx.Close()
 
 	// All of these should result in ignoring all files
 	for _, variant := range []string{"**", "**/", "**/**", "*"} {
 		ctx.Add(".dockerignore", variant)
 		_, err = buildImageFromContext("noname", ctx, true)
 		c.Assert(err, check.IsNil, check.Commentf("variant: %s", variant))
 	}
 }
 
 func (s *DockerSuite) TestBuildDockerignoringWildDirs(c *check.C) {
eed648ac
 	testRequires(c, DaemonIsLinux) // TODO Windows: Fix this test; also perf
eddb14a4
 
 	dockerfile := `
         FROM busybox
 		COPY . /
eed648ac
 		#RUN sh -c "[[ -e /.dockerignore ]]"
c77bb28d
 		RUN sh -c "[[ -e /Dockerfile ]]           && \
 		           [[ ! -e /file0 ]]              && \
 		           [[ ! -e /dir1/file0 ]]         && \
 		           [[ ! -e /dir2/file0 ]]         && \
 		           [[ ! -e /file1 ]]              && \
 		           [[ ! -e /dir1/file1 ]]         && \
 		           [[ ! -e /dir1/dir2/file1 ]]    && \
 		           [[ ! -e /dir1/file2 ]]         && \
 		           [[   -e /dir1/dir2/file2 ]]    && \
 		           [[ ! -e /dir1/dir2/file4 ]]    && \
 		           [[ ! -e /dir1/dir2/file5 ]]    && \
 		           [[ ! -e /dir1/dir2/file6 ]]    && \
 		           [[ ! -e /dir1/dir3/file7 ]]    && \
 		           [[ ! -e /dir1/dir3/file8 ]]    && \
 		           [[   -e /dir1/dir3 ]]          && \
 		           [[   -e /dir1/dir4 ]]          && \
 		           [[ ! -e 'dir1/dir5/fileAA' ]]  && \
 		           [[   -e 'dir1/dir5/fileAB' ]]  && \
 		           [[   -e 'dir1/dir5/fileB' ]]"   # "." in pattern means nothing
eddb14a4
 
 		RUN echo all done!`
 
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Dockerfile":      "FROM scratch",
 		"file0":           "",
 		"dir1/file0":      "",
 		"dir1/dir2/file0": "",
 
 		"file1":           "",
 		"dir1/file1":      "",
 		"dir1/dir2/file1": "",
 
 		"dir1/file2":      "",
 		"dir1/dir2/file2": "", // remains
 
 		"dir1/dir2/file4": "",
 		"dir1/dir2/file5": "",
 		"dir1/dir2/file6": "",
 		"dir1/dir3/file7": "",
 		"dir1/dir3/file8": "",
 		"dir1/dir4/file9": "",
 
 		"dir1/dir5/fileAA": "",
 		"dir1/dir5/fileAB": "",
 		"dir1/dir5/fileB":  "",
 
 		".dockerignore": `
 **/file0
 **/*file1
 **/dir1/file2
 dir1/**/file4
 **/dir2/file5
 **/dir1/dir2/file6
 dir1/dir3/**
 **/dir4/**
 **/file?A
 **/file\?B
 **/dir5/file.
 `,
 	})
 	c.Assert(err, check.IsNil)
 	defer ctx.Close()
 
 	_, err = buildImageFromContext("noname", ctx, true)
 	c.Assert(err, check.IsNil)
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildLineBreak(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildlinebreak"
 	_, err := buildImage(name,
 		`FROM  busybox
 RUN    sh -c 'echo root:testpass \
 	> /tmp/passwd'
 RUN    mkdir -p /var/run/sshd
eed648ac
 RUN    sh -c "[ "$(cat /tmp/passwd)" = "root:testpass" ]"
 RUN    sh -c "[ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]"`,
1d4862b7
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1d4862b7
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEOLInLine(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildeolinline"
 	_, err := buildImage(name,
 		`FROM   busybox
 RUN    sh -c 'echo root:testpass > /tmp/passwd'
 RUN    echo "foo \n bar"; echo "baz"
 RUN    mkdir -p /var/run/sshd
eed648ac
 RUN    sh -c "[ "$(cat /tmp/passwd)" = "root:testpass" ]"
 RUN    sh -c "[ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]"`,
1d4862b7
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1d4862b7
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCommentsShebangs(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildcomments"
 	_, err := buildImage(name,
 		`FROM busybox
 # This is an ordinary comment.
 RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh
 RUN [ ! -x /hello.sh ]
 # comment with line break \
 RUN chmod +x /hello.sh
 RUN [ -x /hello.sh ]
 RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ]
 RUN [ "$(/hello.sh)" = "hello world" ]`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1d4862b7
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildUsersAndGroups(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildusers"
 	_, err := buildImage(name,
 		`FROM busybox
 
 # Make sure our defaults work
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ]
 
 # TODO decide if "args.user = strconv.Itoa(syscall.Getuid())" is acceptable behavior for changeUser in sysvinit instead of "return nil" when "USER" isn't specified (so that we get the proper group list even if that is the empty list, even in the default case of not supplying an explicit USER to run as, which implies USER 0)
 USER root
 RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ]
 
 # Setup dockerio user and group
deeb5c95
 RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd && \
 	echo 'dockerio:x:1001:' >> /etc/group
1d4862b7
 
 # Make sure we can switch to our user and all the information is exactly as we expect it to be
 USER dockerio
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 
 # Switch back to root and double check that worked exactly as we might expect it to
 USER root
deeb5c95
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] && \
 	# Add a "supplementary" group for our dockerio user \
 	echo 'supplementary:x:1002:dockerio' >> /etc/group
1d4862b7
 
 # ... and then go verify that we get it like we expect
 USER dockerio
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ]
 USER 1001
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ]
 
 # super test the new "user:group" syntax
 USER dockerio:dockerio
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 USER 1001:dockerio
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 USER dockerio:1001
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 USER 1001:1001
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
 USER dockerio:supplementary
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
 USER dockerio:1002
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
 USER 1001:supplementary
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
 USER 1001:1002
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
 
 # make sure unknown uid/gid still works properly
 USER 1042:1043
 RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1d4862b7
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvUsage(c *check.C) {
ea3afdad
 	// /docker/world/hello is not owned by the correct user
 	testRequires(c, NotUserNamespace)
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildenvusage"
 	dockerfile := `FROM busybox
4e74cd49
 ENV    HOME /root
cb51681a
 ENV    PATH $HOME/bin:$PATH
 ENV    PATH /tmp:$PATH
 RUN    [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ]
1d4862b7
 ENV    FOO /foo/baz
 ENV    BAR /bar
 ENV    BAZ $BAR
 ENV    FOOPATH $PATH:$FOO
 RUN    [ "$BAR" = "$BAZ" ]
 RUN    [ "$FOOPATH" = "$PATH:/foo/baz" ]
 ENV	   FROM hello/docker/world
 ENV    TO /docker/world/hello
 ADD    $FROM $TO
cb51681a
 RUN    [ "$(cat $TO)" = "hello" ]
ed3bc3b9
 ENV    abc=def
 ENV    ghi=$abc
 RUN    [ "$ghi" = "def" ]
cb51681a
 `
1d4862b7
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"hello/docker/world": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1d4862b7
 	}
db7fded1
 	defer ctx.Close()
 
1d4862b7
 	_, err = buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1d4862b7
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) {
ea3afdad
 	// /docker/world/hello is not owned by the correct user
 	testRequires(c, NotUserNamespace)
f9a3558a
 	testRequires(c, DaemonIsLinux)
1314e158
 	name := "testbuildenvusage2"
 	dockerfile := `FROM busybox
74fafa5d
 ENV    abc=def def="hello world"
 RUN    [ "$abc,$def" = "def,hello world" ]
 ENV    def=hello\ world v1=abc v2="hi there" v3='boogie nights' v4="with'quotes too"
 RUN    [ "$def,$v1,$v2,$v3,$v4" = "hello world,abc,hi there,boogie nights,with'quotes too" ]
1314e158
 ENV    abc=zzz FROM=hello/docker/world
 ENV    abc=zzz TO=/docker/world/hello
 ADD    $FROM $TO
74fafa5d
 RUN    [ "$abc,$(cat $TO)" = "zzz,hello" ]
1314e158
 ENV    abc 'yyy'
6d66e3e7
 RUN    [ $abc = 'yyy' ]
1314e158
 ENV    abc=
 RUN    [ "$abc" = "" ]
ed3bc3b9
 
 # use grep to make sure if the builder substitutes \$foo by mistake
 # we don't get a false positive
 ENV    abc=\$foo
 RUN    [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo)
 ENV    abc \$foo
 RUN    [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo)
 
74fafa5d
 ENV    abc=\'foo\' abc2=\"foo\"
 RUN    [ "$abc,$abc2" = "'foo',\"foo\"" ]
ed3bc3b9
 ENV    abc "foo"
6d66e3e7
 RUN    [ "$abc" = "foo" ]
ed3bc3b9
 ENV    abc 'foo'
6d66e3e7
 RUN    [ "$abc" = 'foo' ]
ed3bc3b9
 ENV    abc \'foo\'
6d66e3e7
 RUN    [ "$abc" = "'foo'" ]
ed3bc3b9
 ENV    abc \"foo\"
6d66e3e7
 RUN    [ "$abc" = '"foo"' ]
 
39908fc6
 ENV    abc=ABC
 RUN    [ "$abc" = "ABC" ]
74fafa5d
 ENV    def1=${abc:-DEF} def2=${ccc:-DEF}
 ENV    def3=${ccc:-${def2}xx} def4=${abc:+ALT} def5=${def2:+${abc}:} def6=${ccc:-\$abc:} def7=${ccc:-\${abc}:}
 RUN    [ "$def1,$def2,$def3,$def4,$def5,$def6,$def7" = 'ABC,DEF,DEFxx,ALT,ABC:,$abc:,${abc:}' ]
39908fc6
 ENV    mypath=${mypath:+$mypath:}/home
 ENV    mypath=${mypath:+$mypath:}/away
 RUN    [ "$mypath" = '/home:/away' ]
 
6d66e3e7
 ENV    e1=bar
74fafa5d
 ENV    e2=$e1 e3=$e11 e4=\$e1 e5=\$e11
6d66e3e7
 RUN    [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ]
 
 ENV    ee1 bar
 ENV    ee2 $ee1
 ENV    ee3 $ee11
 ENV    ee4 \$ee1
 ENV    ee5 \$ee11
 RUN    [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ]
 
74fafa5d
 ENV    eee1="foo" eee2='foo'
6d66e3e7
 ENV    eee3 "foo"
 ENV    eee4 'foo'
 RUN    [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ]
 
1314e158
 `
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"hello/docker/world": "hello",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1314e158
 	}
f6e95ef3
 	defer ctx.Close()
 
1314e158
 	_, err = buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1314e158
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddScript(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1d4862b7
 	name := "testbuildaddscript"
 	dockerfile := `
 FROM busybox
 ADD test /test
 RUN ["chmod","+x","/test"]
 RUN ["/test"]
 RUN [ "$(cat /testfile)" = 'test!' ]`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"test": "#!/bin/sh\necho 'test!' > /testfile",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1d4862b7
 	}
db7fded1
 	defer ctx.Close()
 
1d4862b7
 	_, err = buildImageFromContext(name, ctx, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
1d4862b7
 	}
 }
cfa4999d
 
dc944ea7
 func (s *DockerSuite) TestBuildAddTar(c *check.C) {
ea3afdad
 	// /test/foo is not owned by the correct user
 	testRequires(c, NotUserNamespace)
fc2631b4
 	name := "testbuildaddtar"
cfa4999d
 
24c00c85
 	ctx := func() *FakeContext {
5d8e80ba
 		dockerfile := `
 FROM busybox
 ADD test.tar /
 RUN cat /test/foo | grep Hi
 ADD test.tar /test.tar
 RUN cat /test.tar/test/foo | grep Hi
 ADD test.tar /unlikely-to-exist
 RUN cat /unlikely-to-exist/test/foo | grep Hi
 ADD test.tar /unlikely-to-exist-trailing-slash/
 RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi
0adcce10
 RUN sh -c "mkdir /existing-directory" #sh -c is needed on Windows to use the correct mkdir
5d8e80ba
 ADD test.tar /existing-directory
 RUN cat /existing-directory/test/foo | grep Hi
 ADD test.tar /existing-directory-trailing-slash/
 RUN cat /existing-directory-trailing-slash/test/foo | grep Hi`
24c00c85
 		tmpDir, err := ioutil.TempDir("", "fake-context")
b616b8a1
 		c.Assert(err, check.IsNil)
24c00c85
 		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to create test.tar archive: %v", err)
cfa4999d
 		}
24c00c85
 		defer testTar.Close()
 
 		tw := tar.NewWriter(testTar)
 
 		if err := tw.WriteHeader(&tar.Header{
 			Name: "test/foo",
 			Size: 2,
 		}); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file header: %v", err)
24c00c85
 		}
 		if _, err := tw.Write([]byte("Hi")); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file content: %v", err)
24c00c85
 		}
 		if err := tw.Close(); err != nil {
dc944ea7
 			c.Fatalf("failed to close tar archive: %v", err)
cfa4999d
 		}
 
5d8e80ba
 		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
dc944ea7
 			c.Fatalf("failed to open destination dockerfile: %v", err)
24c00c85
 		}
44ffb199
 		return fakeContextFromDir(tmpDir)
24c00c85
 	}()
db7fded1
 	defer ctx.Close()
24c00c85
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("build failed to complete for TestBuildAddTar: %v", err)
cfa4999d
 	}
30519330
 
cfa4999d
 }
5b0d4cf2
 
3243e504
 func (s *DockerSuite) TestBuildAddBrokenTar(c *check.C) {
 	name := "testbuildaddbrokentar"
 
 	ctx := func() *FakeContext {
 		dockerfile := `
 FROM busybox
 ADD test.tar /`
 		tmpDir, err := ioutil.TempDir("", "fake-context")
 		c.Assert(err, check.IsNil)
 		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
 		if err != nil {
 			c.Fatalf("failed to create test.tar archive: %v", err)
 		}
 		defer testTar.Close()
 
 		tw := tar.NewWriter(testTar)
 
 		if err := tw.WriteHeader(&tar.Header{
 			Name: "test/foo",
 			Size: 2,
 		}); err != nil {
 			c.Fatalf("failed to write tar file header: %v", err)
 		}
 		if _, err := tw.Write([]byte("Hi")); err != nil {
 			c.Fatalf("failed to write tar file content: %v", err)
 		}
 		if err := tw.Close(); err != nil {
 			c.Fatalf("failed to close tar archive: %v", err)
 		}
 
 		// Corrupt the tar by removing one byte off the end
 		stat, err := testTar.Stat()
 		if err != nil {
 			c.Fatalf("failed to stat tar archive: %v", err)
 		}
 		if err := testTar.Truncate(stat.Size() - 1); err != nil {
 			c.Fatalf("failed to truncate tar archive: %v", err)
 		}
 
 		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
 			c.Fatalf("failed to open destination dockerfile: %v", err)
 		}
 		return fakeContextFromDir(tmpDir)
 	}()
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(name, ctx, true); err == nil {
 		c.Fatalf("build should have failed for TestBuildAddBrokenTar")
 	}
 }
 
 func (s *DockerSuite) TestBuildAddNonTar(c *check.C) {
 	name := "testbuildaddnontar"
 
 	// Should not try to extract test.tar
 	ctx, err := fakeContext(`
 		FROM busybox
 		ADD test.tar /
 		RUN test -f /test.tar`,
 		map[string]string{"test.tar": "not_a_tar_file"})
 
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
 		c.Fatalf("build failed for TestBuildAddNonTar")
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddTarXz(c *check.C) {
ea3afdad
 	// /test/foo is not owned by the correct user
 	testRequires(c, NotUserNamespace)
f9a3558a
 	testRequires(c, DaemonIsLinux)
e4ba82d5
 	name := "testbuildaddtarxz"
 
 	ctx := func() *FakeContext {
 		dockerfile := `
 			FROM busybox
 			ADD test.tar.xz /
 			RUN cat /test/foo | grep Hi`
 		tmpDir, err := ioutil.TempDir("", "fake-context")
b616b8a1
 		c.Assert(err, check.IsNil)
e4ba82d5
 		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to create test.tar archive: %v", err)
e4ba82d5
 		}
 		defer testTar.Close()
 
 		tw := tar.NewWriter(testTar)
 
 		if err := tw.WriteHeader(&tar.Header{
 			Name: "test/foo",
 			Size: 2,
 		}); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file header: %v", err)
e4ba82d5
 		}
 		if _, err := tw.Write([]byte("Hi")); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file content: %v", err)
e4ba82d5
 		}
 		if err := tw.Close(); err != nil {
dc944ea7
 			c.Fatalf("failed to close tar archive: %v", err)
e4ba82d5
 		}
5c295460
 
2f53820c
 		xzCompressCmd := exec.Command("xz", "-k", "test.tar")
e4ba82d5
 		xzCompressCmd.Dir = tmpDir
 		out, _, err := runCommandWithOutput(xzCompressCmd)
 		if err != nil {
dc944ea7
 			c.Fatal(err, out)
e4ba82d5
 		}
 
 		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
dc944ea7
 			c.Fatalf("failed to open destination dockerfile: %v", err)
e4ba82d5
 		}
44ffb199
 		return fakeContextFromDir(tmpDir)
e4ba82d5
 	}()
 
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err)
e4ba82d5
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
e4ba82d5
 	name := "testbuildaddtarxzgz"
 
 	ctx := func() *FakeContext {
 		dockerfile := `
 			FROM busybox
 			ADD test.tar.xz.gz /
 			RUN ls /test.tar.xz.gz`
 		tmpDir, err := ioutil.TempDir("", "fake-context")
b616b8a1
 		c.Assert(err, check.IsNil)
e4ba82d5
 		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
 		if err != nil {
dc944ea7
 			c.Fatalf("failed to create test.tar archive: %v", err)
e4ba82d5
 		}
 		defer testTar.Close()
 
 		tw := tar.NewWriter(testTar)
 
 		if err := tw.WriteHeader(&tar.Header{
 			Name: "test/foo",
 			Size: 2,
 		}); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file header: %v", err)
e4ba82d5
 		}
 		if _, err := tw.Write([]byte("Hi")); err != nil {
dc944ea7
 			c.Fatalf("failed to write tar file content: %v", err)
e4ba82d5
 		}
 		if err := tw.Close(); err != nil {
dc944ea7
 			c.Fatalf("failed to close tar archive: %v", err)
e4ba82d5
 		}
 
2f53820c
 		xzCompressCmd := exec.Command("xz", "-k", "test.tar")
e4ba82d5
 		xzCompressCmd.Dir = tmpDir
 		out, _, err := runCommandWithOutput(xzCompressCmd)
 		if err != nil {
dc944ea7
 			c.Fatal(err, out)
e4ba82d5
 		}
 
 		gzipCompressCmd := exec.Command("gzip", "test.tar.xz")
 		gzipCompressCmd.Dir = tmpDir
 		out, _, err = runCommandWithOutput(gzipCompressCmd)
 		if err != nil {
dc944ea7
 			c.Fatal(err, out)
e4ba82d5
 		}
 
 		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
dc944ea7
 			c.Fatalf("failed to open destination dockerfile: %v", err)
e4ba82d5
 		}
44ffb199
 		return fakeContextFromDir(tmpDir)
e4ba82d5
 	}()
 
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatalf("build failed to complete for TestBuildAddTarXz: %v", err)
e4ba82d5
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildFromGIT(c *check.C) {
5b0d4cf2
 	name := "testbuildfromgit"
6b3c9281
 	git, err := newFakeGit("repo", map[string]string{
5b0d4cf2
 		"Dockerfile": `FROM busybox
 					ADD first /first
 					RUN [ -f /first ]
 					MAINTAINER docker`,
 		"first": "test git data",
44ffb199
 	}, true)
5b0d4cf2
 	if err != nil {
dc944ea7
 		c.Fatal(err)
5b0d4cf2
 	}
 	defer git.Close()
 
 	_, err = buildImageFromPath(name, git.RepoURL, true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
5b0d4cf2
 	}
62a856e9
 	res := inspectField(c, name, "Author")
5b0d4cf2
 	if res != "docker" {
dc944ea7
 		c.Fatalf("Maintainer should be docker, got %s", res)
5b0d4cf2
 	}
 }
1b6546b8
 
49fd83a2
 func (s *DockerSuite) TestBuildFromGITWithContext(c *check.C) {
 	name := "testbuildfromgit"
6b3c9281
 	git, err := newFakeGit("repo", map[string]string{
49fd83a2
 		"docker/Dockerfile": `FROM busybox
 					ADD first /first
 					RUN [ -f /first ]
 					MAINTAINER docker`,
 		"docker/first": "test git data",
 	}, true)
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer git.Close()
 
 	u := fmt.Sprintf("%s#master:docker", git.RepoURL)
 	_, err = buildImageFromPath(name, u, true)
 	if err != nil {
 		c.Fatal(err)
 	}
62a856e9
 	res := inspectField(c, name, "Author")
49fd83a2
 	if res != "docker" {
 		c.Fatalf("Maintainer should be docker, got %s", res)
 	}
 }
 
d8835404
 func (s *DockerSuite) TestBuildFromGITwithF(c *check.C) {
 	name := "testbuildfromgitwithf"
 	git, err := newFakeGit("repo", map[string]string{
 		"myApp/myDockerfile": `FROM busybox
 					RUN echo hi from Dockerfile`,
 	}, true)
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer git.Close()
 
693ba98c
 	out, _, err := dockerCmdWithError("build", "-t", name, "--no-cache", "-f", "myApp/myDockerfile", git.RepoURL)
d8835404
 	if err != nil {
 		c.Fatalf("Error on build. Out: %s\nErr: %v", out, err)
 	}
 
 	if !strings.Contains(out, "hi from Dockerfile") {
 		c.Fatalf("Missing expected output, got:\n%s", out)
 	}
 }
 
d48bface
 func (s *DockerSuite) TestBuildFromRemoteTarball(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
d48bface
 	name := "testbuildfromremotetarball"
 
 	buffer := new(bytes.Buffer)
 	tw := tar.NewWriter(buffer)
 	defer tw.Close()
 
 	dockerfile := []byte(`FROM busybox
 					MAINTAINER docker`)
 	if err := tw.WriteHeader(&tar.Header{
 		Name: "Dockerfile",
 		Size: int64(len(dockerfile)),
 	}); err != nil {
 		c.Fatalf("failed to write tar file header: %v", err)
 	}
 	if _, err := tw.Write(dockerfile); err != nil {
 		c.Fatalf("failed to write tar file content: %v", err)
 	}
 	if err := tw.Close(); err != nil {
 		c.Fatalf("failed to close tar archive: %v", err)
 	}
 
 	server, err := fakeBinaryStorage(map[string]*bytes.Buffer{
 		"testT.tar": buffer,
 	})
 	c.Assert(err, check.IsNil)
 
 	defer server.Close()
 
 	_, err = buildImageFromPath(name, server.URL()+"/testT.tar", true)
 	c.Assert(err, check.IsNil)
 
62a856e9
 	res := inspectField(c, name, "Author")
d48bface
 
 	if res != "docker" {
 		c.Fatalf("Maintainer should be docker, got %s", res)
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) {
1b6546b8
 	name := "testbuildcmdcleanuponentrypoint"
 	if _, err := buildImage(name,
0adcce10
 		`FROM `+minimalBaseImage()+`
1b6546b8
         CMD ["test"]
 		ENTRYPOINT ["echo"]`,
 		true); err != nil {
dc944ea7
 		c.Fatal(err)
1b6546b8
 	}
 	if _, err := buildImage(name,
 		fmt.Sprintf(`FROM %s
 		ENTRYPOINT ["cat"]`, name),
 		true); err != nil {
dc944ea7
 		c.Fatal(err)
1b6546b8
 	}
62a856e9
 	res := inspectField(c, name, "Config.Cmd")
53b0d626
 	if res != "[]" {
231d362d
 		c.Fatalf("Cmd %s, expected nil", res)
1b6546b8
 	}
231d362d
 
62a856e9
 	res = inspectField(c, name, "Config.Entrypoint")
53b0d626
 	if expected := "[cat]"; res != expected {
dc944ea7
 		c.Fatalf("Entrypoint %s, expected %s", res, expected)
1b6546b8
 	}
 }
ac107995
 
dc944ea7
 func (s *DockerSuite) TestBuildClearCmd(c *check.C) {
ac107995
 	name := "testbuildclearcmd"
 	_, err := buildImage(name,
0adcce10
 		`From `+minimalBaseImage()+`
ac107995
    ENTRYPOINT ["/bin/bash"]
    CMD []`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
ac107995
 	}
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Cmd")
ac107995
 	if res != "[]" {
dc944ea7
 		c.Fatalf("Cmd %s, expected %s", res, "[]")
ac107995
 	}
 }
d1613e1d
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyCmd(c *check.C) {
9185a0a6
 	// Windows Server 2016 RS1 builds load the windowsservercore image from a tar rather than
 	// a .WIM file, and the tar layer has the default CMD set (same as the Linux ubuntu image),
 	// where-as the TP5 .WIM had a blank CMD. Hence this test is not applicable on RS1 or later
 	// builds
 	if daemonPlatform == "windows" && windowsDaemonKV >= 14375 {
 		c.Skip("Not applicable on Windows RS1 or later builds")
 	}
 
d1613e1d
 	name := "testbuildemptycmd"
0adcce10
 	if _, err := buildImage(name, "FROM "+minimalBaseImage()+"\nMAINTAINER quux\n", true); err != nil {
dc944ea7
 		c.Fatal(err)
d1613e1d
 	}
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Cmd")
d1613e1d
 	if res != "null" {
dc944ea7
 		c.Fatalf("Cmd %s, expected %s", res, "null")
d1613e1d
 	}
 }
8edacc67
 
dc944ea7
 func (s *DockerSuite) TestBuildOnBuildOutput(c *check.C) {
8edacc67
 	name := "testbuildonbuildparent"
 	if _, err := buildImage(name, "FROM busybox\nONBUILD RUN echo foo\n", true); err != nil {
dc944ea7
 		c.Fatal(err)
8edacc67
 	}
 
 	_, out, err := buildImageWithOut(name, "FROM "+name+"\nMAINTAINER quux\n", true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
8edacc67
 	}
 
66201029
 	if !strings.Contains(out, "# Executing 1 build trigger") {
 		c.Fatal("failed to find the build trigger output", out)
8edacc67
 	}
 }
8833d800
 
dc944ea7
 func (s *DockerSuite) TestBuildInvalidTag(c *check.C) {
b80fae73
 	name := "abcd:" + stringutils.GenerateRandomAlphaOnlyString(200)
0adcce10
 	_, out, err := buildImageWithOut(name, "FROM "+minimalBaseImage()+"\nMAINTAINER quux\n", true)
927b334e
 	// if the error doesn't check for illegal tag name, or the image is built
8833d800
 	// then this should fail
15d84a3a
 	if !strings.Contains(out, "Error parsing reference") || strings.Contains(out, "Sending build context to Docker daemon") {
dc944ea7
 		c.Fatalf("failed to stop before building. Error: %s, Output: %s", err, out)
8833d800
 	}
 }
9f142bf9
 
dc944ea7
 func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) {
9f142bf9
 	name := "testbuildcmdshc"
 	if _, err := buildImage(name, "FROM busybox\nCMD echo cmd\n", true); err != nil {
dc944ea7
 		c.Fatal(err)
9f142bf9
 	}
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Cmd")
9f142bf9
 
 	expected := `["/bin/sh","-c","echo cmd"]`
0adcce10
 	if daemonPlatform == "windows" {
 		expected = `["cmd","/S","/C","echo cmd"]`
 	}
9f142bf9
 
 	if res != expected {
dc944ea7
 		c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
9f142bf9
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCmdSpaces(c *check.C) {
88905793
 	// Test to make sure that when we strcat arrays we take into account
 	// the arg separator to make sure ["echo","hi"] and ["echo hi"] don't
 	// look the same
 	name := "testbuildcmdspaces"
 	var id1 string
 	var id2 string
 	var err error
 
 	if id1, err = buildImage(name, "FROM busybox\nCMD [\"echo hi\"]\n", true); err != nil {
dc944ea7
 		c.Fatal(err)
88905793
 	}
 
 	if id2, err = buildImage(name, "FROM busybox\nCMD [\"echo\", \"hi\"]\n", true); err != nil {
dc944ea7
 		c.Fatal(err)
88905793
 	}
 
 	if id1 == id2 {
dc944ea7
 		c.Fatal("Should not have resulted in the same CMD")
88905793
 	}
 
 	// Now do the same with ENTRYPOINT
 	if id1, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo hi\"]\n", true); err != nil {
dc944ea7
 		c.Fatal(err)
88905793
 	}
 
 	if id2, err = buildImage(name, "FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n", true); err != nil {
dc944ea7
 		c.Fatal(err)
88905793
 	}
 
 	if id1 == id2 {
dc944ea7
 		c.Fatal("Should not have resulted in the same ENTRYPOINT")
88905793
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildCmdJSONNoShDashC(c *check.C) {
9f142bf9
 	name := "testbuildcmdjson"
 	if _, err := buildImage(name, "FROM busybox\nCMD [\"echo\", \"cmd\"]", true); err != nil {
dc944ea7
 		c.Fatal(err)
9f142bf9
 	}
 
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Cmd")
9f142bf9
 
 	expected := `["echo","cmd"]`
 
 	if res != expected {
dc944ea7
 		c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
9f142bf9
 	}
 
 }
9fe1dd31
 
dc944ea7
 func (s *DockerSuite) TestBuildEntrypointInheritance(c *check.C) {
50fa9dff
 
 	if _, err := buildImage("parent", `
     FROM busybox
     ENTRYPOINT exit 130
     `, true); err != nil {
dc944ea7
 		c.Fatal(err)
50fa9dff
 	}
 
693ba98c
 	if _, status, _ := dockerCmdWithError("run", "parent"); status != 130 {
dc944ea7
 		c.Fatalf("expected exit code 130 but received %d", status)
50fa9dff
 	}
 
 	if _, err := buildImage("child", `
     FROM parent
     ENTRYPOINT exit 5
     `, true); err != nil {
dc944ea7
 		c.Fatal(err)
50fa9dff
 	}
 
693ba98c
 	if _, status, _ := dockerCmdWithError("run", "child"); status != 5 {
dc944ea7
 		c.Fatalf("expected exit code 5 but received %d", status)
50fa9dff
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildEntrypointInheritanceInspect(c *check.C) {
50fa9dff
 	var (
 		name     = "testbuildepinherit"
 		name2    = "testbuildepinherit2"
 		expected = `["/bin/sh","-c","echo quux"]`
 	)
 
0adcce10
 	if daemonPlatform == "windows" {
 		expected = `["cmd","/S","/C","echo quux"]`
 	}
 
50fa9dff
 	if _, err := buildImage(name, "FROM busybox\nENTRYPOINT /foo/bar", true); err != nil {
dc944ea7
 		c.Fatal(err)
50fa9dff
 	}
 
 	if _, err := buildImage(name2, fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name), true); err != nil {
dc944ea7
 		c.Fatal(err)
50fa9dff
 	}
 
62a856e9
 	res := inspectFieldJSON(c, name2, "Config.Entrypoint")
50fa9dff
 
 	if res != expected {
dc944ea7
 		c.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res)
50fa9dff
 	}
 
0adcce10
 	out, _ := dockerCmd(c, "run", name2)
50fa9dff
 
 	expected = "quux"
 
 	if strings.TrimSpace(out) != expected {
dc944ea7
 		c.Fatalf("Expected output is %s, got %s", expected, out)
50fa9dff
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildRunShEntrypoint(c *check.C) {
50fa9dff
 	name := "testbuildentrypoint"
 	_, err := buildImage(name,
 		`FROM busybox
0adcce10
                                 ENTRYPOINT echo`,
50fa9dff
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
50fa9dff
 	}
 
5c295460
 	dockerCmd(c, "run", "--rm", name)
50fa9dff
 }
24189b2c
 
dc944ea7
 func (s *DockerSuite) TestBuildExoticShellInterpolation(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
24189b2c
 	name := "testbuildexoticshellinterpolation"
 
 	_, err := buildImage(name, `
 		FROM busybox
f3680e74
 
24189b2c
 		ENV SOME_VAR a.b.c
 
 		RUN [ "$SOME_VAR"       = 'a.b.c' ]
 		RUN [ "${SOME_VAR}"     = 'a.b.c' ]
 		RUN [ "${SOME_VAR%.*}"  = 'a.b'   ]
 		RUN [ "${SOME_VAR%%.*}" = 'a'     ]
 		RUN [ "${SOME_VAR#*.}"  = 'b.c'   ]
 		RUN [ "${SOME_VAR##*.}" = 'c'     ]
 		RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ]
 		RUN [ "${#SOME_VAR}"    = '5'     ]
 
 		RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ]
 		RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ]
 		RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ]
 		RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ]
 	`, false)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
24189b2c
 	}
 
 }
9edf9678
 
dc944ea7
 func (s *DockerSuite) TestBuildVerifySingleQuoteFails(c *check.C) {
9edf9678
 	// This testcase is supposed to generate an error because the
 	// JSON array we're passing in on the CMD uses single quotes instead
 	// of double quotes (per the JSON spec). This means we interpret it
927b334e
 	// as a "string" instead of "JSON array" and pass it on to "sh -c" and
9edf9678
 	// it should barf on it.
 	name := "testbuildsinglequotefails"
 
5c295460
 	if _, err := buildImage(name,
9edf9678
 		`FROM busybox
 		CMD [ '/bin/sh', '-c', 'echo hi' ]`,
5c295460
 		true); err != nil {
 		c.Fatal(err)
 	}
9edf9678
 
693ba98c
 	if _, _, err := dockerCmdWithError("run", "--rm", name); err == nil {
dc944ea7
 		c.Fatal("The image was not supposed to be able to run")
9edf9678
 	}
 
 }
6f09d064
 
dc944ea7
 func (s *DockerSuite) TestBuildVerboseOut(c *check.C) {
6f09d064
 	name := "testbuildverboseout"
0adcce10
 	expected := "\n123\n"
 
 	if daemonPlatform == "windows" {
 		expected = "\n123\r\n"
 	}
6f09d064
 
 	_, out, err := buildImageWithOut(name,
 		`FROM busybox
 RUN echo 123`,
 		false)
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
6f09d064
 	}
0adcce10
 	if !strings.Contains(out, expected) {
dc944ea7
 		c.Fatalf("Output should contain %q: %q", "123", out)
6f09d064
 	}
 
 }
c980fe09
 
dc944ea7
 func (s *DockerSuite) TestBuildWithTabs(c *check.C) {
c980fe09
 	name := "testbuildwithtabs"
 	_, err := buildImage(name,
 		"FROM busybox\nRUN echo\tone\t\ttwo", true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
c980fe09
 	}
62a856e9
 	res := inspectFieldJSON(c, name, "ContainerConfig.Cmd")
14236945
 	expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]`
 	expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
0adcce10
 	if daemonPlatform == "windows" {
 		expected1 = `["cmd","/S","/C","echo\tone\t\ttwo"]`
 		expected2 = `["cmd","/S","/C","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
 	}
14236945
 	if res != expected1 && res != expected2 {
dc944ea7
 		c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2)
c980fe09
 	}
 }
5c91bb93
 
dc944ea7
 func (s *DockerSuite) TestBuildLabels(c *check.C) {
cdfdfbfb
 	name := "testbuildlabel"
 	expected := `{"License":"GPL","Vendor":"Acme"}`
 	_, err := buildImage(name,
 		`FROM busybox
 		LABEL Vendor=Acme
                 LABEL License GPL`,
 		true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
cdfdfbfb
 	}
62a856e9
 	res := inspectFieldJSON(c, name, "Config.Labels")
cdfdfbfb
 	if res != expected {
dc944ea7
 		c.Fatalf("Labels %s, expected %s", res, expected)
cdfdfbfb
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildLabelsCache(c *check.C) {
97c573bf
 	name := "testbuildlabelcache"
 
 	id1, err := buildImage(name,
 		`FROM busybox
 		LABEL Vendor=Acme`, false)
 	if err != nil {
dc944ea7
 		c.Fatalf("Build 1 should have worked: %v", err)
97c573bf
 	}
 
 	id2, err := buildImage(name,
 		`FROM busybox
 		LABEL Vendor=Acme`, true)
 	if err != nil || id1 != id2 {
dc944ea7
 		c.Fatalf("Build 2 should have worked & used cache(%s,%s): %v", id1, id2, err)
97c573bf
 	}
 
 	id2, err = buildImage(name,
 		`FROM busybox
 		LABEL Vendor=Acme1`, true)
 	if err != nil || id1 == id2 {
dc944ea7
 		c.Fatalf("Build 3 should have worked & NOT used cache(%s,%s): %v", id1, id2, err)
97c573bf
 	}
 
 	id2, err = buildImage(name,
 		`FROM busybox
 		LABEL Vendor Acme`, true) // Note: " " and "=" should be same
 	if err != nil || id1 != id2 {
dc944ea7
 		c.Fatalf("Build 4 should have worked & used cache(%s,%s): %v", id1, id2, err)
b4beb063
 	}
 
 	// Now make sure the cache isn't used by mistake
 	id1, err = buildImage(name,
 		`FROM busybox
        LABEL f1=b1 f2=b2`, false)
 	if err != nil {
dc944ea7
 		c.Fatalf("Build 5 should have worked: %q", err)
b4beb063
 	}
 
 	id2, err = buildImage(name,
 		`FROM busybox
        LABEL f1="b1 f2=b2"`, true)
 	if err != nil || id1 == id2 {
dc944ea7
 		c.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s): %q", id1, id2, err)
97c573bf
 	}
 
 }
 
60b4db7e
 func (s *DockerSuite) TestBuildNotVerboseSuccess(c *check.C) {
 	// This test makes sure that -q works correctly when build is successful:
 	// stdout has only the image ID (long image ID) and stderr is empty.
 	var stdout, stderr string
 	var err error
 	outRegexp := regexp.MustCompile("^(sha256:|)[a-z0-9]{64}\\n$")
 
 	tt := []struct {
 		Name      string
 		BuildFunc func(string)
 	}{
 		{
 			Name: "quiet_build_stdin_success",
 			BuildFunc: func(name string) {
 				_, stdout, stderr, err = buildImageWithStdoutStderr(name, "FROM busybox", true, "-q", "--force-rm", "--rm")
 			},
 		},
 		{
 			Name: "quiet_build_ctx_success",
 			BuildFunc: func(name string) {
 				ctx, err := fakeContext("FROM busybox", map[string]string{
 					"quiet_build_success_fctx": "test",
 				})
 				if err != nil {
 					c.Fatalf("Failed to create context: %s", err.Error())
 				}
 				defer ctx.Close()
 				_, stdout, stderr, err = buildImageFromContextWithStdoutStderr(name, ctx, true, "-q", "--force-rm", "--rm")
 			},
 		},
 		{
 			Name: "quiet_build_git_success",
 			BuildFunc: func(name string) {
 				git, err := newFakeGit("repo", map[string]string{
 					"Dockerfile": "FROM busybox",
 				}, true)
 				if err != nil {
 					c.Fatalf("Failed to create the git repo: %s", err.Error())
 				}
 				defer git.Close()
 				_, stdout, stderr, err = buildImageFromGitWithStdoutStderr(name, git, true, "-q", "--force-rm", "--rm")
 
 			},
 		},
 	}
 
 	for _, te := range tt {
 		te.BuildFunc(te.Name)
 		if err != nil {
 			c.Fatalf("Test %s shouldn't fail, but got the following error: %s", te.Name, err.Error())
 		}
 		if outRegexp.Find([]byte(stdout)) == nil {
 			c.Fatalf("Test %s expected stdout to match the [%v] regexp, but it is [%v]", te.Name, outRegexp, stdout)
 		}
ebf4c917
 		if runtime.GOOS == "windows" {
 			// stderr contains a security warning on Windows if the daemon isn't Windows
 			lines := strings.Split(stderr, "\n")
 			warningCount := 0
 			for _, v := range lines {
 				warningText := "SECURITY WARNING: You are building a Docker image from Windows against a non-Windows Docker host."
 				if strings.Contains(v, warningText) {
 					warningCount++
 				}
 				if v != "" && !strings.Contains(v, warningText) {
 					c.Fatalf("Stderr contains unexpected output line: %q", v)
 				}
 			}
 			if warningCount != 1 && daemonPlatform != "windows" {
 				c.Fatalf("Test %s didn't get security warning running from Windows to non-Windows", te.Name)
 			}
 		} else {
 			if stderr != "" {
 				c.Fatalf("Test %s expected stderr to be empty, but it is [%#v]", te.Name, stderr)
 			}
60b4db7e
 		}
 	}
 
 }
 
9ab0aa43
 func (s *DockerSuite) TestBuildNotVerboseFailureWithNonExistImage(c *check.C) {
 	// This test makes sure that -q works correctly when build fails by
 	// comparing between the stderr output in quiet mode and in stdout
 	// and stderr output in verbose mode
 	testRequires(c, Network)
 	testName := "quiet_build_not_exists_image"
 	buildCmd := "FROM busybox11"
 	_, _, qstderr, qerr := buildImageWithStdoutStderr(testName, buildCmd, false, "-q", "--force-rm", "--rm")
 	_, vstdout, vstderr, verr := buildImageWithStdoutStderr(testName, buildCmd, false, "--force-rm", "--rm")
 	if verr == nil || qerr == nil {
 		c.Fatal(fmt.Errorf("Test [%s] expected to fail but didn't", testName))
 	}
 	if qstderr != vstdout+vstderr {
 		c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", testName, qstderr, vstdout+vstderr))
 	}
 }
 
60b4db7e
 func (s *DockerSuite) TestBuildNotVerboseFailure(c *check.C) {
 	// This test makes sure that -q works correctly when build fails by
 	// comparing between the stderr output in quiet mode and in stdout
 	// and stderr output in verbose mode
 	tt := []struct {
 		TestName  string
 		BuildCmds string
 	}{
 		{"quiet_build_no_from_at_the_beginning", "RUN whoami"},
 		{"quiet_build_unknown_instr", "FROMD busybox"},
 	}
 
 	for _, te := range tt {
 		_, _, qstderr, qerr := buildImageWithStdoutStderr(te.TestName, te.BuildCmds, false, "-q", "--force-rm", "--rm")
 		_, vstdout, vstderr, verr := buildImageWithStdoutStderr(te.TestName, te.BuildCmds, false, "--force-rm", "--rm")
 		if verr == nil || qerr == nil {
 			c.Fatal(fmt.Errorf("Test [%s] expected to fail but didn't", te.TestName))
 		}
 		if qstderr != vstdout+vstderr {
f4a1e3db
 			c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", te.TestName, qstderr, vstdout+vstderr))
60b4db7e
 		}
 	}
 }
 
 func (s *DockerSuite) TestBuildNotVerboseFailureRemote(c *check.C) {
 	// This test ensures that when given a wrong URL, stderr in quiet mode and
60f447b6
 	// stderr in verbose mode are identical.
 	// TODO(vdemeester) with cobra, stdout has a carriage return too much so this test should not check stdout
 	URL := "http://something.invalid"
60b4db7e
 	Name := "quiet_build_wrong_remote"
 	_, _, qstderr, qerr := buildImageWithStdoutStderr(Name, "", false, "-q", "--force-rm", "--rm", URL)
60f447b6
 	_, _, vstderr, verr := buildImageWithStdoutStderr(Name, "", false, "--force-rm", "--rm", URL)
60b4db7e
 	if qerr == nil || verr == nil {
 		c.Fatal(fmt.Errorf("Test [%s] expected to fail but didn't", Name))
 	}
60f447b6
 	if qstderr != vstderr {
 		c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", Name, qstderr, vstderr))
60b4db7e
 	}
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildStderr(c *check.C) {
5c91bb93
 	// This test just makes sure that no non-error output goes
 	// to stderr
 	name := "testbuildstderr"
 	_, _, stderr, err := buildImageWithStdoutStderr(name,
 		"FROM busybox\nRUN echo one", true)
 	if err != nil {
dc944ea7
 		c.Fatal(err)
5c91bb93
 	}
4a8b3cad
 
 	if runtime.GOOS == "windows" {
 		// stderr might contain a security warning on windows
 		lines := strings.Split(stderr, "\n")
 		for _, v := range lines {
 			if v != "" && !strings.Contains(v, "SECURITY WARNING:") {
dc944ea7
 				c.Fatalf("Stderr contains unexpected output line: %q", v)
4a8b3cad
 			}
 		}
 	} else {
 		if stderr != "" {
dc944ea7
 			c.Fatalf("Stderr should have been empty, instead its: %q", stderr)
4a8b3cad
 		}
5c91bb93
 	}
 }
cfc24769
 
dc944ea7
 func (s *DockerSuite) TestBuildChownSingleFile(c *check.C) {
 	testRequires(c, UnixCli) // test uses chown: not available on windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
492a58f0
 
cfc24769
 	name := "testbuildchownsinglefile"
 
 	ctx, err := fakeContext(`
 FROM busybox
 COPY test /
 RUN ls -l /test
 RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ]
 `, map[string]string{
 		"test": "test",
 	})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
cfc24769
 	}
 	defer ctx.Close()
 
 	if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil {
dc944ea7
 		c.Fatal(err)
cfc24769
 	}
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
cfc24769
 	}
 
 }
0e71a48d
 
dc944ea7
 func (s *DockerSuite) TestBuildSymlinkBreakout(c *check.C) {
0e71a48d
 	name := "testbuildsymlinkbreakout"
 	tmpdir, err := ioutil.TempDir("", name)
b616b8a1
 	c.Assert(err, check.IsNil)
0e71a48d
 	defer os.RemoveAll(tmpdir)
 	ctx := filepath.Join(tmpdir, "context")
 	if err := os.MkdirAll(ctx, 0755); err != nil {
dc944ea7
 		c.Fatal(err)
0e71a48d
 	}
 	if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(`
 	from busybox
 	add symlink.tar /
 	add inject /symlink/
 	`), 0644); err != nil {
dc944ea7
 		c.Fatal(err)
0e71a48d
 	}
 	inject := filepath.Join(ctx, "inject")
 	if err := ioutil.WriteFile(inject, nil, 0644); err != nil {
dc944ea7
 		c.Fatal(err)
0e71a48d
 	}
 	f, err := os.Create(filepath.Join(ctx, "symlink.tar"))
 	if err != nil {
dc944ea7
 		c.Fatal(err)
0e71a48d
 	}
 	w := tar.NewWriter(f)
 	w.WriteHeader(&tar.Header{
 		Name:     "symlink2",
 		Typeflag: tar.TypeSymlink,
 		Linkname: "/../../../../../../../../../../../../../../",
 		Uid:      os.Getuid(),
 		Gid:      os.Getgid(),
 	})
 	w.WriteHeader(&tar.Header{
 		Name:     "symlink",
 		Typeflag: tar.TypeSymlink,
 		Linkname: filepath.Join("symlink2", tmpdir),
 		Uid:      os.Getuid(),
 		Gid:      os.Getgid(),
 	})
 	w.Close()
 	f.Close()
44ffb199
 	if _, err := buildImageFromContext(name, fakeContextFromDir(ctx), false); err != nil {
dc944ea7
 		c.Fatal(err)
0e71a48d
 	}
 	if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil {
dc944ea7
 		c.Fatal("symlink breakout - inject")
0e71a48d
 	} else if !os.IsNotExist(err) {
dc944ea7
 		c.Fatalf("unexpected error: %v", err)
0e71a48d
 	}
 }
af202195
 
dc944ea7
 func (s *DockerSuite) TestBuildXZHost(c *check.C) {
ea3afdad
 	// /usr/local/sbin/xz gets permission denied for the user
 	testRequires(c, NotUserNamespace)
f9a3558a
 	testRequires(c, DaemonIsLinux)
af202195
 	name := "testbuildxzhost"
 
 	ctx, err := fakeContext(`
 FROM busybox
 ADD xz /usr/local/sbin/
 RUN chmod 755 /usr/local/sbin/xz
 ADD test.xz /
 RUN [ ! -e /injected ]`,
 		map[string]string{
 			"test.xz": "\xfd\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00" +
 				"\x21\x01\x16\x00\x00\x00\x74\x2f\xe5\xa3\x01\x00\x3f\xfd" +
 				"\x37\x7a\x58\x5a\x00\x00\x04\xe6\xd6\xb4\x46\x02\x00\x21",
 			"xz": "#!/bin/sh\ntouch /injected",
 		})
 
 	if err != nil {
dc944ea7
 		c.Fatal(err)
af202195
 	}
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
dc944ea7
 		c.Fatal(err)
af202195
 	}
 
 }
4856ec07
 
dc944ea7
 func (s *DockerSuite) TestBuildVolumesRetainContents(c *check.C) {
ea3afdad
 	// /foo/file gets permission denied for the user
 	testRequires(c, NotUserNamespace)
0adcce10
 	testRequires(c, DaemonIsLinux) // TODO Windows: Issue #20127
4856ec07
 	var (
 		name     = "testbuildvolumescontent"
 		expected = "some text"
0adcce10
 		volName  = "/foo"
4856ec07
 	)
0adcce10
 
 	if daemonPlatform == "windows" {
 		volName = "C:/foo"
 	}
 
4856ec07
 	ctx, err := fakeContext(`
 FROM busybox
 COPY content /foo/file
0adcce10
 VOLUME `+volName+`
4856ec07
 CMD cat /foo/file`,
 		map[string]string{
 			"content": expected,
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
4856ec07
 	}
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(name, ctx, false); err != nil {
dc944ea7
 		c.Fatal(err)
4856ec07
 	}
 
5c295460
 	out, _ := dockerCmd(c, "run", "--rm", name)
4856ec07
 	if out != expected {
dc944ea7
 		c.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out)
4856ec07
 	}
 
 }
eb3ea3b4
 
dc944ea7
 func (s *DockerSuite) TestBuildRenamedDockerfile(c *check.C) {
eb3ea3b4
 
 	ctx, err := fakeContext(`FROM busybox
 	RUN echo from Dockerfile`,
 		map[string]string{
 			"Dockerfile":       "FROM busybox\nRUN echo from Dockerfile",
 			"files/Dockerfile": "FROM busybox\nRUN echo from files/Dockerfile",
 			"files/dFile":      "FROM busybox\nRUN echo from files/dFile",
 			"dFile":            "FROM busybox\nRUN echo from dFile",
c42d2625
 			"files/dFile2":     "FROM busybox\nRUN echo from files/dFile2",
eb3ea3b4
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
eb3ea3b4
 	}
04ef69a1
 	defer ctx.Close()
eb3ea3b4
 
dc944ea7
 	out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".")
eb3ea3b4
 	if err != nil {
dc944ea7
 		c.Fatalf("Failed to build: %s\n%s", out, err)
eb3ea3b4
 	}
 	if !strings.Contains(out, "from Dockerfile") {
dc944ea7
 		c.Fatalf("test1 should have used Dockerfile, output:%s", out)
eb3ea3b4
 	}
 
dc944ea7
 	out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "-f", filepath.Join("files", "Dockerfile"), "-t", "test2", ".")
eb3ea3b4
 	if err != nil {
dc944ea7
 		c.Fatal(err)
eb3ea3b4
 	}
 	if !strings.Contains(out, "from files/Dockerfile") {
dc944ea7
 		c.Fatalf("test2 should have used files/Dockerfile, output:%s", out)
eb3ea3b4
 	}
 
dc944ea7
 	out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", filepath.Join("files", "dFile")), "-t", "test3", ".")
eb3ea3b4
 	if err != nil {
dc944ea7
 		c.Fatal(err)
eb3ea3b4
 	}
 	if !strings.Contains(out, "from files/dFile") {
dc944ea7
 		c.Fatalf("test3 should have used files/dFile, output:%s", out)
eb3ea3b4
 	}
 
dc944ea7
 	out, _, err = dockerCmdInDir(c, ctx.Dir, "build", "--file=dFile", "-t", "test4", ".")
eb3ea3b4
 	if err != nil {
dc944ea7
 		c.Fatal(err)
eb3ea3b4
 	}
 	if !strings.Contains(out, "from dFile") {
dc944ea7
 		c.Fatalf("test4 should have used dFile, output:%s", out)
eb3ea3b4
 	}
 
51e721ab
 	dirWithNoDockerfile, err := ioutil.TempDir(os.TempDir(), "test5")
 	c.Assert(err, check.IsNil)
967d85a2
 	nonDockerfileFile := filepath.Join(dirWithNoDockerfile, "notDockerfile")
 	if _, err = os.Create(nonDockerfileFile); err != nil {
dc944ea7
 		c.Fatal(err)
967d85a2
 	}
dc944ea7
 	out, _, err = dockerCmdInDir(c, ctx.Dir, "build", fmt.Sprintf("--file=%s", nonDockerfileFile), "-t", "test5", ".")
967d85a2
 
eb3ea3b4
 	if err == nil {
dc944ea7
 		c.Fatalf("test5 was supposed to fail to find passwd")
eb3ea3b4
 	}
967d85a2
 
0024935f
 	if expected := fmt.Sprintf("The Dockerfile (%s) must be within the build context (.)", nonDockerfileFile); !strings.Contains(out, expected) {
dc944ea7
 		c.Fatalf("wrong error messsage:%v\nexpected to contain=%v", out, expected)
eb3ea3b4
 	}
 
dc944ea7
 	out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test6", "..")
eb3ea3b4
 	if err != nil {
dc944ea7
 		c.Fatalf("test6 failed: %s", err)
eb3ea3b4
 	}
 	if !strings.Contains(out, "from Dockerfile") {
dc944ea7
 		c.Fatalf("test6 should have used root Dockerfile, output:%s", out)
eb3ea3b4
 	}
 
dc944ea7
 	out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join(ctx.Dir, "files", "Dockerfile"), "-t", "test7", "..")
eb3ea3b4
 	if err != nil {
dc944ea7
 		c.Fatalf("test7 failed: %s", err)
eb3ea3b4
 	}
 	if !strings.Contains(out, "from files/Dockerfile") {
dc944ea7
 		c.Fatalf("test7 should have used files Dockerfile, output:%s", out)
eb3ea3b4
 	}
 
dc944ea7
 	out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", filepath.Join("..", "Dockerfile"), "-t", "test8", ".")
eb3ea3b4
 	if err == nil || !strings.Contains(out, "must be within the build context") {
dc944ea7
 		c.Fatalf("test8 should have failed with Dockerfile out of context: %s", err)
eb3ea3b4
 	}
 
c42d2625
 	tmpDir := os.TempDir()
dc944ea7
 	out, _, err = dockerCmdInDir(c, tmpDir, "build", "-t", "test9", ctx.Dir)
eb3ea3b4
 	if err != nil {
dc944ea7
 		c.Fatalf("test9 - failed: %s", err)
eb3ea3b4
 	}
 	if !strings.Contains(out, "from Dockerfile") {
dc944ea7
 		c.Fatalf("test9 should have used root Dockerfile, output:%s", out)
c42d2625
 	}
 
dc944ea7
 	out, _, err = dockerCmdInDir(c, filepath.Join(ctx.Dir, "files"), "build", "-f", "dFile2", "-t", "test10", ".")
c42d2625
 	if err != nil {
dc944ea7
 		c.Fatalf("test10 should have worked: %s", err)
c42d2625
 	}
 	if !strings.Contains(out, "from files/dFile2") {
dc944ea7
 		c.Fatalf("test10 should have used files/dFile2, output:%s", out)
eb3ea3b4
 	}
 
 }
568f86eb
 
dc944ea7
 func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) {
 	testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
15924f23
 
 	ctx, err := fakeContext(`FROM busybox
 	RUN echo from dockerfile`,
 		map[string]string{
 			"dockerfile": "FROM busybox\nRUN echo from dockerfile",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
15924f23
 	}
04ef69a1
 	defer ctx.Close()
15924f23
 
dc944ea7
 	out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".")
15924f23
 	if err != nil {
dc944ea7
 		c.Fatalf("Failed to build: %s\n%s", out, err)
15924f23
 	}
 
 	if !strings.Contains(out, "from dockerfile") {
dc944ea7
 		c.Fatalf("Missing proper output: %s", out)
15924f23
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildWithTwoDockerfiles(c *check.C) {
 	testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows
f9a3558a
 	testRequires(c, DaemonIsLinux)
15924f23
 
 	ctx, err := fakeContext(`FROM busybox
 RUN echo from Dockerfile`,
 		map[string]string{
 			"dockerfile": "FROM busybox\nRUN echo from dockerfile",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
15924f23
 	}
04ef69a1
 	defer ctx.Close()
15924f23
 
dc944ea7
 	out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-t", "test1", ".")
15924f23
 	if err != nil {
dc944ea7
 		c.Fatalf("Failed to build: %s\n%s", out, err)
15924f23
 	}
 
 	if !strings.Contains(out, "from Dockerfile") {
dc944ea7
 		c.Fatalf("Missing proper output: %s", out)
15924f23
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildFromURLWithF(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
15924f23
 
 	server, err := fakeStorage(map[string]string{"baz": `FROM busybox
 RUN echo from baz
 COPY * /tmp/
 RUN find /tmp/`})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
15924f23
 	}
 	defer server.Close()
 
 	ctx, err := fakeContext(`FROM busybox
 RUN echo from Dockerfile`,
 		map[string]string{})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
15924f23
 	}
04ef69a1
 	defer ctx.Close()
15924f23
 
 	// Make sure that -f is ignored and that we don't use the Dockerfile
 	// that's in the current dir
dc944ea7
 	out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "-f", "baz", "-t", "test1", server.URL()+"/baz")
15924f23
 	if err != nil {
dc944ea7
 		c.Fatalf("Failed to build: %s\n%s", out, err)
15924f23
 	}
 
 	if !strings.Contains(out, "from baz") ||
 		strings.Contains(out, "/tmp/baz") ||
 		!strings.Contains(out, "/tmp/Dockerfile") {
dc944ea7
 		c.Fatalf("Missing proper output: %s", out)
15924f23
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildFromStdinWithF(c *check.C) {
0adcce10
 	testRequires(c, DaemonIsLinux) // TODO Windows: This test is flaky; no idea why
15924f23
 	ctx, err := fakeContext(`FROM busybox
0adcce10
 RUN echo "from Dockerfile"`,
15924f23
 		map[string]string{})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
15924f23
 	}
04ef69a1
 	defer ctx.Close()
15924f23
 
 	// Make sure that -f is ignored and that we don't use the Dockerfile
 	// that's in the current dir
 	dockerCommand := exec.Command(dockerBinary, "build", "-f", "baz", "-t", "test1", "-")
 	dockerCommand.Dir = ctx.Dir
 	dockerCommand.Stdin = strings.NewReader(`FROM busybox
0adcce10
 RUN echo "from baz"
15924f23
 COPY * /tmp/
0adcce10
 RUN sh -c "find /tmp/" # sh -c is needed on Windows to use the correct find`)
15924f23
 	out, status, err := runCommandWithOutput(dockerCommand)
 	if err != nil || status != 0 {
dc944ea7
 		c.Fatalf("Error building: %s", err)
15924f23
 	}
 
 	if !strings.Contains(out, "from baz") ||
 		strings.Contains(out, "/tmp/baz") ||
 		!strings.Contains(out, "/tmp/Dockerfile") {
dc944ea7
 		c.Fatalf("Missing proper output: %s", out)
15924f23
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildFromOfficialNames(c *check.C) {
568f86eb
 	name := "testbuildfromofficial"
 	fromNames := []string{
 		"busybox",
 		"docker.io/busybox",
 		"index.docker.io/busybox",
 		"library/busybox",
 		"docker.io/library/busybox",
 		"index.docker.io/library/busybox",
 	}
 	for idx, fromName := range fromNames {
 		imgName := fmt.Sprintf("%s%d", name, idx)
 		_, err := buildImage(imgName, "FROM "+fromName, true)
 		if err != nil {
dc944ea7
 			c.Errorf("Build failed using FROM %s: %s", fromName, err)
568f86eb
 		}
 		deleteImages(imgName)
 	}
 }
73d5baf5
 
dc944ea7
 func (s *DockerSuite) TestBuildDockerfileOutsideContext(c *check.C) {
 	testRequires(c, UnixCli) // uses os.Symlink: not implemented in windows at the time of writing (go-1.4.2)
f9a3558a
 	testRequires(c, DaemonIsLinux)
492a58f0
 
73d5baf5
 	name := "testbuilddockerfileoutsidecontext"
 	tmpdir, err := ioutil.TempDir("", name)
b616b8a1
 	c.Assert(err, check.IsNil)
73d5baf5
 	defer os.RemoveAll(tmpdir)
 	ctx := filepath.Join(tmpdir, "context")
 	if err := os.MkdirAll(ctx, 0755); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
c42d2625
 	if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte("FROM scratch\nENV X Y"), 0644); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
 	wd, err := os.Getwd()
 	if err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
 	defer os.Chdir(wd)
 	if err := os.Chdir(ctx); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
c42d2625
 	if err := ioutil.WriteFile(filepath.Join(tmpdir, "outsideDockerfile"), []byte("FROM scratch\nENV x y"), 0644); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
4581240e
 	if err := os.Symlink(filepath.Join("..", "outsideDockerfile"), filepath.Join(ctx, "dockerfile1")); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
 	if err := os.Symlink(filepath.Join(tmpdir, "outsideDockerfile"), filepath.Join(ctx, "dockerfile2")); err != nil {
dc944ea7
 		c.Fatal(err)
73d5baf5
 	}
4581240e
 
73d5baf5
 	for _, dockerfilePath := range []string{
4581240e
 		filepath.Join("..", "outsideDockerfile"),
73d5baf5
 		filepath.Join(ctx, "dockerfile1"),
 		filepath.Join(ctx, "dockerfile2"),
 	} {
693ba98c
 		out, _, err := dockerCmdWithError("build", "-t", name, "--no-cache", "-f", dockerfilePath, ".")
73d5baf5
 		if err == nil {
dc944ea7
 			c.Fatalf("Expected error with %s. Out: %s", dockerfilePath, out)
73d5baf5
 		}
c42d2625
 		if !strings.Contains(out, "must be within the build context") && !strings.Contains(out, "Cannot locate Dockerfile") {
dc944ea7
 			c.Fatalf("Unexpected error with %s. Out: %s", dockerfilePath, out)
c42d2625
 		}
73d5baf5
 		deleteImages(name)
 	}
 
 	os.Chdir(tmpdir)
 
 	// Path to Dockerfile should be resolved relative to working directory, not relative to context.
 	// There is a Dockerfile in the context, but since there is no Dockerfile in the current directory, the following should fail
693ba98c
 	out, _, err := dockerCmdWithError("build", "-t", name, "--no-cache", "-f", "Dockerfile", ctx)
73d5baf5
 	if err == nil {
dc944ea7
 		c.Fatalf("Expected error. Out: %s", out)
73d5baf5
 	}
 }
3859c485
 
dc944ea7
 func (s *DockerSuite) TestBuildSpaces(c *check.C) {
3859c485
 	// Test to make sure that leading/trailing spaces on a command
 	// doesn't change the error msg we get
 	var (
 		err1 error
 		err2 error
 	)
 
 	name := "testspaces"
d1e9d07c
 	ctx, err := fakeContext("FROM busybox\nCOPY\n",
3859c485
 		map[string]string{
d1e9d07c
 			"Dockerfile": "FROM busybox\nCOPY\n",
3859c485
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
3859c485
 	}
 	defer ctx.Close()
 
 	if _, err1 = buildImageFromContext(name, ctx, false); err1 == nil {
dc944ea7
 		c.Fatal("Build 1 was supposed to fail, but didn't")
3859c485
 	}
 
d1e9d07c
 	ctx.Add("Dockerfile", "FROM busybox\nCOPY    ")
3859c485
 	if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil {
dc944ea7
 		c.Fatal("Build 2 was supposed to fail, but didn't")
3859c485
 	}
 
28a34dff
 	removeLogTimestamps := func(s string) string {
 		return regexp.MustCompile(`time="(.*?)"`).ReplaceAllString(s, `time=[TIMESTAMP]`)
 	}
 
3859c485
 	// Skip over the times
28a34dff
 	e1 := removeLogTimestamps(err1.Error())
 	e2 := removeLogTimestamps(err2.Error())
3859c485
 
 	// Ignore whitespace since that's what were verifying doesn't change stuff
 	if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
dc944ea7
 		c.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", err1, err2)
3859c485
 	}
 
d1e9d07c
 	ctx.Add("Dockerfile", "FROM busybox\n   COPY")
3859c485
 	if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil {
dc944ea7
 		c.Fatal("Build 3 was supposed to fail, but didn't")
3859c485
 	}
 
 	// Skip over the times
28a34dff
 	e1 = removeLogTimestamps(err1.Error())
 	e2 = removeLogTimestamps(err2.Error())
3859c485
 
 	// Ignore whitespace since that's what were verifying doesn't change stuff
 	if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
dc944ea7
 		c.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", err1, err2)
3859c485
 	}
 
d1e9d07c
 	ctx.Add("Dockerfile", "FROM busybox\n   COPY    ")
3859c485
 	if _, err2 = buildImageFromContext(name, ctx, false); err2 == nil {
dc944ea7
 		c.Fatal("Build 4 was supposed to fail, but didn't")
3859c485
 	}
 
 	// Skip over the times
28a34dff
 	e1 = removeLogTimestamps(err1.Error())
 	e2 = removeLogTimestamps(err2.Error())
3859c485
 
 	// Ignore whitespace since that's what were verifying doesn't change stuff
 	if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
dc944ea7
 		c.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", err1, err2)
3859c485
 	}
 
 }
 
dc944ea7
 func (s *DockerSuite) TestBuildSpacesWithQuotes(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
3859c485
 	// Test to make sure that spaces in quotes aren't lost
 	name := "testspacesquotes"
 
 	dockerfile := `FROM busybox
 RUN echo "  \
   foo  "`
 
 	_, out, err := buildImageWithOut(name, dockerfile, false)
 	if err != nil {
dc944ea7
 		c.Fatal("Build failed:", err)
3859c485
 	}
 
 	expecting := "\n    foo  \n"
 	if !strings.Contains(out, expecting) {
3941623f
 		c.Fatalf("Bad output: %q expecting to contain %q", out, expecting)
3859c485
 	}
 
 }
c73e3bf4
 
 // #4393
dc944ea7
 func (s *DockerSuite) TestBuildVolumeFileExistsinContainer(c *check.C) {
0adcce10
 	testRequires(c, DaemonIsLinux) // TODO Windows: This should error out
c73e3bf4
 	buildCmd := exec.Command(dockerBinary, "build", "-t", "docker-test-errcreatevolumewithfile", "-")
 	buildCmd.Stdin = strings.NewReader(`
 	FROM busybox
 	RUN touch /foo
 	VOLUME /foo
 	`)
 
 	out, _, err := runCommandWithOutput(buildCmd)
 	if err == nil || !strings.Contains(out, "file exists") {
dc944ea7
 		c.Fatalf("expected build to fail when file exists in container at requested volume path")
c73e3bf4
 	}
 
 }
e4f02abb
 
dc944ea7
 func (s *DockerSuite) TestBuildMissingArgs(c *check.C) {
d1e9d07c
 	// Test to make sure that all Dockerfile commands (except the ones listed
 	// in skipCmds) will generate an error if no args are provided.
 	// Note: INSERT is deprecated so we exclude it because of that.
 	skipCmds := map[string]struct{}{
 		"CMD":        {},
 		"RUN":        {},
 		"ENTRYPOINT": {},
 		"INSERT":     {},
e4f02abb
 	}
 
0adcce10
 	if daemonPlatform == "windows" {
 		skipCmds = map[string]struct{}{
 			"CMD":        {},
 			"RUN":        {},
 			"ENTRYPOINT": {},
 			"INSERT":     {},
 			"STOPSIGNAL": {},
 			"ARG":        {},
 			"USER":       {},
 			"EXPOSE":     {},
 		}
 	}
 
6ecf2386
 	for cmd := range command.Commands {
d1e9d07c
 		cmd = strings.ToUpper(cmd)
 		if _, ok := skipCmds[cmd]; ok {
 			continue
 		}
 
ccde3a1f
 		var dockerfile string
e4f02abb
 		if cmd == "FROM" {
 			dockerfile = cmd
 		} else {
 			// Add FROM to make sure we don't complain about it missing
 			dockerfile = "FROM busybox\n" + cmd
 		}
 
 		ctx, err := fakeContext(dockerfile, map[string]string{})
 		if err != nil {
dc944ea7
 			c.Fatal(err)
e4f02abb
 		}
 		defer ctx.Close()
 		var out string
 		if out, err = buildImageFromContext("args", ctx, true); err == nil {
dc944ea7
 			c.Fatalf("%s was supposed to fail. Out:%s", cmd, out)
e4f02abb
 		}
 		if !strings.Contains(err.Error(), cmd+" requires") {
dc944ea7
 			c.Fatalf("%s returned the wrong type of error:%s", cmd, err)
e4f02abb
 		}
 	}
 
 }
1654dfdf
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyScratch(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
1654dfdf
 	_, out, err := buildImageWithOut("sc", "FROM scratch", true)
 	if err == nil {
dc944ea7
 		c.Fatalf("Build was supposed to fail")
1654dfdf
 	}
 	if !strings.Contains(out, "No image was generated") {
dc944ea7
 		c.Fatalf("Wrong error message: %v", out)
1654dfdf
 	}
 }
0826ac15
 
dc944ea7
 func (s *DockerSuite) TestBuildDotDotFile(c *check.C) {
0826ac15
 	ctx, err := fakeContext("FROM busybox\n",
 		map[string]string{
 			"..gitme": "",
 		})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
0826ac15
 	}
 	defer ctx.Close()
 
 	if _, err = buildImageFromContext("sc", ctx, false); err != nil {
dc944ea7
 		c.Fatalf("Build was supposed to work: %s", err)
0826ac15
 	}
 }
92c35358
 
dc944ea7
 func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // No hello-world Windows image
645f8a32
 	name := "testbuildrunonejson"
 
636037c3
 	ctx, err := fakeContext(`FROM hello-world:frozen
645f8a32
 RUN [ "/hello" ]`, map[string]string{})
 	if err != nil {
dc944ea7
 		c.Fatal(err)
645f8a32
 	}
 	defer ctx.Close()
 
5c295460
 	out, _, err := dockerCmdInDir(c, ctx.Dir, "build", "--no-cache", "-t", name, ".")
645f8a32
 	if err != nil {
dc944ea7
 		c.Fatalf("failed to build the image: %s, %v", out, err)
645f8a32
 	}
 
 	if !strings.Contains(out, "Hello from Docker") {
dc944ea7
 		c.Fatalf("bad output: %s", out)
645f8a32
 	}
 
 }
e6ae89a4
 
dc944ea7
 func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) {
8071bf39
 	name := "testbuildemptystringvolume"
 
 	_, err := buildImage(name, `
   FROM busybox
   ENV foo=""
   VOLUME $foo
   `, false)
 	if err == nil {
dc944ea7
 		c.Fatal("Should have failed to build")
8071bf39
 	}
 
 }
f40dd69c
 
9dbe12b7
 func (s *DockerSuite) TestBuildContainerWithCgroupParent(c *check.C) {
 	testRequires(c, SameHostDaemon)
f9a3558a
 	testRequires(c, DaemonIsLinux)
f40dd69c
 
 	cgroupParent := "test"
 	data, err := ioutil.ReadFile("/proc/self/cgroup")
 	if err != nil {
9dbe12b7
 		c.Fatalf("failed to read '/proc/self/cgroup - %v", err)
f40dd69c
 	}
 	selfCgroupPaths := parseCgroupPaths(string(data))
 	_, found := selfCgroupPaths["memory"]
 	if !found {
0d09439a
 		c.Fatalf("unable to find self memory cgroup path. CgroupsPath: %v", selfCgroupPaths)
f40dd69c
 	}
f039c699
 	cmd := exec.Command(dockerBinary, "build", "--cgroup-parent", cgroupParent, "-")
f40dd69c
 	cmd.Stdin = strings.NewReader(`
 FROM busybox
 RUN cat /proc/self/cgroup
 `)
 
 	out, _, err := runCommandWithOutput(cmd)
 	if err != nil {
9dbe12b7
 		c.Fatalf("unexpected failure when running container with --cgroup-parent option - %s\n%v", string(out), err)
f40dd69c
 	}
0d09439a
 	m, err := regexp.MatchString(fmt.Sprintf("memory:.*/%s/.*", cgroupParent), out)
 	c.Assert(err, check.IsNil)
 	if !m {
 		c.Fatalf("There is no expected memory cgroup with parent /%s/: %s", cgroupParent, out)
 	}
f40dd69c
 }
08b7f30f
 
 func (s *DockerSuite) TestBuildNoDupOutput(c *check.C) {
 	// Check to make sure our build output prints the Dockerfile cmd
 	// property - there was a bug that caused it to be duplicated on the
 	// Step X  line
 	name := "testbuildnodupoutput"
 
 	_, out, err := buildImageWithOut(name, `
   FROM busybox
   RUN env`, false)
 	if err != nil {
 		c.Fatalf("Build should have worked: %q", err)
 	}
 
17d6c6c7
 	exp := "\nStep 2 : RUN env\n"
 	if !strings.Contains(out, exp) {
 		c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", out, exp)
 	}
 }
 
 // GH15826
 func (s *DockerSuite) TestBuildStartsFromOne(c *check.C) {
 	// Explicit check to ensure that build starts from step 1 rather than 0
 	name := "testbuildstartsfromone"
 
 	_, out, err := buildImageWithOut(name, `
   FROM busybox`, false)
 	if err != nil {
 		c.Fatalf("Build should have worked: %q", err)
 	}
 
 	exp := "\nStep 1 : FROM busybox\n"
08b7f30f
 	if !strings.Contains(out, exp) {
 		c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", out, exp)
 	}
 }
 
54662eae
 func (s *DockerSuite) TestBuildRUNErrMsg(c *check.C) {
 	// Test to make sure the bad command is quoted with just "s and
 	// not as a Go []string
 	name := "testbuildbadrunerrmsg"
 	_, out, err := buildImageWithOut(name, `
   FROM busybox
006c066b
   RUN badEXE a1 \& a2	a3`, false) // tab between a2 and a3
54662eae
 	if err == nil {
 		c.Fatal("Should have failed to build")
 	}
5fc0de26
 	shell := "/bin/sh -c"
 	exitCode := "127"
 	if daemonPlatform == "windows" {
 		shell = "cmd /S /C"
 		// architectural - Windows has to start the container to determine the exe is bad, Linux does not
 		exitCode = "1"
 	}
 	exp := `The command '` + shell + ` badEXE a1 \& a2	a3' returned a non-zero code: ` + exitCode
54662eae
 	if !strings.Contains(out, exp) {
 		c.Fatalf("RUN doesn't have the correct output:\nGot:%s\nExpected:%s", out, exp)
 	}
 }
871d2b96
 
 func (s *DockerTrustSuite) TestTrustedBuild(c *check.C) {
 	repoName := s.setupTrustedImage(c, "trusted-build")
 	dockerFile := fmt.Sprintf(`
   FROM %s
   RUN []
     `, repoName)
 
 	name := "testtrustedbuild"
 
 	buildCmd := buildImageCmd(name, dockerFile, true)
 	s.trustedCmd(buildCmd)
 	out, _, err := runCommandWithOutput(buildCmd)
 	if err != nil {
 		c.Fatalf("Error running trusted build: %s\n%s", err, out)
 	}
 
 	if !strings.Contains(out, fmt.Sprintf("FROM %s@sha", repoName[:len(repoName)-7])) {
 		c.Fatalf("Unexpected output on trusted build:\n%s", out)
 	}
 
bb2e6c72
 	// We should also have a tag reference for the image.
 	if out, exitCode := dockerCmd(c, "inspect", repoName); exitCode != 0 {
 		c.Fatalf("unexpected exit code inspecting image %q: %d: %s", repoName, exitCode, out)
 	}
 
 	// We should now be able to remove the tag reference.
 	if out, exitCode := dockerCmd(c, "rmi", repoName); exitCode != 0 {
 		c.Fatalf("unexpected exit code inspecting image %q: %d: %s", repoName, exitCode, out)
 	}
871d2b96
 }
 
 func (s *DockerTrustSuite) TestTrustedBuildUntrustedTag(c *check.C) {
 	repoName := fmt.Sprintf("%v/dockercli/build-untrusted-tag:latest", privateRegistryURL)
 	dockerFile := fmt.Sprintf(`
   FROM %s
   RUN []
     `, repoName)
 
 	name := "testtrustedbuilduntrustedtag"
 
 	buildCmd := buildImageCmd(name, dockerFile, true)
 	s.trustedCmd(buildCmd)
 	out, _, err := runCommandWithOutput(buildCmd)
 	if err == nil {
 		c.Fatalf("Expected error on trusted build with untrusted tag: %s\n%s", err, out)
 	}
 
1c32a668
 	if !strings.Contains(out, "does not have trust data for") {
871d2b96
 		c.Fatalf("Unexpected output on trusted build with untrusted tag:\n%s", out)
 	}
 }
01d570ad
 
 func (s *DockerTrustSuite) TestBuildContextDirIsSymlink(c *check.C) {
f9a3558a
 	testRequires(c, DaemonIsLinux)
01d570ad
 	tempDir, err := ioutil.TempDir("", "test-build-dir-is-symlink-")
b616b8a1
 	c.Assert(err, check.IsNil)
01d570ad
 	defer os.RemoveAll(tempDir)
 
 	// Make a real context directory in this temp directory with a simple
 	// Dockerfile.
 	realContextDirname := filepath.Join(tempDir, "context")
 	if err := os.Mkdir(realContextDirname, os.FileMode(0755)); err != nil {
 		c.Fatal(err)
 	}
 
 	if err = ioutil.WriteFile(
 		filepath.Join(realContextDirname, "Dockerfile"),
 		[]byte(`
 			FROM busybox
 			RUN echo hello world
 		`),
 		os.FileMode(0644),
 	); err != nil {
 		c.Fatal(err)
 	}
 
 	// Make a symlink to the real context directory.
 	contextSymlinkName := filepath.Join(tempDir, "context_link")
 	if err := os.Symlink(realContextDirname, contextSymlinkName); err != nil {
 		c.Fatal(err)
 	}
 
 	// Executing the build with the symlink as the specified context should
 	// *not* fail.
 	if out, exitStatus := dockerCmd(c, "build", contextSymlinkName); exitStatus != 0 {
 		c.Fatalf("build failed with exit status %d: %s", exitStatus, out)
 	}
 }
d45fcc6c
 
623ccc2f
 func (s *DockerTrustSuite) TestTrustedBuildTagFromReleasesRole(c *check.C) {
 	testRequires(c, NotaryHosting)
 
 	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
 	repoName := strings.TrimSuffix(latestTag, ":latest")
 
 	// Now create the releases role
 	s.notaryCreateDelegation(c, repoName, "targets/releases", s.not.keys[0].Public)
 	s.notaryImportKey(c, repoName, "targets/releases", s.not.keys[0].Private)
 	s.notaryPublish(c, repoName)
 
 	// push a different tag to the releases role
 	otherTag := fmt.Sprintf("%s:other", repoName)
 	dockerCmd(c, "tag", "busybox", otherTag)
 
 	pushCmd := exec.Command(dockerBinary, "push", otherTag)
 	s.trustedCmd(pushCmd)
 	out, _, err := runCommandWithOutput(pushCmd)
 	c.Assert(err, check.IsNil, check.Commentf("Trusted push failed: %s", out))
 	s.assertTargetInRoles(c, repoName, "other", "targets/releases")
 	s.assertTargetNotInRoles(c, repoName, "other", "targets")
 
 	out, status := dockerCmd(c, "rmi", otherTag)
 	c.Assert(status, check.Equals, 0, check.Commentf("docker rmi failed: %s", out))
 
 	dockerFile := fmt.Sprintf(`
   FROM %s
   RUN []
     `, otherTag)
 
 	name := "testtrustedbuildreleasesrole"
 
 	buildCmd := buildImageCmd(name, dockerFile, true)
 	s.trustedCmd(buildCmd)
 	out, _, err = runCommandWithOutput(buildCmd)
 	c.Assert(err, check.IsNil, check.Commentf("Trusted build failed: %s", out))
 	c.Assert(out, checker.Contains, fmt.Sprintf("FROM %s@sha", repoName))
 }
 
 func (s *DockerTrustSuite) TestTrustedBuildTagIgnoresOtherDelegationRoles(c *check.C) {
 	testRequires(c, NotaryHosting)
 
 	latestTag := s.setupTrustedImage(c, "trusted-build-releases-role")
 	repoName := strings.TrimSuffix(latestTag, ":latest")
 
 	// Now create a non-releases delegation role
 	s.notaryCreateDelegation(c, repoName, "targets/other", s.not.keys[0].Public)
 	s.notaryImportKey(c, repoName, "targets/other", s.not.keys[0].Private)
 	s.notaryPublish(c, repoName)
 
 	// push a different tag to the other role
 	otherTag := fmt.Sprintf("%s:other", repoName)
 	dockerCmd(c, "tag", "busybox", otherTag)
 
 	pushCmd := exec.Command(dockerBinary, "push", otherTag)
 	s.trustedCmd(pushCmd)
 	out, _, err := runCommandWithOutput(pushCmd)
 	c.Assert(err, check.IsNil, check.Commentf("Trusted push failed: %s", out))
 	s.assertTargetInRoles(c, repoName, "other", "targets/other")
 	s.assertTargetNotInRoles(c, repoName, "other", "targets")
 
 	out, status := dockerCmd(c, "rmi", otherTag)
 	c.Assert(status, check.Equals, 0, check.Commentf("docker rmi failed: %s", out))
 
 	dockerFile := fmt.Sprintf(`
   FROM %s
   RUN []
     `, otherTag)
 
 	name := "testtrustedbuildotherrole"
 
 	buildCmd := buildImageCmd(name, dockerFile, true)
 	s.trustedCmd(buildCmd)
 	out, _, err = runCommandWithOutput(buildCmd)
 	c.Assert(err, check.NotNil, check.Commentf("Trusted build expected to fail: %s", out))
 }
 
d45fcc6c
 // Issue #15634: COPY fails when path starts with "null"
 func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
 	name := "testbuildnullstringinaddcopyvolume"
 
5fc0de26
 	volName := "nullvolume"
 
 	if daemonPlatform == "windows" {
 		volName = `C:\\nullvolume`
 	}
 
d45fcc6c
 	ctx, err := fakeContext(`
 		FROM busybox
8e5bb8fd
 
d45fcc6c
 		ADD null /
 		COPY nullfile /
5fc0de26
 		VOLUME `+volName+`
d45fcc6c
 		`,
 		map[string]string{
 			"null":     "test1",
 			"nullfile": "test2",
 		},
 	)
a41f431d
 	c.Assert(err, check.IsNil)
04ef69a1
 	defer ctx.Close()
d45fcc6c
 
a41f431d
 	_, err = buildImageFromContext(name, ctx, true)
 	c.Assert(err, check.IsNil)
d45fcc6c
 }
3781cde6
 
 func (s *DockerSuite) TestBuildStopSignal(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support STOPSIGNAL yet
a252516e
 	imgName := "test_build_stop_signal"
 	_, err := buildImage(imgName,
3781cde6
 		`FROM busybox
 		 STOPSIGNAL SIGKILL`,
 		true)
 	c.Assert(err, check.IsNil)
a252516e
 	res := inspectFieldJSON(c, imgName, "Config.StopSignal")
 	if res != `"SIGKILL"` {
 		c.Fatalf("Signal %s, expected SIGKILL", res)
 	}
 
 	containerName := "test-container-stop-signal"
 	dockerCmd(c, "run", "-d", "--name", containerName, imgName, "top")
3781cde6
 
a252516e
 	res = inspectFieldJSON(c, containerName, "Config.StopSignal")
3781cde6
 	if res != `"SIGKILL"` {
 		c.Fatalf("Signal %s, expected SIGKILL", res)
 	}
 }
54240f8d
 
 func (s *DockerSuite) TestBuildBuildTimeArg(c *check.C) {
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
6b5c83bf
 	args := []string{"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)}
 	var dockerfile string
 	if daemonPlatform == "windows" {
 		// Bugs in Windows busybox port - use the default base image and native cmd stuff
 		dockerfile = fmt.Sprintf(`FROM `+minimalBaseImage()+`
 			ARG %s
 			RUN echo %%%s%%
 			CMD setlocal enableextensions && if defined %s (echo %%%s%%)`, envKey, envKey, envKey, envKey)
 	} else {
 		dockerfile = fmt.Sprintf(`FROM busybox
 			ARG %s
 			RUN echo $%s
 			CMD echo $%s`, envKey, envKey, envKey)
 
54240f8d
 	}
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || !strings.Contains(out, envVal) {
 		if err != nil {
 			c.Fatalf("build failed to complete: %q %q", out, err)
 		}
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envVal)
 	}
 
 	containerName := "bldargCont"
6b5c83bf
 	out, _ := dockerCmd(c, "run", "--name", containerName, imgName)
 	out = strings.Trim(out, " \r\n'")
 	if out != "" {
54240f8d
 		c.Fatalf("run produced invalid output: %q, expected empty string", out)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgHistory(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	envDef := "bar1"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s=%s`, envKey, envDef)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || !strings.Contains(out, envVal) {
 		if err != nil {
 			c.Fatalf("build failed to complete: %q %q", out, err)
 		}
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envVal)
 	}
 
 	out, _ := dockerCmd(c, "history", "--no-trunc", imgName)
 	outputTabs := strings.Split(out, "\n")[1]
 	if !strings.Contains(outputTabs, envDef) {
 		c.Fatalf("failed to find arg default in image history output: %q expected: %q", outputTabs, envDef)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgCacheHit(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		RUN echo $%s`, envKey, envKey)
 
 	origImgID := ""
 	var err error
 	if origImgID, err = buildImage(imgName, dockerfile, true, args...); err != nil {
 		c.Fatal(err)
 	}
 
 	imgNameCache := "bldargtestcachehit"
 	if newImgID, err := buildImage(imgNameCache, dockerfile, true, args...); err != nil || newImgID != origImgID {
 		if err != nil {
 			c.Fatal(err)
 		}
 		c.Fatalf("build didn't use cache! expected image id: %q built image id: %q", origImgID, newImgID)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgCacheMissExtraArg(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	extraEnvKey := "foo1"
 	extraEnvVal := "bar1"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		ARG %s
 		RUN echo $%s`, envKey, extraEnvKey, envKey)
 
 	origImgID := ""
 	var err error
 	if origImgID, err = buildImage(imgName, dockerfile, true, args...); err != nil {
 		c.Fatal(err)
 	}
 
 	imgNameCache := "bldargtestcachemiss"
 	args = append(args, "--build-arg", fmt.Sprintf("%s=%s", extraEnvKey, extraEnvVal))
 	if newImgID, err := buildImage(imgNameCache, dockerfile, true, args...); err != nil || newImgID == origImgID {
 		if err != nil {
 			c.Fatal(err)
 		}
 		c.Fatalf("build used cache, expected a miss!")
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgCacheMissSameArgDiffVal(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	newEnvVal := "bar1"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		RUN echo $%s`, envKey, envKey)
 
 	origImgID := ""
 	var err error
 	if origImgID, err = buildImage(imgName, dockerfile, true, args...); err != nil {
 		c.Fatal(err)
 	}
 
 	imgNameCache := "bldargtestcachemiss"
 	args = []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, newEnvVal),
 	}
 	if newImgID, err := buildImage(imgNameCache, dockerfile, true, args...); err != nil || newImgID == origImgID {
 		if err != nil {
 			c.Fatal(err)
 		}
 		c.Fatalf("build used cache, expected a miss!")
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgOverrideArgDefinedBeforeEnv(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	envValOveride := "barOverride"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		ENV %s %s
 		RUN echo $%s
 		CMD echo $%s
         `, envKey, envKey, envValOveride, envKey, envKey)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envValOveride) != 2 {
 		if err != nil {
 			c.Fatalf("build failed to complete: %q %q", out, err)
 		}
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envValOveride)
 	}
 
 	containerName := "bldargCont"
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOveride) {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOveride)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgOverrideEnvDefinedBeforeArg(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	envValOveride := "barOverride"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ENV %s %s
 		ARG %s
 		RUN echo $%s
 		CMD echo $%s
         `, envKey, envValOveride, envKey, envKey, envKey)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envValOveride) != 2 {
 		if err != nil {
 			c.Fatalf("build failed to complete: %q %q", out, err)
 		}
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envValOveride)
 	}
 
 	containerName := "bldargCont"
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOveride) {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOveride)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgExpansion(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldvarstest"
 
 	wdVar := "WDIR"
 	wdVal := "/tmp/"
 	addVar := "AFILE"
 	addVal := "addFile"
 	copyVar := "CFILE"
 	copyVal := "copyFile"
 	envVar := "foo"
 	envVal := "bar"
 	exposeVar := "EPORT"
 	exposeVal := "9999"
 	userVar := "USER"
 	userVal := "testUser"
 	volVar := "VOL"
 	volVal := "/testVol/"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", wdVar, wdVal),
 		"--build-arg", fmt.Sprintf("%s=%s", addVar, addVal),
 		"--build-arg", fmt.Sprintf("%s=%s", copyVar, copyVal),
 		"--build-arg", fmt.Sprintf("%s=%s", envVar, envVal),
 		"--build-arg", fmt.Sprintf("%s=%s", exposeVar, exposeVal),
 		"--build-arg", fmt.Sprintf("%s=%s", userVar, userVal),
 		"--build-arg", fmt.Sprintf("%s=%s", volVar, volVal),
 	}
 	ctx, err := fakeContext(fmt.Sprintf(`FROM busybox
 		ARG %s
 		WORKDIR ${%s}
 		ARG %s
 		ADD ${%s} testDir/
 		ARG %s
 		COPY $%s testDir/
 		ARG %s
 		ENV %s=${%s}
 		ARG %s
 		EXPOSE $%s
 		ARG %s
 		USER $%s
 		ARG %s
 		VOLUME ${%s}`,
 		wdVar, wdVar, addVar, addVar, copyVar, copyVar, envVar, envVar,
 		envVar, exposeVar, exposeVar, userVar, userVar, volVar, volVar),
 		map[string]string{
 			addVal:  "some stuff",
 			copyVal: "some stuff",
 		})
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer ctx.Close()
 
 	if _, err := buildImageFromContext(imgName, ctx, true, args...); err != nil {
 		c.Fatal(err)
 	}
 
 	var resMap map[string]interface{}
 	var resArr []string
 	res := ""
62a856e9
 	res = inspectField(c, imgName, "Config.WorkingDir")
d3392a3b
 	if res != filepath.ToSlash(filepath.Clean(wdVal)) {
 		c.Fatalf("Config.WorkingDir value mismatch. Expected: %s, got: %s", filepath.ToSlash(filepath.Clean(wdVal)), res)
54240f8d
 	}
 
62a856e9
 	inspectFieldAndMarshall(c, imgName, "Config.Env", &resArr)
54240f8d
 
 	found := false
 	for _, v := range resArr {
 		if fmt.Sprintf("%s=%s", envVar, envVal) == v {
 			found = true
 			break
 		}
 	}
 	if !found {
 		c.Fatalf("Config.Env value mismatch. Expected <key=value> to exist: %s=%s, got: %v",
 			envVar, envVal, resArr)
 	}
 
62a856e9
 	inspectFieldAndMarshall(c, imgName, "Config.ExposedPorts", &resMap)
54240f8d
 	if _, ok := resMap[fmt.Sprintf("%s/tcp", exposeVal)]; !ok {
 		c.Fatalf("Config.ExposedPorts value mismatch. Expected exposed port: %s/tcp, got: %v", exposeVal, resMap)
 	}
 
62a856e9
 	res = inspectField(c, imgName, "Config.User")
54240f8d
 	if res != userVal {
 		c.Fatalf("Config.User value mismatch. Expected: %s, got: %s", userVal, res)
 	}
 
62a856e9
 	inspectFieldAndMarshall(c, imgName, "Config.Volumes", &resMap)
54240f8d
 	if _, ok := resMap[volVal]; !ok {
 		c.Fatalf("Config.Volumes value mismatch. Expected volume: %s, got: %v", volVal, resMap)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgExpansionOverride(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldvarstest"
 	envKey := "foo"
 	envVal := "bar"
 	envKey1 := "foo1"
 	envValOveride := "barOverride"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		ENV %s %s
 		ENV %s ${%s}
 		RUN echo $%s
 		CMD echo $%s`, envKey, envKey, envValOveride, envKey1, envKey, envKey1, envKey1)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envValOveride) != 2 {
 		if err != nil {
 			c.Fatalf("build failed to complete: %q %q", out, err)
 		}
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envValOveride)
 	}
 
 	containerName := "bldargCont"
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOveride) {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOveride)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgUntrustedDefinedAfterUse(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		RUN echo $%s
 		ARG %s
 		CMD echo $%s`, envKey, envKey, envKey)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Contains(out, envVal) {
 		if err != nil {
 			c.Fatalf("build failed to complete: %q %q", out, err)
 		}
 		c.Fatalf("able to access environment variable in output: %q expected to be missing", out)
 	}
 
 	containerName := "bldargCont"
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); out != "\n" {
 		c.Fatalf("run produced invalid output: %q, expected empty string", out)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgBuiltinArg(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support --build-arg
54240f8d
 	imgName := "bldargtest"
 	envKey := "HTTP_PROXY"
 	envVal := "bar"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		RUN echo $%s
 		CMD echo $%s`, envKey, envKey)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || !strings.Contains(out, envVal) {
 		if err != nil {
 			c.Fatalf("build failed to complete: %q %q", out, err)
 		}
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envVal)
 	}
 
 	containerName := "bldargCont"
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); out != "\n" {
 		c.Fatalf("run produced invalid output: %q, expected empty string", out)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgDefaultOverride(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	envValOveride := "barOverride"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envValOveride),
 	}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s=%s
 		ENV %s $%s
 		RUN echo $%s
 		CMD echo $%s`, envKey, envVal, envKey, envKey, envKey, envKey)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envValOveride) != 1 {
 		if err != nil {
 			c.Fatalf("build failed to complete: %q %q", out, err)
 		}
 		c.Fatalf("failed to access environment variable in output: %q expected: %q", out, envValOveride)
 	}
 
 	containerName := "bldargCont"
 	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOveride) {
 		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOveride)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgUnconsumedArg(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support --build-arg
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envVal := "bar"
 	args := []string{
 		"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
 	}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		RUN echo $%s
 		CMD echo $%s`, envKey, envKey)
 
 	errStr := "One or more build-args"
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err == nil {
 		c.Fatalf("build succeeded, expected to fail. Output: %v", out)
 	} else if !strings.Contains(out, errStr) {
 		c.Fatalf("Unexpected error. output: %q, expected error: %q", out, errStr)
 	}
 
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgQuotedValVariants(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envKey1 := "foo1"
 	envKey2 := "foo2"
 	envKey3 := "foo3"
 	args := []string{}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s=""
 		ARG %s=''
 		ARG %s="''"
 		ARG %s='""'
 		RUN [ "$%s" != "$%s" ]
 		RUN [ "$%s" != "$%s" ]
 		RUN [ "$%s" != "$%s" ]
 		RUN [ "$%s" != "$%s" ]
 		RUN [ "$%s" != "$%s" ]`, envKey, envKey1, envKey2, envKey3,
 		envKey, envKey2, envKey, envKey3, envKey1, envKey2, envKey1, envKey3,
 		envKey2, envKey3)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil {
 		c.Fatalf("build failed to complete: %q %q", out, err)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgEmptyValVariants(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	envKey1 := "foo1"
 	envKey2 := "foo2"
 	args := []string{}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s=
 		ARG %s=""
 		ARG %s=''
 		RUN [ "$%s" == "$%s" ]
 		RUN [ "$%s" == "$%s" ]
 		RUN [ "$%s" == "$%s" ]`, envKey, envKey1, envKey2, envKey, envKey1, envKey1, envKey2, envKey, envKey2)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil {
 		c.Fatalf("build failed to complete: %q %q", out, err)
 	}
 }
 
 func (s *DockerSuite) TestBuildBuildTimeArgDefintionWithNoEnvInjection(c *check.C) {
5fc0de26
 	testRequires(c, DaemonIsLinux) // Windows does not support ARG
54240f8d
 	imgName := "bldargtest"
 	envKey := "foo"
 	args := []string{}
 	dockerfile := fmt.Sprintf(`FROM busybox
 		ARG %s
 		RUN env`, envKey)
 
 	if _, out, err := buildImageWithOut(imgName, dockerfile, true, args...); err != nil || strings.Count(out, envKey) != 1 {
 		if err != nil {
 			c.Fatalf("build failed to complete: %q %q", out, err)
 		}
 		c.Fatalf("unexpected number of occurrences of the arg in output: %q expected: 1", out)
 	}
 }
8e5bb8fd
 
 func (s *DockerSuite) TestBuildNoNamedVolume(c *check.C) {
5fc0de26
 	volName := "testname:/foo"
 
 	if daemonPlatform == "windows" {
 		volName = "testname:C:\\foo"
 	}
 	dockerCmd(c, "run", "-v", volName, "busybox", "sh", "-c", "touch /foo/oops")
8e5bb8fd
 
 	dockerFile := `FROM busybox
5fc0de26
 	VOLUME ` + volName + `
8e5bb8fd
 	RUN ls /foo/oops
 	`
 	_, err := buildImage("test", dockerFile, false)
 	c.Assert(err, check.NotNil, check.Commentf("image build should have failed"))
 }
2968fa44
 
 func (s *DockerSuite) TestBuildTagEvent(c *check.C) {
55053d35
 	since := daemonUnixTime(c)
2968fa44
 
 	dockerFile := `FROM busybox
 	RUN echo events
 	`
72f1881d
 	_, err := buildImage("test", dockerFile, false)
2968fa44
 	c.Assert(err, check.IsNil)
 
55053d35
 	until := daemonUnixTime(c)
 	out, _ := dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "type=image")
72f1881d
 	events := strings.Split(strings.TrimSpace(out), "\n")
 	actions := eventActionsByIDAndType(c, events, "test:latest", "image")
 	var foundTag bool
 	for _, a := range actions {
 		if a == "tag" {
 			foundTag = true
 			break
af51df20
 		}
 	}
 
72f1881d
 	c.Assert(foundTag, checker.True, check.Commentf("No tag event found:\n%s", out))
2968fa44
 }
c2eb37f9
 
 // #15780
 func (s *DockerSuite) TestBuildMultipleTags(c *check.C) {
 	dockerfile := `
 	FROM busybox
 	MAINTAINER test-15780
 	`
 	cmd := exec.Command(dockerBinary, "build", "-t", "tag1", "-t", "tag2:v2",
 		"-t", "tag1:latest", "-t", "tag1", "--no-cache", "-")
 	cmd.Stdin = strings.NewReader(dockerfile)
 	_, err := runCommand(cmd)
 	c.Assert(err, check.IsNil)
 
 	id1, err := getIDByName("tag1")
 	c.Assert(err, check.IsNil)
 	id2, err := getIDByName("tag2:v2")
 	c.Assert(err, check.IsNil)
 	c.Assert(id1, check.Equals, id2)
 }
47da59f7
 
 // #17290
 func (s *DockerSuite) TestBuildCacheBrokenSymlink(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 	name := "testbuildbrokensymlink"
 	ctx, err := fakeContext(`
 	FROM busybox
 	COPY . ./`,
 		map[string]string{
 			"foo": "bar",
 		})
 	c.Assert(err, checker.IsNil)
 	defer ctx.Close()
 
 	err = os.Symlink(filepath.Join(ctx.Dir, "nosuchfile"), filepath.Join(ctx.Dir, "asymlink"))
 	c.Assert(err, checker.IsNil)
 
 	// warm up cache
 	_, err = buildImageFromContext(name, ctx, true)
 	c.Assert(err, checker.IsNil)
 
 	// add new file to context, should invalidate cache
 	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "newfile"), []byte("foo"), 0644)
 	c.Assert(err, checker.IsNil)
 
 	_, out, err := buildImageFromContextWithOut(name, ctx, true)
 	c.Assert(err, checker.IsNil)
 
 	c.Assert(out, checker.Not(checker.Contains), "Using cache")
 
 }
 
 func (s *DockerSuite) TestBuildFollowSymlinkToFile(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 	name := "testbuildbrokensymlink"
 	ctx, err := fakeContext(`
 	FROM busybox
 	COPY asymlink target`,
 		map[string]string{
 			"foo": "bar",
 		})
 	c.Assert(err, checker.IsNil)
 	defer ctx.Close()
 
 	err = os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
 	c.Assert(err, checker.IsNil)
 
 	id, err := buildImageFromContext(name, ctx, true)
 	c.Assert(err, checker.IsNil)
 
 	out, _ := dockerCmd(c, "run", "--rm", id, "cat", "target")
 	c.Assert(out, checker.Matches, "bar")
 
 	// change target file should invalidate cache
 	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo"), []byte("baz"), 0644)
 	c.Assert(err, checker.IsNil)
 
 	id, out, err = buildImageFromContextWithOut(name, ctx, true)
 	c.Assert(err, checker.IsNil)
 	c.Assert(out, checker.Not(checker.Contains), "Using cache")
 
 	out, _ = dockerCmd(c, "run", "--rm", id, "cat", "target")
 	c.Assert(out, checker.Matches, "baz")
 }
 
 func (s *DockerSuite) TestBuildFollowSymlinkToDir(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 	name := "testbuildbrokensymlink"
 	ctx, err := fakeContext(`
 	FROM busybox
 	COPY asymlink /`,
 		map[string]string{
 			"foo/abc": "bar",
 			"foo/def": "baz",
 		})
 	c.Assert(err, checker.IsNil)
 	defer ctx.Close()
 
 	err = os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
 	c.Assert(err, checker.IsNil)
 
 	id, err := buildImageFromContext(name, ctx, true)
 	c.Assert(err, checker.IsNil)
 
 	out, _ := dockerCmd(c, "run", "--rm", id, "cat", "abc", "def")
 	c.Assert(out, checker.Matches, "barbaz")
 
 	// change target file should invalidate cache
 	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo/def"), []byte("bax"), 0644)
 	c.Assert(err, checker.IsNil)
 
 	id, out, err = buildImageFromContextWithOut(name, ctx, true)
 	c.Assert(err, checker.IsNil)
 	c.Assert(out, checker.Not(checker.Contains), "Using cache")
 
 	out, _ = dockerCmd(c, "run", "--rm", id, "cat", "abc", "def")
 	c.Assert(out, checker.Matches, "barbax")
 
 }
 
 // TestBuildSymlinkBasename tests that target file gets basename from symlink,
 // not from the target file.
 func (s *DockerSuite) TestBuildSymlinkBasename(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 	name := "testbuildbrokensymlink"
 	ctx, err := fakeContext(`
 	FROM busybox
 	COPY asymlink /`,
 		map[string]string{
 			"foo": "bar",
 		})
 	c.Assert(err, checker.IsNil)
 	defer ctx.Close()
 
 	err = os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
 	c.Assert(err, checker.IsNil)
 
 	id, err := buildImageFromContext(name, ctx, true)
 	c.Assert(err, checker.IsNil)
 
 	out, _ := dockerCmd(c, "run", "--rm", id, "cat", "asymlink")
 	c.Assert(out, checker.Matches, "bar")
 
 }
86faf1e1
 
 // #17827
 func (s *DockerSuite) TestBuildCacheRootSource(c *check.C) {
 	name := "testbuildrootsource"
 	ctx, err := fakeContext(`
 	FROM busybox
 	COPY / /data`,
 		map[string]string{
 			"foo": "bar",
 		})
 	c.Assert(err, checker.IsNil)
 	defer ctx.Close()
 
 	// warm up cache
 	_, err = buildImageFromContext(name, ctx, true)
 	c.Assert(err, checker.IsNil)
 
 	// change file, should invalidate cache
 	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo"), []byte("baz"), 0644)
 	c.Assert(err, checker.IsNil)
 
 	_, out, err := buildImageFromContextWithOut(name, ctx, true)
 	c.Assert(err, checker.IsNil)
 
 	c.Assert(out, checker.Not(checker.Contains), "Using cache")
 }
167cc429
 
 // #19375
 func (s *DockerSuite) TestBuildFailsGitNotCallable(c *check.C) {
 	cmd := exec.Command(dockerBinary, "build", "github.com/docker/v1.10-migrator.git")
 	cmd.Env = append(cmd.Env, "PATH=")
 	out, _, err := runCommandWithOutput(cmd)
 	c.Assert(err, checker.NotNil)
 	c.Assert(out, checker.Contains, "unable to prepare context: unable to find 'git': ")
 
 	cmd = exec.Command(dockerBinary, "build", "https://github.com/docker/v1.10-migrator.git")
 	cmd.Env = append(cmd.Env, "PATH=")
 	out, _, err = runCommandWithOutput(cmd)
 	c.Assert(err, checker.NotNil)
 	c.Assert(out, checker.Contains, "unable to prepare context: unable to find 'git': ")
 }
67912303
 
 // TestBuildWorkdirWindowsPath tests that a Windows style path works as a workdir
 func (s *DockerSuite) TestBuildWorkdirWindowsPath(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildworkdirwindowspath"
 
 	_, err := buildImage(name, `
 	FROM windowsservercore
 	RUN mkdir C:\\work
 	WORKDIR C:\\work
 	RUN if "%CD%" NEQ "C:\work" exit -1
 	`, true)
 
 	if err != nil {
 		c.Fatal(err)
 	}
 }
6fed46ae
 
fc214b44
 func (s *DockerSuite) TestBuildLabel(c *check.C) {
 	name := "testbuildlabel"
 	testLabel := "foo"
 
 	_, err := buildImage(name, `
   FROM `+minimalBaseImage()+`
   LABEL default foo
1a85c8eb
 `, false, "--label", testLabel)
fc214b44
 
1a85c8eb
 	c.Assert(err, checker.IsNil)
fc214b44
 
 	res := inspectFieldJSON(c, name, "Config.Labels")
 
 	var labels map[string]string
 
 	if err := json.Unmarshal([]byte(res), &labels); err != nil {
 		c.Fatal(err)
 	}
 
 	if _, ok := labels[testLabel]; !ok {
 		c.Fatal("label not found in image")
 	}
 }
 
1a85c8eb
 func (s *DockerSuite) TestBuildLabelOneNode(c *check.C) {
 	name := "testbuildlabel"
 
 	_, err := buildImage(name, "FROM busybox", false, "--label", "foo=bar")
 
 	c.Assert(err, checker.IsNil)
 
 	res, err := inspectImage(name, "json .Config.Labels")
 	c.Assert(err, checker.IsNil)
 	var labels map[string]string
 
 	if err := json.Unmarshal([]byte(res), &labels); err != nil {
 		c.Fatal(err)
 	}
 
 	v, ok := labels["foo"]
 	if !ok {
 		c.Fatal("label `foo` not found in image")
 	}
 	c.Assert(v, checker.Equals, "bar")
 }
 
fc214b44
 func (s *DockerSuite) TestBuildLabelCacheCommit(c *check.C) {
 	name := "testbuildlabelcachecommit"
 	testLabel := "foo"
 
 	if _, err := buildImage(name, `
   FROM `+minimalBaseImage()+`
   LABEL default foo
   `, false); err != nil {
 		c.Fatal(err)
 	}
 
 	_, err := buildImage(name, `
   FROM `+minimalBaseImage()+`
   LABEL default foo
1a85c8eb
 `, true, "--label", testLabel)
fc214b44
 
1a85c8eb
 	c.Assert(err, checker.IsNil)
fc214b44
 
 	res := inspectFieldJSON(c, name, "Config.Labels")
 
 	var labels map[string]string
 
 	if err := json.Unmarshal([]byte(res), &labels); err != nil {
 		c.Fatal(err)
 	}
 
 	if _, ok := labels[testLabel]; !ok {
 		c.Fatal("label not found in image")
 	}
 }
 
 func (s *DockerSuite) TestBuildLabelMultiple(c *check.C) {
 	name := "testbuildlabelmultiple"
 	testLabels := map[string]string{
 		"foo": "bar",
 		"123": "456",
 	}
 
 	labelArgs := []string{}
 
 	for k, v := range testLabels {
 		labelArgs = append(labelArgs, "--label", k+"="+v)
 	}
 
 	_, err := buildImage(name, `
   FROM `+minimalBaseImage()+`
   LABEL default foo
 `, false, labelArgs...)
 
 	if err != nil {
 		c.Fatal("error building image with labels", err)
 	}
 
 	res := inspectFieldJSON(c, name, "Config.Labels")
 
 	var labels map[string]string
 
 	if err := json.Unmarshal([]byte(res), &labels); err != nil {
 		c.Fatal(err)
 	}
 
 	for k, v := range testLabels {
 		if x, ok := labels[k]; !ok || x != v {
 			c.Fatalf("label %s=%s not found in image", k, v)
 		}
 	}
 }
 
 func (s *DockerSuite) TestBuildLabelOverwrite(c *check.C) {
 	name := "testbuildlabeloverwrite"
 	testLabel := "foo"
 	testValue := "bar"
 
 	_, err := buildImage(name, `
   FROM `+minimalBaseImage()+`
   LABEL `+testLabel+`+ foo
 `, false, []string{"--label", testLabel + "=" + testValue}...)
 
 	if err != nil {
 		c.Fatal("error building image with labels", err)
 	}
 
 	res := inspectFieldJSON(c, name, "Config.Labels")
 
 	var labels map[string]string
 
 	if err := json.Unmarshal([]byte(res), &labels); err != nil {
 		c.Fatal(err)
 	}
 
 	v, ok := labels[testLabel]
 	if !ok {
 		c.Fatal("label not found in image")
 	}
 
 	if v != testValue {
 		c.Fatal("label not overwritten")
 	}
 }
 
1b5c2e1d
 func (s *DockerRegistryAuthHtpasswdSuite) TestBuildFromAuthenticatedRegistry(c *check.C) {
aee260d4
 	dockerCmd(c, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
6fed46ae
 
 	baseImage := privateRegistryURL + "/baseimage"
 
 	_, err := buildImage(baseImage, `
 	FROM busybox
 	ENV env1 val1
 	`, true)
 
 	c.Assert(err, checker.IsNil)
 
 	dockerCmd(c, "push", baseImage)
 	dockerCmd(c, "rmi", baseImage)
 
 	_, err = buildImage(baseImage, fmt.Sprintf(`
 	FROM %s
 	ENV env2 val2
 	`, baseImage), true)
 
 	c.Assert(err, checker.IsNil)
 }
44152144
 
1b5c2e1d
 func (s *DockerRegistryAuthHtpasswdSuite) TestBuildWithExternalAuth(c *check.C) {
44152144
 	osPath := os.Getenv("PATH")
 	defer os.Setenv("PATH", osPath)
 
 	workingDir, err := os.Getwd()
 	c.Assert(err, checker.IsNil)
 	absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
 	c.Assert(err, checker.IsNil)
 	testPath := fmt.Sprintf("%s%c%s", osPath, filepath.ListSeparator, absolute)
 
 	os.Setenv("PATH", testPath)
 
 	repoName := fmt.Sprintf("%v/dockercli/busybox:authtest", privateRegistryURL)
 
 	tmp, err := ioutil.TempDir("", "integration-cli-")
 	c.Assert(err, checker.IsNil)
 
 	externalAuthConfig := `{ "credsStore": "shell-test" }`
 
 	configPath := filepath.Join(tmp, "config.json")
 	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
 	c.Assert(err, checker.IsNil)
 
 	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.username, "-p", s.reg.password, privateRegistryURL)
 
 	b, err := ioutil.ReadFile(configPath)
 	c.Assert(err, checker.IsNil)
 	c.Assert(string(b), checker.Not(checker.Contains), "\"auth\":")
 
 	dockerCmd(c, "--config", tmp, "tag", "busybox", repoName)
 	dockerCmd(c, "--config", tmp, "push", repoName)
 
 	// make sure the image is pulled when building
 	dockerCmd(c, "rmi", repoName)
 
 	buildCmd := exec.Command(dockerBinary, "--config", tmp, "build", "-")
 	buildCmd.Stdin = strings.NewReader(fmt.Sprintf("FROM %s", repoName))
 
 	out, _, err := runCommandWithOutput(buildCmd)
 	c.Assert(err, check.IsNil, check.Commentf(out))
 }
5844736c
 
 // Test cases in #22036
 func (s *DockerSuite) TestBuildLabelsOverride(c *check.C) {
 	testRequires(c, DaemonIsLinux)
 
 	// Command line option labels will always override
 	name := "scratchy"
 	expected := `{"bar":"from-flag","foo":"from-flag"}`
 	_, err := buildImage(name,
 		`FROM scratch
                 LABEL foo=from-dockerfile`,
 		true, "--label", "foo=from-flag", "--label", "bar=from-flag")
 	c.Assert(err, check.IsNil)
 
 	res := inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	name = "from"
 	expected = `{"foo":"from-dockerfile"}`
 	_, err = buildImage(name,
 		`FROM scratch
                 LABEL foo from-dockerfile`,
 		true)
 	c.Assert(err, check.IsNil)
 
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	// Command line option label will override even via `FROM`
 	name = "new"
 	expected = `{"bar":"from-dockerfile2","foo":"new"}`
 	_, err = buildImage(name,
 		`FROM from
                 LABEL bar from-dockerfile2`,
 		true, "--label", "foo=new")
 	c.Assert(err, check.IsNil)
 
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	// Command line option without a value set (--label foo, --label bar=)
 	// will be treated as --label foo="", --label bar=""
 	name = "scratchy2"
 	expected = `{"bar":"","foo":""}`
 	_, err = buildImage(name,
 		`FROM scratch
                 LABEL foo=from-dockerfile`,
 		true, "--label", "foo", "--label", "bar=")
 	c.Assert(err, check.IsNil)
 
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	// Command line option without a value set (--label foo, --label bar=)
 	// will be treated as --label foo="", --label bar=""
 	// This time is for inherited images
 	name = "new2"
 	expected = `{"bar":"","foo":""}`
 	_, err = buildImage(name,
 		`FROM from
                 LABEL bar from-dockerfile2`,
 		true, "--label", "foo=", "--label", "bar")
 	c.Assert(err, check.IsNil)
 
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 	// Command line option labels with only `FROM`
 	name = "scratchy"
 	expected = `{"bar":"from-flag","foo":"from-flag"}`
 	_, err = buildImage(name,
 		`FROM scratch`,
 		true, "--label", "foo=from-flag", "--label", "bar=from-flag")
 	c.Assert(err, check.IsNil)
 
 	res = inspectFieldJSON(c, name, "Config.Labels")
 	if res != expected {
 		c.Fatalf("Labels %s, expected %s", res, expected)
 	}
 
 }
d96e36cb
 
 // Test case for #22855
 func (s *DockerSuite) TestBuildDeleteCommittedFile(c *check.C) {
 	name := "test-delete-committed-file"
 
 	_, err := buildImage(name,
 		`FROM busybox
 		RUN echo test > file
 		RUN test -e file
 		RUN rm file
 		RUN sh -c "! test -e file"`, false)
 	if err != nil {
 		c.Fatal(err)
 	}
 }
8913dace
 
 // #20083
 func (s *DockerSuite) TestBuildDockerignoreComment(c *check.C) {
d75aaa2c
 	// TODO Windows: Figure out why this test is flakey on TP5. If you add
 	// something like RUN sleep 5, or even RUN ls /tmp after the ADD line,
 	// it is more reliable, but that's not a good fix.
 	testRequires(c, DaemonIsLinux)
 
8913dace
 	name := "testbuilddockerignorecleanpaths"
 	dockerfile := `
         FROM busybox
         ADD . /tmp/
         RUN sh -c "(ls -la /tmp/#1)"
         RUN sh -c "(! ls -la /tmp/#2)"
         RUN sh -c "(! ls /tmp/foo) && (! ls /tmp/foo2) && (ls /tmp/dir1/foo)"`
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"foo":      "foo",
 		"foo2":     "foo2",
 		"dir1/foo": "foo in dir1",
 		"#1":       "# file 1",
 		"#2":       "# file 2",
 		".dockerignore": `# Visual C++ cache files
 # because we have git ;-)
 # The above comment is from #20083
 foo
 #dir1/foo
 foo2
 # The following is considered as comment as # is at the beginning
 #1
 # The following is not considered as comment as # is not at the beginning
   #2
 `,
 	})
 	if err != nil {
 		c.Fatal(err)
 	}
 	defer ctx.Close()
 	if _, err := buildImageFromContext(name, ctx, true); err != nil {
 		c.Fatal(err)
 	}
 }
678c80f9
 
 // Test case for #23221
 func (s *DockerSuite) TestBuildWithUTF8BOM(c *check.C) {
 	name := "test-with-utf8-bom"
 	dockerfile := []byte(`FROM busybox`)
 	bomDockerfile := append([]byte{0xEF, 0xBB, 0xBF}, dockerfile...)
 	ctx, err := fakeContextFromNewTempDir()
 	c.Assert(err, check.IsNil)
 	defer ctx.Close()
 	err = ctx.addFile("Dockerfile", bomDockerfile)
 	c.Assert(err, check.IsNil)
 	_, err = buildImageFromContext(name, ctx, true)
 	c.Assert(err, check.IsNil)
 }
ea86320f
 
 // Test case for UTF-8 BOM in .dockerignore, related to #23221
 func (s *DockerSuite) TestBuildWithUTF8BOMDockerignore(c *check.C) {
 	name := "test-with-utf8-bom-dockerignore"
 	dockerfile := `
         FROM busybox
 		ADD . /tmp/
 		RUN ls -la /tmp
 		RUN sh -c "! ls /tmp/Dockerfile"
 		RUN ls /tmp/.dockerignore`
 	dockerignore := []byte("./Dockerfile\n")
 	bomDockerignore := append([]byte{0xEF, 0xBB, 0xBF}, dockerignore...)
 	ctx, err := fakeContext(dockerfile, map[string]string{
 		"Dockerfile": dockerfile,
 	})
 	c.Assert(err, check.IsNil)
 	defer ctx.Close()
 	err = ctx.addFile(".dockerignore", bomDockerignore)
 	c.Assert(err, check.IsNil)
 	_, err = buildImageFromContext(name, ctx, true)
 	if err != nil {
 		c.Fatal(err)
 	}
 }
b18ae8c9
 
 // #22489 Shell test to confirm config gets updated correctly
 func (s *DockerSuite) TestBuildShellUpdatesConfig(c *check.C) {
 	name := "testbuildshellupdatesconfig"
 
 	expected := `["foo","-bar","#(nop) ","SHELL [foo -bar]"]`
 	_, err := buildImage(name,
 		`FROM `+minimalBaseImage()+`
         SHELL ["foo", "-bar"]`,
 		true)
 	if err != nil {
 		c.Fatal(err)
 	}
 	res := inspectFieldJSON(c, name, "ContainerConfig.Cmd")
 	if res != expected {
 		c.Fatalf("%s, expected %s", res, expected)
 	}
 	res = inspectFieldJSON(c, name, "ContainerConfig.Shell")
 	if res != `["foo","-bar"]` {
 		c.Fatalf(`%s, expected ["foo","-bar"]`, res)
 	}
 }
 
 // #22489 Changing the shell multiple times and CMD after.
 func (s *DockerSuite) TestBuildShellMultiple(c *check.C) {
 	name := "testbuildshellmultiple"
 
 	_, out, _, err := buildImageWithStdoutStderr(name,
 		`FROM busybox
 		RUN echo defaultshell
 		SHELL ["echo"]
 		RUN echoshell
 		SHELL ["ls"]
 		RUN -l
 		CMD -l`,
 		true)
 	if err != nil {
 		c.Fatal(err)
 	}
 
 	// Must contain 'defaultshell' twice
 	if len(strings.Split(out, "defaultshell")) != 3 {
 		c.Fatalf("defaultshell should have appeared twice in %s", out)
 	}
 
 	// Must contain 'echoshell' twice
 	if len(strings.Split(out, "echoshell")) != 3 {
 		c.Fatalf("echoshell should have appeared twice in %s", out)
 	}
 
 	// Must contain "total " (part of ls -l)
 	if !strings.Contains(out, "total ") {
 		c.Fatalf("%s should have contained 'total '", out)
 	}
 
 	// A container started from the image uses the shell-form CMD.
 	// Last shell is ls. CMD is -l. So should contain 'total '.
 	outrun, _ := dockerCmd(c, "run", "--rm", name)
 	if !strings.Contains(outrun, "total ") {
 		c.Fatalf("Expected started container to run ls -l. %s", outrun)
 	}
 }
 
 // #22489. Changed SHELL with ENTRYPOINT
 func (s *DockerSuite) TestBuildShellEntrypoint(c *check.C) {
 	name := "testbuildshellentrypoint"
 
 	_, err := buildImage(name,
 		`FROM busybox
 		SHELL ["ls"]
 		ENTRYPOINT -l`,
 		true)
 	if err != nil {
 		c.Fatal(err)
 	}
 
 	// A container started from the image uses the shell-form ENTRYPOINT.
 	// Shell is ls. ENTRYPOINT is -l. So should contain 'total '.
 	outrun, _ := dockerCmd(c, "run", "--rm", name)
 	if !strings.Contains(outrun, "total ") {
 		c.Fatalf("Expected started container to run ls -l. %s", outrun)
 	}
 }
 
 // #22489 Shell test to confirm shell is inherited in a subsequent build
 func (s *DockerSuite) TestBuildShellInherited(c *check.C) {
 	name1 := "testbuildshellinherited1"
 	_, err := buildImage(name1,
 		`FROM busybox
         SHELL ["ls"]`,
 		true)
 	if err != nil {
 		c.Fatal(err)
 	}
 
 	name2 := "testbuildshellinherited2"
 	_, out, _, err := buildImageWithStdoutStderr(name2,
 		`FROM `+name1+`
         RUN -l`,
 		true)
 	if err != nil {
 		c.Fatal(err)
 	}
 
 	// ls -l has "total " followed by some number in it, ls without -l does not.
 	if !strings.Contains(out, "total ") {
 		c.Fatalf("Should have seen total in 'ls -l'.\n%s", out)
 	}
 }
 
 // #22489 Shell test to confirm non-JSON doesn't work
 func (s *DockerSuite) TestBuildShellNotJSON(c *check.C) {
 	name := "testbuildshellnotjson"
 
 	_, err := buildImage(name,
 		`FROM `+minimalBaseImage()+`
         sHeLl exec -form`, // Casing explicit to ensure error is upper-cased.
 		true)
 	if err == nil {
 		c.Fatal("Image build should have failed")
 	}
 	if !strings.Contains(err.Error(), "SHELL requires the arguments to be in JSON form") {
 		c.Fatal("Error didn't indicate that arguments must be in JSON form")
 	}
 }
 
 // #22489 Windows shell test to confirm native is powershell if executing a PS command
 // This would error if the default shell were still cmd.
 func (s *DockerSuite) TestBuildShellWindowsPowershell(c *check.C) {
 	testRequires(c, DaemonIsWindows)
 	name := "testbuildshellpowershell"
 	_, out, err := buildImageWithOut(name,
 		`FROM `+minimalBaseImage()+`
         SHELL ["powershell", "-command"]
 		RUN Write-Host John`,
 		true)
 	if err != nil {
 		c.Fatal(err)
 	}
 	if !strings.Contains(out, "\nJohn\n") {
 		c.Fatalf("Line with 'John' not found in output %q", out)
 	}
 }