Signed-off-by: Daniel Nephin <dnephin@docker.com>
| ... | ... |
@@ -8,8 +8,6 @@ import ( |
| 8 | 8 |
"github.com/go-check/check" |
| 9 | 9 |
) |
| 10 | 10 |
|
| 11 |
-// docker cp CONTAINER:PATH LOCALPATH |
|
| 12 |
- |
|
| 13 | 11 |
// Try all of the test cases from the archive package which implements the |
| 14 | 12 |
// internals of `docker cp` and ensure that the behavior matches when actually |
| 15 | 13 |
// copying to and from containers. |
| ... | ... |
@@ -20,67 +18,9 @@ import ( |
| 20 | 20 |
// 3. DST parent directory must exist. |
| 21 | 21 |
// 4. If DST exists as a file, it must not end with a trailing separator. |
| 22 | 22 |
|
| 23 |
-// First get these easy error cases out of the way. |
|
| 24 |
- |
|
| 25 |
-// Test for error when SRC does not exist. |
|
| 26 |
-func (s *DockerSuite) TestCpFromErrSrcNotExists(c *check.C) {
|
|
| 27 |
- containerID := makeTestContainer(c, testContainerOptions{})
|
|
| 28 |
- |
|
| 29 |
- tmpDir := getTestDir(c, "test-cp-from-err-src-not-exists") |
|
| 30 |
- defer os.RemoveAll(tmpDir) |
|
| 31 |
- |
|
| 32 |
- err := runDockerCp(c, containerCpPath(containerID, "file1"), tmpDir, nil) |
|
| 33 |
- c.Assert(err, checker.NotNil) |
|
| 34 |
- |
|
| 35 |
- c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
|
|
| 36 |
-} |
|
| 37 |
- |
|
| 38 |
-// Test for error when SRC ends in a trailing |
|
| 39 |
-// path separator but it exists as a file. |
|
| 40 |
-func (s *DockerSuite) TestCpFromErrSrcNotDir(c *check.C) {
|
|
| 41 |
- testRequires(c, DaemonIsLinux) |
|
| 42 |
- containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
|
| 43 |
- |
|
| 44 |
- tmpDir := getTestDir(c, "test-cp-from-err-src-not-dir") |
|
| 45 |
- defer os.RemoveAll(tmpDir) |
|
| 46 |
- |
|
| 47 |
- err := runDockerCp(c, containerCpPathTrailingSep(containerID, "file1"), tmpDir, nil) |
|
| 48 |
- c.Assert(err, checker.NotNil) |
|
| 49 |
- |
|
| 50 |
- c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
|
|
| 51 |
-} |
|
| 52 |
- |
|
| 53 |
-// Test for error when DST ends in a trailing |
|
| 54 |
-// path separator but exists as a file. |
|
| 55 |
-func (s *DockerSuite) TestCpFromErrDstNotDir(c *check.C) {
|
|
| 56 |
- testRequires(c, DaemonIsLinux) |
|
| 57 |
- containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
|
| 58 |
- |
|
| 59 |
- tmpDir := getTestDir(c, "test-cp-from-err-dst-not-dir") |
|
| 60 |
- defer os.RemoveAll(tmpDir) |
|
| 61 |
- |
|
| 62 |
- makeTestContentInDir(c, tmpDir) |
|
| 63 |
- |
|
| 64 |
- // Try with a file source. |
|
| 65 |
- srcPath := containerCpPath(containerID, "/file1") |
|
| 66 |
- dstPath := cpPathTrailingSep(tmpDir, "file1") |
|
| 67 |
- |
|
| 68 |
- err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 69 |
- c.Assert(err, checker.NotNil) |
|
| 70 |
- |
|
| 71 |
- c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
|
|
| 72 |
- |
|
| 73 |
- // Try with a directory source. |
|
| 74 |
- srcPath = containerCpPath(containerID, "/dir1") |
|
| 75 |
- |
|
| 76 |
- err = runDockerCp(c, srcPath, dstPath, nil) |
|
| 77 |
- c.Assert(err, checker.NotNil) |
|
| 78 |
- |
|
| 79 |
- c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
|
|
| 80 |
-} |
|
| 81 |
- |
|
| 82 | 23 |
// Check that copying from a container to a local symlink copies to the symlink |
| 83 | 24 |
// target and does not overwrite the local symlink itself. |
| 25 |
+// TODO: move to docker/cli and/or integration/container/copy_test.go |
|
| 84 | 26 |
func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
|
| 85 | 27 |
testRequires(c, DaemonIsLinux) |
| 86 | 28 |
containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
| ... | ... |
@@ -2,15 +2,11 @@ package main |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 | 4 |
"os" |
| 5 |
- "runtime" |
|
| 6 |
- "strings" |
|
| 7 | 5 |
|
| 8 | 6 |
"github.com/docker/docker/integration-cli/checker" |
| 9 | 7 |
"github.com/go-check/check" |
| 10 | 8 |
) |
| 11 | 9 |
|
| 12 |
-// docker cp LOCALPATH CONTAINER:PATH |
|
| 13 |
- |
|
| 14 | 10 |
// Try all of the test cases from the archive package which implements the |
| 15 | 11 |
// internals of `docker cp` and ensure that the behavior matches when actually |
| 16 | 12 |
// copying to and from containers. |
| ... | ... |
@@ -21,124 +17,6 @@ import ( |
| 21 | 21 |
// 3. DST parent directory must exist. |
| 22 | 22 |
// 4. If DST exists as a file, it must not end with a trailing separator. |
| 23 | 23 |
|
| 24 |
-// First get these easy error cases out of the way. |
|
| 25 |
- |
|
| 26 |
-// Test for error when SRC does not exist. |
|
| 27 |
-func (s *DockerSuite) TestCpToErrSrcNotExists(c *check.C) {
|
|
| 28 |
- containerID := makeTestContainer(c, testContainerOptions{})
|
|
| 29 |
- |
|
| 30 |
- tmpDir := getTestDir(c, "test-cp-to-err-src-not-exists") |
|
| 31 |
- defer os.RemoveAll(tmpDir) |
|
| 32 |
- |
|
| 33 |
- srcPath := cpPath(tmpDir, "file1") |
|
| 34 |
- dstPath := containerCpPath(containerID, "file1") |
|
| 35 |
- _, srcStatErr := os.Stat(srcPath) |
|
| 36 |
- c.Assert(os.IsNotExist(srcStatErr), checker.True) |
|
| 37 |
- |
|
| 38 |
- err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 39 |
- if runtime.GOOS == "windows" {
|
|
| 40 |
- // Go 1.9+ on Windows returns a different error for `os.Stat()`, see |
|
| 41 |
- // https://github.com/golang/go/commit/6144c7270e5812d9de8fb97456ee4e5ae657fcbb#diff-f63e1a4b4377b2fe0b05011db3df9599 |
|
| 42 |
- // |
|
| 43 |
- // Go 1.8: CreateFile C:\not-exist: The system cannot find the file specified. |
|
| 44 |
- // Go 1.9: GetFileAttributesEx C:\not-exist: The system cannot find the file specified. |
|
| 45 |
- // |
|
| 46 |
- // Due to the CLI using a different version than the daemon, comparing the |
|
| 47 |
- // error message won't work, so just hard-code the common part here. |
|
| 48 |
- // |
|
| 49 |
- // TODO this should probably be a test in the CLI repository instead |
|
| 50 |
- c.Assert(strings.ToLower(err.Error()), checker.Contains, "cannot find the file specified") |
|
| 51 |
- c.Assert(strings.ToLower(err.Error()), checker.Contains, strings.ToLower(tmpDir)) |
|
| 52 |
- } else {
|
|
| 53 |
- c.Assert(strings.ToLower(err.Error()), checker.Contains, strings.ToLower(srcStatErr.Error())) |
|
| 54 |
- } |
|
| 55 |
-} |
|
| 56 |
- |
|
| 57 |
-// Test for error when SRC ends in a trailing |
|
| 58 |
-// path separator but it exists as a file. |
|
| 59 |
-func (s *DockerSuite) TestCpToErrSrcNotDir(c *check.C) {
|
|
| 60 |
- containerID := makeTestContainer(c, testContainerOptions{})
|
|
| 61 |
- |
|
| 62 |
- tmpDir := getTestDir(c, "test-cp-to-err-src-not-dir") |
|
| 63 |
- defer os.RemoveAll(tmpDir) |
|
| 64 |
- |
|
| 65 |
- makeTestContentInDir(c, tmpDir) |
|
| 66 |
- |
|
| 67 |
- srcPath := cpPathTrailingSep(tmpDir, "file1") |
|
| 68 |
- dstPath := containerCpPath(containerID, "testDir") |
|
| 69 |
- |
|
| 70 |
- err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 71 |
- c.Assert(err, checker.NotNil) |
|
| 72 |
- |
|
| 73 |
- c.Assert(isCpNotDir(err), checker.True, check.Commentf("expected IsNotDir error, but got %T: %s", err, err))
|
|
| 74 |
-} |
|
| 75 |
- |
|
| 76 |
-// Test for error when SRC is a valid file or directory, |
|
| 77 |
-// but the DST parent directory does not exist. |
|
| 78 |
-func (s *DockerSuite) TestCpToErrDstParentNotExists(c *check.C) {
|
|
| 79 |
- testRequires(c, DaemonIsLinux) |
|
| 80 |
- containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
|
| 81 |
- |
|
| 82 |
- tmpDir := getTestDir(c, "test-cp-to-err-dst-parent-not-exists") |
|
| 83 |
- defer os.RemoveAll(tmpDir) |
|
| 84 |
- |
|
| 85 |
- makeTestContentInDir(c, tmpDir) |
|
| 86 |
- |
|
| 87 |
- // Try with a file source. |
|
| 88 |
- srcPath := cpPath(tmpDir, "file1") |
|
| 89 |
- dstPath := containerCpPath(containerID, "/notExists", "file1") |
|
| 90 |
- |
|
| 91 |
- err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 92 |
- c.Assert(err, checker.NotNil) |
|
| 93 |
- |
|
| 94 |
- c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
|
|
| 95 |
- |
|
| 96 |
- // Try with a directory source. |
|
| 97 |
- srcPath = cpPath(tmpDir, "dir1") |
|
| 98 |
- |
|
| 99 |
- err = runDockerCp(c, srcPath, dstPath, nil) |
|
| 100 |
- c.Assert(err, checker.NotNil) |
|
| 101 |
- |
|
| 102 |
- c.Assert(isCpNotExist(err), checker.True, check.Commentf("expected IsNotExist error, but got %T: %s", err, err))
|
|
| 103 |
-} |
|
| 104 |
- |
|
| 105 |
-// Test for error when DST ends in a trailing path separator but exists as a |
|
| 106 |
-// file. Also test that we cannot overwrite an existing directory with a |
|
| 107 |
-// non-directory and cannot overwrite an existing |
|
| 108 |
-func (s *DockerSuite) TestCpToErrDstNotDir(c *check.C) {
|
|
| 109 |
- testRequires(c, DaemonIsLinux) |
|
| 110 |
- containerID := makeTestContainer(c, testContainerOptions{addContent: true})
|
|
| 111 |
- |
|
| 112 |
- tmpDir := getTestDir(c, "test-cp-to-err-dst-not-dir") |
|
| 113 |
- defer os.RemoveAll(tmpDir) |
|
| 114 |
- |
|
| 115 |
- makeTestContentInDir(c, tmpDir) |
|
| 116 |
- |
|
| 117 |
- // Try with a file source. |
|
| 118 |
- srcPath := cpPath(tmpDir, "dir1/file1-1") |
|
| 119 |
- dstPath := containerCpPathTrailingSep(containerID, "file1") |
|
| 120 |
- |
|
| 121 |
- // The client should encounter an error trying to stat the destination |
|
| 122 |
- // and then be unable to copy since the destination is asserted to be a |
|
| 123 |
- // directory but does not exist. |
|
| 124 |
- err := runDockerCp(c, srcPath, dstPath, nil) |
|
| 125 |
- c.Assert(err, checker.NotNil) |
|
| 126 |
- |
|
| 127 |
- c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExist error, but got %T: %s", err, err))
|
|
| 128 |
- |
|
| 129 |
- // Try with a directory source. |
|
| 130 |
- srcPath = cpPath(tmpDir, "dir1") |
|
| 131 |
- |
|
| 132 |
- // The client should encounter an error trying to stat the destination and |
|
| 133 |
- // then decide to extract to the parent directory instead with a rebased |
|
| 134 |
- // name in the source archive, but this directory would overwrite the |
|
| 135 |
- // existing file with the same name. |
|
| 136 |
- err = runDockerCp(c, srcPath, dstPath, nil) |
|
| 137 |
- c.Assert(err, checker.NotNil) |
|
| 138 |
- |
|
| 139 |
- c.Assert(isCannotOverwriteNonDirWithDir(err), checker.True, check.Commentf("expected CannotOverwriteNonDirWithDir error, but got %T: %s", err, err))
|
|
| 140 |
-} |
|
| 141 |
- |
|
| 142 | 24 |
// Check that copying from a local path to a symlink in a container copies to |
| 143 | 25 |
// the symlink target and does not overwrite the container symlink itself. |
| 144 | 26 |
func (s *DockerSuite) TestCpToSymlinkDestination(c *check.C) {
|
| ... | ... |
@@ -228,18 +228,10 @@ func getTestDir(c *check.C, label string) (tmpDir string) {
|
| 228 | 228 |
return |
| 229 | 229 |
} |
| 230 | 230 |
|
| 231 |
-func isCpNotExist(err error) bool {
|
|
| 232 |
- return strings.Contains(strings.ToLower(err.Error()), "could not find the file") |
|
| 233 |
-} |
|
| 234 |
- |
|
| 235 | 231 |
func isCpDirNotExist(err error) bool {
|
| 236 | 232 |
return strings.Contains(err.Error(), archive.ErrDirNotExists.Error()) |
| 237 | 233 |
} |
| 238 | 234 |
|
| 239 |
-func isCpNotDir(err error) bool {
|
|
| 240 |
- return strings.Contains(err.Error(), archive.ErrNotDirectory.Error()) || strings.Contains(err.Error(), "filename, directory name, or volume label syntax is incorrect") |
|
| 241 |
-} |
|
| 242 |
- |
|
| 243 | 235 |
func isCpCannotCopyDir(err error) bool {
|
| 244 | 236 |
return strings.Contains(err.Error(), archive.ErrCannotCopyDir.Error()) |
| 245 | 237 |
} |
| ... | ... |
@@ -248,10 +240,6 @@ func isCpCannotCopyReadOnly(err error) bool {
|
| 248 | 248 |
return strings.Contains(err.Error(), "marked read-only") |
| 249 | 249 |
} |
| 250 | 250 |
|
| 251 |
-func isCannotOverwriteNonDirWithDir(err error) bool {
|
|
| 252 |
- return strings.Contains(err.Error(), "cannot overwrite non-directory") |
|
| 253 |
-} |
|
| 254 |
- |
|
| 255 | 251 |
func fileContentEquals(c *check.C, filename, contents string) (err error) {
|
| 256 | 252 |
c.Logf("checking that file %q contains %q\n", filename, contents)
|
| 257 | 253 |
|
| 258 | 254 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,65 @@ |
| 0 |
+package container // import "github.com/docker/docker/integration/container" |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "context" |
|
| 4 |
+ "fmt" |
|
| 5 |
+ "testing" |
|
| 6 |
+ |
|
| 7 |
+ "github.com/docker/docker/api/types" |
|
| 8 |
+ "github.com/docker/docker/client" |
|
| 9 |
+ "github.com/docker/docker/integration/internal/container" |
|
| 10 |
+ "github.com/docker/docker/internal/testutil" |
|
| 11 |
+ "github.com/gotestyourself/gotestyourself/skip" |
|
| 12 |
+ "github.com/stretchr/testify/require" |
|
| 13 |
+) |
|
| 14 |
+ |
|
| 15 |
+func TestCopyFromContainerPathDoesNotExist(t *testing.T) {
|
|
| 16 |
+ defer setupTest(t)() |
|
| 17 |
+ |
|
| 18 |
+ ctx := context.Background() |
|
| 19 |
+ apiclient := testEnv.APIClient() |
|
| 20 |
+ cid := container.Create(t, ctx, apiclient) |
|
| 21 |
+ |
|
| 22 |
+ _, _, err := apiclient.CopyFromContainer(ctx, cid, "/dne") |
|
| 23 |
+ require.True(t, client.IsErrNotFound(err)) |
|
| 24 |
+ expected := fmt.Sprintf("No such container:path: %s:%s", cid, "/dne")
|
|
| 25 |
+ testutil.ErrorContains(t, err, expected) |
|
| 26 |
+} |
|
| 27 |
+ |
|
| 28 |
+func TestCopyFromContainerPathIsNotDir(t *testing.T) {
|
|
| 29 |
+ defer setupTest(t)() |
|
| 30 |
+ skip.If(t, testEnv.OSType == "windows") |
|
| 31 |
+ |
|
| 32 |
+ ctx := context.Background() |
|
| 33 |
+ apiclient := testEnv.APIClient() |
|
| 34 |
+ cid := container.Create(t, ctx, apiclient) |
|
| 35 |
+ |
|
| 36 |
+ _, _, err := apiclient.CopyFromContainer(ctx, cid, "/etc/passwd/") |
|
| 37 |
+ require.Contains(t, err.Error(), "not a directory") |
|
| 38 |
+} |
|
| 39 |
+ |
|
| 40 |
+func TestCopyToContainerPathDoesNotExist(t *testing.T) {
|
|
| 41 |
+ defer setupTest(t)() |
|
| 42 |
+ skip.If(t, testEnv.OSType == "windows") |
|
| 43 |
+ |
|
| 44 |
+ ctx := context.Background() |
|
| 45 |
+ apiclient := testEnv.APIClient() |
|
| 46 |
+ cid := container.Create(t, ctx, apiclient) |
|
| 47 |
+ |
|
| 48 |
+ err := apiclient.CopyToContainer(ctx, cid, "/dne", nil, types.CopyToContainerOptions{})
|
|
| 49 |
+ require.True(t, client.IsErrNotFound(err)) |
|
| 50 |
+ expected := fmt.Sprintf("No such container:path: %s:%s", cid, "/dne")
|
|
| 51 |
+ testutil.ErrorContains(t, err, expected) |
|
| 52 |
+} |
|
| 53 |
+ |
|
| 54 |
+func TestCopyToContainerPathIsNotDir(t *testing.T) {
|
|
| 55 |
+ defer setupTest(t)() |
|
| 56 |
+ skip.If(t, testEnv.OSType == "windows") |
|
| 57 |
+ |
|
| 58 |
+ ctx := context.Background() |
|
| 59 |
+ apiclient := testEnv.APIClient() |
|
| 60 |
+ cid := container.Create(t, ctx, apiclient) |
|
| 61 |
+ |
|
| 62 |
+ err := apiclient.CopyToContainer(ctx, cid, "/etc/passwd/", nil, types.CopyToContainerOptions{})
|
|
| 63 |
+ require.Contains(t, err.Error(), "not a directory") |
|
| 64 |
+} |