object: fixed Seek() behavior for seeking to end of object

This commit is contained in:
Jarek Kowalski
2019-11-24 18:48:18 -08:00
parent 4598a05083
commit f4afaec9b5
2 changed files with 63 additions and 9 deletions

View File

@@ -8,6 +8,7 @@
"encoding/hex"
"encoding/json"
"fmt"
"io"
"io/ioutil"
"math/rand"
"runtime/debug"
@@ -349,3 +350,54 @@ func verify(ctx context.Context, t *testing.T, om *Manager, objectID ID, expecte
}
}
}
// nolint:gocyclo
func TestSeek(t *testing.T) {
ctx := context.Background()
_, om := setupTest(t)
for _, size := range []int{0, 1, 500000, 15000000} {
randomData := make([]byte, size)
cryptorand.Read(randomData) //nolint:errcheck
writer := om.NewWriter(ctx, WriterOptions{})
if _, err := writer.Write(randomData); err != nil {
t.Errorf("write error: %v", err)
}
objectID, err := writer.Result()
if err != nil {
t.Fatalf("unable to write: %v", err)
}
r, err := om.Open(ctx, objectID)
if err != nil {
t.Fatalf("open error: %v", err)
}
if pos, err := r.Seek(0, io.SeekStart); err != nil || pos != 0 {
t.Errorf("invalid seek-start result %v %v", pos, err)
}
if pos, err := r.Seek(0, io.SeekCurrent); err != nil || pos != 0 {
t.Errorf("invalid seek-current at start result %v %v", pos, err)
}
if pos, err := r.Seek(0, io.SeekEnd); err != nil || pos != int64(size) {
t.Errorf("invalid seek-end result %v %v", pos, err)
}
if pos, err := r.Seek(0, io.SeekCurrent); err != nil || pos != int64(size) {
t.Errorf("invalid seek-current at end result %v %v, wanted %v", pos, err, size)
}
if pos, err := r.Seek(1, io.SeekCurrent); err != nil || pos != int64(size)+1 {
t.Errorf("unexpected result when seeking past end of file: %v, %v, wanted %v", pos, err, size+1)
}
buf := make([]byte, 5)
if n, err := r.Read(buf); n != 0 || err != io.EOF {
t.Errorf("unexpected read result %v %v", n, err)
}
}
}

View File

@@ -29,6 +29,10 @@ func (r *objectReader) Read(buffer []byte) (int, error) {
readBytes := 0
remaining := len(buffer)
if r.currentPosition >= r.totalLength {
return 0, io.EOF
}
for remaining > 0 {
if r.currentChunkData != nil {
toCopy := len(r.currentChunkData) - r.currentChunkPosition
@@ -114,20 +118,19 @@ func (r *objectReader) findChunkIndexForOffset(offset int64) (int, error) {
}
func (r *objectReader) Seek(offset int64, whence int) (int64, error) {
if whence == 1 {
if whence == io.SeekCurrent {
return r.Seek(r.currentPosition+offset, 0)
}
if whence == 2 {
if whence == io.SeekEnd {
return r.Seek(r.totalLength+offset, 0)
}
if offset < 0 {
return -1, errors.Errorf("invalid seek %v %v", offset, whence)
}
if offset > r.totalLength {
offset = r.totalLength
if offset >= r.totalLength {
r.currentChunkIndex = len(r.seekTable)
r.currentChunkData = nil
r.currentPosition = offset
return offset, nil
}
index, err := r.findChunkIndexForOffset(offset)
@@ -136,7 +139,6 @@ func (r *objectReader) Seek(offset int64, whence int) (int64, error) {
}
chunkStartOffset := r.seekTable[index].Start
if index != r.currentChunkIndex {
r.closeCurrentChunk()
r.currentChunkIndex = index