github.com/jwhonce/docker@v0.6.7-0.20190327063223-da823cf3a5a3/integration-cli/docker_cli_build_test.go (about)

     1  package main
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io/ioutil"
     9  	"os"
    10  	"path/filepath"
    11  	"reflect"
    12  	"regexp"
    13  	"runtime"
    14  	"strconv"
    15  	"strings"
    16  	"text/template"
    17  	"time"
    18  
    19  	"github.com/docker/docker/integration-cli/checker"
    20  	"github.com/docker/docker/integration-cli/cli"
    21  	"github.com/docker/docker/integration-cli/cli/build"
    22  	"github.com/docker/docker/internal/test/fakecontext"
    23  	"github.com/docker/docker/internal/test/fakegit"
    24  	"github.com/docker/docker/internal/test/fakestorage"
    25  	"github.com/docker/docker/internal/testutil"
    26  	"github.com/docker/docker/pkg/archive"
    27  	"github.com/docker/docker/pkg/system"
    28  	"github.com/go-check/check"
    29  	"github.com/moby/buildkit/frontend/dockerfile/command"
    30  	"github.com/opencontainers/go-digest"
    31  	"gotest.tools/icmd"
    32  )
    33  
    34  func (s *DockerSuite) TestBuildJSONEmptyRun(c *check.C) {
    35  	cli.BuildCmd(c, "testbuildjsonemptyrun", build.WithDockerfile(`
    36      FROM busybox
    37      RUN []
    38      `))
    39  }
    40  
    41  func (s *DockerSuite) TestBuildShCmdJSONEntrypoint(c *check.C) {
    42  	name := "testbuildshcmdjsonentrypoint"
    43  	expected := "/bin/sh -c echo test"
    44  	if testEnv.OSType == "windows" {
    45  		expected = "cmd /S /C echo test"
    46  	}
    47  
    48  	buildImageSuccessfully(c, name, build.WithDockerfile(`
    49      FROM busybox
    50      ENTRYPOINT ["echo"]
    51      CMD echo test
    52      `))
    53  	out, _ := dockerCmd(c, "run", "--rm", name)
    54  
    55  	if strings.TrimSpace(out) != expected {
    56  		c.Fatalf("CMD did not contain %q : %q", expected, out)
    57  	}
    58  }
    59  
    60  func (s *DockerSuite) TestBuildEnvironmentReplacementUser(c *check.C) {
    61  	// Windows does not support FROM scratch or the USER command
    62  	testRequires(c, DaemonIsLinux)
    63  	name := "testbuildenvironmentreplacement"
    64  
    65  	buildImageSuccessfully(c, name, build.WithDockerfile(`
    66    FROM scratch
    67    ENV user foo
    68    USER ${user}
    69    `))
    70  	res := inspectFieldJSON(c, name, "Config.User")
    71  
    72  	if res != `"foo"` {
    73  		c.Fatal("User foo from environment not in Config.User on image")
    74  	}
    75  }
    76  
    77  func (s *DockerSuite) TestBuildEnvironmentReplacementVolume(c *check.C) {
    78  	name := "testbuildenvironmentreplacement"
    79  
    80  	var volumePath string
    81  
    82  	if testEnv.OSType == "windows" {
    83  		volumePath = "c:/quux"
    84  	} else {
    85  		volumePath = "/quux"
    86  	}
    87  
    88  	buildImageSuccessfully(c, name, build.WithDockerfile(`
    89    FROM `+minimalBaseImage()+`
    90    ENV volume `+volumePath+`
    91    VOLUME ${volume}
    92    `))
    93  
    94  	var volumes map[string]interface{}
    95  	inspectFieldAndUnmarshall(c, name, "Config.Volumes", &volumes)
    96  	if _, ok := volumes[volumePath]; !ok {
    97  		c.Fatal("Volume " + volumePath + " from environment not in Config.Volumes on image")
    98  	}
    99  
   100  }
   101  
   102  func (s *DockerSuite) TestBuildEnvironmentReplacementExpose(c *check.C) {
   103  	// Windows does not support FROM scratch or the EXPOSE command
   104  	testRequires(c, DaemonIsLinux)
   105  	name := "testbuildenvironmentreplacement"
   106  
   107  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   108    FROM scratch
   109    ENV port 80
   110    EXPOSE ${port}
   111    ENV ports "  99   100 "
   112    EXPOSE ${ports}
   113    `))
   114  
   115  	var exposedPorts map[string]interface{}
   116  	inspectFieldAndUnmarshall(c, name, "Config.ExposedPorts", &exposedPorts)
   117  	exp := []int{80, 99, 100}
   118  	for _, p := range exp {
   119  		tmp := fmt.Sprintf("%d/tcp", p)
   120  		if _, ok := exposedPorts[tmp]; !ok {
   121  			c.Fatalf("Exposed port %d from environment not in Config.ExposedPorts on image", p)
   122  		}
   123  	}
   124  
   125  }
   126  
   127  func (s *DockerSuite) TestBuildEnvironmentReplacementWorkdir(c *check.C) {
   128  	name := "testbuildenvironmentreplacement"
   129  
   130  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   131    FROM busybox
   132    ENV MYWORKDIR /work
   133    RUN mkdir ${MYWORKDIR}
   134    WORKDIR ${MYWORKDIR}
   135    `))
   136  	res := inspectFieldJSON(c, name, "Config.WorkingDir")
   137  
   138  	expected := `"/work"`
   139  	if testEnv.OSType == "windows" {
   140  		expected = `"C:\\work"`
   141  	}
   142  	if res != expected {
   143  		c.Fatalf("Workdir /workdir from environment not in Config.WorkingDir on image: %s", res)
   144  	}
   145  }
   146  
   147  func (s *DockerSuite) TestBuildEnvironmentReplacementAddCopy(c *check.C) {
   148  	name := "testbuildenvironmentreplacement"
   149  
   150  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
   151  		build.WithFile("Dockerfile", `
   152    FROM `+minimalBaseImage()+`
   153    ENV baz foo
   154    ENV quux bar
   155    ENV dot .
   156    ENV fee fff
   157    ENV gee ggg
   158  
   159    ADD ${baz} ${dot}
   160    COPY ${quux} ${dot}
   161    ADD ${zzz:-${fee}} ${dot}
   162    COPY ${zzz:-${gee}} ${dot}
   163    `),
   164  		build.WithFile("foo", "test1"),
   165  		build.WithFile("bar", "test2"),
   166  		build.WithFile("fff", "test3"),
   167  		build.WithFile("ggg", "test4"),
   168  	))
   169  }
   170  
   171  func (s *DockerSuite) TestBuildEnvironmentReplacementEnv(c *check.C) {
   172  	// ENV expansions work differently in Windows
   173  	testRequires(c, DaemonIsLinux)
   174  	name := "testbuildenvironmentreplacement"
   175  
   176  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   177    FROM busybox
   178    ENV foo zzz
   179    ENV bar ${foo}
   180    ENV abc1='$foo'
   181    ENV env1=$foo env2=${foo} env3="$foo" env4="${foo}"
   182    RUN [ "$abc1" = '$foo' ] && (echo "$abc1" | grep -q foo)
   183    ENV abc2="\$foo"
   184    RUN [ "$abc2" = '$foo' ] && (echo "$abc2" | grep -q foo)
   185    ENV abc3 '$foo'
   186    RUN [ "$abc3" = '$foo' ] && (echo "$abc3" | grep -q foo)
   187    ENV abc4 "\$foo"
   188    RUN [ "$abc4" = '$foo' ] && (echo "$abc4" | grep -q foo)
   189    ENV foo2="abc\def"
   190    RUN [ "$foo2" = 'abc\def' ]
   191    ENV foo3="abc\\def"
   192    RUN [ "$foo3" = 'abc\def' ]
   193    ENV foo4='abc\\def'
   194    RUN [ "$foo4" = 'abc\\def' ]
   195    ENV foo5='abc\def'
   196    RUN [ "$foo5" = 'abc\def' ]
   197    `))
   198  
   199  	var envResult []string
   200  	inspectFieldAndUnmarshall(c, name, "Config.Env", &envResult)
   201  	found := false
   202  	envCount := 0
   203  
   204  	for _, env := range envResult {
   205  		parts := strings.SplitN(env, "=", 2)
   206  		if parts[0] == "bar" {
   207  			found = true
   208  			if parts[1] != "zzz" {
   209  				c.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1])
   210  			}
   211  		} else if strings.HasPrefix(parts[0], "env") {
   212  			envCount++
   213  			if parts[1] != "zzz" {
   214  				c.Fatalf("%s should be 'zzz' but instead its %q", parts[0], parts[1])
   215  			}
   216  		} else if strings.HasPrefix(parts[0], "env") {
   217  			envCount++
   218  			if parts[1] != "foo" {
   219  				c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
   220  			}
   221  		}
   222  	}
   223  
   224  	if !found {
   225  		c.Fatal("Never found the `bar` env variable")
   226  	}
   227  
   228  	if envCount != 4 {
   229  		c.Fatalf("Didn't find all env vars - only saw %d\n%s", envCount, envResult)
   230  	}
   231  
   232  }
   233  
   234  func (s *DockerSuite) TestBuildHandleEscapesInVolume(c *check.C) {
   235  	// The volume paths used in this test are invalid on Windows
   236  	testRequires(c, DaemonIsLinux)
   237  	name := "testbuildhandleescapes"
   238  
   239  	testCases := []struct {
   240  		volumeValue string
   241  		expected    string
   242  	}{
   243  		{
   244  			volumeValue: "${FOO}",
   245  			expected:    "bar",
   246  		},
   247  		{
   248  			volumeValue: `\${FOO}`,
   249  			expected:    "${FOO}",
   250  		},
   251  		// this test in particular provides *7* backslashes and expects 6 to come back.
   252  		// Like above, the first escape is swallowed and the rest are treated as
   253  		// literals, this one is just less obvious because of all the character noise.
   254  		{
   255  			volumeValue: `\\\\\\\${FOO}`,
   256  			expected:    `\\\${FOO}`,
   257  		},
   258  	}
   259  
   260  	for _, tc := range testCases {
   261  		buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`
   262    FROM scratch
   263    ENV FOO bar
   264    VOLUME %s
   265    `, tc.volumeValue)))
   266  
   267  		var result map[string]map[string]struct{}
   268  		inspectFieldAndUnmarshall(c, name, "Config.Volumes", &result)
   269  		if _, ok := result[tc.expected]; !ok {
   270  			c.Fatalf("Could not find volume %s set from env foo in volumes table, got %q", tc.expected, result)
   271  		}
   272  
   273  		// Remove the image for the next iteration
   274  		dockerCmd(c, "rmi", name)
   275  	}
   276  }
   277  
   278  func (s *DockerSuite) TestBuildOnBuildLowercase(c *check.C) {
   279  	name := "testbuildonbuildlowercase"
   280  	name2 := "testbuildonbuildlowercase2"
   281  
   282  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   283    FROM busybox
   284    onbuild run echo quux
   285    `))
   286  
   287  	result := buildImage(name2, build.WithDockerfile(fmt.Sprintf(`
   288    FROM %s
   289    `, name)))
   290  	result.Assert(c, icmd.Success)
   291  
   292  	if !strings.Contains(result.Combined(), "quux") {
   293  		c.Fatalf("Did not receive the expected echo text, got %s", result.Combined())
   294  	}
   295  
   296  	if strings.Contains(result.Combined(), "ONBUILD ONBUILD") {
   297  		c.Fatalf("Got an ONBUILD ONBUILD error with no error: got %s", result.Combined())
   298  	}
   299  
   300  }
   301  
   302  func (s *DockerSuite) TestBuildEnvEscapes(c *check.C) {
   303  	// ENV expansions work differently in Windows
   304  	testRequires(c, DaemonIsLinux)
   305  	name := "testbuildenvescapes"
   306  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   307      FROM busybox
   308      ENV TEST foo
   309      CMD echo \$
   310      `))
   311  
   312  	out, _ := dockerCmd(c, "run", "-t", name)
   313  	if strings.TrimSpace(out) != "$" {
   314  		c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
   315  	}
   316  
   317  }
   318  
   319  func (s *DockerSuite) TestBuildEnvOverwrite(c *check.C) {
   320  	// ENV expansions work differently in Windows
   321  	testRequires(c, DaemonIsLinux)
   322  	name := "testbuildenvoverwrite"
   323  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   324      FROM busybox
   325      ENV TEST foo
   326      CMD echo ${TEST}
   327      `))
   328  
   329  	out, _ := dockerCmd(c, "run", "-e", "TEST=bar", "-t", name)
   330  	if strings.TrimSpace(out) != "bar" {
   331  		c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
   332  	}
   333  
   334  }
   335  
   336  // FIXME(vdemeester) why we disabled cache here ?
   337  func (s *DockerSuite) TestBuildOnBuildCmdEntrypointJSON(c *check.C) {
   338  	name1 := "onbuildcmd"
   339  	name2 := "onbuildgenerated"
   340  
   341  	cli.BuildCmd(c, name1, build.WithDockerfile(`
   342  FROM busybox
   343  ONBUILD CMD ["hello world"]
   344  ONBUILD ENTRYPOINT ["echo"]
   345  ONBUILD RUN ["true"]`))
   346  
   347  	cli.BuildCmd(c, name2, build.WithDockerfile(fmt.Sprintf(`FROM %s`, name1)))
   348  
   349  	result := cli.DockerCmd(c, "run", name2)
   350  	result.Assert(c, icmd.Expected{Out: "hello world"})
   351  }
   352  
   353  // FIXME(vdemeester) why we disabled cache here ?
   354  func (s *DockerSuite) TestBuildOnBuildEntrypointJSON(c *check.C) {
   355  	name1 := "onbuildcmd"
   356  	name2 := "onbuildgenerated"
   357  
   358  	buildImageSuccessfully(c, name1, build.WithDockerfile(`
   359  FROM busybox
   360  ONBUILD ENTRYPOINT ["echo"]`))
   361  
   362  	buildImageSuccessfully(c, name2, build.WithDockerfile(fmt.Sprintf("FROM %s\nCMD [\"hello world\"]\n", name1)))
   363  
   364  	out, _ := dockerCmd(c, "run", name2)
   365  	if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) {
   366  		c.Fatal("got malformed output from onbuild", out)
   367  	}
   368  
   369  }
   370  
   371  func (s *DockerSuite) TestBuildCacheAdd(c *check.C) {
   372  	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
   373  	name := "testbuildtwoimageswithadd"
   374  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   375  		"robots.txt": "hello",
   376  		"index.html": "world",
   377  	}))
   378  	defer server.Close()
   379  
   380  	cli.BuildCmd(c, name, build.WithDockerfile(fmt.Sprintf(`FROM scratch
   381  		ADD %s/robots.txt /`, server.URL())))
   382  
   383  	result := cli.Docker(cli.Build(name), build.WithDockerfile(fmt.Sprintf(`FROM scratch
   384  		ADD %s/index.html /`, server.URL())))
   385  	result.Assert(c, icmd.Success)
   386  	if strings.Contains(result.Combined(), "Using cache") {
   387  		c.Fatal("2nd build used cache on ADD, it shouldn't")
   388  	}
   389  }
   390  
   391  func (s *DockerSuite) TestBuildLastModified(c *check.C) {
   392  	// Temporary fix for #30890. TODO @jhowardmsft figure out what
   393  	// has changed in the master busybox image.
   394  	testRequires(c, DaemonIsLinux)
   395  
   396  	name := "testbuildlastmodified"
   397  
   398  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   399  		"file": "hello",
   400  	}))
   401  	defer server.Close()
   402  
   403  	var out, out2 string
   404  	args := []string{"run", name, "ls", "-l", "--full-time", "/file"}
   405  
   406  	dFmt := `FROM busybox
   407  ADD %s/file /`
   408  	dockerfile := fmt.Sprintf(dFmt, server.URL())
   409  
   410  	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
   411  	out = cli.DockerCmd(c, args...).Combined()
   412  
   413  	// Build it again and make sure the mtime of the file didn't change.
   414  	// Wait a few seconds to make sure the time changed enough to notice
   415  	time.Sleep(2 * time.Second)
   416  
   417  	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
   418  	out2 = cli.DockerCmd(c, args...).Combined()
   419  
   420  	if out != out2 {
   421  		c.Fatalf("MTime changed:\nOrigin:%s\nNew:%s", out, out2)
   422  	}
   423  
   424  	// Now 'touch' the file and make sure the timestamp DID change this time
   425  	// Create a new fakeStorage instead of just using Add() to help windows
   426  	server = fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   427  		"file": "hello",
   428  	}))
   429  	defer server.Close()
   430  
   431  	dockerfile = fmt.Sprintf(dFmt, server.URL())
   432  	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
   433  	out2 = cli.DockerCmd(c, args...).Combined()
   434  
   435  	if out == out2 {
   436  		c.Fatalf("MTime didn't change:\nOrigin:%s\nNew:%s", out, out2)
   437  	}
   438  
   439  }
   440  
   441  // Regression for https://github.com/docker/docker/pull/27805
   442  // Makes sure that we don't use the cache if the contents of
   443  // a file in a subfolder of the context is modified and we re-build.
   444  func (s *DockerSuite) TestBuildModifyFileInFolder(c *check.C) {
   445  	name := "testbuildmodifyfileinfolder"
   446  
   447  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
   448  RUN ["mkdir", "/test"]
   449  ADD folder/file /test/changetarget`))
   450  	defer ctx.Close()
   451  	if err := ctx.Add("folder/file", "first"); err != nil {
   452  		c.Fatal(err)
   453  	}
   454  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
   455  	id1 := getIDByName(c, name)
   456  	if err := ctx.Add("folder/file", "second"); err != nil {
   457  		c.Fatal(err)
   458  	}
   459  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
   460  	id2 := getIDByName(c, name)
   461  	if id1 == id2 {
   462  		c.Fatal("cache was used even though file contents in folder was changed")
   463  	}
   464  }
   465  
   466  func (s *DockerSuite) TestBuildAddSingleFileToRoot(c *check.C) {
   467  	testRequires(c, DaemonIsLinux) // Linux specific test
   468  	buildImageSuccessfully(c, "testaddimg", build.WithBuildContext(c,
   469  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   470  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   471  RUN echo 'dockerio:x:1001:' >> /etc/group
   472  RUN touch /exists
   473  RUN chown dockerio.dockerio /exists
   474  ADD test_file /
   475  RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
   476  RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ]
   477  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
   478  		build.WithFile("test_file", "test1")))
   479  }
   480  
   481  // Issue #3960: "ADD src ." hangs
   482  func (s *DockerSuite) TestBuildAddSingleFileToWorkdir(c *check.C) {
   483  	name := "testaddsinglefiletoworkdir"
   484  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(
   485  		`FROM busybox
   486  	       ADD test_file .`),
   487  		fakecontext.WithFiles(map[string]string{
   488  			"test_file": "test1",
   489  		}))
   490  	defer ctx.Close()
   491  
   492  	errChan := make(chan error)
   493  	go func() {
   494  		errChan <- buildImage(name, build.WithExternalBuildContext(ctx)).Error
   495  		close(errChan)
   496  	}()
   497  	select {
   498  	case <-time.After(15 * time.Second):
   499  		c.Fatal("Build with adding to workdir timed out")
   500  	case err := <-errChan:
   501  		c.Assert(err, check.IsNil)
   502  	}
   503  }
   504  
   505  func (s *DockerSuite) TestBuildAddSingleFileToExistDir(c *check.C) {
   506  	testRequires(c, DaemonIsLinux) // Linux specific test
   507  	cli.BuildCmd(c, "testaddsinglefiletoexistdir", build.WithBuildContext(c,
   508  		build.WithFile("Dockerfile", `FROM busybox
   509  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   510  RUN echo 'dockerio:x:1001:' >> /etc/group
   511  RUN mkdir /exists
   512  RUN touch /exists/exists_file
   513  RUN chown -R dockerio.dockerio /exists
   514  ADD test_file /exists/
   515  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   516  RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]
   517  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   518  		build.WithFile("test_file", "test1")))
   519  }
   520  
   521  func (s *DockerSuite) TestBuildCopyAddMultipleFiles(c *check.C) {
   522  	testRequires(c, DaemonIsLinux) // Linux specific test
   523  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   524  		"robots.txt": "hello",
   525  	}))
   526  	defer server.Close()
   527  
   528  	cli.BuildCmd(c, "testcopymultiplefilestofile", build.WithBuildContext(c,
   529  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   530  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   531  RUN echo 'dockerio:x:1001:' >> /etc/group
   532  RUN mkdir /exists
   533  RUN touch /exists/exists_file
   534  RUN chown -R dockerio.dockerio /exists
   535  COPY test_file1 test_file2 /exists/
   536  ADD test_file3 test_file4 %s/robots.txt /exists/
   537  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   538  RUN [ $(ls -l /exists/test_file1 | awk '{print $3":"$4}') = 'root:root' ]
   539  RUN [ $(ls -l /exists/test_file2 | awk '{print $3":"$4}') = 'root:root' ]
   540  RUN [ $(ls -l /exists/test_file3 | awk '{print $3":"$4}') = 'root:root' ]
   541  RUN [ $(ls -l /exists/test_file4 | awk '{print $3":"$4}') = 'root:root' ]
   542  RUN [ $(ls -l /exists/robots.txt | awk '{print $3":"$4}') = 'root:root' ]
   543  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   544  `, server.URL())),
   545  		build.WithFile("test_file1", "test1"),
   546  		build.WithFile("test_file2", "test2"),
   547  		build.WithFile("test_file3", "test3"),
   548  		build.WithFile("test_file3", "test3"),
   549  		build.WithFile("test_file4", "test4")))
   550  }
   551  
   552  // These tests are mainly for user namespaces to verify that new directories
   553  // are created as the remapped root uid/gid pair
   554  func (s *DockerSuite) TestBuildUsernamespaceValidateRemappedRoot(c *check.C) {
   555  	testRequires(c, DaemonIsLinux)
   556  	testCases := []string{
   557  		"ADD . /new_dir",
   558  		"COPY test_dir /new_dir",
   559  		"WORKDIR /new_dir",
   560  	}
   561  	name := "testbuildusernamespacevalidateremappedroot"
   562  	for _, tc := range testCases {
   563  		cli.BuildCmd(c, name, build.WithBuildContext(c,
   564  			build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   565  %s
   566  RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'root:root' ]`, tc)),
   567  			build.WithFile("test_dir/test_file", "test file")))
   568  
   569  		cli.DockerCmd(c, "rmi", name)
   570  	}
   571  }
   572  
   573  func (s *DockerSuite) TestBuildAddAndCopyFileWithWhitespace(c *check.C) {
   574  	testRequires(c, DaemonIsLinux) // Not currently passing on Windows
   575  	name := "testaddfilewithwhitespace"
   576  
   577  	for _, command := range []string{"ADD", "COPY"} {
   578  		cli.BuildCmd(c, name, build.WithBuildContext(c,
   579  			build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   580  RUN mkdir "/test dir"
   581  RUN mkdir "/test_dir"
   582  %s [ "test file1", "/test_file1" ]
   583  %s [ "test_file2", "/test file2" ]
   584  %s [ "test file3", "/test file3" ]
   585  %s [ "test dir/test_file4", "/test_dir/test_file4" ]
   586  %s [ "test_dir/test_file5", "/test dir/test_file5" ]
   587  %s [ "test dir/test_file6", "/test dir/test_file6" ]
   588  RUN [ $(cat "/test_file1") = 'test1' ]
   589  RUN [ $(cat "/test file2") = 'test2' ]
   590  RUN [ $(cat "/test file3") = 'test3' ]
   591  RUN [ $(cat "/test_dir/test_file4") = 'test4' ]
   592  RUN [ $(cat "/test dir/test_file5") = 'test5' ]
   593  RUN [ $(cat "/test dir/test_file6") = 'test6' ]`, command, command, command, command, command, command)),
   594  			build.WithFile("test file1", "test1"),
   595  			build.WithFile("test_file2", "test2"),
   596  			build.WithFile("test file3", "test3"),
   597  			build.WithFile("test dir/test_file4", "test4"),
   598  			build.WithFile("test_dir/test_file5", "test5"),
   599  			build.WithFile("test dir/test_file6", "test6"),
   600  		))
   601  
   602  		cli.DockerCmd(c, "rmi", name)
   603  	}
   604  }
   605  
   606  func (s *DockerSuite) TestBuildCopyFileWithWhitespaceOnWindows(c *check.C) {
   607  	testRequires(c, DaemonIsWindows)
   608  	dockerfile := `FROM ` + testEnv.PlatformDefaults.BaseImage + `
   609  RUN mkdir "C:/test dir"
   610  RUN mkdir "C:/test_dir"
   611  COPY [ "test file1", "/test_file1" ]
   612  COPY [ "test_file2", "/test file2" ]
   613  COPY [ "test file3", "/test file3" ]
   614  COPY [ "test dir/test_file4", "/test_dir/test_file4" ]
   615  COPY [ "test_dir/test_file5", "/test dir/test_file5" ]
   616  COPY [ "test dir/test_file6", "/test dir/test_file6" ]
   617  RUN find "test1" "C:/test_file1"
   618  RUN find "test2" "C:/test file2"
   619  RUN find "test3" "C:/test file3"
   620  RUN find "test4" "C:/test_dir/test_file4"
   621  RUN find "test5" "C:/test dir/test_file5"
   622  RUN find "test6" "C:/test dir/test_file6"`
   623  
   624  	name := "testcopyfilewithwhitespace"
   625  	cli.BuildCmd(c, name, build.WithBuildContext(c,
   626  		build.WithFile("Dockerfile", dockerfile),
   627  		build.WithFile("test file1", "test1"),
   628  		build.WithFile("test_file2", "test2"),
   629  		build.WithFile("test file3", "test3"),
   630  		build.WithFile("test dir/test_file4", "test4"),
   631  		build.WithFile("test_dir/test_file5", "test5"),
   632  		build.WithFile("test dir/test_file6", "test6"),
   633  	))
   634  }
   635  
   636  func (s *DockerSuite) TestBuildCopyWildcard(c *check.C) {
   637  	name := "testcopywildcard"
   638  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   639  		"robots.txt": "hello",
   640  		"index.html": "world",
   641  	}))
   642  	defer server.Close()
   643  
   644  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM busybox
   645  	COPY file*.txt /tmp/
   646  	RUN ls /tmp/file1.txt /tmp/file2.txt
   647  	RUN [ "mkdir",  "/tmp1" ]
   648  	COPY dir* /tmp1/
   649  	RUN ls /tmp1/dirt /tmp1/nested_file /tmp1/nested_dir/nest_nest_file
   650  	RUN [ "mkdir",  "/tmp2" ]
   651          ADD dir/*dir %s/robots.txt /tmp2/
   652  	RUN ls /tmp2/nest_nest_file /tmp2/robots.txt
   653  	`, server.URL())),
   654  		fakecontext.WithFiles(map[string]string{
   655  			"file1.txt":                     "test1",
   656  			"file2.txt":                     "test2",
   657  			"dir/nested_file":               "nested file",
   658  			"dir/nested_dir/nest_nest_file": "2 times nested",
   659  			"dirt":                          "dirty",
   660  		}))
   661  	defer ctx.Close()
   662  
   663  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
   664  	id1 := getIDByName(c, name)
   665  
   666  	// Now make sure we use a cache the 2nd time
   667  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
   668  	id2 := getIDByName(c, name)
   669  
   670  	if id1 != id2 {
   671  		c.Fatal("didn't use the cache")
   672  	}
   673  
   674  }
   675  
   676  func (s *DockerSuite) TestBuildCopyWildcardInName(c *check.C) {
   677  	// Run this only on Linux
   678  	// Below is the original comment (that I don't agree with — vdemeester)
   679  	// Normally we would do c.Fatal(err) here but given that
   680  	// the odds of this failing are so rare, it must be because
   681  	// the OS we're running the client on doesn't support * in
   682  	// filenames (like windows).  So, instead of failing the test
   683  	// just let it pass. Then we don't need to explicitly
   684  	// say which OSs this works on or not.
   685  	testRequires(c, DaemonIsLinux, UnixCli)
   686  
   687  	buildImageSuccessfully(c, "testcopywildcardinname", build.WithBuildContext(c,
   688  		build.WithFile("Dockerfile", `FROM busybox
   689  	COPY *.txt /tmp/
   690  	RUN [ "$(cat /tmp/\*.txt)" = 'hi there' ]
   691  	`),
   692  		build.WithFile("*.txt", "hi there"),
   693  	))
   694  }
   695  
   696  func (s *DockerSuite) TestBuildCopyWildcardCache(c *check.C) {
   697  	name := "testcopywildcardcache"
   698  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
   699  	COPY file1.txt /tmp/`),
   700  		fakecontext.WithFiles(map[string]string{
   701  			"file1.txt": "test1",
   702  		}))
   703  	defer ctx.Close()
   704  
   705  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
   706  	id1 := getIDByName(c, name)
   707  
   708  	// Now make sure we use a cache the 2nd time even with wild cards.
   709  	// Use the same context so the file is the same and the checksum will match
   710  	ctx.Add("Dockerfile", `FROM busybox
   711  	COPY file*.txt /tmp/`)
   712  
   713  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
   714  	id2 := getIDByName(c, name)
   715  
   716  	if id1 != id2 {
   717  		c.Fatal("didn't use the cache")
   718  	}
   719  
   720  }
   721  
   722  func (s *DockerSuite) TestBuildAddSingleFileToNonExistingDir(c *check.C) {
   723  	testRequires(c, DaemonIsLinux) // Linux specific test
   724  	buildImageSuccessfully(c, "testaddsinglefiletononexistingdir", build.WithBuildContext(c,
   725  		build.WithFile("Dockerfile", `FROM busybox
   726  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   727  RUN echo 'dockerio:x:1001:' >> /etc/group
   728  RUN touch /exists
   729  RUN chown dockerio.dockerio /exists
   730  ADD test_file /test_dir/
   731  RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
   732  RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
   733  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   734  		build.WithFile("test_file", "test1")))
   735  }
   736  
   737  func (s *DockerSuite) TestBuildAddDirContentToRoot(c *check.C) {
   738  	testRequires(c, DaemonIsLinux) // Linux specific test
   739  	buildImageSuccessfully(c, "testadddircontenttoroot", build.WithBuildContext(c,
   740  		build.WithFile("Dockerfile", `FROM busybox
   741  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   742  RUN echo 'dockerio:x:1001:' >> /etc/group
   743  RUN touch /exists
   744  RUN chown dockerio.dockerio exists
   745  ADD test_dir /
   746  RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
   747  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   748  		build.WithFile("test_dir/test_file", "test1")))
   749  }
   750  
   751  func (s *DockerSuite) TestBuildAddDirContentToExistingDir(c *check.C) {
   752  	testRequires(c, DaemonIsLinux) // Linux specific test
   753  	buildImageSuccessfully(c, "testadddircontenttoexistingdir", build.WithBuildContext(c,
   754  		build.WithFile("Dockerfile", `FROM busybox
   755  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   756  RUN echo 'dockerio:x:1001:' >> /etc/group
   757  RUN mkdir /exists
   758  RUN touch /exists/exists_file
   759  RUN chown -R dockerio.dockerio /exists
   760  ADD test_dir/ /exists/
   761  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   762  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   763  RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`),
   764  		build.WithFile("test_dir/test_file", "test1")))
   765  }
   766  
   767  func (s *DockerSuite) TestBuildAddWholeDirToRoot(c *check.C) {
   768  	testRequires(c, DaemonIsLinux) // Linux specific test
   769  	buildImageSuccessfully(c, "testaddwholedirtoroot", build.WithBuildContext(c,
   770  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   771  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   772  RUN echo 'dockerio:x:1001:' >> /etc/group
   773  RUN touch /exists
   774  RUN chown dockerio.dockerio exists
   775  ADD test_dir /test_dir
   776  RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
   777  RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ]
   778  RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
   779  RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ]
   780  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
   781  		build.WithFile("test_dir/test_file", "test1")))
   782  }
   783  
   784  // Testing #5941 : Having an etc directory in context conflicts with the /etc/mtab
   785  func (s *DockerSuite) TestBuildAddOrCopyEtcToRootShouldNotConflict(c *check.C) {
   786  	buildImageSuccessfully(c, "testaddetctoroot", build.WithBuildContext(c,
   787  		build.WithFile("Dockerfile", `FROM `+minimalBaseImage()+`
   788  ADD . /`),
   789  		build.WithFile("etc/test_file", "test1")))
   790  	buildImageSuccessfully(c, "testcopyetctoroot", build.WithBuildContext(c,
   791  		build.WithFile("Dockerfile", `FROM `+minimalBaseImage()+`
   792  COPY . /`),
   793  		build.WithFile("etc/test_file", "test1")))
   794  }
   795  
   796  // Testing #9401 : Losing setuid flag after a ADD
   797  func (s *DockerSuite) TestBuildAddPreservesFilesSpecialBits(c *check.C) {
   798  	testRequires(c, DaemonIsLinux) // Linux specific test
   799  	buildImageSuccessfully(c, "testaddetctoroot", build.WithBuildContext(c,
   800  		build.WithFile("Dockerfile", `FROM busybox
   801  ADD suidbin /usr/bin/suidbin
   802  RUN chmod 4755 /usr/bin/suidbin
   803  RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]
   804  ADD ./data/ /
   805  RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]`),
   806  		build.WithFile("suidbin", "suidbin"),
   807  		build.WithFile("/data/usr/test_file", "test1")))
   808  }
   809  
   810  func (s *DockerSuite) TestBuildCopySingleFileToRoot(c *check.C) {
   811  	testRequires(c, DaemonIsLinux) // Linux specific test
   812  	buildImageSuccessfully(c, "testcopysinglefiletoroot", build.WithBuildContext(c,
   813  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   814  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   815  RUN echo 'dockerio:x:1001:' >> /etc/group
   816  RUN touch /exists
   817  RUN chown dockerio.dockerio /exists
   818  COPY test_file /
   819  RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
   820  RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ]
   821  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
   822  		build.WithFile("test_file", "test1")))
   823  }
   824  
   825  // Issue #3960: "ADD src ." hangs - adapted for COPY
   826  func (s *DockerSuite) TestBuildCopySingleFileToWorkdir(c *check.C) {
   827  	name := "testcopysinglefiletoworkdir"
   828  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
   829  COPY test_file .`),
   830  		fakecontext.WithFiles(map[string]string{
   831  			"test_file": "test1",
   832  		}))
   833  	defer ctx.Close()
   834  
   835  	errChan := make(chan error)
   836  	go func() {
   837  		errChan <- buildImage(name, build.WithExternalBuildContext(ctx)).Error
   838  		close(errChan)
   839  	}()
   840  	select {
   841  	case <-time.After(15 * time.Second):
   842  		c.Fatal("Build with adding to workdir timed out")
   843  	case err := <-errChan:
   844  		c.Assert(err, check.IsNil)
   845  	}
   846  }
   847  
   848  func (s *DockerSuite) TestBuildCopySingleFileToExistDir(c *check.C) {
   849  	testRequires(c, DaemonIsLinux) // Linux specific test
   850  	buildImageSuccessfully(c, "testcopysinglefiletoexistdir", build.WithBuildContext(c,
   851  		build.WithFile("Dockerfile", `FROM busybox
   852  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   853  RUN echo 'dockerio:x:1001:' >> /etc/group
   854  RUN mkdir /exists
   855  RUN touch /exists/exists_file
   856  RUN chown -R dockerio.dockerio /exists
   857  COPY test_file /exists/
   858  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   859  RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]
   860  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   861  		build.WithFile("test_file", "test1")))
   862  }
   863  
   864  func (s *DockerSuite) TestBuildCopySingleFileToNonExistDir(c *check.C) {
   865  	testRequires(c, DaemonIsLinux) // Linux specific
   866  	buildImageSuccessfully(c, "testcopysinglefiletononexistdir", build.WithBuildContext(c,
   867  		build.WithFile("Dockerfile", `FROM busybox
   868  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   869  RUN echo 'dockerio:x:1001:' >> /etc/group
   870  RUN touch /exists
   871  RUN chown dockerio.dockerio /exists
   872  COPY test_file /test_dir/
   873  RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
   874  RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
   875  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   876  		build.WithFile("test_file", "test1")))
   877  }
   878  
   879  func (s *DockerSuite) TestBuildCopyDirContentToRoot(c *check.C) {
   880  	testRequires(c, DaemonIsLinux) // Linux specific test
   881  	buildImageSuccessfully(c, "testcopydircontenttoroot", build.WithBuildContext(c,
   882  		build.WithFile("Dockerfile", `FROM busybox
   883  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   884  RUN echo 'dockerio:x:1001:' >> /etc/group
   885  RUN touch /exists
   886  RUN chown dockerio.dockerio exists
   887  COPY test_dir /
   888  RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
   889  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   890  		build.WithFile("test_dir/test_file", "test1")))
   891  }
   892  
   893  func (s *DockerSuite) TestBuildCopyDirContentToExistDir(c *check.C) {
   894  	testRequires(c, DaemonIsLinux) // Linux specific test
   895  	buildImageSuccessfully(c, "testcopydircontenttoexistdir", build.WithBuildContext(c,
   896  		build.WithFile("Dockerfile", `FROM busybox
   897  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   898  RUN echo 'dockerio:x:1001:' >> /etc/group
   899  RUN mkdir /exists
   900  RUN touch /exists/exists_file
   901  RUN chown -R dockerio.dockerio /exists
   902  COPY test_dir/ /exists/
   903  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   904  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   905  RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`),
   906  		build.WithFile("test_dir/test_file", "test1")))
   907  }
   908  
   909  func (s *DockerSuite) TestBuildCopyWholeDirToRoot(c *check.C) {
   910  	testRequires(c, DaemonIsLinux) // Linux specific test
   911  	buildImageSuccessfully(c, "testcopywholedirtoroot", build.WithBuildContext(c,
   912  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   913  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   914  RUN echo 'dockerio:x:1001:' >> /etc/group
   915  RUN touch /exists
   916  RUN chown dockerio.dockerio exists
   917  COPY test_dir /test_dir
   918  RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
   919  RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ]
   920  RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
   921  RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ]
   922  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
   923  		build.WithFile("test_dir/test_file", "test1")))
   924  }
   925  
   926  func (s *DockerSuite) TestBuildAddBadLinks(c *check.C) {
   927  	testRequires(c, DaemonIsLinux) // Not currently working on Windows
   928  
   929  	dockerfile := `
   930  		FROM scratch
   931  		ADD links.tar /
   932  		ADD foo.txt /symlink/
   933  		`
   934  	targetFile := "foo.txt"
   935  	var (
   936  		name = "test-link-absolute"
   937  	)
   938  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
   939  	defer ctx.Close()
   940  
   941  	tempDir, err := ioutil.TempDir("", "test-link-absolute-temp-")
   942  	if err != nil {
   943  		c.Fatalf("failed to create temporary directory: %s", tempDir)
   944  	}
   945  	defer os.RemoveAll(tempDir)
   946  
   947  	var symlinkTarget string
   948  	if runtime.GOOS == "windows" {
   949  		var driveLetter string
   950  		if abs, err := filepath.Abs(tempDir); err != nil {
   951  			c.Fatal(err)
   952  		} else {
   953  			driveLetter = abs[:1]
   954  		}
   955  		tempDirWithoutDrive := tempDir[2:]
   956  		symlinkTarget = fmt.Sprintf(`%s:\..\..\..\..\..\..\..\..\..\..\..\..%s`, driveLetter, tempDirWithoutDrive)
   957  	} else {
   958  		symlinkTarget = fmt.Sprintf("/../../../../../../../../../../../..%s", tempDir)
   959  	}
   960  
   961  	tarPath := filepath.Join(ctx.Dir, "links.tar")
   962  	nonExistingFile := filepath.Join(tempDir, targetFile)
   963  	fooPath := filepath.Join(ctx.Dir, targetFile)
   964  
   965  	tarOut, err := os.Create(tarPath)
   966  	if err != nil {
   967  		c.Fatal(err)
   968  	}
   969  
   970  	tarWriter := tar.NewWriter(tarOut)
   971  
   972  	header := &tar.Header{
   973  		Name:     "symlink",
   974  		Typeflag: tar.TypeSymlink,
   975  		Linkname: symlinkTarget,
   976  		Mode:     0755,
   977  		Uid:      0,
   978  		Gid:      0,
   979  	}
   980  
   981  	err = tarWriter.WriteHeader(header)
   982  	if err != nil {
   983  		c.Fatal(err)
   984  	}
   985  
   986  	tarWriter.Close()
   987  	tarOut.Close()
   988  
   989  	foo, err := os.Create(fooPath)
   990  	if err != nil {
   991  		c.Fatal(err)
   992  	}
   993  	defer foo.Close()
   994  
   995  	if _, err := foo.WriteString("test"); err != nil {
   996  		c.Fatal(err)
   997  	}
   998  
   999  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  1000  	if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
  1001  		c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
  1002  	}
  1003  
  1004  }
  1005  
  1006  func (s *DockerSuite) TestBuildAddBadLinksVolume(c *check.C) {
  1007  	testRequires(c, DaemonIsLinux) // ln not implemented on Windows busybox
  1008  	const (
  1009  		dockerfileTemplate = `
  1010  		FROM busybox
  1011  		RUN ln -s /../../../../../../../../%s /x
  1012  		VOLUME /x
  1013  		ADD foo.txt /x/`
  1014  		targetFile = "foo.txt"
  1015  	)
  1016  
  1017  	tempDir, err := ioutil.TempDir("", "test-link-absolute-volume-temp-")
  1018  	if err != nil {
  1019  		c.Fatalf("failed to create temporary directory: %s", tempDir)
  1020  	}
  1021  	defer os.RemoveAll(tempDir)
  1022  
  1023  	dockerfile := fmt.Sprintf(dockerfileTemplate, tempDir)
  1024  	nonExistingFile := filepath.Join(tempDir, targetFile)
  1025  
  1026  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
  1027  	defer ctx.Close()
  1028  	fooPath := filepath.Join(ctx.Dir, targetFile)
  1029  
  1030  	foo, err := os.Create(fooPath)
  1031  	if err != nil {
  1032  		c.Fatal(err)
  1033  	}
  1034  	defer foo.Close()
  1035  
  1036  	if _, err := foo.WriteString("test"); err != nil {
  1037  		c.Fatal(err)
  1038  	}
  1039  
  1040  	buildImageSuccessfully(c, "test-link-absolute-volume", build.WithExternalBuildContext(ctx))
  1041  	if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
  1042  		c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
  1043  	}
  1044  
  1045  }
  1046  
  1047  // Issue #5270 - ensure we throw a better error than "unexpected EOF"
  1048  // when we can't access files in the context.
  1049  func (s *DockerSuite) TestBuildWithInaccessibleFilesInContext(c *check.C) {
  1050  	testRequires(c, DaemonIsLinux, UnixCli, testEnv.IsLocalDaemon) // test uses chown/chmod: not available on windows
  1051  
  1052  	{
  1053  		name := "testbuildinaccessiblefiles"
  1054  		ctx := fakecontext.New(c, "",
  1055  			fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"),
  1056  			fakecontext.WithFiles(map[string]string{"fileWithoutReadAccess": "foo"}),
  1057  		)
  1058  		defer ctx.Close()
  1059  		// This is used to ensure we detect inaccessible files early during build in the cli client
  1060  		pathToFileWithoutReadAccess := filepath.Join(ctx.Dir, "fileWithoutReadAccess")
  1061  
  1062  		if err := os.Chown(pathToFileWithoutReadAccess, 0, 0); err != nil {
  1063  			c.Fatalf("failed to chown file to root: %s", err)
  1064  		}
  1065  		if err := os.Chmod(pathToFileWithoutReadAccess, 0700); err != nil {
  1066  			c.Fatalf("failed to chmod file to 700: %s", err)
  1067  		}
  1068  		result := icmd.RunCmd(icmd.Cmd{
  1069  			Command: []string{"su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)},
  1070  			Dir:     ctx.Dir,
  1071  		})
  1072  		if result.Error == nil {
  1073  			c.Fatalf("build should have failed: %s %s", result.Error, result.Combined())
  1074  		}
  1075  
  1076  		// check if we've detected the failure before we started building
  1077  		if !strings.Contains(result.Combined(), "no permission to read from ") {
  1078  			c.Fatalf("output should've contained the string: no permission to read from but contained: %s", result.Combined())
  1079  		}
  1080  
  1081  		if !strings.Contains(result.Combined(), "error checking context") {
  1082  			c.Fatalf("output should've contained the string: error checking context")
  1083  		}
  1084  	}
  1085  	{
  1086  		name := "testbuildinaccessibledirectory"
  1087  		ctx := fakecontext.New(c, "",
  1088  			fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"),
  1089  			fakecontext.WithFiles(map[string]string{"directoryWeCantStat/bar": "foo"}),
  1090  		)
  1091  		defer ctx.Close()
  1092  		// This is used to ensure we detect inaccessible directories early during build in the cli client
  1093  		pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat")
  1094  		pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
  1095  
  1096  		if err := os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
  1097  			c.Fatalf("failed to chown directory to root: %s", err)
  1098  		}
  1099  		if err := os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
  1100  			c.Fatalf("failed to chmod directory to 444: %s", err)
  1101  		}
  1102  		if err := os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
  1103  			c.Fatalf("failed to chmod file to 700: %s", err)
  1104  		}
  1105  
  1106  		result := icmd.RunCmd(icmd.Cmd{
  1107  			Command: []string{"su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)},
  1108  			Dir:     ctx.Dir,
  1109  		})
  1110  		if result.Error == nil {
  1111  			c.Fatalf("build should have failed: %s %s", result.Error, result.Combined())
  1112  		}
  1113  
  1114  		// check if we've detected the failure before we started building
  1115  		if !strings.Contains(result.Combined(), "can't stat") {
  1116  			c.Fatalf("output should've contained the string: can't access %s", result.Combined())
  1117  		}
  1118  
  1119  		if !strings.Contains(result.Combined(), "error checking context") {
  1120  			c.Fatalf("output should've contained the string: error checking context\ngot:%s", result.Combined())
  1121  		}
  1122  
  1123  	}
  1124  	{
  1125  		name := "testlinksok"
  1126  		ctx := fakecontext.New(c, "", fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"))
  1127  		defer ctx.Close()
  1128  
  1129  		target := "../../../../../../../../../../../../../../../../../../../azA"
  1130  		if err := os.Symlink(filepath.Join(ctx.Dir, "g"), target); err != nil {
  1131  			c.Fatal(err)
  1132  		}
  1133  		defer os.Remove(target)
  1134  		// This is used to ensure we don't follow links when checking if everything in the context is accessible
  1135  		// This test doesn't require that we run commands as an unprivileged user
  1136  		buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  1137  	}
  1138  	{
  1139  		name := "testbuildignoredinaccessible"
  1140  		ctx := fakecontext.New(c, "",
  1141  			fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"),
  1142  			fakecontext.WithFiles(map[string]string{
  1143  				"directoryWeCantStat/bar": "foo",
  1144  				".dockerignore":           "directoryWeCantStat",
  1145  			}),
  1146  		)
  1147  		defer ctx.Close()
  1148  		// This is used to ensure we don't try to add inaccessible files when they are ignored by a .dockerignore pattern
  1149  		pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat")
  1150  		pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
  1151  		if err := os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
  1152  			c.Fatalf("failed to chown directory to root: %s", err)
  1153  		}
  1154  		if err := os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
  1155  			c.Fatalf("failed to chmod directory to 444: %s", err)
  1156  		}
  1157  		if err := os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
  1158  			c.Fatalf("failed to chmod file to 700: %s", err)
  1159  		}
  1160  
  1161  		result := icmd.RunCmd(icmd.Cmd{
  1162  			Dir: ctx.Dir,
  1163  			Command: []string{"su", "unprivilegeduser", "-c",
  1164  				fmt.Sprintf("%s build -t %s .", dockerBinary, name)},
  1165  		})
  1166  		result.Assert(c, icmd.Expected{})
  1167  	}
  1168  }
  1169  
  1170  func (s *DockerSuite) TestBuildForceRm(c *check.C) {
  1171  	containerCountBefore := getContainerCount(c)
  1172  	name := "testbuildforcerm"
  1173  
  1174  	r := buildImage(name, cli.WithFlags("--force-rm"), build.WithBuildContext(c,
  1175  		build.WithFile("Dockerfile", `FROM busybox
  1176  	RUN true
  1177  	RUN thiswillfail`)))
  1178  	if r.ExitCode != 1 && r.ExitCode != 127 { // different on Linux / Windows
  1179  		c.Fatalf("Wrong exit code")
  1180  	}
  1181  
  1182  	containerCountAfter := getContainerCount(c)
  1183  	if containerCountBefore != containerCountAfter {
  1184  		c.Fatalf("--force-rm shouldn't have left containers behind")
  1185  	}
  1186  
  1187  }
  1188  
  1189  func (s *DockerSuite) TestBuildRm(c *check.C) {
  1190  	name := "testbuildrm"
  1191  
  1192  	testCases := []struct {
  1193  		buildflags                []string
  1194  		shouldLeftContainerBehind bool
  1195  	}{
  1196  		// Default case (i.e. --rm=true)
  1197  		{
  1198  			buildflags:                []string{},
  1199  			shouldLeftContainerBehind: false,
  1200  		},
  1201  		{
  1202  			buildflags:                []string{"--rm"},
  1203  			shouldLeftContainerBehind: false,
  1204  		},
  1205  		{
  1206  			buildflags:                []string{"--rm=false"},
  1207  			shouldLeftContainerBehind: true,
  1208  		},
  1209  	}
  1210  
  1211  	for _, tc := range testCases {
  1212  		containerCountBefore := getContainerCount(c)
  1213  
  1214  		buildImageSuccessfully(c, name, cli.WithFlags(tc.buildflags...), build.WithDockerfile(`FROM busybox
  1215  	RUN echo hello world`))
  1216  
  1217  		containerCountAfter := getContainerCount(c)
  1218  		if tc.shouldLeftContainerBehind {
  1219  			if containerCountBefore == containerCountAfter {
  1220  				c.Fatalf("flags %v should have left containers behind", tc.buildflags)
  1221  			}
  1222  		} else {
  1223  			if containerCountBefore != containerCountAfter {
  1224  				c.Fatalf("flags %v shouldn't have left containers behind", tc.buildflags)
  1225  			}
  1226  		}
  1227  
  1228  		dockerCmd(c, "rmi", name)
  1229  	}
  1230  }
  1231  
  1232  func (s *DockerSuite) TestBuildWithVolumes(c *check.C) {
  1233  	testRequires(c, DaemonIsLinux) // Invalid volume paths on Windows
  1234  	var (
  1235  		result   map[string]map[string]struct{}
  1236  		name     = "testbuildvolumes"
  1237  		emptyMap = make(map[string]struct{})
  1238  		expected = map[string]map[string]struct{}{
  1239  			"/test1":  emptyMap,
  1240  			"/test2":  emptyMap,
  1241  			"/test3":  emptyMap,
  1242  			"/test4":  emptyMap,
  1243  			"/test5":  emptyMap,
  1244  			"/test6":  emptyMap,
  1245  			"[/test7": emptyMap,
  1246  			"/test8]": emptyMap,
  1247  		}
  1248  	)
  1249  
  1250  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
  1251  		VOLUME /test1
  1252  		VOLUME /test2
  1253      VOLUME /test3 /test4
  1254      VOLUME ["/test5", "/test6"]
  1255      VOLUME [/test7 /test8]
  1256      `))
  1257  
  1258  	inspectFieldAndUnmarshall(c, name, "Config.Volumes", &result)
  1259  
  1260  	equal := reflect.DeepEqual(&result, &expected)
  1261  	if !equal {
  1262  		c.Fatalf("Volumes %s, expected %s", result, expected)
  1263  	}
  1264  
  1265  }
  1266  
  1267  func (s *DockerSuite) TestBuildMaintainer(c *check.C) {
  1268  	name := "testbuildmaintainer"
  1269  
  1270  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1271          MAINTAINER dockerio`))
  1272  
  1273  	expected := "dockerio"
  1274  	res := inspectField(c, name, "Author")
  1275  	if res != expected {
  1276  		c.Fatalf("Maintainer %s, expected %s", res, expected)
  1277  	}
  1278  }
  1279  
  1280  func (s *DockerSuite) TestBuildUser(c *check.C) {
  1281  	testRequires(c, DaemonIsLinux)
  1282  	name := "testbuilduser"
  1283  	expected := "dockerio"
  1284  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1285  		RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
  1286  		USER dockerio
  1287  		RUN [ $(whoami) = 'dockerio' ]`))
  1288  	res := inspectField(c, name, "Config.User")
  1289  	if res != expected {
  1290  		c.Fatalf("User %s, expected %s", res, expected)
  1291  	}
  1292  }
  1293  
  1294  func (s *DockerSuite) TestBuildRelativeWorkdir(c *check.C) {
  1295  	name := "testbuildrelativeworkdir"
  1296  
  1297  	var (
  1298  		expected1     string
  1299  		expected2     string
  1300  		expected3     string
  1301  		expected4     string
  1302  		expectedFinal string
  1303  	)
  1304  
  1305  	if testEnv.OSType == "windows" {
  1306  		expected1 = `C:/`
  1307  		expected2 = `C:/test1`
  1308  		expected3 = `C:/test2`
  1309  		expected4 = `C:/test2/test3`
  1310  		expectedFinal = `C:\test2\test3` // Note inspect is going to return Windows paths, as it's not in busybox
  1311  	} else {
  1312  		expected1 = `/`
  1313  		expected2 = `/test1`
  1314  		expected3 = `/test2`
  1315  		expected4 = `/test2/test3`
  1316  		expectedFinal = `/test2/test3`
  1317  	}
  1318  
  1319  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1320  		RUN sh -c "[ "$PWD" = "`+expected1+`" ]"
  1321  		WORKDIR test1
  1322  		RUN sh -c "[ "$PWD" = "`+expected2+`" ]"
  1323  		WORKDIR /test2
  1324  		RUN sh -c "[ "$PWD" = "`+expected3+`" ]"
  1325  		WORKDIR test3
  1326  		RUN sh -c "[ "$PWD" = "`+expected4+`" ]"`))
  1327  
  1328  	res := inspectField(c, name, "Config.WorkingDir")
  1329  	if res != expectedFinal {
  1330  		c.Fatalf("Workdir %s, expected %s", res, expectedFinal)
  1331  	}
  1332  }
  1333  
  1334  // #22181 Regression test. Single end-to-end test of using
  1335  // Windows semantics. Most path handling verifications are in unit tests
  1336  func (s *DockerSuite) TestBuildWindowsWorkdirProcessing(c *check.C) {
  1337  	testRequires(c, DaemonIsWindows)
  1338  	buildImageSuccessfully(c, "testbuildwindowsworkdirprocessing", build.WithDockerfile(`FROM busybox
  1339  		WORKDIR C:\\foo
  1340  		WORKDIR bar
  1341  		RUN sh -c "[ "$PWD" = "C:/foo/bar" ]"
  1342  		`))
  1343  }
  1344  
  1345  // #22181 Regression test. Most paths handling verifications are in unit test.
  1346  // One functional test for end-to-end
  1347  func (s *DockerSuite) TestBuildWindowsAddCopyPathProcessing(c *check.C) {
  1348  	testRequires(c, DaemonIsWindows)
  1349  	// TODO Windows (@jhowardmsft). Needs a follow-up PR to 22181 to
  1350  	// support backslash such as .\\ being equivalent to ./ and c:\\ being
  1351  	// equivalent to c:/. This is not currently (nor ever has been) supported
  1352  	// by docker on the Windows platform.
  1353  	buildImageSuccessfully(c, "testbuildwindowsaddcopypathprocessing", build.WithBuildContext(c,
  1354  		build.WithFile("Dockerfile", `FROM busybox
  1355  			# No trailing slash on COPY/ADD
  1356  			# Results in dir being changed to a file
  1357  			WORKDIR /wc1
  1358  			COPY wc1 c:/wc1
  1359  			WORKDIR /wc2
  1360  			ADD wc2 c:/wc2
  1361  			WORKDIR c:/
  1362  			RUN sh -c "[ $(cat c:/wc1/wc1) = 'hellowc1' ]"
  1363  			RUN sh -c "[ $(cat c:/wc2/wc2) = 'worldwc2' ]"
  1364  
  1365  			# Trailing slash on COPY/ADD, Windows-style path.
  1366  			WORKDIR /wd1
  1367  			COPY wd1 c:/wd1/
  1368  			WORKDIR /wd2
  1369  			ADD wd2 c:/wd2/
  1370  			RUN sh -c "[ $(cat c:/wd1/wd1) = 'hellowd1' ]"
  1371  			RUN sh -c "[ $(cat c:/wd2/wd2) = 'worldwd2' ]"
  1372  			`),
  1373  		build.WithFile("wc1", "hellowc1"),
  1374  		build.WithFile("wc2", "worldwc2"),
  1375  		build.WithFile("wd1", "hellowd1"),
  1376  		build.WithFile("wd2", "worldwd2"),
  1377  	))
  1378  }
  1379  
  1380  func (s *DockerSuite) TestBuildWorkdirWithEnvVariables(c *check.C) {
  1381  	name := "testbuildworkdirwithenvvariables"
  1382  
  1383  	var expected string
  1384  	if testEnv.OSType == "windows" {
  1385  		expected = `C:\test1\test2`
  1386  	} else {
  1387  		expected = `/test1/test2`
  1388  	}
  1389  
  1390  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1391  		ENV DIRPATH /test1
  1392  		ENV SUBDIRNAME test2
  1393  		WORKDIR $DIRPATH
  1394  		WORKDIR $SUBDIRNAME/$MISSING_VAR`))
  1395  	res := inspectField(c, name, "Config.WorkingDir")
  1396  	if res != expected {
  1397  		c.Fatalf("Workdir %s, expected %s", res, expected)
  1398  	}
  1399  }
  1400  
  1401  func (s *DockerSuite) TestBuildRelativeCopy(c *check.C) {
  1402  	// cat /test1/test2/foo gets permission denied for the user
  1403  	testRequires(c, NotUserNamespace)
  1404  
  1405  	var expected string
  1406  	if testEnv.OSType == "windows" {
  1407  		expected = `C:/test1/test2`
  1408  	} else {
  1409  		expected = `/test1/test2`
  1410  	}
  1411  
  1412  	buildImageSuccessfully(c, "testbuildrelativecopy", build.WithBuildContext(c,
  1413  		build.WithFile("Dockerfile", `FROM busybox
  1414  			WORKDIR /test1
  1415  			WORKDIR test2
  1416  			RUN sh -c "[ "$PWD" = '`+expected+`' ]"
  1417  			COPY foo ./
  1418  			RUN sh -c "[ $(cat /test1/test2/foo) = 'hello' ]"
  1419  			ADD foo ./bar/baz
  1420  			RUN sh -c "[ $(cat /test1/test2/bar/baz) = 'hello' ]"
  1421  			COPY foo ./bar/baz2
  1422  			RUN sh -c "[ $(cat /test1/test2/bar/baz2) = 'hello' ]"
  1423  			WORKDIR ..
  1424  			COPY foo ./
  1425  			RUN sh -c "[ $(cat /test1/foo) = 'hello' ]"
  1426  			COPY foo /test3/
  1427  			RUN sh -c "[ $(cat /test3/foo) = 'hello' ]"
  1428  			WORKDIR /test4
  1429  			COPY . .
  1430  			RUN sh -c "[ $(cat /test4/foo) = 'hello' ]"
  1431  			WORKDIR /test5/test6
  1432  			COPY foo ../
  1433  			RUN sh -c "[ $(cat /test5/foo) = 'hello' ]"
  1434  			`),
  1435  		build.WithFile("foo", "hello"),
  1436  	))
  1437  }
  1438  
  1439  // FIXME(vdemeester) should be unit test
  1440  func (s *DockerSuite) TestBuildBlankName(c *check.C) {
  1441  	name := "testbuildblankname"
  1442  	testCases := []struct {
  1443  		expression     string
  1444  		expectedStderr string
  1445  	}{
  1446  		{
  1447  			expression:     "ENV =",
  1448  			expectedStderr: "ENV names can not be blank",
  1449  		},
  1450  		{
  1451  			expression:     "LABEL =",
  1452  			expectedStderr: "LABEL names can not be blank",
  1453  		},
  1454  		{
  1455  			expression:     "ARG =foo",
  1456  			expectedStderr: "ARG names can not be blank",
  1457  		},
  1458  	}
  1459  
  1460  	for _, tc := range testCases {
  1461  		buildImage(name, build.WithDockerfile(fmt.Sprintf(`FROM busybox
  1462  		%s`, tc.expression))).Assert(c, icmd.Expected{
  1463  			ExitCode: 1,
  1464  			Err:      tc.expectedStderr,
  1465  		})
  1466  	}
  1467  }
  1468  
  1469  func (s *DockerSuite) TestBuildEnv(c *check.C) {
  1470  	testRequires(c, DaemonIsLinux) // ENV expansion is different in Windows
  1471  	name := "testbuildenv"
  1472  	expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]"
  1473  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1474  		ENV PATH /test:$PATH
  1475  		ENV PORT 2375
  1476  		RUN [ $(env | grep PORT) = 'PORT=2375' ]`))
  1477  	res := inspectField(c, name, "Config.Env")
  1478  	if res != expected {
  1479  		c.Fatalf("Env %s, expected %s", res, expected)
  1480  	}
  1481  }
  1482  
  1483  func (s *DockerSuite) TestBuildPATH(c *check.C) {
  1484  	testRequires(c, DaemonIsLinux) // ENV expansion is different in Windows
  1485  
  1486  	defPath := "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
  1487  
  1488  	fn := func(dockerfile string, expected string) {
  1489  		buildImageSuccessfully(c, "testbldpath", build.WithDockerfile(dockerfile))
  1490  		res := inspectField(c, "testbldpath", "Config.Env")
  1491  		if res != expected {
  1492  			c.Fatalf("Env %q, expected %q for dockerfile:%q", res, expected, dockerfile)
  1493  		}
  1494  	}
  1495  
  1496  	tests := []struct{ dockerfile, exp string }{
  1497  		{"FROM scratch\nMAINTAINER me", "[PATH=" + defPath + "]"},
  1498  		{"FROM busybox\nMAINTAINER me", "[PATH=" + defPath + "]"},
  1499  		{"FROM scratch\nENV FOO=bar", "[PATH=" + defPath + " FOO=bar]"},
  1500  		{"FROM busybox\nENV FOO=bar", "[PATH=" + defPath + " FOO=bar]"},
  1501  		{"FROM scratch\nENV PATH=/test", "[PATH=/test]"},
  1502  		{"FROM busybox\nENV PATH=/test", "[PATH=/test]"},
  1503  		{"FROM scratch\nENV PATH=''", "[PATH=]"},
  1504  		{"FROM busybox\nENV PATH=''", "[PATH=]"},
  1505  	}
  1506  
  1507  	for _, test := range tests {
  1508  		fn(test.dockerfile, test.exp)
  1509  	}
  1510  }
  1511  
  1512  func (s *DockerSuite) TestBuildContextCleanup(c *check.C) {
  1513  	testRequires(c, testEnv.IsLocalDaemon)
  1514  
  1515  	name := "testbuildcontextcleanup"
  1516  	entries, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
  1517  	if err != nil {
  1518  		c.Fatalf("failed to list contents of tmp dir: %s", err)
  1519  	}
  1520  
  1521  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1522          ENTRYPOINT ["/bin/echo"]`))
  1523  
  1524  	entriesFinal, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
  1525  	if err != nil {
  1526  		c.Fatalf("failed to list contents of tmp dir: %s", err)
  1527  	}
  1528  	if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
  1529  		c.Fatalf("context should have been deleted, but wasn't")
  1530  	}
  1531  
  1532  }
  1533  
  1534  func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) {
  1535  	testRequires(c, testEnv.IsLocalDaemon)
  1536  
  1537  	name := "testbuildcontextcleanup"
  1538  	entries, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
  1539  	if err != nil {
  1540  		c.Fatalf("failed to list contents of tmp dir: %s", err)
  1541  	}
  1542  
  1543  	buildImage(name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1544  	RUN /non/existing/command`)).Assert(c, icmd.Expected{
  1545  		ExitCode: 1,
  1546  	})
  1547  
  1548  	entriesFinal, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
  1549  	if err != nil {
  1550  		c.Fatalf("failed to list contents of tmp dir: %s", err)
  1551  	}
  1552  	if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
  1553  		c.Fatalf("context should have been deleted, but wasn't")
  1554  	}
  1555  
  1556  }
  1557  
  1558  // compareDirectoryEntries compares two sets of FileInfo (usually taken from a directory)
  1559  // and returns an error if different.
  1560  func compareDirectoryEntries(e1 []os.FileInfo, e2 []os.FileInfo) error {
  1561  	var (
  1562  		e1Entries = make(map[string]struct{})
  1563  		e2Entries = make(map[string]struct{})
  1564  	)
  1565  	for _, e := range e1 {
  1566  		e1Entries[e.Name()] = struct{}{}
  1567  	}
  1568  	for _, e := range e2 {
  1569  		e2Entries[e.Name()] = struct{}{}
  1570  	}
  1571  	if !reflect.DeepEqual(e1Entries, e2Entries) {
  1572  		return fmt.Errorf("entries differ")
  1573  	}
  1574  	return nil
  1575  }
  1576  
  1577  func (s *DockerSuite) TestBuildCmd(c *check.C) {
  1578  	name := "testbuildcmd"
  1579  	expected := "[/bin/echo Hello World]"
  1580  
  1581  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1582          CMD ["/bin/echo", "Hello World"]`))
  1583  
  1584  	res := inspectField(c, name, "Config.Cmd")
  1585  	if res != expected {
  1586  		c.Fatalf("Cmd %s, expected %s", res, expected)
  1587  	}
  1588  }
  1589  
  1590  func (s *DockerSuite) TestBuildExpose(c *check.C) {
  1591  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1592  	name := "testbuildexpose"
  1593  	expected := "map[2375/tcp:{}]"
  1594  
  1595  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
  1596          EXPOSE 2375`))
  1597  
  1598  	res := inspectField(c, name, "Config.ExposedPorts")
  1599  	if res != expected {
  1600  		c.Fatalf("Exposed ports %s, expected %s", res, expected)
  1601  	}
  1602  }
  1603  
  1604  func (s *DockerSuite) TestBuildExposeMorePorts(c *check.C) {
  1605  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1606  	// start building docker file with a large number of ports
  1607  	portList := make([]string, 50)
  1608  	line := make([]string, 100)
  1609  	expectedPorts := make([]int, len(portList)*len(line))
  1610  	for i := 0; i < len(portList); i++ {
  1611  		for j := 0; j < len(line); j++ {
  1612  			p := i*len(line) + j + 1
  1613  			line[j] = strconv.Itoa(p)
  1614  			expectedPorts[p-1] = p
  1615  		}
  1616  		if i == len(portList)-1 {
  1617  			portList[i] = strings.Join(line, " ")
  1618  		} else {
  1619  			portList[i] = strings.Join(line, " ") + ` \`
  1620  		}
  1621  	}
  1622  
  1623  	dockerfile := `FROM scratch
  1624  	EXPOSE {{range .}} {{.}}
  1625  	{{end}}`
  1626  	tmpl := template.Must(template.New("dockerfile").Parse(dockerfile))
  1627  	buf := bytes.NewBuffer(nil)
  1628  	tmpl.Execute(buf, portList)
  1629  
  1630  	name := "testbuildexpose"
  1631  	buildImageSuccessfully(c, name, build.WithDockerfile(buf.String()))
  1632  
  1633  	// check if all the ports are saved inside Config.ExposedPorts
  1634  	res := inspectFieldJSON(c, name, "Config.ExposedPorts")
  1635  	var exposedPorts map[string]interface{}
  1636  	if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil {
  1637  		c.Fatal(err)
  1638  	}
  1639  
  1640  	for _, p := range expectedPorts {
  1641  		ep := fmt.Sprintf("%d/tcp", p)
  1642  		if _, ok := exposedPorts[ep]; !ok {
  1643  			c.Errorf("Port(%s) is not exposed", ep)
  1644  		} else {
  1645  			delete(exposedPorts, ep)
  1646  		}
  1647  	}
  1648  	if len(exposedPorts) != 0 {
  1649  		c.Errorf("Unexpected extra exposed ports %v", exposedPorts)
  1650  	}
  1651  }
  1652  
  1653  func (s *DockerSuite) TestBuildExposeOrder(c *check.C) {
  1654  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1655  	buildID := func(name, exposed string) string {
  1656  		buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM scratch
  1657  		EXPOSE %s`, exposed)))
  1658  		id := inspectField(c, name, "Id")
  1659  		return id
  1660  	}
  1661  
  1662  	id1 := buildID("testbuildexpose1", "80 2375")
  1663  	id2 := buildID("testbuildexpose2", "2375 80")
  1664  	if id1 != id2 {
  1665  		c.Errorf("EXPOSE should invalidate the cache only when ports actually changed")
  1666  	}
  1667  }
  1668  
  1669  func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) {
  1670  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1671  	name := "testbuildexposeuppercaseproto"
  1672  	expected := "map[5678/udp:{}]"
  1673  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
  1674          EXPOSE 5678/UDP`))
  1675  	res := inspectField(c, name, "Config.ExposedPorts")
  1676  	if res != expected {
  1677  		c.Fatalf("Exposed ports %s, expected %s", res, expected)
  1678  	}
  1679  }
  1680  
  1681  func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) {
  1682  	name := "testbuildentrypointinheritance"
  1683  	name2 := "testbuildentrypointinheritance2"
  1684  
  1685  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1686          ENTRYPOINT ["/bin/echo"]`))
  1687  	res := inspectField(c, name, "Config.Entrypoint")
  1688  
  1689  	expected := "[/bin/echo]"
  1690  	if res != expected {
  1691  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  1692  	}
  1693  
  1694  	buildImageSuccessfully(c, name2, build.WithDockerfile(fmt.Sprintf(`FROM %s
  1695          ENTRYPOINT []`, name)))
  1696  	res = inspectField(c, name2, "Config.Entrypoint")
  1697  
  1698  	expected = "[]"
  1699  	if res != expected {
  1700  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  1701  	}
  1702  }
  1703  
  1704  func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) {
  1705  	name := "testbuildentrypoint"
  1706  	expected := "[]"
  1707  
  1708  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1709          ENTRYPOINT []`))
  1710  
  1711  	res := inspectField(c, name, "Config.Entrypoint")
  1712  	if res != expected {
  1713  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  1714  	}
  1715  
  1716  }
  1717  
  1718  func (s *DockerSuite) TestBuildEntrypoint(c *check.C) {
  1719  	name := "testbuildentrypoint"
  1720  
  1721  	expected := "[/bin/echo]"
  1722  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1723          ENTRYPOINT ["/bin/echo"]`))
  1724  
  1725  	res := inspectField(c, name, "Config.Entrypoint")
  1726  	if res != expected {
  1727  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  1728  	}
  1729  
  1730  }
  1731  
  1732  // #6445 ensure ONBUILD triggers aren't committed to grandchildren
  1733  func (s *DockerSuite) TestBuildOnBuildLimitedInheritance(c *check.C) {
  1734  	buildImageSuccessfully(c, "testonbuildtrigger1", build.WithDockerfile(`
  1735  		FROM busybox
  1736  		RUN echo "GRANDPARENT"
  1737  		ONBUILD RUN echo "ONBUILD PARENT"
  1738  		`))
  1739  	// ONBUILD should be run in second build.
  1740  	buildImage("testonbuildtrigger2", build.WithDockerfile("FROM testonbuildtrigger1")).Assert(c, icmd.Expected{
  1741  		Out: "ONBUILD PARENT",
  1742  	})
  1743  	// ONBUILD should *not* be run in third build.
  1744  	result := buildImage("testonbuildtrigger3", build.WithDockerfile("FROM testonbuildtrigger2"))
  1745  	result.Assert(c, icmd.Success)
  1746  	if strings.Contains(result.Combined(), "ONBUILD PARENT") {
  1747  		c.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent")
  1748  	}
  1749  }
  1750  
  1751  func (s *DockerSuite) TestBuildSameDockerfileWithAndWithoutCache(c *check.C) {
  1752  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1753  	name := "testbuildwithcache"
  1754  	dockerfile := `FROM scratch
  1755  		MAINTAINER dockerio
  1756  		EXPOSE 5432
  1757          ENTRYPOINT ["/bin/echo"]`
  1758  	buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile))
  1759  	id1 := getIDByName(c, name)
  1760  	buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile))
  1761  	id2 := getIDByName(c, name)
  1762  	buildImageSuccessfully(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
  1763  	id3 := getIDByName(c, name)
  1764  	if id1 != id2 {
  1765  		c.Fatal("The cache should have been used but hasn't.")
  1766  	}
  1767  	if id1 == id3 {
  1768  		c.Fatal("The cache should have been invalided but hasn't.")
  1769  	}
  1770  }
  1771  
  1772  // Make sure that ADD/COPY still populate the cache even if they don't use it
  1773  func (s *DockerSuite) TestBuildConditionalCache(c *check.C) {
  1774  	name := "testbuildconditionalcache"
  1775  
  1776  	dockerfile := `
  1777  		FROM busybox
  1778          ADD foo /tmp/`
  1779  	ctx := fakecontext.New(c, "",
  1780  		fakecontext.WithDockerfile(dockerfile),
  1781  		fakecontext.WithFiles(map[string]string{
  1782  			"foo": "hello",
  1783  		}))
  1784  	defer ctx.Close()
  1785  
  1786  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1787  	id1 := getIDByName(c, name)
  1788  
  1789  	if err := ctx.Add("foo", "bye"); err != nil {
  1790  		c.Fatalf("Error modifying foo: %s", err)
  1791  	}
  1792  
  1793  	// Updating a file should invalidate the cache
  1794  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1795  	id2 := getIDByName(c, name)
  1796  	if id2 == id1 {
  1797  		c.Fatal("Should not have used the cache")
  1798  	}
  1799  
  1800  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1801  	id3 := getIDByName(c, name)
  1802  	if id3 != id2 {
  1803  		c.Fatal("Should have used the cache")
  1804  	}
  1805  }
  1806  
  1807  func (s *DockerSuite) TestBuildAddMultipleLocalFileWithAndWithoutCache(c *check.C) {
  1808  	name := "testbuildaddmultiplelocalfilewithcache"
  1809  	baseName := name + "-base"
  1810  
  1811  	cli.BuildCmd(c, baseName, build.WithDockerfile(`
  1812  		FROM busybox
  1813  		ENTRYPOINT ["/bin/sh"]
  1814  	`))
  1815  
  1816  	dockerfile := `
  1817  		FROM testbuildaddmultiplelocalfilewithcache-base
  1818          MAINTAINER dockerio
  1819          ADD foo Dockerfile /usr/lib/bla/
  1820  		RUN sh -c "[ $(cat /usr/lib/bla/foo) = "hello" ]"`
  1821  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
  1822  		"foo": "hello",
  1823  	}))
  1824  	defer ctx.Close()
  1825  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1826  	id1 := getIDByName(c, name)
  1827  	result2 := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1828  	id2 := getIDByName(c, name)
  1829  	result3 := cli.BuildCmd(c, name, build.WithoutCache, build.WithExternalBuildContext(ctx))
  1830  	id3 := getIDByName(c, name)
  1831  	if id1 != id2 {
  1832  		c.Fatalf("The cache should have been used but hasn't: %s", result2.Stdout())
  1833  	}
  1834  	if id1 == id3 {
  1835  		c.Fatalf("The cache should have been invalided but hasn't: %s", result3.Stdout())
  1836  	}
  1837  }
  1838  
  1839  func (s *DockerSuite) TestBuildCopyDirButNotFile(c *check.C) {
  1840  	name := "testbuildcopydirbutnotfile"
  1841  	name2 := "testbuildcopydirbutnotfile2"
  1842  
  1843  	dockerfile := `
  1844          FROM ` + minimalBaseImage() + `
  1845          COPY dir /tmp/`
  1846  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
  1847  		"dir/foo": "hello",
  1848  	}))
  1849  	defer ctx.Close()
  1850  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1851  	id1 := getIDByName(c, name)
  1852  	// Check that adding file with similar name doesn't mess with cache
  1853  	if err := ctx.Add("dir_file", "hello2"); err != nil {
  1854  		c.Fatal(err)
  1855  	}
  1856  	cli.BuildCmd(c, name2, build.WithExternalBuildContext(ctx))
  1857  	id2 := getIDByName(c, name2)
  1858  	if id1 != id2 {
  1859  		c.Fatal("The cache should have been used but wasn't")
  1860  	}
  1861  }
  1862  
  1863  func (s *DockerSuite) TestBuildAddCurrentDirWithCache(c *check.C) {
  1864  	name := "testbuildaddcurrentdirwithcache"
  1865  	name2 := name + "2"
  1866  	name3 := name + "3"
  1867  	name4 := name + "4"
  1868  	dockerfile := `
  1869          FROM ` + minimalBaseImage() + `
  1870          MAINTAINER dockerio
  1871          ADD . /usr/lib/bla`
  1872  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
  1873  		"foo": "hello",
  1874  	}))
  1875  	defer ctx.Close()
  1876  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  1877  	id1 := getIDByName(c, name)
  1878  	// Check that adding file invalidate cache of "ADD ."
  1879  	if err := ctx.Add("bar", "hello2"); err != nil {
  1880  		c.Fatal(err)
  1881  	}
  1882  	buildImageSuccessfully(c, name2, build.WithExternalBuildContext(ctx))
  1883  	id2 := getIDByName(c, name2)
  1884  	if id1 == id2 {
  1885  		c.Fatal("The cache should have been invalided but hasn't.")
  1886  	}
  1887  	// Check that changing file invalidate cache of "ADD ."
  1888  	if err := ctx.Add("foo", "hello1"); err != nil {
  1889  		c.Fatal(err)
  1890  	}
  1891  	buildImageSuccessfully(c, name3, build.WithExternalBuildContext(ctx))
  1892  	id3 := getIDByName(c, name3)
  1893  	if id2 == id3 {
  1894  		c.Fatal("The cache should have been invalided but hasn't.")
  1895  	}
  1896  	// Check that changing file to same content with different mtime does not
  1897  	// invalidate cache of "ADD ."
  1898  	time.Sleep(1 * time.Second) // wait second because of mtime precision
  1899  	if err := ctx.Add("foo", "hello1"); err != nil {
  1900  		c.Fatal(err)
  1901  	}
  1902  	buildImageSuccessfully(c, name4, build.WithExternalBuildContext(ctx))
  1903  	id4 := getIDByName(c, name4)
  1904  	if id3 != id4 {
  1905  		c.Fatal("The cache should have been used but hasn't.")
  1906  	}
  1907  }
  1908  
  1909  // FIXME(vdemeester) this really seems to test the same thing as before (TestBuildAddMultipleLocalFileWithAndWithoutCache)
  1910  func (s *DockerSuite) TestBuildAddCurrentDirWithoutCache(c *check.C) {
  1911  	name := "testbuildaddcurrentdirwithoutcache"
  1912  	dockerfile := `
  1913          FROM ` + minimalBaseImage() + `
  1914          MAINTAINER dockerio
  1915          ADD . /usr/lib/bla`
  1916  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
  1917  		"foo": "hello",
  1918  	}))
  1919  	defer ctx.Close()
  1920  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  1921  	id1 := getIDByName(c, name)
  1922  	buildImageSuccessfully(c, name, build.WithoutCache, build.WithExternalBuildContext(ctx))
  1923  	id2 := getIDByName(c, name)
  1924  	if id1 == id2 {
  1925  		c.Fatal("The cache should have been invalided but hasn't.")
  1926  	}
  1927  }
  1928  
  1929  func (s *DockerSuite) TestBuildAddRemoteFileWithAndWithoutCache(c *check.C) {
  1930  	name := "testbuildaddremotefilewithcache"
  1931  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
  1932  		"baz": "hello",
  1933  	}))
  1934  	defer server.Close()
  1935  
  1936  	dockerfile := fmt.Sprintf(`FROM `+minimalBaseImage()+`
  1937          MAINTAINER dockerio
  1938          ADD %s/baz /usr/lib/baz/quux`, server.URL())
  1939  	cli.BuildCmd(c, name, build.WithDockerfile(dockerfile))
  1940  	id1 := getIDByName(c, name)
  1941  	cli.BuildCmd(c, name, build.WithDockerfile(dockerfile))
  1942  	id2 := getIDByName(c, name)
  1943  	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
  1944  	id3 := getIDByName(c, name)
  1945  
  1946  	if id1 != id2 {
  1947  		c.Fatal("The cache should have been used but hasn't.")
  1948  	}
  1949  	if id1 == id3 {
  1950  		c.Fatal("The cache should have been invalided but hasn't.")
  1951  	}
  1952  }
  1953  
  1954  func (s *DockerSuite) TestBuildAddRemoteFileMTime(c *check.C) {
  1955  	name := "testbuildaddremotefilemtime"
  1956  	name2 := name + "2"
  1957  	name3 := name + "3"
  1958  
  1959  	files := map[string]string{"baz": "hello"}
  1960  	server := fakestorage.New(c, "", fakecontext.WithFiles(files))
  1961  	defer server.Close()
  1962  
  1963  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM `+minimalBaseImage()+`
  1964          MAINTAINER dockerio
  1965          ADD %s/baz /usr/lib/baz/quux`, server.URL())))
  1966  	defer ctx.Close()
  1967  
  1968  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1969  	id1 := getIDByName(c, name)
  1970  	cli.BuildCmd(c, name2, build.WithExternalBuildContext(ctx))
  1971  	id2 := getIDByName(c, name2)
  1972  	if id1 != id2 {
  1973  		c.Fatal("The cache should have been used but wasn't - #1")
  1974  	}
  1975  
  1976  	// Now create a different server with same contents (causes different mtime)
  1977  	// The cache should still be used
  1978  
  1979  	// allow some time for clock to pass as mtime precision is only 1s
  1980  	time.Sleep(2 * time.Second)
  1981  
  1982  	server2 := fakestorage.New(c, "", fakecontext.WithFiles(files))
  1983  	defer server2.Close()
  1984  
  1985  	ctx2 := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM `+minimalBaseImage()+`
  1986          MAINTAINER dockerio
  1987          ADD %s/baz /usr/lib/baz/quux`, server2.URL())))
  1988  	defer ctx2.Close()
  1989  	cli.BuildCmd(c, name3, build.WithExternalBuildContext(ctx2))
  1990  	id3 := getIDByName(c, name3)
  1991  	if id1 != id3 {
  1992  		c.Fatal("The cache should have been used but wasn't")
  1993  	}
  1994  }
  1995  
  1996  // FIXME(vdemeester) this really seems to test the same thing as before (combined)
  1997  func (s *DockerSuite) TestBuildAddLocalAndRemoteFilesWithAndWithoutCache(c *check.C) {
  1998  	name := "testbuildaddlocalandremotefilewithcache"
  1999  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
  2000  		"baz": "hello",
  2001  	}))
  2002  	defer server.Close()
  2003  
  2004  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM `+minimalBaseImage()+`
  2005          MAINTAINER dockerio
  2006          ADD foo /usr/lib/bla/bar
  2007          ADD %s/baz /usr/lib/baz/quux`, server.URL())),
  2008  		fakecontext.WithFiles(map[string]string{
  2009  			"foo": "hello world",
  2010  		}))
  2011  	defer ctx.Close()
  2012  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  2013  	id1 := getIDByName(c, name)
  2014  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  2015  	id2 := getIDByName(c, name)
  2016  	buildImageSuccessfully(c, name, build.WithoutCache, build.WithExternalBuildContext(ctx))
  2017  	id3 := getIDByName(c, name)
  2018  	if id1 != id2 {
  2019  		c.Fatal("The cache should have been used but hasn't.")
  2020  	}
  2021  	if id1 == id3 {
  2022  		c.Fatal("The cache should have been invalidated but hasn't.")
  2023  	}
  2024  }
  2025  
  2026  func testContextTar(c *check.C, compression archive.Compression) {
  2027  	ctx := fakecontext.New(c, "",
  2028  		fakecontext.WithDockerfile(`FROM busybox
  2029  ADD foo /foo
  2030  CMD ["cat", "/foo"]`),
  2031  		fakecontext.WithFiles(map[string]string{
  2032  			"foo": "bar",
  2033  		}),
  2034  	)
  2035  	defer ctx.Close()
  2036  	context, err := archive.Tar(ctx.Dir, compression)
  2037  	if err != nil {
  2038  		c.Fatalf("failed to build context tar: %v", err)
  2039  	}
  2040  	name := "contexttar"
  2041  
  2042  	cli.BuildCmd(c, name, build.WithStdinContext(context))
  2043  }
  2044  
  2045  func (s *DockerSuite) TestBuildContextTarGzip(c *check.C) {
  2046  	testContextTar(c, archive.Gzip)
  2047  }
  2048  
  2049  func (s *DockerSuite) TestBuildContextTarNoCompression(c *check.C) {
  2050  	testContextTar(c, archive.Uncompressed)
  2051  }
  2052  
  2053  func (s *DockerSuite) TestBuildNoContext(c *check.C) {
  2054  	name := "nocontext"
  2055  	icmd.RunCmd(icmd.Cmd{
  2056  		Command: []string{dockerBinary, "build", "-t", name, "-"},
  2057  		Stdin: strings.NewReader(
  2058  			`FROM busybox
  2059  			CMD ["echo", "ok"]`),
  2060  	}).Assert(c, icmd.Success)
  2061  
  2062  	if out, _ := dockerCmd(c, "run", "--rm", "nocontext"); out != "ok\n" {
  2063  		c.Fatalf("run produced invalid output: %q, expected %q", out, "ok")
  2064  	}
  2065  }
  2066  
  2067  // FIXME(vdemeester) migrate to docker/cli e2e
  2068  func (s *DockerSuite) TestBuildDockerfileStdin(c *check.C) {
  2069  	name := "stdindockerfile"
  2070  	tmpDir, err := ioutil.TempDir("", "fake-context")
  2071  	c.Assert(err, check.IsNil)
  2072  	err = ioutil.WriteFile(filepath.Join(tmpDir, "foo"), []byte("bar"), 0600)
  2073  	c.Assert(err, check.IsNil)
  2074  
  2075  	icmd.RunCmd(icmd.Cmd{
  2076  		Command: []string{dockerBinary, "build", "-t", name, "-f", "-", tmpDir},
  2077  		Stdin: strings.NewReader(
  2078  			`FROM busybox
  2079  ADD foo /foo
  2080  CMD ["cat", "/foo"]`),
  2081  	}).Assert(c, icmd.Success)
  2082  
  2083  	res := inspectField(c, name, "Config.Cmd")
  2084  	c.Assert(strings.TrimSpace(string(res)), checker.Equals, `[cat /foo]`)
  2085  }
  2086  
  2087  // FIXME(vdemeester) migrate to docker/cli tests (unit or e2e)
  2088  func (s *DockerSuite) TestBuildDockerfileStdinConflict(c *check.C) {
  2089  	name := "stdindockerfiletarcontext"
  2090  	icmd.RunCmd(icmd.Cmd{
  2091  		Command: []string{dockerBinary, "build", "-t", name, "-f", "-", "-"},
  2092  	}).Assert(c, icmd.Expected{
  2093  		ExitCode: 1,
  2094  		Err:      "use stdin for both build context and dockerfile",
  2095  	})
  2096  }
  2097  
  2098  func (s *DockerSuite) TestBuildDockerfileStdinNoExtraFiles(c *check.C) {
  2099  	s.testBuildDockerfileStdinNoExtraFiles(c, false, false)
  2100  }
  2101  
  2102  func (s *DockerSuite) TestBuildDockerfileStdinDockerignore(c *check.C) {
  2103  	s.testBuildDockerfileStdinNoExtraFiles(c, true, false)
  2104  }
  2105  
  2106  func (s *DockerSuite) TestBuildDockerfileStdinDockerignoreIgnored(c *check.C) {
  2107  	s.testBuildDockerfileStdinNoExtraFiles(c, true, true)
  2108  }
  2109  
  2110  func (s *DockerSuite) testBuildDockerfileStdinNoExtraFiles(c *check.C, hasDockerignore, ignoreDockerignore bool) {
  2111  	name := "stdindockerfilenoextra"
  2112  	tmpDir, err := ioutil.TempDir("", "fake-context")
  2113  	c.Assert(err, check.IsNil)
  2114  	defer os.RemoveAll(tmpDir)
  2115  
  2116  	writeFile := func(filename, content string) {
  2117  		err = ioutil.WriteFile(filepath.Join(tmpDir, filename), []byte(content), 0600)
  2118  		c.Assert(err, check.IsNil)
  2119  	}
  2120  
  2121  	writeFile("foo", "bar")
  2122  
  2123  	if hasDockerignore {
  2124  		// Add an empty Dockerfile to verify that it is not added to the image
  2125  		writeFile("Dockerfile", "")
  2126  
  2127  		ignores := "Dockerfile\n"
  2128  		if ignoreDockerignore {
  2129  			ignores += ".dockerignore\n"
  2130  		}
  2131  		writeFile(".dockerignore", ignores)
  2132  	}
  2133  
  2134  	result := icmd.RunCmd(icmd.Cmd{
  2135  		Command: []string{dockerBinary, "build", "-t", name, "-f", "-", tmpDir},
  2136  		Stdin: strings.NewReader(
  2137  			`FROM busybox
  2138  COPY . /baz`),
  2139  	})
  2140  	result.Assert(c, icmd.Success)
  2141  
  2142  	result = cli.DockerCmd(c, "run", "--rm", name, "ls", "-A", "/baz")
  2143  	if hasDockerignore && !ignoreDockerignore {
  2144  		c.Assert(result.Stdout(), checker.Equals, ".dockerignore\nfoo\n")
  2145  	} else {
  2146  		c.Assert(result.Stdout(), checker.Equals, "foo\n")
  2147  	}
  2148  }
  2149  
  2150  func (s *DockerSuite) TestBuildWithVolumeOwnership(c *check.C) {
  2151  	testRequires(c, DaemonIsLinux)
  2152  	name := "testbuildimg"
  2153  
  2154  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox:latest
  2155          RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test
  2156          VOLUME /test`))
  2157  
  2158  	out, _ := dockerCmd(c, "run", "--rm", "testbuildimg", "ls", "-la", "/test")
  2159  	if expected := "drw-------"; !strings.Contains(out, expected) {
  2160  		c.Fatalf("expected %s received %s", expected, out)
  2161  	}
  2162  	if expected := "daemon   daemon"; !strings.Contains(out, expected) {
  2163  		c.Fatalf("expected %s received %s", expected, out)
  2164  	}
  2165  
  2166  }
  2167  
  2168  // testing #1405 - config.Cmd does not get cleaned up if
  2169  // utilizing cache
  2170  func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) {
  2171  	name := "testbuildcmdcleanup"
  2172  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  2173          RUN echo "hello"`))
  2174  
  2175  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2176  		build.WithFile("Dockerfile", `FROM busybox
  2177          RUN echo "hello"
  2178          ADD foo /foo
  2179          ENTRYPOINT ["/bin/echo"]`),
  2180  		build.WithFile("foo", "hello")))
  2181  
  2182  	res := inspectField(c, name, "Config.Cmd")
  2183  	// Cmd must be cleaned up
  2184  	if res != "[]" {
  2185  		c.Fatalf("Cmd %s, expected nil", res)
  2186  	}
  2187  }
  2188  
  2189  func (s *DockerSuite) TestBuildAddFileNotFound(c *check.C) {
  2190  	name := "testbuildaddnotfound"
  2191  	expected := "foo: no such file or directory"
  2192  
  2193  	if testEnv.OSType == "windows" {
  2194  		expected = "foo: The system cannot find the file specified"
  2195  	}
  2196  
  2197  	buildImage(name, build.WithBuildContext(c,
  2198  		build.WithFile("Dockerfile", `FROM `+minimalBaseImage()+`
  2199          ADD foo /usr/local/bar`),
  2200  		build.WithFile("bar", "hello"))).Assert(c, icmd.Expected{
  2201  		ExitCode: 1,
  2202  		Err:      expected,
  2203  	})
  2204  }
  2205  
  2206  func (s *DockerSuite) TestBuildInheritance(c *check.C) {
  2207  	testRequires(c, DaemonIsLinux)
  2208  	name := "testbuildinheritance"
  2209  
  2210  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
  2211  		EXPOSE 2375`))
  2212  	ports1 := inspectField(c, name, "Config.ExposedPorts")
  2213  
  2214  	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM %s
  2215  		ENTRYPOINT ["/bin/echo"]`, name)))
  2216  
  2217  	res := inspectField(c, name, "Config.Entrypoint")
  2218  	if expected := "[/bin/echo]"; res != expected {
  2219  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  2220  	}
  2221  	ports2 := inspectField(c, name, "Config.ExposedPorts")
  2222  	if ports1 != ports2 {
  2223  		c.Fatalf("Ports must be same: %s != %s", ports1, ports2)
  2224  	}
  2225  }
  2226  
  2227  func (s *DockerSuite) TestBuildFails(c *check.C) {
  2228  	name := "testbuildfails"
  2229  	buildImage(name, build.WithDockerfile(`FROM busybox
  2230  		RUN sh -c "exit 23"`)).Assert(c, icmd.Expected{
  2231  		ExitCode: 23,
  2232  		Err:      "returned a non-zero code: 23",
  2233  	})
  2234  }
  2235  
  2236  func (s *DockerSuite) TestBuildOnBuild(c *check.C) {
  2237  	name := "testbuildonbuild"
  2238  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  2239  		ONBUILD RUN touch foobar`))
  2240  	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM %s
  2241  		RUN [ -f foobar ]`, name)))
  2242  }
  2243  
  2244  // gh #2446
  2245  func (s *DockerSuite) TestBuildAddToSymlinkDest(c *check.C) {
  2246  	makeLink := `ln -s /foo /bar`
  2247  	if testEnv.OSType == "windows" {
  2248  		makeLink = `mklink /D C:\bar C:\foo`
  2249  	}
  2250  	name := "testbuildaddtosymlinkdest"
  2251  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2252  		build.WithFile("Dockerfile", `
  2253  		FROM busybox
  2254  		RUN sh -c "mkdir /foo"
  2255  		RUN `+makeLink+`
  2256  		ADD foo /bar/
  2257  		RUN sh -c "[ -f /bar/foo ]"
  2258  		RUN sh -c "[ -f /foo/foo ]"`),
  2259  		build.WithFile("foo", "hello"),
  2260  	))
  2261  }
  2262  
  2263  func (s *DockerSuite) TestBuildEscapeWhitespace(c *check.C) {
  2264  	name := "testbuildescapewhitespace"
  2265  
  2266  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  2267    # ESCAPE=\
  2268    FROM busybox
  2269    MAINTAINER "Docker \
  2270  IO <io@\
  2271  docker.com>"
  2272    `))
  2273  
  2274  	res := inspectField(c, name, "Author")
  2275  	if res != "\"Docker IO <io@docker.com>\"" {
  2276  		c.Fatalf("Parsed string did not match the escaped string. Got: %q", res)
  2277  	}
  2278  
  2279  }
  2280  
  2281  func (s *DockerSuite) TestBuildVerifyIntString(c *check.C) {
  2282  	// Verify that strings that look like ints are still passed as strings
  2283  	name := "testbuildstringing"
  2284  
  2285  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  2286  	FROM busybox
  2287  	MAINTAINER 123`))
  2288  
  2289  	out, _ := dockerCmd(c, "inspect", name)
  2290  	if !strings.Contains(out, "\"123\"") {
  2291  		c.Fatalf("Output does not contain the int as a string:\n%s", out)
  2292  	}
  2293  
  2294  }
  2295  
  2296  func (s *DockerSuite) TestBuildDockerignore(c *check.C) {
  2297  	name := "testbuilddockerignore"
  2298  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2299  		build.WithFile("Dockerfile", `
  2300  		FROM busybox
  2301  		 ADD . /bla
  2302  		RUN sh -c "[[ -f /bla/src/x.go ]]"
  2303  		RUN sh -c "[[ -f /bla/Makefile ]]"
  2304  		RUN sh -c "[[ ! -e /bla/src/_vendor ]]"
  2305  		RUN sh -c "[[ ! -e /bla/.gitignore ]]"
  2306  		RUN sh -c "[[ ! -e /bla/README.md ]]"
  2307  		RUN sh -c "[[ ! -e /bla/dir/foo ]]"
  2308  		RUN sh -c "[[ ! -e /bla/foo ]]"
  2309  		RUN sh -c "[[ ! -e /bla/.git ]]"
  2310  		RUN sh -c "[[ ! -e v.cc ]]"
  2311  		RUN sh -c "[[ ! -e src/v.cc ]]"
  2312  		RUN sh -c "[[ ! -e src/_vendor/v.cc ]]"`),
  2313  		build.WithFile("Makefile", "all:"),
  2314  		build.WithFile(".git/HEAD", "ref: foo"),
  2315  		build.WithFile("src/x.go", "package main"),
  2316  		build.WithFile("src/_vendor/v.go", "package main"),
  2317  		build.WithFile("src/_vendor/v.cc", "package main"),
  2318  		build.WithFile("src/v.cc", "package main"),
  2319  		build.WithFile("v.cc", "package main"),
  2320  		build.WithFile("dir/foo", ""),
  2321  		build.WithFile(".gitignore", ""),
  2322  		build.WithFile("README.md", "readme"),
  2323  		build.WithFile(".dockerignore", `
  2324  .git
  2325  pkg
  2326  .gitignore
  2327  src/_vendor
  2328  *.md
  2329  **/*.cc
  2330  dir`),
  2331  	))
  2332  }
  2333  
  2334  func (s *DockerSuite) TestBuildDockerignoreCleanPaths(c *check.C) {
  2335  	name := "testbuilddockerignorecleanpaths"
  2336  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2337  		build.WithFile("Dockerfile", `
  2338          FROM busybox
  2339          ADD . /tmp/
  2340          RUN sh -c "(! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)"`),
  2341  		build.WithFile("foo", "foo"),
  2342  		build.WithFile("foo2", "foo2"),
  2343  		build.WithFile("dir1/foo", "foo in dir1"),
  2344  		build.WithFile(".dockerignore", "./foo\ndir1//foo\n./dir1/../foo2"),
  2345  	))
  2346  }
  2347  
  2348  func (s *DockerSuite) TestBuildDockerignoreExceptions(c *check.C) {
  2349  	name := "testbuilddockerignoreexceptions"
  2350  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2351  		build.WithFile("Dockerfile", `
  2352  		FROM busybox
  2353  		ADD . /bla
  2354  		RUN sh -c "[[ -f /bla/src/x.go ]]"
  2355  		RUN sh -c "[[ -f /bla/Makefile ]]"
  2356  		RUN sh -c "[[ ! -e /bla/src/_vendor ]]"
  2357  		RUN sh -c "[[ ! -e /bla/.gitignore ]]"
  2358  		RUN sh -c "[[ ! -e /bla/README.md ]]"
  2359  		RUN sh -c "[[  -e /bla/dir/dir/foo ]]"
  2360  		RUN sh -c "[[ ! -e /bla/dir/foo1 ]]"
  2361  		RUN sh -c "[[ -f /bla/dir/e ]]"
  2362  		RUN sh -c "[[ -f /bla/dir/e-dir/foo ]]"
  2363  		RUN sh -c "[[ ! -e /bla/foo ]]"
  2364  		RUN sh -c "[[ ! -e /bla/.git ]]"
  2365  		RUN sh -c "[[ -e /bla/dir/a.cc ]]"`),
  2366  		build.WithFile("Makefile", "all:"),
  2367  		build.WithFile(".git/HEAD", "ref: foo"),
  2368  		build.WithFile("src/x.go", "package main"),
  2369  		build.WithFile("src/_vendor/v.go", "package main"),
  2370  		build.WithFile("dir/foo", ""),
  2371  		build.WithFile("dir/foo1", ""),
  2372  		build.WithFile("dir/dir/f1", ""),
  2373  		build.WithFile("dir/dir/foo", ""),
  2374  		build.WithFile("dir/e", ""),
  2375  		build.WithFile("dir/e-dir/foo", ""),
  2376  		build.WithFile(".gitignore", ""),
  2377  		build.WithFile("README.md", "readme"),
  2378  		build.WithFile("dir/a.cc", "hello"),
  2379  		build.WithFile(".dockerignore", `
  2380  .git
  2381  pkg
  2382  .gitignore
  2383  src/_vendor
  2384  *.md
  2385  dir
  2386  !dir/e*
  2387  !dir/dir/foo
  2388  **/*.cc
  2389  !**/*.cc`),
  2390  	))
  2391  }
  2392  
  2393  func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) {
  2394  	name := "testbuilddockerignoredockerfile"
  2395  	dockerfile := `
  2396  		FROM busybox
  2397  		ADD . /tmp/
  2398  		RUN sh -c "! ls /tmp/Dockerfile"
  2399  		RUN ls /tmp/.dockerignore`
  2400  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2401  		build.WithFile("Dockerfile", dockerfile),
  2402  		build.WithFile(".dockerignore", "Dockerfile\n"),
  2403  	))
  2404  	// FIXME(vdemeester) why twice ?
  2405  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2406  		build.WithFile("Dockerfile", dockerfile),
  2407  		build.WithFile(".dockerignore", "./Dockerfile\n"),
  2408  	))
  2409  }
  2410  
  2411  func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) {
  2412  	name := "testbuilddockerignoredockerfile"
  2413  	dockerfile := `
  2414  		FROM busybox
  2415  		ADD . /tmp/
  2416  		RUN ls /tmp/Dockerfile
  2417  		RUN sh -c "! ls /tmp/MyDockerfile"
  2418  		RUN ls /tmp/.dockerignore`
  2419  	buildImageSuccessfully(c, name, cli.WithFlags("-f", "MyDockerfile"), build.WithBuildContext(c,
  2420  		build.WithFile("Dockerfile", "Should not use me"),
  2421  		build.WithFile("MyDockerfile", dockerfile),
  2422  		build.WithFile(".dockerignore", "MyDockerfile\n"),
  2423  	))
  2424  	// FIXME(vdemeester) why twice ?
  2425  	buildImageSuccessfully(c, name, cli.WithFlags("-f", "MyDockerfile"), build.WithBuildContext(c,
  2426  		build.WithFile("Dockerfile", "Should not use me"),
  2427  		build.WithFile("MyDockerfile", dockerfile),
  2428  		build.WithFile(".dockerignore", "./MyDockerfile\n"),
  2429  	))
  2430  }
  2431  
  2432  func (s *DockerSuite) TestBuildDockerignoringDockerignore(c *check.C) {
  2433  	name := "testbuilddockerignoredockerignore"
  2434  	dockerfile := `
  2435  		FROM busybox
  2436  		ADD . /tmp/
  2437  		RUN sh -c "! ls /tmp/.dockerignore"
  2438  		RUN ls /tmp/Dockerfile`
  2439  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2440  		build.WithFile("Dockerfile", dockerfile),
  2441  		build.WithFile(".dockerignore", ".dockerignore\n"),
  2442  	))
  2443  }
  2444  
  2445  func (s *DockerSuite) TestBuildDockerignoreTouchDockerfile(c *check.C) {
  2446  	name := "testbuilddockerignoretouchdockerfile"
  2447  	dockerfile := `
  2448          FROM busybox
  2449  		ADD . /tmp/`
  2450  	ctx := fakecontext.New(c, "",
  2451  		fakecontext.WithDockerfile(dockerfile),
  2452  		fakecontext.WithFiles(map[string]string{
  2453  			".dockerignore": "Dockerfile\n",
  2454  		}))
  2455  	defer ctx.Close()
  2456  
  2457  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  2458  	id1 := getIDByName(c, name)
  2459  
  2460  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  2461  	id2 := getIDByName(c, name)
  2462  	if id1 != id2 {
  2463  		c.Fatalf("Didn't use the cache - 1")
  2464  	}
  2465  
  2466  	// Now make sure touching Dockerfile doesn't invalidate the cache
  2467  	if err := ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
  2468  		c.Fatalf("Didn't add Dockerfile: %s", err)
  2469  	}
  2470  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  2471  	id2 = getIDByName(c, name)
  2472  	if id1 != id2 {
  2473  		c.Fatalf("Didn't use the cache - 2")
  2474  	}
  2475  
  2476  	// One more time but just 'touch' it instead of changing the content
  2477  	if err := ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
  2478  		c.Fatalf("Didn't add Dockerfile: %s", err)
  2479  	}
  2480  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  2481  	id2 = getIDByName(c, name)
  2482  	if id1 != id2 {
  2483  		c.Fatalf("Didn't use the cache - 3")
  2484  	}
  2485  }
  2486  
  2487  func (s *DockerSuite) TestBuildDockerignoringWholeDir(c *check.C) {
  2488  	name := "testbuilddockerignorewholedir"
  2489  
  2490  	dockerfile := `
  2491  		FROM busybox
  2492  		COPY . /
  2493  		RUN sh -c "[[ ! -e /.gitignore ]]"
  2494  		RUN sh -c "[[ ! -e /Makefile ]]"`
  2495  
  2496  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2497  		build.WithFile("Dockerfile", dockerfile),
  2498  		build.WithFile(".dockerignore", "*\n"),
  2499  		build.WithFile("Makefile", "all:"),
  2500  		build.WithFile(".gitignore", ""),
  2501  	))
  2502  }
  2503  
  2504  func (s *DockerSuite) TestBuildDockerignoringOnlyDotfiles(c *check.C) {
  2505  	name := "testbuilddockerignorewholedir"
  2506  
  2507  	dockerfile := `
  2508  		FROM busybox
  2509  		COPY . /
  2510  		RUN sh -c "[[ ! -e /.gitignore ]]"
  2511  		RUN sh -c "[[ -f /Makefile ]]"`
  2512  
  2513  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2514  		build.WithFile("Dockerfile", dockerfile),
  2515  		build.WithFile(".dockerignore", ".*"),
  2516  		build.WithFile("Makefile", "all:"),
  2517  		build.WithFile(".gitignore", ""),
  2518  	))
  2519  }
  2520  
  2521  func (s *DockerSuite) TestBuildDockerignoringBadExclusion(c *check.C) {
  2522  	name := "testbuilddockerignorebadexclusion"
  2523  	buildImage(name, build.WithBuildContext(c,
  2524  		build.WithFile("Dockerfile", `
  2525  		FROM busybox
  2526  		COPY . /
  2527  		RUN sh -c "[[ ! -e /.gitignore ]]"
  2528  		RUN sh -c "[[ -f /Makefile ]]"`),
  2529  		build.WithFile("Makefile", "all:"),
  2530  		build.WithFile(".gitignore", ""),
  2531  		build.WithFile(".dockerignore", "!\n"),
  2532  	)).Assert(c, icmd.Expected{
  2533  		ExitCode: 1,
  2534  		Err:      `illegal exclusion pattern: "!"`,
  2535  	})
  2536  }
  2537  
  2538  func (s *DockerSuite) TestBuildDockerignoringWildTopDir(c *check.C) {
  2539  	dockerfile := `
  2540  		FROM busybox
  2541  		COPY . /
  2542  		RUN sh -c "[[ ! -e /.dockerignore ]]"
  2543  		RUN sh -c "[[ ! -e /Dockerfile ]]"
  2544  		RUN sh -c "[[ ! -e /file1 ]]"
  2545  		RUN sh -c "[[ ! -e /dir ]]"`
  2546  
  2547  	// All of these should result in ignoring all files
  2548  	for _, variant := range []string{"**", "**/", "**/**", "*"} {
  2549  		buildImageSuccessfully(c, "noname", build.WithBuildContext(c,
  2550  			build.WithFile("Dockerfile", dockerfile),
  2551  			build.WithFile("file1", ""),
  2552  			build.WithFile("dir/file1", ""),
  2553  			build.WithFile(".dockerignore", variant),
  2554  		))
  2555  
  2556  		dockerCmd(c, "rmi", "noname")
  2557  	}
  2558  }
  2559  
  2560  func (s *DockerSuite) TestBuildDockerignoringWildDirs(c *check.C) {
  2561  	dockerfile := `
  2562          FROM busybox
  2563  		COPY . /
  2564  		#RUN sh -c "[[ -e /.dockerignore ]]"
  2565  		RUN sh -c "[[ -e /Dockerfile ]]           && \
  2566  		           [[ ! -e /file0 ]]              && \
  2567  		           [[ ! -e /dir1/file0 ]]         && \
  2568  		           [[ ! -e /dir2/file0 ]]         && \
  2569  		           [[ ! -e /file1 ]]              && \
  2570  		           [[ ! -e /dir1/file1 ]]         && \
  2571  		           [[ ! -e /dir1/dir2/file1 ]]    && \
  2572  		           [[ ! -e /dir1/file2 ]]         && \
  2573  		           [[   -e /dir1/dir2/file2 ]]    && \
  2574  		           [[ ! -e /dir1/dir2/file4 ]]    && \
  2575  		           [[ ! -e /dir1/dir2/file5 ]]    && \
  2576  		           [[ ! -e /dir1/dir2/file6 ]]    && \
  2577  		           [[ ! -e /dir1/dir3/file7 ]]    && \
  2578  		           [[ ! -e /dir1/dir3/file8 ]]    && \
  2579  		           [[   -e /dir1/dir3 ]]          && \
  2580  		           [[   -e /dir1/dir4 ]]          && \
  2581  		           [[ ! -e 'dir1/dir5/fileAA' ]]  && \
  2582  		           [[   -e 'dir1/dir5/fileAB' ]]  && \
  2583  		           [[   -e 'dir1/dir5/fileB' ]]"   # "." in pattern means nothing
  2584  
  2585  		RUN echo all done!`
  2586  
  2587  	dockerignore := `
  2588  **/file0
  2589  **/*file1
  2590  **/dir1/file2
  2591  dir1/**/file4
  2592  **/dir2/file5
  2593  **/dir1/dir2/file6
  2594  dir1/dir3/**
  2595  **/dir4/**
  2596  **/file?A
  2597  **/file\?B
  2598  **/dir5/file.
  2599  `
  2600  
  2601  	buildImageSuccessfully(c, "noname", build.WithBuildContext(c,
  2602  		build.WithFile("Dockerfile", dockerfile),
  2603  		build.WithFile(".dockerignore", dockerignore),
  2604  		build.WithFile("dir1/file0", ""),
  2605  		build.WithFile("dir1/dir2/file0", ""),
  2606  		build.WithFile("file1", ""),
  2607  		build.WithFile("dir1/file1", ""),
  2608  		build.WithFile("dir1/dir2/file1", ""),
  2609  		build.WithFile("dir1/file2", ""),
  2610  		build.WithFile("dir1/dir2/file2", ""), // remains
  2611  		build.WithFile("dir1/dir2/file4", ""),
  2612  		build.WithFile("dir1/dir2/file5", ""),
  2613  		build.WithFile("dir1/dir2/file6", ""),
  2614  		build.WithFile("dir1/dir3/file7", ""),
  2615  		build.WithFile("dir1/dir3/file8", ""),
  2616  		build.WithFile("dir1/dir4/file9", ""),
  2617  		build.WithFile("dir1/dir5/fileAA", ""),
  2618  		build.WithFile("dir1/dir5/fileAB", ""),
  2619  		build.WithFile("dir1/dir5/fileB", ""),
  2620  	))
  2621  }
  2622  
  2623  func (s *DockerSuite) TestBuildLineBreak(c *check.C) {
  2624  	testRequires(c, DaemonIsLinux)
  2625  	name := "testbuildlinebreak"
  2626  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM  busybox
  2627  RUN    sh -c 'echo root:testpass \
  2628  	> /tmp/passwd'
  2629  RUN    mkdir -p /var/run/sshd
  2630  RUN    sh -c "[ "$(cat /tmp/passwd)" = "root:testpass" ]"
  2631  RUN    sh -c "[ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]"`))
  2632  }
  2633  
  2634  func (s *DockerSuite) TestBuildEOLInLine(c *check.C) {
  2635  	testRequires(c, DaemonIsLinux)
  2636  	name := "testbuildeolinline"
  2637  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM   busybox
  2638  RUN    sh -c 'echo root:testpass > /tmp/passwd'
  2639  RUN    echo "foo \n bar"; echo "baz"
  2640  RUN    mkdir -p /var/run/sshd
  2641  RUN    sh -c "[ "$(cat /tmp/passwd)" = "root:testpass" ]"
  2642  RUN    sh -c "[ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]"`))
  2643  }
  2644  
  2645  func (s *DockerSuite) TestBuildCommentsShebangs(c *check.C) {
  2646  	testRequires(c, DaemonIsLinux)
  2647  	name := "testbuildcomments"
  2648  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  2649  # This is an ordinary comment.
  2650  RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh
  2651  RUN [ ! -x /hello.sh ]
  2652  # comment with line break \
  2653  RUN chmod +x /hello.sh
  2654  RUN [ -x /hello.sh ]
  2655  RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ]
  2656  RUN [ "$(/hello.sh)" = "hello world" ]`))
  2657  }
  2658  
  2659  func (s *DockerSuite) TestBuildUsersAndGroups(c *check.C) {
  2660  	testRequires(c, DaemonIsLinux)
  2661  	name := "testbuildusers"
  2662  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  2663  
  2664  # Make sure our defaults work
  2665  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ]
  2666  
  2667  # 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)
  2668  USER root
  2669  RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ]
  2670  
  2671  # Setup dockerio user and group
  2672  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd && \
  2673  	echo 'dockerio:x:1001:' >> /etc/group
  2674  
  2675  # Make sure we can switch to our user and all the information is exactly as we expect it to be
  2676  USER dockerio
  2677  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2678  
  2679  # Switch back to root and double check that worked exactly as we might expect it to
  2680  USER root
  2681  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] && \
  2682          # Add a "supplementary" group for our dockerio user
  2683  	echo 'supplementary:x:1002:dockerio' >> /etc/group
  2684  
  2685  # ... and then go verify that we get it like we expect
  2686  USER dockerio
  2687  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ]
  2688  USER 1001
  2689  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ]
  2690  
  2691  # super test the new "user:group" syntax
  2692  USER dockerio:dockerio
  2693  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2694  USER 1001:dockerio
  2695  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2696  USER dockerio:1001
  2697  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2698  USER 1001:1001
  2699  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2700  USER dockerio:supplementary
  2701  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
  2702  USER dockerio:1002
  2703  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
  2704  USER 1001:supplementary
  2705  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
  2706  USER 1001:1002
  2707  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
  2708  
  2709  # make sure unknown uid/gid still works properly
  2710  USER 1042:1043
  2711  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`))
  2712  }
  2713  
  2714  // FIXME(vdemeester) rename this test (and probably "merge" it with the one below TestBuildEnvUsage2)
  2715  func (s *DockerSuite) TestBuildEnvUsage(c *check.C) {
  2716  	// /docker/world/hello is not owned by the correct user
  2717  	testRequires(c, NotUserNamespace)
  2718  	testRequires(c, DaemonIsLinux)
  2719  	name := "testbuildenvusage"
  2720  	dockerfile := `FROM busybox
  2721  ENV    HOME /root
  2722  ENV    PATH $HOME/bin:$PATH
  2723  ENV    PATH /tmp:$PATH
  2724  RUN    [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ]
  2725  ENV    FOO /foo/baz
  2726  ENV    BAR /bar
  2727  ENV    BAZ $BAR
  2728  ENV    FOOPATH $PATH:$FOO
  2729  RUN    [ "$BAR" = "$BAZ" ]
  2730  RUN    [ "$FOOPATH" = "$PATH:/foo/baz" ]
  2731  ENV    FROM hello/docker/world
  2732  ENV    TO /docker/world/hello
  2733  ADD    $FROM $TO
  2734  RUN    [ "$(cat $TO)" = "hello" ]
  2735  ENV    abc=def
  2736  ENV    ghi=$abc
  2737  RUN    [ "$ghi" = "def" ]
  2738  `
  2739  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2740  		build.WithFile("Dockerfile", dockerfile),
  2741  		build.WithFile("hello/docker/world", "hello"),
  2742  	))
  2743  }
  2744  
  2745  // FIXME(vdemeester) rename this test (and probably "merge" it with the one above TestBuildEnvUsage)
  2746  func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) {
  2747  	// /docker/world/hello is not owned by the correct user
  2748  	testRequires(c, NotUserNamespace)
  2749  	testRequires(c, DaemonIsLinux)
  2750  	name := "testbuildenvusage2"
  2751  	dockerfile := `FROM busybox
  2752  ENV    abc=def def="hello world"
  2753  RUN    [ "$abc,$def" = "def,hello world" ]
  2754  ENV    def=hello\ world v1=abc v2="hi there" v3='boogie nights' v4="with'quotes too"
  2755  RUN    [ "$def,$v1,$v2,$v3,$v4" = "hello world,abc,hi there,boogie nights,with'quotes too" ]
  2756  ENV    abc=zzz FROM=hello/docker/world
  2757  ENV    abc=zzz TO=/docker/world/hello
  2758  ADD    $FROM $TO
  2759  RUN    [ "$abc,$(cat $TO)" = "zzz,hello" ]
  2760  ENV    abc 'yyy'
  2761  RUN    [ $abc = 'yyy' ]
  2762  ENV    abc=
  2763  RUN    [ "$abc" = "" ]
  2764  
  2765  # use grep to make sure if the builder substitutes \$foo by mistake
  2766  # we don't get a false positive
  2767  ENV    abc=\$foo
  2768  RUN    [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo)
  2769  ENV    abc \$foo
  2770  RUN    [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo)
  2771  
  2772  ENV    abc=\'foo\' abc2=\"foo\"
  2773  RUN    [ "$abc,$abc2" = "'foo',\"foo\"" ]
  2774  ENV    abc "foo"
  2775  RUN    [ "$abc" = "foo" ]
  2776  ENV    abc 'foo'
  2777  RUN    [ "$abc" = 'foo' ]
  2778  ENV    abc \'foo\'
  2779  RUN    [ "$abc" = "'foo'" ]
  2780  ENV    abc \"foo\"
  2781  RUN    [ "$abc" = '"foo"' ]
  2782  
  2783  ENV    abc=ABC
  2784  RUN    [ "$abc" = "ABC" ]
  2785  ENV    def1=${abc:-DEF} def2=${ccc:-DEF}
  2786  ENV    def3=${ccc:-${def2}xx} def4=${abc:+ALT} def5=${def2:+${abc}:} def6=${ccc:-\$abc:} def7=${ccc:-\${abc}:}
  2787  RUN    [ "$def1,$def2,$def3,$def4,$def5,$def6,$def7" = 'ABC,DEF,DEFxx,ALT,ABC:,$abc:,${abc:}' ]
  2788  ENV    mypath=${mypath:+$mypath:}/home
  2789  ENV    mypath=${mypath:+$mypath:}/away
  2790  RUN    [ "$mypath" = '/home:/away' ]
  2791  
  2792  ENV    e1=bar
  2793  ENV    e2=$e1 e3=$e11 e4=\$e1 e5=\$e11
  2794  RUN    [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ]
  2795  
  2796  ENV    ee1 bar
  2797  ENV    ee2 $ee1
  2798  ENV    ee3 $ee11
  2799  ENV    ee4 \$ee1
  2800  ENV    ee5 \$ee11
  2801  RUN    [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ]
  2802  
  2803  ENV    eee1="foo" eee2='foo'
  2804  ENV    eee3 "foo"
  2805  ENV    eee4 'foo'
  2806  RUN    [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ]
  2807  
  2808  `
  2809  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2810  		build.WithFile("Dockerfile", dockerfile),
  2811  		build.WithFile("hello/docker/world", "hello"),
  2812  	))
  2813  }
  2814  
  2815  func (s *DockerSuite) TestBuildAddScript(c *check.C) {
  2816  	testRequires(c, DaemonIsLinux)
  2817  	name := "testbuildaddscript"
  2818  	dockerfile := `
  2819  FROM busybox
  2820  ADD test /test
  2821  RUN ["chmod","+x","/test"]
  2822  RUN ["/test"]
  2823  RUN [ "$(cat /testfile)" = 'test!' ]`
  2824  
  2825  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2826  		build.WithFile("Dockerfile", dockerfile),
  2827  		build.WithFile("test", "#!/bin/sh\necho 'test!' > /testfile"),
  2828  	))
  2829  }
  2830  
  2831  func (s *DockerSuite) TestBuildAddTar(c *check.C) {
  2832  	// /test/foo is not owned by the correct user
  2833  	testRequires(c, NotUserNamespace)
  2834  	name := "testbuildaddtar"
  2835  
  2836  	ctx := func() *fakecontext.Fake {
  2837  		dockerfile := `
  2838  FROM busybox
  2839  ADD test.tar /
  2840  RUN cat /test/foo | grep Hi
  2841  ADD test.tar /test.tar
  2842  RUN cat /test.tar/test/foo | grep Hi
  2843  ADD test.tar /unlikely-to-exist
  2844  RUN cat /unlikely-to-exist/test/foo | grep Hi
  2845  ADD test.tar /unlikely-to-exist-trailing-slash/
  2846  RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi
  2847  RUN sh -c "mkdir /existing-directory" #sh -c is needed on Windows to use the correct mkdir
  2848  ADD test.tar /existing-directory
  2849  RUN cat /existing-directory/test/foo | grep Hi
  2850  ADD test.tar /existing-directory-trailing-slash/
  2851  RUN cat /existing-directory-trailing-slash/test/foo | grep Hi`
  2852  		tmpDir, err := ioutil.TempDir("", "fake-context")
  2853  		c.Assert(err, check.IsNil)
  2854  		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
  2855  		if err != nil {
  2856  			c.Fatalf("failed to create test.tar archive: %v", err)
  2857  		}
  2858  		defer testTar.Close()
  2859  
  2860  		tw := tar.NewWriter(testTar)
  2861  
  2862  		if err := tw.WriteHeader(&tar.Header{
  2863  			Name: "test/foo",
  2864  			Size: 2,
  2865  		}); err != nil {
  2866  			c.Fatalf("failed to write tar file header: %v", err)
  2867  		}
  2868  		if _, err := tw.Write([]byte("Hi")); err != nil {
  2869  			c.Fatalf("failed to write tar file content: %v", err)
  2870  		}
  2871  		if err := tw.Close(); err != nil {
  2872  			c.Fatalf("failed to close tar archive: %v", err)
  2873  		}
  2874  
  2875  		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
  2876  			c.Fatalf("failed to open destination dockerfile: %v", err)
  2877  		}
  2878  		return fakecontext.New(c, tmpDir)
  2879  	}()
  2880  	defer ctx.Close()
  2881  
  2882  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  2883  }
  2884  
  2885  func (s *DockerSuite) TestBuildAddBrokenTar(c *check.C) {
  2886  	name := "testbuildaddbrokentar"
  2887  
  2888  	ctx := func() *fakecontext.Fake {
  2889  		dockerfile := `
  2890  FROM busybox
  2891  ADD test.tar /`
  2892  		tmpDir, err := ioutil.TempDir("", "fake-context")
  2893  		c.Assert(err, check.IsNil)
  2894  		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
  2895  		if err != nil {
  2896  			c.Fatalf("failed to create test.tar archive: %v", err)
  2897  		}
  2898  		defer testTar.Close()
  2899  
  2900  		tw := tar.NewWriter(testTar)
  2901  
  2902  		if err := tw.WriteHeader(&tar.Header{
  2903  			Name: "test/foo",
  2904  			Size: 2,
  2905  		}); err != nil {
  2906  			c.Fatalf("failed to write tar file header: %v", err)
  2907  		}
  2908  		if _, err := tw.Write([]byte("Hi")); err != nil {
  2909  			c.Fatalf("failed to write tar file content: %v", err)
  2910  		}
  2911  		if err := tw.Close(); err != nil {
  2912  			c.Fatalf("failed to close tar archive: %v", err)
  2913  		}
  2914  
  2915  		// Corrupt the tar by removing one byte off the end
  2916  		stat, err := testTar.Stat()
  2917  		if err != nil {
  2918  			c.Fatalf("failed to stat tar archive: %v", err)
  2919  		}
  2920  		if err := testTar.Truncate(stat.Size() - 1); err != nil {
  2921  			c.Fatalf("failed to truncate tar archive: %v", err)
  2922  		}
  2923  
  2924  		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
  2925  			c.Fatalf("failed to open destination dockerfile: %v", err)
  2926  		}
  2927  		return fakecontext.New(c, tmpDir)
  2928  	}()
  2929  	defer ctx.Close()
  2930  
  2931  	buildImage(name, build.WithExternalBuildContext(ctx)).Assert(c, icmd.Expected{
  2932  		ExitCode: 1,
  2933  	})
  2934  }
  2935  
  2936  func (s *DockerSuite) TestBuildAddNonTar(c *check.C) {
  2937  	name := "testbuildaddnontar"
  2938  
  2939  	// Should not try to extract test.tar
  2940  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2941  		build.WithFile("Dockerfile", `
  2942  		FROM busybox
  2943  		ADD test.tar /
  2944  		RUN test -f /test.tar`),
  2945  		build.WithFile("test.tar", "not_a_tar_file"),
  2946  	))
  2947  }
  2948  
  2949  func (s *DockerSuite) TestBuildAddTarXz(c *check.C) {
  2950  	// /test/foo is not owned by the correct user
  2951  	testRequires(c, NotUserNamespace)
  2952  	testRequires(c, DaemonIsLinux)
  2953  	name := "testbuildaddtarxz"
  2954  
  2955  	ctx := func() *fakecontext.Fake {
  2956  		dockerfile := `
  2957  			FROM busybox
  2958  			ADD test.tar.xz /
  2959  			RUN cat /test/foo | grep Hi`
  2960  		tmpDir, err := ioutil.TempDir("", "fake-context")
  2961  		c.Assert(err, check.IsNil)
  2962  		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
  2963  		if err != nil {
  2964  			c.Fatalf("failed to create test.tar archive: %v", err)
  2965  		}
  2966  		defer testTar.Close()
  2967  
  2968  		tw := tar.NewWriter(testTar)
  2969  
  2970  		if err := tw.WriteHeader(&tar.Header{
  2971  			Name: "test/foo",
  2972  			Size: 2,
  2973  		}); err != nil {
  2974  			c.Fatalf("failed to write tar file header: %v", err)
  2975  		}
  2976  		if _, err := tw.Write([]byte("Hi")); err != nil {
  2977  			c.Fatalf("failed to write tar file content: %v", err)
  2978  		}
  2979  		if err := tw.Close(); err != nil {
  2980  			c.Fatalf("failed to close tar archive: %v", err)
  2981  		}
  2982  
  2983  		icmd.RunCmd(icmd.Cmd{
  2984  			Command: []string{"xz", "-k", "test.tar"},
  2985  			Dir:     tmpDir,
  2986  		}).Assert(c, icmd.Success)
  2987  		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
  2988  			c.Fatalf("failed to open destination dockerfile: %v", err)
  2989  		}
  2990  		return fakecontext.New(c, tmpDir)
  2991  	}()
  2992  
  2993  	defer ctx.Close()
  2994  
  2995  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  2996  }
  2997  
  2998  func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) {
  2999  	testRequires(c, DaemonIsLinux)
  3000  	name := "testbuildaddtarxzgz"
  3001  
  3002  	ctx := func() *fakecontext.Fake {
  3003  		dockerfile := `
  3004  			FROM busybox
  3005  			ADD test.tar.xz.gz /
  3006  			RUN ls /test.tar.xz.gz`
  3007  		tmpDir, err := ioutil.TempDir("", "fake-context")
  3008  		c.Assert(err, check.IsNil)
  3009  		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
  3010  		if err != nil {
  3011  			c.Fatalf("failed to create test.tar archive: %v", err)
  3012  		}
  3013  		defer testTar.Close()
  3014  
  3015  		tw := tar.NewWriter(testTar)
  3016  
  3017  		if err := tw.WriteHeader(&tar.Header{
  3018  			Name: "test/foo",
  3019  			Size: 2,
  3020  		}); err != nil {
  3021  			c.Fatalf("failed to write tar file header: %v", err)
  3022  		}
  3023  		if _, err := tw.Write([]byte("Hi")); err != nil {
  3024  			c.Fatalf("failed to write tar file content: %v", err)
  3025  		}
  3026  		if err := tw.Close(); err != nil {
  3027  			c.Fatalf("failed to close tar archive: %v", err)
  3028  		}
  3029  
  3030  		icmd.RunCmd(icmd.Cmd{
  3031  			Command: []string{"xz", "-k", "test.tar"},
  3032  			Dir:     tmpDir,
  3033  		}).Assert(c, icmd.Success)
  3034  
  3035  		icmd.RunCmd(icmd.Cmd{
  3036  			Command: []string{"gzip", "test.tar.xz"},
  3037  			Dir:     tmpDir,
  3038  		})
  3039  		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
  3040  			c.Fatalf("failed to open destination dockerfile: %v", err)
  3041  		}
  3042  		return fakecontext.New(c, tmpDir)
  3043  	}()
  3044  
  3045  	defer ctx.Close()
  3046  
  3047  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  3048  }
  3049  
  3050  // FIXME(vdemeester) most of the from git tests could be moved to `docker/cli` e2e tests
  3051  func (s *DockerSuite) TestBuildFromGit(c *check.C) {
  3052  	name := "testbuildfromgit"
  3053  	git := fakegit.New(c, "repo", map[string]string{
  3054  		"Dockerfile": `FROM busybox
  3055  		ADD first /first
  3056  		RUN [ -f /first ]
  3057  		MAINTAINER docker`,
  3058  		"first": "test git data",
  3059  	}, true)
  3060  	defer git.Close()
  3061  
  3062  	buildImageSuccessfully(c, name, build.WithContextPath(git.RepoURL))
  3063  
  3064  	res := inspectField(c, name, "Author")
  3065  	if res != "docker" {
  3066  		c.Fatalf("Maintainer should be docker, got %s", res)
  3067  	}
  3068  }
  3069  
  3070  func (s *DockerSuite) TestBuildFromGitWithContext(c *check.C) {
  3071  	name := "testbuildfromgit"
  3072  	git := fakegit.New(c, "repo", map[string]string{
  3073  		"docker/Dockerfile": `FROM busybox
  3074  					ADD first /first
  3075  					RUN [ -f /first ]
  3076  					MAINTAINER docker`,
  3077  		"docker/first": "test git data",
  3078  	}, true)
  3079  	defer git.Close()
  3080  
  3081  	buildImageSuccessfully(c, name, build.WithContextPath(fmt.Sprintf("%s#master:docker", git.RepoURL)))
  3082  
  3083  	res := inspectField(c, name, "Author")
  3084  	if res != "docker" {
  3085  		c.Fatalf("Maintainer should be docker, got %s", res)
  3086  	}
  3087  }
  3088  
  3089  func (s *DockerSuite) TestBuildFromGitWithF(c *check.C) {
  3090  	name := "testbuildfromgitwithf"
  3091  	git := fakegit.New(c, "repo", map[string]string{
  3092  		"myApp/myDockerfile": `FROM busybox
  3093  					RUN echo hi from Dockerfile`,
  3094  	}, true)
  3095  	defer git.Close()
  3096  
  3097  	buildImage(name, cli.WithFlags("-f", "myApp/myDockerfile"), build.WithContextPath(git.RepoURL)).Assert(c, icmd.Expected{
  3098  		Out: "hi from Dockerfile",
  3099  	})
  3100  }
  3101  
  3102  func (s *DockerSuite) TestBuildFromRemoteTarball(c *check.C) {
  3103  	name := "testbuildfromremotetarball"
  3104  
  3105  	buffer := new(bytes.Buffer)
  3106  	tw := tar.NewWriter(buffer)
  3107  	defer tw.Close()
  3108  
  3109  	dockerfile := []byte(`FROM busybox
  3110  					MAINTAINER docker`)
  3111  	if err := tw.WriteHeader(&tar.Header{
  3112  		Name: "Dockerfile",
  3113  		Size: int64(len(dockerfile)),
  3114  	}); err != nil {
  3115  		c.Fatalf("failed to write tar file header: %v", err)
  3116  	}
  3117  	if _, err := tw.Write(dockerfile); err != nil {
  3118  		c.Fatalf("failed to write tar file content: %v", err)
  3119  	}
  3120  	if err := tw.Close(); err != nil {
  3121  		c.Fatalf("failed to close tar archive: %v", err)
  3122  	}
  3123  
  3124  	server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
  3125  		"testT.tar": buffer,
  3126  	}))
  3127  	defer server.Close()
  3128  
  3129  	cli.BuildCmd(c, name, build.WithContextPath(server.URL()+"/testT.tar"))
  3130  
  3131  	res := inspectField(c, name, "Author")
  3132  	if res != "docker" {
  3133  		c.Fatalf("Maintainer should be docker, got %s", res)
  3134  	}
  3135  }
  3136  
  3137  func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) {
  3138  	name := "testbuildcmdcleanuponentrypoint"
  3139  
  3140  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  3141  		CMD ["test"]
  3142  		ENTRYPOINT ["echo"]`))
  3143  	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM %s
  3144  		ENTRYPOINT ["cat"]`, name)))
  3145  
  3146  	res := inspectField(c, name, "Config.Cmd")
  3147  	if res != "[]" {
  3148  		c.Fatalf("Cmd %s, expected nil", res)
  3149  	}
  3150  	res = inspectField(c, name, "Config.Entrypoint")
  3151  	if expected := "[cat]"; res != expected {
  3152  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  3153  	}
  3154  }
  3155  
  3156  func (s *DockerSuite) TestBuildClearCmd(c *check.C) {
  3157  	name := "testbuildclearcmd"
  3158  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  3159     ENTRYPOINT ["/bin/bash"]
  3160     CMD []`))
  3161  
  3162  	res := inspectFieldJSON(c, name, "Config.Cmd")
  3163  	if res != "[]" {
  3164  		c.Fatalf("Cmd %s, expected %s", res, "[]")
  3165  	}
  3166  }
  3167  
  3168  func (s *DockerSuite) TestBuildEmptyCmd(c *check.C) {
  3169  	// Skip on Windows. Base image on Windows has a CMD set in the image.
  3170  	testRequires(c, DaemonIsLinux)
  3171  
  3172  	name := "testbuildemptycmd"
  3173  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM "+minimalBaseImage()+"\nMAINTAINER quux\n"))
  3174  
  3175  	res := inspectFieldJSON(c, name, "Config.Cmd")
  3176  	if res != "null" {
  3177  		c.Fatalf("Cmd %s, expected %s", res, "null")
  3178  	}
  3179  }
  3180  
  3181  func (s *DockerSuite) TestBuildOnBuildOutput(c *check.C) {
  3182  	name := "testbuildonbuildparent"
  3183  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nONBUILD RUN echo foo\n"))
  3184  
  3185  	buildImage(name, build.WithDockerfile("FROM "+name+"\nMAINTAINER quux\n")).Assert(c, icmd.Expected{
  3186  		Out: "# Executing 1 build trigger",
  3187  	})
  3188  }
  3189  
  3190  // FIXME(vdemeester) should be a unit test
  3191  func (s *DockerSuite) TestBuildInvalidTag(c *check.C) {
  3192  	name := "abcd:" + testutil.GenerateRandomAlphaOnlyString(200)
  3193  	buildImage(name, build.WithDockerfile("FROM "+minimalBaseImage()+"\nMAINTAINER quux\n")).Assert(c, icmd.Expected{
  3194  		ExitCode: 125,
  3195  		Err:      "invalid reference format",
  3196  	})
  3197  }
  3198  
  3199  func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) {
  3200  	name := "testbuildcmdshc"
  3201  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD echo cmd\n"))
  3202  
  3203  	res := inspectFieldJSON(c, name, "Config.Cmd")
  3204  	expected := `["/bin/sh","-c","echo cmd"]`
  3205  	if testEnv.OSType == "windows" {
  3206  		expected = `["cmd /S /C echo cmd"]`
  3207  	}
  3208  	if res != expected {
  3209  		c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
  3210  	}
  3211  
  3212  }
  3213  
  3214  func (s *DockerSuite) TestBuildCmdSpaces(c *check.C) {
  3215  	// Test to make sure that when we strcat arrays we take into account
  3216  	// the arg separator to make sure ["echo","hi"] and ["echo hi"] don't
  3217  	// look the same
  3218  	name := "testbuildcmdspaces"
  3219  
  3220  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD [\"echo hi\"]\n"))
  3221  	id1 := getIDByName(c, name)
  3222  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD [\"echo\", \"hi\"]\n"))
  3223  	id2 := getIDByName(c, name)
  3224  
  3225  	if id1 == id2 {
  3226  		c.Fatal("Should not have resulted in the same CMD")
  3227  	}
  3228  
  3229  	// Now do the same with ENTRYPOINT
  3230  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT [\"echo hi\"]\n"))
  3231  	id1 = getIDByName(c, name)
  3232  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n"))
  3233  	id2 = getIDByName(c, name)
  3234  
  3235  	if id1 == id2 {
  3236  		c.Fatal("Should not have resulted in the same ENTRYPOINT")
  3237  	}
  3238  }
  3239  
  3240  func (s *DockerSuite) TestBuildCmdJSONNoShDashC(c *check.C) {
  3241  	name := "testbuildcmdjson"
  3242  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD [\"echo\", \"cmd\"]"))
  3243  
  3244  	res := inspectFieldJSON(c, name, "Config.Cmd")
  3245  	expected := `["echo","cmd"]`
  3246  	if res != expected {
  3247  		c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
  3248  	}
  3249  }
  3250  
  3251  func (s *DockerSuite) TestBuildEntrypointCanBeOverriddenByChild(c *check.C) {
  3252  	buildImageSuccessfully(c, "parent", build.WithDockerfile(`
  3253      FROM busybox
  3254      ENTRYPOINT exit 130
  3255      `))
  3256  
  3257  	icmd.RunCommand(dockerBinary, "run", "parent").Assert(c, icmd.Expected{
  3258  		ExitCode: 130,
  3259  	})
  3260  
  3261  	buildImageSuccessfully(c, "child", build.WithDockerfile(`
  3262      FROM parent
  3263      ENTRYPOINT exit 5
  3264      `))
  3265  
  3266  	icmd.RunCommand(dockerBinary, "run", "child").Assert(c, icmd.Expected{
  3267  		ExitCode: 5,
  3268  	})
  3269  }
  3270  
  3271  func (s *DockerSuite) TestBuildEntrypointCanBeOverriddenByChildInspect(c *check.C) {
  3272  	var (
  3273  		name     = "testbuildepinherit"
  3274  		name2    = "testbuildepinherit2"
  3275  		expected = `["/bin/sh","-c","echo quux"]`
  3276  	)
  3277  
  3278  	if testEnv.OSType == "windows" {
  3279  		expected = `["cmd /S /C echo quux"]`
  3280  	}
  3281  
  3282  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT /foo/bar"))
  3283  	buildImageSuccessfully(c, name2, build.WithDockerfile(fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name)))
  3284  
  3285  	res := inspectFieldJSON(c, name2, "Config.Entrypoint")
  3286  	if res != expected {
  3287  		c.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res)
  3288  	}
  3289  
  3290  	icmd.RunCommand(dockerBinary, "run", name2).Assert(c, icmd.Expected{
  3291  		Out: "quux",
  3292  	})
  3293  }
  3294  
  3295  func (s *DockerSuite) TestBuildRunShEntrypoint(c *check.C) {
  3296  	name := "testbuildentrypoint"
  3297  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3298                                  ENTRYPOINT echo`))
  3299  	dockerCmd(c, "run", "--rm", name)
  3300  }
  3301  
  3302  func (s *DockerSuite) TestBuildExoticShellInterpolation(c *check.C) {
  3303  	testRequires(c, DaemonIsLinux)
  3304  	name := "testbuildexoticshellinterpolation"
  3305  
  3306  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  3307  		FROM busybox
  3308  
  3309  		ENV SOME_VAR a.b.c
  3310  
  3311  		RUN [ "$SOME_VAR"       = 'a.b.c' ]
  3312  		RUN [ "${SOME_VAR}"     = 'a.b.c' ]
  3313  		RUN [ "${SOME_VAR%.*}"  = 'a.b'   ]
  3314  		RUN [ "${SOME_VAR%%.*}" = 'a'     ]
  3315  		RUN [ "${SOME_VAR#*.}"  = 'b.c'   ]
  3316  		RUN [ "${SOME_VAR##*.}" = 'c'     ]
  3317  		RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ]
  3318  		RUN [ "${#SOME_VAR}"    = '5'     ]
  3319  
  3320  		RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ]
  3321  		RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ]
  3322  		RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ]
  3323  		RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ]
  3324  	`))
  3325  }
  3326  
  3327  func (s *DockerSuite) TestBuildVerifySingleQuoteFails(c *check.C) {
  3328  	// This testcase is supposed to generate an error because the
  3329  	// JSON array we're passing in on the CMD uses single quotes instead
  3330  	// of double quotes (per the JSON spec). This means we interpret it
  3331  	// as a "string" instead of "JSON array" and pass it on to "sh -c" and
  3332  	// it should barf on it.
  3333  	name := "testbuildsinglequotefails"
  3334  	expectedExitCode := 2
  3335  
  3336  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3337  		CMD [ '/bin/sh', '-c', 'echo hi' ]`))
  3338  
  3339  	icmd.RunCommand(dockerBinary, "run", "--rm", name).Assert(c, icmd.Expected{
  3340  		ExitCode: expectedExitCode,
  3341  	})
  3342  }
  3343  
  3344  func (s *DockerSuite) TestBuildVerboseOut(c *check.C) {
  3345  	name := "testbuildverboseout"
  3346  	expected := "\n123\n"
  3347  
  3348  	if testEnv.OSType == "windows" {
  3349  		expected = "\n123\r\n"
  3350  	}
  3351  
  3352  	buildImage(name, build.WithDockerfile(`FROM busybox
  3353  RUN echo 123`)).Assert(c, icmd.Expected{
  3354  		Out: expected,
  3355  	})
  3356  }
  3357  
  3358  func (s *DockerSuite) TestBuildWithTabs(c *check.C) {
  3359  	name := "testbuildwithtabs"
  3360  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nRUN echo\tone\t\ttwo"))
  3361  	res := inspectFieldJSON(c, name, "ContainerConfig.Cmd")
  3362  	expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]`
  3363  	expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
  3364  	if testEnv.OSType == "windows" {
  3365  		expected1 = `["cmd /S /C echo\tone\t\ttwo"]`
  3366  		expected2 = `["cmd /S /C echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
  3367  	}
  3368  	if res != expected1 && res != expected2 {
  3369  		c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2)
  3370  	}
  3371  }
  3372  
  3373  func (s *DockerSuite) TestBuildLabels(c *check.C) {
  3374  	name := "testbuildlabel"
  3375  	expected := `{"License":"GPL","Vendor":"Acme"}`
  3376  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3377  		LABEL Vendor=Acme
  3378                  LABEL License GPL`))
  3379  	res := inspectFieldJSON(c, name, "Config.Labels")
  3380  	if res != expected {
  3381  		c.Fatalf("Labels %s, expected %s", res, expected)
  3382  	}
  3383  }
  3384  
  3385  func (s *DockerSuite) TestBuildLabelsCache(c *check.C) {
  3386  	name := "testbuildlabelcache"
  3387  
  3388  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3389  		LABEL Vendor=Acme`))
  3390  	id1 := getIDByName(c, name)
  3391  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3392  		LABEL Vendor=Acme`))
  3393  	id2 := getIDByName(c, name)
  3394  	if id1 != id2 {
  3395  		c.Fatalf("Build 2 should have worked & used cache(%s,%s)", id1, id2)
  3396  	}
  3397  
  3398  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3399  		LABEL Vendor=Acme1`))
  3400  	id2 = getIDByName(c, name)
  3401  	if id1 == id2 {
  3402  		c.Fatalf("Build 3 should have worked & NOT used cache(%s,%s)", id1, id2)
  3403  	}
  3404  
  3405  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3406  		LABEL Vendor Acme`))
  3407  	id2 = getIDByName(c, name)
  3408  	if id1 != id2 {
  3409  		c.Fatalf("Build 4 should have worked & used cache(%s,%s)", id1, id2)
  3410  	}
  3411  
  3412  	// Now make sure the cache isn't used by mistake
  3413  	buildImageSuccessfully(c, name, build.WithoutCache, build.WithDockerfile(`FROM busybox
  3414         LABEL f1=b1 f2=b2`))
  3415  
  3416  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3417         LABEL f1=b1 f2=b2`))
  3418  	id2 = getIDByName(c, name)
  3419  	if id1 == id2 {
  3420  		c.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s)", id1, id2)
  3421  	}
  3422  
  3423  }
  3424  
  3425  // FIXME(vdemeester) port to docker/cli e2e tests (api tests should test suppressOutput option though)
  3426  func (s *DockerSuite) TestBuildNotVerboseSuccess(c *check.C) {
  3427  	// This test makes sure that -q works correctly when build is successful:
  3428  	// stdout has only the image ID (long image ID) and stderr is empty.
  3429  	outRegexp := regexp.MustCompile("^(sha256:|)[a-z0-9]{64}\\n$")
  3430  	buildFlags := cli.WithFlags("-q")
  3431  
  3432  	tt := []struct {
  3433  		Name      string
  3434  		BuildFunc func(string) *icmd.Result
  3435  	}{
  3436  		{
  3437  			Name: "quiet_build_stdin_success",
  3438  			BuildFunc: func(name string) *icmd.Result {
  3439  				return buildImage(name, buildFlags, build.WithDockerfile("FROM busybox"))
  3440  			},
  3441  		},
  3442  		{
  3443  			Name: "quiet_build_ctx_success",
  3444  			BuildFunc: func(name string) *icmd.Result {
  3445  				return buildImage(name, buildFlags, build.WithBuildContext(c,
  3446  					build.WithFile("Dockerfile", "FROM busybox"),
  3447  					build.WithFile("quiet_build_success_fctx", "test"),
  3448  				))
  3449  			},
  3450  		},
  3451  		{
  3452  			Name: "quiet_build_git_success",
  3453  			BuildFunc: func(name string) *icmd.Result {
  3454  				git := fakegit.New(c, "repo", map[string]string{
  3455  					"Dockerfile": "FROM busybox",
  3456  				}, true)
  3457  				return buildImage(name, buildFlags, build.WithContextPath(git.RepoURL))
  3458  			},
  3459  		},
  3460  	}
  3461  
  3462  	for _, te := range tt {
  3463  		result := te.BuildFunc(te.Name)
  3464  		result.Assert(c, icmd.Success)
  3465  		if outRegexp.Find([]byte(result.Stdout())) == nil {
  3466  			c.Fatalf("Test %s expected stdout to match the [%v] regexp, but it is [%v]", te.Name, outRegexp, result.Stdout())
  3467  		}
  3468  
  3469  		if result.Stderr() != "" {
  3470  			c.Fatalf("Test %s expected stderr to be empty, but it is [%#v]", te.Name, result.Stderr())
  3471  		}
  3472  	}
  3473  
  3474  }
  3475  
  3476  // FIXME(vdemeester) migrate to docker/cli tests
  3477  func (s *DockerSuite) TestBuildNotVerboseFailureWithNonExistImage(c *check.C) {
  3478  	// This test makes sure that -q works correctly when build fails by
  3479  	// comparing between the stderr output in quiet mode and in stdout
  3480  	// and stderr output in verbose mode
  3481  	testRequires(c, Network)
  3482  	testName := "quiet_build_not_exists_image"
  3483  	dockerfile := "FROM busybox11"
  3484  	quietResult := buildImage(testName, cli.WithFlags("-q"), build.WithDockerfile(dockerfile))
  3485  	quietResult.Assert(c, icmd.Expected{
  3486  		ExitCode: 1,
  3487  	})
  3488  	result := buildImage(testName, build.WithDockerfile(dockerfile))
  3489  	result.Assert(c, icmd.Expected{
  3490  		ExitCode: 1,
  3491  	})
  3492  	if quietResult.Stderr() != result.Combined() {
  3493  		c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", testName, quietResult.Stderr(), result.Combined()))
  3494  	}
  3495  }
  3496  
  3497  // FIXME(vdemeester) migrate to docker/cli tests
  3498  func (s *DockerSuite) TestBuildNotVerboseFailure(c *check.C) {
  3499  	// This test makes sure that -q works correctly when build fails by
  3500  	// comparing between the stderr output in quiet mode and in stdout
  3501  	// and stderr output in verbose mode
  3502  	testCases := []struct {
  3503  		testName   string
  3504  		dockerfile string
  3505  	}{
  3506  		{"quiet_build_no_from_at_the_beginning", "RUN whoami"},
  3507  		{"quiet_build_unknown_instr", "FROMD busybox"},
  3508  	}
  3509  
  3510  	for _, tc := range testCases {
  3511  		quietResult := buildImage(tc.testName, cli.WithFlags("-q"), build.WithDockerfile(tc.dockerfile))
  3512  		quietResult.Assert(c, icmd.Expected{
  3513  			ExitCode: 1,
  3514  		})
  3515  		result := buildImage(tc.testName, build.WithDockerfile(tc.dockerfile))
  3516  		result.Assert(c, icmd.Expected{
  3517  			ExitCode: 1,
  3518  		})
  3519  		if quietResult.Stderr() != result.Combined() {
  3520  			c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", tc.testName, quietResult.Stderr(), result.Combined()))
  3521  		}
  3522  	}
  3523  }
  3524  
  3525  // FIXME(vdemeester) migrate to docker/cli tests
  3526  func (s *DockerSuite) TestBuildNotVerboseFailureRemote(c *check.C) {
  3527  	// This test ensures that when given a wrong URL, stderr in quiet mode and
  3528  	// stderr in verbose mode are identical.
  3529  	// TODO(vdemeester) with cobra, stdout has a carriage return too much so this test should not check stdout
  3530  	URL := "http://something.invalid"
  3531  	name := "quiet_build_wrong_remote"
  3532  	quietResult := buildImage(name, cli.WithFlags("-q"), build.WithContextPath(URL))
  3533  	quietResult.Assert(c, icmd.Expected{
  3534  		ExitCode: 1,
  3535  	})
  3536  	result := buildImage(name, build.WithContextPath(URL))
  3537  	result.Assert(c, icmd.Expected{
  3538  		ExitCode: 1,
  3539  	})
  3540  
  3541  	// An error message should contain name server IP and port, like this:
  3542  	//  "dial tcp: lookup something.invalid on 172.29.128.11:53: no such host"
  3543  	// The IP:port need to be removed in order to not trigger a test failur
  3544  	// when more than one nameserver is configured.
  3545  	// While at it, also strip excessive newlines.
  3546  	normalize := func(msg string) string {
  3547  		return strings.TrimSpace(regexp.MustCompile("[1-9][0-9.]+:[0-9]+").ReplaceAllLiteralString(msg, "<ip:port>"))
  3548  	}
  3549  
  3550  	if normalize(quietResult.Stderr()) != normalize(result.Combined()) {
  3551  		c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", name, quietResult.Stderr(), result.Combined()))
  3552  	}
  3553  }
  3554  
  3555  // FIXME(vdemeester) migrate to docker/cli tests
  3556  func (s *DockerSuite) TestBuildStderr(c *check.C) {
  3557  	// This test just makes sure that no non-error output goes
  3558  	// to stderr
  3559  	name := "testbuildstderr"
  3560  	result := buildImage(name, build.WithDockerfile("FROM busybox\nRUN echo one"))
  3561  	result.Assert(c, icmd.Success)
  3562  
  3563  	// Windows to non-Windows should have a security warning
  3564  	if runtime.GOOS == "windows" && testEnv.OSType != "windows" && !strings.Contains(result.Stdout(), "SECURITY WARNING:") {
  3565  		c.Fatalf("Stdout contains unexpected output: %q", result.Stdout())
  3566  	}
  3567  
  3568  	// Stderr should always be empty
  3569  	if result.Stderr() != "" {
  3570  		c.Fatalf("Stderr should have been empty, instead it's: %q", result.Stderr())
  3571  	}
  3572  }
  3573  
  3574  func (s *DockerSuite) TestBuildChownSingleFile(c *check.C) {
  3575  	testRequires(c, UnixCli, DaemonIsLinux) // test uses chown: not available on windows
  3576  
  3577  	name := "testbuildchownsinglefile"
  3578  
  3579  	ctx := fakecontext.New(c, "",
  3580  		fakecontext.WithDockerfile(`
  3581  FROM busybox
  3582  COPY test /
  3583  RUN ls -l /test
  3584  RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ]
  3585  `),
  3586  		fakecontext.WithFiles(map[string]string{
  3587  			"test": "test",
  3588  		}))
  3589  	defer ctx.Close()
  3590  
  3591  	if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil {
  3592  		c.Fatal(err)
  3593  	}
  3594  
  3595  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  3596  }
  3597  
  3598  func (s *DockerSuite) TestBuildSymlinkBreakout(c *check.C) {
  3599  	name := "testbuildsymlinkbreakout"
  3600  	tmpdir, err := ioutil.TempDir("", name)
  3601  	c.Assert(err, check.IsNil)
  3602  
  3603  	// See https://github.com/moby/moby/pull/37770 for reason for next line.
  3604  	tmpdir, err = system.GetLongPathName(tmpdir)
  3605  	c.Assert(err, check.IsNil)
  3606  
  3607  	defer os.RemoveAll(tmpdir)
  3608  	ctx := filepath.Join(tmpdir, "context")
  3609  	if err := os.MkdirAll(ctx, 0755); err != nil {
  3610  		c.Fatal(err)
  3611  	}
  3612  	if err := ioutil.WriteFile(filepath.Join(ctx, "Dockerfile"), []byte(`
  3613  	from busybox
  3614  	add symlink.tar /
  3615  	add inject /symlink/
  3616  	`), 0644); err != nil {
  3617  		c.Fatal(err)
  3618  	}
  3619  	inject := filepath.Join(ctx, "inject")
  3620  	if err := ioutil.WriteFile(inject, nil, 0644); err != nil {
  3621  		c.Fatal(err)
  3622  	}
  3623  	f, err := os.Create(filepath.Join(ctx, "symlink.tar"))
  3624  	if err != nil {
  3625  		c.Fatal(err)
  3626  	}
  3627  	w := tar.NewWriter(f)
  3628  	w.WriteHeader(&tar.Header{
  3629  		Name:     "symlink2",
  3630  		Typeflag: tar.TypeSymlink,
  3631  		Linkname: "/../../../../../../../../../../../../../../",
  3632  		Uid:      os.Getuid(),
  3633  		Gid:      os.Getgid(),
  3634  	})
  3635  	w.WriteHeader(&tar.Header{
  3636  		Name:     "symlink",
  3637  		Typeflag: tar.TypeSymlink,
  3638  		Linkname: filepath.Join("symlink2", tmpdir),
  3639  		Uid:      os.Getuid(),
  3640  		Gid:      os.Getgid(),
  3641  	})
  3642  	w.Close()
  3643  	f.Close()
  3644  
  3645  	buildImageSuccessfully(c, name, build.WithoutCache, build.WithExternalBuildContext(fakecontext.New(c, ctx)))
  3646  	if _, err := os.Lstat(filepath.Join(tmpdir, "inject")); err == nil {
  3647  		c.Fatal("symlink breakout - inject")
  3648  	} else if !os.IsNotExist(err) {
  3649  		c.Fatalf("unexpected error: %v", err)
  3650  	}
  3651  }
  3652  
  3653  func (s *DockerSuite) TestBuildXZHost(c *check.C) {
  3654  	// /usr/local/sbin/xz gets permission denied for the user
  3655  	testRequires(c, NotUserNamespace)
  3656  	testRequires(c, DaemonIsLinux)
  3657  	name := "testbuildxzhost"
  3658  
  3659  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  3660  		build.WithFile("Dockerfile", `
  3661  FROM busybox
  3662  ADD xz /usr/local/sbin/
  3663  RUN chmod 755 /usr/local/sbin/xz
  3664  ADD test.xz /
  3665  RUN [ ! -e /injected ]`),
  3666  		build.WithFile("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"),
  3667  		build.WithFile("xz", "#!/bin/sh\ntouch /injected"),
  3668  	))
  3669  }
  3670  
  3671  func (s *DockerSuite) TestBuildVolumesRetainContents(c *check.C) {
  3672  	// /foo/file gets permission denied for the user
  3673  	testRequires(c, NotUserNamespace)
  3674  	testRequires(c, DaemonIsLinux) // TODO Windows: Issue #20127
  3675  	var (
  3676  		name     = "testbuildvolumescontent"
  3677  		expected = "some text"
  3678  		volName  = "/foo"
  3679  	)
  3680  
  3681  	if testEnv.OSType == "windows" {
  3682  		volName = "C:/foo"
  3683  	}
  3684  
  3685  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  3686  		build.WithFile("Dockerfile", `
  3687  FROM busybox
  3688  COPY content /foo/file
  3689  VOLUME `+volName+`
  3690  CMD cat /foo/file`),
  3691  		build.WithFile("content", expected),
  3692  	))
  3693  
  3694  	out, _ := dockerCmd(c, "run", "--rm", name)
  3695  	if out != expected {
  3696  		c.Fatalf("expected file contents for /foo/file to be %q but received %q", expected, out)
  3697  	}
  3698  
  3699  }
  3700  
  3701  func (s *DockerSuite) TestBuildFromMixedcaseDockerfile(c *check.C) {
  3702  	testRequires(c, UnixCli) // Dockerfile overwrites dockerfile on windows
  3703  	testRequires(c, DaemonIsLinux)
  3704  
  3705  	// If Dockerfile is not present, use dockerfile
  3706  	buildImage("test1", build.WithBuildContext(c,
  3707  		build.WithFile("dockerfile", `FROM busybox
  3708  	RUN echo from dockerfile`),
  3709  	)).Assert(c, icmd.Expected{
  3710  		Out: "from dockerfile",
  3711  	})
  3712  
  3713  	// Prefer Dockerfile in place of dockerfile
  3714  	buildImage("test1", build.WithBuildContext(c,
  3715  		build.WithFile("dockerfile", `FROM busybox
  3716  	RUN echo from dockerfile`),
  3717  		build.WithFile("Dockerfile", `FROM busybox
  3718  	RUN echo from Dockerfile`),
  3719  	)).Assert(c, icmd.Expected{
  3720  		Out: "from Dockerfile",
  3721  	})
  3722  }
  3723  
  3724  // FIXME(vdemeester) should migrate to docker/cli tests
  3725  func (s *DockerSuite) TestBuildFromURLWithF(c *check.C) {
  3726  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{"baz": `FROM busybox
  3727  RUN echo from baz
  3728  COPY * /tmp/
  3729  RUN find /tmp/`}))
  3730  	defer server.Close()
  3731  
  3732  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
  3733  	RUN echo from Dockerfile`))
  3734  	defer ctx.Close()
  3735  
  3736  	// Make sure that -f is ignored and that we don't use the Dockerfile
  3737  	// that's in the current dir
  3738  	result := cli.BuildCmd(c, "test1", cli.WithFlags("-f", "baz", server.URL()+"/baz"), func(cmd *icmd.Cmd) func() {
  3739  		cmd.Dir = ctx.Dir
  3740  		return nil
  3741  	})
  3742  
  3743  	if !strings.Contains(result.Combined(), "from baz") ||
  3744  		strings.Contains(result.Combined(), "/tmp/baz") ||
  3745  		!strings.Contains(result.Combined(), "/tmp/Dockerfile") {
  3746  		c.Fatalf("Missing proper output: %s", result.Combined())
  3747  	}
  3748  
  3749  }
  3750  
  3751  // FIXME(vdemeester) should migrate to docker/cli tests
  3752  func (s *DockerSuite) TestBuildFromStdinWithF(c *check.C) {
  3753  	testRequires(c, DaemonIsLinux) // TODO Windows: This test is flaky; no idea why
  3754  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
  3755  RUN echo "from Dockerfile"`))
  3756  	defer ctx.Close()
  3757  
  3758  	// Make sure that -f is ignored and that we don't use the Dockerfile
  3759  	// that's in the current dir
  3760  	result := cli.BuildCmd(c, "test1", cli.WithFlags("-f", "baz", "-"), func(cmd *icmd.Cmd) func() {
  3761  		cmd.Dir = ctx.Dir
  3762  		cmd.Stdin = strings.NewReader(`FROM busybox
  3763  RUN echo "from baz"
  3764  COPY * /tmp/
  3765  RUN sh -c "find /tmp/" # sh -c is needed on Windows to use the correct find`)
  3766  		return nil
  3767  	})
  3768  
  3769  	if !strings.Contains(result.Combined(), "from baz") ||
  3770  		strings.Contains(result.Combined(), "/tmp/baz") ||
  3771  		!strings.Contains(result.Combined(), "/tmp/Dockerfile") {
  3772  		c.Fatalf("Missing proper output: %s", result.Combined())
  3773  	}
  3774  
  3775  }
  3776  
  3777  func (s *DockerSuite) TestBuildFromOfficialNames(c *check.C) {
  3778  	name := "testbuildfromofficial"
  3779  	fromNames := []string{
  3780  		"busybox",
  3781  		"docker.io/busybox",
  3782  		"index.docker.io/busybox",
  3783  		"library/busybox",
  3784  		"docker.io/library/busybox",
  3785  		"index.docker.io/library/busybox",
  3786  	}
  3787  	for idx, fromName := range fromNames {
  3788  		imgName := fmt.Sprintf("%s%d", name, idx)
  3789  		buildImageSuccessfully(c, imgName, build.WithDockerfile("FROM "+fromName))
  3790  		dockerCmd(c, "rmi", imgName)
  3791  	}
  3792  }
  3793  
  3794  // FIXME(vdemeester) should be a unit test
  3795  func (s *DockerSuite) TestBuildSpaces(c *check.C) {
  3796  	// Test to make sure that leading/trailing spaces on a command
  3797  	// doesn't change the error msg we get
  3798  	name := "testspaces"
  3799  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile("FROM busybox\nCOPY\n"))
  3800  	defer ctx.Close()
  3801  
  3802  	result1 := cli.Docker(cli.Build(name), build.WithExternalBuildContext(ctx))
  3803  	result1.Assert(c, icmd.Expected{
  3804  		ExitCode: 1,
  3805  	})
  3806  
  3807  	ctx.Add("Dockerfile", "FROM busybox\nCOPY    ")
  3808  	result2 := cli.Docker(cli.Build(name), build.WithExternalBuildContext(ctx))
  3809  	result2.Assert(c, icmd.Expected{
  3810  		ExitCode: 1,
  3811  	})
  3812  
  3813  	removeLogTimestamps := func(s string) string {
  3814  		return regexp.MustCompile(`time="(.*?)"`).ReplaceAllString(s, `time=[TIMESTAMP]`)
  3815  	}
  3816  
  3817  	// Skip over the times
  3818  	e1 := removeLogTimestamps(result1.Error.Error())
  3819  	e2 := removeLogTimestamps(result2.Error.Error())
  3820  
  3821  	// Ignore whitespace since that's what were verifying doesn't change stuff
  3822  	if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
  3823  		c.Fatalf("Build 2's error wasn't the same as build 1's\n1:%s\n2:%s", result1.Error, result2.Error)
  3824  	}
  3825  
  3826  	ctx.Add("Dockerfile", "FROM busybox\n   COPY")
  3827  	result2 = cli.Docker(cli.Build(name), build.WithoutCache, build.WithExternalBuildContext(ctx))
  3828  	result2.Assert(c, icmd.Expected{
  3829  		ExitCode: 1,
  3830  	})
  3831  
  3832  	// Skip over the times
  3833  	e1 = removeLogTimestamps(result1.Error.Error())
  3834  	e2 = removeLogTimestamps(result2.Error.Error())
  3835  
  3836  	// Ignore whitespace since that's what were verifying doesn't change stuff
  3837  	if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
  3838  		c.Fatalf("Build 3's error wasn't the same as build 1's\n1:%s\n3:%s", result1.Error, result2.Error)
  3839  	}
  3840  
  3841  	ctx.Add("Dockerfile", "FROM busybox\n   COPY    ")
  3842  	result2 = cli.Docker(cli.Build(name), build.WithoutCache, build.WithExternalBuildContext(ctx))
  3843  	result2.Assert(c, icmd.Expected{
  3844  		ExitCode: 1,
  3845  	})
  3846  
  3847  	// Skip over the times
  3848  	e1 = removeLogTimestamps(result1.Error.Error())
  3849  	e2 = removeLogTimestamps(result2.Error.Error())
  3850  
  3851  	// Ignore whitespace since that's what were verifying doesn't change stuff
  3852  	if strings.Replace(e1, " ", "", -1) != strings.Replace(e2, " ", "", -1) {
  3853  		c.Fatalf("Build 4's error wasn't the same as build 1's\n1:%s\n4:%s", result1.Error, result2.Error)
  3854  	}
  3855  
  3856  }
  3857  
  3858  func (s *DockerSuite) TestBuildSpacesWithQuotes(c *check.C) {
  3859  	// Test to make sure that spaces in quotes aren't lost
  3860  	name := "testspacesquotes"
  3861  
  3862  	dockerfile := `FROM busybox
  3863  RUN echo "  \
  3864    foo  "`
  3865  
  3866  	expected := "\n    foo  \n"
  3867  	// Windows uses the builtin echo, which preserves quotes
  3868  	if testEnv.OSType == "windows" {
  3869  		expected = "\"    foo  \""
  3870  	}
  3871  
  3872  	buildImage(name, build.WithDockerfile(dockerfile)).Assert(c, icmd.Expected{
  3873  		Out: expected,
  3874  	})
  3875  }
  3876  
  3877  // #4393
  3878  func (s *DockerSuite) TestBuildVolumeFileExistsinContainer(c *check.C) {
  3879  	testRequires(c, DaemonIsLinux) // TODO Windows: This should error out
  3880  	buildImage("docker-test-errcreatevolumewithfile", build.WithDockerfile(`
  3881  	FROM busybox
  3882  	RUN touch /foo
  3883  	VOLUME /foo
  3884  	`)).Assert(c, icmd.Expected{
  3885  		ExitCode: 1,
  3886  		Err:      "file exists",
  3887  	})
  3888  }
  3889  
  3890  // FIXME(vdemeester) should be a unit test
  3891  func (s *DockerSuite) TestBuildMissingArgs(c *check.C) {
  3892  	// Test to make sure that all Dockerfile commands (except the ones listed
  3893  	// in skipCmds) will generate an error if no args are provided.
  3894  	// Note: INSERT is deprecated so we exclude it because of that.
  3895  	skipCmds := map[string]struct{}{
  3896  		"CMD":        {},
  3897  		"RUN":        {},
  3898  		"ENTRYPOINT": {},
  3899  		"INSERT":     {},
  3900  	}
  3901  
  3902  	if testEnv.OSType == "windows" {
  3903  		skipCmds = map[string]struct{}{
  3904  			"CMD":        {},
  3905  			"RUN":        {},
  3906  			"ENTRYPOINT": {},
  3907  			"INSERT":     {},
  3908  			"STOPSIGNAL": {},
  3909  			"ARG":        {},
  3910  			"USER":       {},
  3911  			"EXPOSE":     {},
  3912  		}
  3913  	}
  3914  
  3915  	for cmd := range command.Commands {
  3916  		cmd = strings.ToUpper(cmd)
  3917  		if _, ok := skipCmds[cmd]; ok {
  3918  			continue
  3919  		}
  3920  		var dockerfile string
  3921  		if cmd == "FROM" {
  3922  			dockerfile = cmd
  3923  		} else {
  3924  			// Add FROM to make sure we don't complain about it missing
  3925  			dockerfile = "FROM busybox\n" + cmd
  3926  		}
  3927  
  3928  		buildImage("args", build.WithDockerfile(dockerfile)).Assert(c, icmd.Expected{
  3929  			ExitCode: 1,
  3930  			Err:      cmd + " requires",
  3931  		})
  3932  	}
  3933  
  3934  }
  3935  
  3936  func (s *DockerSuite) TestBuildEmptyScratch(c *check.C) {
  3937  	testRequires(c, DaemonIsLinux)
  3938  	buildImage("sc", build.WithDockerfile("FROM scratch")).Assert(c, icmd.Expected{
  3939  		ExitCode: 1,
  3940  		Err:      "No image was generated",
  3941  	})
  3942  }
  3943  
  3944  func (s *DockerSuite) TestBuildDotDotFile(c *check.C) {
  3945  	buildImageSuccessfully(c, "sc", build.WithBuildContext(c,
  3946  		build.WithFile("Dockerfile", "FROM busybox\n"),
  3947  		build.WithFile("..gitme", ""),
  3948  	))
  3949  }
  3950  
  3951  func (s *DockerSuite) TestBuildRUNoneJSON(c *check.C) {
  3952  	testRequires(c, DaemonIsLinux) // No hello-world Windows image
  3953  	name := "testbuildrunonejson"
  3954  
  3955  	buildImage(name, build.WithDockerfile(`FROM hello-world:frozen
  3956  RUN [ "/hello" ]`)).Assert(c, icmd.Expected{
  3957  		Out: "Hello from Docker",
  3958  	})
  3959  }
  3960  
  3961  func (s *DockerSuite) TestBuildEmptyStringVolume(c *check.C) {
  3962  	name := "testbuildemptystringvolume"
  3963  
  3964  	buildImage(name, build.WithDockerfile(`
  3965    FROM busybox
  3966    ENV foo=""
  3967    VOLUME $foo
  3968    `)).Assert(c, icmd.Expected{
  3969  		ExitCode: 1,
  3970  	})
  3971  }
  3972  
  3973  func (s *DockerSuite) TestBuildContainerWithCgroupParent(c *check.C) {
  3974  	testRequires(c, testEnv.IsLocalDaemon, DaemonIsLinux)
  3975  
  3976  	cgroupParent := "test"
  3977  	data, err := ioutil.ReadFile("/proc/self/cgroup")
  3978  	if err != nil {
  3979  		c.Fatalf("failed to read '/proc/self/cgroup - %v", err)
  3980  	}
  3981  	selfCgroupPaths := ParseCgroupPaths(string(data))
  3982  	_, found := selfCgroupPaths["memory"]
  3983  	if !found {
  3984  		c.Fatalf("unable to find self memory cgroup path. CgroupsPath: %v", selfCgroupPaths)
  3985  	}
  3986  	result := buildImage("buildcgroupparent",
  3987  		cli.WithFlags("--cgroup-parent", cgroupParent),
  3988  		build.WithDockerfile(`
  3989  FROM busybox
  3990  RUN cat /proc/self/cgroup
  3991  `))
  3992  	result.Assert(c, icmd.Success)
  3993  	m, err := regexp.MatchString(fmt.Sprintf("memory:.*/%s/.*", cgroupParent), result.Combined())
  3994  	c.Assert(err, check.IsNil)
  3995  	if !m {
  3996  		c.Fatalf("There is no expected memory cgroup with parent /%s/: %s", cgroupParent, result.Combined())
  3997  	}
  3998  }
  3999  
  4000  // FIXME(vdemeester) could be a unit test
  4001  func (s *DockerSuite) TestBuildNoDupOutput(c *check.C) {
  4002  	// Check to make sure our build output prints the Dockerfile cmd
  4003  	// property - there was a bug that caused it to be duplicated on the
  4004  	// Step X  line
  4005  	name := "testbuildnodupoutput"
  4006  	result := buildImage(name, build.WithDockerfile(`
  4007    FROM busybox
  4008    RUN env`))
  4009  	result.Assert(c, icmd.Success)
  4010  	exp := "\nStep 2/2 : RUN env\n"
  4011  	if !strings.Contains(result.Combined(), exp) {
  4012  		c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", result.Combined(), exp)
  4013  	}
  4014  }
  4015  
  4016  // GH15826
  4017  // FIXME(vdemeester) could be a unit test
  4018  func (s *DockerSuite) TestBuildStartsFromOne(c *check.C) {
  4019  	// Explicit check to ensure that build starts from step 1 rather than 0
  4020  	name := "testbuildstartsfromone"
  4021  	result := buildImage(name, build.WithDockerfile(`FROM busybox`))
  4022  	result.Assert(c, icmd.Success)
  4023  	exp := "\nStep 1/1 : FROM busybox\n"
  4024  	if !strings.Contains(result.Combined(), exp) {
  4025  		c.Fatalf("Bad output\nGot:%s\n\nExpected to contain:%s\n", result.Combined(), exp)
  4026  	}
  4027  }
  4028  
  4029  func (s *DockerSuite) TestBuildRUNErrMsg(c *check.C) {
  4030  	// Test to make sure the bad command is quoted with just "s and
  4031  	// not as a Go []string
  4032  	name := "testbuildbadrunerrmsg"
  4033  	shell := "/bin/sh -c"
  4034  	exitCode := 127
  4035  	if testEnv.OSType == "windows" {
  4036  		shell = "cmd /S /C"
  4037  		// architectural - Windows has to start the container to determine the exe is bad, Linux does not
  4038  		exitCode = 1
  4039  	}
  4040  	exp := fmt.Sprintf(`The command '%s badEXE a1 \& a2	a3' returned a non-zero code: %d`, shell, exitCode)
  4041  
  4042  	buildImage(name, build.WithDockerfile(`
  4043    FROM busybox
  4044    RUN badEXE a1 \& a2	a3`)).Assert(c, icmd.Expected{
  4045  		ExitCode: exitCode,
  4046  		Err:      exp,
  4047  	})
  4048  }
  4049  
  4050  // Issue #15634: COPY fails when path starts with "null"
  4051  func (s *DockerSuite) TestBuildNullStringInAddCopyVolume(c *check.C) {
  4052  	name := "testbuildnullstringinaddcopyvolume"
  4053  	volName := "nullvolume"
  4054  	if testEnv.OSType == "windows" {
  4055  		volName = `C:\\nullvolume`
  4056  	}
  4057  
  4058  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  4059  		build.WithFile("Dockerfile", `
  4060  		FROM busybox
  4061  
  4062  		ADD null /
  4063  		COPY nullfile /
  4064  		VOLUME `+volName+`
  4065  		`),
  4066  		build.WithFile("null", "test1"),
  4067  		build.WithFile("nullfile", "test2"),
  4068  	))
  4069  }
  4070  
  4071  func (s *DockerSuite) TestBuildStopSignal(c *check.C) {
  4072  	testRequires(c, DaemonIsLinux) // Windows does not support STOPSIGNAL yet
  4073  	imgName := "test_build_stop_signal"
  4074  	buildImageSuccessfully(c, imgName, build.WithDockerfile(`FROM busybox
  4075  		 STOPSIGNAL SIGKILL`))
  4076  	res := inspectFieldJSON(c, imgName, "Config.StopSignal")
  4077  	if res != `"SIGKILL"` {
  4078  		c.Fatalf("Signal %s, expected SIGKILL", res)
  4079  	}
  4080  
  4081  	containerName := "test-container-stop-signal"
  4082  	dockerCmd(c, "run", "-d", "--name", containerName, imgName, "top")
  4083  	res = inspectFieldJSON(c, containerName, "Config.StopSignal")
  4084  	if res != `"SIGKILL"` {
  4085  		c.Fatalf("Signal %s, expected SIGKILL", res)
  4086  	}
  4087  }
  4088  
  4089  func (s *DockerSuite) TestBuildBuildTimeArg(c *check.C) {
  4090  	imgName := "bldargtest"
  4091  	envKey := "foo"
  4092  	envVal := "bar"
  4093  	var dockerfile string
  4094  	if testEnv.OSType == "windows" {
  4095  		// Bugs in Windows busybox port - use the default base image and native cmd stuff
  4096  		dockerfile = fmt.Sprintf(`FROM `+minimalBaseImage()+`
  4097  			ARG %s
  4098  			RUN echo %%%s%%
  4099  			CMD setlocal enableextensions && if defined %s (echo %%%s%%)`, envKey, envKey, envKey, envKey)
  4100  	} else {
  4101  		dockerfile = fmt.Sprintf(`FROM busybox
  4102  			ARG %s
  4103  			RUN echo $%s
  4104  			CMD echo $%s`, envKey, envKey, envKey)
  4105  
  4106  	}
  4107  	buildImage(imgName,
  4108  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4109  		build.WithDockerfile(dockerfile),
  4110  	).Assert(c, icmd.Expected{
  4111  		Out: envVal,
  4112  	})
  4113  
  4114  	containerName := "bldargCont"
  4115  	out, _ := dockerCmd(c, "run", "--name", containerName, imgName)
  4116  	out = strings.Trim(out, " \r\n'")
  4117  	if out != "" {
  4118  		c.Fatalf("run produced invalid output: %q, expected empty string", out)
  4119  	}
  4120  }
  4121  
  4122  func (s *DockerSuite) TestBuildBuildTimeArgHistory(c *check.C) {
  4123  	imgName := "bldargtest"
  4124  	envKey := "foo"
  4125  	envVal := "bar"
  4126  	envDef := "bar1"
  4127  	dockerfile := fmt.Sprintf(`FROM busybox
  4128  		ARG %s=%s`, envKey, envDef)
  4129  	buildImage(imgName,
  4130  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4131  		build.WithDockerfile(dockerfile),
  4132  	).Assert(c, icmd.Expected{
  4133  		Out: envVal,
  4134  	})
  4135  
  4136  	out, _ := dockerCmd(c, "history", "--no-trunc", imgName)
  4137  	outputTabs := strings.Split(out, "\n")[1]
  4138  	if !strings.Contains(outputTabs, envDef) {
  4139  		c.Fatalf("failed to find arg default in image history output: %q expected: %q", outputTabs, envDef)
  4140  	}
  4141  }
  4142  
  4143  func (s *DockerSuite) TestBuildTimeArgHistoryExclusions(c *check.C) {
  4144  	imgName := "bldargtest"
  4145  	envKey := "foo"
  4146  	envVal := "bar"
  4147  	proxy := "HTTP_PROXY=http://user:password@proxy.example.com"
  4148  	explicitProxyKey := "http_proxy"
  4149  	explicitProxyVal := "http://user:password@someproxy.example.com"
  4150  	dockerfile := fmt.Sprintf(`FROM busybox
  4151  		ARG %s
  4152  		ARG %s
  4153  		RUN echo "Testing Build Args!"`, envKey, explicitProxyKey)
  4154  
  4155  	buildImage := func(imgName string) string {
  4156  		cli.BuildCmd(c, imgName,
  4157  			cli.WithFlags("--build-arg", "https_proxy=https://proxy.example.com",
  4158  				"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
  4159  				"--build-arg", fmt.Sprintf("%s=%s", explicitProxyKey, explicitProxyVal),
  4160  				"--build-arg", proxy),
  4161  			build.WithDockerfile(dockerfile),
  4162  		)
  4163  		return getIDByName(c, imgName)
  4164  	}
  4165  
  4166  	origID := buildImage(imgName)
  4167  	result := cli.DockerCmd(c, "history", "--no-trunc", imgName)
  4168  	out := result.Stdout()
  4169  
  4170  	if strings.Contains(out, proxy) {
  4171  		c.Fatalf("failed to exclude proxy settings from history!")
  4172  	}
  4173  	if strings.Contains(out, "https_proxy") {
  4174  		c.Fatalf("failed to exclude proxy settings from history!")
  4175  	}
  4176  	result.Assert(c, icmd.Expected{Out: fmt.Sprintf("%s=%s", envKey, envVal)})
  4177  	result.Assert(c, icmd.Expected{Out: fmt.Sprintf("%s=%s", explicitProxyKey, explicitProxyVal)})
  4178  
  4179  	cacheID := buildImage(imgName + "-two")
  4180  	c.Assert(origID, checker.Equals, cacheID)
  4181  }
  4182  
  4183  func (s *DockerSuite) TestBuildBuildTimeArgCacheHit(c *check.C) {
  4184  	imgName := "bldargtest"
  4185  	envKey := "foo"
  4186  	envVal := "bar"
  4187  	dockerfile := fmt.Sprintf(`FROM busybox
  4188  		ARG %s
  4189  		RUN echo $%s`, envKey, envKey)
  4190  	buildImageSuccessfully(c, imgName,
  4191  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4192  		build.WithDockerfile(dockerfile),
  4193  	)
  4194  	origImgID := getIDByName(c, imgName)
  4195  
  4196  	imgNameCache := "bldargtestcachehit"
  4197  	buildImageSuccessfully(c, imgNameCache,
  4198  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4199  		build.WithDockerfile(dockerfile),
  4200  	)
  4201  	newImgID := getIDByName(c, imgName)
  4202  	if newImgID != origImgID {
  4203  		c.Fatalf("build didn't use cache! expected image id: %q built image id: %q", origImgID, newImgID)
  4204  	}
  4205  }
  4206  
  4207  func (s *DockerSuite) TestBuildBuildTimeArgCacheMissExtraArg(c *check.C) {
  4208  	imgName := "bldargtest"
  4209  	envKey := "foo"
  4210  	envVal := "bar"
  4211  	extraEnvKey := "foo1"
  4212  	extraEnvVal := "bar1"
  4213  	dockerfile := fmt.Sprintf(`FROM busybox
  4214  		ARG %s
  4215  		ARG %s
  4216  		RUN echo $%s`, envKey, extraEnvKey, envKey)
  4217  	buildImageSuccessfully(c, imgName,
  4218  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4219  		build.WithDockerfile(dockerfile),
  4220  	)
  4221  	origImgID := getIDByName(c, imgName)
  4222  
  4223  	imgNameCache := "bldargtestcachemiss"
  4224  	buildImageSuccessfully(c, imgNameCache,
  4225  		cli.WithFlags(
  4226  			"--build-arg", fmt.Sprintf("%s=%s", envKey, envVal),
  4227  			"--build-arg", fmt.Sprintf("%s=%s", extraEnvKey, extraEnvVal),
  4228  		),
  4229  		build.WithDockerfile(dockerfile),
  4230  	)
  4231  	newImgID := getIDByName(c, imgNameCache)
  4232  
  4233  	if newImgID == origImgID {
  4234  		c.Fatalf("build used cache, expected a miss!")
  4235  	}
  4236  }
  4237  
  4238  func (s *DockerSuite) TestBuildBuildTimeArgCacheMissSameArgDiffVal(c *check.C) {
  4239  	imgName := "bldargtest"
  4240  	envKey := "foo"
  4241  	envVal := "bar"
  4242  	newEnvVal := "bar1"
  4243  	dockerfile := fmt.Sprintf(`FROM busybox
  4244  		ARG %s
  4245  		RUN echo $%s`, envKey, envKey)
  4246  	buildImageSuccessfully(c, imgName,
  4247  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4248  		build.WithDockerfile(dockerfile),
  4249  	)
  4250  	origImgID := getIDByName(c, imgName)
  4251  
  4252  	imgNameCache := "bldargtestcachemiss"
  4253  	buildImageSuccessfully(c, imgNameCache,
  4254  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, newEnvVal)),
  4255  		build.WithDockerfile(dockerfile),
  4256  	)
  4257  	newImgID := getIDByName(c, imgNameCache)
  4258  	if newImgID == origImgID {
  4259  		c.Fatalf("build used cache, expected a miss!")
  4260  	}
  4261  }
  4262  
  4263  func (s *DockerSuite) TestBuildBuildTimeArgOverrideArgDefinedBeforeEnv(c *check.C) {
  4264  	testRequires(c, DaemonIsLinux) // Windows does not support ARG
  4265  	imgName := "bldargtest"
  4266  	envKey := "foo"
  4267  	envVal := "bar"
  4268  	envValOverride := "barOverride"
  4269  	dockerfile := fmt.Sprintf(`FROM busybox
  4270  		ARG %s
  4271  		ENV %s %s
  4272  		RUN echo $%s
  4273  		CMD echo $%s
  4274          `, envKey, envKey, envValOverride, envKey, envKey)
  4275  
  4276  	result := buildImage(imgName,
  4277  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4278  		build.WithDockerfile(dockerfile),
  4279  	)
  4280  	result.Assert(c, icmd.Success)
  4281  	if strings.Count(result.Combined(), envValOverride) != 2 {
  4282  		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envValOverride)
  4283  	}
  4284  
  4285  	containerName := "bldargCont"
  4286  	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOverride) {
  4287  		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOverride)
  4288  	}
  4289  }
  4290  
  4291  // FIXME(vdemeester) might be useful to merge with the one above ?
  4292  func (s *DockerSuite) TestBuildBuildTimeArgOverrideEnvDefinedBeforeArg(c *check.C) {
  4293  	testRequires(c, DaemonIsLinux) // Windows does not support ARG
  4294  	imgName := "bldargtest"
  4295  	envKey := "foo"
  4296  	envVal := "bar"
  4297  	envValOverride := "barOverride"
  4298  	dockerfile := fmt.Sprintf(`FROM busybox
  4299  		ENV %s %s
  4300  		ARG %s
  4301  		RUN echo $%s
  4302  		CMD echo $%s
  4303          `, envKey, envValOverride, envKey, envKey, envKey)
  4304  	result := buildImage(imgName,
  4305  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4306  		build.WithDockerfile(dockerfile),
  4307  	)
  4308  	result.Assert(c, icmd.Success)
  4309  	if strings.Count(result.Combined(), envValOverride) != 2 {
  4310  		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envValOverride)
  4311  	}
  4312  
  4313  	containerName := "bldargCont"
  4314  	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOverride) {
  4315  		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOverride)
  4316  	}
  4317  }
  4318  
  4319  func (s *DockerSuite) TestBuildBuildTimeArgExpansion(c *check.C) {
  4320  	imgName := "bldvarstest"
  4321  
  4322  	wdVar := "WDIR"
  4323  	wdVal := "/tmp/"
  4324  	addVar := "AFILE"
  4325  	addVal := "addFile"
  4326  	copyVar := "CFILE"
  4327  	copyVal := "copyFile"
  4328  	envVar := "foo"
  4329  	envVal := "bar"
  4330  	exposeVar := "EPORT"
  4331  	exposeVal := "9999"
  4332  	userVar := "USER"
  4333  	userVal := "testUser"
  4334  	volVar := "VOL"
  4335  	volVal := "/testVol/"
  4336  	if DaemonIsWindows() {
  4337  		volVal = "C:\\testVol"
  4338  		wdVal = "C:\\tmp"
  4339  	}
  4340  
  4341  	buildImageSuccessfully(c, imgName,
  4342  		cli.WithFlags(
  4343  			"--build-arg", fmt.Sprintf("%s=%s", wdVar, wdVal),
  4344  			"--build-arg", fmt.Sprintf("%s=%s", addVar, addVal),
  4345  			"--build-arg", fmt.Sprintf("%s=%s", copyVar, copyVal),
  4346  			"--build-arg", fmt.Sprintf("%s=%s", envVar, envVal),
  4347  			"--build-arg", fmt.Sprintf("%s=%s", exposeVar, exposeVal),
  4348  			"--build-arg", fmt.Sprintf("%s=%s", userVar, userVal),
  4349  			"--build-arg", fmt.Sprintf("%s=%s", volVar, volVal),
  4350  		),
  4351  		build.WithBuildContext(c,
  4352  			build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
  4353  		ARG %s
  4354  		WORKDIR ${%s}
  4355  		ARG %s
  4356  		ADD ${%s} testDir/
  4357  		ARG %s
  4358  		COPY $%s testDir/
  4359  		ARG %s
  4360  		ENV %s=${%s}
  4361  		ARG %s
  4362  		EXPOSE $%s
  4363  		ARG %s
  4364  		USER $%s
  4365  		ARG %s
  4366  		VOLUME ${%s}`,
  4367  				wdVar, wdVar, addVar, addVar, copyVar, copyVar, envVar, envVar,
  4368  				envVar, exposeVar, exposeVar, userVar, userVar, volVar, volVar)),
  4369  			build.WithFile(addVal, "some stuff"),
  4370  			build.WithFile(copyVal, "some stuff"),
  4371  		),
  4372  	)
  4373  
  4374  	res := inspectField(c, imgName, "Config.WorkingDir")
  4375  	c.Check(filepath.ToSlash(res), check.Equals, filepath.ToSlash(wdVal))
  4376  
  4377  	var resArr []string
  4378  	inspectFieldAndUnmarshall(c, imgName, "Config.Env", &resArr)
  4379  
  4380  	found := false
  4381  	for _, v := range resArr {
  4382  		if fmt.Sprintf("%s=%s", envVar, envVal) == v {
  4383  			found = true
  4384  			break
  4385  		}
  4386  	}
  4387  	if !found {
  4388  		c.Fatalf("Config.Env value mismatch. Expected <key=value> to exist: %s=%s, got: %v",
  4389  			envVar, envVal, resArr)
  4390  	}
  4391  
  4392  	var resMap map[string]interface{}
  4393  	inspectFieldAndUnmarshall(c, imgName, "Config.ExposedPorts", &resMap)
  4394  	if _, ok := resMap[fmt.Sprintf("%s/tcp", exposeVal)]; !ok {
  4395  		c.Fatalf("Config.ExposedPorts value mismatch. Expected exposed port: %s/tcp, got: %v", exposeVal, resMap)
  4396  	}
  4397  
  4398  	res = inspectField(c, imgName, "Config.User")
  4399  	if res != userVal {
  4400  		c.Fatalf("Config.User value mismatch. Expected: %s, got: %s", userVal, res)
  4401  	}
  4402  
  4403  	inspectFieldAndUnmarshall(c, imgName, "Config.Volumes", &resMap)
  4404  	if _, ok := resMap[volVal]; !ok {
  4405  		c.Fatalf("Config.Volumes value mismatch. Expected volume: %s, got: %v", volVal, resMap)
  4406  	}
  4407  }
  4408  
  4409  func (s *DockerSuite) TestBuildBuildTimeArgExpansionOverride(c *check.C) {
  4410  	testRequires(c, DaemonIsLinux) // Windows does not support ARG
  4411  	imgName := "bldvarstest"
  4412  	envKey := "foo"
  4413  	envVal := "bar"
  4414  	envKey1 := "foo1"
  4415  	envValOverride := "barOverride"
  4416  	dockerfile := fmt.Sprintf(`FROM busybox
  4417  		ARG %s
  4418  		ENV %s %s
  4419  		ENV %s ${%s}
  4420  		RUN echo $%s
  4421  		CMD echo $%s`, envKey, envKey, envValOverride, envKey1, envKey, envKey1, envKey1)
  4422  	result := buildImage(imgName,
  4423  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4424  		build.WithDockerfile(dockerfile),
  4425  	)
  4426  	result.Assert(c, icmd.Success)
  4427  	if strings.Count(result.Combined(), envValOverride) != 2 {
  4428  		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envValOverride)
  4429  	}
  4430  
  4431  	containerName := "bldargCont"
  4432  	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOverride) {
  4433  		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOverride)
  4434  	}
  4435  }
  4436  
  4437  func (s *DockerSuite) TestBuildBuildTimeArgUntrustedDefinedAfterUse(c *check.C) {
  4438  	testRequires(c, DaemonIsLinux) // Windows does not support ARG
  4439  	imgName := "bldargtest"
  4440  	envKey := "foo"
  4441  	envVal := "bar"
  4442  	dockerfile := fmt.Sprintf(`FROM busybox
  4443  		RUN echo $%s
  4444  		ARG %s
  4445  		CMD echo $%s`, envKey, envKey, envKey)
  4446  	result := buildImage(imgName,
  4447  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4448  		build.WithDockerfile(dockerfile),
  4449  	)
  4450  	result.Assert(c, icmd.Success)
  4451  	if strings.Contains(result.Combined(), envVal) {
  4452  		c.Fatalf("able to access environment variable in output: %q expected to be missing", result.Combined())
  4453  	}
  4454  
  4455  	containerName := "bldargCont"
  4456  	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); out != "\n" {
  4457  		c.Fatalf("run produced invalid output: %q, expected empty string", out)
  4458  	}
  4459  }
  4460  
  4461  func (s *DockerSuite) TestBuildBuildTimeArgBuiltinArg(c *check.C) {
  4462  	testRequires(c, DaemonIsLinux) // Windows does not support --build-arg
  4463  	imgName := "bldargtest"
  4464  	envKey := "HTTP_PROXY"
  4465  	envVal := "bar"
  4466  	dockerfile := fmt.Sprintf(`FROM busybox
  4467  		RUN echo $%s
  4468  		CMD echo $%s`, envKey, envKey)
  4469  
  4470  	result := buildImage(imgName,
  4471  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4472  		build.WithDockerfile(dockerfile),
  4473  	)
  4474  	result.Assert(c, icmd.Success)
  4475  	if !strings.Contains(result.Combined(), envVal) {
  4476  		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envVal)
  4477  	}
  4478  	containerName := "bldargCont"
  4479  	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); out != "\n" {
  4480  		c.Fatalf("run produced invalid output: %q, expected empty string", out)
  4481  	}
  4482  }
  4483  
  4484  func (s *DockerSuite) TestBuildBuildTimeArgDefaultOverride(c *check.C) {
  4485  	testRequires(c, DaemonIsLinux) // Windows does not support ARG
  4486  	imgName := "bldargtest"
  4487  	envKey := "foo"
  4488  	envVal := "bar"
  4489  	envValOverride := "barOverride"
  4490  	dockerfile := fmt.Sprintf(`FROM busybox
  4491  		ARG %s=%s
  4492  		ENV %s $%s
  4493  		RUN echo $%s
  4494  		CMD echo $%s`, envKey, envVal, envKey, envKey, envKey, envKey)
  4495  	result := buildImage(imgName,
  4496  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envValOverride)),
  4497  		build.WithDockerfile(dockerfile),
  4498  	)
  4499  	result.Assert(c, icmd.Success)
  4500  	if strings.Count(result.Combined(), envValOverride) != 1 {
  4501  		c.Fatalf("failed to access environment variable in output: %q expected: %q", result.Combined(), envValOverride)
  4502  	}
  4503  
  4504  	containerName := "bldargCont"
  4505  	if out, _ := dockerCmd(c, "run", "--name", containerName, imgName); !strings.Contains(out, envValOverride) {
  4506  		c.Fatalf("run produced invalid output: %q, expected %q", out, envValOverride)
  4507  	}
  4508  }
  4509  
  4510  func (s *DockerSuite) TestBuildBuildTimeArgUnconsumedArg(c *check.C) {
  4511  	imgName := "bldargtest"
  4512  	envKey := "foo"
  4513  	envVal := "bar"
  4514  	dockerfile := fmt.Sprintf(`FROM busybox
  4515  		RUN echo $%s
  4516  		CMD echo $%s`, envKey, envKey)
  4517  	warnStr := "[Warning] One or more build-args"
  4518  	buildImage(imgName,
  4519  		cli.WithFlags("--build-arg", fmt.Sprintf("%s=%s", envKey, envVal)),
  4520  		build.WithDockerfile(dockerfile),
  4521  	).Assert(c, icmd.Expected{
  4522  		Out: warnStr,
  4523  	})
  4524  }
  4525  
  4526  func (s *DockerSuite) TestBuildBuildTimeArgEnv(c *check.C) {
  4527  	testRequires(c, DaemonIsLinux) // Windows does not support ARG
  4528  	dockerfile := `FROM busybox
  4529  		ARG FOO1=fromfile
  4530  		ARG FOO2=fromfile
  4531  		ARG FOO3=fromfile
  4532  		ARG FOO4=fromfile
  4533  		ARG FOO5
  4534  		ARG FOO6
  4535  		ARG FO10
  4536  		RUN env
  4537  		RUN [ "$FOO1" == "fromcmd" ]
  4538  		RUN [ "$FOO2" == "" ]
  4539  		RUN [ "$FOO3" == "fromenv" ]
  4540  		RUN [ "$FOO4" == "fromfile" ]
  4541  		RUN [ "$FOO5" == "fromcmd" ]
  4542  		# The following should not exist at all in the env
  4543  		RUN [ "$(env | grep FOO6)" == "" ]
  4544  		RUN [ "$(env | grep FOO7)" == "" ]
  4545  		RUN [ "$(env | grep FOO8)" == "" ]
  4546  		RUN [ "$(env | grep FOO9)" == "" ]
  4547  		RUN [ "$FO10" == "" ]
  4548  	    `
  4549  	result := buildImage("testbuildtimeargenv",
  4550  		cli.WithFlags(
  4551  			"--build-arg", fmt.Sprintf("FOO1=fromcmd"),
  4552  			"--build-arg", fmt.Sprintf("FOO2="),
  4553  			"--build-arg", fmt.Sprintf("FOO3"), // set in env
  4554  			"--build-arg", fmt.Sprintf("FOO4"), // not set in env
  4555  			"--build-arg", fmt.Sprintf("FOO5=fromcmd"),
  4556  			// FOO6 is not set at all
  4557  			"--build-arg", fmt.Sprintf("FOO7=fromcmd"), // should produce a warning
  4558  			"--build-arg", fmt.Sprintf("FOO8="), // should produce a warning
  4559  			"--build-arg", fmt.Sprintf("FOO9"), // should produce a warning
  4560  			"--build-arg", fmt.Sprintf("FO10"), // not set in env, empty value
  4561  		),
  4562  		cli.WithEnvironmentVariables(append(os.Environ(),
  4563  			"FOO1=fromenv",
  4564  			"FOO2=fromenv",
  4565  			"FOO3=fromenv")...),
  4566  		build.WithBuildContext(c,
  4567  			build.WithFile("Dockerfile", dockerfile),
  4568  		),
  4569  	)
  4570  	result.Assert(c, icmd.Success)
  4571  
  4572  	// Now check to make sure we got a warning msg about unused build-args
  4573  	i := strings.Index(result.Combined(), "[Warning]")
  4574  	if i < 0 {
  4575  		c.Fatalf("Missing the build-arg warning in %q", result.Combined())
  4576  	}
  4577  
  4578  	out := result.Combined()[i:] // "out" should contain just the warning message now
  4579  
  4580  	// These were specified on a --build-arg but no ARG was in the Dockerfile
  4581  	c.Assert(out, checker.Contains, "FOO7")
  4582  	c.Assert(out, checker.Contains, "FOO8")
  4583  	c.Assert(out, checker.Contains, "FOO9")
  4584  }
  4585  
  4586  func (s *DockerSuite) TestBuildBuildTimeArgQuotedValVariants(c *check.C) {
  4587  	imgName := "bldargtest"
  4588  	envKey := "foo"
  4589  	envKey1 := "foo1"
  4590  	envKey2 := "foo2"
  4591  	envKey3 := "foo3"
  4592  	dockerfile := fmt.Sprintf(`FROM busybox
  4593  		ARG %s=""
  4594  		ARG %s=''
  4595  		ARG %s="''"
  4596  		ARG %s='""'
  4597  		RUN [ "$%s" != "$%s" ]
  4598  		RUN [ "$%s" != "$%s" ]
  4599  		RUN [ "$%s" != "$%s" ]
  4600  		RUN [ "$%s" != "$%s" ]
  4601  		RUN [ "$%s" != "$%s" ]`, envKey, envKey1, envKey2, envKey3,
  4602  		envKey, envKey2, envKey, envKey3, envKey1, envKey2, envKey1, envKey3,
  4603  		envKey2, envKey3)
  4604  	buildImageSuccessfully(c, imgName, build.WithDockerfile(dockerfile))
  4605  }
  4606  
  4607  func (s *DockerSuite) TestBuildBuildTimeArgEmptyValVariants(c *check.C) {
  4608  	testRequires(c, DaemonIsLinux) // Windows does not support ARG
  4609  	imgName := "bldargtest"
  4610  	envKey := "foo"
  4611  	envKey1 := "foo1"
  4612  	envKey2 := "foo2"
  4613  	dockerfile := fmt.Sprintf(`FROM busybox
  4614  		ARG %s=
  4615  		ARG %s=""
  4616  		ARG %s=''
  4617  		RUN [ "$%s" == "$%s" ]
  4618  		RUN [ "$%s" == "$%s" ]
  4619  		RUN [ "$%s" == "$%s" ]`, envKey, envKey1, envKey2, envKey, envKey1, envKey1, envKey2, envKey, envKey2)
  4620  	buildImageSuccessfully(c, imgName, build.WithDockerfile(dockerfile))
  4621  }
  4622  
  4623  func (s *DockerSuite) TestBuildBuildTimeArgDefinitionWithNoEnvInjection(c *check.C) {
  4624  	imgName := "bldargtest"
  4625  	envKey := "foo"
  4626  	dockerfile := fmt.Sprintf(`FROM busybox
  4627  		ARG %s
  4628  		RUN env`, envKey)
  4629  
  4630  	result := cli.BuildCmd(c, imgName, build.WithDockerfile(dockerfile))
  4631  	result.Assert(c, icmd.Success)
  4632  	if strings.Count(result.Combined(), envKey) != 1 {
  4633  		c.Fatalf("unexpected number of occurrences of the arg in output: %q expected: 1", result.Combined())
  4634  	}
  4635  }
  4636  
  4637  func (s *DockerSuite) TestBuildMultiStageArg(c *check.C) {
  4638  	imgName := "multifrombldargtest"
  4639  	dockerfile := `FROM busybox
  4640      ARG foo=abc
  4641      LABEL multifromtest=1
  4642      RUN env > /out
  4643      FROM busybox
  4644      ARG bar=def
  4645      RUN env > /out`
  4646  
  4647  	result := cli.BuildCmd(c, imgName, build.WithDockerfile(dockerfile))
  4648  	result.Assert(c, icmd.Success)
  4649  
  4650  	result = cli.DockerCmd(c, "images", "-q", "-f", "label=multifromtest=1")
  4651  	parentID := strings.TrimSpace(result.Stdout())
  4652  
  4653  	result = cli.DockerCmd(c, "run", "--rm", parentID, "cat", "/out")
  4654  	c.Assert(result.Stdout(), checker.Contains, "foo=abc")
  4655  
  4656  	result = cli.DockerCmd(c, "run", "--rm", imgName, "cat", "/out")
  4657  	c.Assert(result.Stdout(), checker.Not(checker.Contains), "foo")
  4658  	c.Assert(result.Stdout(), checker.Contains, "bar=def")
  4659  }
  4660  
  4661  func (s *DockerSuite) TestBuildMultiStageGlobalArg(c *check.C) {
  4662  	imgName := "multifrombldargtest"
  4663  	dockerfile := `ARG tag=nosuchtag
  4664       FROM busybox:${tag}
  4665       LABEL multifromtest=1
  4666       RUN env > /out
  4667       FROM busybox:${tag}
  4668       ARG tag
  4669       RUN env > /out`
  4670  
  4671  	result := cli.BuildCmd(c, imgName,
  4672  		build.WithDockerfile(dockerfile),
  4673  		cli.WithFlags("--build-arg", fmt.Sprintf("tag=latest")))
  4674  	result.Assert(c, icmd.Success)
  4675  
  4676  	result = cli.DockerCmd(c, "images", "-q", "-f", "label=multifromtest=1")
  4677  	parentID := strings.TrimSpace(result.Stdout())
  4678  
  4679  	result = cli.DockerCmd(c, "run", "--rm", parentID, "cat", "/out")
  4680  	c.Assert(result.Stdout(), checker.Not(checker.Contains), "tag")
  4681  
  4682  	result = cli.DockerCmd(c, "run", "--rm", imgName, "cat", "/out")
  4683  	c.Assert(result.Stdout(), checker.Contains, "tag=latest")
  4684  }
  4685  
  4686  func (s *DockerSuite) TestBuildMultiStageUnusedArg(c *check.C) {
  4687  	imgName := "multifromunusedarg"
  4688  	dockerfile := `FROM busybox
  4689      ARG foo
  4690      FROM busybox
  4691      ARG bar
  4692      RUN env > /out`
  4693  
  4694  	result := cli.BuildCmd(c, imgName,
  4695  		build.WithDockerfile(dockerfile),
  4696  		cli.WithFlags("--build-arg", fmt.Sprintf("baz=abc")))
  4697  	result.Assert(c, icmd.Success)
  4698  	c.Assert(result.Combined(), checker.Contains, "[Warning]")
  4699  	c.Assert(result.Combined(), checker.Contains, "[baz] were not consumed")
  4700  
  4701  	result = cli.DockerCmd(c, "run", "--rm", imgName, "cat", "/out")
  4702  	c.Assert(result.Stdout(), checker.Not(checker.Contains), "bar")
  4703  	c.Assert(result.Stdout(), checker.Not(checker.Contains), "baz")
  4704  }
  4705  
  4706  func (s *DockerSuite) TestBuildNoNamedVolume(c *check.C) {
  4707  	volName := "testname:/foo"
  4708  
  4709  	if testEnv.OSType == "windows" {
  4710  		volName = "testname:C:\\foo"
  4711  	}
  4712  	dockerCmd(c, "run", "-v", volName, "busybox", "sh", "-c", "touch /foo/oops")
  4713  
  4714  	dockerFile := `FROM busybox
  4715  	VOLUME ` + volName + `
  4716  	RUN ls /foo/oops
  4717  	`
  4718  	buildImage("test", build.WithDockerfile(dockerFile)).Assert(c, icmd.Expected{
  4719  		ExitCode: 1,
  4720  	})
  4721  }
  4722  
  4723  func (s *DockerSuite) TestBuildTagEvent(c *check.C) {
  4724  	since := daemonUnixTime(c)
  4725  
  4726  	dockerFile := `FROM busybox
  4727  	RUN echo events
  4728  	`
  4729  	buildImageSuccessfully(c, "test", build.WithDockerfile(dockerFile))
  4730  
  4731  	until := daemonUnixTime(c)
  4732  	out, _ := dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "type=image")
  4733  	events := strings.Split(strings.TrimSpace(out), "\n")
  4734  	actions := eventActionsByIDAndType(c, events, "test:latest", "image")
  4735  	var foundTag bool
  4736  	for _, a := range actions {
  4737  		if a == "tag" {
  4738  			foundTag = true
  4739  			break
  4740  		}
  4741  	}
  4742  
  4743  	c.Assert(foundTag, checker.True, check.Commentf("No tag event found:\n%s", out))
  4744  }
  4745  
  4746  // #15780
  4747  func (s *DockerSuite) TestBuildMultipleTags(c *check.C) {
  4748  	dockerfile := `
  4749  	FROM busybox
  4750  	MAINTAINER test-15780
  4751  	`
  4752  	buildImageSuccessfully(c, "tag1", cli.WithFlags("-t", "tag2:v2", "-t", "tag1:latest", "-t", "tag1"), build.WithDockerfile(dockerfile))
  4753  
  4754  	id1 := getIDByName(c, "tag1")
  4755  	id2 := getIDByName(c, "tag2:v2")
  4756  	c.Assert(id1, check.Equals, id2)
  4757  }
  4758  
  4759  // #17290
  4760  func (s *DockerSuite) TestBuildCacheBrokenSymlink(c *check.C) {
  4761  	name := "testbuildbrokensymlink"
  4762  	ctx := fakecontext.New(c, "",
  4763  		fakecontext.WithDockerfile(`
  4764  	FROM busybox
  4765  	COPY . ./`),
  4766  		fakecontext.WithFiles(map[string]string{
  4767  			"foo": "bar",
  4768  		}))
  4769  	defer ctx.Close()
  4770  
  4771  	err := os.Symlink(filepath.Join(ctx.Dir, "nosuchfile"), filepath.Join(ctx.Dir, "asymlink"))
  4772  	c.Assert(err, checker.IsNil)
  4773  
  4774  	// warm up cache
  4775  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  4776  
  4777  	// add new file to context, should invalidate cache
  4778  	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "newfile"), []byte("foo"), 0644)
  4779  	c.Assert(err, checker.IsNil)
  4780  
  4781  	result := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  4782  	if strings.Contains(result.Combined(), "Using cache") {
  4783  		c.Fatal("2nd build used cache on ADD, it shouldn't")
  4784  	}
  4785  }
  4786  
  4787  func (s *DockerSuite) TestBuildFollowSymlinkToFile(c *check.C) {
  4788  	name := "testbuildbrokensymlink"
  4789  	ctx := fakecontext.New(c, "",
  4790  		fakecontext.WithDockerfile(`
  4791  	FROM busybox
  4792  	COPY asymlink target`),
  4793  		fakecontext.WithFiles(map[string]string{
  4794  			"foo": "bar",
  4795  		}))
  4796  	defer ctx.Close()
  4797  
  4798  	err := os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
  4799  	c.Assert(err, checker.IsNil)
  4800  
  4801  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  4802  
  4803  	out := cli.DockerCmd(c, "run", "--rm", name, "cat", "target").Combined()
  4804  	c.Assert(out, checker.Matches, "bar")
  4805  
  4806  	// change target file should invalidate cache
  4807  	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo"), []byte("baz"), 0644)
  4808  	c.Assert(err, checker.IsNil)
  4809  
  4810  	result := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  4811  	c.Assert(result.Combined(), checker.Not(checker.Contains), "Using cache")
  4812  
  4813  	out = cli.DockerCmd(c, "run", "--rm", name, "cat", "target").Combined()
  4814  	c.Assert(out, checker.Matches, "baz")
  4815  }
  4816  
  4817  func (s *DockerSuite) TestBuildFollowSymlinkToDir(c *check.C) {
  4818  	name := "testbuildbrokensymlink"
  4819  	ctx := fakecontext.New(c, "",
  4820  		fakecontext.WithDockerfile(`
  4821  	FROM busybox
  4822  	COPY asymlink /`),
  4823  		fakecontext.WithFiles(map[string]string{
  4824  			"foo/abc": "bar",
  4825  			"foo/def": "baz",
  4826  		}))
  4827  	defer ctx.Close()
  4828  
  4829  	err := os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
  4830  	c.Assert(err, checker.IsNil)
  4831  
  4832  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  4833  
  4834  	out := cli.DockerCmd(c, "run", "--rm", name, "cat", "abc", "def").Combined()
  4835  	c.Assert(out, checker.Matches, "barbaz")
  4836  
  4837  	// change target file should invalidate cache
  4838  	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo/def"), []byte("bax"), 0644)
  4839  	c.Assert(err, checker.IsNil)
  4840  
  4841  	result := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  4842  	c.Assert(result.Combined(), checker.Not(checker.Contains), "Using cache")
  4843  
  4844  	out = cli.DockerCmd(c, "run", "--rm", name, "cat", "abc", "def").Combined()
  4845  	c.Assert(out, checker.Matches, "barbax")
  4846  
  4847  }
  4848  
  4849  // TestBuildSymlinkBasename tests that target file gets basename from symlink,
  4850  // not from the target file.
  4851  func (s *DockerSuite) TestBuildSymlinkBasename(c *check.C) {
  4852  	name := "testbuildbrokensymlink"
  4853  	ctx := fakecontext.New(c, "",
  4854  		fakecontext.WithDockerfile(`
  4855  	FROM busybox
  4856  	COPY asymlink /`),
  4857  		fakecontext.WithFiles(map[string]string{
  4858  			"foo": "bar",
  4859  		}))
  4860  	defer ctx.Close()
  4861  
  4862  	err := os.Symlink("foo", filepath.Join(ctx.Dir, "asymlink"))
  4863  	c.Assert(err, checker.IsNil)
  4864  
  4865  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  4866  
  4867  	out := cli.DockerCmd(c, "run", "--rm", name, "cat", "asymlink").Combined()
  4868  	c.Assert(out, checker.Matches, "bar")
  4869  }
  4870  
  4871  // #17827
  4872  func (s *DockerSuite) TestBuildCacheRootSource(c *check.C) {
  4873  	name := "testbuildrootsource"
  4874  	ctx := fakecontext.New(c, "",
  4875  		fakecontext.WithDockerfile(`
  4876  	FROM busybox
  4877  	COPY / /data`),
  4878  		fakecontext.WithFiles(map[string]string{
  4879  			"foo": "bar",
  4880  		}))
  4881  	defer ctx.Close()
  4882  
  4883  	// warm up cache
  4884  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  4885  
  4886  	// change file, should invalidate cache
  4887  	err := ioutil.WriteFile(filepath.Join(ctx.Dir, "foo"), []byte("baz"), 0644)
  4888  	c.Assert(err, checker.IsNil)
  4889  
  4890  	result := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  4891  
  4892  	c.Assert(result.Combined(), checker.Not(checker.Contains), "Using cache")
  4893  }
  4894  
  4895  // #19375
  4896  // FIXME(vdemeester) should migrate to docker/cli tests
  4897  func (s *DockerSuite) TestBuildFailsGitNotCallable(c *check.C) {
  4898  	buildImage("gitnotcallable", cli.WithEnvironmentVariables("PATH="),
  4899  		build.WithContextPath("github.com/docker/v1.10-migrator.git")).Assert(c, icmd.Expected{
  4900  		ExitCode: 1,
  4901  		Err:      "unable to prepare context: unable to find 'git': ",
  4902  	})
  4903  
  4904  	buildImage("gitnotcallable", cli.WithEnvironmentVariables("PATH="),
  4905  		build.WithContextPath("https://github.com/docker/v1.10-migrator.git")).Assert(c, icmd.Expected{
  4906  		ExitCode: 1,
  4907  		Err:      "unable to prepare context: unable to find 'git': ",
  4908  	})
  4909  }
  4910  
  4911  // TestBuildWorkdirWindowsPath tests that a Windows style path works as a workdir
  4912  func (s *DockerSuite) TestBuildWorkdirWindowsPath(c *check.C) {
  4913  	testRequires(c, DaemonIsWindows)
  4914  	name := "testbuildworkdirwindowspath"
  4915  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  4916  	FROM `+testEnv.PlatformDefaults.BaseImage+`
  4917  	RUN mkdir C:\\work
  4918  	WORKDIR C:\\work
  4919  	RUN if "%CD%" NEQ "C:\work" exit -1
  4920  	`))
  4921  }
  4922  
  4923  func (s *DockerSuite) TestBuildLabel(c *check.C) {
  4924  	name := "testbuildlabel"
  4925  	testLabel := "foo"
  4926  
  4927  	buildImageSuccessfully(c, name, cli.WithFlags("--label", testLabel),
  4928  		build.WithDockerfile(`
  4929    FROM `+minimalBaseImage()+`
  4930    LABEL default foo
  4931  `))
  4932  
  4933  	var labels map[string]string
  4934  	inspectFieldAndUnmarshall(c, name, "Config.Labels", &labels)
  4935  	if _, ok := labels[testLabel]; !ok {
  4936  		c.Fatal("label not found in image")
  4937  	}
  4938  }
  4939  
  4940  func (s *DockerSuite) TestBuildLabelOneNode(c *check.C) {
  4941  	name := "testbuildlabel"
  4942  	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=bar"),
  4943  		build.WithDockerfile("FROM busybox"))
  4944  
  4945  	var labels map[string]string
  4946  	inspectFieldAndUnmarshall(c, name, "Config.Labels", &labels)
  4947  	v, ok := labels["foo"]
  4948  	if !ok {
  4949  		c.Fatal("label `foo` not found in image")
  4950  	}
  4951  	c.Assert(v, checker.Equals, "bar")
  4952  }
  4953  
  4954  func (s *DockerSuite) TestBuildLabelCacheCommit(c *check.C) {
  4955  	name := "testbuildlabelcachecommit"
  4956  	testLabel := "foo"
  4957  
  4958  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  4959    FROM `+minimalBaseImage()+`
  4960    LABEL default foo
  4961    `))
  4962  	buildImageSuccessfully(c, name, cli.WithFlags("--label", testLabel),
  4963  		build.WithDockerfile(`
  4964    FROM `+minimalBaseImage()+`
  4965    LABEL default foo
  4966    `))
  4967  
  4968  	var labels map[string]string
  4969  	inspectFieldAndUnmarshall(c, name, "Config.Labels", &labels)
  4970  	if _, ok := labels[testLabel]; !ok {
  4971  		c.Fatal("label not found in image")
  4972  	}
  4973  }
  4974  
  4975  func (s *DockerSuite) TestBuildLabelMultiple(c *check.C) {
  4976  	name := "testbuildlabelmultiple"
  4977  	testLabels := map[string]string{
  4978  		"foo": "bar",
  4979  		"123": "456",
  4980  	}
  4981  	var labelArgs []string
  4982  	for k, v := range testLabels {
  4983  		labelArgs = append(labelArgs, "--label", k+"="+v)
  4984  	}
  4985  
  4986  	buildImageSuccessfully(c, name, cli.WithFlags(labelArgs...),
  4987  		build.WithDockerfile(`
  4988    FROM `+minimalBaseImage()+`
  4989    LABEL default foo
  4990  `))
  4991  
  4992  	var labels map[string]string
  4993  	inspectFieldAndUnmarshall(c, name, "Config.Labels", &labels)
  4994  	for k, v := range testLabels {
  4995  		if x, ok := labels[k]; !ok || x != v {
  4996  			c.Fatalf("label %s=%s not found in image", k, v)
  4997  		}
  4998  	}
  4999  }
  5000  
  5001  func (s *DockerRegistryAuthHtpasswdSuite) TestBuildFromAuthenticatedRegistry(c *check.C) {
  5002  	dockerCmd(c, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
  5003  	baseImage := privateRegistryURL + "/baseimage"
  5004  
  5005  	buildImageSuccessfully(c, baseImage, build.WithDockerfile(`
  5006  	FROM busybox
  5007  	ENV env1 val1
  5008  	`))
  5009  
  5010  	dockerCmd(c, "push", baseImage)
  5011  	dockerCmd(c, "rmi", baseImage)
  5012  
  5013  	buildImageSuccessfully(c, baseImage, build.WithDockerfile(fmt.Sprintf(`
  5014  	FROM %s
  5015  	ENV env2 val2
  5016  	`, baseImage)))
  5017  }
  5018  
  5019  func (s *DockerRegistryAuthHtpasswdSuite) TestBuildWithExternalAuth(c *check.C) {
  5020  	osPath := os.Getenv("PATH")
  5021  	defer os.Setenv("PATH", osPath)
  5022  
  5023  	workingDir, err := os.Getwd()
  5024  	c.Assert(err, checker.IsNil)
  5025  	absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
  5026  	c.Assert(err, checker.IsNil)
  5027  	testPath := fmt.Sprintf("%s%c%s", osPath, filepath.ListSeparator, absolute)
  5028  
  5029  	os.Setenv("PATH", testPath)
  5030  
  5031  	repoName := fmt.Sprintf("%v/dockercli/busybox:authtest", privateRegistryURL)
  5032  
  5033  	tmp, err := ioutil.TempDir("", "integration-cli-")
  5034  	c.Assert(err, checker.IsNil)
  5035  
  5036  	externalAuthConfig := `{ "credsStore": "shell-test" }`
  5037  
  5038  	configPath := filepath.Join(tmp, "config.json")
  5039  	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
  5040  	c.Assert(err, checker.IsNil)
  5041  
  5042  	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
  5043  
  5044  	b, err := ioutil.ReadFile(configPath)
  5045  	c.Assert(err, checker.IsNil)
  5046  	c.Assert(string(b), checker.Not(checker.Contains), "\"auth\":")
  5047  
  5048  	dockerCmd(c, "--config", tmp, "tag", "busybox", repoName)
  5049  	dockerCmd(c, "--config", tmp, "push", repoName)
  5050  
  5051  	// make sure the image is pulled when building
  5052  	dockerCmd(c, "rmi", repoName)
  5053  
  5054  	icmd.RunCmd(icmd.Cmd{
  5055  		Command: []string{dockerBinary, "--config", tmp, "build", "-"},
  5056  		Stdin:   strings.NewReader(fmt.Sprintf("FROM %s", repoName)),
  5057  	}).Assert(c, icmd.Success)
  5058  }
  5059  
  5060  // Test cases in #22036
  5061  func (s *DockerSuite) TestBuildLabelsOverride(c *check.C) {
  5062  	// Command line option labels will always override
  5063  	name := "scratchy"
  5064  	expected := `{"bar":"from-flag","foo":"from-flag"}`
  5065  	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=from-flag", "--label", "bar=from-flag"),
  5066  		build.WithDockerfile(`FROM `+minimalBaseImage()+`
  5067                  LABEL foo=from-dockerfile`))
  5068  	res := inspectFieldJSON(c, name, "Config.Labels")
  5069  	if res != expected {
  5070  		c.Fatalf("Labels %s, expected %s", res, expected)
  5071  	}
  5072  
  5073  	name = "from"
  5074  	expected = `{"foo":"from-dockerfile"}`
  5075  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  5076                  LABEL foo from-dockerfile`))
  5077  	res = inspectFieldJSON(c, name, "Config.Labels")
  5078  	if res != expected {
  5079  		c.Fatalf("Labels %s, expected %s", res, expected)
  5080  	}
  5081  
  5082  	// Command line option label will override even via `FROM`
  5083  	name = "new"
  5084  	expected = `{"bar":"from-dockerfile2","foo":"new"}`
  5085  	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=new"),
  5086  		build.WithDockerfile(`FROM from
  5087                  LABEL bar from-dockerfile2`))
  5088  	res = inspectFieldJSON(c, name, "Config.Labels")
  5089  	if res != expected {
  5090  		c.Fatalf("Labels %s, expected %s", res, expected)
  5091  	}
  5092  
  5093  	// Command line option without a value set (--label foo, --label bar=)
  5094  	// will be treated as --label foo="", --label bar=""
  5095  	name = "scratchy2"
  5096  	expected = `{"bar":"","foo":""}`
  5097  	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo", "--label", "bar="),
  5098  		build.WithDockerfile(`FROM `+minimalBaseImage()+`
  5099                  LABEL foo=from-dockerfile`))
  5100  	res = inspectFieldJSON(c, name, "Config.Labels")
  5101  	if res != expected {
  5102  		c.Fatalf("Labels %s, expected %s", res, expected)
  5103  	}
  5104  
  5105  	// Command line option without a value set (--label foo, --label bar=)
  5106  	// will be treated as --label foo="", --label bar=""
  5107  	// This time is for inherited images
  5108  	name = "new2"
  5109  	expected = `{"bar":"","foo":""}`
  5110  	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=", "--label", "bar"),
  5111  		build.WithDockerfile(`FROM from
  5112                  LABEL bar from-dockerfile2`))
  5113  	res = inspectFieldJSON(c, name, "Config.Labels")
  5114  	if res != expected {
  5115  		c.Fatalf("Labels %s, expected %s", res, expected)
  5116  	}
  5117  
  5118  	// Command line option labels with only `FROM`
  5119  	name = "scratchy"
  5120  	expected = `{"bar":"from-flag","foo":"from-flag"}`
  5121  	buildImageSuccessfully(c, name, cli.WithFlags("--label", "foo=from-flag", "--label", "bar=from-flag"),
  5122  		build.WithDockerfile(`FROM `+minimalBaseImage()))
  5123  	res = inspectFieldJSON(c, name, "Config.Labels")
  5124  	if res != expected {
  5125  		c.Fatalf("Labels %s, expected %s", res, expected)
  5126  	}
  5127  
  5128  	// Command line option labels with env var
  5129  	name = "scratchz"
  5130  	expected = `{"bar":"$PATH"}`
  5131  	buildImageSuccessfully(c, name, cli.WithFlags("--label", "bar=$PATH"),
  5132  		build.WithDockerfile(`FROM `+minimalBaseImage()))
  5133  	res = inspectFieldJSON(c, name, "Config.Labels")
  5134  	if res != expected {
  5135  		c.Fatalf("Labels %s, expected %s", res, expected)
  5136  	}
  5137  }
  5138  
  5139  // Test case for #22855
  5140  func (s *DockerSuite) TestBuildDeleteCommittedFile(c *check.C) {
  5141  	name := "test-delete-committed-file"
  5142  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  5143  		RUN echo test > file
  5144  		RUN test -e file
  5145  		RUN rm file
  5146  		RUN sh -c "! test -e file"`))
  5147  }
  5148  
  5149  // #20083
  5150  func (s *DockerSuite) TestBuildDockerignoreComment(c *check.C) {
  5151  	// TODO Windows: Figure out why this test is flakey on TP5. If you add
  5152  	// something like RUN sleep 5, or even RUN ls /tmp after the ADD line,
  5153  	// it is more reliable, but that's not a good fix.
  5154  	testRequires(c, DaemonIsLinux)
  5155  
  5156  	name := "testbuilddockerignorecleanpaths"
  5157  	dockerfile := `
  5158          FROM busybox
  5159          ADD . /tmp/
  5160          RUN sh -c "(ls -la /tmp/#1)"
  5161          RUN sh -c "(! ls -la /tmp/#2)"
  5162          RUN sh -c "(! ls /tmp/foo) && (! ls /tmp/foo2) && (ls /tmp/dir1/foo)"`
  5163  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  5164  		build.WithFile("Dockerfile", dockerfile),
  5165  		build.WithFile("foo", "foo"),
  5166  		build.WithFile("foo2", "foo2"),
  5167  		build.WithFile("dir1/foo", "foo in dir1"),
  5168  		build.WithFile("#1", "# file 1"),
  5169  		build.WithFile("#2", "# file 2"),
  5170  		build.WithFile(".dockerignore", `# Visual C++ cache files
  5171  # because we have git ;-)
  5172  # The above comment is from #20083
  5173  foo
  5174  #dir1/foo
  5175  foo2
  5176  # The following is considered as comment as # is at the beginning
  5177  #1
  5178  # The following is not considered as comment as # is not at the beginning
  5179    #2
  5180  `)))
  5181  }
  5182  
  5183  // Test case for #23221
  5184  func (s *DockerSuite) TestBuildWithUTF8BOM(c *check.C) {
  5185  	name := "test-with-utf8-bom"
  5186  	dockerfile := []byte(`FROM busybox`)
  5187  	bomDockerfile := append([]byte{0xEF, 0xBB, 0xBF}, dockerfile...)
  5188  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  5189  		build.WithFile("Dockerfile", string(bomDockerfile)),
  5190  	))
  5191  }
  5192  
  5193  // Test case for UTF-8 BOM in .dockerignore, related to #23221
  5194  func (s *DockerSuite) TestBuildWithUTF8BOMDockerignore(c *check.C) {
  5195  	name := "test-with-utf8-bom-dockerignore"
  5196  	dockerfile := `
  5197          FROM busybox
  5198  		ADD . /tmp/
  5199  		RUN ls -la /tmp
  5200  		RUN sh -c "! ls /tmp/Dockerfile"
  5201  		RUN ls /tmp/.dockerignore`
  5202  	dockerignore := []byte("./Dockerfile\n")
  5203  	bomDockerignore := append([]byte{0xEF, 0xBB, 0xBF}, dockerignore...)
  5204  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  5205  		build.WithFile("Dockerfile", dockerfile),
  5206  		build.WithFile(".dockerignore", string(bomDockerignore)),
  5207  	))
  5208  }
  5209  
  5210  // #22489 Shell test to confirm config gets updated correctly
  5211  func (s *DockerSuite) TestBuildShellUpdatesConfig(c *check.C) {
  5212  	name := "testbuildshellupdatesconfig"
  5213  
  5214  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  5215          SHELL ["foo", "-bar"]`))
  5216  	expected := `["foo","-bar","#(nop) ","SHELL [foo -bar]"]`
  5217  	res := inspectFieldJSON(c, name, "ContainerConfig.Cmd")
  5218  	if res != expected {
  5219  		c.Fatalf("%s, expected %s", res, expected)
  5220  	}
  5221  	res = inspectFieldJSON(c, name, "ContainerConfig.Shell")
  5222  	if res != `["foo","-bar"]` {
  5223  		c.Fatalf(`%s, expected ["foo","-bar"]`, res)
  5224  	}
  5225  }
  5226  
  5227  // #22489 Changing the shell multiple times and CMD after.
  5228  func (s *DockerSuite) TestBuildShellMultiple(c *check.C) {
  5229  	name := "testbuildshellmultiple"
  5230  
  5231  	result := buildImage(name, build.WithDockerfile(`FROM busybox
  5232  		RUN echo defaultshell
  5233  		SHELL ["echo"]
  5234  		RUN echoshell
  5235  		SHELL ["ls"]
  5236  		RUN -l
  5237  		CMD -l`))
  5238  	result.Assert(c, icmd.Success)
  5239  
  5240  	// Must contain 'defaultshell' twice
  5241  	if len(strings.Split(result.Combined(), "defaultshell")) != 3 {
  5242  		c.Fatalf("defaultshell should have appeared twice in %s", result.Combined())
  5243  	}
  5244  
  5245  	// Must contain 'echoshell' twice
  5246  	if len(strings.Split(result.Combined(), "echoshell")) != 3 {
  5247  		c.Fatalf("echoshell should have appeared twice in %s", result.Combined())
  5248  	}
  5249  
  5250  	// Must contain "total " (part of ls -l)
  5251  	if !strings.Contains(result.Combined(), "total ") {
  5252  		c.Fatalf("%s should have contained 'total '", result.Combined())
  5253  	}
  5254  
  5255  	// A container started from the image uses the shell-form CMD.
  5256  	// Last shell is ls. CMD is -l. So should contain 'total '.
  5257  	outrun, _ := dockerCmd(c, "run", "--rm", name)
  5258  	if !strings.Contains(outrun, "total ") {
  5259  		c.Fatalf("Expected started container to run ls -l. %s", outrun)
  5260  	}
  5261  }
  5262  
  5263  // #22489. Changed SHELL with ENTRYPOINT
  5264  func (s *DockerSuite) TestBuildShellEntrypoint(c *check.C) {
  5265  	name := "testbuildshellentrypoint"
  5266  
  5267  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  5268  		SHELL ["ls"]
  5269  		ENTRYPOINT -l`))
  5270  	// A container started from the image uses the shell-form ENTRYPOINT.
  5271  	// Shell is ls. ENTRYPOINT is -l. So should contain 'total '.
  5272  	outrun, _ := dockerCmd(c, "run", "--rm", name)
  5273  	if !strings.Contains(outrun, "total ") {
  5274  		c.Fatalf("Expected started container to run ls -l. %s", outrun)
  5275  	}
  5276  }
  5277  
  5278  // #22489 Shell test to confirm shell is inherited in a subsequent build
  5279  func (s *DockerSuite) TestBuildShellInherited(c *check.C) {
  5280  	name1 := "testbuildshellinherited1"
  5281  	buildImageSuccessfully(c, name1, build.WithDockerfile(`FROM busybox
  5282          SHELL ["ls"]`))
  5283  	name2 := "testbuildshellinherited2"
  5284  	buildImage(name2, build.WithDockerfile(`FROM `+name1+`
  5285          RUN -l`)).Assert(c, icmd.Expected{
  5286  		// ls -l has "total " followed by some number in it, ls without -l does not.
  5287  		Out: "total ",
  5288  	})
  5289  }
  5290  
  5291  // #22489 Shell test to confirm non-JSON doesn't work
  5292  func (s *DockerSuite) TestBuildShellNotJSON(c *check.C) {
  5293  	name := "testbuildshellnotjson"
  5294  
  5295  	buildImage(name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  5296          sHeLl exec -form`, // Casing explicit to ensure error is upper-cased.
  5297  	)).Assert(c, icmd.Expected{
  5298  		ExitCode: 1,
  5299  		Err:      "SHELL requires the arguments to be in JSON form",
  5300  	})
  5301  }
  5302  
  5303  // #22489 Windows shell test to confirm native is powershell if executing a PS command
  5304  // This would error if the default shell were still cmd.
  5305  func (s *DockerSuite) TestBuildShellWindowsPowershell(c *check.C) {
  5306  	testRequires(c, DaemonIsWindows)
  5307  	name := "testbuildshellpowershell"
  5308  	buildImage(name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  5309          SHELL ["powershell", "-command"]
  5310  		RUN Write-Host John`)).Assert(c, icmd.Expected{
  5311  		Out: "\nJohn\n",
  5312  	})
  5313  }
  5314  
  5315  // Verify that escape is being correctly applied to words when escape directive is not \.
  5316  // Tests WORKDIR, ADD
  5317  func (s *DockerSuite) TestBuildEscapeNotBackslashWordTest(c *check.C) {
  5318  	testRequires(c, DaemonIsWindows)
  5319  	name := "testbuildescapenotbackslashwordtesta"
  5320  	buildImage(name, build.WithDockerfile(`# escape= `+"`"+`
  5321  		FROM `+minimalBaseImage()+`
  5322          WORKDIR c:\windows
  5323  		RUN dir /w`)).Assert(c, icmd.Expected{
  5324  		Out: "[System32]",
  5325  	})
  5326  
  5327  	name = "testbuildescapenotbackslashwordtestb"
  5328  	buildImage(name, build.WithDockerfile(`# escape= `+"`"+`
  5329  		FROM `+minimalBaseImage()+`
  5330  		SHELL ["powershell.exe"]
  5331          WORKDIR c:\foo
  5332  		ADD Dockerfile c:\foo\
  5333  		RUN dir Dockerfile`)).Assert(c, icmd.Expected{
  5334  		Out: "-a----",
  5335  	})
  5336  }
  5337  
  5338  // #22868. Make sure shell-form CMD is not marked as escaped in the config of the image,
  5339  // but an exec-form CMD is marked.
  5340  func (s *DockerSuite) TestBuildCmdShellArgsEscaped(c *check.C) {
  5341  	testRequires(c, DaemonIsWindows)
  5342  	name1 := "testbuildcmdshellescapedshellform"
  5343  	buildImageSuccessfully(c, name1, build.WithDockerfile(`
  5344    FROM `+minimalBaseImage()+`
  5345    CMD "ipconfig"
  5346    `))
  5347  	res := inspectFieldJSON(c, name1, "Config.ArgsEscaped")
  5348  	if res != "true" {
  5349  		c.Fatalf("CMD did not update Config.ArgsEscaped on image: %v", res)
  5350  	}
  5351  	dockerCmd(c, "run", "--name", "inspectme1", name1)
  5352  	dockerCmd(c, "wait", "inspectme1")
  5353  	res = inspectFieldJSON(c, name1, "Config.Cmd")
  5354  
  5355  	if res != `["cmd /S /C \"ipconfig\""]` {
  5356  		c.Fatalf("CMD incorrect in Config.Cmd: got %v", res)
  5357  	}
  5358  
  5359  	// Now in JSON/exec-form
  5360  	name2 := "testbuildcmdshellescapedexecform"
  5361  	buildImageSuccessfully(c, name2, build.WithDockerfile(`
  5362    FROM `+minimalBaseImage()+`
  5363    CMD ["ipconfig"]
  5364    `))
  5365  	res = inspectFieldJSON(c, name2, "Config.ArgsEscaped")
  5366  	if res != "false" {
  5367  		c.Fatalf("CMD set Config.ArgsEscaped on image: %v", res)
  5368  	}
  5369  	dockerCmd(c, "run", "--name", "inspectme2", name2)
  5370  	dockerCmd(c, "wait", "inspectme2")
  5371  	res = inspectFieldJSON(c, name2, "Config.Cmd")
  5372  
  5373  	if res != `["ipconfig"]` {
  5374  		c.Fatalf("CMD incorrect in Config.Cmd: got %v", res)
  5375  	}
  5376  
  5377  }
  5378  
  5379  // Test case for #24912.
  5380  func (s *DockerSuite) TestBuildStepsWithProgress(c *check.C) {
  5381  	name := "testbuildstepswithprogress"
  5382  	totalRun := 5
  5383  	result := buildImage(name, build.WithDockerfile("FROM busybox\n"+strings.Repeat("RUN echo foo\n", totalRun)))
  5384  	result.Assert(c, icmd.Success)
  5385  	c.Assert(result.Combined(), checker.Contains, fmt.Sprintf("Step 1/%d : FROM busybox", 1+totalRun))
  5386  	for i := 2; i <= 1+totalRun; i++ {
  5387  		c.Assert(result.Combined(), checker.Contains, fmt.Sprintf("Step %d/%d : RUN echo foo", i, 1+totalRun))
  5388  	}
  5389  }
  5390  
  5391  func (s *DockerSuite) TestBuildWithFailure(c *check.C) {
  5392  	name := "testbuildwithfailure"
  5393  
  5394  	// First test case can only detect `nobody` in runtime so all steps will show up
  5395  	dockerfile := "FROM busybox\nRUN nobody"
  5396  	result := buildImage(name, build.WithDockerfile(dockerfile))
  5397  	c.Assert(result.Error, checker.NotNil)
  5398  	c.Assert(result.Stdout(), checker.Contains, "Step 1/2 : FROM busybox")
  5399  	c.Assert(result.Stdout(), checker.Contains, "Step 2/2 : RUN nobody")
  5400  
  5401  	// Second test case `FFOM` should have been detected before build runs so no steps
  5402  	dockerfile = "FFOM nobody\nRUN nobody"
  5403  	result = buildImage(name, build.WithDockerfile(dockerfile))
  5404  	c.Assert(result.Error, checker.NotNil)
  5405  	c.Assert(result.Stdout(), checker.Not(checker.Contains), "Step 1/2 : FROM busybox")
  5406  	c.Assert(result.Stdout(), checker.Not(checker.Contains), "Step 2/2 : RUN nobody")
  5407  }
  5408  
  5409  func (s *DockerSuite) TestBuildCacheFromEqualDiffIDsLength(c *check.C) {
  5410  	dockerfile := `
  5411  		FROM busybox
  5412  		RUN echo "test"
  5413  		ENTRYPOINT ["sh"]`
  5414  	ctx := fakecontext.New(c, "",
  5415  		fakecontext.WithDockerfile(dockerfile),
  5416  		fakecontext.WithFiles(map[string]string{
  5417  			"Dockerfile": dockerfile,
  5418  		}))
  5419  	defer ctx.Close()
  5420  
  5421  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5422  	id1 := getIDByName(c, "build1")
  5423  
  5424  	// rebuild with cache-from
  5425  	result := cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
  5426  	id2 := getIDByName(c, "build2")
  5427  	c.Assert(id1, checker.Equals, id2)
  5428  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 2)
  5429  }
  5430  
  5431  func (s *DockerSuite) TestBuildCacheFrom(c *check.C) {
  5432  	testRequires(c, DaemonIsLinux) // All tests that do save are skipped in windows
  5433  	dockerfile := `
  5434  		FROM busybox
  5435  		ENV FOO=bar
  5436  		ADD baz /
  5437  		RUN touch bax`
  5438  	ctx := fakecontext.New(c, "",
  5439  		fakecontext.WithDockerfile(dockerfile),
  5440  		fakecontext.WithFiles(map[string]string{
  5441  			"Dockerfile": dockerfile,
  5442  			"baz":        "baz",
  5443  		}))
  5444  	defer ctx.Close()
  5445  
  5446  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5447  	id1 := getIDByName(c, "build1")
  5448  
  5449  	// rebuild with cache-from
  5450  	result := cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
  5451  	id2 := getIDByName(c, "build2")
  5452  	c.Assert(id1, checker.Equals, id2)
  5453  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 3)
  5454  	cli.DockerCmd(c, "rmi", "build2")
  5455  
  5456  	// no cache match with unknown source
  5457  	result = cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=nosuchtag"), build.WithExternalBuildContext(ctx))
  5458  	id2 = getIDByName(c, "build2")
  5459  	c.Assert(id1, checker.Not(checker.Equals), id2)
  5460  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 0)
  5461  	cli.DockerCmd(c, "rmi", "build2")
  5462  
  5463  	// clear parent images
  5464  	tempDir, err := ioutil.TempDir("", "test-build-cache-from-")
  5465  	if err != nil {
  5466  		c.Fatalf("failed to create temporary directory: %s", tempDir)
  5467  	}
  5468  	defer os.RemoveAll(tempDir)
  5469  	tempFile := filepath.Join(tempDir, "img.tar")
  5470  	cli.DockerCmd(c, "save", "-o", tempFile, "build1")
  5471  	cli.DockerCmd(c, "rmi", "build1")
  5472  	cli.DockerCmd(c, "load", "-i", tempFile)
  5473  	parentID := cli.DockerCmd(c, "inspect", "-f", "{{.Parent}}", "build1").Combined()
  5474  	c.Assert(strings.TrimSpace(parentID), checker.Equals, "")
  5475  
  5476  	// cache still applies without parents
  5477  	result = cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
  5478  	id2 = getIDByName(c, "build2")
  5479  	c.Assert(id1, checker.Equals, id2)
  5480  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 3)
  5481  	history1 := cli.DockerCmd(c, "history", "-q", "build2").Combined()
  5482  
  5483  	// Retry, no new intermediate images
  5484  	result = cli.BuildCmd(c, "build3", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
  5485  	id3 := getIDByName(c, "build3")
  5486  	c.Assert(id1, checker.Equals, id3)
  5487  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 3)
  5488  	history2 := cli.DockerCmd(c, "history", "-q", "build3").Combined()
  5489  
  5490  	c.Assert(history1, checker.Equals, history2)
  5491  	cli.DockerCmd(c, "rmi", "build2")
  5492  	cli.DockerCmd(c, "rmi", "build3")
  5493  	cli.DockerCmd(c, "rmi", "build1")
  5494  	cli.DockerCmd(c, "load", "-i", tempFile)
  5495  
  5496  	// Modify file, everything up to last command and layers are reused
  5497  	dockerfile = `
  5498  		FROM busybox
  5499  		ENV FOO=bar
  5500  		ADD baz /
  5501  		RUN touch newfile`
  5502  	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "Dockerfile"), []byte(dockerfile), 0644)
  5503  	c.Assert(err, checker.IsNil)
  5504  
  5505  	result = cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
  5506  	id2 = getIDByName(c, "build2")
  5507  	c.Assert(id1, checker.Not(checker.Equals), id2)
  5508  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 2)
  5509  
  5510  	layers1Str := cli.DockerCmd(c, "inspect", "-f", "{{json .RootFS.Layers}}", "build1").Combined()
  5511  	layers2Str := cli.DockerCmd(c, "inspect", "-f", "{{json .RootFS.Layers}}", "build2").Combined()
  5512  
  5513  	var layers1 []string
  5514  	var layers2 []string
  5515  	c.Assert(json.Unmarshal([]byte(layers1Str), &layers1), checker.IsNil)
  5516  	c.Assert(json.Unmarshal([]byte(layers2Str), &layers2), checker.IsNil)
  5517  
  5518  	c.Assert(len(layers1), checker.Equals, len(layers2))
  5519  	for i := 0; i < len(layers1)-1; i++ {
  5520  		c.Assert(layers1[i], checker.Equals, layers2[i])
  5521  	}
  5522  	c.Assert(layers1[len(layers1)-1], checker.Not(checker.Equals), layers2[len(layers1)-1])
  5523  }
  5524  
  5525  func (s *DockerSuite) TestBuildMultiStageCache(c *check.C) {
  5526  	testRequires(c, DaemonIsLinux) // All tests that do save are skipped in windows
  5527  	dockerfile := `
  5528  		FROM busybox
  5529  		ADD baz /
  5530  		FROM busybox
  5531      ADD baz /`
  5532  	ctx := fakecontext.New(c, "",
  5533  		fakecontext.WithDockerfile(dockerfile),
  5534  		fakecontext.WithFiles(map[string]string{
  5535  			"Dockerfile": dockerfile,
  5536  			"baz":        "baz",
  5537  		}))
  5538  	defer ctx.Close()
  5539  
  5540  	result := cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5541  	// second part of dockerfile was a repeat of first so should be cached
  5542  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 1)
  5543  
  5544  	result = cli.BuildCmd(c, "build2", cli.WithFlags("--cache-from=build1"), build.WithExternalBuildContext(ctx))
  5545  	// now both parts of dockerfile should be cached
  5546  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 2)
  5547  }
  5548  
  5549  func (s *DockerSuite) TestBuildNetNone(c *check.C) {
  5550  	testRequires(c, DaemonIsLinux)
  5551  	name := "testbuildnetnone"
  5552  	buildImage(name, cli.WithFlags("--network=none"), build.WithDockerfile(`
  5553    FROM busybox
  5554    RUN ping -c 1 8.8.8.8
  5555    `)).Assert(c, icmd.Expected{
  5556  		ExitCode: 1,
  5557  		Out:      "unreachable",
  5558  	})
  5559  }
  5560  
  5561  func (s *DockerSuite) TestBuildNetContainer(c *check.C) {
  5562  	testRequires(c, DaemonIsLinux)
  5563  
  5564  	id, _ := dockerCmd(c, "run", "--hostname", "foobar", "-d", "busybox", "nc", "-ll", "-p", "1234", "-e", "hostname")
  5565  
  5566  	name := "testbuildnetcontainer"
  5567  	buildImageSuccessfully(c, name, cli.WithFlags("--network=container:"+strings.TrimSpace(id)),
  5568  		build.WithDockerfile(`
  5569    FROM busybox
  5570    RUN nc localhost 1234 > /otherhost
  5571    `))
  5572  
  5573  	host, _ := dockerCmd(c, "run", "testbuildnetcontainer", "cat", "/otherhost")
  5574  	c.Assert(strings.TrimSpace(host), check.Equals, "foobar")
  5575  }
  5576  
  5577  func (s *DockerSuite) TestBuildWithExtraHost(c *check.C) {
  5578  	testRequires(c, DaemonIsLinux)
  5579  
  5580  	name := "testbuildwithextrahost"
  5581  	buildImageSuccessfully(c, name,
  5582  		cli.WithFlags(
  5583  			"--add-host", "foo:127.0.0.1",
  5584  			"--add-host", "bar:127.0.0.1",
  5585  		),
  5586  		build.WithDockerfile(`
  5587    FROM busybox
  5588    RUN ping -c 1 foo
  5589    RUN ping -c 1 bar
  5590    `))
  5591  }
  5592  
  5593  func (s *DockerSuite) TestBuildWithExtraHostInvalidFormat(c *check.C) {
  5594  	testRequires(c, DaemonIsLinux)
  5595  	dockerfile := `
  5596  		FROM busybox
  5597  		RUN ping -c 1 foo`
  5598  
  5599  	testCases := []struct {
  5600  		testName   string
  5601  		dockerfile string
  5602  		buildFlag  string
  5603  	}{
  5604  		{"extra_host_missing_ip", dockerfile, "--add-host=foo"},
  5605  		{"extra_host_missing_ip_with_delimiter", dockerfile, "--add-host=foo:"},
  5606  		{"extra_host_missing_hostname", dockerfile, "--add-host=:127.0.0.1"},
  5607  		{"extra_host_invalid_ipv4", dockerfile, "--add-host=foo:101.10.2"},
  5608  		{"extra_host_invalid_ipv6", dockerfile, "--add-host=foo:2001::1::3F"},
  5609  	}
  5610  
  5611  	for _, tc := range testCases {
  5612  		result := buildImage(tc.testName, cli.WithFlags(tc.buildFlag), build.WithDockerfile(tc.dockerfile))
  5613  		result.Assert(c, icmd.Expected{
  5614  			ExitCode: 125,
  5615  		})
  5616  	}
  5617  
  5618  }
  5619  
  5620  func (s *DockerSuite) TestBuildContChar(c *check.C) {
  5621  	name := "testbuildcontchar"
  5622  
  5623  	buildImage(name, build.WithDockerfile(`FROM busybox\`)).Assert(c, icmd.Expected{
  5624  		Out: "Step 1/1 : FROM busybox",
  5625  	})
  5626  
  5627  	result := buildImage(name, build.WithDockerfile(`FROM busybox
  5628  		 RUN echo hi \`))
  5629  	result.Assert(c, icmd.Success)
  5630  	c.Assert(result.Combined(), checker.Contains, "Step 1/2 : FROM busybox")
  5631  	c.Assert(result.Combined(), checker.Contains, "Step 2/2 : RUN echo hi\n")
  5632  
  5633  	result = buildImage(name, build.WithDockerfile(`FROM busybox
  5634  		 RUN echo hi \\`))
  5635  	result.Assert(c, icmd.Success)
  5636  	c.Assert(result.Combined(), checker.Contains, "Step 1/2 : FROM busybox")
  5637  	c.Assert(result.Combined(), checker.Contains, "Step 2/2 : RUN echo hi \\\n")
  5638  
  5639  	result = buildImage(name, build.WithDockerfile(`FROM busybox
  5640  		 RUN echo hi \\\`))
  5641  	result.Assert(c, icmd.Success)
  5642  	c.Assert(result.Combined(), checker.Contains, "Step 1/2 : FROM busybox")
  5643  	c.Assert(result.Combined(), checker.Contains, "Step 2/2 : RUN echo hi \\\\\n")
  5644  }
  5645  
  5646  func (s *DockerSuite) TestBuildMultiStageCopyFromSyntax(c *check.C) {
  5647  	dockerfile := `
  5648  		FROM busybox AS first
  5649  		COPY foo bar
  5650  
  5651  		FROM busybox
  5652  		%s
  5653  		COPY baz baz
  5654  		RUN echo mno > baz/cc
  5655  
  5656  		FROM busybox
  5657  		COPY bar /
  5658  		COPY --from=1 baz sub/
  5659  		COPY --from=0 bar baz
  5660  		COPY --from=first bar bay`
  5661  
  5662  	ctx := fakecontext.New(c, "",
  5663  		fakecontext.WithDockerfile(fmt.Sprintf(dockerfile, "")),
  5664  		fakecontext.WithFiles(map[string]string{
  5665  			"foo":    "abc",
  5666  			"bar":    "def",
  5667  			"baz/aa": "ghi",
  5668  			"baz/bb": "jkl",
  5669  		}))
  5670  	defer ctx.Close()
  5671  
  5672  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5673  
  5674  	cli.DockerCmd(c, "run", "build1", "cat", "bar").Assert(c, icmd.Expected{Out: "def"})
  5675  	cli.DockerCmd(c, "run", "build1", "cat", "sub/aa").Assert(c, icmd.Expected{Out: "ghi"})
  5676  	cli.DockerCmd(c, "run", "build1", "cat", "sub/cc").Assert(c, icmd.Expected{Out: "mno"})
  5677  	cli.DockerCmd(c, "run", "build1", "cat", "baz").Assert(c, icmd.Expected{Out: "abc"})
  5678  	cli.DockerCmd(c, "run", "build1", "cat", "bay").Assert(c, icmd.Expected{Out: "abc"})
  5679  
  5680  	result := cli.BuildCmd(c, "build2", build.WithExternalBuildContext(ctx))
  5681  
  5682  	// all commands should be cached
  5683  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 7)
  5684  	c.Assert(getIDByName(c, "build1"), checker.Equals, getIDByName(c, "build2"))
  5685  
  5686  	err := ioutil.WriteFile(filepath.Join(ctx.Dir, "Dockerfile"), []byte(fmt.Sprintf(dockerfile, "COPY baz/aa foo")), 0644)
  5687  	c.Assert(err, checker.IsNil)
  5688  
  5689  	// changing file in parent block should not affect last block
  5690  	result = cli.BuildCmd(c, "build3", build.WithExternalBuildContext(ctx))
  5691  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 5)
  5692  
  5693  	err = ioutil.WriteFile(filepath.Join(ctx.Dir, "foo"), []byte("pqr"), 0644)
  5694  	c.Assert(err, checker.IsNil)
  5695  
  5696  	// changing file in parent block should affect both first and last block
  5697  	result = cli.BuildCmd(c, "build4", build.WithExternalBuildContext(ctx))
  5698  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 5)
  5699  
  5700  	cli.DockerCmd(c, "run", "build4", "cat", "bay").Assert(c, icmd.Expected{Out: "pqr"})
  5701  	cli.DockerCmd(c, "run", "build4", "cat", "baz").Assert(c, icmd.Expected{Out: "pqr"})
  5702  }
  5703  
  5704  func (s *DockerSuite) TestBuildMultiStageCopyFromErrors(c *check.C) {
  5705  	testCases := []struct {
  5706  		dockerfile    string
  5707  		expectedError string
  5708  	}{
  5709  		{
  5710  			dockerfile: `
  5711  		FROM busybox
  5712  		COPY --from=foo foo bar`,
  5713  			expectedError: "invalid from flag value foo",
  5714  		},
  5715  		{
  5716  			dockerfile: `
  5717  		FROM busybox
  5718  		COPY --from=0 foo bar`,
  5719  			expectedError: "invalid from flag value 0: refers to current build stage",
  5720  		},
  5721  		{
  5722  			dockerfile: `
  5723  		FROM busybox AS foo
  5724  		COPY --from=bar foo bar`,
  5725  			expectedError: "invalid from flag value bar",
  5726  		},
  5727  		{
  5728  			dockerfile: `
  5729  		FROM busybox AS 1
  5730  		COPY --from=1 foo bar`,
  5731  			expectedError: "invalid name for build stage",
  5732  		},
  5733  	}
  5734  
  5735  	for _, tc := range testCases {
  5736  		ctx := fakecontext.New(c, "",
  5737  			fakecontext.WithDockerfile(tc.dockerfile),
  5738  			fakecontext.WithFiles(map[string]string{
  5739  				"foo": "abc",
  5740  			}))
  5741  
  5742  		cli.Docker(cli.Build("build1"), build.WithExternalBuildContext(ctx)).Assert(c, icmd.Expected{
  5743  			ExitCode: 1,
  5744  			Err:      tc.expectedError,
  5745  		})
  5746  
  5747  		ctx.Close()
  5748  	}
  5749  }
  5750  
  5751  func (s *DockerSuite) TestBuildMultiStageMultipleBuilds(c *check.C) {
  5752  	dockerfile := `
  5753  		FROM busybox
  5754  		COPY foo bar`
  5755  	ctx := fakecontext.New(c, "",
  5756  		fakecontext.WithDockerfile(dockerfile),
  5757  		fakecontext.WithFiles(map[string]string{
  5758  			"foo": "abc",
  5759  		}))
  5760  	defer ctx.Close()
  5761  
  5762  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5763  
  5764  	dockerfile = `
  5765  		FROM build1:latest AS foo
  5766      FROM busybox
  5767  		COPY --from=foo bar /
  5768  		COPY foo /`
  5769  	ctx = fakecontext.New(c, "",
  5770  		fakecontext.WithDockerfile(dockerfile),
  5771  		fakecontext.WithFiles(map[string]string{
  5772  			"foo": "def",
  5773  		}))
  5774  	defer ctx.Close()
  5775  
  5776  	cli.BuildCmd(c, "build2", build.WithExternalBuildContext(ctx))
  5777  
  5778  	out := cli.DockerCmd(c, "run", "build2", "cat", "bar").Combined()
  5779  	c.Assert(strings.TrimSpace(out), check.Equals, "abc")
  5780  	out = cli.DockerCmd(c, "run", "build2", "cat", "foo").Combined()
  5781  	c.Assert(strings.TrimSpace(out), check.Equals, "def")
  5782  }
  5783  
  5784  func (s *DockerSuite) TestBuildMultiStageImplicitFrom(c *check.C) {
  5785  	dockerfile := `
  5786  		FROM busybox
  5787  		COPY --from=busybox /etc/passwd /mypasswd
  5788  		RUN cmp /etc/passwd /mypasswd`
  5789  
  5790  	if DaemonIsWindows() {
  5791  		dockerfile = `
  5792  			FROM busybox
  5793  			COPY --from=busybox License.txt foo`
  5794  	}
  5795  
  5796  	ctx := fakecontext.New(c, "",
  5797  		fakecontext.WithDockerfile(dockerfile),
  5798  	)
  5799  	defer ctx.Close()
  5800  
  5801  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5802  
  5803  	if DaemonIsWindows() {
  5804  		out := cli.DockerCmd(c, "run", "build1", "cat", "License.txt").Combined()
  5805  		c.Assert(len(out), checker.GreaterThan, 10)
  5806  		out2 := cli.DockerCmd(c, "run", "build1", "cat", "foo").Combined()
  5807  		c.Assert(out, check.Equals, out2)
  5808  	}
  5809  }
  5810  
  5811  func (s *DockerRegistrySuite) TestBuildMultiStageImplicitPull(c *check.C) {
  5812  	repoName := fmt.Sprintf("%v/dockercli/testf", privateRegistryURL)
  5813  
  5814  	dockerfile := `
  5815  		FROM busybox
  5816  		COPY foo bar`
  5817  	ctx := fakecontext.New(c, "",
  5818  		fakecontext.WithDockerfile(dockerfile),
  5819  		fakecontext.WithFiles(map[string]string{
  5820  			"foo": "abc",
  5821  		}))
  5822  	defer ctx.Close()
  5823  
  5824  	cli.BuildCmd(c, repoName, build.WithExternalBuildContext(ctx))
  5825  
  5826  	cli.DockerCmd(c, "push", repoName)
  5827  	cli.DockerCmd(c, "rmi", repoName)
  5828  
  5829  	dockerfile = `
  5830  		FROM busybox
  5831  		COPY --from=%s bar baz`
  5832  
  5833  	ctx = fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(dockerfile, repoName)))
  5834  	defer ctx.Close()
  5835  
  5836  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5837  
  5838  	cli.Docker(cli.Args("run", "build1", "cat", "baz")).Assert(c, icmd.Expected{Out: "abc"})
  5839  }
  5840  
  5841  func (s *DockerSuite) TestBuildMultiStageNameVariants(c *check.C) {
  5842  	dockerfile := `
  5843  		FROM busybox as foo
  5844  		COPY foo /
  5845  		FROM foo as foo1
  5846  		RUN echo 1 >> foo
  5847  		FROM foo as foO2
  5848  		RUN echo 2 >> foo
  5849  		FROM foo
  5850  		COPY --from=foo1 foo f1
  5851  		COPY --from=FOo2 foo f2
  5852  		` // foo2 case also tests that names are case insensitive
  5853  	ctx := fakecontext.New(c, "",
  5854  		fakecontext.WithDockerfile(dockerfile),
  5855  		fakecontext.WithFiles(map[string]string{
  5856  			"foo": "bar",
  5857  		}))
  5858  	defer ctx.Close()
  5859  
  5860  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5861  	cli.Docker(cli.Args("run", "build1", "cat", "foo")).Assert(c, icmd.Expected{Out: "bar"})
  5862  	cli.Docker(cli.Args("run", "build1", "cat", "f1")).Assert(c, icmd.Expected{Out: "bar1"})
  5863  	cli.Docker(cli.Args("run", "build1", "cat", "f2")).Assert(c, icmd.Expected{Out: "bar2"})
  5864  }
  5865  
  5866  func (s *DockerSuite) TestBuildMultiStageMultipleBuildsWindows(c *check.C) {
  5867  	testRequires(c, DaemonIsWindows)
  5868  	dockerfile := `
  5869  		FROM ` + testEnv.PlatformDefaults.BaseImage + `
  5870  		COPY foo c:\\bar`
  5871  	ctx := fakecontext.New(c, "",
  5872  		fakecontext.WithDockerfile(dockerfile),
  5873  		fakecontext.WithFiles(map[string]string{
  5874  			"foo": "abc",
  5875  		}))
  5876  	defer ctx.Close()
  5877  
  5878  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5879  
  5880  	dockerfile = `
  5881  		FROM build1:latest
  5882      	FROM ` + testEnv.PlatformDefaults.BaseImage + `
  5883  		COPY --from=0 c:\\bar /
  5884  		COPY foo /`
  5885  	ctx = fakecontext.New(c, "",
  5886  		fakecontext.WithDockerfile(dockerfile),
  5887  		fakecontext.WithFiles(map[string]string{
  5888  			"foo": "def",
  5889  		}))
  5890  	defer ctx.Close()
  5891  
  5892  	cli.BuildCmd(c, "build2", build.WithExternalBuildContext(ctx))
  5893  
  5894  	out := cli.DockerCmd(c, "run", "build2", "cmd.exe", "/s", "/c", "type", "c:\\bar").Combined()
  5895  	c.Assert(strings.TrimSpace(out), check.Equals, "abc")
  5896  	out = cli.DockerCmd(c, "run", "build2", "cmd.exe", "/s", "/c", "type", "c:\\foo").Combined()
  5897  	c.Assert(strings.TrimSpace(out), check.Equals, "def")
  5898  }
  5899  
  5900  func (s *DockerSuite) TestBuildCopyFromForbidWindowsSystemPaths(c *check.C) {
  5901  	testRequires(c, DaemonIsWindows)
  5902  	dockerfile := `
  5903  		FROM ` + testEnv.PlatformDefaults.BaseImage + `
  5904  		FROM ` + testEnv.PlatformDefaults.BaseImage + `
  5905  		COPY --from=0 %s c:\\oscopy
  5906  		`
  5907  	exp := icmd.Expected{
  5908  		ExitCode: 1,
  5909  		Err:      "copy from c:\\ or c:\\windows is not allowed on windows",
  5910  	}
  5911  	buildImage("testforbidsystempaths1", build.WithDockerfile(fmt.Sprintf(dockerfile, "c:\\\\"))).Assert(c, exp)
  5912  	buildImage("testforbidsystempaths2", build.WithDockerfile(fmt.Sprintf(dockerfile, "C:\\\\"))).Assert(c, exp)
  5913  	buildImage("testforbidsystempaths3", build.WithDockerfile(fmt.Sprintf(dockerfile, "c:\\\\windows"))).Assert(c, exp)
  5914  	buildImage("testforbidsystempaths4", build.WithDockerfile(fmt.Sprintf(dockerfile, "c:\\\\wInDows"))).Assert(c, exp)
  5915  }
  5916  
  5917  func (s *DockerSuite) TestBuildCopyFromForbidWindowsRelativePaths(c *check.C) {
  5918  	testRequires(c, DaemonIsWindows)
  5919  	dockerfile := `
  5920  		FROM ` + testEnv.PlatformDefaults.BaseImage + `
  5921  		FROM ` + testEnv.PlatformDefaults.BaseImage + `
  5922  		COPY --from=0 %s c:\\oscopy
  5923  		`
  5924  	exp := icmd.Expected{
  5925  		ExitCode: 1,
  5926  		Err:      "copy from c:\\ or c:\\windows is not allowed on windows",
  5927  	}
  5928  	buildImage("testforbidsystempaths1", build.WithDockerfile(fmt.Sprintf(dockerfile, "c:"))).Assert(c, exp)
  5929  	buildImage("testforbidsystempaths2", build.WithDockerfile(fmt.Sprintf(dockerfile, "."))).Assert(c, exp)
  5930  	buildImage("testforbidsystempaths3", build.WithDockerfile(fmt.Sprintf(dockerfile, "..\\\\"))).Assert(c, exp)
  5931  	buildImage("testforbidsystempaths4", build.WithDockerfile(fmt.Sprintf(dockerfile, ".\\\\windows"))).Assert(c, exp)
  5932  	buildImage("testforbidsystempaths5", build.WithDockerfile(fmt.Sprintf(dockerfile, "\\\\windows"))).Assert(c, exp)
  5933  }
  5934  
  5935  func (s *DockerSuite) TestBuildCopyFromWindowsIsCaseInsensitive(c *check.C) {
  5936  	testRequires(c, DaemonIsWindows)
  5937  	dockerfile := `
  5938  		FROM ` + testEnv.PlatformDefaults.BaseImage + `
  5939  		COPY foo /
  5940  		FROM ` + testEnv.PlatformDefaults.BaseImage + `
  5941  		COPY --from=0 c:\\fOo c:\\copied
  5942  		RUN type c:\\copied
  5943  		`
  5944  	cli.Docker(cli.Build("copyfrom-windows-insensitive"), build.WithBuildContext(c,
  5945  		build.WithFile("Dockerfile", dockerfile),
  5946  		build.WithFile("foo", "hello world"),
  5947  	)).Assert(c, icmd.Expected{
  5948  		ExitCode: 0,
  5949  		Out:      "hello world",
  5950  	})
  5951  }
  5952  
  5953  // #33176
  5954  func (s *DockerSuite) TestBuildMulitStageResetScratch(c *check.C) {
  5955  	testRequires(c, DaemonIsLinux)
  5956  
  5957  	dockerfile := `
  5958  		FROM busybox
  5959  		WORKDIR /foo/bar
  5960  		FROM scratch
  5961  		ENV FOO=bar
  5962  		`
  5963  	ctx := fakecontext.New(c, "",
  5964  		fakecontext.WithDockerfile(dockerfile),
  5965  	)
  5966  	defer ctx.Close()
  5967  
  5968  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx))
  5969  
  5970  	res := cli.InspectCmd(c, "build1", cli.Format(".Config.WorkingDir")).Combined()
  5971  	c.Assert(strings.TrimSpace(res), checker.Equals, "")
  5972  }
  5973  
  5974  func (s *DockerSuite) TestBuildIntermediateTarget(c *check.C) {
  5975  	//todo: need to be removed after 18.06 release
  5976  	if strings.Contains(testEnv.DaemonInfo.ServerVersion, "18.05.0") {
  5977  		c.Skip(fmt.Sprintf("Bug fixed in 18.06 or higher.Skipping it for %s", testEnv.DaemonInfo.ServerVersion))
  5978  	}
  5979  	dockerfile := `
  5980  		FROM busybox AS build-env
  5981  		CMD ["/dev"]
  5982  		FROM busybox
  5983  		CMD ["/dist"]
  5984  		`
  5985  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
  5986  	defer ctx.Close()
  5987  
  5988  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx),
  5989  		cli.WithFlags("--target", "build-env"))
  5990  
  5991  	res := cli.InspectCmd(c, "build1", cli.Format("json .Config.Cmd")).Combined()
  5992  	c.Assert(strings.TrimSpace(res), checker.Equals, `["/dev"]`)
  5993  
  5994  	// Stage name is case-insensitive by design
  5995  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx),
  5996  		cli.WithFlags("--target", "BUIld-EnV"))
  5997  
  5998  	res = cli.InspectCmd(c, "build1", cli.Format("json .Config.Cmd")).Combined()
  5999  	c.Assert(strings.TrimSpace(res), checker.Equals, `["/dev"]`)
  6000  
  6001  	result := cli.Docker(cli.Build("build1"), build.WithExternalBuildContext(ctx),
  6002  		cli.WithFlags("--target", "nosuchtarget"))
  6003  	result.Assert(c, icmd.Expected{
  6004  		ExitCode: 1,
  6005  		Err:      "failed to reach build target",
  6006  	})
  6007  }
  6008  
  6009  // TestBuildOpaqueDirectory tests that a build succeeds which
  6010  // creates opaque directories.
  6011  // See https://github.com/docker/docker/issues/25244
  6012  func (s *DockerSuite) TestBuildOpaqueDirectory(c *check.C) {
  6013  	testRequires(c, DaemonIsLinux)
  6014  	dockerFile := `
  6015  		FROM busybox
  6016  		RUN mkdir /dir1 && touch /dir1/f1
  6017  		RUN rm -rf /dir1 && mkdir /dir1 && touch /dir1/f2
  6018  		RUN touch /dir1/f3
  6019  		RUN [ -f /dir1/f2 ]
  6020  		`
  6021  	// Test that build succeeds, last command fails if opaque directory
  6022  	// was not handled correctly
  6023  	buildImageSuccessfully(c, "testopaquedirectory", build.WithDockerfile(dockerFile))
  6024  }
  6025  
  6026  // Windows test for USER in dockerfile
  6027  func (s *DockerSuite) TestBuildWindowsUser(c *check.C) {
  6028  	testRequires(c, DaemonIsWindows)
  6029  	name := "testbuildwindowsuser"
  6030  	buildImage(name, build.WithDockerfile(`FROM `+testEnv.PlatformDefaults.BaseImage+`
  6031  		RUN net user user /add
  6032  		USER user
  6033  		RUN set username
  6034  		`)).Assert(c, icmd.Expected{
  6035  		Out: "USERNAME=user",
  6036  	})
  6037  }
  6038  
  6039  // Verifies if COPY file . when WORKDIR is set to a non-existing directory,
  6040  // the directory is created and the file is copied into the directory,
  6041  // as opposed to the file being copied as a file with the name of the
  6042  // directory. Fix for 27545 (found on Windows, but regression good for Linux too).
  6043  // Note 27545 was reverted in 28505, but a new fix was added subsequently in 28514.
  6044  func (s *DockerSuite) TestBuildCopyFileDotWithWorkdir(c *check.C) {
  6045  	name := "testbuildcopyfiledotwithworkdir"
  6046  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  6047  		build.WithFile("Dockerfile", `FROM busybox
  6048  WORKDIR /foo
  6049  COPY file .
  6050  RUN ["cat", "/foo/file"]
  6051  `),
  6052  		build.WithFile("file", "content"),
  6053  	))
  6054  }
  6055  
  6056  // Case-insensitive environment variables on Windows
  6057  func (s *DockerSuite) TestBuildWindowsEnvCaseInsensitive(c *check.C) {
  6058  	testRequires(c, DaemonIsWindows)
  6059  	name := "testbuildwindowsenvcaseinsensitive"
  6060  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  6061  		FROM `+testEnv.PlatformDefaults.BaseImage+`
  6062  		ENV FOO=bar foo=baz
  6063    `))
  6064  	res := inspectFieldJSON(c, name, "Config.Env")
  6065  	if res != `["foo=baz"]` { // Should not have FOO=bar in it - takes the last one processed. And only one entry as deduped.
  6066  		c.Fatalf("Case insensitive environment variables on Windows failed. Got %s", res)
  6067  	}
  6068  }
  6069  
  6070  // Test case for 29667
  6071  func (s *DockerSuite) TestBuildWorkdirImageCmd(c *check.C) {
  6072  	image := "testworkdirimagecmd"
  6073  	buildImageSuccessfully(c, image, build.WithDockerfile(`
  6074  FROM busybox
  6075  WORKDIR /foo/bar
  6076  `))
  6077  	out, _ := dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", image)
  6078  	c.Assert(strings.TrimSpace(out), checker.Equals, `["sh"]`)
  6079  
  6080  	image = "testworkdirlabelimagecmd"
  6081  	buildImageSuccessfully(c, image, build.WithDockerfile(`
  6082  FROM busybox
  6083  WORKDIR /foo/bar
  6084  LABEL a=b
  6085  `))
  6086  
  6087  	out, _ = dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", image)
  6088  	c.Assert(strings.TrimSpace(out), checker.Equals, `["sh"]`)
  6089  }
  6090  
  6091  // Test case for 28902/28909
  6092  func (s *DockerSuite) TestBuildWorkdirCmd(c *check.C) {
  6093  	testRequires(c, DaemonIsLinux)
  6094  	name := "testbuildworkdircmd"
  6095  	dockerFile := `
  6096                  FROM busybox
  6097                  WORKDIR /
  6098                  `
  6099  	buildImageSuccessfully(c, name, build.WithDockerfile(dockerFile))
  6100  	result := buildImage(name, build.WithDockerfile(dockerFile))
  6101  	result.Assert(c, icmd.Success)
  6102  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 1)
  6103  }
  6104  
  6105  // FIXME(vdemeester) should be a unit test
  6106  func (s *DockerSuite) TestBuildLineErrorOnBuild(c *check.C) {
  6107  	name := "test_build_line_error_onbuild"
  6108  	buildImage(name, build.WithDockerfile(`FROM busybox
  6109    ONBUILD
  6110    `)).Assert(c, icmd.Expected{
  6111  		ExitCode: 1,
  6112  		Err:      "Dockerfile parse error line 2: ONBUILD requires at least one argument",
  6113  	})
  6114  }
  6115  
  6116  // FIXME(vdemeester) should be a unit test
  6117  func (s *DockerSuite) TestBuildLineErrorUnknownInstruction(c *check.C) {
  6118  	name := "test_build_line_error_unknown_instruction"
  6119  	cli.Docker(cli.Build(name), build.WithDockerfile(`FROM busybox
  6120    RUN echo hello world
  6121    NOINSTRUCTION echo ba
  6122    RUN echo hello
  6123    ERROR
  6124    `)).Assert(c, icmd.Expected{
  6125  		ExitCode: 1,
  6126  		Err:      "Dockerfile parse error line 3: unknown instruction: NOINSTRUCTION",
  6127  	})
  6128  }
  6129  
  6130  // FIXME(vdemeester) should be a unit test
  6131  func (s *DockerSuite) TestBuildLineErrorWithEmptyLines(c *check.C) {
  6132  	name := "test_build_line_error_with_empty_lines"
  6133  	cli.Docker(cli.Build(name), build.WithDockerfile(`
  6134    FROM busybox
  6135  
  6136    RUN echo hello world
  6137  
  6138    NOINSTRUCTION echo ba
  6139  
  6140    CMD ["/bin/init"]
  6141    `)).Assert(c, icmd.Expected{
  6142  		ExitCode: 1,
  6143  		Err:      "Dockerfile parse error line 6: unknown instruction: NOINSTRUCTION",
  6144  	})
  6145  }
  6146  
  6147  // FIXME(vdemeester) should be a unit test
  6148  func (s *DockerSuite) TestBuildLineErrorWithComments(c *check.C) {
  6149  	name := "test_build_line_error_with_comments"
  6150  	cli.Docker(cli.Build(name), build.WithDockerfile(`FROM busybox
  6151    # This will print hello world
  6152    # and then ba
  6153    RUN echo hello world
  6154    NOINSTRUCTION echo ba
  6155    `)).Assert(c, icmd.Expected{
  6156  		ExitCode: 1,
  6157  		Err:      "Dockerfile parse error line 5: unknown instruction: NOINSTRUCTION",
  6158  	})
  6159  }
  6160  
  6161  // #31957
  6162  func (s *DockerSuite) TestBuildSetCommandWithDefinedShell(c *check.C) {
  6163  	buildImageSuccessfully(c, "build1", build.WithDockerfile(`
  6164  FROM busybox
  6165  SHELL ["/bin/sh", "-c"]
  6166  `))
  6167  	buildImageSuccessfully(c, "build2", build.WithDockerfile(`
  6168  FROM build1
  6169  CMD echo foo
  6170  `))
  6171  
  6172  	out, _ := dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", "build2")
  6173  	expected := `["/bin/sh","-c","echo foo"]`
  6174  	if testEnv.OSType == "windows" {
  6175  		expected = `["/bin/sh -c echo foo"]`
  6176  	}
  6177  	c.Assert(strings.TrimSpace(out), checker.Equals, expected)
  6178  }
  6179  
  6180  // FIXME(vdemeester) should migrate to docker/cli tests
  6181  func (s *DockerSuite) TestBuildIidFile(c *check.C) {
  6182  	tmpDir, err := ioutil.TempDir("", "TestBuildIidFile")
  6183  	if err != nil {
  6184  		c.Fatal(err)
  6185  	}
  6186  	defer os.RemoveAll(tmpDir)
  6187  	tmpIidFile := filepath.Join(tmpDir, "iid")
  6188  
  6189  	name := "testbuildiidfile"
  6190  	// Use a Dockerfile with multiple stages to ensure we get the last one
  6191  	cli.BuildCmd(c, name,
  6192  		build.WithDockerfile(`FROM `+minimalBaseImage()+` AS stage1
  6193  ENV FOO FOO
  6194  FROM `+minimalBaseImage()+`
  6195  ENV BAR BAZ`),
  6196  		cli.WithFlags("--iidfile", tmpIidFile))
  6197  
  6198  	id, err := ioutil.ReadFile(tmpIidFile)
  6199  	c.Assert(err, check.IsNil)
  6200  	d, err := digest.Parse(string(id))
  6201  	c.Assert(err, check.IsNil)
  6202  	c.Assert(d.String(), checker.Equals, getIDByName(c, name))
  6203  }
  6204  
  6205  // FIXME(vdemeester) should migrate to docker/cli tests
  6206  func (s *DockerSuite) TestBuildIidFileCleanupOnFail(c *check.C) {
  6207  	tmpDir, err := ioutil.TempDir("", "TestBuildIidFileCleanupOnFail")
  6208  	if err != nil {
  6209  		c.Fatal(err)
  6210  	}
  6211  	defer os.RemoveAll(tmpDir)
  6212  	tmpIidFile := filepath.Join(tmpDir, "iid")
  6213  
  6214  	err = ioutil.WriteFile(tmpIidFile, []byte("Dummy"), 0666)
  6215  	c.Assert(err, check.IsNil)
  6216  
  6217  	cli.Docker(cli.Build("testbuildiidfilecleanuponfail"),
  6218  		build.WithDockerfile(`FROM `+minimalBaseImage()+`
  6219  	RUN /non/existing/command`),
  6220  		cli.WithFlags("--iidfile", tmpIidFile)).Assert(c, icmd.Expected{
  6221  		ExitCode: 1,
  6222  	})
  6223  	_, err = os.Stat(tmpIidFile)
  6224  	c.Assert(err, check.NotNil)
  6225  	c.Assert(os.IsNotExist(err), check.Equals, true)
  6226  }