github.com/moby/docker@v26.1.3+incompatible/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 err := os.WriteFile(path.Join(src, name), msg, 0666) 28 if err != nil { 29 t.Fatal(err) 30 } 31 }() 32 } 33 // Create dest, with changes that includes hardlinks 34 dest, err := os.MkdirTemp("", "docker-hardlink-test-dest-") 35 if err != nil { 36 t.Fatal(err) 37 } 38 os.RemoveAll(dest) // we just want the name, at first 39 if err := copyDir(src, dest); err != nil { 40 t.Fatal(err) 41 } 42 defer os.RemoveAll(dest) 43 for _, name := range names { 44 for i := 0; i < 5; i++ { 45 if err := os.Link(path.Join(dest, name), path.Join(dest, fmt.Sprintf("%s.link%d", name, i))); err != nil { 46 t.Fatal(err) 47 } 48 } 49 } 50 51 // get changes 52 changes, err := ChangesDirs(dest, src) 53 if err != nil { 54 t.Fatal(err) 55 } 56 57 // sort 58 sort.Sort(changesByPath(changes)) 59 60 // ExportChanges 61 ar, err := ExportChanges(dest, changes, idtools.IdentityMapping{}) 62 if err != nil { 63 t.Fatal(err) 64 } 65 hdrs, err := walkHeaders(ar) 66 if err != nil { 67 t.Fatal(err) 68 } 69 70 // reverse sort 71 sort.Sort(sort.Reverse(changesByPath(changes))) 72 // ExportChanges 73 arRev, err := ExportChanges(dest, changes, idtools.IdentityMapping{}) 74 if err != nil { 75 t.Fatal(err) 76 } 77 hdrsRev, err := walkHeaders(arRev) 78 if err != nil { 79 t.Fatal(err) 80 } 81 82 // line up the two sets 83 sort.Sort(tarHeaders(hdrs)) 84 sort.Sort(tarHeaders(hdrsRev)) 85 86 // compare Size and LinkName 87 for i := range hdrs { 88 if hdrs[i].Name != hdrsRev[i].Name { 89 t.Errorf("headers - expected name %q; but got %q", hdrs[i].Name, hdrsRev[i].Name) 90 } 91 if hdrs[i].Size != hdrsRev[i].Size { 92 t.Errorf("headers - %q expected size %d; but got %d", hdrs[i].Name, hdrs[i].Size, hdrsRev[i].Size) 93 } 94 if hdrs[i].Typeflag != hdrsRev[i].Typeflag { 95 t.Errorf("headers - %q expected type %d; but got %d", hdrs[i].Name, hdrs[i].Typeflag, hdrsRev[i].Typeflag) 96 } 97 if hdrs[i].Linkname != hdrsRev[i].Linkname { 98 t.Errorf("headers - %q expected linkname %q; but got %q", hdrs[i].Name, hdrs[i].Linkname, hdrsRev[i].Linkname) 99 } 100 } 101 } 102 103 type tarHeaders []tar.Header 104 105 func (th tarHeaders) Len() int { return len(th) } 106 func (th tarHeaders) Swap(i, j int) { th[j], th[i] = th[i], th[j] } 107 func (th tarHeaders) Less(i, j int) bool { return th[i].Name < th[j].Name } 108 109 func walkHeaders(r io.Reader) ([]tar.Header, error) { 110 t := tar.NewReader(r) 111 var headers []tar.Header 112 for { 113 hdr, err := t.Next() 114 if err != nil { 115 if err == io.EOF { 116 break 117 } 118 return headers, err 119 } 120 headers = append(headers, *hdr) 121 } 122 return headers, nil 123 }