github.com/endocode/docker@v1.4.2-0.20160113120958-46eb4700391e/pkg/archive/copy_test.go (about) 1 package archive 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "encoding/hex" 7 "fmt" 8 "io" 9 "io/ioutil" 10 "os" 11 "path/filepath" 12 "strings" 13 "testing" 14 ) 15 16 func removeAllPaths(paths ...string) { 17 for _, path := range paths { 18 os.RemoveAll(path) 19 } 20 } 21 22 func getTestTempDirs(t *testing.T) (tmpDirA, tmpDirB string) { 23 var err error 24 25 if tmpDirA, err = ioutil.TempDir("", "archive-copy-test"); err != nil { 26 t.Fatal(err) 27 } 28 29 if tmpDirB, err = ioutil.TempDir("", "archive-copy-test"); err != nil { 30 t.Fatal(err) 31 } 32 33 return 34 } 35 36 func isNotDir(err error) bool { 37 return strings.Contains(err.Error(), "not a directory") 38 } 39 40 func joinTrailingSep(pathElements ...string) string { 41 joined := filepath.Join(pathElements...) 42 43 return fmt.Sprintf("%s%c", joined, filepath.Separator) 44 } 45 46 func fileContentsEqual(t *testing.T, filenameA, filenameB string) (err error) { 47 t.Logf("checking for equal file contents: %q and %q\n", filenameA, filenameB) 48 49 fileA, err := os.Open(filenameA) 50 if err != nil { 51 return 52 } 53 defer fileA.Close() 54 55 fileB, err := os.Open(filenameB) 56 if err != nil { 57 return 58 } 59 defer fileB.Close() 60 61 hasher := sha256.New() 62 63 if _, err = io.Copy(hasher, fileA); err != nil { 64 return 65 } 66 67 hashA := hasher.Sum(nil) 68 hasher.Reset() 69 70 if _, err = io.Copy(hasher, fileB); err != nil { 71 return 72 } 73 74 hashB := hasher.Sum(nil) 75 76 if !bytes.Equal(hashA, hashB) { 77 err = fmt.Errorf("file content hashes not equal - expected %s, got %s", hex.EncodeToString(hashA), hex.EncodeToString(hashB)) 78 } 79 80 return 81 } 82 83 func dirContentsEqual(t *testing.T, newDir, oldDir string) (err error) { 84 t.Logf("checking for equal directory contents: %q and %q\n", newDir, oldDir) 85 86 var changes []Change 87 88 if changes, err = ChangesDirs(newDir, oldDir); err != nil { 89 return 90 } 91 92 if len(changes) != 0 { 93 err = fmt.Errorf("expected no changes between directories, but got: %v", changes) 94 } 95 96 return 97 } 98 99 func logDirContents(t *testing.T, dirPath string) { 100 logWalkedPaths := filepath.WalkFunc(func(path string, info os.FileInfo, err error) error { 101 if err != nil { 102 t.Errorf("stat error for path %q: %s", path, err) 103 return nil 104 } 105 106 if info.IsDir() { 107 path = joinTrailingSep(path) 108 } 109 110 t.Logf("\t%s", path) 111 112 return nil 113 }) 114 115 t.Logf("logging directory contents: %q", dirPath) 116 117 if err := filepath.Walk(dirPath, logWalkedPaths); err != nil { 118 t.Fatal(err) 119 } 120 } 121 122 func testCopyHelper(t *testing.T, srcPath, dstPath string) (err error) { 123 t.Logf("copying from %q to %q (not follow symbol link)", srcPath, dstPath) 124 125 return CopyResource(srcPath, dstPath, false) 126 } 127 128 func testCopyHelperFSym(t *testing.T, srcPath, dstPath string) (err error) { 129 t.Logf("copying from %q to %q (follow symbol link)", srcPath, dstPath) 130 131 return CopyResource(srcPath, dstPath, true) 132 } 133 134 // Basic assumptions about SRC and DST: 135 // 1. SRC must exist. 136 // 2. If SRC ends with a trailing separator, it must be a directory. 137 // 3. DST parent directory must exist. 138 // 4. If DST exists as a file, it must not end with a trailing separator. 139 140 // First get these easy error cases out of the way. 141 142 // Test for error when SRC does not exist. 143 func TestCopyErrSrcNotExists(t *testing.T) { 144 tmpDirA, tmpDirB := getTestTempDirs(t) 145 defer removeAllPaths(tmpDirA, tmpDirB) 146 147 if _, err := CopyInfoSourcePath(filepath.Join(tmpDirA, "file1"), false); !os.IsNotExist(err) { 148 t.Fatalf("expected IsNotExist error, but got %T: %s", err, err) 149 } 150 } 151 152 // Test for error when SRC ends in a trailing 153 // path separator but it exists as a file. 154 func TestCopyErrSrcNotDir(t *testing.T) { 155 tmpDirA, tmpDirB := getTestTempDirs(t) 156 defer removeAllPaths(tmpDirA, tmpDirB) 157 158 // Load A with some sample files and directories. 159 createSampleDir(t, tmpDirA) 160 161 if _, err := CopyInfoSourcePath(joinTrailingSep(tmpDirA, "file1"), false); !isNotDir(err) { 162 t.Fatalf("expected IsNotDir error, but got %T: %s", err, err) 163 } 164 } 165 166 // Test for error when SRC is a valid file or directory, 167 // but the DST parent directory does not exist. 168 func TestCopyErrDstParentNotExists(t *testing.T) { 169 tmpDirA, tmpDirB := getTestTempDirs(t) 170 defer removeAllPaths(tmpDirA, tmpDirB) 171 172 // Load A with some sample files and directories. 173 createSampleDir(t, tmpDirA) 174 175 srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false} 176 177 // Try with a file source. 178 content, err := TarResource(srcInfo) 179 if err != nil { 180 t.Fatalf("unexpected error %T: %s", err, err) 181 } 182 defer content.Close() 183 184 // Copy to a file whose parent does not exist. 185 if err = CopyTo(content, srcInfo, filepath.Join(tmpDirB, "fakeParentDir", "file1")); err == nil { 186 t.Fatal("expected IsNotExist error, but got nil instead") 187 } 188 189 if !os.IsNotExist(err) { 190 t.Fatalf("expected IsNotExist error, but got %T: %s", err, err) 191 } 192 193 // Try with a directory source. 194 srcInfo = CopyInfo{Path: filepath.Join(tmpDirA, "dir1"), Exists: true, IsDir: true} 195 196 content, err = TarResource(srcInfo) 197 if err != nil { 198 t.Fatalf("unexpected error %T: %s", err, err) 199 } 200 defer content.Close() 201 202 // Copy to a directory whose parent does not exist. 203 if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "fakeParentDir", "fakeDstDir")); err == nil { 204 t.Fatal("expected IsNotExist error, but got nil instead") 205 } 206 207 if !os.IsNotExist(err) { 208 t.Fatalf("expected IsNotExist error, but got %T: %s", err, err) 209 } 210 } 211 212 // Test for error when DST ends in a trailing 213 // path separator but exists as a file. 214 func TestCopyErrDstNotDir(t *testing.T) { 215 tmpDirA, tmpDirB := getTestTempDirs(t) 216 defer removeAllPaths(tmpDirA, tmpDirB) 217 218 // Load A and B with some sample files and directories. 219 createSampleDir(t, tmpDirA) 220 createSampleDir(t, tmpDirB) 221 222 // Try with a file source. 223 srcInfo := CopyInfo{Path: filepath.Join(tmpDirA, "file1"), Exists: true, IsDir: false} 224 225 content, err := TarResource(srcInfo) 226 if err != nil { 227 t.Fatalf("unexpected error %T: %s", err, err) 228 } 229 defer content.Close() 230 231 if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "file1")); err == nil { 232 t.Fatal("expected IsNotDir error, but got nil instead") 233 } 234 235 if !isNotDir(err) { 236 t.Fatalf("expected IsNotDir error, but got %T: %s", err, err) 237 } 238 239 // Try with a directory source. 240 srcInfo = CopyInfo{Path: filepath.Join(tmpDirA, "dir1"), Exists: true, IsDir: true} 241 242 content, err = TarResource(srcInfo) 243 if err != nil { 244 t.Fatalf("unexpected error %T: %s", err, err) 245 } 246 defer content.Close() 247 248 if err = CopyTo(content, srcInfo, joinTrailingSep(tmpDirB, "file1")); err == nil { 249 t.Fatal("expected IsNotDir error, but got nil instead") 250 } 251 252 if !isNotDir(err) { 253 t.Fatalf("expected IsNotDir error, but got %T: %s", err, err) 254 } 255 } 256 257 // Possibilities are reduced to the remaining 10 cases: 258 // 259 // case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action 260 // =================================================================================================== 261 // A | no | - | no | - | no | create file 262 // B | no | - | no | - | yes | error 263 // C | no | - | yes | no | - | overwrite file 264 // D | no | - | yes | yes | - | create file in dst dir 265 // E | yes | no | no | - | - | create dir, copy contents 266 // F | yes | no | yes | no | - | error 267 // G | yes | no | yes | yes | - | copy dir and contents 268 // H | yes | yes | no | - | - | create dir, copy contents 269 // I | yes | yes | yes | no | - | error 270 // J | yes | yes | yes | yes | - | copy dir contents 271 // 272 273 // A. SRC specifies a file and DST (no trailing path separator) doesn't 274 // exist. This should create a file with the name DST and copy the 275 // contents of the source file into it. 276 func TestCopyCaseA(t *testing.T) { 277 tmpDirA, tmpDirB := getTestTempDirs(t) 278 defer removeAllPaths(tmpDirA, tmpDirB) 279 280 // Load A with some sample files and directories. 281 createSampleDir(t, tmpDirA) 282 283 srcPath := filepath.Join(tmpDirA, "file1") 284 dstPath := filepath.Join(tmpDirB, "itWorks.txt") 285 286 var err error 287 288 if err = testCopyHelper(t, srcPath, dstPath); err != nil { 289 t.Fatalf("unexpected error %T: %s", err, err) 290 } 291 292 if err = fileContentsEqual(t, srcPath, dstPath); err != nil { 293 t.Fatal(err) 294 } 295 os.Remove(dstPath) 296 297 symlinkPath := filepath.Join(tmpDirA, "symlink3") 298 symlinkPath1 := filepath.Join(tmpDirA, "symlink4") 299 linkTarget := filepath.Join(tmpDirA, "file1") 300 301 if err = testCopyHelperFSym(t, symlinkPath, dstPath); err != nil { 302 t.Fatalf("unexpected error %T: %s", err, err) 303 } 304 305 if err = fileContentsEqual(t, linkTarget, dstPath); err != nil { 306 t.Fatal(err) 307 } 308 os.Remove(dstPath) 309 if err = testCopyHelperFSym(t, symlinkPath1, dstPath); err != nil { 310 t.Fatalf("unexpected error %T: %s", err, err) 311 } 312 313 if err = fileContentsEqual(t, linkTarget, dstPath); err != nil { 314 t.Fatal(err) 315 } 316 } 317 318 // B. SRC specifies a file and DST (with trailing path separator) doesn't 319 // exist. This should cause an error because the copy operation cannot 320 // create a directory when copying a single file. 321 func TestCopyCaseB(t *testing.T) { 322 tmpDirA, tmpDirB := getTestTempDirs(t) 323 defer removeAllPaths(tmpDirA, tmpDirB) 324 325 // Load A with some sample files and directories. 326 createSampleDir(t, tmpDirA) 327 328 srcPath := filepath.Join(tmpDirA, "file1") 329 dstDir := joinTrailingSep(tmpDirB, "testDir") 330 331 var err error 332 333 if err = testCopyHelper(t, srcPath, dstDir); err == nil { 334 t.Fatal("expected ErrDirNotExists error, but got nil instead") 335 } 336 337 if err != ErrDirNotExists { 338 t.Fatalf("expected ErrDirNotExists error, but got %T: %s", err, err) 339 } 340 341 symlinkPath := filepath.Join(tmpDirA, "symlink3") 342 343 if err = testCopyHelperFSym(t, symlinkPath, dstDir); err == nil { 344 t.Fatal("expected ErrDirNotExists error, but got nil instead") 345 } 346 if err != ErrDirNotExists { 347 t.Fatalf("expected ErrDirNotExists error, but got %T: %s", err, err) 348 } 349 350 } 351 352 // C. SRC specifies a file and DST exists as a file. This should overwrite 353 // the file at DST with the contents of the source file. 354 func TestCopyCaseC(t *testing.T) { 355 tmpDirA, tmpDirB := getTestTempDirs(t) 356 defer removeAllPaths(tmpDirA, tmpDirB) 357 358 // Load A and B with some sample files and directories. 359 createSampleDir(t, tmpDirA) 360 createSampleDir(t, tmpDirB) 361 362 srcPath := filepath.Join(tmpDirA, "file1") 363 dstPath := filepath.Join(tmpDirB, "file2") 364 365 var err error 366 367 // Ensure they start out different. 368 if err = fileContentsEqual(t, srcPath, dstPath); err == nil { 369 t.Fatal("expected different file contents") 370 } 371 372 if err = testCopyHelper(t, srcPath, dstPath); err != nil { 373 t.Fatalf("unexpected error %T: %s", err, err) 374 } 375 376 if err = fileContentsEqual(t, srcPath, dstPath); err != nil { 377 t.Fatal(err) 378 } 379 } 380 381 // C. Symbol link following version: 382 // SRC specifies a file and DST exists as a file. This should overwrite 383 // the file at DST with the contents of the source file. 384 func TestCopyCaseCFSym(t *testing.T) { 385 tmpDirA, tmpDirB := getTestTempDirs(t) 386 defer removeAllPaths(tmpDirA, tmpDirB) 387 388 // Load A and B with some sample files and directories. 389 createSampleDir(t, tmpDirA) 390 createSampleDir(t, tmpDirB) 391 392 symlinkPathBad := filepath.Join(tmpDirA, "symlink1") 393 symlinkPath := filepath.Join(tmpDirA, "symlink3") 394 linkTarget := filepath.Join(tmpDirA, "file1") 395 dstPath := filepath.Join(tmpDirB, "file2") 396 397 var err error 398 399 // first to test broken link 400 if err = testCopyHelperFSym(t, symlinkPathBad, dstPath); err == nil { 401 t.Fatalf("unexpected error %T: %s", err, err) 402 } 403 404 // test symbol link -> symbol link -> target 405 // Ensure they start out different. 406 if err = fileContentsEqual(t, linkTarget, dstPath); err == nil { 407 t.Fatal("expected different file contents") 408 } 409 410 if err = testCopyHelperFSym(t, symlinkPath, dstPath); err != nil { 411 t.Fatalf("unexpected error %T: %s", err, err) 412 } 413 414 if err = fileContentsEqual(t, linkTarget, dstPath); err != nil { 415 t.Fatal(err) 416 } 417 } 418 419 // D. SRC specifies a file and DST exists as a directory. This should place 420 // a copy of the source file inside it using the basename from SRC. Ensure 421 // this works whether DST has a trailing path separator or not. 422 func TestCopyCaseD(t *testing.T) { 423 tmpDirA, tmpDirB := getTestTempDirs(t) 424 defer removeAllPaths(tmpDirA, tmpDirB) 425 426 // Load A and B with some sample files and directories. 427 createSampleDir(t, tmpDirA) 428 createSampleDir(t, tmpDirB) 429 430 srcPath := filepath.Join(tmpDirA, "file1") 431 dstDir := filepath.Join(tmpDirB, "dir1") 432 dstPath := filepath.Join(dstDir, "file1") 433 434 var err error 435 436 // Ensure that dstPath doesn't exist. 437 if _, err = os.Stat(dstPath); !os.IsNotExist(err) { 438 t.Fatalf("did not expect dstPath %q to exist", dstPath) 439 } 440 441 if err = testCopyHelper(t, srcPath, dstDir); err != nil { 442 t.Fatalf("unexpected error %T: %s", err, err) 443 } 444 445 if err = fileContentsEqual(t, srcPath, dstPath); err != nil { 446 t.Fatal(err) 447 } 448 449 // Now try again but using a trailing path separator for dstDir. 450 451 if err = os.RemoveAll(dstDir); err != nil { 452 t.Fatalf("unable to remove dstDir: %s", err) 453 } 454 455 if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 456 t.Fatalf("unable to make dstDir: %s", err) 457 } 458 459 dstDir = joinTrailingSep(tmpDirB, "dir1") 460 461 if err = testCopyHelper(t, srcPath, dstDir); err != nil { 462 t.Fatalf("unexpected error %T: %s", err, err) 463 } 464 465 if err = fileContentsEqual(t, srcPath, dstPath); err != nil { 466 t.Fatal(err) 467 } 468 } 469 470 // D. Symbol link following version: 471 // SRC specifies a file and DST exists as a directory. This should place 472 // a copy of the source file inside it using the basename from SRC. Ensure 473 // this works whether DST has a trailing path separator or not. 474 func TestCopyCaseDFSym(t *testing.T) { 475 tmpDirA, tmpDirB := getTestTempDirs(t) 476 defer removeAllPaths(tmpDirA, tmpDirB) 477 478 // Load A and B with some sample files and directories. 479 createSampleDir(t, tmpDirA) 480 createSampleDir(t, tmpDirB) 481 482 srcPath := filepath.Join(tmpDirA, "symlink4") 483 linkTarget := filepath.Join(tmpDirA, "file1") 484 dstDir := filepath.Join(tmpDirB, "dir1") 485 dstPath := filepath.Join(dstDir, "symlink4") 486 487 var err error 488 489 // Ensure that dstPath doesn't exist. 490 if _, err = os.Stat(dstPath); !os.IsNotExist(err) { 491 t.Fatalf("did not expect dstPath %q to exist", dstPath) 492 } 493 494 if err = testCopyHelperFSym(t, srcPath, dstDir); err != nil { 495 t.Fatalf("unexpected error %T: %s", err, err) 496 } 497 498 if err = fileContentsEqual(t, linkTarget, dstPath); err != nil { 499 t.Fatal(err) 500 } 501 502 // Now try again but using a trailing path separator for dstDir. 503 504 if err = os.RemoveAll(dstDir); err != nil { 505 t.Fatalf("unable to remove dstDir: %s", err) 506 } 507 508 if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 509 t.Fatalf("unable to make dstDir: %s", err) 510 } 511 512 dstDir = joinTrailingSep(tmpDirB, "dir1") 513 514 if err = testCopyHelperFSym(t, srcPath, dstDir); err != nil { 515 t.Fatalf("unexpected error %T: %s", err, err) 516 } 517 518 if err = fileContentsEqual(t, linkTarget, dstPath); err != nil { 519 t.Fatal(err) 520 } 521 } 522 523 // E. SRC specifies a directory and DST does not exist. This should create a 524 // directory at DST and copy the contents of the SRC directory into the DST 525 // directory. Ensure this works whether DST has a trailing path separator or 526 // not. 527 func TestCopyCaseE(t *testing.T) { 528 tmpDirA, tmpDirB := getTestTempDirs(t) 529 defer removeAllPaths(tmpDirA, tmpDirB) 530 531 // Load A with some sample files and directories. 532 createSampleDir(t, tmpDirA) 533 534 srcDir := filepath.Join(tmpDirA, "dir1") 535 dstDir := filepath.Join(tmpDirB, "testDir") 536 537 var err error 538 539 if err = testCopyHelper(t, srcDir, dstDir); err != nil { 540 t.Fatalf("unexpected error %T: %s", err, err) 541 } 542 543 if err = dirContentsEqual(t, dstDir, srcDir); err != nil { 544 t.Log("dir contents not equal") 545 logDirContents(t, tmpDirA) 546 logDirContents(t, tmpDirB) 547 t.Fatal(err) 548 } 549 550 // Now try again but using a trailing path separator for dstDir. 551 552 if err = os.RemoveAll(dstDir); err != nil { 553 t.Fatalf("unable to remove dstDir: %s", err) 554 } 555 556 dstDir = joinTrailingSep(tmpDirB, "testDir") 557 558 if err = testCopyHelper(t, srcDir, dstDir); err != nil { 559 t.Fatalf("unexpected error %T: %s", err, err) 560 } 561 562 if err = dirContentsEqual(t, dstDir, srcDir); err != nil { 563 t.Fatal(err) 564 } 565 } 566 567 // E. Symbol link following version: 568 // SRC specifies a directory and DST does not exist. This should create a 569 // directory at DST and copy the contents of the SRC directory into the DST 570 // directory. Ensure this works whether DST has a trailing path separator or 571 // not. 572 func TestCopyCaseEFSym(t *testing.T) { 573 tmpDirA, tmpDirB := getTestTempDirs(t) 574 defer removeAllPaths(tmpDirA, tmpDirB) 575 576 // Load A with some sample files and directories. 577 createSampleDir(t, tmpDirA) 578 579 srcDir := filepath.Join(tmpDirA, "dirSymlink") 580 linkTarget := filepath.Join(tmpDirA, "dir1") 581 dstDir := filepath.Join(tmpDirB, "testDir") 582 583 var err error 584 585 if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil { 586 t.Fatalf("unexpected error %T: %s", err, err) 587 } 588 589 if err = dirContentsEqual(t, dstDir, linkTarget); err != nil { 590 t.Log("dir contents not equal") 591 logDirContents(t, tmpDirA) 592 logDirContents(t, tmpDirB) 593 t.Fatal(err) 594 } 595 596 // Now try again but using a trailing path separator for dstDir. 597 598 if err = os.RemoveAll(dstDir); err != nil { 599 t.Fatalf("unable to remove dstDir: %s", err) 600 } 601 602 dstDir = joinTrailingSep(tmpDirB, "testDir") 603 604 if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil { 605 t.Fatalf("unexpected error %T: %s", err, err) 606 } 607 608 if err = dirContentsEqual(t, dstDir, linkTarget); err != nil { 609 t.Fatal(err) 610 } 611 } 612 613 // F. SRC specifies a directory and DST exists as a file. This should cause an 614 // error as it is not possible to overwrite a file with a directory. 615 func TestCopyCaseF(t *testing.T) { 616 tmpDirA, tmpDirB := getTestTempDirs(t) 617 defer removeAllPaths(tmpDirA, tmpDirB) 618 619 // Load A and B with some sample files and directories. 620 createSampleDir(t, tmpDirA) 621 createSampleDir(t, tmpDirB) 622 623 srcDir := filepath.Join(tmpDirA, "dir1") 624 symSrcDir := filepath.Join(tmpDirA, "dirSymlink") 625 dstFile := filepath.Join(tmpDirB, "file1") 626 627 var err error 628 629 if err = testCopyHelper(t, srcDir, dstFile); err == nil { 630 t.Fatal("expected ErrCannotCopyDir error, but got nil instead") 631 } 632 633 if err != ErrCannotCopyDir { 634 t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err) 635 } 636 637 // now test with symbol link 638 if err = testCopyHelperFSym(t, symSrcDir, dstFile); err == nil { 639 t.Fatal("expected ErrCannotCopyDir error, but got nil instead") 640 } 641 642 if err != ErrCannotCopyDir { 643 t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err) 644 } 645 } 646 647 // G. SRC specifies a directory and DST exists as a directory. This should copy 648 // the SRC directory and all its contents to the DST directory. Ensure this 649 // works whether DST has a trailing path separator or not. 650 func TestCopyCaseG(t *testing.T) { 651 tmpDirA, tmpDirB := getTestTempDirs(t) 652 defer removeAllPaths(tmpDirA, tmpDirB) 653 654 // Load A and B with some sample files and directories. 655 createSampleDir(t, tmpDirA) 656 createSampleDir(t, tmpDirB) 657 658 srcDir := filepath.Join(tmpDirA, "dir1") 659 dstDir := filepath.Join(tmpDirB, "dir2") 660 resultDir := filepath.Join(dstDir, "dir1") 661 662 var err error 663 664 if err = testCopyHelper(t, srcDir, dstDir); err != nil { 665 t.Fatalf("unexpected error %T: %s", err, err) 666 } 667 668 if err = dirContentsEqual(t, resultDir, srcDir); err != nil { 669 t.Fatal(err) 670 } 671 672 // Now try again but using a trailing path separator for dstDir. 673 674 if err = os.RemoveAll(dstDir); err != nil { 675 t.Fatalf("unable to remove dstDir: %s", err) 676 } 677 678 if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 679 t.Fatalf("unable to make dstDir: %s", err) 680 } 681 682 dstDir = joinTrailingSep(tmpDirB, "dir2") 683 684 if err = testCopyHelper(t, srcDir, dstDir); err != nil { 685 t.Fatalf("unexpected error %T: %s", err, err) 686 } 687 688 if err = dirContentsEqual(t, resultDir, srcDir); err != nil { 689 t.Fatal(err) 690 } 691 } 692 693 // G. Symbol link version: 694 // SRC specifies a directory and DST exists as a directory. This should copy 695 // the SRC directory and all its contents to the DST directory. Ensure this 696 // works whether DST has a trailing path separator or not. 697 func TestCopyCaseGFSym(t *testing.T) { 698 tmpDirA, tmpDirB := getTestTempDirs(t) 699 defer removeAllPaths(tmpDirA, tmpDirB) 700 701 // Load A and B with some sample files and directories. 702 createSampleDir(t, tmpDirA) 703 createSampleDir(t, tmpDirB) 704 705 srcDir := filepath.Join(tmpDirA, "dirSymlink") 706 linkTarget := filepath.Join(tmpDirA, "dir1") 707 dstDir := filepath.Join(tmpDirB, "dir2") 708 resultDir := filepath.Join(dstDir, "dirSymlink") 709 710 var err error 711 712 if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil { 713 t.Fatalf("unexpected error %T: %s", err, err) 714 } 715 716 if err = dirContentsEqual(t, resultDir, linkTarget); err != nil { 717 t.Fatal(err) 718 } 719 720 // Now try again but using a trailing path separator for dstDir. 721 722 if err = os.RemoveAll(dstDir); err != nil { 723 t.Fatalf("unable to remove dstDir: %s", err) 724 } 725 726 if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 727 t.Fatalf("unable to make dstDir: %s", err) 728 } 729 730 dstDir = joinTrailingSep(tmpDirB, "dir2") 731 732 if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil { 733 t.Fatalf("unexpected error %T: %s", err, err) 734 } 735 736 if err = dirContentsEqual(t, resultDir, linkTarget); err != nil { 737 t.Fatal(err) 738 } 739 } 740 741 // H. SRC specifies a directory's contents only and DST does not exist. This 742 // should create a directory at DST and copy the contents of the SRC 743 // directory (but not the directory itself) into the DST directory. Ensure 744 // this works whether DST has a trailing path separator or not. 745 func TestCopyCaseH(t *testing.T) { 746 tmpDirA, tmpDirB := getTestTempDirs(t) 747 defer removeAllPaths(tmpDirA, tmpDirB) 748 749 // Load A with some sample files and directories. 750 createSampleDir(t, tmpDirA) 751 752 srcDir := joinTrailingSep(tmpDirA, "dir1") + "." 753 dstDir := filepath.Join(tmpDirB, "testDir") 754 755 var err error 756 757 if err = testCopyHelper(t, srcDir, dstDir); err != nil { 758 t.Fatalf("unexpected error %T: %s", err, err) 759 } 760 761 if err = dirContentsEqual(t, dstDir, srcDir); err != nil { 762 t.Log("dir contents not equal") 763 logDirContents(t, tmpDirA) 764 logDirContents(t, tmpDirB) 765 t.Fatal(err) 766 } 767 768 // Now try again but using a trailing path separator for dstDir. 769 770 if err = os.RemoveAll(dstDir); err != nil { 771 t.Fatalf("unable to remove dstDir: %s", err) 772 } 773 774 dstDir = joinTrailingSep(tmpDirB, "testDir") 775 776 if err = testCopyHelper(t, srcDir, dstDir); err != nil { 777 t.Fatalf("unexpected error %T: %s", err, err) 778 } 779 780 if err = dirContentsEqual(t, dstDir, srcDir); err != nil { 781 t.Log("dir contents not equal") 782 logDirContents(t, tmpDirA) 783 logDirContents(t, tmpDirB) 784 t.Fatal(err) 785 } 786 } 787 788 // H. Symbol link following version: 789 // SRC specifies a directory's contents only and DST does not exist. This 790 // should create a directory at DST and copy the contents of the SRC 791 // directory (but not the directory itself) into the DST directory. Ensure 792 // this works whether DST has a trailing path separator or not. 793 func TestCopyCaseHFSym(t *testing.T) { 794 tmpDirA, tmpDirB := getTestTempDirs(t) 795 defer removeAllPaths(tmpDirA, tmpDirB) 796 797 // Load A with some sample files and directories. 798 createSampleDir(t, tmpDirA) 799 800 srcDir := joinTrailingSep(tmpDirA, "dirSymlink") + "." 801 linkTarget := filepath.Join(tmpDirA, "dir1") 802 dstDir := filepath.Join(tmpDirB, "testDir") 803 804 var err error 805 806 if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil { 807 t.Fatalf("unexpected error %T: %s", err, err) 808 } 809 810 if err = dirContentsEqual(t, dstDir, linkTarget); err != nil { 811 t.Log("dir contents not equal") 812 logDirContents(t, tmpDirA) 813 logDirContents(t, tmpDirB) 814 t.Fatal(err) 815 } 816 817 // Now try again but using a trailing path separator for dstDir. 818 819 if err = os.RemoveAll(dstDir); err != nil { 820 t.Fatalf("unable to remove dstDir: %s", err) 821 } 822 823 dstDir = joinTrailingSep(tmpDirB, "testDir") 824 825 if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil { 826 t.Fatalf("unexpected error %T: %s", err, err) 827 } 828 829 if err = dirContentsEqual(t, dstDir, linkTarget); err != nil { 830 t.Log("dir contents not equal") 831 logDirContents(t, tmpDirA) 832 logDirContents(t, tmpDirB) 833 t.Fatal(err) 834 } 835 } 836 837 // I. SRC specifies a directory's contents only and DST exists as a file. This 838 // should cause an error as it is not possible to overwrite a file with a 839 // directory. 840 func TestCopyCaseI(t *testing.T) { 841 tmpDirA, tmpDirB := getTestTempDirs(t) 842 defer removeAllPaths(tmpDirA, tmpDirB) 843 844 // Load A and B with some sample files and directories. 845 createSampleDir(t, tmpDirA) 846 createSampleDir(t, tmpDirB) 847 848 srcDir := joinTrailingSep(tmpDirA, "dir1") + "." 849 symSrcDir := filepath.Join(tmpDirB, "dirSymlink") 850 dstFile := filepath.Join(tmpDirB, "file1") 851 852 var err error 853 854 if err = testCopyHelper(t, srcDir, dstFile); err == nil { 855 t.Fatal("expected ErrCannotCopyDir error, but got nil instead") 856 } 857 858 if err != ErrCannotCopyDir { 859 t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err) 860 } 861 862 // now try with symbol link of dir 863 if err = testCopyHelperFSym(t, symSrcDir, dstFile); err == nil { 864 t.Fatal("expected ErrCannotCopyDir error, but got nil instead") 865 } 866 867 if err != ErrCannotCopyDir { 868 t.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err) 869 } 870 } 871 872 // J. SRC specifies a directory's contents only and DST exists as a directory. 873 // This should copy the contents of the SRC directory (but not the directory 874 // itself) into the DST directory. Ensure this works whether DST has a 875 // trailing path separator or not. 876 func TestCopyCaseJ(t *testing.T) { 877 tmpDirA, tmpDirB := getTestTempDirs(t) 878 defer removeAllPaths(tmpDirA, tmpDirB) 879 880 // Load A and B with some sample files and directories. 881 createSampleDir(t, tmpDirA) 882 createSampleDir(t, tmpDirB) 883 884 srcDir := joinTrailingSep(tmpDirA, "dir1") + "." 885 dstDir := filepath.Join(tmpDirB, "dir5") 886 887 var err error 888 889 // first to create an empty dir 890 if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 891 t.Fatalf("unable to make dstDir: %s", err) 892 } 893 894 if err = testCopyHelper(t, srcDir, dstDir); err != nil { 895 t.Fatalf("unexpected error %T: %s", err, err) 896 } 897 898 if err = dirContentsEqual(t, dstDir, srcDir); err != nil { 899 t.Fatal(err) 900 } 901 902 // Now try again but using a trailing path separator for dstDir. 903 904 if err = os.RemoveAll(dstDir); err != nil { 905 t.Fatalf("unable to remove dstDir: %s", err) 906 } 907 908 if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 909 t.Fatalf("unable to make dstDir: %s", err) 910 } 911 912 dstDir = joinTrailingSep(tmpDirB, "dir5") 913 914 if err = testCopyHelper(t, srcDir, dstDir); err != nil { 915 t.Fatalf("unexpected error %T: %s", err, err) 916 } 917 918 if err = dirContentsEqual(t, dstDir, srcDir); err != nil { 919 t.Fatal(err) 920 } 921 } 922 923 // J. Symbol link following version: 924 // SRC specifies a directory's contents only and DST exists as a directory. 925 // This should copy the contents of the SRC directory (but not the directory 926 // itself) into the DST directory. Ensure this works whether DST has a 927 // trailing path separator or not. 928 func TestCopyCaseJFSym(t *testing.T) { 929 tmpDirA, tmpDirB := getTestTempDirs(t) 930 defer removeAllPaths(tmpDirA, tmpDirB) 931 932 // Load A and B with some sample files and directories. 933 createSampleDir(t, tmpDirA) 934 createSampleDir(t, tmpDirB) 935 936 srcDir := joinTrailingSep(tmpDirA, "dirSymlink") + "." 937 linkTarget := filepath.Join(tmpDirA, "dir1") 938 dstDir := filepath.Join(tmpDirB, "dir5") 939 940 var err error 941 942 // first to create an empty dir 943 if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 944 t.Fatalf("unable to make dstDir: %s", err) 945 } 946 947 if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil { 948 t.Fatalf("unexpected error %T: %s", err, err) 949 } 950 951 if err = dirContentsEqual(t, dstDir, linkTarget); err != nil { 952 t.Fatal(err) 953 } 954 955 // Now try again but using a trailing path separator for dstDir. 956 957 if err = os.RemoveAll(dstDir); err != nil { 958 t.Fatalf("unable to remove dstDir: %s", err) 959 } 960 961 if err = os.MkdirAll(dstDir, os.FileMode(0755)); err != nil { 962 t.Fatalf("unable to make dstDir: %s", err) 963 } 964 965 dstDir = joinTrailingSep(tmpDirB, "dir5") 966 967 if err = testCopyHelperFSym(t, srcDir, dstDir); err != nil { 968 t.Fatalf("unexpected error %T: %s", err, err) 969 } 970 971 if err = dirContentsEqual(t, dstDir, linkTarget); err != nil { 972 t.Fatal(err) 973 } 974 }