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