-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
reimplement bufferedReader on top of bufio.Reader (#180)
* reimplement bufferedReader on top of bufio.Reader This reimplements bufferedReader on top of bufio.Reader. This doens't make the code shorter, but it delegates more complexity to standard library functions. In particular, bufio.Reader: - handles storing errors and passing them out via Read() where appropriate - handles errors where a read would exceed the buffer size Furthermore this commit removes any HTTP concerns from bufferedReader. The downloadBody() function has been changed to a generic ReadFrom(). * test bufferedReader * Ensure bufferedReader doesn't stall bufio.Reader can stall if 100 consecutive Read() calls make no progress. The previous bytes.Buffer implementation used io.Copy which doesn't have this case.
- Loading branch information
1 parent
c72c384
commit 4ebad73
Showing
5 changed files
with
179 additions
and
41 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
package download | ||
|
||
import ( | ||
"bytes" | ||
"io" | ||
"strings" | ||
"sync" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestBufferedReaderSerial(t *testing.T) { | ||
pool := newBufferPool(10) | ||
br := newBufferedReader(pool) | ||
n, err := br.ReadFrom(strings.NewReader("foobar")) | ||
assert.NoError(t, err) | ||
assert.Equal(t, int64(6), n) | ||
br.Done() | ||
buf, err := io.ReadAll(br) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "foobar", string(buf)) | ||
} | ||
|
||
func TestBufferedReaderParallel(t *testing.T) { | ||
pool := newBufferPool(10) | ||
br := newBufferedReader(pool) | ||
wg := new(sync.WaitGroup) | ||
wg.Add(1) | ||
go func() { | ||
defer br.Done() | ||
defer wg.Done() | ||
n, err := br.ReadFrom(strings.NewReader("foobar")) | ||
assert.NoError(t, err) | ||
assert.Equal(t, int64(6), n) | ||
}() | ||
buf, err := io.ReadAll(br) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "foobar", string(buf)) | ||
wg.Wait() | ||
} | ||
|
||
func TestBufferedReaderReadsWholeChunk(t *testing.T) { | ||
chunkSize := int64(1024 * 1024) | ||
pool := newBufferPool(chunkSize) | ||
br := newBufferedReader(pool) | ||
data := bytes.Repeat([]byte("x"), int(chunkSize)) | ||
n64, err := br.ReadFrom(bytes.NewReader(data)) | ||
assert.NoError(t, err) | ||
assert.Equal(t, chunkSize, n64) | ||
br.Done() | ||
buf := make([]byte, chunkSize) | ||
// We should only require a single Read() call because all the data should | ||
// be buffered | ||
n, err := br.Read(buf) | ||
assert.NoError(t, err) | ||
assert.Equal(t, data, buf) | ||
assert.Equal(t, int(chunkSize), n) | ||
} | ||
|
||
func TestBufferedReaderSubsequentReadsReturnEOF(t *testing.T) { | ||
pool := newBufferPool(10) | ||
br := newBufferedReader(pool) | ||
n64, err := br.ReadFrom(strings.NewReader("foobar")) | ||
assert.NoError(t, err) | ||
assert.Equal(t, int64(6), n64) | ||
br.Done() | ||
buf, err := io.ReadAll(br) | ||
assert.NoError(t, err) | ||
assert.Equal(t, "foobar", string(buf)) | ||
|
||
n, err := br.Read(buf) | ||
assert.Equal(t, 0, n) | ||
assert.ErrorIs(t, err, io.EOF) | ||
} | ||
|
||
func TestBufferedReaderDoneWithoutReadFrom(t *testing.T) { | ||
pool := newBufferPool(10) | ||
br := newBufferedReader(pool) | ||
br.Done() | ||
buf, err := io.ReadAll(br) | ||
assert.NoError(t, err) | ||
assert.Equal(t, 0, len(buf)) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters