splitting_test.go 2.77 KB
Newer Older
1 2 3 4
package chunk

import (
	"bytes"
5
	"io"
6
	"testing"
7

8
	u "github.com/ipfs/go-ipfs-util"
Jakub Sztandera's avatar
Jakub Sztandera committed
9
	util "github.com/ipfs/go-ipfs-util"
10 11 12 13
)

func randBuf(t *testing.T, size int) []byte {
	buf := make([]byte, size)
14
	if _, err := u.NewTimeSeededRand().Read(buf); err != nil {
15 16 17 18 19 20 21 22 23 24 25
		t.Fatal("failed to read enough randomness")
	}
	return buf
}

func copyBuf(buf []byte) []byte {
	cpy := make([]byte, len(buf))
	copy(cpy, buf)
	return cpy
}

26 27 28 29 30 31 32 33 34 35 36 37 38 39
func TestSizeSplitterOverAllocate(t *testing.T) {
	max := 1000
	r := bytes.NewReader(randBuf(t, max))
	chunksize := int64(1024 * 256)
	splitter := NewSizeSplitter(r, chunksize)
	chunk, err := splitter.NextBytes()
	if err != nil {
		t.Fatal(err)
	}
	if cap(chunk) > len(chunk) {
		t.Fatal("chunk capacity too large")
	}
}

40
func TestSizeSplitterIsDeterministic(t *testing.T) {
41 42 43
	if testing.Short() {
		t.SkipNow()
	}
44 45 46 47 48 49

	test := func() {
		bufR := randBuf(t, 10000000) // crank this up to satisfy yourself.
		bufA := copyBuf(bufR)
		bufB := copyBuf(bufR)

50 51
		chunksA, _ := Chan(DefaultSplitter(bytes.NewReader(bufA)))
		chunksB, _ := Chan(DefaultSplitter(bytes.NewReader(bufB)))
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

		for n := 0; ; n++ {
			a, moreA := <-chunksA
			b, moreB := <-chunksB

			if !moreA {
				if moreB {
					t.Fatal("A ended, B didnt.")
				}
				return
			}

			if !bytes.Equal(a, b) {
				t.Fatalf("chunk %d not equal", n)
			}
		}
	}

	for run := 0; run < 1; run++ { // crank this up to satisfy yourself.
		test()
	}
}
74 75 76 77 78 79 80 81 82

func TestSizeSplitterFillsChunks(t *testing.T) {
	if testing.Short() {
		t.SkipNow()
	}

	max := 10000000
	b := randBuf(t, max)
	r := &clipReader{r: bytes.NewReader(b), size: 4000}
83 84
	chunksize := int64(1024 * 256)
	c, _ := Chan(NewSizeSplitter(r, chunksize))
85 86 87 88 89 90 91 92 93 94 95 96 97

	sofar := 0
	whole := make([]byte, max)
	for chunk := range c {

		bc := b[sofar : sofar+len(chunk)]
		if !bytes.Equal(bc, chunk) {
			t.Fatalf("chunk not correct: (sofar: %d) %d != %d, %v != %v", sofar, len(bc), len(chunk), bc[:100], chunk[:100])
		}

		copy(whole[sofar:], chunk)

		sofar += len(chunk)
98
		if sofar != max && len(chunk) < int(chunksize) {
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
			t.Fatal("sizesplitter split at a smaller size")
		}
	}

	if !bytes.Equal(b, whole) {
		t.Fatal("splitter did not split right")
	}
}

type clipReader struct {
	size int
	r    io.Reader
}

func (s *clipReader) Read(buf []byte) (int, error) {

	// clip the incoming buffer to produce smaller chunks
	if len(buf) > s.size {
		buf = buf[:s.size]
	}

	return s.r.Read(buf)
}
Jakub Sztandera's avatar
Jakub Sztandera committed
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148

func BenchmarkDefault(b *testing.B) {
	data := make([]byte, 16<<20)
	util.NewTimeSeededRand().Read(data)

	b.SetBytes(16 << 20)
	b.ReportAllocs()
	b.ResetTimer()

	var res uint64

	for i := 0; i < b.N; i++ {
		r := DefaultSplitter(bytes.NewReader(data))

		for {
			chunk, err := r.NextBytes()
			if err != nil {
				if err == io.EOF {
					break
				}
				b.Fatal(err)
			}
			res = res + uint64(len(chunk))
		}
	}
	Res = Res + res
}