github.com/olljanat/moby@v1.13.1/pkg/tarsum/tarsum_test.go (about)

     1  package tarsum
     2  
     3  import (
     4  	"archive/tar"
     5  	"bytes"
     6  	"compress/gzip"
     7  	"crypto/md5"
     8  	"crypto/rand"
     9  	"crypto/sha1"
    10  	"crypto/sha256"
    11  	"crypto/sha512"
    12  	"encoding/hex"
    13  	"fmt"
    14  	"io"
    15  	"io/ioutil"
    16  	"os"
    17  	"strings"
    18  	"testing"
    19  )
    20  
    21  type testLayer struct {
    22  	filename string
    23  	options  *sizedOptions
    24  	jsonfile string
    25  	gzip     bool
    26  	tarsum   string
    27  	version  Version
    28  	hash     THash
    29  }
    30  
    31  var testLayers = []testLayer{
    32  	{
    33  		filename: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar",
    34  		jsonfile: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/json",
    35  		version:  Version0,
    36  		tarsum:   "tarsum+sha256:4095cc12fa5fdb1ab2760377e1cd0c4ecdd3e61b4f9b82319d96fcea6c9a41c6"},
    37  	{
    38  		filename: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar",
    39  		jsonfile: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/json",
    40  		version:  VersionDev,
    41  		tarsum:   "tarsum.dev+sha256:db56e35eec6ce65ba1588c20ba6b1ea23743b59e81fb6b7f358ccbde5580345c"},
    42  	{
    43  		filename: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar",
    44  		jsonfile: "testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/json",
    45  		gzip:     true,
    46  		tarsum:   "tarsum+sha256:4095cc12fa5fdb1ab2760377e1cd0c4ecdd3e61b4f9b82319d96fcea6c9a41c6"},
    47  	{
    48  		// Tests existing version of TarSum when xattrs are present
    49  		filename: "testdata/xattr/layer.tar",
    50  		jsonfile: "testdata/xattr/json",
    51  		version:  Version0,
    52  		tarsum:   "tarsum+sha256:07e304a8dbcb215b37649fde1a699f8aeea47e60815707f1cdf4d55d25ff6ab4"},
    53  	{
    54  		// Tests next version of TarSum when xattrs are present
    55  		filename: "testdata/xattr/layer.tar",
    56  		jsonfile: "testdata/xattr/json",
    57  		version:  VersionDev,
    58  		tarsum:   "tarsum.dev+sha256:6c58917892d77b3b357b0f9ad1e28e1f4ae4de3a8006bd3beb8beda214d8fd16"},
    59  	{
    60  		filename: "testdata/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/layer.tar",
    61  		jsonfile: "testdata/511136ea3c5a64f264b78b5433614aec563103b4d4702f3ba7d4d2698e22c158/json",
    62  		tarsum:   "tarsum+sha256:c66bd5ec9f87b8f4c6135ca37684618f486a3dd1d113b138d0a177bfa39c2571"},
    63  	{
    64  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
    65  		tarsum:  "tarsum+sha256:8bf12d7e67c51ee2e8306cba569398b1b9f419969521a12ffb9d8875e8836738"},
    66  	{
    67  		// this tar has two files with the same path
    68  		filename: "testdata/collision/collision-0.tar",
    69  		tarsum:   "tarsum+sha256:08653904a68d3ab5c59e65ef58c49c1581caa3c34744f8d354b3f575ea04424a"},
    70  	{
    71  		// this tar has the same two files (with the same path), but reversed order. ensuring is has different hash than above
    72  		filename: "testdata/collision/collision-1.tar",
    73  		tarsum:   "tarsum+sha256:b51c13fbefe158b5ce420d2b930eef54c5cd55c50a2ee4abdddea8fa9f081e0d"},
    74  	{
    75  		// this tar has newer of collider-0.tar, ensuring is has different hash
    76  		filename: "testdata/collision/collision-2.tar",
    77  		tarsum:   "tarsum+sha256:381547080919bb82691e995508ae20ed33ce0f6948d41cafbeb70ce20c73ee8e"},
    78  	{
    79  		// this tar has newer of collider-1.tar, ensuring is has different hash
    80  		filename: "testdata/collision/collision-3.tar",
    81  		tarsum:   "tarsum+sha256:f886e431c08143164a676805205979cd8fa535dfcef714db5515650eea5a7c0f"},
    82  	{
    83  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
    84  		tarsum:  "tarsum+md5:0d7529ec7a8360155b48134b8e599f53",
    85  		hash:    md5THash,
    86  	},
    87  	{
    88  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
    89  		tarsum:  "tarsum+sha1:f1fee39c5925807ff75ef1925e7a23be444ba4df",
    90  		hash:    sha1Hash,
    91  	},
    92  	{
    93  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
    94  		tarsum:  "tarsum+sha224:6319390c0b061d639085d8748b14cd55f697cf9313805218b21cf61c",
    95  		hash:    sha224Hash,
    96  	},
    97  	{
    98  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
    99  		tarsum:  "tarsum+sha384:a578ce3ce29a2ae03b8ed7c26f47d0f75b4fc849557c62454be4b5ffd66ba021e713b48ce71e947b43aab57afd5a7636",
   100  		hash:    sha384Hash,
   101  	},
   102  	{
   103  		options: &sizedOptions{1, 1024 * 1024, false, false}, // a 1mb file (in memory)
   104  		tarsum:  "tarsum+sha512:e9bfb90ca5a4dfc93c46ee061a5cf9837de6d2fdf82544d6460d3147290aecfabf7b5e415b9b6e72db9b8941f149d5d69fb17a394cbfaf2eac523bd9eae21855",
   105  		hash:    sha512Hash,
   106  	},
   107  }
   108  
   109  type sizedOptions struct {
   110  	num      int64
   111  	size     int64
   112  	isRand   bool
   113  	realFile bool
   114  }
   115  
   116  // make a tar:
   117  // * num is the number of files the tar should have
   118  // * size is the bytes per file
   119  // * isRand is whether the contents of the files should be a random chunk (otherwise it's all zeros)
   120  // * realFile will write to a TempFile, instead of an in memory buffer
   121  func sizedTar(opts sizedOptions) io.Reader {
   122  	var (
   123  		fh  io.ReadWriter
   124  		err error
   125  	)
   126  	if opts.realFile {
   127  		fh, err = ioutil.TempFile("", "tarsum")
   128  		if err != nil {
   129  			return nil
   130  		}
   131  	} else {
   132  		fh = bytes.NewBuffer([]byte{})
   133  	}
   134  	tarW := tar.NewWriter(fh)
   135  	defer tarW.Close()
   136  	for i := int64(0); i < opts.num; i++ {
   137  		err := tarW.WriteHeader(&tar.Header{
   138  			Name: fmt.Sprintf("/testdata%d", i),
   139  			Mode: 0755,
   140  			Uid:  0,
   141  			Gid:  0,
   142  			Size: opts.size,
   143  		})
   144  		if err != nil {
   145  			return nil
   146  		}
   147  		var rBuf []byte
   148  		if opts.isRand {
   149  			rBuf = make([]byte, 8)
   150  			_, err = rand.Read(rBuf)
   151  			if err != nil {
   152  				return nil
   153  			}
   154  		} else {
   155  			rBuf = []byte{0, 0, 0, 0, 0, 0, 0, 0}
   156  		}
   157  
   158  		for i := int64(0); i < opts.size/int64(8); i++ {
   159  			tarW.Write(rBuf)
   160  		}
   161  	}
   162  	return fh
   163  }
   164  
   165  func emptyTarSum(gzip bool) (TarSum, error) {
   166  	reader, writer := io.Pipe()
   167  	tarWriter := tar.NewWriter(writer)
   168  
   169  	// Immediately close tarWriter and write-end of the
   170  	// Pipe in a separate goroutine so we don't block.
   171  	go func() {
   172  		tarWriter.Close()
   173  		writer.Close()
   174  	}()
   175  
   176  	return NewTarSum(reader, !gzip, Version0)
   177  }
   178  
   179  // Test errors on NewTarsumForLabel
   180  func TestNewTarSumForLabelInvalid(t *testing.T) {
   181  	reader := strings.NewReader("")
   182  
   183  	if _, err := NewTarSumForLabel(reader, true, "invalidlabel"); err == nil {
   184  		t.Fatalf("Expected an error, got nothing.")
   185  	}
   186  
   187  	if _, err := NewTarSumForLabel(reader, true, "invalid+sha256"); err == nil {
   188  		t.Fatalf("Expected an error, got nothing.")
   189  	}
   190  	if _, err := NewTarSumForLabel(reader, true, "tarsum.v1+invalid"); err == nil {
   191  		t.Fatalf("Expected an error, got nothing.")
   192  	}
   193  }
   194  
   195  func TestNewTarSumForLabel(t *testing.T) {
   196  
   197  	layer := testLayers[0]
   198  
   199  	reader, err := os.Open(layer.filename)
   200  	if err != nil {
   201  		t.Fatal(err)
   202  	}
   203  	defer reader.Close()
   204  
   205  	label := strings.Split(layer.tarsum, ":")[0]
   206  	ts, err := NewTarSumForLabel(reader, false, label)
   207  	if err != nil {
   208  		t.Fatal(err)
   209  	}
   210  
   211  	// Make sure it actually worked by reading a little bit of it
   212  	nbByteToRead := 8 * 1024
   213  	dBuf := make([]byte, nbByteToRead)
   214  	_, err = ts.Read(dBuf)
   215  	if err != nil {
   216  		t.Errorf("failed to read %vKB from %s: %s", nbByteToRead, layer.filename, err)
   217  	}
   218  }
   219  
   220  // TestEmptyTar tests that tarsum does not fail to read an empty tar
   221  // and correctly returns the hex digest of an empty hash.
   222  func TestEmptyTar(t *testing.T) {
   223  	// Test without gzip.
   224  	ts, err := emptyTarSum(false)
   225  	if err != nil {
   226  		t.Fatal(err)
   227  	}
   228  
   229  	zeroBlock := make([]byte, 1024)
   230  	buf := new(bytes.Buffer)
   231  
   232  	n, err := io.Copy(buf, ts)
   233  	if err != nil {
   234  		t.Fatal(err)
   235  	}
   236  
   237  	if n != int64(len(zeroBlock)) || !bytes.Equal(buf.Bytes(), zeroBlock) {
   238  		t.Fatalf("tarSum did not write the correct number of zeroed bytes: %d", n)
   239  	}
   240  
   241  	expectedSum := ts.Version().String() + "+sha256:" + hex.EncodeToString(sha256.New().Sum(nil))
   242  	resultSum := ts.Sum(nil)
   243  
   244  	if resultSum != expectedSum {
   245  		t.Fatalf("expected [%s] but got [%s]", expectedSum, resultSum)
   246  	}
   247  
   248  	// Test with gzip.
   249  	ts, err = emptyTarSum(true)
   250  	if err != nil {
   251  		t.Fatal(err)
   252  	}
   253  	buf.Reset()
   254  
   255  	n, err = io.Copy(buf, ts)
   256  	if err != nil {
   257  		t.Fatal(err)
   258  	}
   259  
   260  	bufgz := new(bytes.Buffer)
   261  	gz := gzip.NewWriter(bufgz)
   262  	n, err = io.Copy(gz, bytes.NewBuffer(zeroBlock))
   263  	gz.Close()
   264  	gzBytes := bufgz.Bytes()
   265  
   266  	if n != int64(len(zeroBlock)) || !bytes.Equal(buf.Bytes(), gzBytes) {
   267  		t.Fatalf("tarSum did not write the correct number of gzipped-zeroed bytes: %d", n)
   268  	}
   269  
   270  	resultSum = ts.Sum(nil)
   271  
   272  	if resultSum != expectedSum {
   273  		t.Fatalf("expected [%s] but got [%s]", expectedSum, resultSum)
   274  	}
   275  
   276  	// Test without ever actually writing anything.
   277  	if ts, err = NewTarSum(bytes.NewReader([]byte{}), true, Version0); err != nil {
   278  		t.Fatal(err)
   279  	}
   280  
   281  	resultSum = ts.Sum(nil)
   282  
   283  	if resultSum != expectedSum {
   284  		t.Fatalf("expected [%s] but got [%s]", expectedSum, resultSum)
   285  	}
   286  }
   287  
   288  var (
   289  	md5THash   = NewTHash("md5", md5.New)
   290  	sha1Hash   = NewTHash("sha1", sha1.New)
   291  	sha224Hash = NewTHash("sha224", sha256.New224)
   292  	sha384Hash = NewTHash("sha384", sha512.New384)
   293  	sha512Hash = NewTHash("sha512", sha512.New)
   294  )
   295  
   296  // Test all the build-in read size : buf8K, buf16K, buf32K and more
   297  func TestTarSumsReadSize(t *testing.T) {
   298  	// Test always on the same layer (that is big enough)
   299  	layer := testLayers[0]
   300  
   301  	for i := 0; i < 5; i++ {
   302  
   303  		reader, err := os.Open(layer.filename)
   304  		if err != nil {
   305  			t.Fatal(err)
   306  		}
   307  		defer reader.Close()
   308  
   309  		ts, err := NewTarSum(reader, false, layer.version)
   310  		if err != nil {
   311  			t.Fatal(err)
   312  		}
   313  
   314  		// Read and discard bytes so that it populates sums
   315  		nbByteToRead := (i + 1) * 8 * 1024
   316  		dBuf := make([]byte, nbByteToRead)
   317  		_, err = ts.Read(dBuf)
   318  		if err != nil {
   319  			t.Errorf("failed to read %vKB from %s: %s", nbByteToRead, layer.filename, err)
   320  			continue
   321  		}
   322  	}
   323  }
   324  
   325  func TestTarSums(t *testing.T) {
   326  	for _, layer := range testLayers {
   327  		var (
   328  			fh  io.Reader
   329  			err error
   330  		)
   331  		if len(layer.filename) > 0 {
   332  			fh, err = os.Open(layer.filename)
   333  			if err != nil {
   334  				t.Errorf("failed to open %s: %s", layer.filename, err)
   335  				continue
   336  			}
   337  		} else if layer.options != nil {
   338  			fh = sizedTar(*layer.options)
   339  		} else {
   340  			// What else is there to test?
   341  			t.Errorf("what to do with %#v", layer)
   342  			continue
   343  		}
   344  		if file, ok := fh.(*os.File); ok {
   345  			defer file.Close()
   346  		}
   347  
   348  		var ts TarSum
   349  		if layer.hash == nil {
   350  			//                           double negatives!
   351  			ts, err = NewTarSum(fh, !layer.gzip, layer.version)
   352  		} else {
   353  			ts, err = NewTarSumHash(fh, !layer.gzip, layer.version, layer.hash)
   354  		}
   355  		if err != nil {
   356  			t.Errorf("%q :: %q", err, layer.filename)
   357  			continue
   358  		}
   359  
   360  		// Read variable number of bytes to test dynamic buffer
   361  		dBuf := make([]byte, 1)
   362  		_, err = ts.Read(dBuf)
   363  		if err != nil {
   364  			t.Errorf("failed to read 1B from %s: %s", layer.filename, err)
   365  			continue
   366  		}
   367  		dBuf = make([]byte, 16*1024)
   368  		_, err = ts.Read(dBuf)
   369  		if err != nil {
   370  			t.Errorf("failed to read 16KB from %s: %s", layer.filename, err)
   371  			continue
   372  		}
   373  
   374  		// Read and discard remaining bytes
   375  		_, err = io.Copy(ioutil.Discard, ts)
   376  		if err != nil {
   377  			t.Errorf("failed to copy from %s: %s", layer.filename, err)
   378  			continue
   379  		}
   380  		var gotSum string
   381  		if len(layer.jsonfile) > 0 {
   382  			jfh, err := os.Open(layer.jsonfile)
   383  			if err != nil {
   384  				t.Errorf("failed to open %s: %s", layer.jsonfile, err)
   385  				continue
   386  			}
   387  			defer jfh.Close()
   388  
   389  			buf, err := ioutil.ReadAll(jfh)
   390  			if err != nil {
   391  				t.Errorf("failed to readAll %s: %s", layer.jsonfile, err)
   392  				continue
   393  			}
   394  			gotSum = ts.Sum(buf)
   395  		} else {
   396  			gotSum = ts.Sum(nil)
   397  		}
   398  
   399  		if layer.tarsum != gotSum {
   400  			t.Errorf("expecting [%s], but got [%s]", layer.tarsum, gotSum)
   401  		}
   402  		var expectedHashName string
   403  		if layer.hash != nil {
   404  			expectedHashName = layer.hash.Name()
   405  		} else {
   406  			expectedHashName = DefaultTHash.Name()
   407  		}
   408  		if expectedHashName != ts.Hash().Name() {
   409  			t.Errorf("expecting hash [%v], but got [%s]", expectedHashName, ts.Hash().Name())
   410  		}
   411  	}
   412  }
   413  
   414  func TestIteration(t *testing.T) {
   415  	headerTests := []struct {
   416  		expectedSum string // TODO(vbatts) it would be nice to get individual sums of each
   417  		version     Version
   418  		hdr         *tar.Header
   419  		data        []byte
   420  	}{
   421  		{
   422  			"tarsum+sha256:626c4a2e9a467d65c33ae81f7f3dedd4de8ccaee72af73223c4bc4718cbc7bbd",
   423  			Version0,
   424  			&tar.Header{
   425  				Name:     "file.txt",
   426  				Size:     0,
   427  				Typeflag: tar.TypeReg,
   428  				Devminor: 0,
   429  				Devmajor: 0,
   430  			},
   431  			[]byte(""),
   432  		},
   433  		{
   434  			"tarsum.dev+sha256:6ffd43a1573a9913325b4918e124ee982a99c0f3cba90fc032a65f5e20bdd465",
   435  			VersionDev,
   436  			&tar.Header{
   437  				Name:     "file.txt",
   438  				Size:     0,
   439  				Typeflag: tar.TypeReg,
   440  				Devminor: 0,
   441  				Devmajor: 0,
   442  			},
   443  			[]byte(""),
   444  		},
   445  		{
   446  			"tarsum.dev+sha256:b38166c059e11fb77bef30bf16fba7584446e80fcc156ff46d47e36c5305d8ef",
   447  			VersionDev,
   448  			&tar.Header{
   449  				Name:     "another.txt",
   450  				Uid:      1000,
   451  				Gid:      1000,
   452  				Uname:    "slartibartfast",
   453  				Gname:    "users",
   454  				Size:     4,
   455  				Typeflag: tar.TypeReg,
   456  				Devminor: 0,
   457  				Devmajor: 0,
   458  			},
   459  			[]byte("test"),
   460  		},
   461  		{
   462  			"tarsum.dev+sha256:4cc2e71ac5d31833ab2be9b4f7842a14ce595ec96a37af4ed08f87bc374228cd",
   463  			VersionDev,
   464  			&tar.Header{
   465  				Name:     "xattrs.txt",
   466  				Uid:      1000,
   467  				Gid:      1000,
   468  				Uname:    "slartibartfast",
   469  				Gname:    "users",
   470  				Size:     4,
   471  				Typeflag: tar.TypeReg,
   472  				Xattrs: map[string]string{
   473  					"user.key1": "value1",
   474  					"user.key2": "value2",
   475  				},
   476  			},
   477  			[]byte("test"),
   478  		},
   479  		{
   480  			"tarsum.dev+sha256:65f4284fa32c0d4112dd93c3637697805866415b570587e4fd266af241503760",
   481  			VersionDev,
   482  			&tar.Header{
   483  				Name:     "xattrs.txt",
   484  				Uid:      1000,
   485  				Gid:      1000,
   486  				Uname:    "slartibartfast",
   487  				Gname:    "users",
   488  				Size:     4,
   489  				Typeflag: tar.TypeReg,
   490  				Xattrs: map[string]string{
   491  					"user.KEY1": "value1", // adding different case to ensure different sum
   492  					"user.key2": "value2",
   493  				},
   494  			},
   495  			[]byte("test"),
   496  		},
   497  		{
   498  			"tarsum+sha256:c12bb6f1303a9ddbf4576c52da74973c00d14c109bcfa76b708d5da1154a07fa",
   499  			Version0,
   500  			&tar.Header{
   501  				Name:     "xattrs.txt",
   502  				Uid:      1000,
   503  				Gid:      1000,
   504  				Uname:    "slartibartfast",
   505  				Gname:    "users",
   506  				Size:     4,
   507  				Typeflag: tar.TypeReg,
   508  				Xattrs: map[string]string{
   509  					"user.NOT": "CALCULATED",
   510  				},
   511  			},
   512  			[]byte("test"),
   513  		},
   514  	}
   515  	for _, htest := range headerTests {
   516  		s, err := renderSumForHeader(htest.version, htest.hdr, htest.data)
   517  		if err != nil {
   518  			t.Fatal(err)
   519  		}
   520  
   521  		if s != htest.expectedSum {
   522  			t.Errorf("expected sum: %q, got: %q", htest.expectedSum, s)
   523  		}
   524  	}
   525  
   526  }
   527  
   528  func renderSumForHeader(v Version, h *tar.Header, data []byte) (string, error) {
   529  	buf := bytes.NewBuffer(nil)
   530  	// first build our test tar
   531  	tw := tar.NewWriter(buf)
   532  	if err := tw.WriteHeader(h); err != nil {
   533  		return "", err
   534  	}
   535  	if _, err := tw.Write(data); err != nil {
   536  		return "", err
   537  	}
   538  	tw.Close()
   539  
   540  	ts, err := NewTarSum(buf, true, v)
   541  	if err != nil {
   542  		return "", err
   543  	}
   544  	tr := tar.NewReader(ts)
   545  	for {
   546  		hdr, err := tr.Next()
   547  		if hdr == nil || err == io.EOF {
   548  			// Signals the end of the archive.
   549  			break
   550  		}
   551  		if err != nil {
   552  			return "", err
   553  		}
   554  		if _, err = io.Copy(ioutil.Discard, tr); err != nil {
   555  			return "", err
   556  		}
   557  	}
   558  	return ts.Sum(nil), nil
   559  }
   560  
   561  func Benchmark9kTar(b *testing.B) {
   562  	buf := bytes.NewBuffer([]byte{})
   563  	fh, err := os.Open("testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar")
   564  	if err != nil {
   565  		b.Error(err)
   566  		return
   567  	}
   568  	defer fh.Close()
   569  
   570  	n, err := io.Copy(buf, fh)
   571  	if err != nil {
   572  		b.Error(err)
   573  		return
   574  	}
   575  
   576  	reader := bytes.NewReader(buf.Bytes())
   577  
   578  	b.SetBytes(n)
   579  	b.ResetTimer()
   580  	for i := 0; i < b.N; i++ {
   581  		reader.Seek(0, 0)
   582  		ts, err := NewTarSum(reader, true, Version0)
   583  		if err != nil {
   584  			b.Error(err)
   585  			return
   586  		}
   587  		io.Copy(ioutil.Discard, ts)
   588  		ts.Sum(nil)
   589  	}
   590  }
   591  
   592  func Benchmark9kTarGzip(b *testing.B) {
   593  	buf := bytes.NewBuffer([]byte{})
   594  	fh, err := os.Open("testdata/46af0962ab5afeb5ce6740d4d91652e69206fc991fd5328c1a94d364ad00e457/layer.tar")
   595  	if err != nil {
   596  		b.Error(err)
   597  		return
   598  	}
   599  	defer fh.Close()
   600  
   601  	n, err := io.Copy(buf, fh)
   602  	if err != nil {
   603  		b.Error(err)
   604  		return
   605  	}
   606  
   607  	reader := bytes.NewReader(buf.Bytes())
   608  
   609  	b.SetBytes(n)
   610  	b.ResetTimer()
   611  	for i := 0; i < b.N; i++ {
   612  		reader.Seek(0, 0)
   613  		ts, err := NewTarSum(reader, false, Version0)
   614  		if err != nil {
   615  			b.Error(err)
   616  			return
   617  		}
   618  		io.Copy(ioutil.Discard, ts)
   619  		ts.Sum(nil)
   620  	}
   621  }
   622  
   623  // this is a single big file in the tar archive
   624  func Benchmark1mbSingleFileTar(b *testing.B) {
   625  	benchmarkTar(b, sizedOptions{1, 1024 * 1024, true, true}, false)
   626  }
   627  
   628  // this is a single big file in the tar archive
   629  func Benchmark1mbSingleFileTarGzip(b *testing.B) {
   630  	benchmarkTar(b, sizedOptions{1, 1024 * 1024, true, true}, true)
   631  }
   632  
   633  // this is 1024 1k files in the tar archive
   634  func Benchmark1kFilesTar(b *testing.B) {
   635  	benchmarkTar(b, sizedOptions{1024, 1024, true, true}, false)
   636  }
   637  
   638  // this is 1024 1k files in the tar archive
   639  func Benchmark1kFilesTarGzip(b *testing.B) {
   640  	benchmarkTar(b, sizedOptions{1024, 1024, true, true}, true)
   641  }
   642  
   643  func benchmarkTar(b *testing.B, opts sizedOptions, isGzip bool) {
   644  	var fh *os.File
   645  	tarReader := sizedTar(opts)
   646  	if br, ok := tarReader.(*os.File); ok {
   647  		fh = br
   648  	}
   649  	defer os.Remove(fh.Name())
   650  	defer fh.Close()
   651  
   652  	b.SetBytes(opts.size * opts.num)
   653  	b.ResetTimer()
   654  	for i := 0; i < b.N; i++ {
   655  		ts, err := NewTarSum(fh, !isGzip, Version0)
   656  		if err != nil {
   657  			b.Error(err)
   658  			return
   659  		}
   660  		io.Copy(ioutil.Discard, ts)
   661  		ts.Sum(nil)
   662  		fh.Seek(0, 0)
   663  	}
   664  }