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