build_squash_test.go 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. package build
  2. import (
  3. "bytes"
  4. "io"
  5. "strings"
  6. "testing"
  7. "github.com/docker/docker/api/types"
  8. containertypes "github.com/docker/docker/api/types/container"
  9. dclient "github.com/docker/docker/client"
  10. "github.com/docker/docker/integration/internal/container"
  11. "github.com/docker/docker/pkg/stdcopy"
  12. "github.com/docker/docker/testutil"
  13. "github.com/docker/docker/testutil/daemon"
  14. "github.com/docker/docker/testutil/fakecontext"
  15. "gotest.tools/v3/assert"
  16. is "gotest.tools/v3/assert/cmp"
  17. "gotest.tools/v3/skip"
  18. )
  19. func TestBuildSquashParent(t *testing.T) {
  20. skip.If(t, testEnv.DaemonInfo.OSType == "windows")
  21. skip.If(t, testEnv.UsingSnapshotter(), "squash is not implemented for containerd image store")
  22. ctx := testutil.StartSpan(baseContext, t)
  23. var client dclient.APIClient
  24. if !testEnv.DaemonInfo.ExperimentalBuild {
  25. skip.If(t, testEnv.IsRemoteDaemon, "cannot run daemon when remote daemon")
  26. d := daemon.New(t, daemon.WithExperimental())
  27. d.StartWithBusybox(ctx, t)
  28. defer d.Stop(t)
  29. client = d.NewClientT(t)
  30. } else {
  31. client = testEnv.APIClient()
  32. }
  33. dockerfile := `
  34. FROM busybox
  35. RUN echo hello > /hello
  36. RUN echo world >> /hello
  37. RUN echo hello > /remove_me
  38. ENV HELLO world
  39. RUN rm /remove_me
  40. `
  41. // build and get the ID that we can use later for history comparison
  42. source := fakecontext.New(t, "", fakecontext.WithDockerfile(dockerfile))
  43. defer source.Close()
  44. name := strings.ToLower(t.Name())
  45. resp, err := client.ImageBuild(ctx,
  46. source.AsTarReader(t),
  47. types.ImageBuildOptions{
  48. Remove: true,
  49. ForceRemove: true,
  50. Tags: []string{name},
  51. })
  52. assert.NilError(t, err)
  53. _, err = io.Copy(io.Discard, resp.Body)
  54. resp.Body.Close()
  55. assert.NilError(t, err)
  56. inspect, _, err := client.ImageInspectWithRaw(ctx, name)
  57. assert.NilError(t, err)
  58. origID := inspect.ID
  59. // build with squash
  60. resp, err = client.ImageBuild(ctx,
  61. source.AsTarReader(t),
  62. types.ImageBuildOptions{
  63. Remove: true,
  64. ForceRemove: true,
  65. Squash: true,
  66. Tags: []string{name},
  67. })
  68. assert.NilError(t, err)
  69. _, err = io.Copy(io.Discard, resp.Body)
  70. resp.Body.Close()
  71. assert.NilError(t, err)
  72. cid := container.Run(ctx, t, client,
  73. container.WithImage(name),
  74. container.WithCmd("/bin/sh", "-c", "cat /hello"),
  75. )
  76. reader, err := client.ContainerLogs(ctx, cid, containertypes.LogsOptions{
  77. ShowStdout: true,
  78. })
  79. assert.NilError(t, err)
  80. actualStdout := new(bytes.Buffer)
  81. actualStderr := io.Discard
  82. _, err = stdcopy.StdCopy(actualStdout, actualStderr, reader)
  83. assert.NilError(t, err)
  84. assert.Check(t, is.Equal(strings.TrimSpace(actualStdout.String()), "hello\nworld"))
  85. container.Run(ctx, t, client,
  86. container.WithImage(name),
  87. container.WithCmd("/bin/sh", "-c", "[ ! -f /remove_me ]"),
  88. )
  89. container.Run(ctx, t, client,
  90. container.WithImage(name),
  91. container.WithCmd("/bin/sh", "-c", `[ "$(echo $HELLO)" = "world" ]`),
  92. )
  93. origHistory, err := client.ImageHistory(ctx, origID)
  94. assert.NilError(t, err)
  95. testHistory, err := client.ImageHistory(ctx, name)
  96. assert.NilError(t, err)
  97. inspect, _, err = client.ImageInspectWithRaw(ctx, name)
  98. assert.NilError(t, err)
  99. assert.Check(t, is.Len(testHistory, len(origHistory)+1))
  100. assert.Check(t, is.Len(inspect.RootFS.Layers, 2))
  101. }