Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(145)

Unified Diff: common/recordio/reader_test.go

Issue 1253353008: logdog: Add frame read/write library. (Closed) Base URL: https://github.com/luci/luci-go@logdog-review-output
Patch Set: Refresh? Created 5 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « common/recordio/reader.go ('k') | common/recordio/writer.go » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: common/recordio/reader_test.go
diff --git a/common/recordio/reader_test.go b/common/recordio/reader_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..74f2f41aef5f1ae348e3c79c005bbe8580926d44
--- /dev/null
+++ b/common/recordio/reader_test.go
@@ -0,0 +1,207 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package recordio
+
+import (
+ "bytes"
+ "encoding/binary"
+ "errors"
+ "io"
+ "io/ioutil"
+ "testing"
+
+ . "github.com/smartystreets/goconvey/convey"
+)
+
+// plainReader implements the io.Reader interface on top of a bytes.Buffer;
+// however, it does not also implement io.ByteReader.
+type plainReader struct {
+ buf bytes.Buffer
+ err error
+}
+
+func (r *plainReader) loadFrames(chunks ...[]byte) {
+ for _, chunk := range chunks {
+ _, err := WriteFrame(&r.buf, chunk)
+ if err != nil {
+ panic(err)
+ }
+ }
+}
+
+func (r *plainReader) Read(data []byte) (int, error) {
+ if r.err != nil {
+ return 0, r.err
+ }
+ return r.buf.Read(data)
+}
+
+type testByteReader struct {
+ plainReader
+
+ readByteErr error
+ readBytes int
+ byteBuf [1]byte
+}
+
+func (r *testByteReader) ReadByte() (b byte, err error) {
+ if r.readByteErr != nil {
+ return 0, r.readByteErr
+ }
+
+ b, err = r.buf.ReadByte()
+ if err == nil {
+ r.readBytes++
+ }
+ return
+}
+
+// TestReader tests the default Reader implementation, "reader".
+func TestReader(t *testing.T) {
+ t.Parallel()
+
+ Convey(`A frame reader with max size 1MB using a plain io.Reader`, t, func() {
+ maxSize := int64(1024 * 1024)
+ tr := plainReader{}
+ r := NewReader(&tr, maxSize)
+
+ Convey(`Will return io.EOF with an empty reader.`, func() {
+ _, err := r.ReadFrameAll()
+ So(err, ShouldEqual, io.EOF)
+ })
+
+ Convey(`Can successfully read a frame.`, func() {
+ data := []byte{0x13, 0x37, 0xd0, 0x65}
+ tr.loadFrames(data)
+
+ f, err := r.ReadFrameAll()
+ So(err, ShouldBeNil)
+ So(f, ShouldResemble, data)
+ })
+
+ Convey(`Can successfully read two frames.`, func() {
+ data := [][]byte{
+ {0x13, 0x37, 0xd0, 0x65},
+ {0xd0, 0x06, 0xea, 0x15, 0xf0, 0x0d},
+ }
+ tr.loadFrames(data...)
+
+ c, fr, err := r.ReadFrame()
+ So(err, ShouldBeNil)
+ So(c, ShouldEqual, 4)
+
+ d, err := ioutil.ReadAll(fr)
+ So(err, ShouldBeNil)
+ So(d, ShouldResemble, data[0])
+
+ c, fr, err = r.ReadFrame()
+ So(err, ShouldBeNil)
+ So(c, ShouldEqual, 6)
+
+ d, err = ioutil.ReadAll(fr)
+ So(err, ShouldBeNil)
+ So(d, ShouldResemble, data[1])
+ })
+
+ Convey(`When reading a frame, will return EOF if the frame is exceeded.`, func() {
+ data := []byte{0x13, 0x37, 0xd0, 0x65}
+ tr.loadFrames(data)
+
+ count, fr, err := r.ReadFrame()
+ So(err, ShouldBeNil)
+ So(count, ShouldEqual, 4)
+
+ buf := make([]byte, 5)
+ c, err := fr.Read(make([]byte, 5))
+ So(c, ShouldEqual, 4)
+ So(err, ShouldBeNil)
+
+ buf = buf[count:]
+ _, err = fr.Read(buf)
+ So(err, ShouldEqual, io.EOF)
+ })
+
+ Convey(`Will fail if the underlying frame exceeds the maximum size.`, func() {
+ var sizeBuf [binary.MaxVarintLen64]byte
+ tr.buf.Write(sizeBuf[:binary.PutUvarint(sizeBuf[:], uint64(maxSize+1))])
+
+ _, err := r.ReadFrameAll()
+ So(err, ShouldEqual, ErrFrameTooLarge)
+ })
+
+ Convey(`Will fail if the frame contains an invalid size header.`, func() {
+ tr.buf.Write([]byte{0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF})
+ _, err := r.ReadFrameAll()
+ So(err, ShouldNotBeNil)
+ })
+
+ Convey(`Can read conscutive frames, then io.EOF.`, func() {
+ data := [][]byte{}
+ for _, size := range []int{
+ 0,
+ 14,
+ 1024 * 1024,
+ 0,
+ 511,
+ } {
+ data = append(data, bytes.Repeat([]byte{0x5A}, size))
+ tr.loadFrames(data[len(data)-1])
+ }
+
+ for _, expected := range data {
+ f, err := r.ReadFrameAll()
+ So(err, ShouldBeNil)
+
+ if len(expected) == 0 {
+ expected = nil
+ }
+ So(f, ShouldResemble, expected)
+ }
+
+ _, err := r.ReadFrameAll()
+ So(err, ShouldEqual, io.EOF)
+ })
+ })
+
+ Convey(`A frame reader with max size 1MB using an io.Reader+io.ByteReader`, t, func() {
+ tr := testByteReader{}
+ r := NewReader(&tr, 1024*1024)
+
+ Convey(`Will return io.EOF with an empty reader.`, func() {
+ _, err := r.ReadFrameAll()
+ So(err, ShouldEqual, io.EOF)
+ })
+
+ Convey(`Will use io.ByteReader to read the frame header.`, func() {
+ data := []byte{0x13, 0x37, 0xd0, 0x65}
+ tr.loadFrames(data)
+
+ f, err := r.ReadFrameAll()
+ So(err, ShouldBeNil)
+ So(f, ShouldResemble, data)
+ So(tr.readBytes, ShouldEqual, 1)
+ })
+
+ Convey(`Will fail if the underlying io.Reader returns an error.`, func() {
+ tr.loadFrames([]byte{})
+ tr.err = errors.New("test: test-induced error")
+ tr.readByteErr = tr.err
+ _, err := r.ReadFrameAll()
+ So(err, ShouldEqual, tr.err)
+ })
+
+ Convey(`Will fail if an error is returned while reading frame's data.`, func() {
+ data := []byte{0x13, 0x37, 0xd0, 0x65}
+ tr.loadFrames(data)
+
+ // Have "ReadByte()" calls ignore the configured error. This will cause
+ // the frame size to be read without incident, but the frame data to still
+ // return an error.
+ tr.err = errors.New("test: test-induced error")
+ data, err := r.ReadFrameAll()
+ So(err, ShouldEqual, tr.err)
+ })
+ })
+}
« no previous file with comments | « common/recordio/reader.go ('k') | common/recordio/writer.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698