copy_unix_test.go 28 KB

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