github.com/jiasir/docker@v1.3.3-0.20170609024000-252e610103e7/integration-cli/docker_api_build_test.go (about)

     1  package main
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"encoding/json"
     7  	"io/ioutil"
     8  	"net/http"
     9  	"regexp"
    10  	"strings"
    11  
    12  	"github.com/docker/docker/integration-cli/checker"
    13  	"github.com/docker/docker/integration-cli/cli/build/fakecontext"
    14  	"github.com/docker/docker/integration-cli/cli/build/fakegit"
    15  	"github.com/docker/docker/integration-cli/cli/build/fakestorage"
    16  	"github.com/docker/docker/integration-cli/request"
    17  	"github.com/docker/docker/pkg/testutil"
    18  	"github.com/go-check/check"
    19  	"github.com/stretchr/testify/assert"
    20  	"github.com/stretchr/testify/require"
    21  	"golang.org/x/net/context"
    22  )
    23  
    24  func (s *DockerSuite) TestBuildAPIDockerFileRemote(c *check.C) {
    25  	testRequires(c, NotUserNamespace)
    26  	var testD string
    27  	if testEnv.DaemonPlatform() == "windows" {
    28  		testD = `FROM busybox
    29  RUN find / -name ba*
    30  RUN find /tmp/`
    31  	} else {
    32  		// -xdev is required because sysfs can cause EPERM
    33  		testD = `FROM busybox
    34  RUN find / -xdev -name ba*
    35  RUN find /tmp/`
    36  	}
    37  	server := fakestorage.New(c, "", fakecontext.WithFiles(map[string]string{"testD": testD}))
    38  	defer server.Close()
    39  
    40  	res, body, err := request.Post("/build?dockerfile=baz&remote="+server.URL()+"/testD", request.JSON)
    41  	c.Assert(err, checker.IsNil)
    42  	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
    43  
    44  	buf, err := testutil.ReadBody(body)
    45  	c.Assert(err, checker.IsNil)
    46  
    47  	// Make sure Dockerfile exists.
    48  	// Make sure 'baz' doesn't exist ANYWHERE despite being mentioned in the URL
    49  	out := string(buf)
    50  	c.Assert(out, checker.Contains, "RUN find /tmp")
    51  	c.Assert(out, checker.Not(checker.Contains), "baz")
    52  }
    53  
    54  func (s *DockerSuite) TestBuildAPIRemoteTarballContext(c *check.C) {
    55  	buffer := new(bytes.Buffer)
    56  	tw := tar.NewWriter(buffer)
    57  	defer tw.Close()
    58  
    59  	dockerfile := []byte("FROM busybox")
    60  	err := tw.WriteHeader(&tar.Header{
    61  		Name: "Dockerfile",
    62  		Size: int64(len(dockerfile)),
    63  	})
    64  	// failed to write tar file header
    65  	c.Assert(err, checker.IsNil)
    66  
    67  	_, err = tw.Write(dockerfile)
    68  	// failed to write tar file content
    69  	c.Assert(err, checker.IsNil)
    70  
    71  	// failed to close tar archive
    72  	c.Assert(tw.Close(), checker.IsNil)
    73  
    74  	server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
    75  		"testT.tar": buffer,
    76  	}))
    77  	defer server.Close()
    78  
    79  	res, b, err := request.Post("/build?remote="+server.URL()+"/testT.tar", request.ContentType("application/tar"))
    80  	c.Assert(err, checker.IsNil)
    81  	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
    82  	b.Close()
    83  }
    84  
    85  func (s *DockerSuite) TestBuildAPIRemoteTarballContextWithCustomDockerfile(c *check.C) {
    86  	buffer := new(bytes.Buffer)
    87  	tw := tar.NewWriter(buffer)
    88  	defer tw.Close()
    89  
    90  	dockerfile := []byte(`FROM busybox
    91  RUN echo 'wrong'`)
    92  	err := tw.WriteHeader(&tar.Header{
    93  		Name: "Dockerfile",
    94  		Size: int64(len(dockerfile)),
    95  	})
    96  	// failed to write tar file header
    97  	c.Assert(err, checker.IsNil)
    98  
    99  	_, err = tw.Write(dockerfile)
   100  	// failed to write tar file content
   101  	c.Assert(err, checker.IsNil)
   102  
   103  	custom := []byte(`FROM busybox
   104  RUN echo 'right'
   105  `)
   106  	err = tw.WriteHeader(&tar.Header{
   107  		Name: "custom",
   108  		Size: int64(len(custom)),
   109  	})
   110  
   111  	// failed to write tar file header
   112  	c.Assert(err, checker.IsNil)
   113  
   114  	_, err = tw.Write(custom)
   115  	// failed to write tar file content
   116  	c.Assert(err, checker.IsNil)
   117  
   118  	// failed to close tar archive
   119  	c.Assert(tw.Close(), checker.IsNil)
   120  
   121  	server := fakestorage.New(c, "", fakecontext.WithBinaryFiles(map[string]*bytes.Buffer{
   122  		"testT.tar": buffer,
   123  	}))
   124  	defer server.Close()
   125  
   126  	url := "/build?dockerfile=custom&remote=" + server.URL() + "/testT.tar"
   127  	res, body, err := request.Post(url, request.ContentType("application/tar"))
   128  	c.Assert(err, checker.IsNil)
   129  	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
   130  
   131  	defer body.Close()
   132  	content, err := testutil.ReadBody(body)
   133  	c.Assert(err, checker.IsNil)
   134  
   135  	// Build used the wrong dockerfile.
   136  	c.Assert(string(content), checker.Not(checker.Contains), "wrong")
   137  }
   138  
   139  func (s *DockerSuite) TestBuildAPILowerDockerfile(c *check.C) {
   140  	git := fakegit.New(c, "repo", map[string]string{
   141  		"dockerfile": `FROM busybox
   142  RUN echo from dockerfile`,
   143  	}, false)
   144  	defer git.Close()
   145  
   146  	res, body, err := request.Post("/build?remote="+git.RepoURL, request.JSON)
   147  	c.Assert(err, checker.IsNil)
   148  	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
   149  
   150  	buf, err := testutil.ReadBody(body)
   151  	c.Assert(err, checker.IsNil)
   152  
   153  	out := string(buf)
   154  	c.Assert(out, checker.Contains, "from dockerfile")
   155  }
   156  
   157  func (s *DockerSuite) TestBuildAPIBuildGitWithF(c *check.C) {
   158  	git := fakegit.New(c, "repo", map[string]string{
   159  		"baz": `FROM busybox
   160  RUN echo from baz`,
   161  		"Dockerfile": `FROM busybox
   162  RUN echo from Dockerfile`,
   163  	}, false)
   164  	defer git.Close()
   165  
   166  	// Make sure it tries to 'dockerfile' query param value
   167  	res, body, err := request.Post("/build?dockerfile=baz&remote="+git.RepoURL, request.JSON)
   168  	c.Assert(err, checker.IsNil)
   169  	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
   170  
   171  	buf, err := testutil.ReadBody(body)
   172  	c.Assert(err, checker.IsNil)
   173  
   174  	out := string(buf)
   175  	c.Assert(out, checker.Contains, "from baz")
   176  }
   177  
   178  func (s *DockerSuite) TestBuildAPIDoubleDockerfile(c *check.C) {
   179  	testRequires(c, UnixCli) // dockerfile overwrites Dockerfile on Windows
   180  	git := fakegit.New(c, "repo", map[string]string{
   181  		"Dockerfile": `FROM busybox
   182  RUN echo from Dockerfile`,
   183  		"dockerfile": `FROM busybox
   184  RUN echo from dockerfile`,
   185  	}, false)
   186  	defer git.Close()
   187  
   188  	// Make sure it tries to 'dockerfile' query param value
   189  	res, body, err := request.Post("/build?remote="+git.RepoURL, request.JSON)
   190  	c.Assert(err, checker.IsNil)
   191  	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
   192  
   193  	buf, err := testutil.ReadBody(body)
   194  	c.Assert(err, checker.IsNil)
   195  
   196  	out := string(buf)
   197  	c.Assert(out, checker.Contains, "from Dockerfile")
   198  }
   199  
   200  func (s *DockerSuite) TestBuildAPIUnnormalizedTarPaths(c *check.C) {
   201  	// Make sure that build context tars with entries of the form
   202  	// x/./y don't cause caching false positives.
   203  
   204  	buildFromTarContext := func(fileContents []byte) string {
   205  		buffer := new(bytes.Buffer)
   206  		tw := tar.NewWriter(buffer)
   207  		defer tw.Close()
   208  
   209  		dockerfile := []byte(`FROM busybox
   210  	COPY dir /dir/`)
   211  		err := tw.WriteHeader(&tar.Header{
   212  			Name: "Dockerfile",
   213  			Size: int64(len(dockerfile)),
   214  		})
   215  		//failed to write tar file header
   216  		c.Assert(err, checker.IsNil)
   217  
   218  		_, err = tw.Write(dockerfile)
   219  		// failed to write Dockerfile in tar file content
   220  		c.Assert(err, checker.IsNil)
   221  
   222  		err = tw.WriteHeader(&tar.Header{
   223  			Name: "dir/./file",
   224  			Size: int64(len(fileContents)),
   225  		})
   226  		//failed to write tar file header
   227  		c.Assert(err, checker.IsNil)
   228  
   229  		_, err = tw.Write(fileContents)
   230  		// failed to write file contents in tar file content
   231  		c.Assert(err, checker.IsNil)
   232  
   233  		// failed to close tar archive
   234  		c.Assert(tw.Close(), checker.IsNil)
   235  
   236  		res, body, err := request.Post("/build", request.RawContent(ioutil.NopCloser(buffer)), request.ContentType("application/x-tar"))
   237  		c.Assert(err, checker.IsNil)
   238  		c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
   239  
   240  		out, err := testutil.ReadBody(body)
   241  		c.Assert(err, checker.IsNil)
   242  		lines := strings.Split(string(out), "\n")
   243  		c.Assert(len(lines), checker.GreaterThan, 1)
   244  		c.Assert(lines[len(lines)-2], checker.Matches, ".*Successfully built [0-9a-f]{12}.*")
   245  
   246  		re := regexp.MustCompile("Successfully built ([0-9a-f]{12})")
   247  		matches := re.FindStringSubmatch(lines[len(lines)-2])
   248  		return matches[1]
   249  	}
   250  
   251  	imageA := buildFromTarContext([]byte("abc"))
   252  	imageB := buildFromTarContext([]byte("def"))
   253  
   254  	c.Assert(imageA, checker.Not(checker.Equals), imageB)
   255  }
   256  
   257  func (s *DockerSuite) TestBuildOnBuildWithCopy(c *check.C) {
   258  	dockerfile := `
   259  		FROM ` + minimalBaseImage() + ` as onbuildbase
   260  		ONBUILD COPY file /file
   261  
   262  		FROM onbuildbase
   263  	`
   264  	ctx := fakecontext.New(c, "",
   265  		fakecontext.WithDockerfile(dockerfile),
   266  		fakecontext.WithFile("file", "some content"),
   267  	)
   268  	defer ctx.Close()
   269  
   270  	res, body, err := request.Post(
   271  		"/build",
   272  		request.RawContent(ctx.AsTarReader(c)),
   273  		request.ContentType("application/x-tar"))
   274  	c.Assert(err, checker.IsNil)
   275  	c.Assert(res.StatusCode, checker.Equals, http.StatusOK)
   276  
   277  	out, err := testutil.ReadBody(body)
   278  	c.Assert(err, checker.IsNil)
   279  	c.Assert(string(out), checker.Contains, "Successfully built")
   280  }
   281  
   282  func (s *DockerSuite) TestBuildOnBuildCache(c *check.C) {
   283  	build := func(dockerfile string) []byte {
   284  		ctx := fakecontext.New(c, "",
   285  			fakecontext.WithDockerfile(dockerfile),
   286  		)
   287  		defer ctx.Close()
   288  
   289  		res, body, err := request.Post(
   290  			"/build",
   291  			request.RawContent(ctx.AsTarReader(c)),
   292  			request.ContentType("application/x-tar"))
   293  		require.NoError(c, err)
   294  		assert.Equal(c, http.StatusOK, res.StatusCode)
   295  
   296  		out, err := testutil.ReadBody(body)
   297  		require.NoError(c, err)
   298  		assert.Contains(c, string(out), "Successfully built")
   299  		return out
   300  	}
   301  
   302  	dockerfile := `
   303  		FROM ` + minimalBaseImage() + ` as onbuildbase
   304  		ENV something=bar
   305  		ONBUILD ENV foo=bar
   306  	`
   307  	build(dockerfile)
   308  
   309  	dockerfile += "FROM onbuildbase"
   310  	out := build(dockerfile)
   311  
   312  	imageIDs := getImageIDsFromBuild(c, out)
   313  	assert.Len(c, imageIDs, 2)
   314  	parentID, childID := imageIDs[0], imageIDs[1]
   315  
   316  	client, err := request.NewClient()
   317  	require.NoError(c, err)
   318  
   319  	// check parentID is correct
   320  	image, _, err := client.ImageInspectWithRaw(context.Background(), childID)
   321  	require.NoError(c, err)
   322  	assert.Equal(c, parentID, image.Parent)
   323  }
   324  
   325  type buildLine struct {
   326  	Stream string
   327  	Aux    struct {
   328  		ID string
   329  	}
   330  }
   331  
   332  func getImageIDsFromBuild(c *check.C, output []byte) []string {
   333  	ids := []string{}
   334  	for _, line := range bytes.Split(output, []byte("\n")) {
   335  		if len(line) == 0 {
   336  			continue
   337  		}
   338  		entry := buildLine{}
   339  		require.NoError(c, json.Unmarshal(line, &entry))
   340  		if entry.Aux.ID != "" {
   341  			ids = append(ids, entry.Aux.ID)
   342  		}
   343  	}
   344  	return ids
   345  }