tarsum_test.go 17 KB

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