All `docker build` tests that require an `ExperimentalDaemon` are
migrated to `integration/build` package and start an experimental
daemon to test on it.
The end goal being to remove the `experimental` builds.
Signed-off-by: Vincent Demeester <vincent@sbr.pm>
| ... | ... |
@@ -20,10 +20,7 @@ import ( |
| 20 | 20 |
"github.com/go-check/check" |
| 21 | 21 |
"github.com/gotestyourself/gotestyourself/assert" |
| 22 | 22 |
is "github.com/gotestyourself/gotestyourself/assert/cmp" |
| 23 |
- "github.com/moby/buildkit/session" |
|
| 24 |
- "github.com/moby/buildkit/session/filesync" |
|
| 25 | 23 |
"golang.org/x/net/context" |
| 26 |
- "golang.org/x/sync/errgroup" |
|
| 27 | 24 |
) |
| 28 | 25 |
|
| 29 | 26 |
func (s *DockerSuite) TestBuildAPIDockerFileRemote(c *check.C) {
|
| ... | ... |
@@ -515,106 +512,6 @@ ADD file /file` |
| 515 | 515 |
} |
| 516 | 516 |
} |
| 517 | 517 |
|
| 518 |
-func (s *DockerSuite) TestBuildWithSession(c *check.C) {
|
|
| 519 |
- testRequires(c, ExperimentalDaemon) |
|
| 520 |
- |
|
| 521 |
- dockerfile := ` |
|
| 522 |
- FROM busybox |
|
| 523 |
- COPY file / |
|
| 524 |
- RUN cat /file |
|
| 525 |
- ` |
|
| 526 |
- |
|
| 527 |
- fctx := fakecontext.New(c, "", |
|
| 528 |
- fakecontext.WithFile("file", "some content"),
|
|
| 529 |
- ) |
|
| 530 |
- defer fctx.Close() |
|
| 531 |
- |
|
| 532 |
- out := testBuildWithSession(c, fctx.Dir, dockerfile) |
|
| 533 |
- assert.Check(c, is.Contains(out, "some content")) |
|
| 534 |
- |
|
| 535 |
- fctx.Add("second", "contentcontent")
|
|
| 536 |
- |
|
| 537 |
- dockerfile += ` |
|
| 538 |
- COPY second / |
|
| 539 |
- RUN cat /second |
|
| 540 |
- ` |
|
| 541 |
- |
|
| 542 |
- out = testBuildWithSession(c, fctx.Dir, dockerfile) |
|
| 543 |
- assert.Check(c, is.Equal(strings.Count(out, "Using cache"), 2)) |
|
| 544 |
- assert.Check(c, is.Contains(out, "contentcontent")) |
|
| 545 |
- |
|
| 546 |
- client := testEnv.APIClient() |
|
| 547 |
- du, err := client.DiskUsage(context.TODO()) |
|
| 548 |
- assert.Check(c, err) |
|
| 549 |
- assert.Check(c, du.BuilderSize > 10) |
|
| 550 |
- |
|
| 551 |
- out = testBuildWithSession(c, fctx.Dir, dockerfile) |
|
| 552 |
- assert.Check(c, is.Equal(strings.Count(out, "Using cache"), 4)) |
|
| 553 |
- |
|
| 554 |
- du2, err := client.DiskUsage(context.TODO()) |
|
| 555 |
- assert.Check(c, err) |
|
| 556 |
- assert.Check(c, is.Equal(du.BuilderSize, du2.BuilderSize)) |
|
| 557 |
- |
|
| 558 |
- // rebuild with regular tar, confirm cache still applies |
|
| 559 |
- fctx.Add("Dockerfile", dockerfile)
|
|
| 560 |
- res, body, err := request.Post( |
|
| 561 |
- "/build", |
|
| 562 |
- request.RawContent(fctx.AsTarReader(c)), |
|
| 563 |
- request.ContentType("application/x-tar"))
|
|
| 564 |
- assert.NilError(c, err) |
|
| 565 |
- assert.Check(c, is.DeepEqual(http.StatusOK, res.StatusCode)) |
|
| 566 |
- |
|
| 567 |
- outBytes, err := request.ReadBody(body) |
|
| 568 |
- assert.NilError(c, err) |
|
| 569 |
- assert.Check(c, is.Contains(string(outBytes), "Successfully built")) |
|
| 570 |
- assert.Check(c, is.Equal(strings.Count(string(outBytes), "Using cache"), 4)) |
|
| 571 |
- |
|
| 572 |
- _, err = client.BuildCachePrune(context.TODO()) |
|
| 573 |
- assert.Check(c, err) |
|
| 574 |
- |
|
| 575 |
- du, err = client.DiskUsage(context.TODO()) |
|
| 576 |
- assert.Check(c, err) |
|
| 577 |
- assert.Check(c, is.Equal(du.BuilderSize, int64(0))) |
|
| 578 |
-} |
|
| 579 |
- |
|
| 580 |
-func testBuildWithSession(c *check.C, dir, dockerfile string) (outStr string) {
|
|
| 581 |
- client := testEnv.APIClient() |
|
| 582 |
- sess, err := session.NewSession("foo1", "foo")
|
|
| 583 |
- assert.Check(c, err) |
|
| 584 |
- |
|
| 585 |
- fsProvider := filesync.NewFSSyncProvider([]filesync.SyncedDir{
|
|
| 586 |
- {Dir: dir},
|
|
| 587 |
- }) |
|
| 588 |
- sess.Allow(fsProvider) |
|
| 589 |
- |
|
| 590 |
- g, ctx := errgroup.WithContext(context.Background()) |
|
| 591 |
- |
|
| 592 |
- g.Go(func() error {
|
|
| 593 |
- return sess.Run(ctx, client.DialSession) |
|
| 594 |
- }) |
|
| 595 |
- |
|
| 596 |
- g.Go(func() error {
|
|
| 597 |
- res, body, err := request.Post("/build?remote=client-session&session="+sess.ID(), func(req *http.Request) error {
|
|
| 598 |
- req.Body = ioutil.NopCloser(strings.NewReader(dockerfile)) |
|
| 599 |
- return nil |
|
| 600 |
- }) |
|
| 601 |
- if err != nil {
|
|
| 602 |
- return err |
|
| 603 |
- } |
|
| 604 |
- assert.Check(c, is.DeepEqual(res.StatusCode, http.StatusOK)) |
|
| 605 |
- out, err := request.ReadBody(body) |
|
| 606 |
- assert.NilError(c, err) |
|
| 607 |
- assert.Check(c, is.Contains(string(out), "Successfully built")) |
|
| 608 |
- sess.Close() |
|
| 609 |
- outStr = string(out) |
|
| 610 |
- return nil |
|
| 611 |
- }) |
|
| 612 |
- |
|
| 613 |
- err = g.Wait() |
|
| 614 |
- assert.Check(c, err) |
|
| 615 |
- return |
|
| 616 |
-} |
|
| 617 |
- |
|
| 618 | 518 |
func (s *DockerSuite) TestBuildScratchCopy(c *check.C) {
|
| 619 | 519 |
testRequires(c, DaemonIsLinux) |
| 620 | 520 |
dockerfile := `FROM scratch |
| ... | ... |
@@ -5598,46 +5598,6 @@ func (s *DockerSuite) TestBuildWithExtraHostInvalidFormat(c *check.C) {
|
| 5598 | 5598 |
|
| 5599 | 5599 |
} |
| 5600 | 5600 |
|
| 5601 |
-func (s *DockerSuite) TestBuildSquashParent(c *check.C) {
|
|
| 5602 |
- testRequires(c, ExperimentalDaemon) |
|
| 5603 |
- dockerFile := ` |
|
| 5604 |
- FROM busybox |
|
| 5605 |
- RUN echo hello > /hello |
|
| 5606 |
- RUN echo world >> /hello |
|
| 5607 |
- RUN echo hello > /remove_me |
|
| 5608 |
- ENV HELLO world |
|
| 5609 |
- RUN rm /remove_me |
|
| 5610 |
- ` |
|
| 5611 |
- // build and get the ID that we can use later for history comparison |
|
| 5612 |
- name := "test" |
|
| 5613 |
- buildImageSuccessfully(c, name, build.WithDockerfile(dockerFile)) |
|
| 5614 |
- origID := getIDByName(c, name) |
|
| 5615 |
- |
|
| 5616 |
- // build with squash |
|
| 5617 |
- buildImageSuccessfully(c, name, cli.WithFlags("--squash"), build.WithDockerfile(dockerFile))
|
|
| 5618 |
- id := getIDByName(c, name) |
|
| 5619 |
- |
|
| 5620 |
- out, _ := dockerCmd(c, "run", "--rm", id, "/bin/sh", "-c", "cat /hello") |
|
| 5621 |
- c.Assert(strings.TrimSpace(out), checker.Equals, "hello\nworld") |
|
| 5622 |
- |
|
| 5623 |
- dockerCmd(c, "run", "--rm", id, "/bin/sh", "-c", "[ ! -f /remove_me ]") |
|
| 5624 |
- dockerCmd(c, "run", "--rm", id, "/bin/sh", "-c", `[ "$(echo $HELLO)" == "world" ]`) |
|
| 5625 |
- |
|
| 5626 |
- // make sure the ID produced is the ID of the tag we specified |
|
| 5627 |
- inspectID := inspectImage(c, "test", ".ID") |
|
| 5628 |
- c.Assert(inspectID, checker.Equals, id) |
|
| 5629 |
- |
|
| 5630 |
- origHistory, _ := dockerCmd(c, "history", origID) |
|
| 5631 |
- testHistory, _ := dockerCmd(c, "history", "test") |
|
| 5632 |
- |
|
| 5633 |
- splitOrigHistory := strings.Split(strings.TrimSpace(origHistory), "\n") |
|
| 5634 |
- splitTestHistory := strings.Split(strings.TrimSpace(testHistory), "\n") |
|
| 5635 |
- c.Assert(len(splitTestHistory), checker.Equals, len(splitOrigHistory)+1) |
|
| 5636 |
- |
|
| 5637 |
- out = inspectImage(c, id, "len .RootFS.Layers") |
|
| 5638 |
- c.Assert(strings.TrimSpace(out), checker.Equals, "2") |
|
| 5639 |
-} |
|
| 5640 |
- |
|
| 5641 | 5601 |
func (s *DockerSuite) TestBuildContChar(c *check.C) {
|
| 5642 | 5602 |
name := "testbuildcontchar" |
| 5643 | 5603 |
|
| ... | ... |
@@ -6237,33 +6197,3 @@ func (s *DockerSuite) TestBuildIidFileCleanupOnFail(c *check.C) {
|
| 6237 | 6237 |
c.Assert(err, check.NotNil) |
| 6238 | 6238 |
c.Assert(os.IsNotExist(err), check.Equals, true) |
| 6239 | 6239 |
} |
| 6240 |
- |
|
| 6241 |
-// FIXME(vdemeester) should migrate to docker/cli tests |
|
| 6242 |
-func (s *DockerSuite) TestBuildIidFileSquash(c *check.C) {
|
|
| 6243 |
- testRequires(c, ExperimentalDaemon) |
|
| 6244 |
- tmpDir, err := ioutil.TempDir("", "TestBuildIidFileSquash")
|
|
| 6245 |
- if err != nil {
|
|
| 6246 |
- c.Fatal(err) |
|
| 6247 |
- } |
|
| 6248 |
- defer os.RemoveAll(tmpDir) |
|
| 6249 |
- tmpIidFile := filepath.Join(tmpDir, "iidsquash") |
|
| 6250 |
- |
|
| 6251 |
- name := "testbuildiidfilesquash" |
|
| 6252 |
- // Use a Dockerfile with multiple stages to ensure we get the last one |
|
| 6253 |
- cli.BuildCmd(c, name, |
|
| 6254 |
- // This could be minimalBaseImage except |
|
| 6255 |
- // https://github.com/moby/moby/issues/33823 requires |
|
| 6256 |
- // `touch` to workaround. |
|
| 6257 |
- build.WithDockerfile(`FROM busybox |
|
| 6258 |
-ENV FOO FOO |
|
| 6259 |
-ENV BAR BAR |
|
| 6260 |
-RUN touch /foop |
|
| 6261 |
-`), |
|
| 6262 |
- cli.WithFlags("--iidfile", tmpIidFile, "--squash"))
|
|
| 6263 |
- |
|
| 6264 |
- id, err := ioutil.ReadFile(tmpIidFile) |
|
| 6265 |
- c.Assert(err, check.IsNil) |
|
| 6266 |
- d, err := digest.Parse(string(id)) |
|
| 6267 |
- c.Assert(err, check.IsNil) |
|
| 6268 |
- c.Assert(d.String(), checker.Equals, getIDByName(c, name)) |
|
| 6269 |
-} |
| 6270 | 6240 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,132 @@ |
| 0 |
+package build |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "context" |
|
| 4 |
+ "io/ioutil" |
|
| 5 |
+ "net/http" |
|
| 6 |
+ "strings" |
|
| 7 |
+ "testing" |
|
| 8 |
+ |
|
| 9 |
+ dclient "github.com/docker/docker/client" |
|
| 10 |
+ "github.com/docker/docker/integration-cli/cli/build/fakecontext" |
|
| 11 |
+ "github.com/docker/docker/integration-cli/daemon" |
|
| 12 |
+ "github.com/docker/docker/integration-cli/request" |
|
| 13 |
+ "github.com/gotestyourself/gotestyourself/assert" |
|
| 14 |
+ is "github.com/gotestyourself/gotestyourself/assert/cmp" |
|
| 15 |
+ "github.com/moby/buildkit/session" |
|
| 16 |
+ "github.com/moby/buildkit/session/filesync" |
|
| 17 |
+ "golang.org/x/sync/errgroup" |
|
| 18 |
+) |
|
| 19 |
+ |
|
| 20 |
+func TestBuildWithSession(t *testing.T) {
|
|
| 21 |
+ d := daemon.New(t, "", "dockerd", daemon.Config{
|
|
| 22 |
+ Experimental: true, |
|
| 23 |
+ }) |
|
| 24 |
+ d.StartWithBusybox(t) |
|
| 25 |
+ defer d.Stop(t) |
|
| 26 |
+ |
|
| 27 |
+ client, err := d.NewClient() |
|
| 28 |
+ assert.NilError(t, err) |
|
| 29 |
+ |
|
| 30 |
+ dockerfile := ` |
|
| 31 |
+ FROM busybox |
|
| 32 |
+ COPY file / |
|
| 33 |
+ RUN cat /file |
|
| 34 |
+ ` |
|
| 35 |
+ |
|
| 36 |
+ fctx := fakecontext.New(t, "", |
|
| 37 |
+ fakecontext.WithFile("file", "some content"),
|
|
| 38 |
+ ) |
|
| 39 |
+ defer fctx.Close() |
|
| 40 |
+ |
|
| 41 |
+ out := testBuildWithSession(t, client, d.Sock(), fctx.Dir, dockerfile) |
|
| 42 |
+ assert.Check(t, is.Contains(out, "some content")) |
|
| 43 |
+ |
|
| 44 |
+ fctx.Add("second", "contentcontent")
|
|
| 45 |
+ |
|
| 46 |
+ dockerfile += ` |
|
| 47 |
+ COPY second / |
|
| 48 |
+ RUN cat /second |
|
| 49 |
+ ` |
|
| 50 |
+ |
|
| 51 |
+ out = testBuildWithSession(t, client, d.Sock(), fctx.Dir, dockerfile) |
|
| 52 |
+ assert.Check(t, is.Equal(strings.Count(out, "Using cache"), 2)) |
|
| 53 |
+ assert.Check(t, is.Contains(out, "contentcontent")) |
|
| 54 |
+ |
|
| 55 |
+ du, err := client.DiskUsage(context.TODO()) |
|
| 56 |
+ assert.Check(t, err) |
|
| 57 |
+ assert.Check(t, du.BuilderSize > 10) |
|
| 58 |
+ |
|
| 59 |
+ out = testBuildWithSession(t, client, d.Sock(), fctx.Dir, dockerfile) |
|
| 60 |
+ assert.Check(t, is.Equal(strings.Count(out, "Using cache"), 4)) |
|
| 61 |
+ |
|
| 62 |
+ du2, err := client.DiskUsage(context.TODO()) |
|
| 63 |
+ assert.Check(t, err) |
|
| 64 |
+ assert.Check(t, is.Equal(du.BuilderSize, du2.BuilderSize)) |
|
| 65 |
+ |
|
| 66 |
+ // rebuild with regular tar, confirm cache still applies |
|
| 67 |
+ fctx.Add("Dockerfile", dockerfile)
|
|
| 68 |
+ // FIXME(vdemeester) use sock here |
|
| 69 |
+ res, body, err := request.DoOnHost(d.Sock(), |
|
| 70 |
+ "/build", |
|
| 71 |
+ request.Method(http.MethodPost), |
|
| 72 |
+ request.RawContent(fctx.AsTarReader(t)), |
|
| 73 |
+ request.ContentType("application/x-tar"))
|
|
| 74 |
+ assert.NilError(t, err) |
|
| 75 |
+ assert.Check(t, is.DeepEqual(http.StatusOK, res.StatusCode)) |
|
| 76 |
+ |
|
| 77 |
+ outBytes, err := request.ReadBody(body) |
|
| 78 |
+ assert.NilError(t, err) |
|
| 79 |
+ assert.Check(t, is.Contains(string(outBytes), "Successfully built")) |
|
| 80 |
+ assert.Check(t, is.Equal(strings.Count(string(outBytes), "Using cache"), 4)) |
|
| 81 |
+ |
|
| 82 |
+ _, err = client.BuildCachePrune(context.TODO()) |
|
| 83 |
+ assert.Check(t, err) |
|
| 84 |
+ |
|
| 85 |
+ du, err = client.DiskUsage(context.TODO()) |
|
| 86 |
+ assert.Check(t, err) |
|
| 87 |
+ assert.Check(t, is.Equal(du.BuilderSize, int64(0))) |
|
| 88 |
+} |
|
| 89 |
+ |
|
| 90 |
+func testBuildWithSession(t *testing.T, client dclient.APIClient, daemonSock string, dir, dockerfile string) (outStr string) {
|
|
| 91 |
+ sess, err := session.NewSession("foo1", "foo")
|
|
| 92 |
+ assert.Check(t, err) |
|
| 93 |
+ |
|
| 94 |
+ fsProvider := filesync.NewFSSyncProvider([]filesync.SyncedDir{
|
|
| 95 |
+ {Dir: dir},
|
|
| 96 |
+ }) |
|
| 97 |
+ sess.Allow(fsProvider) |
|
| 98 |
+ |
|
| 99 |
+ g, ctx := errgroup.WithContext(context.Background()) |
|
| 100 |
+ |
|
| 101 |
+ g.Go(func() error {
|
|
| 102 |
+ return sess.Run(ctx, client.DialSession) |
|
| 103 |
+ }) |
|
| 104 |
+ |
|
| 105 |
+ g.Go(func() error {
|
|
| 106 |
+ // FIXME use sock here |
|
| 107 |
+ res, body, err := request.DoOnHost( |
|
| 108 |
+ daemonSock, |
|
| 109 |
+ "/build?remote=client-session&session="+sess.ID(), |
|
| 110 |
+ request.Method(http.MethodPost), |
|
| 111 |
+ func(req *http.Request) error {
|
|
| 112 |
+ req.Body = ioutil.NopCloser(strings.NewReader(dockerfile)) |
|
| 113 |
+ return nil |
|
| 114 |
+ }, |
|
| 115 |
+ ) |
|
| 116 |
+ if err != nil {
|
|
| 117 |
+ return err |
|
| 118 |
+ } |
|
| 119 |
+ assert.Check(t, is.DeepEqual(res.StatusCode, http.StatusOK)) |
|
| 120 |
+ out, err := request.ReadBody(body) |
|
| 121 |
+ assert.NilError(t, err) |
|
| 122 |
+ assert.Check(t, is.Contains(string(out), "Successfully built")) |
|
| 123 |
+ sess.Close() |
|
| 124 |
+ outStr = string(out) |
|
| 125 |
+ return nil |
|
| 126 |
+ }) |
|
| 127 |
+ |
|
| 128 |
+ err = g.Wait() |
|
| 129 |
+ assert.Check(t, err) |
|
| 130 |
+ return |
|
| 131 |
+} |
| 0 | 132 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,108 @@ |
| 0 |
+package build |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "bytes" |
|
| 4 |
+ "context" |
|
| 5 |
+ "io" |
|
| 6 |
+ "io/ioutil" |
|
| 7 |
+ "strings" |
|
| 8 |
+ "testing" |
|
| 9 |
+ |
|
| 10 |
+ "github.com/docker/docker/api/types" |
|
| 11 |
+ "github.com/docker/docker/integration-cli/cli/build/fakecontext" |
|
| 12 |
+ "github.com/docker/docker/integration-cli/daemon" |
|
| 13 |
+ "github.com/docker/docker/integration/internal/container" |
|
| 14 |
+ "github.com/docker/docker/pkg/stdcopy" |
|
| 15 |
+ "github.com/gotestyourself/gotestyourself/assert" |
|
| 16 |
+ is "github.com/gotestyourself/gotestyourself/assert/cmp" |
|
| 17 |
+) |
|
| 18 |
+ |
|
| 19 |
+func TestBuildSquashParent(t *testing.T) {
|
|
| 20 |
+ d := daemon.New(t, "", "dockerd", daemon.Config{
|
|
| 21 |
+ Experimental: true, |
|
| 22 |
+ }) |
|
| 23 |
+ d.StartWithBusybox(t) |
|
| 24 |
+ defer d.Stop(t) |
|
| 25 |
+ |
|
| 26 |
+ client, err := d.NewClient() |
|
| 27 |
+ assert.NilError(t, err) |
|
| 28 |
+ |
|
| 29 |
+ dockerfile := ` |
|
| 30 |
+ FROM busybox |
|
| 31 |
+ RUN echo hello > /hello |
|
| 32 |
+ RUN echo world >> /hello |
|
| 33 |
+ RUN echo hello > /remove_me |
|
| 34 |
+ ENV HELLO world |
|
| 35 |
+ RUN rm /remove_me |
|
| 36 |
+ ` |
|
| 37 |
+ |
|
| 38 |
+ // build and get the ID that we can use later for history comparison |
|
| 39 |
+ ctx := context.Background() |
|
| 40 |
+ source := fakecontext.New(t, "", fakecontext.WithDockerfile(dockerfile)) |
|
| 41 |
+ defer source.Close() |
|
| 42 |
+ |
|
| 43 |
+ name := "test" |
|
| 44 |
+ resp, err := client.ImageBuild(ctx, |
|
| 45 |
+ source.AsTarReader(t), |
|
| 46 |
+ types.ImageBuildOptions{
|
|
| 47 |
+ Remove: true, |
|
| 48 |
+ ForceRemove: true, |
|
| 49 |
+ Tags: []string{name},
|
|
| 50 |
+ }) |
|
| 51 |
+ assert.NilError(t, err) |
|
| 52 |
+ _, err = io.Copy(ioutil.Discard, resp.Body) |
|
| 53 |
+ resp.Body.Close() |
|
| 54 |
+ assert.NilError(t, err) |
|
| 55 |
+ |
|
| 56 |
+ inspect, _, err := client.ImageInspectWithRaw(ctx, name) |
|
| 57 |
+ assert.NilError(t, err) |
|
| 58 |
+ origID := inspect.ID |
|
| 59 |
+ |
|
| 60 |
+ // build with squash |
|
| 61 |
+ resp, err = client.ImageBuild(ctx, |
|
| 62 |
+ source.AsTarReader(t), |
|
| 63 |
+ types.ImageBuildOptions{
|
|
| 64 |
+ Remove: true, |
|
| 65 |
+ ForceRemove: true, |
|
| 66 |
+ Squash: true, |
|
| 67 |
+ Tags: []string{name},
|
|
| 68 |
+ }) |
|
| 69 |
+ assert.NilError(t, err) |
|
| 70 |
+ _, err = io.Copy(ioutil.Discard, resp.Body) |
|
| 71 |
+ resp.Body.Close() |
|
| 72 |
+ assert.NilError(t, err) |
|
| 73 |
+ |
|
| 74 |
+ cid := container.Run(t, ctx, client, |
|
| 75 |
+ container.WithImage(name), |
|
| 76 |
+ container.WithCmd("/bin/sh", "-c", "cat /hello"),
|
|
| 77 |
+ ) |
|
| 78 |
+ reader, err := client.ContainerLogs(ctx, cid, types.ContainerLogsOptions{
|
|
| 79 |
+ ShowStdout: true, |
|
| 80 |
+ }) |
|
| 81 |
+ assert.NilError(t, err) |
|
| 82 |
+ |
|
| 83 |
+ actualStdout := new(bytes.Buffer) |
|
| 84 |
+ actualStderr := ioutil.Discard |
|
| 85 |
+ _, err = stdcopy.StdCopy(actualStdout, actualStderr, reader) |
|
| 86 |
+ assert.NilError(t, err) |
|
| 87 |
+ assert.Check(t, is.Equal(strings.TrimSpace(actualStdout.String()), "hello\nworld")) |
|
| 88 |
+ |
|
| 89 |
+ container.Run(t, ctx, client, |
|
| 90 |
+ container.WithImage(name), |
|
| 91 |
+ container.WithCmd("/bin/sh", "-c", "[ ! -f /remove_me ]"),
|
|
| 92 |
+ ) |
|
| 93 |
+ container.Run(t, ctx, client, |
|
| 94 |
+ container.WithImage(name), |
|
| 95 |
+ container.WithCmd("/bin/sh", "-c", `[ "$(echo $HELLO)" == "world" ]`),
|
|
| 96 |
+ ) |
|
| 97 |
+ |
|
| 98 |
+ origHistory, err := client.ImageHistory(ctx, origID) |
|
| 99 |
+ assert.NilError(t, err) |
|
| 100 |
+ testHistory, err := client.ImageHistory(ctx, name) |
|
| 101 |
+ assert.NilError(t, err) |
|
| 102 |
+ |
|
| 103 |
+ inspect, _, err = client.ImageInspectWithRaw(ctx, name) |
|
| 104 |
+ assert.NilError(t, err) |
|
| 105 |
+ assert.Check(t, is.Len(testHistory, len(origHistory)+1)) |
|
| 106 |
+ assert.Check(t, is.Len(inspect.RootFS.Layers, 2)) |
|
| 107 |
+} |