github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/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/builder/dockerfile/command"
    20  	"github.com/docker/docker/integration-cli/checker"
    21  	"github.com/docker/docker/integration-cli/cli"
    22  	"github.com/docker/docker/integration-cli/cli/build"
    23  	"github.com/docker/docker/internal/test/fakecontext"
    24  	"github.com/docker/docker/internal/test/fakegit"
    25  	"github.com/docker/docker/internal/test/fakestorage"
    26  	"github.com/docker/docker/internal/testutil"
    27  	"github.com/docker/docker/pkg/archive"
    28  	"github.com/go-check/check"
    29  	"github.com/gotestyourself/gotestyourself/icmd"
    30  	digest "github.com/opencontainers/go-digest"
    31  )
    32  
    33  func (s *DockerSuite) TestBuildJSONEmptyRun(c *check.C) {
    34  	cli.BuildCmd(c, "testbuildjsonemptyrun", build.WithDockerfile(`
    35      FROM busybox
    36      RUN []
    37      `))
    38  }
    39  
    40  func (s *DockerSuite) TestBuildShCmdJSONEntrypoint(c *check.C) {
    41  	name := "testbuildshcmdjsonentrypoint"
    42  	expected := "/bin/sh -c echo test"
    43  	if testEnv.OSType == "windows" {
    44  		expected = "cmd /S /C echo test"
    45  	}
    46  
    47  	buildImageSuccessfully(c, name, build.WithDockerfile(`
    48      FROM busybox
    49      ENTRYPOINT ["echo"]
    50      CMD echo test
    51      `))
    52  	out, _ := dockerCmd(c, "run", "--rm", name)
    53  
    54  	if strings.TrimSpace(out) != expected {
    55  		c.Fatalf("CMD did not contain %q : %q", expected, out)
    56  	}
    57  }
    58  
    59  func (s *DockerSuite) TestBuildEnvironmentReplacementUser(c *check.C) {
    60  	// Windows does not support FROM scratch or the USER command
    61  	testRequires(c, DaemonIsLinux)
    62  	name := "testbuildenvironmentreplacement"
    63  
    64  	buildImageSuccessfully(c, name, build.WithDockerfile(`
    65    FROM scratch
    66    ENV user foo
    67    USER ${user}
    68    `))
    69  	res := inspectFieldJSON(c, name, "Config.User")
    70  
    71  	if res != `"foo"` {
    72  		c.Fatal("User foo from environment not in Config.User on image")
    73  	}
    74  }
    75  
    76  func (s *DockerSuite) TestBuildEnvironmentReplacementVolume(c *check.C) {
    77  	name := "testbuildenvironmentreplacement"
    78  
    79  	var volumePath string
    80  
    81  	if testEnv.OSType == "windows" {
    82  		volumePath = "c:/quux"
    83  	} else {
    84  		volumePath = "/quux"
    85  	}
    86  
    87  	buildImageSuccessfully(c, name, build.WithDockerfile(`
    88    FROM `+minimalBaseImage()+`
    89    ENV volume `+volumePath+`
    90    VOLUME ${volume}
    91    `))
    92  
    93  	var volumes map[string]interface{}
    94  	inspectFieldAndUnmarshall(c, name, "Config.Volumes", &volumes)
    95  	if _, ok := volumes[volumePath]; !ok {
    96  		c.Fatal("Volume " + volumePath + " from environment not in Config.Volumes on image")
    97  	}
    98  
    99  }
   100  
   101  func (s *DockerSuite) TestBuildEnvironmentReplacementExpose(c *check.C) {
   102  	// Windows does not support FROM scratch or the EXPOSE command
   103  	testRequires(c, DaemonIsLinux)
   104  	name := "testbuildenvironmentreplacement"
   105  
   106  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   107    FROM scratch
   108    ENV port 80
   109    EXPOSE ${port}
   110    ENV ports "  99   100 "
   111    EXPOSE ${ports}
   112    `))
   113  
   114  	var exposedPorts map[string]interface{}
   115  	inspectFieldAndUnmarshall(c, name, "Config.ExposedPorts", &exposedPorts)
   116  	exp := []int{80, 99, 100}
   117  	for _, p := range exp {
   118  		tmp := fmt.Sprintf("%d/tcp", p)
   119  		if _, ok := exposedPorts[tmp]; !ok {
   120  			c.Fatalf("Exposed port %d from environment not in Config.ExposedPorts on image", p)
   121  		}
   122  	}
   123  
   124  }
   125  
   126  func (s *DockerSuite) TestBuildEnvironmentReplacementWorkdir(c *check.C) {
   127  	name := "testbuildenvironmentreplacement"
   128  
   129  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   130    FROM busybox
   131    ENV MYWORKDIR /work
   132    RUN mkdir ${MYWORKDIR}
   133    WORKDIR ${MYWORKDIR}
   134    `))
   135  	res := inspectFieldJSON(c, name, "Config.WorkingDir")
   136  
   137  	expected := `"/work"`
   138  	if testEnv.OSType == "windows" {
   139  		expected = `"C:\\work"`
   140  	}
   141  	if res != expected {
   142  		c.Fatalf("Workdir /workdir from environment not in Config.WorkingDir on image: %s", res)
   143  	}
   144  }
   145  
   146  func (s *DockerSuite) TestBuildEnvironmentReplacementAddCopy(c *check.C) {
   147  	name := "testbuildenvironmentreplacement"
   148  
   149  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
   150  		build.WithFile("Dockerfile", `
   151    FROM `+minimalBaseImage()+`
   152    ENV baz foo
   153    ENV quux bar
   154    ENV dot .
   155    ENV fee fff
   156    ENV gee ggg
   157  
   158    ADD ${baz} ${dot}
   159    COPY ${quux} ${dot}
   160    ADD ${zzz:-${fee}} ${dot}
   161    COPY ${zzz:-${gee}} ${dot}
   162    `),
   163  		build.WithFile("foo", "test1"),
   164  		build.WithFile("bar", "test2"),
   165  		build.WithFile("fff", "test3"),
   166  		build.WithFile("ggg", "test4"),
   167  	))
   168  }
   169  
   170  func (s *DockerSuite) TestBuildEnvironmentReplacementEnv(c *check.C) {
   171  	// ENV expansions work differently in Windows
   172  	testRequires(c, DaemonIsLinux)
   173  	name := "testbuildenvironmentreplacement"
   174  
   175  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   176    FROM busybox
   177    ENV foo zzz
   178    ENV bar ${foo}
   179    ENV abc1='$foo'
   180    ENV env1=$foo env2=${foo} env3="$foo" env4="${foo}"
   181    RUN [ "$abc1" = '$foo' ] && (echo "$abc1" | grep -q foo)
   182    ENV abc2="\$foo"
   183    RUN [ "$abc2" = '$foo' ] && (echo "$abc2" | grep -q foo)
   184    ENV abc3 '$foo'
   185    RUN [ "$abc3" = '$foo' ] && (echo "$abc3" | grep -q foo)
   186    ENV abc4 "\$foo"
   187    RUN [ "$abc4" = '$foo' ] && (echo "$abc4" | grep -q foo)
   188    ENV foo2="abc\def"
   189    RUN [ "$foo2" = 'abc\def' ]
   190    ENV foo3="abc\\def"
   191    RUN [ "$foo3" = 'abc\def' ]
   192    ENV foo4='abc\\def'
   193    RUN [ "$foo4" = 'abc\\def' ]
   194    ENV foo5='abc\def'
   195    RUN [ "$foo5" = 'abc\def' ]
   196    `))
   197  
   198  	envResult := []string{}
   199  	inspectFieldAndUnmarshall(c, name, "Config.Env", &envResult)
   200  	found := false
   201  	envCount := 0
   202  
   203  	for _, env := range envResult {
   204  		parts := strings.SplitN(env, "=", 2)
   205  		if parts[0] == "bar" {
   206  			found = true
   207  			if parts[1] != "zzz" {
   208  				c.Fatalf("Could not find replaced var for env `bar`: got %q instead of `zzz`", parts[1])
   209  			}
   210  		} else if strings.HasPrefix(parts[0], "env") {
   211  			envCount++
   212  			if parts[1] != "zzz" {
   213  				c.Fatalf("%s should be 'zzz' but instead its %q", parts[0], parts[1])
   214  			}
   215  		} else if strings.HasPrefix(parts[0], "env") {
   216  			envCount++
   217  			if parts[1] != "foo" {
   218  				c.Fatalf("%s should be 'foo' but instead its %q", parts[0], parts[1])
   219  			}
   220  		}
   221  	}
   222  
   223  	if !found {
   224  		c.Fatal("Never found the `bar` env variable")
   225  	}
   226  
   227  	if envCount != 4 {
   228  		c.Fatalf("Didn't find all env vars - only saw %d\n%s", envCount, envResult)
   229  	}
   230  
   231  }
   232  
   233  func (s *DockerSuite) TestBuildHandleEscapesInVolume(c *check.C) {
   234  	// The volume paths used in this test are invalid on Windows
   235  	testRequires(c, DaemonIsLinux)
   236  	name := "testbuildhandleescapes"
   237  
   238  	testCases := []struct {
   239  		volumeValue string
   240  		expected    string
   241  	}{
   242  		{
   243  			volumeValue: "${FOO}",
   244  			expected:    "bar",
   245  		},
   246  		{
   247  			volumeValue: `\${FOO}`,
   248  			expected:    "${FOO}",
   249  		},
   250  		// this test in particular provides *7* backslashes and expects 6 to come back.
   251  		// Like above, the first escape is swallowed and the rest are treated as
   252  		// literals, this one is just less obvious because of all the character noise.
   253  		{
   254  			volumeValue: `\\\\\\\${FOO}`,
   255  			expected:    `\\\${FOO}`,
   256  		},
   257  	}
   258  
   259  	for _, tc := range testCases {
   260  		buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`
   261    FROM scratch
   262    ENV FOO bar
   263    VOLUME %s
   264    `, tc.volumeValue)))
   265  
   266  		var result map[string]map[string]struct{}
   267  		inspectFieldAndUnmarshall(c, name, "Config.Volumes", &result)
   268  		if _, ok := result[tc.expected]; !ok {
   269  			c.Fatalf("Could not find volume %s set from env foo in volumes table, got %q", tc.expected, result)
   270  		}
   271  
   272  		// Remove the image for the next iteration
   273  		dockerCmd(c, "rmi", name)
   274  	}
   275  }
   276  
   277  func (s *DockerSuite) TestBuildOnBuildLowercase(c *check.C) {
   278  	name := "testbuildonbuildlowercase"
   279  	name2 := "testbuildonbuildlowercase2"
   280  
   281  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   282    FROM busybox
   283    onbuild run echo quux
   284    `))
   285  
   286  	result := buildImage(name2, build.WithDockerfile(fmt.Sprintf(`
   287    FROM %s
   288    `, name)))
   289  	result.Assert(c, icmd.Success)
   290  
   291  	if !strings.Contains(result.Combined(), "quux") {
   292  		c.Fatalf("Did not receive the expected echo text, got %s", result.Combined())
   293  	}
   294  
   295  	if strings.Contains(result.Combined(), "ONBUILD ONBUILD") {
   296  		c.Fatalf("Got an ONBUILD ONBUILD error with no error: got %s", result.Combined())
   297  	}
   298  
   299  }
   300  
   301  func (s *DockerSuite) TestBuildEnvEscapes(c *check.C) {
   302  	// ENV expansions work differently in Windows
   303  	testRequires(c, DaemonIsLinux)
   304  	name := "testbuildenvescapes"
   305  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   306      FROM busybox
   307      ENV TEST foo
   308      CMD echo \$
   309      `))
   310  
   311  	out, _ := dockerCmd(c, "run", "-t", name)
   312  	if strings.TrimSpace(out) != "$" {
   313  		c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
   314  	}
   315  
   316  }
   317  
   318  func (s *DockerSuite) TestBuildEnvOverwrite(c *check.C) {
   319  	// ENV expansions work differently in Windows
   320  	testRequires(c, DaemonIsLinux)
   321  	name := "testbuildenvoverwrite"
   322  	buildImageSuccessfully(c, name, build.WithDockerfile(`
   323      FROM busybox
   324      ENV TEST foo
   325      CMD echo ${TEST}
   326      `))
   327  
   328  	out, _ := dockerCmd(c, "run", "-e", "TEST=bar", "-t", name)
   329  	if strings.TrimSpace(out) != "bar" {
   330  		c.Fatalf("Env TEST was not overwritten with bar when foo was supplied to dockerfile: was %q", strings.TrimSpace(out))
   331  	}
   332  
   333  }
   334  
   335  // FIXME(vdemeester) why we disabled cache here ?
   336  func (s *DockerSuite) TestBuildOnBuildCmdEntrypointJSON(c *check.C) {
   337  	name1 := "onbuildcmd"
   338  	name2 := "onbuildgenerated"
   339  
   340  	cli.BuildCmd(c, name1, build.WithDockerfile(`
   341  FROM busybox
   342  ONBUILD CMD ["hello world"]
   343  ONBUILD ENTRYPOINT ["echo"]
   344  ONBUILD RUN ["true"]`))
   345  
   346  	cli.BuildCmd(c, name2, build.WithDockerfile(fmt.Sprintf(`FROM %s`, name1)))
   347  
   348  	result := cli.DockerCmd(c, "run", name2)
   349  	result.Assert(c, icmd.Expected{Out: "hello world"})
   350  }
   351  
   352  // FIXME(vdemeester) why we disabled cache here ?
   353  func (s *DockerSuite) TestBuildOnBuildEntrypointJSON(c *check.C) {
   354  	name1 := "onbuildcmd"
   355  	name2 := "onbuildgenerated"
   356  
   357  	buildImageSuccessfully(c, name1, build.WithDockerfile(`
   358  FROM busybox
   359  ONBUILD ENTRYPOINT ["echo"]`))
   360  
   361  	buildImageSuccessfully(c, name2, build.WithDockerfile(fmt.Sprintf("FROM %s\nCMD [\"hello world\"]\n", name1)))
   362  
   363  	out, _ := dockerCmd(c, "run", name2)
   364  	if !regexp.MustCompile(`(?m)^hello world`).MatchString(out) {
   365  		c.Fatal("got malformed output from onbuild", out)
   366  	}
   367  
   368  }
   369  
   370  func (s *DockerSuite) TestBuildCacheAdd(c *check.C) {
   371  	testRequires(c, DaemonIsLinux) // Windows doesn't have httpserver image yet
   372  	name := "testbuildtwoimageswithadd"
   373  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   374  		"robots.txt": "hello",
   375  		"index.html": "world",
   376  	}))
   377  	defer server.Close()
   378  
   379  	cli.BuildCmd(c, name, build.WithDockerfile(fmt.Sprintf(`FROM scratch
   380  		ADD %s/robots.txt /`, server.URL())))
   381  
   382  	result := cli.Docker(cli.Build(name), build.WithDockerfile(fmt.Sprintf(`FROM scratch
   383  		ADD %s/index.html /`, server.URL())))
   384  	result.Assert(c, icmd.Success)
   385  	if strings.Contains(result.Combined(), "Using cache") {
   386  		c.Fatal("2nd build used cache on ADD, it shouldn't")
   387  	}
   388  }
   389  
   390  func (s *DockerSuite) TestBuildLastModified(c *check.C) {
   391  	// Temporary fix for #30890. TODO @jhowardmsft figure out what
   392  	// has changed in the master busybox image.
   393  	testRequires(c, DaemonIsLinux)
   394  
   395  	name := "testbuildlastmodified"
   396  
   397  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   398  		"file": "hello",
   399  	}))
   400  	defer server.Close()
   401  
   402  	var out, out2 string
   403  	args := []string{"run", name, "ls", "-l", "--full-time", "/file"}
   404  
   405  	dFmt := `FROM busybox
   406  ADD %s/file /`
   407  	dockerfile := fmt.Sprintf(dFmt, server.URL())
   408  
   409  	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
   410  	out = cli.DockerCmd(c, args...).Combined()
   411  
   412  	// Build it again and make sure the mtime of the file didn't change.
   413  	// Wait a few seconds to make sure the time changed enough to notice
   414  	time.Sleep(2 * time.Second)
   415  
   416  	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
   417  	out2 = cli.DockerCmd(c, args...).Combined()
   418  
   419  	if out != out2 {
   420  		c.Fatalf("MTime changed:\nOrigin:%s\nNew:%s", out, out2)
   421  	}
   422  
   423  	// Now 'touch' the file and make sure the timestamp DID change this time
   424  	// Create a new fakeStorage instead of just using Add() to help windows
   425  	server = fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   426  		"file": "hello",
   427  	}))
   428  	defer server.Close()
   429  
   430  	dockerfile = fmt.Sprintf(dFmt, server.URL())
   431  	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
   432  	out2 = cli.DockerCmd(c, args...).Combined()
   433  
   434  	if out == out2 {
   435  		c.Fatalf("MTime didn't change:\nOrigin:%s\nNew:%s", out, out2)
   436  	}
   437  
   438  }
   439  
   440  // Regression for https://github.com/docker/docker/pull/27805
   441  // Makes sure that we don't use the cache if the contents of
   442  // a file in a subfolder of the context is modified and we re-build.
   443  func (s *DockerSuite) TestBuildModifyFileInFolder(c *check.C) {
   444  	name := "testbuildmodifyfileinfolder"
   445  
   446  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
   447  RUN ["mkdir", "/test"]
   448  ADD folder/file /test/changetarget`))
   449  	defer ctx.Close()
   450  	if err := ctx.Add("folder/file", "first"); err != nil {
   451  		c.Fatal(err)
   452  	}
   453  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
   454  	id1 := getIDByName(c, name)
   455  	if err := ctx.Add("folder/file", "second"); err != nil {
   456  		c.Fatal(err)
   457  	}
   458  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
   459  	id2 := getIDByName(c, name)
   460  	if id1 == id2 {
   461  		c.Fatal("cache was used even though file contents in folder was changed")
   462  	}
   463  }
   464  
   465  func (s *DockerSuite) TestBuildAddSingleFileToRoot(c *check.C) {
   466  	testRequires(c, DaemonIsLinux) // Linux specific test
   467  	buildImageSuccessfully(c, "testaddimg", build.WithBuildContext(c,
   468  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   469  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   470  RUN echo 'dockerio:x:1001:' >> /etc/group
   471  RUN touch /exists
   472  RUN chown dockerio.dockerio /exists
   473  ADD test_file /
   474  RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
   475  RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ]
   476  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
   477  		build.WithFile("test_file", "test1")))
   478  }
   479  
   480  // Issue #3960: "ADD src ." hangs
   481  func (s *DockerSuite) TestBuildAddSingleFileToWorkdir(c *check.C) {
   482  	name := "testaddsinglefiletoworkdir"
   483  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(
   484  		`FROM busybox
   485  	       ADD test_file .`),
   486  		fakecontext.WithFiles(map[string]string{
   487  			"test_file": "test1",
   488  		}))
   489  	defer ctx.Close()
   490  
   491  	errChan := make(chan error)
   492  	go func() {
   493  		errChan <- buildImage(name, build.WithExternalBuildContext(ctx)).Error
   494  		close(errChan)
   495  	}()
   496  	select {
   497  	case <-time.After(15 * time.Second):
   498  		c.Fatal("Build with adding to workdir timed out")
   499  	case err := <-errChan:
   500  		c.Assert(err, check.IsNil)
   501  	}
   502  }
   503  
   504  func (s *DockerSuite) TestBuildAddSingleFileToExistDir(c *check.C) {
   505  	testRequires(c, DaemonIsLinux) // Linux specific test
   506  	cli.BuildCmd(c, "testaddsinglefiletoexistdir", build.WithBuildContext(c,
   507  		build.WithFile("Dockerfile", `FROM busybox
   508  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   509  RUN echo 'dockerio:x:1001:' >> /etc/group
   510  RUN mkdir /exists
   511  RUN touch /exists/exists_file
   512  RUN chown -R dockerio.dockerio /exists
   513  ADD test_file /exists/
   514  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   515  RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]
   516  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   517  		build.WithFile("test_file", "test1")))
   518  }
   519  
   520  func (s *DockerSuite) TestBuildCopyAddMultipleFiles(c *check.C) {
   521  	testRequires(c, DaemonIsLinux) // Linux specific test
   522  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   523  		"robots.txt": "hello",
   524  	}))
   525  	defer server.Close()
   526  
   527  	cli.BuildCmd(c, "testcopymultiplefilestofile", build.WithBuildContext(c,
   528  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   529  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   530  RUN echo 'dockerio:x:1001:' >> /etc/group
   531  RUN mkdir /exists
   532  RUN touch /exists/exists_file
   533  RUN chown -R dockerio.dockerio /exists
   534  COPY test_file1 test_file2 /exists/
   535  ADD test_file3 test_file4 %s/robots.txt /exists/
   536  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   537  RUN [ $(ls -l /exists/test_file1 | awk '{print $3":"$4}') = 'root:root' ]
   538  RUN [ $(ls -l /exists/test_file2 | awk '{print $3":"$4}') = 'root:root' ]
   539  RUN [ $(ls -l /exists/test_file3 | awk '{print $3":"$4}') = 'root:root' ]
   540  RUN [ $(ls -l /exists/test_file4 | awk '{print $3":"$4}') = 'root:root' ]
   541  RUN [ $(ls -l /exists/robots.txt | awk '{print $3":"$4}') = 'root:root' ]
   542  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   543  `, server.URL())),
   544  		build.WithFile("test_file1", "test1"),
   545  		build.WithFile("test_file2", "test2"),
   546  		build.WithFile("test_file3", "test3"),
   547  		build.WithFile("test_file3", "test3"),
   548  		build.WithFile("test_file4", "test4")))
   549  }
   550  
   551  // These tests are mainly for user namespaces to verify that new directories
   552  // are created as the remapped root uid/gid pair
   553  func (s *DockerSuite) TestBuildUsernamespaceValidateRemappedRoot(c *check.C) {
   554  	testRequires(c, DaemonIsLinux)
   555  	testCases := []string{
   556  		"ADD . /new_dir",
   557  		"COPY test_dir /new_dir",
   558  		"WORKDIR /new_dir",
   559  	}
   560  	name := "testbuildusernamespacevalidateremappedroot"
   561  	for _, tc := range testCases {
   562  		cli.BuildCmd(c, name, build.WithBuildContext(c,
   563  			build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   564  %s
   565  RUN [ $(ls -l / | grep new_dir | awk '{print $3":"$4}') = 'root:root' ]`, tc)),
   566  			build.WithFile("test_dir/test_file", "test file")))
   567  
   568  		cli.DockerCmd(c, "rmi", name)
   569  	}
   570  }
   571  
   572  func (s *DockerSuite) TestBuildAddAndCopyFileWithWhitespace(c *check.C) {
   573  	testRequires(c, DaemonIsLinux) // Not currently passing on Windows
   574  	name := "testaddfilewithwhitespace"
   575  
   576  	for _, command := range []string{"ADD", "COPY"} {
   577  		cli.BuildCmd(c, name, build.WithBuildContext(c,
   578  			build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   579  RUN mkdir "/test dir"
   580  RUN mkdir "/test_dir"
   581  %s [ "test file1", "/test_file1" ]
   582  %s [ "test_file2", "/test file2" ]
   583  %s [ "test file3", "/test file3" ]
   584  %s [ "test dir/test_file4", "/test_dir/test_file4" ]
   585  %s [ "test_dir/test_file5", "/test dir/test_file5" ]
   586  %s [ "test dir/test_file6", "/test dir/test_file6" ]
   587  RUN [ $(cat "/test_file1") = 'test1' ]
   588  RUN [ $(cat "/test file2") = 'test2' ]
   589  RUN [ $(cat "/test file3") = 'test3' ]
   590  RUN [ $(cat "/test_dir/test_file4") = 'test4' ]
   591  RUN [ $(cat "/test dir/test_file5") = 'test5' ]
   592  RUN [ $(cat "/test dir/test_file6") = 'test6' ]`, command, command, command, command, command, command)),
   593  			build.WithFile("test file1", "test1"),
   594  			build.WithFile("test_file2", "test2"),
   595  			build.WithFile("test file3", "test3"),
   596  			build.WithFile("test dir/test_file4", "test4"),
   597  			build.WithFile("test_dir/test_file5", "test5"),
   598  			build.WithFile("test dir/test_file6", "test6"),
   599  		))
   600  
   601  		cli.DockerCmd(c, "rmi", name)
   602  	}
   603  }
   604  
   605  func (s *DockerSuite) TestBuildCopyFileWithWhitespaceOnWindows(c *check.C) {
   606  	testRequires(c, DaemonIsWindows)
   607  	dockerfile := `FROM ` + testEnv.PlatformDefaults.BaseImage + `
   608  RUN mkdir "C:/test dir"
   609  RUN mkdir "C:/test_dir"
   610  COPY [ "test file1", "/test_file1" ]
   611  COPY [ "test_file2", "/test file2" ]
   612  COPY [ "test file3", "/test file3" ]
   613  COPY [ "test dir/test_file4", "/test_dir/test_file4" ]
   614  COPY [ "test_dir/test_file5", "/test dir/test_file5" ]
   615  COPY [ "test dir/test_file6", "/test dir/test_file6" ]
   616  RUN find "test1" "C:/test_file1"
   617  RUN find "test2" "C:/test file2"
   618  RUN find "test3" "C:/test file3"
   619  RUN find "test4" "C:/test_dir/test_file4"
   620  RUN find "test5" "C:/test dir/test_file5"
   621  RUN find "test6" "C:/test dir/test_file6"`
   622  
   623  	name := "testcopyfilewithwhitespace"
   624  	cli.BuildCmd(c, name, build.WithBuildContext(c,
   625  		build.WithFile("Dockerfile", dockerfile),
   626  		build.WithFile("test file1", "test1"),
   627  		build.WithFile("test_file2", "test2"),
   628  		build.WithFile("test file3", "test3"),
   629  		build.WithFile("test dir/test_file4", "test4"),
   630  		build.WithFile("test_dir/test_file5", "test5"),
   631  		build.WithFile("test dir/test_file6", "test6"),
   632  	))
   633  }
   634  
   635  func (s *DockerSuite) TestBuildCopyWildcard(c *check.C) {
   636  	name := "testcopywildcard"
   637  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
   638  		"robots.txt": "hello",
   639  		"index.html": "world",
   640  	}))
   641  	defer server.Close()
   642  
   643  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM busybox
   644  	COPY file*.txt /tmp/
   645  	RUN ls /tmp/file1.txt /tmp/file2.txt
   646  	RUN [ "mkdir",  "/tmp1" ]
   647  	COPY dir* /tmp1/
   648  	RUN ls /tmp1/dirt /tmp1/nested_file /tmp1/nested_dir/nest_nest_file
   649  	RUN [ "mkdir",  "/tmp2" ]
   650          ADD dir/*dir %s/robots.txt /tmp2/
   651  	RUN ls /tmp2/nest_nest_file /tmp2/robots.txt
   652  	`, server.URL())),
   653  		fakecontext.WithFiles(map[string]string{
   654  			"file1.txt":                     "test1",
   655  			"file2.txt":                     "test2",
   656  			"dir/nested_file":               "nested file",
   657  			"dir/nested_dir/nest_nest_file": "2 times nested",
   658  			"dirt": "dirty",
   659  		}))
   660  	defer ctx.Close()
   661  
   662  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
   663  	id1 := getIDByName(c, name)
   664  
   665  	// Now make sure we use a cache the 2nd time
   666  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
   667  	id2 := getIDByName(c, name)
   668  
   669  	if id1 != id2 {
   670  		c.Fatal("didn't use the cache")
   671  	}
   672  
   673  }
   674  
   675  func (s *DockerSuite) TestBuildCopyWildcardInName(c *check.C) {
   676  	// Run this only on Linux
   677  	// Below is the original comment (that I don't agree with — vdemeester)
   678  	// Normally we would do c.Fatal(err) here but given that
   679  	// the odds of this failing are so rare, it must be because
   680  	// the OS we're running the client on doesn't support * in
   681  	// filenames (like windows).  So, instead of failing the test
   682  	// just let it pass. Then we don't need to explicitly
   683  	// say which OSs this works on or not.
   684  	testRequires(c, DaemonIsLinux, UnixCli)
   685  
   686  	buildImageSuccessfully(c, "testcopywildcardinname", build.WithBuildContext(c,
   687  		build.WithFile("Dockerfile", `FROM busybox
   688  	COPY *.txt /tmp/
   689  	RUN [ "$(cat /tmp/\*.txt)" = 'hi there' ]
   690  	`),
   691  		build.WithFile("*.txt", "hi there"),
   692  	))
   693  }
   694  
   695  func (s *DockerSuite) TestBuildCopyWildcardCache(c *check.C) {
   696  	name := "testcopywildcardcache"
   697  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
   698  	COPY file1.txt /tmp/`),
   699  		fakecontext.WithFiles(map[string]string{
   700  			"file1.txt": "test1",
   701  		}))
   702  	defer ctx.Close()
   703  
   704  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
   705  	id1 := getIDByName(c, name)
   706  
   707  	// Now make sure we use a cache the 2nd time even with wild cards.
   708  	// Use the same context so the file is the same and the checksum will match
   709  	ctx.Add("Dockerfile", `FROM busybox
   710  	COPY file*.txt /tmp/`)
   711  
   712  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
   713  	id2 := getIDByName(c, name)
   714  
   715  	if id1 != id2 {
   716  		c.Fatal("didn't use the cache")
   717  	}
   718  
   719  }
   720  
   721  func (s *DockerSuite) TestBuildAddSingleFileToNonExistingDir(c *check.C) {
   722  	testRequires(c, DaemonIsLinux) // Linux specific test
   723  	buildImageSuccessfully(c, "testaddsinglefiletononexistingdir", build.WithBuildContext(c,
   724  		build.WithFile("Dockerfile", `FROM busybox
   725  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   726  RUN echo 'dockerio:x:1001:' >> /etc/group
   727  RUN touch /exists
   728  RUN chown dockerio.dockerio /exists
   729  ADD test_file /test_dir/
   730  RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
   731  RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
   732  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   733  		build.WithFile("test_file", "test1")))
   734  }
   735  
   736  func (s *DockerSuite) TestBuildAddDirContentToRoot(c *check.C) {
   737  	testRequires(c, DaemonIsLinux) // Linux specific test
   738  	buildImageSuccessfully(c, "testadddircontenttoroot", build.WithBuildContext(c,
   739  		build.WithFile("Dockerfile", `FROM busybox
   740  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   741  RUN echo 'dockerio:x:1001:' >> /etc/group
   742  RUN touch /exists
   743  RUN chown dockerio.dockerio exists
   744  ADD test_dir /
   745  RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
   746  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   747  		build.WithFile("test_dir/test_file", "test1")))
   748  }
   749  
   750  func (s *DockerSuite) TestBuildAddDirContentToExistingDir(c *check.C) {
   751  	testRequires(c, DaemonIsLinux) // Linux specific test
   752  	buildImageSuccessfully(c, "testadddircontenttoexistingdir", build.WithBuildContext(c,
   753  		build.WithFile("Dockerfile", `FROM busybox
   754  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   755  RUN echo 'dockerio:x:1001:' >> /etc/group
   756  RUN mkdir /exists
   757  RUN touch /exists/exists_file
   758  RUN chown -R dockerio.dockerio /exists
   759  ADD test_dir/ /exists/
   760  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   761  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   762  RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`),
   763  		build.WithFile("test_dir/test_file", "test1")))
   764  }
   765  
   766  func (s *DockerSuite) TestBuildAddWholeDirToRoot(c *check.C) {
   767  	testRequires(c, DaemonIsLinux) // Linux specific test
   768  	buildImageSuccessfully(c, "testaddwholedirtoroot", build.WithBuildContext(c,
   769  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   770  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   771  RUN echo 'dockerio:x:1001:' >> /etc/group
   772  RUN touch /exists
   773  RUN chown dockerio.dockerio exists
   774  ADD test_dir /test_dir
   775  RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
   776  RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ]
   777  RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
   778  RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ]
   779  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
   780  		build.WithFile("test_dir/test_file", "test1")))
   781  }
   782  
   783  // Testing #5941 : Having an etc directory in context conflicts with the /etc/mtab
   784  func (s *DockerSuite) TestBuildAddOrCopyEtcToRootShouldNotConflict(c *check.C) {
   785  	buildImageSuccessfully(c, "testaddetctoroot", build.WithBuildContext(c,
   786  		build.WithFile("Dockerfile", `FROM `+minimalBaseImage()+`
   787  ADD . /`),
   788  		build.WithFile("etc/test_file", "test1")))
   789  	buildImageSuccessfully(c, "testcopyetctoroot", build.WithBuildContext(c,
   790  		build.WithFile("Dockerfile", `FROM `+minimalBaseImage()+`
   791  COPY . /`),
   792  		build.WithFile("etc/test_file", "test1")))
   793  }
   794  
   795  // Testing #9401 : Losing setuid flag after a ADD
   796  func (s *DockerSuite) TestBuildAddPreservesFilesSpecialBits(c *check.C) {
   797  	testRequires(c, DaemonIsLinux) // Linux specific test
   798  	buildImageSuccessfully(c, "testaddetctoroot", build.WithBuildContext(c,
   799  		build.WithFile("Dockerfile", `FROM busybox
   800  ADD suidbin /usr/bin/suidbin
   801  RUN chmod 4755 /usr/bin/suidbin
   802  RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]
   803  ADD ./data/ /
   804  RUN [ $(ls -l /usr/bin/suidbin | awk '{print $1}') = '-rwsr-xr-x' ]`),
   805  		build.WithFile("suidbin", "suidbin"),
   806  		build.WithFile("/data/usr/test_file", "test1")))
   807  }
   808  
   809  func (s *DockerSuite) TestBuildCopySingleFileToRoot(c *check.C) {
   810  	testRequires(c, DaemonIsLinux) // Linux specific test
   811  	buildImageSuccessfully(c, "testcopysinglefiletoroot", build.WithBuildContext(c,
   812  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   813  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   814  RUN echo 'dockerio:x:1001:' >> /etc/group
   815  RUN touch /exists
   816  RUN chown dockerio.dockerio /exists
   817  COPY test_file /
   818  RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
   819  RUN [ $(ls -l /test_file | awk '{print $1}') = '%s' ]
   820  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
   821  		build.WithFile("test_file", "test1")))
   822  }
   823  
   824  // Issue #3960: "ADD src ." hangs - adapted for COPY
   825  func (s *DockerSuite) TestBuildCopySingleFileToWorkdir(c *check.C) {
   826  	name := "testcopysinglefiletoworkdir"
   827  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(`FROM busybox
   828  COPY test_file .`),
   829  		fakecontext.WithFiles(map[string]string{
   830  			"test_file": "test1",
   831  		}))
   832  	defer ctx.Close()
   833  
   834  	errChan := make(chan error)
   835  	go func() {
   836  		errChan <- buildImage(name, build.WithExternalBuildContext(ctx)).Error
   837  		close(errChan)
   838  	}()
   839  	select {
   840  	case <-time.After(15 * time.Second):
   841  		c.Fatal("Build with adding to workdir timed out")
   842  	case err := <-errChan:
   843  		c.Assert(err, check.IsNil)
   844  	}
   845  }
   846  
   847  func (s *DockerSuite) TestBuildCopySingleFileToExistDir(c *check.C) {
   848  	testRequires(c, DaemonIsLinux) // Linux specific test
   849  	buildImageSuccessfully(c, "testcopysinglefiletoexistdir", build.WithBuildContext(c,
   850  		build.WithFile("Dockerfile", `FROM busybox
   851  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   852  RUN echo 'dockerio:x:1001:' >> /etc/group
   853  RUN mkdir /exists
   854  RUN touch /exists/exists_file
   855  RUN chown -R dockerio.dockerio /exists
   856  COPY test_file /exists/
   857  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   858  RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]
   859  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   860  		build.WithFile("test_file", "test1")))
   861  }
   862  
   863  func (s *DockerSuite) TestBuildCopySingleFileToNonExistDir(c *check.C) {
   864  	testRequires(c, DaemonIsLinux) // Linux specific
   865  	buildImageSuccessfully(c, "testcopysinglefiletononexistdir", build.WithBuildContext(c,
   866  		build.WithFile("Dockerfile", `FROM busybox
   867  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   868  RUN echo 'dockerio:x:1001:' >> /etc/group
   869  RUN touch /exists
   870  RUN chown dockerio.dockerio /exists
   871  COPY test_file /test_dir/
   872  RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
   873  RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
   874  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   875  		build.WithFile("test_file", "test1")))
   876  }
   877  
   878  func (s *DockerSuite) TestBuildCopyDirContentToRoot(c *check.C) {
   879  	testRequires(c, DaemonIsLinux) // Linux specific test
   880  	buildImageSuccessfully(c, "testcopydircontenttoroot", build.WithBuildContext(c,
   881  		build.WithFile("Dockerfile", `FROM busybox
   882  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   883  RUN echo 'dockerio:x:1001:' >> /etc/group
   884  RUN touch /exists
   885  RUN chown dockerio.dockerio exists
   886  COPY test_dir /
   887  RUN [ $(ls -l /test_file | awk '{print $3":"$4}') = 'root:root' ]
   888  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`),
   889  		build.WithFile("test_dir/test_file", "test1")))
   890  }
   891  
   892  func (s *DockerSuite) TestBuildCopyDirContentToExistDir(c *check.C) {
   893  	testRequires(c, DaemonIsLinux) // Linux specific test
   894  	buildImageSuccessfully(c, "testcopydircontenttoexistdir", build.WithBuildContext(c,
   895  		build.WithFile("Dockerfile", `FROM busybox
   896  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   897  RUN echo 'dockerio:x:1001:' >> /etc/group
   898  RUN mkdir /exists
   899  RUN touch /exists/exists_file
   900  RUN chown -R dockerio.dockerio /exists
   901  COPY test_dir/ /exists/
   902  RUN [ $(ls -l / | grep exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   903  RUN [ $(ls -l /exists/exists_file | awk '{print $3":"$4}') = 'dockerio:dockerio' ]
   904  RUN [ $(ls -l /exists/test_file | awk '{print $3":"$4}') = 'root:root' ]`),
   905  		build.WithFile("test_dir/test_file", "test1")))
   906  }
   907  
   908  func (s *DockerSuite) TestBuildCopyWholeDirToRoot(c *check.C) {
   909  	testRequires(c, DaemonIsLinux) // Linux specific test
   910  	buildImageSuccessfully(c, "testcopywholedirtoroot", build.WithBuildContext(c,
   911  		build.WithFile("Dockerfile", fmt.Sprintf(`FROM busybox
   912  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
   913  RUN echo 'dockerio:x:1001:' >> /etc/group
   914  RUN touch /exists
   915  RUN chown dockerio.dockerio exists
   916  COPY test_dir /test_dir
   917  RUN [ $(ls -l / | grep test_dir | awk '{print $3":"$4}') = 'root:root' ]
   918  RUN [ $(ls -l / | grep test_dir | awk '{print $1}') = 'drwxr-xr-x' ]
   919  RUN [ $(ls -l /test_dir/test_file | awk '{print $3":"$4}') = 'root:root' ]
   920  RUN [ $(ls -l /test_dir/test_file | awk '{print $1}') = '%s' ]
   921  RUN [ $(ls -l /exists | awk '{print $3":"$4}') = 'dockerio:dockerio' ]`, expectedFileChmod)),
   922  		build.WithFile("test_dir/test_file", "test1")))
   923  }
   924  
   925  func (s *DockerSuite) TestBuildAddBadLinks(c *check.C) {
   926  	testRequires(c, DaemonIsLinux) // Not currently working on Windows
   927  
   928  	dockerfile := `
   929  		FROM scratch
   930  		ADD links.tar /
   931  		ADD foo.txt /symlink/
   932  		`
   933  	targetFile := "foo.txt"
   934  	var (
   935  		name = "test-link-absolute"
   936  	)
   937  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
   938  	defer ctx.Close()
   939  
   940  	tempDir, err := ioutil.TempDir("", "test-link-absolute-temp-")
   941  	if err != nil {
   942  		c.Fatalf("failed to create temporary directory: %s", tempDir)
   943  	}
   944  	defer os.RemoveAll(tempDir)
   945  
   946  	var symlinkTarget string
   947  	if runtime.GOOS == "windows" {
   948  		var driveLetter string
   949  		if abs, err := filepath.Abs(tempDir); err != nil {
   950  			c.Fatal(err)
   951  		} else {
   952  			driveLetter = abs[:1]
   953  		}
   954  		tempDirWithoutDrive := tempDir[2:]
   955  		symlinkTarget = fmt.Sprintf(`%s:\..\..\..\..\..\..\..\..\..\..\..\..%s`, driveLetter, tempDirWithoutDrive)
   956  	} else {
   957  		symlinkTarget = fmt.Sprintf("/../../../../../../../../../../../..%s", tempDir)
   958  	}
   959  
   960  	tarPath := filepath.Join(ctx.Dir, "links.tar")
   961  	nonExistingFile := filepath.Join(tempDir, targetFile)
   962  	fooPath := filepath.Join(ctx.Dir, targetFile)
   963  
   964  	tarOut, err := os.Create(tarPath)
   965  	if err != nil {
   966  		c.Fatal(err)
   967  	}
   968  
   969  	tarWriter := tar.NewWriter(tarOut)
   970  
   971  	header := &tar.Header{
   972  		Name:     "symlink",
   973  		Typeflag: tar.TypeSymlink,
   974  		Linkname: symlinkTarget,
   975  		Mode:     0755,
   976  		Uid:      0,
   977  		Gid:      0,
   978  	}
   979  
   980  	err = tarWriter.WriteHeader(header)
   981  	if err != nil {
   982  		c.Fatal(err)
   983  	}
   984  
   985  	tarWriter.Close()
   986  	tarOut.Close()
   987  
   988  	foo, err := os.Create(fooPath)
   989  	if err != nil {
   990  		c.Fatal(err)
   991  	}
   992  	defer foo.Close()
   993  
   994  	if _, err := foo.WriteString("test"); err != nil {
   995  		c.Fatal(err)
   996  	}
   997  
   998  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
   999  	if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
  1000  		c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
  1001  	}
  1002  
  1003  }
  1004  
  1005  func (s *DockerSuite) TestBuildAddBadLinksVolume(c *check.C) {
  1006  	testRequires(c, DaemonIsLinux) // ln not implemented on Windows busybox
  1007  	const (
  1008  		dockerfileTemplate = `
  1009  		FROM busybox
  1010  		RUN ln -s /../../../../../../../../%s /x
  1011  		VOLUME /x
  1012  		ADD foo.txt /x/`
  1013  		targetFile = "foo.txt"
  1014  	)
  1015  	var (
  1016  		name       = "test-link-absolute-volume"
  1017  		dockerfile = ""
  1018  	)
  1019  
  1020  	tempDir, err := ioutil.TempDir("", "test-link-absolute-volume-temp-")
  1021  	if err != nil {
  1022  		c.Fatalf("failed to create temporary directory: %s", tempDir)
  1023  	}
  1024  	defer os.RemoveAll(tempDir)
  1025  
  1026  	dockerfile = fmt.Sprintf(dockerfileTemplate, tempDir)
  1027  	nonExistingFile := filepath.Join(tempDir, targetFile)
  1028  
  1029  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
  1030  	defer ctx.Close()
  1031  	fooPath := filepath.Join(ctx.Dir, targetFile)
  1032  
  1033  	foo, err := os.Create(fooPath)
  1034  	if err != nil {
  1035  		c.Fatal(err)
  1036  	}
  1037  	defer foo.Close()
  1038  
  1039  	if _, err := foo.WriteString("test"); err != nil {
  1040  		c.Fatal(err)
  1041  	}
  1042  
  1043  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  1044  	if _, err := os.Stat(nonExistingFile); err == nil || err != nil && !os.IsNotExist(err) {
  1045  		c.Fatalf("%s shouldn't have been written and it shouldn't exist", nonExistingFile)
  1046  	}
  1047  
  1048  }
  1049  
  1050  // Issue #5270 - ensure we throw a better error than "unexpected EOF"
  1051  // when we can't access files in the context.
  1052  func (s *DockerSuite) TestBuildWithInaccessibleFilesInContext(c *check.C) {
  1053  	testRequires(c, DaemonIsLinux, UnixCli, SameHostDaemon) // test uses chown/chmod: not available on windows
  1054  
  1055  	{
  1056  		name := "testbuildinaccessiblefiles"
  1057  		ctx := fakecontext.New(c, "",
  1058  			fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"),
  1059  			fakecontext.WithFiles(map[string]string{"fileWithoutReadAccess": "foo"}),
  1060  		)
  1061  		defer ctx.Close()
  1062  		// This is used to ensure we detect inaccessible files early during build in the cli client
  1063  		pathToFileWithoutReadAccess := filepath.Join(ctx.Dir, "fileWithoutReadAccess")
  1064  
  1065  		if err := os.Chown(pathToFileWithoutReadAccess, 0, 0); err != nil {
  1066  			c.Fatalf("failed to chown file to root: %s", err)
  1067  		}
  1068  		if err := os.Chmod(pathToFileWithoutReadAccess, 0700); err != nil {
  1069  			c.Fatalf("failed to chmod file to 700: %s", err)
  1070  		}
  1071  		result := icmd.RunCmd(icmd.Cmd{
  1072  			Command: []string{"su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)},
  1073  			Dir:     ctx.Dir,
  1074  		})
  1075  		if result.Error == nil {
  1076  			c.Fatalf("build should have failed: %s %s", result.Error, result.Combined())
  1077  		}
  1078  
  1079  		// check if we've detected the failure before we started building
  1080  		if !strings.Contains(result.Combined(), "no permission to read from ") {
  1081  			c.Fatalf("output should've contained the string: no permission to read from but contained: %s", result.Combined())
  1082  		}
  1083  
  1084  		if !strings.Contains(result.Combined(), "error checking context") {
  1085  			c.Fatalf("output should've contained the string: error checking context")
  1086  		}
  1087  	}
  1088  	{
  1089  		name := "testbuildinaccessibledirectory"
  1090  		ctx := fakecontext.New(c, "",
  1091  			fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"),
  1092  			fakecontext.WithFiles(map[string]string{"directoryWeCantStat/bar": "foo"}),
  1093  		)
  1094  		defer ctx.Close()
  1095  		// This is used to ensure we detect inaccessible directories early during build in the cli client
  1096  		pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat")
  1097  		pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
  1098  
  1099  		if err := os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
  1100  			c.Fatalf("failed to chown directory to root: %s", err)
  1101  		}
  1102  		if err := os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
  1103  			c.Fatalf("failed to chmod directory to 444: %s", err)
  1104  		}
  1105  		if err := os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
  1106  			c.Fatalf("failed to chmod file to 700: %s", err)
  1107  		}
  1108  
  1109  		result := icmd.RunCmd(icmd.Cmd{
  1110  			Command: []string{"su", "unprivilegeduser", "-c", fmt.Sprintf("%s build -t %s .", dockerBinary, name)},
  1111  			Dir:     ctx.Dir,
  1112  		})
  1113  		if result.Error == nil {
  1114  			c.Fatalf("build should have failed: %s %s", result.Error, result.Combined())
  1115  		}
  1116  
  1117  		// check if we've detected the failure before we started building
  1118  		if !strings.Contains(result.Combined(), "can't stat") {
  1119  			c.Fatalf("output should've contained the string: can't access %s", result.Combined())
  1120  		}
  1121  
  1122  		if !strings.Contains(result.Combined(), "error checking context") {
  1123  			c.Fatalf("output should've contained the string: error checking context\ngot:%s", result.Combined())
  1124  		}
  1125  
  1126  	}
  1127  	{
  1128  		name := "testlinksok"
  1129  		ctx := fakecontext.New(c, "", fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"))
  1130  		defer ctx.Close()
  1131  
  1132  		target := "../../../../../../../../../../../../../../../../../../../azA"
  1133  		if err := os.Symlink(filepath.Join(ctx.Dir, "g"), target); err != nil {
  1134  			c.Fatal(err)
  1135  		}
  1136  		defer os.Remove(target)
  1137  		// This is used to ensure we don't follow links when checking if everything in the context is accessible
  1138  		// This test doesn't require that we run commands as an unprivileged user
  1139  		buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  1140  	}
  1141  	{
  1142  		name := "testbuildignoredinaccessible"
  1143  		ctx := fakecontext.New(c, "",
  1144  			fakecontext.WithDockerfile("FROM scratch\nADD . /foo/"),
  1145  			fakecontext.WithFiles(map[string]string{
  1146  				"directoryWeCantStat/bar": "foo",
  1147  				".dockerignore":           "directoryWeCantStat",
  1148  			}),
  1149  		)
  1150  		defer ctx.Close()
  1151  		// This is used to ensure we don't try to add inaccessible files when they are ignored by a .dockerignore pattern
  1152  		pathToDirectoryWithoutReadAccess := filepath.Join(ctx.Dir, "directoryWeCantStat")
  1153  		pathToFileInDirectoryWithoutReadAccess := filepath.Join(pathToDirectoryWithoutReadAccess, "bar")
  1154  		if err := os.Chown(pathToDirectoryWithoutReadAccess, 0, 0); err != nil {
  1155  			c.Fatalf("failed to chown directory to root: %s", err)
  1156  		}
  1157  		if err := os.Chmod(pathToDirectoryWithoutReadAccess, 0444); err != nil {
  1158  			c.Fatalf("failed to chmod directory to 444: %s", err)
  1159  		}
  1160  		if err := os.Chmod(pathToFileInDirectoryWithoutReadAccess, 0700); err != nil {
  1161  			c.Fatalf("failed to chmod file to 700: %s", err)
  1162  		}
  1163  
  1164  		result := icmd.RunCmd(icmd.Cmd{
  1165  			Dir: ctx.Dir,
  1166  			Command: []string{"su", "unprivilegeduser", "-c",
  1167  				fmt.Sprintf("%s build -t %s .", dockerBinary, name)},
  1168  		})
  1169  		result.Assert(c, icmd.Expected{})
  1170  	}
  1171  }
  1172  
  1173  func (s *DockerSuite) TestBuildForceRm(c *check.C) {
  1174  	containerCountBefore := getContainerCount(c)
  1175  	name := "testbuildforcerm"
  1176  
  1177  	r := buildImage(name, cli.WithFlags("--force-rm"), build.WithBuildContext(c,
  1178  		build.WithFile("Dockerfile", `FROM busybox
  1179  	RUN true
  1180  	RUN thiswillfail`)))
  1181  	if r.ExitCode != 1 && r.ExitCode != 127 { // different on Linux / Windows
  1182  		c.Fatalf("Wrong exit code")
  1183  	}
  1184  
  1185  	containerCountAfter := getContainerCount(c)
  1186  	if containerCountBefore != containerCountAfter {
  1187  		c.Fatalf("--force-rm shouldn't have left containers behind")
  1188  	}
  1189  
  1190  }
  1191  
  1192  func (s *DockerSuite) TestBuildRm(c *check.C) {
  1193  	name := "testbuildrm"
  1194  
  1195  	testCases := []struct {
  1196  		buildflags                []string
  1197  		shouldLeftContainerBehind bool
  1198  	}{
  1199  		// Default case (i.e. --rm=true)
  1200  		{
  1201  			buildflags:                []string{},
  1202  			shouldLeftContainerBehind: false,
  1203  		},
  1204  		{
  1205  			buildflags:                []string{"--rm"},
  1206  			shouldLeftContainerBehind: false,
  1207  		},
  1208  		{
  1209  			buildflags:                []string{"--rm=false"},
  1210  			shouldLeftContainerBehind: true,
  1211  		},
  1212  	}
  1213  
  1214  	for _, tc := range testCases {
  1215  		containerCountBefore := getContainerCount(c)
  1216  
  1217  		buildImageSuccessfully(c, name, cli.WithFlags(tc.buildflags...), build.WithDockerfile(`FROM busybox
  1218  	RUN echo hello world`))
  1219  
  1220  		containerCountAfter := getContainerCount(c)
  1221  		if tc.shouldLeftContainerBehind {
  1222  			if containerCountBefore == containerCountAfter {
  1223  				c.Fatalf("flags %v should have left containers behind", tc.buildflags)
  1224  			}
  1225  		} else {
  1226  			if containerCountBefore != containerCountAfter {
  1227  				c.Fatalf("flags %v shouldn't have left containers behind", tc.buildflags)
  1228  			}
  1229  		}
  1230  
  1231  		dockerCmd(c, "rmi", name)
  1232  	}
  1233  }
  1234  
  1235  func (s *DockerSuite) TestBuildWithVolumes(c *check.C) {
  1236  	testRequires(c, DaemonIsLinux) // Invalid volume paths on Windows
  1237  	var (
  1238  		result   map[string]map[string]struct{}
  1239  		name     = "testbuildvolumes"
  1240  		emptyMap = make(map[string]struct{})
  1241  		expected = map[string]map[string]struct{}{
  1242  			"/test1":  emptyMap,
  1243  			"/test2":  emptyMap,
  1244  			"/test3":  emptyMap,
  1245  			"/test4":  emptyMap,
  1246  			"/test5":  emptyMap,
  1247  			"/test6":  emptyMap,
  1248  			"[/test7": emptyMap,
  1249  			"/test8]": emptyMap,
  1250  		}
  1251  	)
  1252  
  1253  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
  1254  		VOLUME /test1
  1255  		VOLUME /test2
  1256      VOLUME /test3 /test4
  1257      VOLUME ["/test5", "/test6"]
  1258      VOLUME [/test7 /test8]
  1259      `))
  1260  
  1261  	inspectFieldAndUnmarshall(c, name, "Config.Volumes", &result)
  1262  
  1263  	equal := reflect.DeepEqual(&result, &expected)
  1264  	if !equal {
  1265  		c.Fatalf("Volumes %s, expected %s", result, expected)
  1266  	}
  1267  
  1268  }
  1269  
  1270  func (s *DockerSuite) TestBuildMaintainer(c *check.C) {
  1271  	name := "testbuildmaintainer"
  1272  
  1273  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1274          MAINTAINER dockerio`))
  1275  
  1276  	expected := "dockerio"
  1277  	res := inspectField(c, name, "Author")
  1278  	if res != expected {
  1279  		c.Fatalf("Maintainer %s, expected %s", res, expected)
  1280  	}
  1281  }
  1282  
  1283  func (s *DockerSuite) TestBuildUser(c *check.C) {
  1284  	testRequires(c, DaemonIsLinux)
  1285  	name := "testbuilduser"
  1286  	expected := "dockerio"
  1287  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1288  		RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd
  1289  		USER dockerio
  1290  		RUN [ $(whoami) = 'dockerio' ]`))
  1291  	res := inspectField(c, name, "Config.User")
  1292  	if res != expected {
  1293  		c.Fatalf("User %s, expected %s", res, expected)
  1294  	}
  1295  }
  1296  
  1297  func (s *DockerSuite) TestBuildRelativeWorkdir(c *check.C) {
  1298  	name := "testbuildrelativeworkdir"
  1299  
  1300  	var (
  1301  		expected1     string
  1302  		expected2     string
  1303  		expected3     string
  1304  		expected4     string
  1305  		expectedFinal string
  1306  	)
  1307  
  1308  	if testEnv.OSType == "windows" {
  1309  		expected1 = `C:/`
  1310  		expected2 = `C:/test1`
  1311  		expected3 = `C:/test2`
  1312  		expected4 = `C:/test2/test3`
  1313  		expectedFinal = `C:\test2\test3` // Note inspect is going to return Windows paths, as it's not in busybox
  1314  	} else {
  1315  		expected1 = `/`
  1316  		expected2 = `/test1`
  1317  		expected3 = `/test2`
  1318  		expected4 = `/test2/test3`
  1319  		expectedFinal = `/test2/test3`
  1320  	}
  1321  
  1322  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1323  		RUN sh -c "[ "$PWD" = "`+expected1+`" ]"
  1324  		WORKDIR test1
  1325  		RUN sh -c "[ "$PWD" = "`+expected2+`" ]"
  1326  		WORKDIR /test2
  1327  		RUN sh -c "[ "$PWD" = "`+expected3+`" ]"
  1328  		WORKDIR test3
  1329  		RUN sh -c "[ "$PWD" = "`+expected4+`" ]"`))
  1330  
  1331  	res := inspectField(c, name, "Config.WorkingDir")
  1332  	if res != expectedFinal {
  1333  		c.Fatalf("Workdir %s, expected %s", res, expectedFinal)
  1334  	}
  1335  }
  1336  
  1337  // #22181 Regression test. Single end-to-end test of using
  1338  // Windows semantics. Most path handling verifications are in unit tests
  1339  func (s *DockerSuite) TestBuildWindowsWorkdirProcessing(c *check.C) {
  1340  	testRequires(c, DaemonIsWindows)
  1341  	buildImageSuccessfully(c, "testbuildwindowsworkdirprocessing", build.WithDockerfile(`FROM busybox
  1342  		WORKDIR C:\\foo
  1343  		WORKDIR bar
  1344  		RUN sh -c "[ "$PWD" = "C:/foo/bar" ]"
  1345  		`))
  1346  }
  1347  
  1348  // #22181 Regression test. Most paths handling verifications are in unit test.
  1349  // One functional test for end-to-end
  1350  func (s *DockerSuite) TestBuildWindowsAddCopyPathProcessing(c *check.C) {
  1351  	testRequires(c, DaemonIsWindows)
  1352  	// TODO Windows (@jhowardmsft). Needs a follow-up PR to 22181 to
  1353  	// support backslash such as .\\ being equivalent to ./ and c:\\ being
  1354  	// equivalent to c:/. This is not currently (nor ever has been) supported
  1355  	// by docker on the Windows platform.
  1356  	buildImageSuccessfully(c, "testbuildwindowsaddcopypathprocessing", build.WithBuildContext(c,
  1357  		build.WithFile("Dockerfile", `FROM busybox
  1358  			# No trailing slash on COPY/ADD
  1359  			# Results in dir being changed to a file
  1360  			WORKDIR /wc1
  1361  			COPY wc1 c:/wc1
  1362  			WORKDIR /wc2
  1363  			ADD wc2 c:/wc2
  1364  			WORKDIR c:/
  1365  			RUN sh -c "[ $(cat c:/wc1/wc1) = 'hellowc1' ]"
  1366  			RUN sh -c "[ $(cat c:/wc2/wc2) = 'worldwc2' ]"
  1367  
  1368  			# Trailing slash on COPY/ADD, Windows-style path.
  1369  			WORKDIR /wd1
  1370  			COPY wd1 c:/wd1/
  1371  			WORKDIR /wd2
  1372  			ADD wd2 c:/wd2/
  1373  			RUN sh -c "[ $(cat c:/wd1/wd1) = 'hellowd1' ]"
  1374  			RUN sh -c "[ $(cat c:/wd2/wd2) = 'worldwd2' ]"
  1375  			`),
  1376  		build.WithFile("wc1", "hellowc1"),
  1377  		build.WithFile("wc2", "worldwc2"),
  1378  		build.WithFile("wd1", "hellowd1"),
  1379  		build.WithFile("wd2", "worldwd2"),
  1380  	))
  1381  }
  1382  
  1383  func (s *DockerSuite) TestBuildWorkdirWithEnvVariables(c *check.C) {
  1384  	name := "testbuildworkdirwithenvvariables"
  1385  
  1386  	var expected string
  1387  	if testEnv.OSType == "windows" {
  1388  		expected = `C:\test1\test2`
  1389  	} else {
  1390  		expected = `/test1/test2`
  1391  	}
  1392  
  1393  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1394  		ENV DIRPATH /test1
  1395  		ENV SUBDIRNAME test2
  1396  		WORKDIR $DIRPATH
  1397  		WORKDIR $SUBDIRNAME/$MISSING_VAR`))
  1398  	res := inspectField(c, name, "Config.WorkingDir")
  1399  	if res != expected {
  1400  		c.Fatalf("Workdir %s, expected %s", res, expected)
  1401  	}
  1402  }
  1403  
  1404  func (s *DockerSuite) TestBuildRelativeCopy(c *check.C) {
  1405  	// cat /test1/test2/foo gets permission denied for the user
  1406  	testRequires(c, NotUserNamespace)
  1407  
  1408  	var expected string
  1409  	if testEnv.OSType == "windows" {
  1410  		expected = `C:/test1/test2`
  1411  	} else {
  1412  		expected = `/test1/test2`
  1413  	}
  1414  
  1415  	buildImageSuccessfully(c, "testbuildrelativecopy", build.WithBuildContext(c,
  1416  		build.WithFile("Dockerfile", `FROM busybox
  1417  			WORKDIR /test1
  1418  			WORKDIR test2
  1419  			RUN sh -c "[ "$PWD" = '`+expected+`' ]"
  1420  			COPY foo ./
  1421  			RUN sh -c "[ $(cat /test1/test2/foo) = 'hello' ]"
  1422  			ADD foo ./bar/baz
  1423  			RUN sh -c "[ $(cat /test1/test2/bar/baz) = 'hello' ]"
  1424  			COPY foo ./bar/baz2
  1425  			RUN sh -c "[ $(cat /test1/test2/bar/baz2) = 'hello' ]"
  1426  			WORKDIR ..
  1427  			COPY foo ./
  1428  			RUN sh -c "[ $(cat /test1/foo) = 'hello' ]"
  1429  			COPY foo /test3/
  1430  			RUN sh -c "[ $(cat /test3/foo) = 'hello' ]"
  1431  			WORKDIR /test4
  1432  			COPY . .
  1433  			RUN sh -c "[ $(cat /test4/foo) = 'hello' ]"
  1434  			WORKDIR /test5/test6
  1435  			COPY foo ../
  1436  			RUN sh -c "[ $(cat /test5/foo) = 'hello' ]"
  1437  			`),
  1438  		build.WithFile("foo", "hello"),
  1439  	))
  1440  }
  1441  
  1442  // FIXME(vdemeester) should be unit test
  1443  func (s *DockerSuite) TestBuildBlankName(c *check.C) {
  1444  	name := "testbuildblankname"
  1445  	testCases := []struct {
  1446  		expression     string
  1447  		expectedStderr string
  1448  	}{
  1449  		{
  1450  			expression:     "ENV =",
  1451  			expectedStderr: "ENV names can not be blank",
  1452  		},
  1453  		{
  1454  			expression:     "LABEL =",
  1455  			expectedStderr: "LABEL names can not be blank",
  1456  		},
  1457  		{
  1458  			expression:     "ARG =foo",
  1459  			expectedStderr: "ARG names can not be blank",
  1460  		},
  1461  	}
  1462  
  1463  	for _, tc := range testCases {
  1464  		buildImage(name, build.WithDockerfile(fmt.Sprintf(`FROM busybox
  1465  		%s`, tc.expression))).Assert(c, icmd.Expected{
  1466  			ExitCode: 1,
  1467  			Err:      tc.expectedStderr,
  1468  		})
  1469  	}
  1470  }
  1471  
  1472  func (s *DockerSuite) TestBuildEnv(c *check.C) {
  1473  	testRequires(c, DaemonIsLinux) // ENV expansion is different in Windows
  1474  	name := "testbuildenv"
  1475  	expected := "[PATH=/test:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin PORT=2375]"
  1476  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1477  		ENV PATH /test:$PATH
  1478  		ENV PORT 2375
  1479  		RUN [ $(env | grep PORT) = 'PORT=2375' ]`))
  1480  	res := inspectField(c, name, "Config.Env")
  1481  	if res != expected {
  1482  		c.Fatalf("Env %s, expected %s", res, expected)
  1483  	}
  1484  }
  1485  
  1486  func (s *DockerSuite) TestBuildPATH(c *check.C) {
  1487  	testRequires(c, DaemonIsLinux) // ENV expansion is different in Windows
  1488  
  1489  	defPath := "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
  1490  
  1491  	fn := func(dockerfile string, expected string) {
  1492  		buildImageSuccessfully(c, "testbldpath", build.WithDockerfile(dockerfile))
  1493  		res := inspectField(c, "testbldpath", "Config.Env")
  1494  		if res != expected {
  1495  			c.Fatalf("Env %q, expected %q for dockerfile:%q", res, expected, dockerfile)
  1496  		}
  1497  	}
  1498  
  1499  	tests := []struct{ dockerfile, exp string }{
  1500  		{"FROM scratch\nMAINTAINER me", "[PATH=" + defPath + "]"},
  1501  		{"FROM busybox\nMAINTAINER me", "[PATH=" + defPath + "]"},
  1502  		{"FROM scratch\nENV FOO=bar", "[PATH=" + defPath + " FOO=bar]"},
  1503  		{"FROM busybox\nENV FOO=bar", "[PATH=" + defPath + " FOO=bar]"},
  1504  		{"FROM scratch\nENV PATH=/test", "[PATH=/test]"},
  1505  		{"FROM busybox\nENV PATH=/test", "[PATH=/test]"},
  1506  		{"FROM scratch\nENV PATH=''", "[PATH=]"},
  1507  		{"FROM busybox\nENV PATH=''", "[PATH=]"},
  1508  	}
  1509  
  1510  	for _, test := range tests {
  1511  		fn(test.dockerfile, test.exp)
  1512  	}
  1513  }
  1514  
  1515  func (s *DockerSuite) TestBuildContextCleanup(c *check.C) {
  1516  	testRequires(c, SameHostDaemon)
  1517  
  1518  	name := "testbuildcontextcleanup"
  1519  	entries, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
  1520  	if err != nil {
  1521  		c.Fatalf("failed to list contents of tmp dir: %s", err)
  1522  	}
  1523  
  1524  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1525          ENTRYPOINT ["/bin/echo"]`))
  1526  
  1527  	entriesFinal, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
  1528  	if err != nil {
  1529  		c.Fatalf("failed to list contents of tmp dir: %s", err)
  1530  	}
  1531  	if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
  1532  		c.Fatalf("context should have been deleted, but wasn't")
  1533  	}
  1534  
  1535  }
  1536  
  1537  func (s *DockerSuite) TestBuildContextCleanupFailedBuild(c *check.C) {
  1538  	testRequires(c, SameHostDaemon)
  1539  
  1540  	name := "testbuildcontextcleanup"
  1541  	entries, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
  1542  	if err != nil {
  1543  		c.Fatalf("failed to list contents of tmp dir: %s", err)
  1544  	}
  1545  
  1546  	buildImage(name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1547  	RUN /non/existing/command`)).Assert(c, icmd.Expected{
  1548  		ExitCode: 1,
  1549  	})
  1550  
  1551  	entriesFinal, err := ioutil.ReadDir(filepath.Join(testEnv.DaemonInfo.DockerRootDir, "tmp"))
  1552  	if err != nil {
  1553  		c.Fatalf("failed to list contents of tmp dir: %s", err)
  1554  	}
  1555  	if err = compareDirectoryEntries(entries, entriesFinal); err != nil {
  1556  		c.Fatalf("context should have been deleted, but wasn't")
  1557  	}
  1558  
  1559  }
  1560  
  1561  // compareDirectoryEntries compares two sets of FileInfo (usually taken from a directory)
  1562  // and returns an error if different.
  1563  func compareDirectoryEntries(e1 []os.FileInfo, e2 []os.FileInfo) error {
  1564  	var (
  1565  		e1Entries = make(map[string]struct{})
  1566  		e2Entries = make(map[string]struct{})
  1567  	)
  1568  	for _, e := range e1 {
  1569  		e1Entries[e.Name()] = struct{}{}
  1570  	}
  1571  	for _, e := range e2 {
  1572  		e2Entries[e.Name()] = struct{}{}
  1573  	}
  1574  	if !reflect.DeepEqual(e1Entries, e2Entries) {
  1575  		return fmt.Errorf("entries differ")
  1576  	}
  1577  	return nil
  1578  }
  1579  
  1580  func (s *DockerSuite) TestBuildCmd(c *check.C) {
  1581  	name := "testbuildcmd"
  1582  	expected := "[/bin/echo Hello World]"
  1583  
  1584  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1585          CMD ["/bin/echo", "Hello World"]`))
  1586  
  1587  	res := inspectField(c, name, "Config.Cmd")
  1588  	if res != expected {
  1589  		c.Fatalf("Cmd %s, expected %s", res, expected)
  1590  	}
  1591  }
  1592  
  1593  func (s *DockerSuite) TestBuildExpose(c *check.C) {
  1594  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1595  	name := "testbuildexpose"
  1596  	expected := "map[2375/tcp:{}]"
  1597  
  1598  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
  1599          EXPOSE 2375`))
  1600  
  1601  	res := inspectField(c, name, "Config.ExposedPorts")
  1602  	if res != expected {
  1603  		c.Fatalf("Exposed ports %s, expected %s", res, expected)
  1604  	}
  1605  }
  1606  
  1607  func (s *DockerSuite) TestBuildExposeMorePorts(c *check.C) {
  1608  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1609  	// start building docker file with a large number of ports
  1610  	portList := make([]string, 50)
  1611  	line := make([]string, 100)
  1612  	expectedPorts := make([]int, len(portList)*len(line))
  1613  	for i := 0; i < len(portList); i++ {
  1614  		for j := 0; j < len(line); j++ {
  1615  			p := i*len(line) + j + 1
  1616  			line[j] = strconv.Itoa(p)
  1617  			expectedPorts[p-1] = p
  1618  		}
  1619  		if i == len(portList)-1 {
  1620  			portList[i] = strings.Join(line, " ")
  1621  		} else {
  1622  			portList[i] = strings.Join(line, " ") + ` \`
  1623  		}
  1624  	}
  1625  
  1626  	dockerfile := `FROM scratch
  1627  	EXPOSE {{range .}} {{.}}
  1628  	{{end}}`
  1629  	tmpl := template.Must(template.New("dockerfile").Parse(dockerfile))
  1630  	buf := bytes.NewBuffer(nil)
  1631  	tmpl.Execute(buf, portList)
  1632  
  1633  	name := "testbuildexpose"
  1634  	buildImageSuccessfully(c, name, build.WithDockerfile(buf.String()))
  1635  
  1636  	// check if all the ports are saved inside Config.ExposedPorts
  1637  	res := inspectFieldJSON(c, name, "Config.ExposedPorts")
  1638  	var exposedPorts map[string]interface{}
  1639  	if err := json.Unmarshal([]byte(res), &exposedPorts); err != nil {
  1640  		c.Fatal(err)
  1641  	}
  1642  
  1643  	for _, p := range expectedPorts {
  1644  		ep := fmt.Sprintf("%d/tcp", p)
  1645  		if _, ok := exposedPorts[ep]; !ok {
  1646  			c.Errorf("Port(%s) is not exposed", ep)
  1647  		} else {
  1648  			delete(exposedPorts, ep)
  1649  		}
  1650  	}
  1651  	if len(exposedPorts) != 0 {
  1652  		c.Errorf("Unexpected extra exposed ports %v", exposedPorts)
  1653  	}
  1654  }
  1655  
  1656  func (s *DockerSuite) TestBuildExposeOrder(c *check.C) {
  1657  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1658  	buildID := func(name, exposed string) string {
  1659  		buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM scratch
  1660  		EXPOSE %s`, exposed)))
  1661  		id := inspectField(c, name, "Id")
  1662  		return id
  1663  	}
  1664  
  1665  	id1 := buildID("testbuildexpose1", "80 2375")
  1666  	id2 := buildID("testbuildexpose2", "2375 80")
  1667  	if id1 != id2 {
  1668  		c.Errorf("EXPOSE should invalidate the cache only when ports actually changed")
  1669  	}
  1670  }
  1671  
  1672  func (s *DockerSuite) TestBuildExposeUpperCaseProto(c *check.C) {
  1673  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1674  	name := "testbuildexposeuppercaseproto"
  1675  	expected := "map[5678/udp:{}]"
  1676  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
  1677          EXPOSE 5678/UDP`))
  1678  	res := inspectField(c, name, "Config.ExposedPorts")
  1679  	if res != expected {
  1680  		c.Fatalf("Exposed ports %s, expected %s", res, expected)
  1681  	}
  1682  }
  1683  
  1684  func (s *DockerSuite) TestBuildEmptyEntrypointInheritance(c *check.C) {
  1685  	name := "testbuildentrypointinheritance"
  1686  	name2 := "testbuildentrypointinheritance2"
  1687  
  1688  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1689          ENTRYPOINT ["/bin/echo"]`))
  1690  	res := inspectField(c, name, "Config.Entrypoint")
  1691  
  1692  	expected := "[/bin/echo]"
  1693  	if res != expected {
  1694  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  1695  	}
  1696  
  1697  	buildImageSuccessfully(c, name2, build.WithDockerfile(fmt.Sprintf(`FROM %s
  1698          ENTRYPOINT []`, name)))
  1699  	res = inspectField(c, name2, "Config.Entrypoint")
  1700  
  1701  	expected = "[]"
  1702  	if res != expected {
  1703  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  1704  	}
  1705  }
  1706  
  1707  func (s *DockerSuite) TestBuildEmptyEntrypoint(c *check.C) {
  1708  	name := "testbuildentrypoint"
  1709  	expected := "[]"
  1710  
  1711  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  1712          ENTRYPOINT []`))
  1713  
  1714  	res := inspectField(c, name, "Config.Entrypoint")
  1715  	if res != expected {
  1716  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  1717  	}
  1718  
  1719  }
  1720  
  1721  func (s *DockerSuite) TestBuildEntrypoint(c *check.C) {
  1722  	name := "testbuildentrypoint"
  1723  
  1724  	expected := "[/bin/echo]"
  1725  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  1726          ENTRYPOINT ["/bin/echo"]`))
  1727  
  1728  	res := inspectField(c, name, "Config.Entrypoint")
  1729  	if res != expected {
  1730  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  1731  	}
  1732  
  1733  }
  1734  
  1735  // #6445 ensure ONBUILD triggers aren't committed to grandchildren
  1736  func (s *DockerSuite) TestBuildOnBuildLimitedInheritance(c *check.C) {
  1737  	buildImageSuccessfully(c, "testonbuildtrigger1", build.WithDockerfile(`
  1738  		FROM busybox
  1739  		RUN echo "GRANDPARENT"
  1740  		ONBUILD RUN echo "ONBUILD PARENT"
  1741  		`))
  1742  	// ONBUILD should be run in second build.
  1743  	buildImage("testonbuildtrigger2", build.WithDockerfile("FROM testonbuildtrigger1")).Assert(c, icmd.Expected{
  1744  		Out: "ONBUILD PARENT",
  1745  	})
  1746  	// ONBUILD should *not* be run in third build.
  1747  	result := buildImage("testonbuildtrigger3", build.WithDockerfile("FROM testonbuildtrigger2"))
  1748  	result.Assert(c, icmd.Success)
  1749  	if strings.Contains(result.Combined(), "ONBUILD PARENT") {
  1750  		c.Fatalf("ONBUILD instruction ran in grandchild of ONBUILD parent")
  1751  	}
  1752  }
  1753  
  1754  func (s *DockerSuite) TestBuildSameDockerfileWithAndWithoutCache(c *check.C) {
  1755  	testRequires(c, DaemonIsLinux) // Expose not implemented on Windows
  1756  	name := "testbuildwithcache"
  1757  	dockerfile := `FROM scratch
  1758  		MAINTAINER dockerio
  1759  		EXPOSE 5432
  1760          ENTRYPOINT ["/bin/echo"]`
  1761  	buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile))
  1762  	id1 := getIDByName(c, name)
  1763  	buildImageSuccessfully(c, name, build.WithDockerfile(dockerfile))
  1764  	id2 := getIDByName(c, name)
  1765  	buildImageSuccessfully(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
  1766  	id3 := getIDByName(c, name)
  1767  	if id1 != id2 {
  1768  		c.Fatal("The cache should have been used but hasn't.")
  1769  	}
  1770  	if id1 == id3 {
  1771  		c.Fatal("The cache should have been invalided but hasn't.")
  1772  	}
  1773  }
  1774  
  1775  // Make sure that ADD/COPY still populate the cache even if they don't use it
  1776  func (s *DockerSuite) TestBuildConditionalCache(c *check.C) {
  1777  	name := "testbuildconditionalcache"
  1778  
  1779  	dockerfile := `
  1780  		FROM busybox
  1781          ADD foo /tmp/`
  1782  	ctx := fakecontext.New(c, "",
  1783  		fakecontext.WithDockerfile(dockerfile),
  1784  		fakecontext.WithFiles(map[string]string{
  1785  			"foo": "hello",
  1786  		}))
  1787  	defer ctx.Close()
  1788  
  1789  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1790  	id1 := getIDByName(c, name)
  1791  
  1792  	if err := ctx.Add("foo", "bye"); err != nil {
  1793  		c.Fatalf("Error modifying foo: %s", err)
  1794  	}
  1795  
  1796  	// Updating a file should invalidate the cache
  1797  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1798  	id2 := getIDByName(c, name)
  1799  	if id2 == id1 {
  1800  		c.Fatal("Should not have used the cache")
  1801  	}
  1802  
  1803  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1804  	id3 := getIDByName(c, name)
  1805  	if id3 != id2 {
  1806  		c.Fatal("Should have used the cache")
  1807  	}
  1808  }
  1809  
  1810  func (s *DockerSuite) TestBuildAddMultipleLocalFileWithAndWithoutCache(c *check.C) {
  1811  	name := "testbuildaddmultiplelocalfilewithcache"
  1812  	baseName := name + "-base"
  1813  
  1814  	cli.BuildCmd(c, baseName, build.WithDockerfile(`
  1815  		FROM busybox
  1816  		ENTRYPOINT ["/bin/sh"]
  1817  	`))
  1818  
  1819  	dockerfile := `
  1820  		FROM testbuildaddmultiplelocalfilewithcache-base
  1821          MAINTAINER dockerio
  1822          ADD foo Dockerfile /usr/lib/bla/
  1823  		RUN sh -c "[ $(cat /usr/lib/bla/foo) = "hello" ]"`
  1824  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
  1825  		"foo": "hello",
  1826  	}))
  1827  	defer ctx.Close()
  1828  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1829  	id1 := getIDByName(c, name)
  1830  	result2 := cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1831  	id2 := getIDByName(c, name)
  1832  	result3 := cli.BuildCmd(c, name, build.WithoutCache, build.WithExternalBuildContext(ctx))
  1833  	id3 := getIDByName(c, name)
  1834  	if id1 != id2 {
  1835  		c.Fatalf("The cache should have been used but hasn't: %s", result2.Stdout())
  1836  	}
  1837  	if id1 == id3 {
  1838  		c.Fatalf("The cache should have been invalided but hasn't: %s", result3.Stdout())
  1839  	}
  1840  }
  1841  
  1842  func (s *DockerSuite) TestBuildCopyDirButNotFile(c *check.C) {
  1843  	name := "testbuildcopydirbutnotfile"
  1844  	name2 := "testbuildcopydirbutnotfile2"
  1845  
  1846  	dockerfile := `
  1847          FROM ` + minimalBaseImage() + `
  1848          COPY dir /tmp/`
  1849  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
  1850  		"dir/foo": "hello",
  1851  	}))
  1852  	defer ctx.Close()
  1853  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1854  	id1 := getIDByName(c, name)
  1855  	// Check that adding file with similar name doesn't mess with cache
  1856  	if err := ctx.Add("dir_file", "hello2"); err != nil {
  1857  		c.Fatal(err)
  1858  	}
  1859  	cli.BuildCmd(c, name2, build.WithExternalBuildContext(ctx))
  1860  	id2 := getIDByName(c, name2)
  1861  	if id1 != id2 {
  1862  		c.Fatal("The cache should have been used but wasn't")
  1863  	}
  1864  }
  1865  
  1866  func (s *DockerSuite) TestBuildAddCurrentDirWithCache(c *check.C) {
  1867  	name := "testbuildaddcurrentdirwithcache"
  1868  	name2 := name + "2"
  1869  	name3 := name + "3"
  1870  	name4 := name + "4"
  1871  	dockerfile := `
  1872          FROM ` + minimalBaseImage() + `
  1873          MAINTAINER dockerio
  1874          ADD . /usr/lib/bla`
  1875  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
  1876  		"foo": "hello",
  1877  	}))
  1878  	defer ctx.Close()
  1879  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  1880  	id1 := getIDByName(c, name)
  1881  	// Check that adding file invalidate cache of "ADD ."
  1882  	if err := ctx.Add("bar", "hello2"); err != nil {
  1883  		c.Fatal(err)
  1884  	}
  1885  	buildImageSuccessfully(c, name2, build.WithExternalBuildContext(ctx))
  1886  	id2 := getIDByName(c, name2)
  1887  	if id1 == id2 {
  1888  		c.Fatal("The cache should have been invalided but hasn't.")
  1889  	}
  1890  	// Check that changing file invalidate cache of "ADD ."
  1891  	if err := ctx.Add("foo", "hello1"); err != nil {
  1892  		c.Fatal(err)
  1893  	}
  1894  	buildImageSuccessfully(c, name3, build.WithExternalBuildContext(ctx))
  1895  	id3 := getIDByName(c, name3)
  1896  	if id2 == id3 {
  1897  		c.Fatal("The cache should have been invalided but hasn't.")
  1898  	}
  1899  	// Check that changing file to same content with different mtime does not
  1900  	// invalidate cache of "ADD ."
  1901  	time.Sleep(1 * time.Second) // wait second because of mtime precision
  1902  	if err := ctx.Add("foo", "hello1"); err != nil {
  1903  		c.Fatal(err)
  1904  	}
  1905  	buildImageSuccessfully(c, name4, build.WithExternalBuildContext(ctx))
  1906  	id4 := getIDByName(c, name4)
  1907  	if id3 != id4 {
  1908  		c.Fatal("The cache should have been used but hasn't.")
  1909  	}
  1910  }
  1911  
  1912  // FIXME(vdemeester) this really seems to test the same thing as before (TestBuildAddMultipleLocalFileWithAndWithoutCache)
  1913  func (s *DockerSuite) TestBuildAddCurrentDirWithoutCache(c *check.C) {
  1914  	name := "testbuildaddcurrentdirwithoutcache"
  1915  	dockerfile := `
  1916          FROM ` + minimalBaseImage() + `
  1917          MAINTAINER dockerio
  1918          ADD . /usr/lib/bla`
  1919  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile), fakecontext.WithFiles(map[string]string{
  1920  		"foo": "hello",
  1921  	}))
  1922  	defer ctx.Close()
  1923  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  1924  	id1 := getIDByName(c, name)
  1925  	buildImageSuccessfully(c, name, build.WithoutCache, build.WithExternalBuildContext(ctx))
  1926  	id2 := getIDByName(c, name)
  1927  	if id1 == id2 {
  1928  		c.Fatal("The cache should have been invalided but hasn't.")
  1929  	}
  1930  }
  1931  
  1932  func (s *DockerSuite) TestBuildAddRemoteFileWithAndWithoutCache(c *check.C) {
  1933  	name := "testbuildaddremotefilewithcache"
  1934  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
  1935  		"baz": "hello",
  1936  	}))
  1937  	defer server.Close()
  1938  
  1939  	dockerfile := fmt.Sprintf(`FROM `+minimalBaseImage()+`
  1940          MAINTAINER dockerio
  1941          ADD %s/baz /usr/lib/baz/quux`, server.URL())
  1942  	cli.BuildCmd(c, name, build.WithDockerfile(dockerfile))
  1943  	id1 := getIDByName(c, name)
  1944  	cli.BuildCmd(c, name, build.WithDockerfile(dockerfile))
  1945  	id2 := getIDByName(c, name)
  1946  	cli.BuildCmd(c, name, build.WithoutCache, build.WithDockerfile(dockerfile))
  1947  	id3 := getIDByName(c, name)
  1948  
  1949  	if id1 != id2 {
  1950  		c.Fatal("The cache should have been used but hasn't.")
  1951  	}
  1952  	if id1 == id3 {
  1953  		c.Fatal("The cache should have been invalided but hasn't.")
  1954  	}
  1955  }
  1956  
  1957  func (s *DockerSuite) TestBuildAddRemoteFileMTime(c *check.C) {
  1958  	name := "testbuildaddremotefilemtime"
  1959  	name2 := name + "2"
  1960  	name3 := name + "3"
  1961  
  1962  	files := map[string]string{"baz": "hello"}
  1963  	server := fakestorage.New(c, "", fakecontext.WithFiles(files))
  1964  	defer server.Close()
  1965  
  1966  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM `+minimalBaseImage()+`
  1967          MAINTAINER dockerio
  1968          ADD %s/baz /usr/lib/baz/quux`, server.URL())))
  1969  	defer ctx.Close()
  1970  
  1971  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  1972  	id1 := getIDByName(c, name)
  1973  	cli.BuildCmd(c, name2, build.WithExternalBuildContext(ctx))
  1974  	id2 := getIDByName(c, name2)
  1975  	if id1 != id2 {
  1976  		c.Fatal("The cache should have been used but wasn't - #1")
  1977  	}
  1978  
  1979  	// Now create a different server with same contents (causes different mtime)
  1980  	// The cache should still be used
  1981  
  1982  	// allow some time for clock to pass as mtime precision is only 1s
  1983  	time.Sleep(2 * time.Second)
  1984  
  1985  	server2 := fakestorage.New(c, "", fakecontext.WithFiles(files))
  1986  	defer server2.Close()
  1987  
  1988  	ctx2 := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM `+minimalBaseImage()+`
  1989          MAINTAINER dockerio
  1990          ADD %s/baz /usr/lib/baz/quux`, server2.URL())))
  1991  	defer ctx2.Close()
  1992  	cli.BuildCmd(c, name3, build.WithExternalBuildContext(ctx2))
  1993  	id3 := getIDByName(c, name3)
  1994  	if id1 != id3 {
  1995  		c.Fatal("The cache should have been used but wasn't")
  1996  	}
  1997  }
  1998  
  1999  // FIXME(vdemeester) this really seems to test the same thing as before (combined)
  2000  func (s *DockerSuite) TestBuildAddLocalAndRemoteFilesWithAndWithoutCache(c *check.C) {
  2001  	name := "testbuildaddlocalandremotefilewithcache"
  2002  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{
  2003  		"baz": "hello",
  2004  	}))
  2005  	defer server.Close()
  2006  
  2007  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(fmt.Sprintf(`FROM `+minimalBaseImage()+`
  2008          MAINTAINER dockerio
  2009          ADD foo /usr/lib/bla/bar
  2010          ADD %s/baz /usr/lib/baz/quux`, server.URL())),
  2011  		fakecontext.WithFiles(map[string]string{
  2012  			"foo": "hello world",
  2013  		}))
  2014  	defer ctx.Close()
  2015  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  2016  	id1 := getIDByName(c, name)
  2017  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  2018  	id2 := getIDByName(c, name)
  2019  	buildImageSuccessfully(c, name, build.WithoutCache, build.WithExternalBuildContext(ctx))
  2020  	id3 := getIDByName(c, name)
  2021  	if id1 != id2 {
  2022  		c.Fatal("The cache should have been used but hasn't.")
  2023  	}
  2024  	if id1 == id3 {
  2025  		c.Fatal("The cache should have been invalidated but hasn't.")
  2026  	}
  2027  }
  2028  
  2029  func testContextTar(c *check.C, compression archive.Compression) {
  2030  	ctx := fakecontext.New(c, "",
  2031  		fakecontext.WithDockerfile(`FROM busybox
  2032  ADD foo /foo
  2033  CMD ["cat", "/foo"]`),
  2034  		fakecontext.WithFiles(map[string]string{
  2035  			"foo": "bar",
  2036  		}),
  2037  	)
  2038  	defer ctx.Close()
  2039  	context, err := archive.Tar(ctx.Dir, compression)
  2040  	if err != nil {
  2041  		c.Fatalf("failed to build context tar: %v", err)
  2042  	}
  2043  	name := "contexttar"
  2044  
  2045  	cli.BuildCmd(c, name, build.WithStdinContext(context))
  2046  }
  2047  
  2048  func (s *DockerSuite) TestBuildContextTarGzip(c *check.C) {
  2049  	testContextTar(c, archive.Gzip)
  2050  }
  2051  
  2052  func (s *DockerSuite) TestBuildContextTarNoCompression(c *check.C) {
  2053  	testContextTar(c, archive.Uncompressed)
  2054  }
  2055  
  2056  func (s *DockerSuite) TestBuildNoContext(c *check.C) {
  2057  	name := "nocontext"
  2058  	icmd.RunCmd(icmd.Cmd{
  2059  		Command: []string{dockerBinary, "build", "-t", name, "-"},
  2060  		Stdin: strings.NewReader(
  2061  			`FROM busybox
  2062  			CMD ["echo", "ok"]`),
  2063  	}).Assert(c, icmd.Success)
  2064  
  2065  	if out, _ := dockerCmd(c, "run", "--rm", "nocontext"); out != "ok\n" {
  2066  		c.Fatalf("run produced invalid output: %q, expected %q", out, "ok")
  2067  	}
  2068  }
  2069  
  2070  // FIXME(vdemeester) migrate to docker/cli e2e
  2071  func (s *DockerSuite) TestBuildDockerfileStdin(c *check.C) {
  2072  	name := "stdindockerfile"
  2073  	tmpDir, err := ioutil.TempDir("", "fake-context")
  2074  	c.Assert(err, check.IsNil)
  2075  	err = ioutil.WriteFile(filepath.Join(tmpDir, "foo"), []byte("bar"), 0600)
  2076  	c.Assert(err, check.IsNil)
  2077  
  2078  	icmd.RunCmd(icmd.Cmd{
  2079  		Command: []string{dockerBinary, "build", "-t", name, "-f", "-", tmpDir},
  2080  		Stdin: strings.NewReader(
  2081  			`FROM busybox
  2082  ADD foo /foo
  2083  CMD ["cat", "/foo"]`),
  2084  	}).Assert(c, icmd.Success)
  2085  
  2086  	res := inspectField(c, name, "Config.Cmd")
  2087  	c.Assert(strings.TrimSpace(string(res)), checker.Equals, `[cat /foo]`)
  2088  }
  2089  
  2090  // FIXME(vdemeester) migrate to docker/cli tests (unit or e2e)
  2091  func (s *DockerSuite) TestBuildDockerfileStdinConflict(c *check.C) {
  2092  	name := "stdindockerfiletarcontext"
  2093  	icmd.RunCmd(icmd.Cmd{
  2094  		Command: []string{dockerBinary, "build", "-t", name, "-f", "-", "-"},
  2095  	}).Assert(c, icmd.Expected{
  2096  		ExitCode: 1,
  2097  		Err:      "use stdin for both build context and dockerfile",
  2098  	})
  2099  }
  2100  
  2101  func (s *DockerSuite) TestBuildDockerfileStdinNoExtraFiles(c *check.C) {
  2102  	s.testBuildDockerfileStdinNoExtraFiles(c, false, false)
  2103  }
  2104  
  2105  func (s *DockerSuite) TestBuildDockerfileStdinDockerignore(c *check.C) {
  2106  	s.testBuildDockerfileStdinNoExtraFiles(c, true, false)
  2107  }
  2108  
  2109  func (s *DockerSuite) TestBuildDockerfileStdinDockerignoreIgnored(c *check.C) {
  2110  	s.testBuildDockerfileStdinNoExtraFiles(c, true, true)
  2111  }
  2112  
  2113  func (s *DockerSuite) testBuildDockerfileStdinNoExtraFiles(c *check.C, hasDockerignore, ignoreDockerignore bool) {
  2114  	name := "stdindockerfilenoextra"
  2115  	tmpDir, err := ioutil.TempDir("", "fake-context")
  2116  	c.Assert(err, check.IsNil)
  2117  	defer os.RemoveAll(tmpDir)
  2118  
  2119  	writeFile := func(filename, content string) {
  2120  		err = ioutil.WriteFile(filepath.Join(tmpDir, filename), []byte(content), 0600)
  2121  		c.Assert(err, check.IsNil)
  2122  	}
  2123  
  2124  	writeFile("foo", "bar")
  2125  
  2126  	if hasDockerignore {
  2127  		// Add an empty Dockerfile to verify that it is not added to the image
  2128  		writeFile("Dockerfile", "")
  2129  
  2130  		ignores := "Dockerfile\n"
  2131  		if ignoreDockerignore {
  2132  			ignores += ".dockerignore\n"
  2133  		}
  2134  		writeFile(".dockerignore", ignores)
  2135  	}
  2136  
  2137  	result := icmd.RunCmd(icmd.Cmd{
  2138  		Command: []string{dockerBinary, "build", "-t", name, "-f", "-", tmpDir},
  2139  		Stdin: strings.NewReader(
  2140  			`FROM busybox
  2141  COPY . /baz`),
  2142  	})
  2143  	result.Assert(c, icmd.Success)
  2144  
  2145  	result = cli.DockerCmd(c, "run", "--rm", name, "ls", "-A", "/baz")
  2146  	if hasDockerignore && !ignoreDockerignore {
  2147  		c.Assert(result.Stdout(), checker.Equals, ".dockerignore\nfoo\n")
  2148  	} else {
  2149  		c.Assert(result.Stdout(), checker.Equals, "foo\n")
  2150  	}
  2151  }
  2152  
  2153  func (s *DockerSuite) TestBuildWithVolumeOwnership(c *check.C) {
  2154  	testRequires(c, DaemonIsLinux)
  2155  	name := "testbuildimg"
  2156  
  2157  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox:latest
  2158          RUN mkdir /test && chown daemon:daemon /test && chmod 0600 /test
  2159          VOLUME /test`))
  2160  
  2161  	out, _ := dockerCmd(c, "run", "--rm", "testbuildimg", "ls", "-la", "/test")
  2162  	if expected := "drw-------"; !strings.Contains(out, expected) {
  2163  		c.Fatalf("expected %s received %s", expected, out)
  2164  	}
  2165  	if expected := "daemon   daemon"; !strings.Contains(out, expected) {
  2166  		c.Fatalf("expected %s received %s", expected, out)
  2167  	}
  2168  
  2169  }
  2170  
  2171  // testing #1405 - config.Cmd does not get cleaned up if
  2172  // utilizing cache
  2173  func (s *DockerSuite) TestBuildEntrypointRunCleanup(c *check.C) {
  2174  	name := "testbuildcmdcleanup"
  2175  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  2176          RUN echo "hello"`))
  2177  
  2178  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2179  		build.WithFile("Dockerfile", `FROM busybox
  2180          RUN echo "hello"
  2181          ADD foo /foo
  2182          ENTRYPOINT ["/bin/echo"]`),
  2183  		build.WithFile("foo", "hello")))
  2184  
  2185  	res := inspectField(c, name, "Config.Cmd")
  2186  	// Cmd must be cleaned up
  2187  	if res != "[]" {
  2188  		c.Fatalf("Cmd %s, expected nil", res)
  2189  	}
  2190  }
  2191  
  2192  func (s *DockerSuite) TestBuildAddFileNotFound(c *check.C) {
  2193  	name := "testbuildaddnotfound"
  2194  	expected := "foo: no such file or directory"
  2195  
  2196  	if testEnv.OSType == "windows" {
  2197  		expected = "foo: The system cannot find the file specified"
  2198  	}
  2199  
  2200  	buildImage(name, build.WithBuildContext(c,
  2201  		build.WithFile("Dockerfile", `FROM `+minimalBaseImage()+`
  2202          ADD foo /usr/local/bar`),
  2203  		build.WithFile("bar", "hello"))).Assert(c, icmd.Expected{
  2204  		ExitCode: 1,
  2205  		Err:      expected,
  2206  	})
  2207  }
  2208  
  2209  func (s *DockerSuite) TestBuildInheritance(c *check.C) {
  2210  	testRequires(c, DaemonIsLinux)
  2211  	name := "testbuildinheritance"
  2212  
  2213  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM scratch
  2214  		EXPOSE 2375`))
  2215  	ports1 := inspectField(c, name, "Config.ExposedPorts")
  2216  
  2217  	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM %s
  2218  		ENTRYPOINT ["/bin/echo"]`, name)))
  2219  
  2220  	res := inspectField(c, name, "Config.Entrypoint")
  2221  	if expected := "[/bin/echo]"; res != expected {
  2222  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  2223  	}
  2224  	ports2 := inspectField(c, name, "Config.ExposedPorts")
  2225  	if ports1 != ports2 {
  2226  		c.Fatalf("Ports must be same: %s != %s", ports1, ports2)
  2227  	}
  2228  }
  2229  
  2230  func (s *DockerSuite) TestBuildFails(c *check.C) {
  2231  	name := "testbuildfails"
  2232  	buildImage(name, build.WithDockerfile(`FROM busybox
  2233  		RUN sh -c "exit 23"`)).Assert(c, icmd.Expected{
  2234  		ExitCode: 23,
  2235  		Err:      "returned a non-zero code: 23",
  2236  	})
  2237  }
  2238  
  2239  func (s *DockerSuite) TestBuildOnBuild(c *check.C) {
  2240  	name := "testbuildonbuild"
  2241  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  2242  		ONBUILD RUN touch foobar`))
  2243  	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM %s
  2244  		RUN [ -f foobar ]`, name)))
  2245  }
  2246  
  2247  // gh #2446
  2248  func (s *DockerSuite) TestBuildAddToSymlinkDest(c *check.C) {
  2249  	makeLink := `ln -s /foo /bar`
  2250  	if testEnv.OSType == "windows" {
  2251  		makeLink = `mklink /D C:\bar C:\foo`
  2252  	}
  2253  	name := "testbuildaddtosymlinkdest"
  2254  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2255  		build.WithFile("Dockerfile", `
  2256  		FROM busybox
  2257  		RUN sh -c "mkdir /foo"
  2258  		RUN `+makeLink+`
  2259  		ADD foo /bar/
  2260  		RUN sh -c "[ -f /bar/foo ]"
  2261  		RUN sh -c "[ -f /foo/foo ]"`),
  2262  		build.WithFile("foo", "hello"),
  2263  	))
  2264  }
  2265  
  2266  func (s *DockerSuite) TestBuildEscapeWhitespace(c *check.C) {
  2267  	name := "testbuildescapewhitespace"
  2268  
  2269  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  2270    # ESCAPE=\
  2271    FROM busybox
  2272    MAINTAINER "Docker \
  2273  IO <io@\
  2274  docker.com>"
  2275    `))
  2276  
  2277  	res := inspectField(c, name, "Author")
  2278  	if res != "\"Docker IO <io@docker.com>\"" {
  2279  		c.Fatalf("Parsed string did not match the escaped string. Got: %q", res)
  2280  	}
  2281  
  2282  }
  2283  
  2284  func (s *DockerSuite) TestBuildVerifyIntString(c *check.C) {
  2285  	// Verify that strings that look like ints are still passed as strings
  2286  	name := "testbuildstringing"
  2287  
  2288  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  2289  	FROM busybox
  2290  	MAINTAINER 123`))
  2291  
  2292  	out, _ := dockerCmd(c, "inspect", name)
  2293  	if !strings.Contains(out, "\"123\"") {
  2294  		c.Fatalf("Output does not contain the int as a string:\n%s", out)
  2295  	}
  2296  
  2297  }
  2298  
  2299  func (s *DockerSuite) TestBuildDockerignore(c *check.C) {
  2300  	name := "testbuilddockerignore"
  2301  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2302  		build.WithFile("Dockerfile", `
  2303  		FROM busybox
  2304  		 ADD . /bla
  2305  		RUN sh -c "[[ -f /bla/src/x.go ]]"
  2306  		RUN sh -c "[[ -f /bla/Makefile ]]"
  2307  		RUN sh -c "[[ ! -e /bla/src/_vendor ]]"
  2308  		RUN sh -c "[[ ! -e /bla/.gitignore ]]"
  2309  		RUN sh -c "[[ ! -e /bla/README.md ]]"
  2310  		RUN sh -c "[[ ! -e /bla/dir/foo ]]"
  2311  		RUN sh -c "[[ ! -e /bla/foo ]]"
  2312  		RUN sh -c "[[ ! -e /bla/.git ]]"
  2313  		RUN sh -c "[[ ! -e v.cc ]]"
  2314  		RUN sh -c "[[ ! -e src/v.cc ]]"
  2315  		RUN sh -c "[[ ! -e src/_vendor/v.cc ]]"`),
  2316  		build.WithFile("Makefile", "all:"),
  2317  		build.WithFile(".git/HEAD", "ref: foo"),
  2318  		build.WithFile("src/x.go", "package main"),
  2319  		build.WithFile("src/_vendor/v.go", "package main"),
  2320  		build.WithFile("src/_vendor/v.cc", "package main"),
  2321  		build.WithFile("src/v.cc", "package main"),
  2322  		build.WithFile("v.cc", "package main"),
  2323  		build.WithFile("dir/foo", ""),
  2324  		build.WithFile(".gitignore", ""),
  2325  		build.WithFile("README.md", "readme"),
  2326  		build.WithFile(".dockerignore", `
  2327  .git
  2328  pkg
  2329  .gitignore
  2330  src/_vendor
  2331  *.md
  2332  **/*.cc
  2333  dir`),
  2334  	))
  2335  }
  2336  
  2337  func (s *DockerSuite) TestBuildDockerignoreCleanPaths(c *check.C) {
  2338  	name := "testbuilddockerignorecleanpaths"
  2339  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2340  		build.WithFile("Dockerfile", `
  2341          FROM busybox
  2342          ADD . /tmp/
  2343          RUN sh -c "(! ls /tmp/foo) && (! ls /tmp/foo2) && (! ls /tmp/dir1/foo)"`),
  2344  		build.WithFile("foo", "foo"),
  2345  		build.WithFile("foo2", "foo2"),
  2346  		build.WithFile("dir1/foo", "foo in dir1"),
  2347  		build.WithFile(".dockerignore", "./foo\ndir1//foo\n./dir1/../foo2"),
  2348  	))
  2349  }
  2350  
  2351  func (s *DockerSuite) TestBuildDockerignoreExceptions(c *check.C) {
  2352  	name := "testbuilddockerignoreexceptions"
  2353  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2354  		build.WithFile("Dockerfile", `
  2355  		FROM busybox
  2356  		ADD . /bla
  2357  		RUN sh -c "[[ -f /bla/src/x.go ]]"
  2358  		RUN sh -c "[[ -f /bla/Makefile ]]"
  2359  		RUN sh -c "[[ ! -e /bla/src/_vendor ]]"
  2360  		RUN sh -c "[[ ! -e /bla/.gitignore ]]"
  2361  		RUN sh -c "[[ ! -e /bla/README.md ]]"
  2362  		RUN sh -c "[[  -e /bla/dir/dir/foo ]]"
  2363  		RUN sh -c "[[ ! -e /bla/dir/foo1 ]]"
  2364  		RUN sh -c "[[ -f /bla/dir/e ]]"
  2365  		RUN sh -c "[[ -f /bla/dir/e-dir/foo ]]"
  2366  		RUN sh -c "[[ ! -e /bla/foo ]]"
  2367  		RUN sh -c "[[ ! -e /bla/.git ]]"
  2368  		RUN sh -c "[[ -e /bla/dir/a.cc ]]"`),
  2369  		build.WithFile("Makefile", "all:"),
  2370  		build.WithFile(".git/HEAD", "ref: foo"),
  2371  		build.WithFile("src/x.go", "package main"),
  2372  		build.WithFile("src/_vendor/v.go", "package main"),
  2373  		build.WithFile("dir/foo", ""),
  2374  		build.WithFile("dir/foo1", ""),
  2375  		build.WithFile("dir/dir/f1", ""),
  2376  		build.WithFile("dir/dir/foo", ""),
  2377  		build.WithFile("dir/e", ""),
  2378  		build.WithFile("dir/e-dir/foo", ""),
  2379  		build.WithFile(".gitignore", ""),
  2380  		build.WithFile("README.md", "readme"),
  2381  		build.WithFile("dir/a.cc", "hello"),
  2382  		build.WithFile(".dockerignore", `
  2383  .git
  2384  pkg
  2385  .gitignore
  2386  src/_vendor
  2387  *.md
  2388  dir
  2389  !dir/e*
  2390  !dir/dir/foo
  2391  **/*.cc
  2392  !**/*.cc`),
  2393  	))
  2394  }
  2395  
  2396  func (s *DockerSuite) TestBuildDockerignoringDockerfile(c *check.C) {
  2397  	name := "testbuilddockerignoredockerfile"
  2398  	dockerfile := `
  2399  		FROM busybox
  2400  		ADD . /tmp/
  2401  		RUN sh -c "! ls /tmp/Dockerfile"
  2402  		RUN ls /tmp/.dockerignore`
  2403  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2404  		build.WithFile("Dockerfile", dockerfile),
  2405  		build.WithFile(".dockerignore", "Dockerfile\n"),
  2406  	))
  2407  	// FIXME(vdemeester) why twice ?
  2408  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2409  		build.WithFile("Dockerfile", dockerfile),
  2410  		build.WithFile(".dockerignore", "./Dockerfile\n"),
  2411  	))
  2412  }
  2413  
  2414  func (s *DockerSuite) TestBuildDockerignoringRenamedDockerfile(c *check.C) {
  2415  	name := "testbuilddockerignoredockerfile"
  2416  	dockerfile := `
  2417  		FROM busybox
  2418  		ADD . /tmp/
  2419  		RUN ls /tmp/Dockerfile
  2420  		RUN sh -c "! ls /tmp/MyDockerfile"
  2421  		RUN ls /tmp/.dockerignore`
  2422  	buildImageSuccessfully(c, name, cli.WithFlags("-f", "MyDockerfile"), build.WithBuildContext(c,
  2423  		build.WithFile("Dockerfile", "Should not use me"),
  2424  		build.WithFile("MyDockerfile", dockerfile),
  2425  		build.WithFile(".dockerignore", "MyDockerfile\n"),
  2426  	))
  2427  	// FIXME(vdemeester) why twice ?
  2428  	buildImageSuccessfully(c, name, cli.WithFlags("-f", "MyDockerfile"), build.WithBuildContext(c,
  2429  		build.WithFile("Dockerfile", "Should not use me"),
  2430  		build.WithFile("MyDockerfile", dockerfile),
  2431  		build.WithFile(".dockerignore", "./MyDockerfile\n"),
  2432  	))
  2433  }
  2434  
  2435  func (s *DockerSuite) TestBuildDockerignoringDockerignore(c *check.C) {
  2436  	name := "testbuilddockerignoredockerignore"
  2437  	dockerfile := `
  2438  		FROM busybox
  2439  		ADD . /tmp/
  2440  		RUN sh -c "! ls /tmp/.dockerignore"
  2441  		RUN ls /tmp/Dockerfile`
  2442  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2443  		build.WithFile("Dockerfile", dockerfile),
  2444  		build.WithFile(".dockerignore", ".dockerignore\n"),
  2445  	))
  2446  }
  2447  
  2448  func (s *DockerSuite) TestBuildDockerignoreTouchDockerfile(c *check.C) {
  2449  	name := "testbuilddockerignoretouchdockerfile"
  2450  	dockerfile := `
  2451          FROM busybox
  2452  		ADD . /tmp/`
  2453  	ctx := fakecontext.New(c, "",
  2454  		fakecontext.WithDockerfile(dockerfile),
  2455  		fakecontext.WithFiles(map[string]string{
  2456  			".dockerignore": "Dockerfile\n",
  2457  		}))
  2458  	defer ctx.Close()
  2459  
  2460  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  2461  	id1 := getIDByName(c, name)
  2462  
  2463  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  2464  	id2 := getIDByName(c, name)
  2465  	if id1 != id2 {
  2466  		c.Fatalf("Didn't use the cache - 1")
  2467  	}
  2468  
  2469  	// Now make sure touching Dockerfile doesn't invalidate the cache
  2470  	if err := ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
  2471  		c.Fatalf("Didn't add Dockerfile: %s", err)
  2472  	}
  2473  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  2474  	id2 = getIDByName(c, name)
  2475  	if id1 != id2 {
  2476  		c.Fatalf("Didn't use the cache - 2")
  2477  	}
  2478  
  2479  	// One more time but just 'touch' it instead of changing the content
  2480  	if err := ctx.Add("Dockerfile", dockerfile+"\n# hi"); err != nil {
  2481  		c.Fatalf("Didn't add Dockerfile: %s", err)
  2482  	}
  2483  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  2484  	id2 = getIDByName(c, name)
  2485  	if id1 != id2 {
  2486  		c.Fatalf("Didn't use the cache - 3")
  2487  	}
  2488  }
  2489  
  2490  func (s *DockerSuite) TestBuildDockerignoringWholeDir(c *check.C) {
  2491  	name := "testbuilddockerignorewholedir"
  2492  
  2493  	dockerfile := `
  2494  		FROM busybox
  2495  		COPY . /
  2496  		RUN sh -c "[[ ! -e /.gitignore ]]"
  2497  		RUN sh -c "[[ ! -e /Makefile ]]"`
  2498  
  2499  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2500  		build.WithFile("Dockerfile", dockerfile),
  2501  		build.WithFile(".dockerignore", "*\n"),
  2502  		build.WithFile("Makefile", "all:"),
  2503  		build.WithFile(".gitignore", ""),
  2504  	))
  2505  }
  2506  
  2507  func (s *DockerSuite) TestBuildDockerignoringOnlyDotfiles(c *check.C) {
  2508  	name := "testbuilddockerignorewholedir"
  2509  
  2510  	dockerfile := `
  2511  		FROM busybox
  2512  		COPY . /
  2513  		RUN sh -c "[[ ! -e /.gitignore ]]"
  2514  		RUN sh -c "[[ -f /Makefile ]]"`
  2515  
  2516  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2517  		build.WithFile("Dockerfile", dockerfile),
  2518  		build.WithFile(".dockerignore", ".*"),
  2519  		build.WithFile("Makefile", "all:"),
  2520  		build.WithFile(".gitignore", ""),
  2521  	))
  2522  }
  2523  
  2524  func (s *DockerSuite) TestBuildDockerignoringBadExclusion(c *check.C) {
  2525  	name := "testbuilddockerignorebadexclusion"
  2526  	buildImage(name, build.WithBuildContext(c,
  2527  		build.WithFile("Dockerfile", `
  2528  		FROM busybox
  2529  		COPY . /
  2530  		RUN sh -c "[[ ! -e /.gitignore ]]"
  2531  		RUN sh -c "[[ -f /Makefile ]]"`),
  2532  		build.WithFile("Makefile", "all:"),
  2533  		build.WithFile(".gitignore", ""),
  2534  		build.WithFile(".dockerignore", "!\n"),
  2535  	)).Assert(c, icmd.Expected{
  2536  		ExitCode: 1,
  2537  		Err:      "error checking context: 'illegal exclusion pattern: \"!\"",
  2538  	})
  2539  }
  2540  
  2541  func (s *DockerSuite) TestBuildDockerignoringWildTopDir(c *check.C) {
  2542  	dockerfile := `
  2543  		FROM busybox
  2544  		COPY . /
  2545  		RUN sh -c "[[ ! -e /.dockerignore ]]"
  2546  		RUN sh -c "[[ ! -e /Dockerfile ]]"
  2547  		RUN sh -c "[[ ! -e /file1 ]]"
  2548  		RUN sh -c "[[ ! -e /dir ]]"`
  2549  
  2550  	// All of these should result in ignoring all files
  2551  	for _, variant := range []string{"**", "**/", "**/**", "*"} {
  2552  		buildImageSuccessfully(c, "noname", build.WithBuildContext(c,
  2553  			build.WithFile("Dockerfile", dockerfile),
  2554  			build.WithFile("file1", ""),
  2555  			build.WithFile("dir/file1", ""),
  2556  			build.WithFile(".dockerignore", variant),
  2557  		))
  2558  
  2559  		dockerCmd(c, "rmi", "noname")
  2560  	}
  2561  }
  2562  
  2563  func (s *DockerSuite) TestBuildDockerignoringWildDirs(c *check.C) {
  2564  	dockerfile := `
  2565          FROM busybox
  2566  		COPY . /
  2567  		#RUN sh -c "[[ -e /.dockerignore ]]"
  2568  		RUN sh -c "[[ -e /Dockerfile ]]           && \
  2569  		           [[ ! -e /file0 ]]              && \
  2570  		           [[ ! -e /dir1/file0 ]]         && \
  2571  		           [[ ! -e /dir2/file0 ]]         && \
  2572  		           [[ ! -e /file1 ]]              && \
  2573  		           [[ ! -e /dir1/file1 ]]         && \
  2574  		           [[ ! -e /dir1/dir2/file1 ]]    && \
  2575  		           [[ ! -e /dir1/file2 ]]         && \
  2576  		           [[   -e /dir1/dir2/file2 ]]    && \
  2577  		           [[ ! -e /dir1/dir2/file4 ]]    && \
  2578  		           [[ ! -e /dir1/dir2/file5 ]]    && \
  2579  		           [[ ! -e /dir1/dir2/file6 ]]    && \
  2580  		           [[ ! -e /dir1/dir3/file7 ]]    && \
  2581  		           [[ ! -e /dir1/dir3/file8 ]]    && \
  2582  		           [[   -e /dir1/dir3 ]]          && \
  2583  		           [[   -e /dir1/dir4 ]]          && \
  2584  		           [[ ! -e 'dir1/dir5/fileAA' ]]  && \
  2585  		           [[   -e 'dir1/dir5/fileAB' ]]  && \
  2586  		           [[   -e 'dir1/dir5/fileB' ]]"   # "." in pattern means nothing
  2587  
  2588  		RUN echo all done!`
  2589  
  2590  	dockerignore := `
  2591  **/file0
  2592  **/*file1
  2593  **/dir1/file2
  2594  dir1/**/file4
  2595  **/dir2/file5
  2596  **/dir1/dir2/file6
  2597  dir1/dir3/**
  2598  **/dir4/**
  2599  **/file?A
  2600  **/file\?B
  2601  **/dir5/file.
  2602  `
  2603  
  2604  	buildImageSuccessfully(c, "noname", build.WithBuildContext(c,
  2605  		build.WithFile("Dockerfile", dockerfile),
  2606  		build.WithFile(".dockerignore", dockerignore),
  2607  		build.WithFile("dir1/file0", ""),
  2608  		build.WithFile("dir1/dir2/file0", ""),
  2609  		build.WithFile("file1", ""),
  2610  		build.WithFile("dir1/file1", ""),
  2611  		build.WithFile("dir1/dir2/file1", ""),
  2612  		build.WithFile("dir1/file2", ""),
  2613  		build.WithFile("dir1/dir2/file2", ""), // remains
  2614  		build.WithFile("dir1/dir2/file4", ""),
  2615  		build.WithFile("dir1/dir2/file5", ""),
  2616  		build.WithFile("dir1/dir2/file6", ""),
  2617  		build.WithFile("dir1/dir3/file7", ""),
  2618  		build.WithFile("dir1/dir3/file8", ""),
  2619  		build.WithFile("dir1/dir4/file9", ""),
  2620  		build.WithFile("dir1/dir5/fileAA", ""),
  2621  		build.WithFile("dir1/dir5/fileAB", ""),
  2622  		build.WithFile("dir1/dir5/fileB", ""),
  2623  	))
  2624  }
  2625  
  2626  func (s *DockerSuite) TestBuildLineBreak(c *check.C) {
  2627  	testRequires(c, DaemonIsLinux)
  2628  	name := "testbuildlinebreak"
  2629  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM  busybox
  2630  RUN    sh -c 'echo root:testpass \
  2631  	> /tmp/passwd'
  2632  RUN    mkdir -p /var/run/sshd
  2633  RUN    sh -c "[ "$(cat /tmp/passwd)" = "root:testpass" ]"
  2634  RUN    sh -c "[ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]"`))
  2635  }
  2636  
  2637  func (s *DockerSuite) TestBuildEOLInLine(c *check.C) {
  2638  	testRequires(c, DaemonIsLinux)
  2639  	name := "testbuildeolinline"
  2640  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM   busybox
  2641  RUN    sh -c 'echo root:testpass > /tmp/passwd'
  2642  RUN    echo "foo \n bar"; echo "baz"
  2643  RUN    mkdir -p /var/run/sshd
  2644  RUN    sh -c "[ "$(cat /tmp/passwd)" = "root:testpass" ]"
  2645  RUN    sh -c "[ "$(ls -d /var/run/sshd)" = "/var/run/sshd" ]"`))
  2646  }
  2647  
  2648  func (s *DockerSuite) TestBuildCommentsShebangs(c *check.C) {
  2649  	testRequires(c, DaemonIsLinux)
  2650  	name := "testbuildcomments"
  2651  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  2652  # This is an ordinary comment.
  2653  RUN { echo '#!/bin/sh'; echo 'echo hello world'; } > /hello.sh
  2654  RUN [ ! -x /hello.sh ]
  2655  # comment with line break \
  2656  RUN chmod +x /hello.sh
  2657  RUN [ -x /hello.sh ]
  2658  RUN [ "$(cat /hello.sh)" = $'#!/bin/sh\necho hello world' ]
  2659  RUN [ "$(/hello.sh)" = "hello world" ]`))
  2660  }
  2661  
  2662  func (s *DockerSuite) TestBuildUsersAndGroups(c *check.C) {
  2663  	testRequires(c, DaemonIsLinux)
  2664  	name := "testbuildusers"
  2665  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  2666  
  2667  # Make sure our defaults work
  2668  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)" = '0:0/root:root' ]
  2669  
  2670  # 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)
  2671  USER root
  2672  RUN [ "$(id -G):$(id -Gn)" = '0 10:root wheel' ]
  2673  
  2674  # Setup dockerio user and group
  2675  RUN echo 'dockerio:x:1001:1001::/bin:/bin/false' >> /etc/passwd && \
  2676  	echo 'dockerio:x:1001:' >> /etc/group
  2677  
  2678  # Make sure we can switch to our user and all the information is exactly as we expect it to be
  2679  USER dockerio
  2680  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2681  
  2682  # Switch back to root and double check that worked exactly as we might expect it to
  2683  USER root
  2684  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '0:0/root:root/0 10:root wheel' ] && \
  2685          # Add a "supplementary" group for our dockerio user
  2686  	echo 'supplementary:x:1002:dockerio' >> /etc/group
  2687  
  2688  # ... and then go verify that we get it like we expect
  2689  USER dockerio
  2690  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ]
  2691  USER 1001
  2692  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001 1002:dockerio supplementary' ]
  2693  
  2694  # super test the new "user:group" syntax
  2695  USER dockerio:dockerio
  2696  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2697  USER 1001:dockerio
  2698  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2699  USER dockerio:1001
  2700  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2701  USER 1001:1001
  2702  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1001/dockerio:dockerio/1001:dockerio' ]
  2703  USER dockerio:supplementary
  2704  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
  2705  USER dockerio:1002
  2706  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
  2707  USER 1001:supplementary
  2708  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
  2709  USER 1001:1002
  2710  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1001:1002/dockerio:supplementary/1002:supplementary' ]
  2711  
  2712  # make sure unknown uid/gid still works properly
  2713  USER 1042:1043
  2714  RUN [ "$(id -u):$(id -g)/$(id -un):$(id -gn)/$(id -G):$(id -Gn)" = '1042:1043/1042:1043/1043:1043' ]`))
  2715  }
  2716  
  2717  // FIXME(vdemeester) rename this test (and probably "merge" it with the one below TestBuildEnvUsage2)
  2718  func (s *DockerSuite) TestBuildEnvUsage(c *check.C) {
  2719  	// /docker/world/hello is not owned by the correct user
  2720  	testRequires(c, NotUserNamespace)
  2721  	testRequires(c, DaemonIsLinux)
  2722  	name := "testbuildenvusage"
  2723  	dockerfile := `FROM busybox
  2724  ENV    HOME /root
  2725  ENV    PATH $HOME/bin:$PATH
  2726  ENV    PATH /tmp:$PATH
  2727  RUN    [ "$PATH" = "/tmp:$HOME/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ]
  2728  ENV    FOO /foo/baz
  2729  ENV    BAR /bar
  2730  ENV    BAZ $BAR
  2731  ENV    FOOPATH $PATH:$FOO
  2732  RUN    [ "$BAR" = "$BAZ" ]
  2733  RUN    [ "$FOOPATH" = "$PATH:/foo/baz" ]
  2734  ENV    FROM hello/docker/world
  2735  ENV    TO /docker/world/hello
  2736  ADD    $FROM $TO
  2737  RUN    [ "$(cat $TO)" = "hello" ]
  2738  ENV    abc=def
  2739  ENV    ghi=$abc
  2740  RUN    [ "$ghi" = "def" ]
  2741  `
  2742  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2743  		build.WithFile("Dockerfile", dockerfile),
  2744  		build.WithFile("hello/docker/world", "hello"),
  2745  	))
  2746  }
  2747  
  2748  // FIXME(vdemeester) rename this test (and probably "merge" it with the one above TestBuildEnvUsage)
  2749  func (s *DockerSuite) TestBuildEnvUsage2(c *check.C) {
  2750  	// /docker/world/hello is not owned by the correct user
  2751  	testRequires(c, NotUserNamespace)
  2752  	testRequires(c, DaemonIsLinux)
  2753  	name := "testbuildenvusage2"
  2754  	dockerfile := `FROM busybox
  2755  ENV    abc=def def="hello world"
  2756  RUN    [ "$abc,$def" = "def,hello world" ]
  2757  ENV    def=hello\ world v1=abc v2="hi there" v3='boogie nights' v4="with'quotes too"
  2758  RUN    [ "$def,$v1,$v2,$v3,$v4" = "hello world,abc,hi there,boogie nights,with'quotes too" ]
  2759  ENV    abc=zzz FROM=hello/docker/world
  2760  ENV    abc=zzz TO=/docker/world/hello
  2761  ADD    $FROM $TO
  2762  RUN    [ "$abc,$(cat $TO)" = "zzz,hello" ]
  2763  ENV    abc 'yyy'
  2764  RUN    [ $abc = 'yyy' ]
  2765  ENV    abc=
  2766  RUN    [ "$abc" = "" ]
  2767  
  2768  # use grep to make sure if the builder substitutes \$foo by mistake
  2769  # we don't get a false positive
  2770  ENV    abc=\$foo
  2771  RUN    [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo)
  2772  ENV    abc \$foo
  2773  RUN    [ "$abc" = "\$foo" ] && (echo "$abc" | grep foo)
  2774  
  2775  ENV    abc=\'foo\' abc2=\"foo\"
  2776  RUN    [ "$abc,$abc2" = "'foo',\"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  ENV    abc \"foo\"
  2784  RUN    [ "$abc" = '"foo"' ]
  2785  
  2786  ENV    abc=ABC
  2787  RUN    [ "$abc" = "ABC" ]
  2788  ENV    def1=${abc:-DEF} def2=${ccc:-DEF}
  2789  ENV    def3=${ccc:-${def2}xx} def4=${abc:+ALT} def5=${def2:+${abc}:} def6=${ccc:-\$abc:} def7=${ccc:-\${abc}:}
  2790  RUN    [ "$def1,$def2,$def3,$def4,$def5,$def6,$def7" = 'ABC,DEF,DEFxx,ALT,ABC:,$abc:,${abc:}' ]
  2791  ENV    mypath=${mypath:+$mypath:}/home
  2792  ENV    mypath=${mypath:+$mypath:}/away
  2793  RUN    [ "$mypath" = '/home:/away' ]
  2794  
  2795  ENV    e1=bar
  2796  ENV    e2=$e1 e3=$e11 e4=\$e1 e5=\$e11
  2797  RUN    [ "$e0,$e1,$e2,$e3,$e4,$e5" = ',bar,bar,,$e1,$e11' ]
  2798  
  2799  ENV    ee1 bar
  2800  ENV    ee2 $ee1
  2801  ENV    ee3 $ee11
  2802  ENV    ee4 \$ee1
  2803  ENV    ee5 \$ee11
  2804  RUN    [ "$ee1,$ee2,$ee3,$ee4,$ee5" = 'bar,bar,,$ee1,$ee11' ]
  2805  
  2806  ENV    eee1="foo" eee2='foo'
  2807  ENV    eee3 "foo"
  2808  ENV    eee4 'foo'
  2809  RUN    [ "$eee1,$eee2,$eee3,$eee4" = 'foo,foo,foo,foo' ]
  2810  
  2811  `
  2812  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2813  		build.WithFile("Dockerfile", dockerfile),
  2814  		build.WithFile("hello/docker/world", "hello"),
  2815  	))
  2816  }
  2817  
  2818  func (s *DockerSuite) TestBuildAddScript(c *check.C) {
  2819  	testRequires(c, DaemonIsLinux)
  2820  	name := "testbuildaddscript"
  2821  	dockerfile := `
  2822  FROM busybox
  2823  ADD test /test
  2824  RUN ["chmod","+x","/test"]
  2825  RUN ["/test"]
  2826  RUN [ "$(cat /testfile)" = 'test!' ]`
  2827  
  2828  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2829  		build.WithFile("Dockerfile", dockerfile),
  2830  		build.WithFile("test", "#!/bin/sh\necho 'test!' > /testfile"),
  2831  	))
  2832  }
  2833  
  2834  func (s *DockerSuite) TestBuildAddTar(c *check.C) {
  2835  	// /test/foo is not owned by the correct user
  2836  	testRequires(c, NotUserNamespace)
  2837  	name := "testbuildaddtar"
  2838  
  2839  	ctx := func() *fakecontext.Fake {
  2840  		dockerfile := `
  2841  FROM busybox
  2842  ADD test.tar /
  2843  RUN cat /test/foo | grep Hi
  2844  ADD test.tar /test.tar
  2845  RUN cat /test.tar/test/foo | grep Hi
  2846  ADD test.tar /unlikely-to-exist
  2847  RUN cat /unlikely-to-exist/test/foo | grep Hi
  2848  ADD test.tar /unlikely-to-exist-trailing-slash/
  2849  RUN cat /unlikely-to-exist-trailing-slash/test/foo | grep Hi
  2850  RUN sh -c "mkdir /existing-directory" #sh -c is needed on Windows to use the correct mkdir
  2851  ADD test.tar /existing-directory
  2852  RUN cat /existing-directory/test/foo | grep Hi
  2853  ADD test.tar /existing-directory-trailing-slash/
  2854  RUN cat /existing-directory-trailing-slash/test/foo | grep Hi`
  2855  		tmpDir, err := ioutil.TempDir("", "fake-context")
  2856  		c.Assert(err, check.IsNil)
  2857  		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
  2858  		if err != nil {
  2859  			c.Fatalf("failed to create test.tar archive: %v", err)
  2860  		}
  2861  		defer testTar.Close()
  2862  
  2863  		tw := tar.NewWriter(testTar)
  2864  
  2865  		if err := tw.WriteHeader(&tar.Header{
  2866  			Name: "test/foo",
  2867  			Size: 2,
  2868  		}); err != nil {
  2869  			c.Fatalf("failed to write tar file header: %v", err)
  2870  		}
  2871  		if _, err := tw.Write([]byte("Hi")); err != nil {
  2872  			c.Fatalf("failed to write tar file content: %v", err)
  2873  		}
  2874  		if err := tw.Close(); err != nil {
  2875  			c.Fatalf("failed to close tar archive: %v", err)
  2876  		}
  2877  
  2878  		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
  2879  			c.Fatalf("failed to open destination dockerfile: %v", err)
  2880  		}
  2881  		return fakecontext.New(c, tmpDir)
  2882  	}()
  2883  	defer ctx.Close()
  2884  
  2885  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  2886  }
  2887  
  2888  func (s *DockerSuite) TestBuildAddBrokenTar(c *check.C) {
  2889  	name := "testbuildaddbrokentar"
  2890  
  2891  	ctx := func() *fakecontext.Fake {
  2892  		dockerfile := `
  2893  FROM busybox
  2894  ADD test.tar /`
  2895  		tmpDir, err := ioutil.TempDir("", "fake-context")
  2896  		c.Assert(err, check.IsNil)
  2897  		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
  2898  		if err != nil {
  2899  			c.Fatalf("failed to create test.tar archive: %v", err)
  2900  		}
  2901  		defer testTar.Close()
  2902  
  2903  		tw := tar.NewWriter(testTar)
  2904  
  2905  		if err := tw.WriteHeader(&tar.Header{
  2906  			Name: "test/foo",
  2907  			Size: 2,
  2908  		}); err != nil {
  2909  			c.Fatalf("failed to write tar file header: %v", err)
  2910  		}
  2911  		if _, err := tw.Write([]byte("Hi")); err != nil {
  2912  			c.Fatalf("failed to write tar file content: %v", err)
  2913  		}
  2914  		if err := tw.Close(); err != nil {
  2915  			c.Fatalf("failed to close tar archive: %v", err)
  2916  		}
  2917  
  2918  		// Corrupt the tar by removing one byte off the end
  2919  		stat, err := testTar.Stat()
  2920  		if err != nil {
  2921  			c.Fatalf("failed to stat tar archive: %v", err)
  2922  		}
  2923  		if err := testTar.Truncate(stat.Size() - 1); err != nil {
  2924  			c.Fatalf("failed to truncate tar archive: %v", err)
  2925  		}
  2926  
  2927  		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
  2928  			c.Fatalf("failed to open destination dockerfile: %v", err)
  2929  		}
  2930  		return fakecontext.New(c, tmpDir)
  2931  	}()
  2932  	defer ctx.Close()
  2933  
  2934  	buildImage(name, build.WithExternalBuildContext(ctx)).Assert(c, icmd.Expected{
  2935  		ExitCode: 1,
  2936  	})
  2937  }
  2938  
  2939  func (s *DockerSuite) TestBuildAddNonTar(c *check.C) {
  2940  	name := "testbuildaddnontar"
  2941  
  2942  	// Should not try to extract test.tar
  2943  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  2944  		build.WithFile("Dockerfile", `
  2945  		FROM busybox
  2946  		ADD test.tar /
  2947  		RUN test -f /test.tar`),
  2948  		build.WithFile("test.tar", "not_a_tar_file"),
  2949  	))
  2950  }
  2951  
  2952  func (s *DockerSuite) TestBuildAddTarXz(c *check.C) {
  2953  	// /test/foo is not owned by the correct user
  2954  	testRequires(c, NotUserNamespace)
  2955  	testRequires(c, DaemonIsLinux)
  2956  	name := "testbuildaddtarxz"
  2957  
  2958  	ctx := func() *fakecontext.Fake {
  2959  		dockerfile := `
  2960  			FROM busybox
  2961  			ADD test.tar.xz /
  2962  			RUN cat /test/foo | grep Hi`
  2963  		tmpDir, err := ioutil.TempDir("", "fake-context")
  2964  		c.Assert(err, check.IsNil)
  2965  		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
  2966  		if err != nil {
  2967  			c.Fatalf("failed to create test.tar archive: %v", err)
  2968  		}
  2969  		defer testTar.Close()
  2970  
  2971  		tw := tar.NewWriter(testTar)
  2972  
  2973  		if err := tw.WriteHeader(&tar.Header{
  2974  			Name: "test/foo",
  2975  			Size: 2,
  2976  		}); err != nil {
  2977  			c.Fatalf("failed to write tar file header: %v", err)
  2978  		}
  2979  		if _, err := tw.Write([]byte("Hi")); err != nil {
  2980  			c.Fatalf("failed to write tar file content: %v", err)
  2981  		}
  2982  		if err := tw.Close(); err != nil {
  2983  			c.Fatalf("failed to close tar archive: %v", err)
  2984  		}
  2985  
  2986  		icmd.RunCmd(icmd.Cmd{
  2987  			Command: []string{"xz", "-k", "test.tar"},
  2988  			Dir:     tmpDir,
  2989  		}).Assert(c, icmd.Success)
  2990  		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
  2991  			c.Fatalf("failed to open destination dockerfile: %v", err)
  2992  		}
  2993  		return fakecontext.New(c, tmpDir)
  2994  	}()
  2995  
  2996  	defer ctx.Close()
  2997  
  2998  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  2999  }
  3000  
  3001  func (s *DockerSuite) TestBuildAddTarXzGz(c *check.C) {
  3002  	testRequires(c, DaemonIsLinux)
  3003  	name := "testbuildaddtarxzgz"
  3004  
  3005  	ctx := func() *fakecontext.Fake {
  3006  		dockerfile := `
  3007  			FROM busybox
  3008  			ADD test.tar.xz.gz /
  3009  			RUN ls /test.tar.xz.gz`
  3010  		tmpDir, err := ioutil.TempDir("", "fake-context")
  3011  		c.Assert(err, check.IsNil)
  3012  		testTar, err := os.Create(filepath.Join(tmpDir, "test.tar"))
  3013  		if err != nil {
  3014  			c.Fatalf("failed to create test.tar archive: %v", err)
  3015  		}
  3016  		defer testTar.Close()
  3017  
  3018  		tw := tar.NewWriter(testTar)
  3019  
  3020  		if err := tw.WriteHeader(&tar.Header{
  3021  			Name: "test/foo",
  3022  			Size: 2,
  3023  		}); err != nil {
  3024  			c.Fatalf("failed to write tar file header: %v", err)
  3025  		}
  3026  		if _, err := tw.Write([]byte("Hi")); err != nil {
  3027  			c.Fatalf("failed to write tar file content: %v", err)
  3028  		}
  3029  		if err := tw.Close(); err != nil {
  3030  			c.Fatalf("failed to close tar archive: %v", err)
  3031  		}
  3032  
  3033  		icmd.RunCmd(icmd.Cmd{
  3034  			Command: []string{"xz", "-k", "test.tar"},
  3035  			Dir:     tmpDir,
  3036  		}).Assert(c, icmd.Success)
  3037  
  3038  		icmd.RunCmd(icmd.Cmd{
  3039  			Command: []string{"gzip", "test.tar.xz"},
  3040  			Dir:     tmpDir,
  3041  		})
  3042  		if err := ioutil.WriteFile(filepath.Join(tmpDir, "Dockerfile"), []byte(dockerfile), 0644); err != nil {
  3043  			c.Fatalf("failed to open destination dockerfile: %v", err)
  3044  		}
  3045  		return fakecontext.New(c, tmpDir)
  3046  	}()
  3047  
  3048  	defer ctx.Close()
  3049  
  3050  	buildImageSuccessfully(c, name, build.WithExternalBuildContext(ctx))
  3051  }
  3052  
  3053  // FIXME(vdemeester) most of the from git tests could be moved to `docker/cli` e2e tests
  3054  func (s *DockerSuite) TestBuildFromGit(c *check.C) {
  3055  	name := "testbuildfromgit"
  3056  	git := fakegit.New(c, "repo", map[string]string{
  3057  		"Dockerfile": `FROM busybox
  3058  		ADD first /first
  3059  		RUN [ -f /first ]
  3060  		MAINTAINER docker`,
  3061  		"first": "test git data",
  3062  	}, true)
  3063  	defer git.Close()
  3064  
  3065  	buildImageSuccessfully(c, name, build.WithContextPath(git.RepoURL))
  3066  
  3067  	res := inspectField(c, name, "Author")
  3068  	if res != "docker" {
  3069  		c.Fatalf("Maintainer should be docker, got %s", res)
  3070  	}
  3071  }
  3072  
  3073  func (s *DockerSuite) TestBuildFromGitWithContext(c *check.C) {
  3074  	name := "testbuildfromgit"
  3075  	git := fakegit.New(c, "repo", map[string]string{
  3076  		"docker/Dockerfile": `FROM busybox
  3077  					ADD first /first
  3078  					RUN [ -f /first ]
  3079  					MAINTAINER docker`,
  3080  		"docker/first": "test git data",
  3081  	}, true)
  3082  	defer git.Close()
  3083  
  3084  	buildImageSuccessfully(c, name, build.WithContextPath(fmt.Sprintf("%s#master:docker", git.RepoURL)))
  3085  
  3086  	res := inspectField(c, name, "Author")
  3087  	if res != "docker" {
  3088  		c.Fatalf("Maintainer should be docker, got %s", res)
  3089  	}
  3090  }
  3091  
  3092  func (s *DockerSuite) TestBuildFromGitWithF(c *check.C) {
  3093  	name := "testbuildfromgitwithf"
  3094  	git := fakegit.New(c, "repo", map[string]string{
  3095  		"myApp/myDockerfile": `FROM busybox
  3096  					RUN echo hi from Dockerfile`,
  3097  	}, true)
  3098  	defer git.Close()
  3099  
  3100  	buildImage(name, cli.WithFlags("-f", "myApp/myDockerfile"), build.WithContextPath(git.RepoURL)).Assert(c, icmd.Expected{
  3101  		Out: "hi from Dockerfile",
  3102  	})
  3103  }
  3104  
  3105  func (s *DockerSuite) TestBuildFromRemoteTarball(c *check.C) {
  3106  	name := "testbuildfromremotetarball"
  3107  
  3108  	buffer := new(bytes.Buffer)
  3109  	tw := tar.NewWriter(buffer)
  3110  	defer tw.Close()
  3111  
  3112  	dockerfile := []byte(`FROM busybox
  3113  					MAINTAINER docker`)
  3114  	if err := tw.WriteHeader(&tar.Header{
  3115  		Name: "Dockerfile",
  3116  		Size: int64(len(dockerfile)),
  3117  	}); err != nil {
  3118  		c.Fatalf("failed to write tar file header: %v", err)
  3119  	}
  3120  	if _, err := tw.Write(dockerfile); err != nil {
  3121  		c.Fatalf("failed to write tar file content: %v", err)
  3122  	}
  3123  	if err := tw.Close(); err != nil {
  3124  		c.Fatalf("failed to close tar archive: %v", err)
  3125  	}
  3126  
  3127  	server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
  3128  		"testT.tar": buffer,
  3129  	}))
  3130  	defer server.Close()
  3131  
  3132  	cli.BuildCmd(c, name, build.WithContextPath(server.URL()+"/testT.tar"))
  3133  
  3134  	res := inspectField(c, name, "Author")
  3135  	if res != "docker" {
  3136  		c.Fatalf("Maintainer should be docker, got %s", res)
  3137  	}
  3138  }
  3139  
  3140  func (s *DockerSuite) TestBuildCleanupCmdOnEntrypoint(c *check.C) {
  3141  	name := "testbuildcmdcleanuponentrypoint"
  3142  
  3143  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  3144  		CMD ["test"]
  3145  		ENTRYPOINT ["echo"]`))
  3146  	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`FROM %s
  3147  		ENTRYPOINT ["cat"]`, name)))
  3148  
  3149  	res := inspectField(c, name, "Config.Cmd")
  3150  	if res != "[]" {
  3151  		c.Fatalf("Cmd %s, expected nil", res)
  3152  	}
  3153  	res = inspectField(c, name, "Config.Entrypoint")
  3154  	if expected := "[cat]"; res != expected {
  3155  		c.Fatalf("Entrypoint %s, expected %s", res, expected)
  3156  	}
  3157  }
  3158  
  3159  func (s *DockerSuite) TestBuildClearCmd(c *check.C) {
  3160  	name := "testbuildclearcmd"
  3161  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM `+minimalBaseImage()+`
  3162     ENTRYPOINT ["/bin/bash"]
  3163     CMD []`))
  3164  
  3165  	res := inspectFieldJSON(c, name, "Config.Cmd")
  3166  	if res != "[]" {
  3167  		c.Fatalf("Cmd %s, expected %s", res, "[]")
  3168  	}
  3169  }
  3170  
  3171  func (s *DockerSuite) TestBuildEmptyCmd(c *check.C) {
  3172  	// Skip on Windows. Base image on Windows has a CMD set in the image.
  3173  	testRequires(c, DaemonIsLinux)
  3174  
  3175  	name := "testbuildemptycmd"
  3176  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM "+minimalBaseImage()+"\nMAINTAINER quux\n"))
  3177  
  3178  	res := inspectFieldJSON(c, name, "Config.Cmd")
  3179  	if res != "null" {
  3180  		c.Fatalf("Cmd %s, expected %s", res, "null")
  3181  	}
  3182  }
  3183  
  3184  func (s *DockerSuite) TestBuildOnBuildOutput(c *check.C) {
  3185  	name := "testbuildonbuildparent"
  3186  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nONBUILD RUN echo foo\n"))
  3187  
  3188  	buildImage(name, build.WithDockerfile("FROM "+name+"\nMAINTAINER quux\n")).Assert(c, icmd.Expected{
  3189  		Out: "# Executing 1 build trigger",
  3190  	})
  3191  }
  3192  
  3193  // FIXME(vdemeester) should be a unit test
  3194  func (s *DockerSuite) TestBuildInvalidTag(c *check.C) {
  3195  	name := "abcd:" + testutil.GenerateRandomAlphaOnlyString(200)
  3196  	buildImage(name, build.WithDockerfile("FROM "+minimalBaseImage()+"\nMAINTAINER quux\n")).Assert(c, icmd.Expected{
  3197  		ExitCode: 125,
  3198  		Err:      "invalid reference format",
  3199  	})
  3200  }
  3201  
  3202  func (s *DockerSuite) TestBuildCmdShDashC(c *check.C) {
  3203  	name := "testbuildcmdshc"
  3204  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD echo cmd\n"))
  3205  
  3206  	res := inspectFieldJSON(c, name, "Config.Cmd")
  3207  	expected := `["/bin/sh","-c","echo cmd"]`
  3208  	if testEnv.OSType == "windows" {
  3209  		expected = `["cmd","/S","/C","echo cmd"]`
  3210  	}
  3211  	if res != expected {
  3212  		c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
  3213  	}
  3214  
  3215  }
  3216  
  3217  func (s *DockerSuite) TestBuildCmdSpaces(c *check.C) {
  3218  	// Test to make sure that when we strcat arrays we take into account
  3219  	// the arg separator to make sure ["echo","hi"] and ["echo hi"] don't
  3220  	// look the same
  3221  	name := "testbuildcmdspaces"
  3222  
  3223  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD [\"echo hi\"]\n"))
  3224  	id1 := getIDByName(c, name)
  3225  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD [\"echo\", \"hi\"]\n"))
  3226  	id2 := getIDByName(c, name)
  3227  
  3228  	if id1 == id2 {
  3229  		c.Fatal("Should not have resulted in the same CMD")
  3230  	}
  3231  
  3232  	// Now do the same with ENTRYPOINT
  3233  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT [\"echo hi\"]\n"))
  3234  	id1 = getIDByName(c, name)
  3235  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT [\"echo\", \"hi\"]\n"))
  3236  	id2 = getIDByName(c, name)
  3237  
  3238  	if id1 == id2 {
  3239  		c.Fatal("Should not have resulted in the same ENTRYPOINT")
  3240  	}
  3241  }
  3242  
  3243  func (s *DockerSuite) TestBuildCmdJSONNoShDashC(c *check.C) {
  3244  	name := "testbuildcmdjson"
  3245  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nCMD [\"echo\", \"cmd\"]"))
  3246  
  3247  	res := inspectFieldJSON(c, name, "Config.Cmd")
  3248  	expected := `["echo","cmd"]`
  3249  	if res != expected {
  3250  		c.Fatalf("Expected value %s not in Config.Cmd: %s", expected, res)
  3251  	}
  3252  }
  3253  
  3254  func (s *DockerSuite) TestBuildEntrypointCanBeOverriddenByChild(c *check.C) {
  3255  	buildImageSuccessfully(c, "parent", build.WithDockerfile(`
  3256      FROM busybox
  3257      ENTRYPOINT exit 130
  3258      `))
  3259  
  3260  	icmd.RunCommand(dockerBinary, "run", "parent").Assert(c, icmd.Expected{
  3261  		ExitCode: 130,
  3262  	})
  3263  
  3264  	buildImageSuccessfully(c, "child", build.WithDockerfile(`
  3265      FROM parent
  3266      ENTRYPOINT exit 5
  3267      `))
  3268  
  3269  	icmd.RunCommand(dockerBinary, "run", "child").Assert(c, icmd.Expected{
  3270  		ExitCode: 5,
  3271  	})
  3272  }
  3273  
  3274  func (s *DockerSuite) TestBuildEntrypointCanBeOverriddenByChildInspect(c *check.C) {
  3275  	var (
  3276  		name     = "testbuildepinherit"
  3277  		name2    = "testbuildepinherit2"
  3278  		expected = `["/bin/sh","-c","echo quux"]`
  3279  	)
  3280  
  3281  	if testEnv.OSType == "windows" {
  3282  		expected = `["cmd","/S","/C","echo quux"]`
  3283  	}
  3284  
  3285  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENTRYPOINT /foo/bar"))
  3286  	buildImageSuccessfully(c, name2, build.WithDockerfile(fmt.Sprintf("FROM %s\nENTRYPOINT echo quux", name)))
  3287  
  3288  	res := inspectFieldJSON(c, name2, "Config.Entrypoint")
  3289  	if res != expected {
  3290  		c.Fatalf("Expected value %s not in Config.Entrypoint: %s", expected, res)
  3291  	}
  3292  
  3293  	icmd.RunCommand(dockerBinary, "run", name2).Assert(c, icmd.Expected{
  3294  		Out: "quux",
  3295  	})
  3296  }
  3297  
  3298  func (s *DockerSuite) TestBuildRunShEntrypoint(c *check.C) {
  3299  	name := "testbuildentrypoint"
  3300  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3301                                  ENTRYPOINT echo`))
  3302  	dockerCmd(c, "run", "--rm", name)
  3303  }
  3304  
  3305  func (s *DockerSuite) TestBuildExoticShellInterpolation(c *check.C) {
  3306  	testRequires(c, DaemonIsLinux)
  3307  	name := "testbuildexoticshellinterpolation"
  3308  
  3309  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  3310  		FROM busybox
  3311  
  3312  		ENV SOME_VAR a.b.c
  3313  
  3314  		RUN [ "$SOME_VAR"       = 'a.b.c' ]
  3315  		RUN [ "${SOME_VAR}"     = 'a.b.c' ]
  3316  		RUN [ "${SOME_VAR%.*}"  = 'a.b'   ]
  3317  		RUN [ "${SOME_VAR%%.*}" = 'a'     ]
  3318  		RUN [ "${SOME_VAR#*.}"  = 'b.c'   ]
  3319  		RUN [ "${SOME_VAR##*.}" = 'c'     ]
  3320  		RUN [ "${SOME_VAR/c/d}" = 'a.b.d' ]
  3321  		RUN [ "${#SOME_VAR}"    = '5'     ]
  3322  
  3323  		RUN [ "${SOME_UNSET_VAR:-$SOME_VAR}" = 'a.b.c' ]
  3324  		RUN [ "${SOME_VAR:+Version: ${SOME_VAR}}" = 'Version: a.b.c' ]
  3325  		RUN [ "${SOME_UNSET_VAR:+${SOME_VAR}}" = '' ]
  3326  		RUN [ "${SOME_UNSET_VAR:-${SOME_VAR:-d.e.f}}" = 'a.b.c' ]
  3327  	`))
  3328  }
  3329  
  3330  func (s *DockerSuite) TestBuildVerifySingleQuoteFails(c *check.C) {
  3331  	// This testcase is supposed to generate an error because the
  3332  	// JSON array we're passing in on the CMD uses single quotes instead
  3333  	// of double quotes (per the JSON spec). This means we interpret it
  3334  	// as a "string" instead of "JSON array" and pass it on to "sh -c" and
  3335  	// it should barf on it.
  3336  	name := "testbuildsinglequotefails"
  3337  	expectedExitCode := 2
  3338  	if testEnv.OSType == "windows" {
  3339  		expectedExitCode = 127
  3340  	}
  3341  
  3342  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3343  		CMD [ '/bin/sh', '-c', 'echo hi' ]`))
  3344  
  3345  	icmd.RunCommand(dockerBinary, "run", "--rm", name).Assert(c, icmd.Expected{
  3346  		ExitCode: expectedExitCode,
  3347  	})
  3348  }
  3349  
  3350  func (s *DockerSuite) TestBuildVerboseOut(c *check.C) {
  3351  	name := "testbuildverboseout"
  3352  	expected := "\n123\n"
  3353  
  3354  	if testEnv.OSType == "windows" {
  3355  		expected = "\n123\r\n"
  3356  	}
  3357  
  3358  	buildImage(name, build.WithDockerfile(`FROM busybox
  3359  RUN echo 123`)).Assert(c, icmd.Expected{
  3360  		Out: expected,
  3361  	})
  3362  }
  3363  
  3364  func (s *DockerSuite) TestBuildWithTabs(c *check.C) {
  3365  	name := "testbuildwithtabs"
  3366  	buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nRUN echo\tone\t\ttwo"))
  3367  	res := inspectFieldJSON(c, name, "ContainerConfig.Cmd")
  3368  	expected1 := `["/bin/sh","-c","echo\tone\t\ttwo"]`
  3369  	expected2 := `["/bin/sh","-c","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
  3370  	if testEnv.OSType == "windows" {
  3371  		expected1 = `["cmd","/S","/C","echo\tone\t\ttwo"]`
  3372  		expected2 = `["cmd","/S","/C","echo\u0009one\u0009\u0009two"]` // syntactically equivalent, and what Go 1.3 generates
  3373  	}
  3374  	if res != expected1 && res != expected2 {
  3375  		c.Fatalf("Missing tabs.\nGot: %s\nExp: %s or %s", res, expected1, expected2)
  3376  	}
  3377  }
  3378  
  3379  func (s *DockerSuite) TestBuildLabels(c *check.C) {
  3380  	name := "testbuildlabel"
  3381  	expected := `{"License":"GPL","Vendor":"Acme"}`
  3382  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3383  		LABEL Vendor=Acme
  3384                  LABEL License GPL`))
  3385  	res := inspectFieldJSON(c, name, "Config.Labels")
  3386  	if res != expected {
  3387  		c.Fatalf("Labels %s, expected %s", res, expected)
  3388  	}
  3389  }
  3390  
  3391  func (s *DockerSuite) TestBuildLabelsCache(c *check.C) {
  3392  	name := "testbuildlabelcache"
  3393  
  3394  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3395  		LABEL Vendor=Acme`))
  3396  	id1 := getIDByName(c, name)
  3397  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3398  		LABEL Vendor=Acme`))
  3399  	id2 := getIDByName(c, name)
  3400  	if id1 != id2 {
  3401  		c.Fatalf("Build 2 should have worked & used cache(%s,%s)", id1, id2)
  3402  	}
  3403  
  3404  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3405  		LABEL Vendor=Acme1`))
  3406  	id2 = getIDByName(c, name)
  3407  	if id1 == id2 {
  3408  		c.Fatalf("Build 3 should have worked & NOT used cache(%s,%s)", id1, id2)
  3409  	}
  3410  
  3411  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3412  		LABEL Vendor Acme`))
  3413  	id2 = getIDByName(c, name)
  3414  	if id1 != id2 {
  3415  		c.Fatalf("Build 4 should have worked & used cache(%s,%s)", id1, id2)
  3416  	}
  3417  
  3418  	// Now make sure the cache isn't used by mistake
  3419  	buildImageSuccessfully(c, name, build.WithoutCache, build.WithDockerfile(`FROM busybox
  3420         LABEL f1=b1 f2=b2`))
  3421  
  3422  	buildImageSuccessfully(c, name, build.WithDockerfile(`FROM busybox
  3423         LABEL f1=b1 f2=b2`))
  3424  	id2 = getIDByName(c, name)
  3425  	if id1 == id2 {
  3426  		c.Fatalf("Build 6 should have worked & NOT used the cache(%s,%s)", id1, id2)
  3427  	}
  3428  
  3429  }
  3430  
  3431  // FIXME(vdemeester) port to docker/cli e2e tests (api tests should test suppressOutput option though)
  3432  func (s *DockerSuite) TestBuildNotVerboseSuccess(c *check.C) {
  3433  	// This test makes sure that -q works correctly when build is successful:
  3434  	// stdout has only the image ID (long image ID) and stderr is empty.
  3435  	outRegexp := regexp.MustCompile("^(sha256:|)[a-z0-9]{64}\\n$")
  3436  	buildFlags := cli.WithFlags("-q")
  3437  
  3438  	tt := []struct {
  3439  		Name      string
  3440  		BuildFunc func(string) *icmd.Result
  3441  	}{
  3442  		{
  3443  			Name: "quiet_build_stdin_success",
  3444  			BuildFunc: func(name string) *icmd.Result {
  3445  				return buildImage(name, buildFlags, build.WithDockerfile("FROM busybox"))
  3446  			},
  3447  		},
  3448  		{
  3449  			Name: "quiet_build_ctx_success",
  3450  			BuildFunc: func(name string) *icmd.Result {
  3451  				return buildImage(name, buildFlags, build.WithBuildContext(c,
  3452  					build.WithFile("Dockerfile", "FROM busybox"),
  3453  					build.WithFile("quiet_build_success_fctx", "test"),
  3454  				))
  3455  			},
  3456  		},
  3457  		{
  3458  			Name: "quiet_build_git_success",
  3459  			BuildFunc: func(name string) *icmd.Result {
  3460  				git := fakegit.New(c, "repo", map[string]string{
  3461  					"Dockerfile": "FROM busybox",
  3462  				}, true)
  3463  				return buildImage(name, buildFlags, build.WithContextPath(git.RepoURL))
  3464  			},
  3465  		},
  3466  	}
  3467  
  3468  	for _, te := range tt {
  3469  		result := te.BuildFunc(te.Name)
  3470  		result.Assert(c, icmd.Success)
  3471  		if outRegexp.Find([]byte(result.Stdout())) == nil {
  3472  			c.Fatalf("Test %s expected stdout to match the [%v] regexp, but it is [%v]", te.Name, outRegexp, result.Stdout())
  3473  		}
  3474  
  3475  		if result.Stderr() != "" {
  3476  			c.Fatalf("Test %s expected stderr to be empty, but it is [%#v]", te.Name, result.Stderr())
  3477  		}
  3478  	}
  3479  
  3480  }
  3481  
  3482  // FIXME(vdemeester) migrate to docker/cli tests
  3483  func (s *DockerSuite) TestBuildNotVerboseFailureWithNonExistImage(c *check.C) {
  3484  	// This test makes sure that -q works correctly when build fails by
  3485  	// comparing between the stderr output in quiet mode and in stdout
  3486  	// and stderr output in verbose mode
  3487  	testRequires(c, Network)
  3488  	testName := "quiet_build_not_exists_image"
  3489  	dockerfile := "FROM busybox11"
  3490  	quietResult := buildImage(testName, cli.WithFlags("-q"), build.WithDockerfile(dockerfile))
  3491  	quietResult.Assert(c, icmd.Expected{
  3492  		ExitCode: 1,
  3493  	})
  3494  	result := buildImage(testName, build.WithDockerfile(dockerfile))
  3495  	result.Assert(c, icmd.Expected{
  3496  		ExitCode: 1,
  3497  	})
  3498  	if quietResult.Stderr() != result.Combined() {
  3499  		c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", testName, quietResult.Stderr(), result.Combined()))
  3500  	}
  3501  }
  3502  
  3503  // FIXME(vdemeester) migrate to docker/cli tests
  3504  func (s *DockerSuite) TestBuildNotVerboseFailure(c *check.C) {
  3505  	// This test makes sure that -q works correctly when build fails by
  3506  	// comparing between the stderr output in quiet mode and in stdout
  3507  	// and stderr output in verbose mode
  3508  	testCases := []struct {
  3509  		testName   string
  3510  		dockerfile string
  3511  	}{
  3512  		{"quiet_build_no_from_at_the_beginning", "RUN whoami"},
  3513  		{"quiet_build_unknown_instr", "FROMD busybox"},
  3514  	}
  3515  
  3516  	for _, tc := range testCases {
  3517  		quietResult := buildImage(tc.testName, cli.WithFlags("-q"), build.WithDockerfile(tc.dockerfile))
  3518  		quietResult.Assert(c, icmd.Expected{
  3519  			ExitCode: 1,
  3520  		})
  3521  		result := buildImage(tc.testName, build.WithDockerfile(tc.dockerfile))
  3522  		result.Assert(c, icmd.Expected{
  3523  			ExitCode: 1,
  3524  		})
  3525  		if quietResult.Stderr() != result.Combined() {
  3526  			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()))
  3527  		}
  3528  	}
  3529  }
  3530  
  3531  // FIXME(vdemeester) migrate to docker/cli tests
  3532  func (s *DockerSuite) TestBuildNotVerboseFailureRemote(c *check.C) {
  3533  	// This test ensures that when given a wrong URL, stderr in quiet mode and
  3534  	// stderr in verbose mode are identical.
  3535  	// TODO(vdemeester) with cobra, stdout has a carriage return too much so this test should not check stdout
  3536  	URL := "http://something.invalid"
  3537  	name := "quiet_build_wrong_remote"
  3538  	quietResult := buildImage(name, cli.WithFlags("-q"), build.WithContextPath(URL))
  3539  	quietResult.Assert(c, icmd.Expected{
  3540  		ExitCode: 1,
  3541  	})
  3542  	result := buildImage(name, build.WithContextPath(URL))
  3543  	result.Assert(c, icmd.Expected{
  3544  		ExitCode: 1,
  3545  	})
  3546  
  3547  	// An error message should contain name server IP and port, like this:
  3548  	//  "dial tcp: lookup something.invalid on 172.29.128.11:53: no such host"
  3549  	// The IP:port need to be removed in order to not trigger a test failur
  3550  	// when more than one nameserver is configured.
  3551  	// While at it, also strip excessive newlines.
  3552  	normalize := func(msg string) string {
  3553  		return strings.TrimSpace(regexp.MustCompile("[1-9][0-9.]+:[0-9]+").ReplaceAllLiteralString(msg, "<ip:port>"))
  3554  	}
  3555  
  3556  	if normalize(quietResult.Stderr()) != normalize(result.Combined()) {
  3557  		c.Fatal(fmt.Errorf("Test[%s] expected that quiet stderr and verbose stdout are equal; quiet [%v], verbose [%v]", name, quietResult.Stderr(), result.Combined()))
  3558  	}
  3559  }
  3560  
  3561  // FIXME(vdemeester) migrate to docker/cli tests
  3562  func (s *DockerSuite) TestBuildStderr(c *check.C) {
  3563  	// This test just makes sure that no non-error output goes
  3564  	// to stderr
  3565  	name := "testbuildstderr"
  3566  	result := buildImage(name, build.WithDockerfile("FROM busybox\nRUN echo one"))
  3567  	result.Assert(c, icmd.Success)
  3568  
  3569  	// Windows to non-Windows should have a security warning
  3570  	if runtime.GOOS == "windows" && testEnv.OSType != "windows" && !strings.Contains(result.Stdout(), "SECURITY WARNING:") {
  3571  		c.Fatalf("Stdout contains unexpected output: %q", result.Stdout())
  3572  	}
  3573  
  3574  	// Stderr should always be empty
  3575  	if result.Stderr() != "" {
  3576  		c.Fatalf("Stderr should have been empty, instead it's: %q", result.Stderr())
  3577  	}
  3578  }
  3579  
  3580  func (s *DockerSuite) TestBuildChownSingleFile(c *check.C) {
  3581  	testRequires(c, UnixCli, DaemonIsLinux) // test uses chown: not available on windows
  3582  
  3583  	name := "testbuildchownsinglefile"
  3584  
  3585  	ctx := fakecontext.New(c, "",
  3586  		fakecontext.WithDockerfile(`
  3587  FROM busybox
  3588  COPY test /
  3589  RUN ls -l /test
  3590  RUN [ $(ls -l /test | awk '{print $3":"$4}') = 'root:root' ]
  3591  `),
  3592  		fakecontext.WithFiles(map[string]string{
  3593  			"test": "test",
  3594  		}))
  3595  	defer ctx.Close()
  3596  
  3597  	if err := os.Chown(filepath.Join(ctx.Dir, "test"), 4242, 4242); err != nil {
  3598  		c.Fatal(err)
  3599  	}
  3600  
  3601  	cli.BuildCmd(c, name, build.WithExternalBuildContext(ctx))
  3602  }
  3603  
  3604  func (s *DockerSuite) TestBuildSymlinkBreakout(c *check.C) {
  3605  	name := "testbuildsymlinkbreakout"
  3606  	tmpdir, err := ioutil.TempDir("", name)
  3607  	c.Assert(err, check.IsNil)
  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, SameHostDaemon, 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  	c.Assert(err, check.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	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  	c.Assert(err, checker.IsNil)
  5026  	absolute, err := filepath.Abs(filepath.Join(workingDir, "fixtures", "auth"))
  5027  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  5036  
  5037  	externalAuthConfig := `{ "credsStore": "shell-test" }`
  5038  
  5039  	configPath := filepath.Join(tmp, "config.json")
  5040  	err = ioutil.WriteFile(configPath, []byte(externalAuthConfig), 0644)
  5041  	c.Assert(err, checker.IsNil)
  5042  
  5043  	dockerCmd(c, "--config", tmp, "login", "-u", s.reg.Username(), "-p", s.reg.Password(), privateRegistryURL)
  5044  
  5045  	b, err := ioutil.ReadFile(configPath)
  5046  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  	c.Assert(err, checker.IsNil)
  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  		c.Assert(len(out), checker.GreaterThan, 10)
  5787  		out2 := cli.DockerCmd(c, "run", "build1", "cat", "foo").Combined()
  5788  		c.Assert(out, check.Equals, 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  	dockerfile := `
  5957  		FROM busybox AS build-env
  5958  		CMD ["/dev"]
  5959  		FROM busybox
  5960  		CMD ["/dist"]
  5961  		`
  5962  	ctx := fakecontext.New(c, "", fakecontext.WithDockerfile(dockerfile))
  5963  	defer ctx.Close()
  5964  
  5965  	cli.BuildCmd(c, "build1", build.WithExternalBuildContext(ctx),
  5966  		cli.WithFlags("--target", "build-env"))
  5967  
  5968  	//res := inspectFieldJSON(c, "build1", "Config.Cmd")
  5969  	res := cli.InspectCmd(c, "build1", cli.Format("json .Config.Cmd")).Combined()
  5970  	c.Assert(strings.TrimSpace(res), checker.Equals, `["/dev"]`)
  5971  
  5972  	result := cli.Docker(cli.Build("build1"), build.WithExternalBuildContext(ctx),
  5973  		cli.WithFlags("--target", "nosuchtarget"))
  5974  	result.Assert(c, icmd.Expected{
  5975  		ExitCode: 1,
  5976  		Err:      "failed to reach build target",
  5977  	})
  5978  }
  5979  
  5980  // TestBuildOpaqueDirectory tests that a build succeeds which
  5981  // creates opaque directories.
  5982  // See https://github.com/docker/docker/issues/25244
  5983  func (s *DockerSuite) TestBuildOpaqueDirectory(c *check.C) {
  5984  	testRequires(c, DaemonIsLinux)
  5985  	dockerFile := `
  5986  		FROM busybox
  5987  		RUN mkdir /dir1 && touch /dir1/f1
  5988  		RUN rm -rf /dir1 && mkdir /dir1 && touch /dir1/f2
  5989  		RUN touch /dir1/f3
  5990  		RUN [ -f /dir1/f2 ]
  5991  		`
  5992  	// Test that build succeeds, last command fails if opaque directory
  5993  	// was not handled correctly
  5994  	buildImageSuccessfully(c, "testopaquedirectory", build.WithDockerfile(dockerFile))
  5995  }
  5996  
  5997  // Windows test for USER in dockerfile
  5998  func (s *DockerSuite) TestBuildWindowsUser(c *check.C) {
  5999  	testRequires(c, DaemonIsWindows)
  6000  	name := "testbuildwindowsuser"
  6001  	buildImage(name, build.WithDockerfile(`FROM `+testEnv.PlatformDefaults.BaseImage+`
  6002  		RUN net user user /add
  6003  		USER user
  6004  		RUN set username
  6005  		`)).Assert(c, icmd.Expected{
  6006  		Out: "USERNAME=user",
  6007  	})
  6008  }
  6009  
  6010  // Verifies if COPY file . when WORKDIR is set to a non-existing directory,
  6011  // the directory is created and the file is copied into the directory,
  6012  // as opposed to the file being copied as a file with the name of the
  6013  // directory. Fix for 27545 (found on Windows, but regression good for Linux too).
  6014  // Note 27545 was reverted in 28505, but a new fix was added subsequently in 28514.
  6015  func (s *DockerSuite) TestBuildCopyFileDotWithWorkdir(c *check.C) {
  6016  	name := "testbuildcopyfiledotwithworkdir"
  6017  	buildImageSuccessfully(c, name, build.WithBuildContext(c,
  6018  		build.WithFile("Dockerfile", `FROM busybox
  6019  WORKDIR /foo
  6020  COPY file .
  6021  RUN ["cat", "/foo/file"]
  6022  `),
  6023  		build.WithFile("file", "content"),
  6024  	))
  6025  }
  6026  
  6027  // Case-insensitive environment variables on Windows
  6028  func (s *DockerSuite) TestBuildWindowsEnvCaseInsensitive(c *check.C) {
  6029  	testRequires(c, DaemonIsWindows)
  6030  	name := "testbuildwindowsenvcaseinsensitive"
  6031  	buildImageSuccessfully(c, name, build.WithDockerfile(`
  6032  		FROM `+testEnv.PlatformDefaults.BaseImage+`
  6033  		ENV FOO=bar foo=baz
  6034    `))
  6035  	res := inspectFieldJSON(c, name, "Config.Env")
  6036  	if res != `["foo=baz"]` { // Should not have FOO=bar in it - takes the last one processed. And only one entry as deduped.
  6037  		c.Fatalf("Case insensitive environment variables on Windows failed. Got %s", res)
  6038  	}
  6039  }
  6040  
  6041  // Test case for 29667
  6042  func (s *DockerSuite) TestBuildWorkdirImageCmd(c *check.C) {
  6043  	image := "testworkdirimagecmd"
  6044  	buildImageSuccessfully(c, image, build.WithDockerfile(`
  6045  FROM busybox
  6046  WORKDIR /foo/bar
  6047  `))
  6048  	out, _ := dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", image)
  6049  
  6050  	// The Windows busybox image has a blank `cmd`
  6051  	lookingFor := `["sh"]`
  6052  	if testEnv.OSType == "windows" {
  6053  		lookingFor = "null"
  6054  	}
  6055  	c.Assert(strings.TrimSpace(out), checker.Equals, lookingFor)
  6056  
  6057  	image = "testworkdirlabelimagecmd"
  6058  	buildImageSuccessfully(c, image, build.WithDockerfile(`
  6059  FROM busybox
  6060  WORKDIR /foo/bar
  6061  LABEL a=b
  6062  `))
  6063  
  6064  	out, _ = dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", image)
  6065  	c.Assert(strings.TrimSpace(out), checker.Equals, lookingFor)
  6066  }
  6067  
  6068  // Test case for 28902/28909
  6069  func (s *DockerSuite) TestBuildWorkdirCmd(c *check.C) {
  6070  	testRequires(c, DaemonIsLinux)
  6071  	name := "testbuildworkdircmd"
  6072  	dockerFile := `
  6073                  FROM busybox
  6074                  WORKDIR /
  6075                  `
  6076  	buildImageSuccessfully(c, name, build.WithDockerfile(dockerFile))
  6077  	result := buildImage(name, build.WithDockerfile(dockerFile))
  6078  	result.Assert(c, icmd.Success)
  6079  	c.Assert(strings.Count(result.Combined(), "Using cache"), checker.Equals, 1)
  6080  }
  6081  
  6082  // FIXME(vdemeester) should be a unit test
  6083  func (s *DockerSuite) TestBuildLineErrorOnBuild(c *check.C) {
  6084  	name := "test_build_line_error_onbuild"
  6085  	buildImage(name, build.WithDockerfile(`FROM busybox
  6086    ONBUILD
  6087    `)).Assert(c, icmd.Expected{
  6088  		ExitCode: 1,
  6089  		Err:      "Dockerfile parse error line 2: ONBUILD requires at least one argument",
  6090  	})
  6091  }
  6092  
  6093  // FIXME(vdemeester) should be a unit test
  6094  func (s *DockerSuite) TestBuildLineErrorUnknownInstruction(c *check.C) {
  6095  	name := "test_build_line_error_unknown_instruction"
  6096  	cli.Docker(cli.Build(name), build.WithDockerfile(`FROM busybox
  6097    RUN echo hello world
  6098    NOINSTRUCTION echo ba
  6099    RUN echo hello
  6100    ERROR
  6101    `)).Assert(c, icmd.Expected{
  6102  		ExitCode: 1,
  6103  		Err:      "Dockerfile parse error line 3: unknown instruction: NOINSTRUCTION",
  6104  	})
  6105  }
  6106  
  6107  // FIXME(vdemeester) should be a unit test
  6108  func (s *DockerSuite) TestBuildLineErrorWithEmptyLines(c *check.C) {
  6109  	name := "test_build_line_error_with_empty_lines"
  6110  	cli.Docker(cli.Build(name), build.WithDockerfile(`
  6111    FROM busybox
  6112  
  6113    RUN echo hello world
  6114  
  6115    NOINSTRUCTION echo ba
  6116  
  6117    CMD ["/bin/init"]
  6118    `)).Assert(c, icmd.Expected{
  6119  		ExitCode: 1,
  6120  		Err:      "Dockerfile parse error line 6: unknown instruction: NOINSTRUCTION",
  6121  	})
  6122  }
  6123  
  6124  // FIXME(vdemeester) should be a unit test
  6125  func (s *DockerSuite) TestBuildLineErrorWithComments(c *check.C) {
  6126  	name := "test_build_line_error_with_comments"
  6127  	cli.Docker(cli.Build(name), build.WithDockerfile(`FROM busybox
  6128    # This will print hello world
  6129    # and then ba
  6130    RUN echo hello world
  6131    NOINSTRUCTION echo ba
  6132    `)).Assert(c, icmd.Expected{
  6133  		ExitCode: 1,
  6134  		Err:      "Dockerfile parse error line 5: unknown instruction: NOINSTRUCTION",
  6135  	})
  6136  }
  6137  
  6138  // #31957
  6139  func (s *DockerSuite) TestBuildSetCommandWithDefinedShell(c *check.C) {
  6140  	buildImageSuccessfully(c, "build1", build.WithDockerfile(`
  6141  FROM busybox
  6142  SHELL ["/bin/sh", "-c"]
  6143  `))
  6144  	buildImageSuccessfully(c, "build2", build.WithDockerfile(`
  6145  FROM build1
  6146  CMD echo foo
  6147  `))
  6148  
  6149  	out, _ := dockerCmd(c, "inspect", "--format", "{{ json .Config.Cmd }}", "build2")
  6150  	c.Assert(strings.TrimSpace(out), checker.Equals, `["/bin/sh","-c","echo foo"]`)
  6151  }
  6152  
  6153  // FIXME(vdemeester) should migrate to docker/cli tests
  6154  func (s *DockerSuite) TestBuildIidFile(c *check.C) {
  6155  	tmpDir, err := ioutil.TempDir("", "TestBuildIidFile")
  6156  	if err != nil {
  6157  		c.Fatal(err)
  6158  	}
  6159  	defer os.RemoveAll(tmpDir)
  6160  	tmpIidFile := filepath.Join(tmpDir, "iid")
  6161  
  6162  	name := "testbuildiidfile"
  6163  	// Use a Dockerfile with multiple stages to ensure we get the last one
  6164  	cli.BuildCmd(c, name,
  6165  		build.WithDockerfile(`FROM `+minimalBaseImage()+` AS stage1
  6166  ENV FOO FOO
  6167  FROM `+minimalBaseImage()+`
  6168  ENV BAR BAZ`),
  6169  		cli.WithFlags("--iidfile", tmpIidFile))
  6170  
  6171  	id, err := ioutil.ReadFile(tmpIidFile)
  6172  	c.Assert(err, check.IsNil)
  6173  	d, err := digest.Parse(string(id))
  6174  	c.Assert(err, check.IsNil)
  6175  	c.Assert(d.String(), checker.Equals, getIDByName(c, name))
  6176  }
  6177  
  6178  // FIXME(vdemeester) should migrate to docker/cli tests
  6179  func (s *DockerSuite) TestBuildIidFileCleanupOnFail(c *check.C) {
  6180  	tmpDir, err := ioutil.TempDir("", "TestBuildIidFileCleanupOnFail")
  6181  	if err != nil {
  6182  		c.Fatal(err)
  6183  	}
  6184  	defer os.RemoveAll(tmpDir)
  6185  	tmpIidFile := filepath.Join(tmpDir, "iid")
  6186  
  6187  	err = ioutil.WriteFile(tmpIidFile, []byte("Dummy"), 0666)
  6188  	c.Assert(err, check.IsNil)
  6189  
  6190  	cli.Docker(cli.Build("testbuildiidfilecleanuponfail"),
  6191  		build.WithDockerfile(`FROM `+minimalBaseImage()+`
  6192  	RUN /non/existing/command`),
  6193  		cli.WithFlags("--iidfile", tmpIidFile)).Assert(c, icmd.Expected{
  6194  		ExitCode: 1,
  6195  	})
  6196  	_, err = os.Stat(tmpIidFile)
  6197  	c.Assert(err, check.NotNil)
  6198  	c.Assert(os.IsNotExist(err), check.Equals, true)
  6199  }