Tizen_4.0 base
[platform/upstream/docker-engine.git] / pkg / archive / copy_unix_test.go
1 // +build !windows
2
3 // TODO Windows: Some of these tests may be salvageable 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 }