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  }