1
0
mirror of https://github.com/moby/moby.git synced 2025-04-18 20:44:11 +03:00
moby/integration-cli/docker_cli_save_load_test.go
Aleksa Sarai 5e4e34a966
tests: migrate strings.Contains -> is.Contains in assertions
Migrated using

  find . -type f -name "*_test.go" |
    xargs gofmt -w \
      -r "assert.Check(t, strings.Contains(a, b)) -> assert.Check(t, is.Contains(a, b))"

  find . -type f -name "*_test.go" |
    xargs gofmt -w \
      -r "assert.Assert(t, strings.Contains(a, b)) -> assert.Assert(t, is.Contains(a, b))"

Using a boolean in assert.Assert or assert.Check results in error
messages that don't contain the actual problematic string, and when
running the integration suite on an actual machine (where the source
code parsing doesn't work) this makes it almost impossible to figure out
what the actual error is.

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
2024-11-22 23:59:20 +11:00

309 lines
10 KiB
Go

package main
import (
"context"
"encoding/json"
"fmt"
"os"
"os/exec"
"path/filepath"
"strings"
"testing"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/integration-cli/cli"
"github.com/docker/docker/integration-cli/cli/build"
"github.com/docker/docker/internal/testutils/specialimage"
"gotest.tools/v3/assert"
is "gotest.tools/v3/assert/cmp"
"gotest.tools/v3/icmd"
"gotest.tools/v3/skip"
)
type DockerCLISaveLoadSuite struct {
ds *DockerSuite
}
func (s *DockerCLISaveLoadSuite) TearDownTest(ctx context.Context, c *testing.T) {
s.ds.TearDownTest(ctx, c)
}
func (s *DockerCLISaveLoadSuite) OnTimeout(c *testing.T) {
s.ds.OnTimeout(c)
}
// save a repo using gz compression and try to load it using stdout
func (s *DockerCLISaveLoadSuite) TestSaveXzAndLoadRepoStdout(c *testing.T) {
testRequires(c, DaemonIsLinux)
name := "test-save-xz-and-load-repo-stdout"
cli.DockerCmd(c, "run", "--name", name, "busybox", "true")
imgRepoName := "foobar-save-load-test-xz-gz"
out := cli.DockerCmd(c, "commit", name, imgRepoName).Combined()
cli.DockerCmd(c, "inspect", imgRepoName)
repoTarball, err := RunCommandPipelineWithOutput(
exec.Command(dockerBinary, "save", imgRepoName),
exec.Command("xz", "-c"),
exec.Command("gzip", "-c"))
assert.NilError(c, err, "failed to save repo: %v %v", out, err)
deleteImages(imgRepoName)
icmd.RunCmd(icmd.Cmd{
Command: []string{dockerBinary, "load"},
Stdin: strings.NewReader(repoTarball),
}).Assert(c, icmd.Expected{
ExitCode: 1,
})
after, _, err := dockerCmdWithError("inspect", imgRepoName)
assert.ErrorContains(c, err, "", "the repo should not exist: %v", after)
}
// save a repo using xz+gz compression and try to load it using stdout
func (s *DockerCLISaveLoadSuite) TestSaveXzGzAndLoadRepoStdout(c *testing.T) {
testRequires(c, DaemonIsLinux)
name := "test-save-xz-gz-and-load-repo-stdout"
cli.DockerCmd(c, "run", "--name", name, "busybox", "true")
repoName := "foobar-save-load-test-xz-gz"
cli.DockerCmd(c, "commit", name, repoName)
cli.DockerCmd(c, "inspect", repoName)
out, err := RunCommandPipelineWithOutput(
exec.Command(dockerBinary, "save", repoName),
exec.Command("xz", "-c"),
exec.Command("gzip", "-c"))
assert.NilError(c, err, "failed to save repo: %v %v", out, err)
deleteImages(repoName)
icmd.RunCmd(icmd.Cmd{
Command: []string{dockerBinary, "load"},
Stdin: strings.NewReader(out),
}).Assert(c, icmd.Expected{
ExitCode: 1,
})
after, _, err := dockerCmdWithError("inspect", repoName)
assert.ErrorContains(c, err, "", "the repo should not exist: %v", after)
}
func (s *DockerCLISaveLoadSuite) TestSaveSingleTag(c *testing.T) {
testRequires(c, DaemonIsLinux)
imgRepoName := "foobar-save-single-tag-test"
cli.DockerCmd(c, "tag", "busybox:latest", fmt.Sprintf("%v:latest", imgRepoName))
out := cli.DockerCmd(c, "images", "-q", "--no-trunc", imgRepoName).Stdout()
cleanedImageID := strings.TrimSpace(out)
filesFilter := fmt.Sprintf("(^manifest.json$|%v)", cleanedImageID)
if testEnv.UsingSnapshotter() {
filesFilter = fmt.Sprintf("(^index.json$|^manifest.json$|%v)", cleanedImageID)
}
out, err := RunCommandPipelineWithOutput(
exec.Command(dockerBinary, "save", fmt.Sprintf("%v:latest", imgRepoName)),
exec.Command("tar", "t"),
exec.Command("grep", "-E", filesFilter))
assert.NilError(c, err, "failed to save repo with image ID and index files: %s, %v", out, err)
}
func (s *DockerCLISaveLoadSuite) TestSaveImageId(c *testing.T) {
testRequires(c, DaemonIsLinux)
emptyFSImage := loadSpecialImage(c, specialimage.EmptyFS)
imgRepoName := "foobar-save-image-id-test"
cli.DockerCmd(c, "tag", emptyFSImage, fmt.Sprintf("%v:latest", imgRepoName))
out := cli.DockerCmd(c, "images", "-q", "--no-trunc", imgRepoName).Stdout()
cleanedLongImageID := strings.TrimPrefix(strings.TrimSpace(out), "sha256:")
out = cli.DockerCmd(c, "images", "-q", imgRepoName).Stdout()
cleanedShortImageID := strings.TrimSpace(out)
// Make sure IDs are not empty
assert.Assert(c, cleanedLongImageID != "", "Id should not be empty.")
assert.Assert(c, cleanedShortImageID != "", "Id should not be empty.")
saveCmd := exec.Command(dockerBinary, "save", cleanedShortImageID)
tarCmd := exec.Command("tar", "t")
var err error
tarCmd.Stdin, err = saveCmd.StdoutPipe()
assert.Assert(c, err == nil, "cannot set stdout pipe for tar: %v", err)
grepCmd := exec.Command("grep", cleanedLongImageID)
grepCmd.Stdin, err = tarCmd.StdoutPipe()
assert.Assert(c, err == nil, "cannot set stdout pipe for grep: %v", err)
assert.Assert(c, tarCmd.Start() == nil, "tar failed with error: %v", err)
assert.Assert(c, saveCmd.Start() == nil, "docker save failed with error: %v", err)
defer func() {
saveCmd.Wait()
tarCmd.Wait()
cli.DockerCmd(c, "rmi", imgRepoName)
}()
out, _, err = runCommandWithOutput(grepCmd)
assert.Assert(c, err == nil, "failed to save repo with image ID: %s, %v", out, err)
}
// save a repo and try to load it using flags
func (s *DockerCLISaveLoadSuite) TestSaveAndLoadRepoFlags(c *testing.T) {
testRequires(c, DaemonIsLinux)
const name = "test-save-and-load-repo-flags"
cli.DockerCmd(c, "run", "--name", name, "busybox", "true")
const imgRepoName = "foobar-save-load-test"
deleteImages(imgRepoName)
cli.DockerCmd(c, "commit", name, imgRepoName)
beforeStr := cli.DockerCmd(c, "inspect", imgRepoName).Stdout()
out, err := RunCommandPipelineWithOutput(
exec.Command(dockerBinary, "save", imgRepoName),
exec.Command(dockerBinary, "load"))
assert.NilError(c, err, "failed to save and load repo: %s, %v", out, err)
afterStr := cli.DockerCmd(c, "inspect", imgRepoName).Stdout()
var before, after []image.InspectResponse
err = json.Unmarshal([]byte(beforeStr), &before)
assert.NilError(c, err, "failed to parse inspect 'before' output")
err = json.Unmarshal([]byte(afterStr), &after)
assert.NilError(c, err, "failed to parse inspect 'after' output")
assert.Assert(c, is.Len(before, 1))
assert.Assert(c, is.Len(after, 1))
if testEnv.UsingSnapshotter() {
// Ignore LastTagTime difference with c8d.
// It is not stored in the image archive, but in the imageStore
// which is a graphdrivers implementation detail.
//
// It works because we load the image into the same daemon which saved
// the image. It would still fail with the graphdrivers if the image
// was loaded into a different daemon (which should be the case in a
// real-world scenario).
before[0].Metadata.LastTagTime = after[0].Metadata.LastTagTime
}
assert.Check(c, is.DeepEqual(before, after), "inspect is not the same after a save / load")
}
func (s *DockerCLISaveLoadSuite) TestSaveWithNoExistImage(c *testing.T) {
testRequires(c, DaemonIsLinux)
imgName := "foobar-non-existing-image"
out, _, err := dockerCmdWithError("save", "-o", "test-img.tar", imgName)
assert.ErrorContains(c, err, "", "save image should fail for non-existing image")
assert.Assert(c, is.Contains(out, fmt.Sprintf("No such image: %s", imgName)))
}
func (s *DockerCLISaveLoadSuite) TestSaveMultipleNames(c *testing.T) {
testRequires(c, DaemonIsLinux)
emptyFSImage := loadSpecialImage(c, specialimage.EmptyFS)
const imgRepoName = "foobar-save-multi-name-test"
oneTag := fmt.Sprintf("%v-one:latest", imgRepoName)
twoTag := fmt.Sprintf("%v-two:latest", imgRepoName)
cli.DockerCmd(c, "tag", emptyFSImage, oneTag)
cli.DockerCmd(c, "tag", emptyFSImage, twoTag)
out, err := RunCommandPipelineWithOutput(
exec.Command(dockerBinary, "save", strings.TrimSuffix(oneTag, ":latest"), twoTag),
exec.Command("tar", "xO", "index.json"),
)
assert.NilError(c, err, "failed to save multiple repos: %s, %v", out, err)
assert.Check(c, is.Contains(out, oneTag))
assert.Check(c, is.Contains(out, twoTag))
}
// Test loading a weird image where one of the layers is of zero size.
// The layer.tar file is actually zero bytes, no padding or anything else.
// See issue: 18170
func (s *DockerCLISaveLoadSuite) TestLoadZeroSizeLayer(c *testing.T) {
// TODO(vvoland): Create an OCI image with 0 bytes layer.
skip.If(c, testEnv.UsingSnapshotter(), "input archive is not OCI compatible")
// this will definitely not work if using remote daemon
// very weird test
testRequires(c, DaemonIsLinux, testEnv.IsLocalDaemon)
cli.DockerCmd(c, "load", "-i", "testdata/emptyLayer.tar")
}
func (s *DockerCLISaveLoadSuite) TestSaveLoadParents(c *testing.T) {
testRequires(c, DaemonIsLinux)
skip.If(c, testEnv.UsingSnapshotter(), "Parent image property is not supported with containerd")
makeImage := func(from string, addfile string) string {
id := cli.DockerCmd(c, "run", "-d", from, "touch", addfile).Stdout()
id = strings.TrimSpace(id)
imageID := cli.DockerCmd(c, "commit", id).Stdout()
imageID = strings.TrimSpace(imageID)
cli.DockerCmd(c, "rm", "-f", id)
return imageID
}
idFoo := makeImage("busybox", "foo")
idBar := makeImage(idFoo, "bar")
tmpDir, err := os.MkdirTemp("", "save-load-parents")
assert.NilError(c, err)
defer os.RemoveAll(tmpDir)
c.Log("tmpdir", tmpDir)
outfile := filepath.Join(tmpDir, "out.tar")
cli.DockerCmd(c, "save", "-o", outfile, idBar, idFoo)
cli.DockerCmd(c, "rmi", idBar)
cli.DockerCmd(c, "load", "-i", outfile)
inspectOut := inspectField(c, idBar, "Parent")
assert.Equal(c, inspectOut, idFoo)
inspectOut = inspectField(c, idFoo, "Parent")
assert.Equal(c, inspectOut, "")
}
func (s *DockerCLISaveLoadSuite) TestSaveLoadNoTag(c *testing.T) {
testRequires(c, DaemonIsLinux)
name := "saveloadnotag"
buildImageSuccessfully(c, name, build.WithDockerfile("FROM busybox\nENV foo=bar"))
id := inspectField(c, name, "Id")
// Test to make sure that save w/o name just shows imageID during load
out, err := RunCommandPipelineWithOutput(
exec.Command(dockerBinary, "save", id),
exec.Command(dockerBinary, "load"))
assert.NilError(c, err, "failed to save and load repo: %s, %v", out, err)
// Should not show 'name' but should show the image ID during the load
assert.Assert(c, !strings.Contains(out, "Loaded image: "))
assert.Assert(c, is.Contains(out, "Loaded image ID:"))
assert.Assert(c, is.Contains(out, id))
// Test to make sure that save by name shows that name during load
out, err = RunCommandPipelineWithOutput(
exec.Command(dockerBinary, "save", name),
exec.Command(dockerBinary, "load"))
assert.NilError(c, err, "failed to save and load repo: %s, %v", out, err)
assert.Assert(c, is.Contains(out, "Loaded image: "+name+":latest"))
assert.Assert(c, !strings.Contains(out, "Loaded image ID:"))
}