418135e7 | package main import ( "bytes" "fmt" "io/ioutil" "os" "os/exec" "path/filepath" |
8a7ff5ff | "runtime" |
418135e7 | "strings" |
e25352a4 | "testing" |
418135e7 | "github.com/docker/docker/pkg/archive" |
6345208b | "gotest.tools/assert" |
418135e7 | ) |
6b3c9281 | type fileType uint32 |
418135e7 | const ( |
6b3c9281 | ftRegular fileType = iota ftDir ftSymlink |
418135e7 | ) |
6b3c9281 | type fileData struct { filetype fileType |
418135e7 | path string contents string |
8a7ff5ff | uid int gid int mode int |
418135e7 | } |
6b3c9281 | func (fd fileData) creationCommand() string { |
418135e7 | var command string switch fd.filetype { |
6b3c9281 | case ftRegular: |
418135e7 | // 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) |
6b3c9281 | case ftDir: |
418135e7 | command = fmt.Sprintf("mkdir -p %s", fd.path) |
6b3c9281 | case ftSymlink: |
418135e7 | command = fmt.Sprintf("ln -fs %s %s", fd.contents, fd.path) } return command } |
6b3c9281 | func mkFilesCommand(fds []fileData) string { |
418135e7 | commands := make([]string, len(fds)) for i, fd := range fds { commands[i] = fd.creationCommand() } return strings.Join(commands, " && ") } |
6b3c9281 | var defaultFileData = []fileData{ |
8a7ff5ff | {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}, |
418135e7 | } func defaultMkContentCommand() string { return mkFilesCommand(defaultFileData) } |
64a928a3 | func makeTestContentInDir(c *testing.T, dir string) { |
418135e7 | for _, fd := range defaultFileData { path := filepath.Join(dir, filepath.FromSlash(fd.path)) switch fd.filetype { |
6b3c9281 | case ftRegular: |
6345208b | assert.NilError(c, ioutil.WriteFile(path, []byte(fd.contents+"\n"), os.FileMode(fd.mode))) |
6b3c9281 | case ftDir: |
6345208b | assert.NilError(c, os.Mkdir(path, os.FileMode(fd.mode))) |
6b3c9281 | case ftSymlink: |
6345208b | assert.NilError(c, os.Symlink(fd.contents, path)) |
418135e7 | } |
8a7ff5ff | if fd.filetype != ftSymlink && runtime.GOOS != "windows" { |
6345208b | assert.NilError(c, os.Chown(path, fd.uid, fd.gid)) |
8a7ff5ff | } |
418135e7 | } } type testContainerOptions struct { addContent bool readOnly bool volumes []string workDir string command string } |
64a928a3 | func makeTestContainer(c *testing.T, options testContainerOptions) (containerID string) { |
418135e7 | 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) |
f26a31e8 | out, _ := dockerCmd(c, args...) |
418135e7 | containerID = strings.TrimSpace(out) |
f26a31e8 | out, _ = dockerCmd(c, "wait", containerID) |
418135e7 | |
f26a31e8 | exitCode := strings.TrimSpace(out) if exitCode != "0" { out, _ = dockerCmd(c, "logs", containerID) |
418135e7 | } |
6345208b | assert.Equal(c, exitCode, "0", "failed to make test container: %s", out) |
418135e7 | 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...)) } |
64a928a3 | func runDockerCp(c *testing.T, src, dst string, params []string) (err error) { |
8a7ff5ff | c.Logf("running `docker cp %s %s %s`", strings.Join(params, " "), src, dst) args := []string{"cp"} |
94cefa21 | args = append(args, params...) |
418135e7 | |
8a7ff5ff | args = append(args, src, dst) |
418135e7 | out, _, err := runCommandWithOutput(exec.Command(dockerBinary, args...)) if err != nil { err = fmt.Errorf("error executing `docker cp` command: %s: %s", err, out) } return } |
64a928a3 | func startContainerGetOutput(c *testing.T, containerID string) (out string, err error) { |
f26a31e8 | c.Logf("running `docker start -a %s`", containerID) |
418135e7 | |
f26a31e8 | args := []string{"start", "-a", containerID} |
418135e7 | out, _, err = runCommandWithOutput(exec.Command(dockerBinary, args...)) if err != nil { err = fmt.Errorf("error executing `docker start` command: %s: %s", err, out) } return } |
64a928a3 | func getTestDir(c *testing.T, label string) (tmpDir string) { |
418135e7 | var err error |
f26a31e8 | tmpDir, err = ioutil.TempDir("", label) // unable to make temporary directory |
6345208b | assert.NilError(c, err) |
418135e7 | 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") } |
64a928a3 | func fileContentEquals(c *testing.T, filename, contents string) (err error) { |
418135e7 | c.Logf("checking that file %q contains %q\n", filename, contents) fileBytes, err := ioutil.ReadFile(filename) if err != nil { return } expectedBytes, err := ioutil.ReadAll(strings.NewReader(contents)) if err != nil { return } if !bytes.Equal(fileBytes, expectedBytes) { err = fmt.Errorf("file content not equal - expected %q, got %q", string(expectedBytes), string(fileBytes)) } return } |
64a928a3 | func symlinkTargetEquals(c *testing.T, symlink, expectedTarget string) (err error) { |
75f6929b | c.Logf("checking that the symlink %q points to %q\n", symlink, expectedTarget) actualTarget, err := os.Readlink(symlink) if err != nil { |
f26a31e8 | return |
75f6929b | } if actualTarget != expectedTarget { |
f26a31e8 | err = fmt.Errorf("symlink target points to %q not %q", actualTarget, expectedTarget) |
75f6929b | } |
f26a31e8 | return |
75f6929b | } |
64a928a3 | func containerStartOutputEquals(c *testing.T, containerID, contents string) (err error) { |
f26a31e8 | c.Logf("checking that container %q start output contains %q\n", containerID, contents) |
418135e7 | |
f26a31e8 | out, err := startContainerGetOutput(c, containerID) |
418135e7 | if err != nil { |
f26a31e8 | return |
418135e7 | } if out != contents { err = fmt.Errorf("output contents not equal - expected %q, got %q", contents, out) } return } func defaultVolumes(tmpDir string) []string { |
43b15e92 | if testEnv.IsLocalDaemon() { |
418135e7 | 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"} } |