github.com/campoy/docker@v1.8.0-rc1/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/go-check/check" 8 ) 9 10 // docker cp CONTAINER:PATH LOCALPATH 11 12 // Try all of the test cases from the archive package which implements the 13 // internals of `docker cp` and ensure that the behavior matches when actually 14 // copying to and from containers. 15 16 // Basic assumptions about SRC and DST: 17 // 1. SRC must exist. 18 // 2. If SRC ends with a trailing separator, it must be a directory. 19 // 3. DST parent directory must exist. 20 // 4. If DST exists as a file, it must not end with a trailing separator. 21 22 // First get these easy error cases out of the way. 23 24 // Test for error when SRC does not exist. 25 func (s *DockerSuite) TestCpFromErrSrcNotExists(c *check.C) { 26 cID := makeTestContainer(c, testContainerOptions{}) 27 defer deleteContainer(cID) 28 29 tmpDir := getTestDir(c, "test-cp-from-err-src-not-exists") 30 defer os.RemoveAll(tmpDir) 31 32 err := runDockerCp(c, containerCpPath(cID, "file1"), tmpDir) 33 if err == nil { 34 c.Fatal("expected IsNotExist error, but got nil instead") 35 } 36 37 if !isCpNotExist(err) { 38 c.Fatalf("expected IsNotExist error, but got %T: %s", err, err) 39 } 40 } 41 42 // Test for error when SRC ends in a trailing 43 // path separator but it exists as a file. 44 func (s *DockerSuite) TestCpFromErrSrcNotDir(c *check.C) { 45 cID := makeTestContainer(c, testContainerOptions{addContent: true}) 46 defer deleteContainer(cID) 47 48 tmpDir := getTestDir(c, "test-cp-from-err-src-not-dir") 49 defer os.RemoveAll(tmpDir) 50 51 err := runDockerCp(c, containerCpPathTrailingSep(cID, "file1"), tmpDir) 52 if err == nil { 53 c.Fatal("expected IsNotDir error, but got nil instead") 54 } 55 56 if !isCpNotDir(err) { 57 c.Fatalf("expected IsNotDir error, but got %T: %s", err, err) 58 } 59 } 60 61 // Test for error when SRC is a valid file or directory, 62 // bu the DST parent directory does not exist. 63 func (s *DockerSuite) TestCpFromErrDstParentNotExists(c *check.C) { 64 cID := makeTestContainer(c, testContainerOptions{addContent: true}) 65 defer deleteContainer(cID) 66 67 tmpDir := getTestDir(c, "test-cp-from-err-dst-parent-not-exists") 68 defer os.RemoveAll(tmpDir) 69 70 makeTestContentInDir(c, tmpDir) 71 72 // Try with a file source. 73 srcPath := containerCpPath(cID, "/file1") 74 dstPath := cpPath(tmpDir, "notExists", "file1") 75 76 err := runDockerCp(c, srcPath, dstPath) 77 if err == nil { 78 c.Fatal("expected IsNotExist error, but got nil instead") 79 } 80 81 if !isCpNotExist(err) { 82 c.Fatalf("expected IsNotExist error, but got %T: %s", err, err) 83 } 84 85 // Try with a directory source. 86 srcPath = containerCpPath(cID, "/dir1") 87 88 if err := runDockerCp(c, srcPath, dstPath); err == nil { 89 c.Fatal("expected IsNotExist error, but got nil instead") 90 } 91 92 if !isCpNotExist(err) { 93 c.Fatalf("expected IsNotExist error, but got %T: %s", err, err) 94 } 95 } 96 97 // Test for error when DST ends in a trailing 98 // path separator but exists as a file. 99 func (s *DockerSuite) TestCpFromErrDstNotDir(c *check.C) { 100 cID := makeTestContainer(c, testContainerOptions{addContent: true}) 101 defer deleteContainer(cID) 102 103 tmpDir := getTestDir(c, "test-cp-from-err-dst-not-dir") 104 defer os.RemoveAll(tmpDir) 105 106 makeTestContentInDir(c, tmpDir) 107 108 // Try with a file source. 109 srcPath := containerCpPath(cID, "/file1") 110 dstPath := cpPathTrailingSep(tmpDir, "file1") 111 112 err := runDockerCp(c, srcPath, dstPath) 113 if err == nil { 114 c.Fatal("expected IsNotDir error, but got nil instead") 115 } 116 117 if !isCpNotDir(err) { 118 c.Fatalf("expected IsNotDir error, but got %T: %s", err, err) 119 } 120 121 // Try with a directory source. 122 srcPath = containerCpPath(cID, "/dir1") 123 124 if err := runDockerCp(c, srcPath, dstPath); err == nil { 125 c.Fatal("expected IsNotDir error, but got nil instead") 126 } 127 128 if !isCpNotDir(err) { 129 c.Fatalf("expected IsNotDir error, but got %T: %s", err, err) 130 } 131 } 132 133 // Possibilities are reduced to the remaining 10 cases: 134 // 135 // case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action 136 // =================================================================================================== 137 // A | no | - | no | - | no | create file 138 // B | no | - | no | - | yes | error 139 // C | no | - | yes | no | - | overwrite file 140 // D | no | - | yes | yes | - | create file in dst dir 141 // E | yes | no | no | - | - | create dir, copy contents 142 // F | yes | no | yes | no | - | error 143 // G | yes | no | yes | yes | - | copy dir and contents 144 // H | yes | yes | no | - | - | create dir, copy contents 145 // I | yes | yes | yes | no | - | error 146 // J | yes | yes | yes | yes | - | copy dir contents 147 // 148 149 // A. SRC specifies a file and DST (no trailing path separator) doesn't 150 // exist. This should create a file with the name DST and copy the 151 // contents of the source file into it. 152 func (s *DockerSuite) TestCpFromCaseA(c *check.C) { 153 cID := makeTestContainer(c, testContainerOptions{ 154 addContent: true, workDir: "/root", 155 }) 156 defer deleteContainer(cID) 157 158 tmpDir := getTestDir(c, "test-cp-from-case-a") 159 defer os.RemoveAll(tmpDir) 160 161 srcPath := containerCpPath(cID, "/root/file1") 162 dstPath := cpPath(tmpDir, "itWorks.txt") 163 164 if err := runDockerCp(c, srcPath, dstPath); err != nil { 165 c.Fatalf("unexpected error %T: %s", err, err) 166 } 167 168 if err := fileContentEquals(c, dstPath, "file1\n"); err != nil { 169 c.Fatal(err) 170 } 171 } 172 173 // B. SRC specifies a file and DST (with trailing path separator) doesn't 174 // exist. This should cause an error because the copy operation cannot 175 // create a directory when copying a single file. 176 func (s *DockerSuite) TestCpFromCaseB(c *check.C) { 177 cID := makeTestContainer(c, testContainerOptions{addContent: true}) 178 defer deleteContainer(cID) 179 180 tmpDir := getTestDir(c, "test-cp-from-case-b") 181 defer os.RemoveAll(tmpDir) 182 183 srcPath := containerCpPath(cID, "/file1") 184 dstDir := cpPathTrailingSep(tmpDir, "testDir") 185 186 err := runDockerCp(c, srcPath, dstDir) 187 if err == nil { 188 c.Fatal("expected DirNotExists error, but got nil instead") 189 } 190 191 if !isCpDirNotExist(err) { 192 c.Fatalf("expected DirNotExists error, but got %T: %s", err, err) 193 } 194 } 195 196 // C. SRC specifies a file and DST exists as a file. This should overwrite 197 // the file at DST with the contents of the source file. 198 func (s *DockerSuite) TestCpFromCaseC(c *check.C) { 199 cID := makeTestContainer(c, testContainerOptions{ 200 addContent: true, workDir: "/root", 201 }) 202 defer deleteContainer(cID) 203 204 tmpDir := getTestDir(c, "test-cp-from-case-c") 205 defer os.RemoveAll(tmpDir) 206 207 makeTestContentInDir(c, tmpDir) 208 209 srcPath := containerCpPath(cID, "/root/file1") 210 dstPath := cpPath(tmpDir, "file2") 211 212 // Ensure the local file starts with different content. 213 if err := fileContentEquals(c, dstPath, "file2\n"); err != nil { 214 c.Fatal(err) 215 } 216 217 if err := runDockerCp(c, srcPath, dstPath); err != nil { 218 c.Fatalf("unexpected error %T: %s", err, err) 219 } 220 221 if err := fileContentEquals(c, dstPath, "file1\n"); err != nil { 222 c.Fatal(err) 223 } 224 } 225 226 // D. SRC specifies a file and DST exists as a directory. This should place 227 // a copy of the source file inside it using the basename from SRC. Ensure 228 // this works whether DST has a trailing path separator or not. 229 func (s *DockerSuite) TestCpFromCaseD(c *check.C) { 230 cID := makeTestContainer(c, testContainerOptions{addContent: true}) 231 defer deleteContainer(cID) 232 233 tmpDir := getTestDir(c, "test-cp-from-case-d") 234 defer os.RemoveAll(tmpDir) 235 236 makeTestContentInDir(c, tmpDir) 237 238 srcPath := containerCpPath(cID, "/file1") 239 dstDir := cpPath(tmpDir, "dir1") 240 dstPath := filepath.Join(dstDir, "file1") 241 242 // Ensure that dstPath doesn't exist. 243 if _, err := os.Stat(dstPath); !os.IsNotExist(err) { 244 c.Fatalf("did not expect dstPath %q to exist", dstPath) 245 } 246 247 if err := runDockerCp(c, srcPath, dstDir); err != nil { 248 c.Fatalf("unexpected error %T: %s", err, err) 249 } 250 251 if err := fileContentEquals(c, dstPath, "file1\n"); err != nil { 252 c.Fatal(err) 253 } 254 255 // Now try again but using a trailing path separator for dstDir. 256 257 if err := os.RemoveAll(dstDir); err != nil { 258 c.Fatalf("unable to remove dstDir: %s", err) 259 } 260 261 if err := os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 262 c.Fatalf("unable to make dstDir: %s", err) 263 } 264 265 dstDir = cpPathTrailingSep(tmpDir, "dir1") 266 267 if err := runDockerCp(c, srcPath, dstDir); err != nil { 268 c.Fatalf("unexpected error %T: %s", err, err) 269 } 270 271 if err := fileContentEquals(c, dstPath, "file1\n"); err != nil { 272 c.Fatal(err) 273 } 274 } 275 276 // E. SRC specifies a directory and DST does not exist. This should create a 277 // directory at DST and copy the contents of the SRC directory into the DST 278 // directory. Ensure this works whether DST has a trailing path separator or 279 // not. 280 func (s *DockerSuite) TestCpFromCaseE(c *check.C) { 281 cID := makeTestContainer(c, testContainerOptions{addContent: true}) 282 defer deleteContainer(cID) 283 284 tmpDir := getTestDir(c, "test-cp-from-case-e") 285 defer os.RemoveAll(tmpDir) 286 287 srcDir := containerCpPath(cID, "dir1") 288 dstDir := cpPath(tmpDir, "testDir") 289 dstPath := filepath.Join(dstDir, "file1-1") 290 291 if err := runDockerCp(c, srcDir, dstDir); err != nil { 292 c.Fatalf("unexpected error %T: %s", err, err) 293 } 294 295 if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil { 296 c.Fatal(err) 297 } 298 299 // Now try again but using a trailing path separator for dstDir. 300 301 if err := os.RemoveAll(dstDir); err != nil { 302 c.Fatalf("unable to remove dstDir: %s", err) 303 } 304 305 dstDir = cpPathTrailingSep(tmpDir, "testDir") 306 307 if err := runDockerCp(c, srcDir, dstDir); err != nil { 308 c.Fatalf("unexpected error %T: %s", err, err) 309 } 310 311 if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil { 312 c.Fatal(err) 313 } 314 } 315 316 // F. SRC specifies a directory and DST exists as a file. This should cause an 317 // error as it is not possible to overwrite a file with a directory. 318 func (s *DockerSuite) TestCpFromCaseF(c *check.C) { 319 cID := makeTestContainer(c, testContainerOptions{ 320 addContent: true, workDir: "/root", 321 }) 322 defer deleteContainer(cID) 323 324 tmpDir := getTestDir(c, "test-cp-from-case-f") 325 defer os.RemoveAll(tmpDir) 326 327 makeTestContentInDir(c, tmpDir) 328 329 srcDir := containerCpPath(cID, "/root/dir1") 330 dstFile := cpPath(tmpDir, "file1") 331 332 err := runDockerCp(c, srcDir, dstFile) 333 if err == nil { 334 c.Fatal("expected ErrCannotCopyDir error, but got nil instead") 335 } 336 337 if !isCpCannotCopyDir(err) { 338 c.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err) 339 } 340 } 341 342 // G. SRC specifies a directory and DST exists as a directory. This should copy 343 // the SRC directory and all its contents to the DST directory. Ensure this 344 // works whether DST has a trailing path separator or not. 345 func (s *DockerSuite) TestCpFromCaseG(c *check.C) { 346 cID := makeTestContainer(c, testContainerOptions{ 347 addContent: true, workDir: "/root", 348 }) 349 defer deleteContainer(cID) 350 351 tmpDir := getTestDir(c, "test-cp-from-case-g") 352 defer os.RemoveAll(tmpDir) 353 354 makeTestContentInDir(c, tmpDir) 355 356 srcDir := containerCpPath(cID, "/root/dir1") 357 dstDir := cpPath(tmpDir, "dir2") 358 resultDir := filepath.Join(dstDir, "dir1") 359 dstPath := filepath.Join(resultDir, "file1-1") 360 361 if err := runDockerCp(c, srcDir, dstDir); err != nil { 362 c.Fatalf("unexpected error %T: %s", err, err) 363 } 364 365 if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil { 366 c.Fatal(err) 367 } 368 369 // Now try again but using a trailing path separator for dstDir. 370 371 if err := os.RemoveAll(dstDir); err != nil { 372 c.Fatalf("unable to remove dstDir: %s", err) 373 } 374 375 if err := os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 376 c.Fatalf("unable to make dstDir: %s", err) 377 } 378 379 dstDir = cpPathTrailingSep(tmpDir, "dir2") 380 381 if err := runDockerCp(c, srcDir, dstDir); err != nil { 382 c.Fatalf("unexpected error %T: %s", err, err) 383 } 384 385 if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil { 386 c.Fatal(err) 387 } 388 } 389 390 // H. SRC specifies a directory's contents only and DST does not exist. This 391 // should create a directory at DST and copy the contents of the SRC 392 // directory (but not the directory itself) into the DST directory. Ensure 393 // this works whether DST has a trailing path separator or not. 394 func (s *DockerSuite) TestCpFromCaseH(c *check.C) { 395 cID := makeTestContainer(c, testContainerOptions{addContent: true}) 396 defer deleteContainer(cID) 397 398 tmpDir := getTestDir(c, "test-cp-from-case-h") 399 defer os.RemoveAll(tmpDir) 400 401 srcDir := containerCpPathTrailingSep(cID, "dir1") + "." 402 dstDir := cpPath(tmpDir, "testDir") 403 dstPath := filepath.Join(dstDir, "file1-1") 404 405 if err := runDockerCp(c, srcDir, dstDir); err != nil { 406 c.Fatalf("unexpected error %T: %s", err, err) 407 } 408 409 if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil { 410 c.Fatal(err) 411 } 412 413 // Now try again but using a trailing path separator for dstDir. 414 415 if err := os.RemoveAll(dstDir); err != nil { 416 c.Fatalf("unable to remove resultDir: %s", err) 417 } 418 419 dstDir = cpPathTrailingSep(tmpDir, "testDir") 420 421 if err := runDockerCp(c, srcDir, dstDir); err != nil { 422 c.Fatalf("unexpected error %T: %s", err, err) 423 } 424 425 if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil { 426 c.Fatal(err) 427 } 428 } 429 430 // I. SRC specifies a direcotry's contents only and DST exists as a file. This 431 // should cause an error as it is not possible to overwrite a file with a 432 // directory. 433 func (s *DockerSuite) TestCpFromCaseI(c *check.C) { 434 cID := makeTestContainer(c, testContainerOptions{ 435 addContent: true, workDir: "/root", 436 }) 437 defer deleteContainer(cID) 438 439 tmpDir := getTestDir(c, "test-cp-from-case-i") 440 defer os.RemoveAll(tmpDir) 441 442 makeTestContentInDir(c, tmpDir) 443 444 srcDir := containerCpPathTrailingSep(cID, "/root/dir1") + "." 445 dstFile := cpPath(tmpDir, "file1") 446 447 err := runDockerCp(c, srcDir, dstFile) 448 if err == nil { 449 c.Fatal("expected ErrCannotCopyDir error, but got nil instead") 450 } 451 452 if !isCpCannotCopyDir(err) { 453 c.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err) 454 } 455 } 456 457 // J. SRC specifies a directory's contents only and DST exists as a directory. 458 // This should copy the contents of the SRC directory (but not the directory 459 // itself) into the DST directory. Ensure this works whether DST has a 460 // trailing path separator or not. 461 func (s *DockerSuite) TestCpFromCaseJ(c *check.C) { 462 cID := makeTestContainer(c, testContainerOptions{ 463 addContent: true, workDir: "/root", 464 }) 465 defer deleteContainer(cID) 466 467 tmpDir := getTestDir(c, "test-cp-from-case-j") 468 defer os.RemoveAll(tmpDir) 469 470 makeTestContentInDir(c, tmpDir) 471 472 srcDir := containerCpPathTrailingSep(cID, "/root/dir1") + "." 473 dstDir := cpPath(tmpDir, "dir2") 474 dstPath := filepath.Join(dstDir, "file1-1") 475 476 if err := runDockerCp(c, srcDir, dstDir); err != nil { 477 c.Fatalf("unexpected error %T: %s", err, err) 478 } 479 480 if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil { 481 c.Fatal(err) 482 } 483 484 // Now try again but using a trailing path separator for dstDir. 485 486 if err := os.RemoveAll(dstDir); err != nil { 487 c.Fatalf("unable to remove dstDir: %s", err) 488 } 489 490 if err := os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 491 c.Fatalf("unable to make dstDir: %s", err) 492 } 493 494 dstDir = cpPathTrailingSep(tmpDir, "dir2") 495 496 if err := runDockerCp(c, srcDir, dstDir); err != nil { 497 c.Fatalf("unexpected error %T: %s", err, err) 498 } 499 500 if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil { 501 c.Fatal(err) 502 } 503 }