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