package snapshots_test import ( "bytes" "errors" "io" "io/ioutil" "testing" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/snapshots" ) func TestChunkWriter(t *testing.T) { ch := make(chan io.ReadCloser, 100) go func() { chunkWriter := snapshots.NewChunkWriter(ch, 2) n, err := chunkWriter.Write([]byte{1, 2, 3}) require.NoError(t, err) assert.Equal(t, 3, n) n, err = chunkWriter.Write([]byte{4, 5, 6}) require.NoError(t, err) assert.Equal(t, 3, n) n, err = chunkWriter.Write([]byte{7, 8, 9}) require.NoError(t, err) assert.Equal(t, 3, n) err = chunkWriter.Close() require.NoError(t, err) // closed writer should error _, err = chunkWriter.Write([]byte{10}) require.Error(t, err) // closing again should be fine err = chunkWriter.Close() require.NoError(t, err) }() assert.Equal(t, [][]byte{{1, 2}, {3, 4}, {5, 6}, {7, 8}, {9}}, readChunks(ch)) // 0-sized chunks should return the whole body as one chunk ch = make(chan io.ReadCloser, 100) go func() { chunkWriter := snapshots.NewChunkWriter(ch, 0) _, err := chunkWriter.Write([]byte{1, 2, 3}) require.NoError(t, err) _, err = chunkWriter.Write([]byte{4, 5, 6}) require.NoError(t, err) err = chunkWriter.Close() require.NoError(t, err) }() assert.Equal(t, [][]byte{{1, 2, 3, 4, 5, 6}}, readChunks(ch)) // closing with error should return the error theErr := errors.New("boom") ch = make(chan io.ReadCloser, 100) go func() { chunkWriter := snapshots.NewChunkWriter(ch, 2) _, err := chunkWriter.Write([]byte{1, 2, 3}) require.NoError(t, err) chunkWriter.CloseWithError(theErr) }() chunk, err := ioutil.ReadAll(<-ch) require.NoError(t, err) assert.Equal(t, []byte{1, 2}, chunk) _, err = ioutil.ReadAll(<-ch) require.Error(t, err) assert.Equal(t, theErr, err) assert.Empty(t, ch) // closing immediately should return no chunks ch = make(chan io.ReadCloser, 100) chunkWriter := snapshots.NewChunkWriter(ch, 2) err = chunkWriter.Close() require.NoError(t, err) assert.Empty(t, ch) } func TestChunkReader(t *testing.T) { ch := makeChunks([][]byte{ {1, 2, 3}, {4}, {}, {5, 6}, }) chunkReader := snapshots.NewChunkReader(ch) buf := []byte{0, 0, 0, 0} n, err := chunkReader.Read(buf) require.NoError(t, err) assert.Equal(t, 3, n) assert.Equal(t, []byte{1, 2, 3, 0}, buf) buf = []byte{0, 0, 0, 0} n, err = chunkReader.Read(buf) require.NoError(t, err) assert.Equal(t, 1, n) assert.Equal(t, []byte{4, 0, 0, 0}, buf) buf = []byte{0, 0, 0, 0} n, err = chunkReader.Read(buf) require.NoError(t, err) assert.Equal(t, 2, n) assert.Equal(t, []byte{5, 6, 0, 0}, buf) buf = []byte{0, 0, 0, 0} _, err = chunkReader.Read(buf) require.Error(t, err) assert.Equal(t, io.EOF, err) err = chunkReader.Close() require.NoError(t, err) err = chunkReader.Close() // closing twice should be fine require.NoError(t, err) // Empty channel should be fine ch = makeChunks(nil) chunkReader = snapshots.NewChunkReader(ch) buf = make([]byte, 4) _, err = chunkReader.Read(buf) require.Error(t, err) assert.Equal(t, io.EOF, err) // Using a pipe that closes with an error should return the error theErr := errors.New("boom") pr, pw := io.Pipe() pch := make(chan io.ReadCloser, 1) pch <- pr pw.CloseWithError(theErr) chunkReader = snapshots.NewChunkReader(pch) buf = make([]byte, 4) _, err = chunkReader.Read(buf) require.Error(t, err) assert.Equal(t, theErr, err) // Closing the reader should close the writer pr, pw = io.Pipe() pch = make(chan io.ReadCloser, 2) pch <- ioutil.NopCloser(bytes.NewBuffer([]byte{1, 2, 3})) pch <- pr close(pch) go func() { chunkReader := snapshots.NewChunkReader(pch) buf := []byte{0, 0, 0, 0} _, err := chunkReader.Read(buf) require.NoError(t, err) assert.Equal(t, []byte{1, 2, 3, 0}, buf) err = chunkReader.Close() require.NoError(t, err) }() _, err = pw.Write([]byte{9, 9, 9}) require.Error(t, err) assert.Equal(t, err, io.ErrClosedPipe) }