github.com/miqui/docker@v1.9.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  	"sort"
    11  	"testing"
    12  )
    13  
    14  func TestHardLinkOrder(t *testing.T) {
    15  	names := []string{"file1.txt", "file2.txt", "file3.txt"}
    16  	msg := []byte("Hey y'all")
    17  
    18  	// Create dir
    19  	src, err := ioutil.TempDir("", "docker-hardlink-test-src-")
    20  	if err != nil {
    21  		t.Fatal(err)
    22  	}
    23  	//defer os.RemoveAll(src)
    24  	for _, name := range names {
    25  		func() {
    26  			fh, err := os.Create(path.Join(src, name))
    27  			if err != nil {
    28  				t.Fatal(err)
    29  			}
    30  			defer fh.Close()
    31  			if _, err = fh.Write(msg); err != nil {
    32  				t.Fatal(err)
    33  			}
    34  		}()
    35  	}
    36  	// Create dest, with changes that includes hardlinks
    37  	dest, err := ioutil.TempDir("", "docker-hardlink-test-dest-")
    38  	if err != nil {
    39  		t.Fatal(err)
    40  	}
    41  	os.RemoveAll(dest) // we just want the name, at first
    42  	if err := copyDir(src, dest); err != nil {
    43  		t.Fatal(err)
    44  	}
    45  	defer os.RemoveAll(dest)
    46  	for _, name := range names {
    47  		for i := 0; i < 5; i++ {
    48  			if err := os.Link(path.Join(dest, name), path.Join(dest, fmt.Sprintf("%s.link%d", name, i))); err != nil {
    49  				t.Fatal(err)
    50  			}
    51  		}
    52  	}
    53  
    54  	// get changes
    55  	changes, err := ChangesDirs(dest, src)
    56  	if err != nil {
    57  		t.Fatal(err)
    58  	}
    59  
    60  	// sort
    61  	sort.Sort(changesByPath(changes))
    62  
    63  	// ExportChanges
    64  	ar, err := ExportChanges(dest, changes, nil, nil)
    65  	if err != nil {
    66  		t.Fatal(err)
    67  	}
    68  	hdrs, err := walkHeaders(ar)
    69  	if err != nil {
    70  		t.Fatal(err)
    71  	}
    72  
    73  	// reverse sort
    74  	sort.Sort(sort.Reverse(changesByPath(changes)))
    75  	// ExportChanges
    76  	arRev, err := ExportChanges(dest, changes, nil, nil)
    77  	if err != nil {
    78  		t.Fatal(err)
    79  	}
    80  	hdrsRev, err := walkHeaders(arRev)
    81  	if err != nil {
    82  		t.Fatal(err)
    83  	}
    84  
    85  	// line up the two sets
    86  	sort.Sort(tarHeaders(hdrs))
    87  	sort.Sort(tarHeaders(hdrsRev))
    88  
    89  	// compare Size and LinkName
    90  	for i := range hdrs {
    91  		if hdrs[i].Name != hdrsRev[i].Name {
    92  			t.Errorf("headers - expected name %q; but got %q", hdrs[i].Name, hdrsRev[i].Name)
    93  		}
    94  		if hdrs[i].Size != hdrsRev[i].Size {
    95  			t.Errorf("headers - %q expected size %d; but got %d", hdrs[i].Name, hdrs[i].Size, hdrsRev[i].Size)
    96  		}
    97  		if hdrs[i].Typeflag != hdrsRev[i].Typeflag {
    98  			t.Errorf("headers - %q expected type %d; but got %d", hdrs[i].Name, hdrs[i].Typeflag, hdrsRev[i].Typeflag)
    99  		}
   100  		if hdrs[i].Linkname != hdrsRev[i].Linkname {
   101  			t.Errorf("headers - %q expected linkname %q; but got %q", hdrs[i].Name, hdrs[i].Linkname, hdrsRev[i].Linkname)
   102  		}
   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  	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  }