copy_unix_test.go 28 KB

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