github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/integration-cli/docker_cli_cp_from_container_test.go (about) 1 package main 2 3 import ( 4 "os" 5 "path/filepath" 6 7 "github.com/docker/docker/integration-cli/checker" 8 "github.com/go-check/check" 9 ) 10 11 // Try all of the test cases from the archive package which implements the 12 // internals of `docker cp` and ensure that the behavior matches when actually 13 // copying to and from containers. 14 15 // Basic assumptions about SRC and DST: 16 // 1. SRC must exist. 17 // 2. If SRC ends with a trailing separator, it must be a directory. 18 // 3. DST parent directory must exist. 19 // 4. If DST exists as a file, it must not end with a trailing separator. 20 21 // Check that copying from a container to a local symlink copies to the symlink 22 // target and does not overwrite the local symlink itself. 23 // TODO: move to docker/cli and/or integration/container/copy_test.go 24 func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) { 25 testRequires(c, DaemonIsLinux) 26 containerID := makeTestContainer(c, testContainerOptions{addContent: true}) 27 28 tmpDir := getTestDir(c, "test-cp-from-err-dst-not-dir") 29 defer os.RemoveAll(tmpDir) 30 31 makeTestContentInDir(c, tmpDir) 32 33 // First, copy a file from the container to a symlink to a file. This 34 // should overwrite the symlink target contents with the source contents. 35 srcPath := containerCpPath(containerID, "/file2") 36 dstPath := cpPath(tmpDir, "symlinkToFile1") 37 38 c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) 39 40 // The symlink should not have been modified. 41 c.Assert(symlinkTargetEquals(c, dstPath, "file1"), checker.IsNil) 42 43 // The file should have the contents of "file2" now. 44 c.Assert(fileContentEquals(c, cpPath(tmpDir, "file1"), "file2\n"), checker.IsNil) 45 46 // Next, copy a file from the container to a symlink to a directory. This 47 // should copy the file into the symlink target directory. 48 dstPath = cpPath(tmpDir, "symlinkToDir1") 49 50 c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) 51 52 // The symlink should not have been modified. 53 c.Assert(symlinkTargetEquals(c, dstPath, "dir1"), checker.IsNil) 54 55 // The file should have the contents of "file2" now. 56 c.Assert(fileContentEquals(c, cpPath(tmpDir, "file2"), "file2\n"), checker.IsNil) 57 58 // Next, copy a file from the container to a symlink to a file that does 59 // not exist (a broken symlink). This should create the target file with 60 // the contents of the source file. 61 dstPath = cpPath(tmpDir, "brokenSymlinkToFileX") 62 63 c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) 64 65 // The symlink should not have been modified. 66 c.Assert(symlinkTargetEquals(c, dstPath, "fileX"), checker.IsNil) 67 68 // The file should have the contents of "file2" now. 69 c.Assert(fileContentEquals(c, cpPath(tmpDir, "fileX"), "file2\n"), checker.IsNil) 70 71 // Next, copy a directory from the container to a symlink to a local 72 // directory. This should copy the directory into the symlink target 73 // directory and not modify the symlink. 74 srcPath = containerCpPath(containerID, "/dir2") 75 dstPath = cpPath(tmpDir, "symlinkToDir1") 76 77 c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) 78 79 // The symlink should not have been modified. 80 c.Assert(symlinkTargetEquals(c, dstPath, "dir1"), checker.IsNil) 81 82 // The directory should now contain a copy of "dir2". 83 c.Assert(fileContentEquals(c, cpPath(tmpDir, "dir1/dir2/file2-1"), "file2-1\n"), checker.IsNil) 84 85 // Next, copy a directory from the container to a symlink to a local 86 // directory that does not exist (a broken symlink). This should create 87 // the target as a directory with the contents of the source directory. It 88 // should not modify the symlink. 89 dstPath = cpPath(tmpDir, "brokenSymlinkToDirX") 90 91 c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) 92 93 // The symlink should not have been modified. 94 c.Assert(symlinkTargetEquals(c, dstPath, "dirX"), checker.IsNil) 95 96 // The "dirX" directory should now be a copy of "dir2". 97 c.Assert(fileContentEquals(c, cpPath(tmpDir, "dirX/file2-1"), "file2-1\n"), checker.IsNil) 98 } 99 100 // Possibilities are reduced to the remaining 10 cases: 101 // 102 // case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action 103 // =================================================================================================== 104 // A | no | - | no | - | no | create file 105 // B | no | - | no | - | yes | error 106 // C | no | - | yes | no | - | overwrite file 107 // D | no | - | yes | yes | - | create file in dst dir 108 // E | yes | no | no | - | - | create dir, copy contents 109 // F | yes | no | yes | no | - | error 110 // G | yes | no | yes | yes | - | copy dir and contents 111 // H | yes | yes | no | - | - | create dir, copy contents 112 // I | yes | yes | yes | no | - | error 113 // J | yes | yes | yes | yes | - | copy dir contents 114 // 115 116 // A. SRC specifies a file and DST (no trailing path separator) doesn't 117 // exist. This should create a file with the name DST and copy the 118 // contents of the source file into it. 119 func (s *DockerSuite) TestCpFromCaseA(c *check.C) { 120 testRequires(c, DaemonIsLinux) 121 containerID := makeTestContainer(c, testContainerOptions{ 122 addContent: true, workDir: "/root", 123 }) 124 125 tmpDir := getTestDir(c, "test-cp-from-case-a") 126 defer os.RemoveAll(tmpDir) 127 128 srcPath := containerCpPath(containerID, "/root/file1") 129 dstPath := cpPath(tmpDir, "itWorks.txt") 130 131 c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) 132 133 c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil) 134 } 135 136 // B. SRC specifies a file and DST (with trailing path separator) doesn't 137 // exist. This should cause an error because the copy operation cannot 138 // create a directory when copying a single file. 139 func (s *DockerSuite) TestCpFromCaseB(c *check.C) { 140 testRequires(c, DaemonIsLinux) 141 containerID := makeTestContainer(c, testContainerOptions{addContent: true}) 142 143 tmpDir := getTestDir(c, "test-cp-from-case-b") 144 defer os.RemoveAll(tmpDir) 145 146 srcPath := containerCpPath(containerID, "/file1") 147 dstDir := cpPathTrailingSep(tmpDir, "testDir") 148 149 err := runDockerCp(c, srcPath, dstDir, nil) 150 c.Assert(err, checker.NotNil) 151 152 c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExists error, but got %T: %s", err, err)) 153 } 154 155 // C. SRC specifies a file and DST exists as a file. This should overwrite 156 // the file at DST with the contents of the source file. 157 func (s *DockerSuite) TestCpFromCaseC(c *check.C) { 158 testRequires(c, DaemonIsLinux) 159 containerID := makeTestContainer(c, testContainerOptions{ 160 addContent: true, workDir: "/root", 161 }) 162 163 tmpDir := getTestDir(c, "test-cp-from-case-c") 164 defer os.RemoveAll(tmpDir) 165 166 makeTestContentInDir(c, tmpDir) 167 168 srcPath := containerCpPath(containerID, "/root/file1") 169 dstPath := cpPath(tmpDir, "file2") 170 171 // Ensure the local file starts with different content. 172 c.Assert(fileContentEquals(c, dstPath, "file2\n"), checker.IsNil) 173 174 c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil) 175 176 c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil) 177 } 178 179 // D. SRC specifies a file and DST exists as a directory. This should place 180 // a copy of the source file inside it using the basename from SRC. Ensure 181 // this works whether DST has a trailing path separator or not. 182 func (s *DockerSuite) TestCpFromCaseD(c *check.C) { 183 testRequires(c, DaemonIsLinux) 184 containerID := makeTestContainer(c, testContainerOptions{addContent: true}) 185 186 tmpDir := getTestDir(c, "test-cp-from-case-d") 187 defer os.RemoveAll(tmpDir) 188 189 makeTestContentInDir(c, tmpDir) 190 191 srcPath := containerCpPath(containerID, "/file1") 192 dstDir := cpPath(tmpDir, "dir1") 193 dstPath := filepath.Join(dstDir, "file1") 194 195 // Ensure that dstPath doesn't exist. 196 _, err := os.Stat(dstPath) 197 c.Assert(os.IsNotExist(err), checker.True, check.Commentf("did not expect dstPath %q to exist", dstPath)) 198 199 c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil) 200 201 c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil) 202 203 // Now try again but using a trailing path separator for dstDir. 204 205 // unable to remove dstDir 206 c.Assert(os.RemoveAll(dstDir), checker.IsNil) 207 208 // unable to make dstDir 209 c.Assert(os.MkdirAll(dstDir, os.FileMode(0755)), checker.IsNil) 210 211 dstDir = cpPathTrailingSep(tmpDir, "dir1") 212 213 c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil) 214 215 c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil) 216 } 217 218 // E. SRC specifies a directory and DST does not exist. This should create a 219 // directory at DST and copy the contents of the SRC directory into the DST 220 // directory. Ensure this works whether DST has a trailing path separator or 221 // not. 222 func (s *DockerSuite) TestCpFromCaseE(c *check.C) { 223 testRequires(c, DaemonIsLinux) 224 containerID := makeTestContainer(c, testContainerOptions{addContent: true}) 225 226 tmpDir := getTestDir(c, "test-cp-from-case-e") 227 defer os.RemoveAll(tmpDir) 228 229 srcDir := containerCpPath(containerID, "dir1") 230 dstDir := cpPath(tmpDir, "testDir") 231 dstPath := filepath.Join(dstDir, "file1-1") 232 233 c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) 234 235 c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) 236 237 // Now try again but using a trailing path separator for dstDir. 238 239 // unable to remove dstDir 240 c.Assert(os.RemoveAll(dstDir), checker.IsNil) 241 242 dstDir = cpPathTrailingSep(tmpDir, "testDir") 243 244 c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) 245 246 c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) 247 } 248 249 // F. SRC specifies a directory and DST exists as a file. This should cause an 250 // error as it is not possible to overwrite a file with a directory. 251 func (s *DockerSuite) TestCpFromCaseF(c *check.C) { 252 testRequires(c, DaemonIsLinux) 253 containerID := makeTestContainer(c, testContainerOptions{ 254 addContent: true, workDir: "/root", 255 }) 256 257 tmpDir := getTestDir(c, "test-cp-from-case-f") 258 defer os.RemoveAll(tmpDir) 259 260 makeTestContentInDir(c, tmpDir) 261 262 srcDir := containerCpPath(containerID, "/root/dir1") 263 dstFile := cpPath(tmpDir, "file1") 264 265 err := runDockerCp(c, srcDir, dstFile, nil) 266 c.Assert(err, checker.NotNil) 267 268 c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err)) 269 } 270 271 // G. SRC specifies a directory and DST exists as a directory. This should copy 272 // the SRC directory and all its contents to the DST directory. Ensure this 273 // works whether DST has a trailing path separator or not. 274 func (s *DockerSuite) TestCpFromCaseG(c *check.C) { 275 testRequires(c, DaemonIsLinux) 276 containerID := makeTestContainer(c, testContainerOptions{ 277 addContent: true, workDir: "/root", 278 }) 279 280 tmpDir := getTestDir(c, "test-cp-from-case-g") 281 defer os.RemoveAll(tmpDir) 282 283 makeTestContentInDir(c, tmpDir) 284 285 srcDir := containerCpPath(containerID, "/root/dir1") 286 dstDir := cpPath(tmpDir, "dir2") 287 resultDir := filepath.Join(dstDir, "dir1") 288 dstPath := filepath.Join(resultDir, "file1-1") 289 290 c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) 291 292 c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) 293 294 // Now try again but using a trailing path separator for dstDir. 295 296 // unable to remove dstDir 297 c.Assert(os.RemoveAll(dstDir), checker.IsNil) 298 299 // unable to make dstDir 300 c.Assert(os.MkdirAll(dstDir, os.FileMode(0755)), checker.IsNil) 301 302 dstDir = cpPathTrailingSep(tmpDir, "dir2") 303 304 c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) 305 306 c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) 307 } 308 309 // H. SRC specifies a directory's contents only and DST does not exist. This 310 // should create a directory at DST and copy the contents of the SRC 311 // directory (but not the directory itself) into the DST directory. Ensure 312 // this works whether DST has a trailing path separator or not. 313 func (s *DockerSuite) TestCpFromCaseH(c *check.C) { 314 testRequires(c, DaemonIsLinux) 315 containerID := makeTestContainer(c, testContainerOptions{addContent: true}) 316 317 tmpDir := getTestDir(c, "test-cp-from-case-h") 318 defer os.RemoveAll(tmpDir) 319 320 srcDir := containerCpPathTrailingSep(containerID, "dir1") + "." 321 dstDir := cpPath(tmpDir, "testDir") 322 dstPath := filepath.Join(dstDir, "file1-1") 323 324 c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) 325 326 c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) 327 328 // Now try again but using a trailing path separator for dstDir. 329 330 // unable to remove resultDir 331 c.Assert(os.RemoveAll(dstDir), checker.IsNil) 332 333 dstDir = cpPathTrailingSep(tmpDir, "testDir") 334 335 c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) 336 337 c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) 338 } 339 340 // I. SRC specifies a directory's contents only and DST exists as a file. This 341 // should cause an error as it is not possible to overwrite a file with a 342 // directory. 343 func (s *DockerSuite) TestCpFromCaseI(c *check.C) { 344 testRequires(c, DaemonIsLinux) 345 containerID := makeTestContainer(c, testContainerOptions{ 346 addContent: true, workDir: "/root", 347 }) 348 349 tmpDir := getTestDir(c, "test-cp-from-case-i") 350 defer os.RemoveAll(tmpDir) 351 352 makeTestContentInDir(c, tmpDir) 353 354 srcDir := containerCpPathTrailingSep(containerID, "/root/dir1") + "." 355 dstFile := cpPath(tmpDir, "file1") 356 357 err := runDockerCp(c, srcDir, dstFile, nil) 358 c.Assert(err, checker.NotNil) 359 360 c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err)) 361 } 362 363 // J. SRC specifies a directory's contents only and DST exists as a directory. 364 // This should copy the contents of the SRC directory (but not the directory 365 // itself) into the DST directory. Ensure this works whether DST has a 366 // trailing path separator or not. 367 func (s *DockerSuite) TestCpFromCaseJ(c *check.C) { 368 testRequires(c, DaemonIsLinux) 369 containerID := makeTestContainer(c, testContainerOptions{ 370 addContent: true, workDir: "/root", 371 }) 372 373 tmpDir := getTestDir(c, "test-cp-from-case-j") 374 defer os.RemoveAll(tmpDir) 375 376 makeTestContentInDir(c, tmpDir) 377 378 srcDir := containerCpPathTrailingSep(containerID, "/root/dir1") + "." 379 dstDir := cpPath(tmpDir, "dir2") 380 dstPath := filepath.Join(dstDir, "file1-1") 381 382 c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) 383 384 c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) 385 386 // Now try again but using a trailing path separator for dstDir. 387 388 // unable to remove dstDir 389 c.Assert(os.RemoveAll(dstDir), checker.IsNil) 390 391 // unable to make dstDir 392 c.Assert(os.MkdirAll(dstDir, os.FileMode(0755)), checker.IsNil) 393 394 dstDir = cpPathTrailingSep(tmpDir, "dir2") 395 396 c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil) 397 398 c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil) 399 }