github.com/spotify/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/src/pkg/archive/tar/reader_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package tar
     6  
     7  import (
     8  	"bytes"
     9  	"crypto/md5"
    10  	"fmt"
    11  	"io"
    12  	"os"
    13  	"reflect"
    14  	"strings"
    15  	"testing"
    16  	"time"
    17  )
    18  
    19  type untarTest struct {
    20  	file    string
    21  	headers []*Header
    22  	cksums  []string
    23  }
    24  
    25  var gnuTarTest = &untarTest{
    26  	file: "testdata/gnu.tar",
    27  	headers: []*Header{
    28  		{
    29  			Name:     "small.txt",
    30  			Mode:     0640,
    31  			Uid:      73025,
    32  			Gid:      5000,
    33  			Size:     5,
    34  			ModTime:  time.Unix(1244428340, 0),
    35  			Typeflag: '0',
    36  			Uname:    "dsymonds",
    37  			Gname:    "eng",
    38  		},
    39  		{
    40  			Name:     "small2.txt",
    41  			Mode:     0640,
    42  			Uid:      73025,
    43  			Gid:      5000,
    44  			Size:     11,
    45  			ModTime:  time.Unix(1244436044, 0),
    46  			Typeflag: '0',
    47  			Uname:    "dsymonds",
    48  			Gname:    "eng",
    49  		},
    50  	},
    51  	cksums: []string{
    52  		"e38b27eaccb4391bdec553a7f3ae6b2f",
    53  		"c65bd2e50a56a2138bf1716f2fd56fe9",
    54  	},
    55  }
    56  
    57  var untarTests = []*untarTest{
    58  	gnuTarTest,
    59  	{
    60  		file: "testdata/star.tar",
    61  		headers: []*Header{
    62  			{
    63  				Name:       "small.txt",
    64  				Mode:       0640,
    65  				Uid:        73025,
    66  				Gid:        5000,
    67  				Size:       5,
    68  				ModTime:    time.Unix(1244592783, 0),
    69  				Typeflag:   '0',
    70  				Uname:      "dsymonds",
    71  				Gname:      "eng",
    72  				AccessTime: time.Unix(1244592783, 0),
    73  				ChangeTime: time.Unix(1244592783, 0),
    74  			},
    75  			{
    76  				Name:       "small2.txt",
    77  				Mode:       0640,
    78  				Uid:        73025,
    79  				Gid:        5000,
    80  				Size:       11,
    81  				ModTime:    time.Unix(1244592783, 0),
    82  				Typeflag:   '0',
    83  				Uname:      "dsymonds",
    84  				Gname:      "eng",
    85  				AccessTime: time.Unix(1244592783, 0),
    86  				ChangeTime: time.Unix(1244592783, 0),
    87  			},
    88  		},
    89  	},
    90  	{
    91  		file: "testdata/v7.tar",
    92  		headers: []*Header{
    93  			{
    94  				Name:     "small.txt",
    95  				Mode:     0444,
    96  				Uid:      73025,
    97  				Gid:      5000,
    98  				Size:     5,
    99  				ModTime:  time.Unix(1244593104, 0),
   100  				Typeflag: '\x00',
   101  			},
   102  			{
   103  				Name:     "small2.txt",
   104  				Mode:     0444,
   105  				Uid:      73025,
   106  				Gid:      5000,
   107  				Size:     11,
   108  				ModTime:  time.Unix(1244593104, 0),
   109  				Typeflag: '\x00',
   110  			},
   111  		},
   112  	},
   113  	{
   114  		file: "testdata/pax.tar",
   115  		headers: []*Header{
   116  			{
   117  				Name:       "a/123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
   118  				Mode:       0664,
   119  				Uid:        1000,
   120  				Gid:        1000,
   121  				Uname:      "shane",
   122  				Gname:      "shane",
   123  				Size:       7,
   124  				ModTime:    time.Unix(1350244992, 23960108),
   125  				ChangeTime: time.Unix(1350244992, 23960108),
   126  				AccessTime: time.Unix(1350244992, 23960108),
   127  				Typeflag:   TypeReg,
   128  			},
   129  			{
   130  				Name:       "a/b",
   131  				Mode:       0777,
   132  				Uid:        1000,
   133  				Gid:        1000,
   134  				Uname:      "shane",
   135  				Gname:      "shane",
   136  				Size:       0,
   137  				ModTime:    time.Unix(1350266320, 910238425),
   138  				ChangeTime: time.Unix(1350266320, 910238425),
   139  				AccessTime: time.Unix(1350266320, 910238425),
   140  				Typeflag:   TypeSymlink,
   141  				Linkname:   "123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100",
   142  			},
   143  		},
   144  	},
   145  	{
   146  		file: "testdata/nil-uid.tar", // golang.org/issue/5290
   147  		headers: []*Header{
   148  			{
   149  				Name:     "P1050238.JPG.log",
   150  				Mode:     0664,
   151  				Uid:      0,
   152  				Gid:      0,
   153  				Size:     14,
   154  				ModTime:  time.Unix(1365454838, 0),
   155  				Typeflag: TypeReg,
   156  				Linkname: "",
   157  				Uname:    "eyefi",
   158  				Gname:    "eyefi",
   159  				Devmajor: 0,
   160  				Devminor: 0,
   161  			},
   162  		},
   163  	},
   164  }
   165  
   166  func TestReader(t *testing.T) {
   167  testLoop:
   168  	for i, test := range untarTests {
   169  		f, err := os.Open(test.file)
   170  		if err != nil {
   171  			t.Errorf("test %d: Unexpected error: %v", i, err)
   172  			continue
   173  		}
   174  		defer f.Close()
   175  		tr := NewReader(f)
   176  		for j, header := range test.headers {
   177  			hdr, err := tr.Next()
   178  			if err != nil || hdr == nil {
   179  				t.Errorf("test %d, entry %d: Didn't get entry: %v", i, j, err)
   180  				f.Close()
   181  				continue testLoop
   182  			}
   183  			if *hdr != *header {
   184  				t.Errorf("test %d, entry %d: Incorrect header:\nhave %+v\nwant %+v",
   185  					i, j, *hdr, *header)
   186  			}
   187  		}
   188  		hdr, err := tr.Next()
   189  		if err == io.EOF {
   190  			continue testLoop
   191  		}
   192  		if hdr != nil || err != nil {
   193  			t.Errorf("test %d: Unexpected entry or error: hdr=%v err=%v", i, hdr, err)
   194  		}
   195  	}
   196  }
   197  
   198  func TestPartialRead(t *testing.T) {
   199  	f, err := os.Open("testdata/gnu.tar")
   200  	if err != nil {
   201  		t.Fatalf("Unexpected error: %v", err)
   202  	}
   203  	defer f.Close()
   204  
   205  	tr := NewReader(f)
   206  
   207  	// Read the first four bytes; Next() should skip the last byte.
   208  	hdr, err := tr.Next()
   209  	if err != nil || hdr == nil {
   210  		t.Fatalf("Didn't get first file: %v", err)
   211  	}
   212  	buf := make([]byte, 4)
   213  	if _, err := io.ReadFull(tr, buf); err != nil {
   214  		t.Fatalf("Unexpected error: %v", err)
   215  	}
   216  	if expected := []byte("Kilt"); !bytes.Equal(buf, expected) {
   217  		t.Errorf("Contents = %v, want %v", buf, expected)
   218  	}
   219  
   220  	// Second file
   221  	hdr, err = tr.Next()
   222  	if err != nil || hdr == nil {
   223  		t.Fatalf("Didn't get second file: %v", err)
   224  	}
   225  	buf = make([]byte, 6)
   226  	if _, err := io.ReadFull(tr, buf); err != nil {
   227  		t.Fatalf("Unexpected error: %v", err)
   228  	}
   229  	if expected := []byte("Google"); !bytes.Equal(buf, expected) {
   230  		t.Errorf("Contents = %v, want %v", buf, expected)
   231  	}
   232  }
   233  
   234  func TestIncrementalRead(t *testing.T) {
   235  	test := gnuTarTest
   236  	f, err := os.Open(test.file)
   237  	if err != nil {
   238  		t.Fatalf("Unexpected error: %v", err)
   239  	}
   240  	defer f.Close()
   241  
   242  	tr := NewReader(f)
   243  
   244  	headers := test.headers
   245  	cksums := test.cksums
   246  	nread := 0
   247  
   248  	// loop over all files
   249  	for ; ; nread++ {
   250  		hdr, err := tr.Next()
   251  		if hdr == nil || err == io.EOF {
   252  			break
   253  		}
   254  
   255  		// check the header
   256  		if *hdr != *headers[nread] {
   257  			t.Errorf("Incorrect header:\nhave %+v\nwant %+v",
   258  				*hdr, headers[nread])
   259  		}
   260  
   261  		// read file contents in little chunks EOF,
   262  		// checksumming all the way
   263  		h := md5.New()
   264  		rdbuf := make([]uint8, 8)
   265  		for {
   266  			nr, err := tr.Read(rdbuf)
   267  			if err == io.EOF {
   268  				break
   269  			}
   270  			if err != nil {
   271  				t.Errorf("Read: unexpected error %v\n", err)
   272  				break
   273  			}
   274  			h.Write(rdbuf[0:nr])
   275  		}
   276  		// verify checksum
   277  		have := fmt.Sprintf("%x", h.Sum(nil))
   278  		want := cksums[nread]
   279  		if want != have {
   280  			t.Errorf("Bad checksum on file %s:\nhave %+v\nwant %+v", hdr.Name, have, want)
   281  		}
   282  	}
   283  	if nread != len(headers) {
   284  		t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(headers), nread)
   285  	}
   286  }
   287  
   288  func TestNonSeekable(t *testing.T) {
   289  	test := gnuTarTest
   290  	f, err := os.Open(test.file)
   291  	if err != nil {
   292  		t.Fatalf("Unexpected error: %v", err)
   293  	}
   294  	defer f.Close()
   295  
   296  	type readerOnly struct {
   297  		io.Reader
   298  	}
   299  	tr := NewReader(readerOnly{f})
   300  	nread := 0
   301  
   302  	for ; ; nread++ {
   303  		_, err := tr.Next()
   304  		if err == io.EOF {
   305  			break
   306  		}
   307  		if err != nil {
   308  			t.Fatalf("Unexpected error: %v", err)
   309  		}
   310  	}
   311  
   312  	if nread != len(test.headers) {
   313  		t.Errorf("Didn't process all files\nexpected: %d\nprocessed %d\n", len(test.headers), nread)
   314  	}
   315  }
   316  
   317  func TestParsePAXHeader(t *testing.T) {
   318  	paxTests := [][3]string{
   319  		{"a", "a=name", "10 a=name\n"}, // Test case involving multiple acceptable lengths
   320  		{"a", "a=name", "9 a=name\n"},  // Test case involving multiple acceptable length
   321  		{"mtime", "mtime=1350244992.023960108", "30 mtime=1350244992.023960108\n"}}
   322  	for _, test := range paxTests {
   323  		key, expected, raw := test[0], test[1], test[2]
   324  		reader := bytes.NewBuffer([]byte(raw))
   325  		headers, err := parsePAX(reader)
   326  		if err != nil {
   327  			t.Errorf("Couldn't parse correctly formatted headers: %v", err)
   328  			continue
   329  		}
   330  		if strings.EqualFold(headers[key], expected) {
   331  			t.Errorf("mtime header incorrectly parsed: got %s, wanted %s", headers[key], expected)
   332  			continue
   333  		}
   334  		trailer := make([]byte, 100)
   335  		n, err := reader.Read(trailer)
   336  		if err != io.EOF || n != 0 {
   337  			t.Error("Buffer wasn't consumed")
   338  		}
   339  	}
   340  	badHeader := bytes.NewBuffer([]byte("3 somelongkey="))
   341  	if _, err := parsePAX(badHeader); err != ErrHeader {
   342  		t.Fatal("Unexpected success when parsing bad header")
   343  	}
   344  }
   345  
   346  func TestParsePAXTime(t *testing.T) {
   347  	// Some valid PAX time values
   348  	timestamps := map[string]time.Time{
   349  		"1350244992.023960108":  time.Unix(1350244992, 23960108), // The commoon case
   350  		"1350244992.02396010":   time.Unix(1350244992, 23960100), // Lower precision value
   351  		"1350244992.0239601089": time.Unix(1350244992, 23960108), // Higher precision value
   352  		"1350244992":            time.Unix(1350244992, 0),        // Low precision value
   353  	}
   354  	for input, expected := range timestamps {
   355  		ts, err := parsePAXTime(input)
   356  		if err != nil {
   357  			t.Fatal(err)
   358  		}
   359  		if !ts.Equal(expected) {
   360  			t.Fatalf("Time parsing failure %s %s", ts, expected)
   361  		}
   362  	}
   363  }
   364  
   365  func TestMergePAX(t *testing.T) {
   366  	hdr := new(Header)
   367  	// Test a string, integer, and time based value.
   368  	headers := map[string]string{
   369  		"path":  "a/b/c",
   370  		"uid":   "1000",
   371  		"mtime": "1350244992.023960108",
   372  	}
   373  	err := mergePAX(hdr, headers)
   374  	if err != nil {
   375  		t.Fatal(err)
   376  	}
   377  	want := &Header{
   378  		Name:    "a/b/c",
   379  		Uid:     1000,
   380  		ModTime: time.Unix(1350244992, 23960108),
   381  	}
   382  	if !reflect.DeepEqual(hdr, want) {
   383  		t.Errorf("incorrect merge: got %+v, want %+v", hdr, want)
   384  	}
   385  }