mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
3ddb4100a0
Now that we marked these utilities as helpers, it should be possible to find which test-case failed (if any), and we can skip logging in the "happy path". This makes these tests less noisy, which makes it easier to find actually important information in the output: --- PASS: TestDockerSuite/TestCpFromCaseC (0.96s) docker_cli_cp_utils_test.go:244: checking that file "/tmp/test-cp-from-case-c450122079/file2" contains "file2\n" docker_cli_cp_utils_test.go:192: running `docker cp 962b1f3311e742b0842e13b2ad350214cea25883999fd26e87e8c9ddf40d5eb4:/root/file1 /tmp/test-cp-from-case-c450122079/file2` docker_cli_cp_utils_test.go:244: checking that file "/tmp/test-cp-from-case-c450122079/file2" contains "file1\n" Some of these tests should probably be rewritten to use subtests, but that's something for a follow-up. Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
301 lines
7.4 KiB
Go
301 lines
7.4 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"os/exec"
|
|
"path/filepath"
|
|
"runtime"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/docker/docker/pkg/archive"
|
|
"gotest.tools/assert"
|
|
)
|
|
|
|
type fileType uint32
|
|
|
|
const (
|
|
ftRegular fileType = iota
|
|
ftDir
|
|
ftSymlink
|
|
)
|
|
|
|
type fileData struct {
|
|
filetype fileType
|
|
path string
|
|
contents string
|
|
uid int
|
|
gid int
|
|
mode int
|
|
}
|
|
|
|
func (fd fileData) creationCommand() string {
|
|
var command string
|
|
|
|
switch fd.filetype {
|
|
case ftRegular:
|
|
// Don't overwrite the file if it already exists!
|
|
command = fmt.Sprintf("if [ ! -f %s ]; then echo %q > %s; fi", fd.path, fd.contents, fd.path)
|
|
case ftDir:
|
|
command = fmt.Sprintf("mkdir -p %s", fd.path)
|
|
case ftSymlink:
|
|
command = fmt.Sprintf("ln -fs %s %s", fd.contents, fd.path)
|
|
}
|
|
|
|
return command
|
|
}
|
|
|
|
func mkFilesCommand(fds []fileData) string {
|
|
commands := make([]string, len(fds))
|
|
|
|
for i, fd := range fds {
|
|
commands[i] = fd.creationCommand()
|
|
}
|
|
|
|
return strings.Join(commands, " && ")
|
|
}
|
|
|
|
var defaultFileData = []fileData{
|
|
{ftRegular, "file1", "file1", 0, 0, 0666},
|
|
{ftRegular, "file2", "file2", 0, 0, 0666},
|
|
{ftRegular, "file3", "file3", 0, 0, 0666},
|
|
{ftRegular, "file4", "file4", 0, 0, 0666},
|
|
{ftRegular, "file5", "file5", 0, 0, 0666},
|
|
{ftRegular, "file6", "file6", 0, 0, 0666},
|
|
{ftRegular, "file7", "file7", 0, 0, 0666},
|
|
{ftDir, "dir1", "", 0, 0, 0777},
|
|
{ftRegular, "dir1/file1-1", "file1-1", 0, 0, 0666},
|
|
{ftRegular, "dir1/file1-2", "file1-2", 0, 0, 0666},
|
|
{ftDir, "dir2", "", 0, 0, 0666},
|
|
{ftRegular, "dir2/file2-1", "file2-1", 0, 0, 0666},
|
|
{ftRegular, "dir2/file2-2", "file2-2", 0, 0, 0666},
|
|
{ftDir, "dir3", "", 0, 0, 0666},
|
|
{ftRegular, "dir3/file3-1", "file3-1", 0, 0, 0666},
|
|
{ftRegular, "dir3/file3-2", "file3-2", 0, 0, 0666},
|
|
{ftDir, "dir4", "", 0, 0, 0666},
|
|
{ftRegular, "dir4/file3-1", "file4-1", 0, 0, 0666},
|
|
{ftRegular, "dir4/file3-2", "file4-2", 0, 0, 0666},
|
|
{ftDir, "dir5", "", 0, 0, 0666},
|
|
{ftSymlink, "symlinkToFile1", "file1", 0, 0, 0666},
|
|
{ftSymlink, "symlinkToDir1", "dir1", 0, 0, 0666},
|
|
{ftSymlink, "brokenSymlinkToFileX", "fileX", 0, 0, 0666},
|
|
{ftSymlink, "brokenSymlinkToDirX", "dirX", 0, 0, 0666},
|
|
{ftSymlink, "symlinkToAbsDir", "/root", 0, 0, 0666},
|
|
{ftDir, "permdirtest", "", 2, 2, 0700},
|
|
{ftRegular, "permdirtest/permtest", "perm_test", 65534, 65534, 0400},
|
|
}
|
|
|
|
func defaultMkContentCommand() string {
|
|
return mkFilesCommand(defaultFileData)
|
|
}
|
|
|
|
func makeTestContentInDir(c *testing.T, dir string) {
|
|
c.Helper()
|
|
for _, fd := range defaultFileData {
|
|
path := filepath.Join(dir, filepath.FromSlash(fd.path))
|
|
switch fd.filetype {
|
|
case ftRegular:
|
|
assert.NilError(c, ioutil.WriteFile(path, []byte(fd.contents+"\n"), os.FileMode(fd.mode)))
|
|
case ftDir:
|
|
assert.NilError(c, os.Mkdir(path, os.FileMode(fd.mode)))
|
|
case ftSymlink:
|
|
assert.NilError(c, os.Symlink(fd.contents, path))
|
|
}
|
|
|
|
if fd.filetype != ftSymlink && runtime.GOOS != "windows" {
|
|
assert.NilError(c, os.Chown(path, fd.uid, fd.gid))
|
|
}
|
|
}
|
|
}
|
|
|
|
type testContainerOptions struct {
|
|
addContent bool
|
|
readOnly bool
|
|
volumes []string
|
|
workDir string
|
|
command string
|
|
}
|
|
|
|
func makeTestContainer(c *testing.T, options testContainerOptions) (containerID string) {
|
|
c.Helper()
|
|
if options.addContent {
|
|
mkContentCmd := defaultMkContentCommand()
|
|
if options.command == "" {
|
|
options.command = mkContentCmd
|
|
} else {
|
|
options.command = fmt.Sprintf("%s && %s", defaultMkContentCommand(), options.command)
|
|
}
|
|
}
|
|
|
|
if options.command == "" {
|
|
options.command = "#(nop)"
|
|
}
|
|
|
|
args := []string{"run", "-d"}
|
|
|
|
for _, volume := range options.volumes {
|
|
args = append(args, "-v", volume)
|
|
}
|
|
|
|
if options.workDir != "" {
|
|
args = append(args, "-w", options.workDir)
|
|
}
|
|
|
|
if options.readOnly {
|
|
args = append(args, "--read-only")
|
|
}
|
|
|
|
args = append(args, "busybox", "/bin/sh", "-c", options.command)
|
|
|
|
out, _ := dockerCmd(c, args...)
|
|
|
|
containerID = strings.TrimSpace(out)
|
|
|
|
out, _ = dockerCmd(c, "wait", containerID)
|
|
|
|
exitCode := strings.TrimSpace(out)
|
|
if exitCode != "0" {
|
|
out, _ = dockerCmd(c, "logs", containerID)
|
|
}
|
|
assert.Equal(c, exitCode, "0", "failed to make test container: %s", out)
|
|
|
|
return
|
|
}
|
|
|
|
func makeCatFileCommand(path string) string {
|
|
return fmt.Sprintf("if [ -f %s ]; then cat %s; fi", path, path)
|
|
}
|
|
|
|
func cpPath(pathElements ...string) string {
|
|
localizedPathElements := make([]string, len(pathElements))
|
|
for i, path := range pathElements {
|
|
localizedPathElements[i] = filepath.FromSlash(path)
|
|
}
|
|
return strings.Join(localizedPathElements, string(filepath.Separator))
|
|
}
|
|
|
|
func cpPathTrailingSep(pathElements ...string) string {
|
|
return fmt.Sprintf("%s%c", cpPath(pathElements...), filepath.Separator)
|
|
}
|
|
|
|
func containerCpPath(containerID string, pathElements ...string) string {
|
|
joined := strings.Join(pathElements, "/")
|
|
return fmt.Sprintf("%s:%s", containerID, joined)
|
|
}
|
|
|
|
func containerCpPathTrailingSep(containerID string, pathElements ...string) string {
|
|
return fmt.Sprintf("%s/", containerCpPath(containerID, pathElements...))
|
|
}
|
|
|
|
func runDockerCp(c *testing.T, src, dst string) error {
|
|
c.Helper()
|
|
|
|
args := []string{"cp", src, dst}
|
|
if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, args...)); err != nil {
|
|
return fmt.Errorf("error executing `docker cp` command: %s: %s", err, out)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func startContainerGetOutput(c *testing.T, containerID string) (out string, err error) {
|
|
c.Helper()
|
|
|
|
args := []string{"start", "-a", containerID}
|
|
|
|
out, _, err = runCommandWithOutput(exec.Command(dockerBinary, args...))
|
|
if err != nil {
|
|
err = fmt.Errorf("error executing `docker start` command: %s: %s", err, out)
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
func getTestDir(c *testing.T, label string) (tmpDir string) {
|
|
c.Helper()
|
|
var err error
|
|
|
|
tmpDir, err = ioutil.TempDir("", label)
|
|
// unable to make temporary directory
|
|
assert.NilError(c, err)
|
|
|
|
return
|
|
}
|
|
|
|
func isCpDirNotExist(err error) bool {
|
|
return strings.Contains(err.Error(), archive.ErrDirNotExists.Error())
|
|
}
|
|
|
|
func isCpCannotCopyDir(err error) bool {
|
|
return strings.Contains(err.Error(), archive.ErrCannotCopyDir.Error())
|
|
}
|
|
|
|
func isCpCannotCopyReadOnly(err error) bool {
|
|
return strings.Contains(err.Error(), "marked read-only")
|
|
}
|
|
|
|
func fileContentEquals(c *testing.T, filename, contents string) error {
|
|
c.Helper()
|
|
|
|
fileBytes, err := ioutil.ReadFile(filename)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
expectedBytes, err := ioutil.ReadAll(strings.NewReader(contents))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if !bytes.Equal(fileBytes, expectedBytes) {
|
|
return fmt.Errorf("file content not equal - expected %q, got %q", string(expectedBytes), string(fileBytes))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func symlinkTargetEquals(c *testing.T, symlink, expectedTarget string) error {
|
|
c.Helper()
|
|
|
|
actualTarget, err := os.Readlink(symlink)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if actualTarget != expectedTarget {
|
|
return fmt.Errorf("symlink target points to %q not %q", actualTarget, expectedTarget)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func containerStartOutputEquals(c *testing.T, containerID, contents string) error {
|
|
c.Helper()
|
|
|
|
out, err := startContainerGetOutput(c, containerID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if out != contents {
|
|
return fmt.Errorf("output contents not equal - expected %q, got %q", contents, out)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func defaultVolumes(tmpDir string) []string {
|
|
if testEnv.IsLocalDaemon() {
|
|
return []string{
|
|
"/vol1",
|
|
fmt.Sprintf("%s:/vol2", tmpDir),
|
|
fmt.Sprintf("%s:/vol3", filepath.Join(tmpDir, "vol3")),
|
|
fmt.Sprintf("%s:/vol_ro:ro", filepath.Join(tmpDir, "vol_ro")),
|
|
}
|
|
}
|
|
|
|
// Can't bind-mount volumes with separate host daemon.
|
|
return []string{"/vol1", "/vol2", "/vol3", "/vol_ro:/vol_ro:ro"}
|
|
}
|