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