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