changes_posix_test.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. package archive
  2. import (
  3. "archive/tar"
  4. "fmt"
  5. "io"
  6. "io/ioutil"
  7. "os"
  8. "path"
  9. "runtime"
  10. "sort"
  11. "testing"
  12. )
  13. func TestHardLinkOrder(t *testing.T) {
  14. //TODO Should run for Solaris
  15. if runtime.GOOS == "solaris" {
  16. t.Skip("gcp failures on Solaris")
  17. }
  18. names := []string{"file1.txt", "file2.txt", "file3.txt"}
  19. msg := []byte("Hey y'all")
  20. // Create dir
  21. src, err := ioutil.TempDir("", "docker-hardlink-test-src-")
  22. if err != nil {
  23. t.Fatal(err)
  24. }
  25. defer os.RemoveAll(src)
  26. for _, name := range names {
  27. func() {
  28. fh, err := os.Create(path.Join(src, name))
  29. if err != nil {
  30. t.Fatal(err)
  31. }
  32. defer fh.Close()
  33. if _, err = fh.Write(msg); err != nil {
  34. t.Fatal(err)
  35. }
  36. }()
  37. }
  38. // Create dest, with changes that includes hardlinks
  39. dest, err := ioutil.TempDir("", "docker-hardlink-test-dest-")
  40. if err != nil {
  41. t.Fatal(err)
  42. }
  43. os.RemoveAll(dest) // we just want the name, at first
  44. if err := copyDir(src, dest); err != nil {
  45. t.Fatal(err)
  46. }
  47. defer os.RemoveAll(dest)
  48. for _, name := range names {
  49. for i := 0; i < 5; i++ {
  50. if err := os.Link(path.Join(dest, name), path.Join(dest, fmt.Sprintf("%s.link%d", name, i))); err != nil {
  51. t.Fatal(err)
  52. }
  53. }
  54. }
  55. // get changes
  56. changes, err := ChangesDirs(dest, src)
  57. if err != nil {
  58. t.Fatal(err)
  59. }
  60. // sort
  61. sort.Sort(changesByPath(changes))
  62. // ExportChanges
  63. ar, err := ExportChanges(dest, changes, nil, nil)
  64. if err != nil {
  65. t.Fatal(err)
  66. }
  67. hdrs, err := walkHeaders(ar)
  68. if err != nil {
  69. t.Fatal(err)
  70. }
  71. // reverse sort
  72. sort.Sort(sort.Reverse(changesByPath(changes)))
  73. // ExportChanges
  74. arRev, err := ExportChanges(dest, changes, nil, nil)
  75. if err != nil {
  76. t.Fatal(err)
  77. }
  78. hdrsRev, err := walkHeaders(arRev)
  79. if err != nil {
  80. t.Fatal(err)
  81. }
  82. // line up the two sets
  83. sort.Sort(tarHeaders(hdrs))
  84. sort.Sort(tarHeaders(hdrsRev))
  85. // compare Size and LinkName
  86. for i := range hdrs {
  87. if hdrs[i].Name != hdrsRev[i].Name {
  88. t.Errorf("headers - expected name %q; but got %q", hdrs[i].Name, hdrsRev[i].Name)
  89. }
  90. if hdrs[i].Size != hdrsRev[i].Size {
  91. t.Errorf("headers - %q expected size %d; but got %d", hdrs[i].Name, hdrs[i].Size, hdrsRev[i].Size)
  92. }
  93. if hdrs[i].Typeflag != hdrsRev[i].Typeflag {
  94. t.Errorf("headers - %q expected type %d; but got %d", hdrs[i].Name, hdrs[i].Typeflag, hdrsRev[i].Typeflag)
  95. }
  96. if hdrs[i].Linkname != hdrsRev[i].Linkname {
  97. t.Errorf("headers - %q expected linkname %q; but got %q", hdrs[i].Name, hdrs[i].Linkname, hdrsRev[i].Linkname)
  98. }
  99. }
  100. }
  101. type tarHeaders []tar.Header
  102. func (th tarHeaders) Len() int { return len(th) }
  103. func (th tarHeaders) Swap(i, j int) { th[j], th[i] = th[i], th[j] }
  104. func (th tarHeaders) Less(i, j int) bool { return th[i].Name < th[j].Name }
  105. func walkHeaders(r io.Reader) ([]tar.Header, error) {
  106. t := tar.NewReader(r)
  107. headers := []tar.Header{}
  108. for {
  109. hdr, err := t.Next()
  110. if err != nil {
  111. if err == io.EOF {
  112. break
  113. }
  114. return headers, err
  115. }
  116. headers = append(headers, *hdr)
  117. }
  118. return headers, nil
  119. }