mirror of https://github.com/minio/minio.git
				
				
				
			
		
			
				
	
	
		
			1050 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			1050 lines
		
	
	
		
			27 KiB
		
	
	
	
		
			Go
		
	
	
	
| package ringbuffer
 | |
| 
 | |
| import (
 | |
| 	"bytes"
 | |
| 	"errors"
 | |
| 	"fmt"
 | |
| 	"hash/crc32"
 | |
| 	"io"
 | |
| 	"math/rand"
 | |
| 	"os"
 | |
| 	"runtime"
 | |
| 	"strings"
 | |
| 	"sync"
 | |
| 	"testing"
 | |
| 	"time"
 | |
| )
 | |
| 
 | |
| func TestRingBuffer_interface(t *testing.T) {
 | |
| 	rb := New(1)
 | |
| 	var _ io.Writer = rb
 | |
| 	var _ io.Reader = rb
 | |
| 	// var _ io.StringWriter = rb
 | |
| 	var _ io.ByteReader = rb
 | |
| 	var _ io.ByteWriter = rb
 | |
| }
 | |
| 
 | |
| func TestRingBuffer_Write(t *testing.T) {
 | |
| 	rb := New(64)
 | |
| 
 | |
| 	// check empty or full
 | |
| 	if !rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is true but got false")
 | |
| 	}
 | |
| 	if rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is false but got true")
 | |
| 	}
 | |
| 	if rb.Length() != 0 {
 | |
| 		t.Fatalf("expect len 0 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 64 {
 | |
| 		t.Fatalf("expect free 64 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	// write 4 * 4 = 16 bytes
 | |
| 	n, err := rb.Write([]byte(strings.Repeat("abcd", 4)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 16 {
 | |
| 		t.Fatalf("expect write 16 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 16 {
 | |
| 		t.Fatalf("expect len 16 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 48 {
 | |
| 		t.Fatalf("expect free 48 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte(strings.Repeat("abcd", 4))) {
 | |
| 		t.Fatalf("expect 4 abcd but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is false but got true")
 | |
| 	}
 | |
| 
 | |
| 	// write 48 bytes, should full
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("abcd", 12)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 48 {
 | |
| 		t.Fatalf("expect write 48 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 64 {
 | |
| 		t.Fatalf("expect len 64 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.w != 0 {
 | |
| 		t.Fatalf("expect r.w=0 but got %d. r.r=%d", rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte(strings.Repeat("abcd", 16))) {
 | |
| 		t.Fatalf("expect 16 abcd but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if !rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is true but got false")
 | |
| 	}
 | |
| 
 | |
| 	// write more 4 bytes, should reject
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("abcd", 1)))
 | |
| 	if err == nil {
 | |
| 		t.Fatalf("expect an error but got nil. n=%d, r.w=%d, r.r=%d", n, rb.w, rb.r)
 | |
| 	}
 | |
| 	if err != ErrIsFull {
 | |
| 		t.Fatalf("expect ErrIsFull but got nil")
 | |
| 	}
 | |
| 	if n != 0 {
 | |
| 		t.Fatalf("expect write 0 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 64 {
 | |
| 		t.Fatalf("expect len 64 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if !rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is true but got false")
 | |
| 	}
 | |
| 
 | |
| 	// reset this ringbuffer and set a long slice
 | |
| 	rb.Reset()
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("abcd", 20)))
 | |
| 	if err == nil {
 | |
| 		t.Fatalf("expect ErrTooManyDataToWrite but got nil")
 | |
| 	}
 | |
| 	if n != 64 {
 | |
| 		t.Fatalf("expect write 64 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 64 {
 | |
| 		t.Fatalf("expect len 64 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.w != 0 {
 | |
| 		t.Fatalf("expect r.w=0 but got %d. r.r=%d", rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if !rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is true but got false")
 | |
| 	}
 | |
| 
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte(strings.Repeat("abcd", 16))) {
 | |
| 		t.Fatalf("expect 16 abcd but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	rb.Reset()
 | |
| 	// write 4 * 2 = 8 bytes
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("abcd", 2)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 8 {
 | |
| 		t.Fatalf("expect write 16 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 8 {
 | |
| 		t.Fatalf("expect len 16 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 56 {
 | |
| 		t.Fatalf("expect free 48 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	buf := make([]byte, 5)
 | |
| 	rb.Read(buf)
 | |
| 	if rb.Length() != 3 {
 | |
| 		t.Fatalf("expect len 3 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	rb.Write([]byte(strings.Repeat("abcd", 15)))
 | |
| 
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte("bcd"+strings.Repeat("abcd", 15))) {
 | |
| 		t.Fatalf("expect 63 ... but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	rb.Reset()
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("abcd", 16)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 64 {
 | |
| 		t.Fatalf("expect write 64 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	buf = make([]byte, 16)
 | |
| 	rb.Read(buf)
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("1234", 4)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 16 {
 | |
| 		t.Fatalf("expect write 16 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(append(buf, rb.Bytes(nil)...), []byte(strings.Repeat("abcd", 16)+strings.Repeat("1234", 4))) {
 | |
| 		t.Fatalf("expect 16 abcd and 4 1234 but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRingBuffer_WriteBlocking(t *testing.T) {
 | |
| 	rb := New(64).SetBlocking(true)
 | |
| 
 | |
| 	// check empty or full
 | |
| 	if !rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is true but got false")
 | |
| 	}
 | |
| 	if rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is false but got true")
 | |
| 	}
 | |
| 	if rb.Length() != 0 {
 | |
| 		t.Fatalf("expect len 0 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 64 {
 | |
| 		t.Fatalf("expect free 64 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	// write 4 * 4 = 16 bytes
 | |
| 	n, err := rb.Write([]byte(strings.Repeat("abcd", 4)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 16 {
 | |
| 		t.Fatalf("expect write 16 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 16 {
 | |
| 		t.Fatalf("expect len 16 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 48 {
 | |
| 		t.Fatalf("expect free 48 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte(strings.Repeat("abcd", 4))) {
 | |
| 		t.Fatalf("expect 4 abcd but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is false but got true")
 | |
| 	}
 | |
| 
 | |
| 	// write 48 bytes, should full
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("abcd", 12)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 48 {
 | |
| 		t.Fatalf("expect write 48 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 64 {
 | |
| 		t.Fatalf("expect len 64 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.w != 0 {
 | |
| 		t.Fatalf("expect r.w=0 but got %d. r.r=%d", rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte(strings.Repeat("abcd", 16))) {
 | |
| 		t.Fatalf("expect 16 abcd but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if !rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is true but got false")
 | |
| 	}
 | |
| 
 | |
| 	rb.Reset()
 | |
| 	// write 4 * 2 = 8 bytes
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("abcd", 2)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 8 {
 | |
| 		t.Fatalf("expect write 16 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 8 {
 | |
| 		t.Fatalf("expect len 16 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 56 {
 | |
| 		t.Fatalf("expect free 48 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	buf := make([]byte, 5)
 | |
| 	rb.Read(buf)
 | |
| 	if rb.Length() != 3 {
 | |
| 		t.Fatalf("expect len 3 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	rb.Write([]byte(strings.Repeat("abcd", 15)))
 | |
| 
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte("bcd"+strings.Repeat("abcd", 15))) {
 | |
| 		t.Fatalf("expect 63 ... but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	rb.Reset()
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("abcd", 16)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 64 {
 | |
| 		t.Fatalf("expect write 64 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	buf = make([]byte, 16)
 | |
| 	rb.Read(buf)
 | |
| 	n, err = rb.Write([]byte(strings.Repeat("1234", 4)))
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("write failed: %v", err)
 | |
| 	}
 | |
| 	if n != 16 {
 | |
| 		t.Fatalf("expect write 16 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(append(buf, rb.Bytes(nil)...), []byte(strings.Repeat("abcd", 16)+strings.Repeat("1234", 4))) {
 | |
| 		t.Fatalf("expect 16 abcd and 4 1234 but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRingBuffer_Read(t *testing.T) {
 | |
| 	defer timeout(5 * time.Second)()
 | |
| 	rb := New(64)
 | |
| 
 | |
| 	// check empty or full
 | |
| 	if !rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is true but got false")
 | |
| 	}
 | |
| 	if rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is false but got true")
 | |
| 	}
 | |
| 	if rb.Length() != 0 {
 | |
| 		t.Fatalf("expect len 0 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 64 {
 | |
| 		t.Fatalf("expect free 64 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 
 | |
| 	// read empty
 | |
| 	buf := make([]byte, 1024)
 | |
| 	n, err := rb.Read(buf)
 | |
| 	if err == nil {
 | |
| 		t.Fatalf("expect an error but got nil")
 | |
| 	}
 | |
| 	if err != ErrIsEmpty {
 | |
| 		t.Fatalf("expect ErrIsEmpty but got nil")
 | |
| 	}
 | |
| 	if n != 0 {
 | |
| 		t.Fatalf("expect read 0 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 0 {
 | |
| 		t.Fatalf("expect len 0 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 64 {
 | |
| 		t.Fatalf("expect free 64 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.r != 0 {
 | |
| 		t.Fatalf("expect r.r=0 but got %d. r.w=%d", rb.r, rb.w)
 | |
| 	}
 | |
| 
 | |
| 	// write 16 bytes to read
 | |
| 	rb.Write([]byte(strings.Repeat("abcd", 4)))
 | |
| 	n, err = rb.Read(buf)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("read failed: %v", err)
 | |
| 	}
 | |
| 	if n != 16 {
 | |
| 		t.Fatalf("expect read 16 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 0 {
 | |
| 		t.Fatalf("expect len 0 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 64 {
 | |
| 		t.Fatalf("expect free 64 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.r != 16 {
 | |
| 		t.Fatalf("expect r.r=16 but got %d. r.w=%d", rb.r, rb.w)
 | |
| 	}
 | |
| 
 | |
| 	// write long slice to  read
 | |
| 	rb.Write([]byte(strings.Repeat("abcd", 20)))
 | |
| 	n, err = rb.Read(buf)
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("read failed: %v", err)
 | |
| 	}
 | |
| 	if n != 64 {
 | |
| 		t.Fatalf("expect read 64 bytes but got %d", n)
 | |
| 	}
 | |
| 	if rb.Length() != 0 {
 | |
| 		t.Fatalf("expect len 0 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 64 {
 | |
| 		t.Fatalf("expect free 64 bytes but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.r != 16 {
 | |
| 		t.Fatalf("expect r.r=16 but got %d. r.w=%d", rb.r, rb.w)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRingBuffer_Blocking(t *testing.T) {
 | |
| 	// Typical runtime is ~5-10s.
 | |
| 	defer timeout(60 * time.Second)()
 | |
| 	const debug = false
 | |
| 
 | |
| 	var readBytes int
 | |
| 	var wroteBytes int
 | |
| 	var readBuf bytes.Buffer
 | |
| 	var wroteBuf bytes.Buffer
 | |
| 	readHash := crc32.NewIEEE()
 | |
| 	wroteHash := crc32.NewIEEE()
 | |
| 	read := io.Writer(readHash)
 | |
| 	wrote := io.Writer(wroteHash)
 | |
| 	if debug {
 | |
| 		read = io.MultiWriter(read, &readBuf)
 | |
| 		wrote = io.MultiWriter(wrote, &wroteBuf)
 | |
| 	}
 | |
| 	debugln := func(args ...interface{}) {
 | |
| 		if debug {
 | |
| 			fmt.Println(args...)
 | |
| 		}
 | |
| 	}
 | |
| 	// Inject random reader/writer sleeps.
 | |
| 	const maxSleep = int(1 * time.Millisecond)
 | |
| 	doSleep := !testing.Short()
 | |
| 	rb := New(4 << 10).SetBlocking(true)
 | |
| 
 | |
| 	// Reader
 | |
| 	var readErr error
 | |
| 	var wg sync.WaitGroup
 | |
| 	wg.Add(1)
 | |
| 	go func() {
 | |
| 		readRng := rand.New(rand.NewSource(1))
 | |
| 		defer wg.Done()
 | |
| 		defer rb.CloseWithError(readErr)
 | |
| 		buf := make([]byte, 1024)
 | |
| 		for {
 | |
| 			// Read
 | |
| 			n, err := rb.Read(buf[:readRng.Intn(len(buf))])
 | |
| 			readBytes += n
 | |
| 			read.Write(buf[:n])
 | |
| 			debugln("READ 1\t", n, readBytes)
 | |
| 			if err != nil {
 | |
| 				readErr = err
 | |
| 				break
 | |
| 			}
 | |
| 
 | |
| 			// ReadByte
 | |
| 			b, err := rb.ReadByte()
 | |
| 			if err != nil {
 | |
| 				readErr = err
 | |
| 				break
 | |
| 			}
 | |
| 			readBytes++
 | |
| 			read.Write([]byte{b})
 | |
| 			debugln("READ 2\t", 1, readBytes)
 | |
| 
 | |
| 			// TryRead
 | |
| 			n, err = rb.TryRead(buf[:readRng.Intn(len(buf))])
 | |
| 			readBytes += n
 | |
| 			read.Write(buf[:n])
 | |
| 			debugln("READ 3\t", n, readBytes)
 | |
| 			if err != nil && err != ErrAcquireLock && err != ErrIsEmpty {
 | |
| 				readErr = err
 | |
| 				break
 | |
| 			}
 | |
| 			if doSleep && readRng.Intn(20) == 0 {
 | |
| 				time.Sleep(time.Duration(readRng.Intn(maxSleep)))
 | |
| 			}
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	// Writer
 | |
| 	{
 | |
| 		buf := make([]byte, 1024)
 | |
| 		writeRng := rand.New(rand.NewSource(2))
 | |
| 		for i := 0; i < 2500; i++ {
 | |
| 			writeRng.Read(buf)
 | |
| 			// Write
 | |
| 			n, err := rb.Write(buf[:writeRng.Intn(len(buf))])
 | |
| 			if err != nil {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			wroteBytes += n
 | |
| 			wrote.Write(buf[:n])
 | |
| 			debugln("WRITE 1\t", n, wroteBytes)
 | |
| 
 | |
| 			// WriteString
 | |
| 			n, err = rb.WriteString(string(buf[:writeRng.Intn(len(buf))]))
 | |
| 			if err != nil {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			wroteBytes += n
 | |
| 			wrote.Write(buf[:n])
 | |
| 			debugln("WRITE 2\t", writeRng.Intn(len(buf)), wroteBytes)
 | |
| 
 | |
| 			// WriteByte
 | |
| 			err = rb.WriteByte(buf[0])
 | |
| 			if err != nil {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			wroteBytes++
 | |
| 			wrote.Write(buf[:1])
 | |
| 			debugln("WRITE 3\t", 1, wroteBytes)
 | |
| 
 | |
| 			// TryWrite
 | |
| 			n, err = rb.TryWrite(buf[:writeRng.Intn(len(buf))])
 | |
| 			if err != nil && err != ErrAcquireLock && err != ErrTooMuchDataToWrite && err != ErrIsFull {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			wroteBytes += n
 | |
| 			wrote.Write(buf[:n])
 | |
| 			debugln("WRITE 4\t", n, wroteBytes)
 | |
| 
 | |
| 			// TryWriteByte
 | |
| 			err = rb.TryWriteByte(buf[0])
 | |
| 			if err != nil && err != ErrAcquireLock && err != ErrTooMuchDataToWrite && err != ErrIsFull {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			if err == nil {
 | |
| 				wroteBytes++
 | |
| 				wrote.Write(buf[:1])
 | |
| 				debugln("WRITE 5\t", 1, wroteBytes)
 | |
| 			}
 | |
| 			if doSleep && writeRng.Intn(10) == 0 {
 | |
| 				time.Sleep(time.Duration(writeRng.Intn(maxSleep)))
 | |
| 			}
 | |
| 		}
 | |
| 		if err := rb.Flush(); err != nil {
 | |
| 			t.Fatalf("flush failed: %v", err)
 | |
| 		}
 | |
| 		rb.CloseWriter()
 | |
| 	}
 | |
| 	wg.Wait()
 | |
| 	if !errors.Is(readErr, io.EOF) {
 | |
| 		t.Fatalf("expect io.EOF but got %v", readErr)
 | |
| 	}
 | |
| 	if readBytes != wroteBytes {
 | |
| 		a, b := readBuf.Bytes(), wroteBuf.Bytes()
 | |
| 		if debug && !bytes.Equal(a, b) {
 | |
| 			common := len(a)
 | |
| 			for i := range a {
 | |
| 				if a[i] != b[i] {
 | |
| 					common = i
 | |
| 					break
 | |
| 				}
 | |
| 			}
 | |
| 			a, b = a[common:], b[common:]
 | |
| 			if len(a) > 64 {
 | |
| 				a = a[:64]
 | |
| 			}
 | |
| 			if len(b) > 64 {
 | |
| 				b = b[:64]
 | |
| 			}
 | |
| 			t.Errorf("after %d common bytes, difference \nread: %x\nwrote:%x", common, a, b)
 | |
| 		}
 | |
| 		t.Fatalf("expect read %d bytes but got %d", wroteBytes, readBytes)
 | |
| 	}
 | |
| 	if readHash.Sum32() != wroteHash.Sum32() {
 | |
| 		t.Fatalf("expect read hash 0x%08x but got 0x%08x", readHash.Sum32(), wroteHash.Sum32())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRingBuffer_BlockingBig(t *testing.T) {
 | |
| 	// Typical runtime is ~5-10s.
 | |
| 	defer timeout(60 * time.Second)()
 | |
| 	const debug = false
 | |
| 
 | |
| 	var readBytes int
 | |
| 	var wroteBytes int
 | |
| 	readHash := crc32.NewIEEE()
 | |
| 	wroteHash := crc32.NewIEEE()
 | |
| 	var readBuf bytes.Buffer
 | |
| 	var wroteBuf bytes.Buffer
 | |
| 	read := io.Writer(readHash)
 | |
| 	wrote := io.Writer(wroteHash)
 | |
| 	if debug {
 | |
| 		read = io.MultiWriter(read, &readBuf)
 | |
| 		wrote = io.MultiWriter(wrote, &wroteBuf)
 | |
| 	}
 | |
| 	debugln := func(args ...interface{}) {
 | |
| 		if debug {
 | |
| 			fmt.Println(args...)
 | |
| 		}
 | |
| 	}
 | |
| 	// Inject random reader/writer sleeps.
 | |
| 	const maxSleep = int(1 * time.Millisecond)
 | |
| 	doSleep := !testing.Short()
 | |
| 	rb := New(4 << 10).SetBlocking(true)
 | |
| 
 | |
| 	// Reader
 | |
| 	var readErr error
 | |
| 	var wg sync.WaitGroup
 | |
| 	wg.Add(1)
 | |
| 	go func() {
 | |
| 		defer wg.Done()
 | |
| 		defer rb.CloseWithError(readErr)
 | |
| 		readRng := rand.New(rand.NewSource(1))
 | |
| 		buf := make([]byte, 64<<10)
 | |
| 		for {
 | |
| 			// Read
 | |
| 			n, err := rb.Read(buf[:readRng.Intn(len(buf))])
 | |
| 			readBytes += n
 | |
| 			read.Write(buf[:n])
 | |
| 			if err != nil {
 | |
| 				readErr = err
 | |
| 				break
 | |
| 			}
 | |
| 			debugln("READ 1\t", n, readBytes)
 | |
| 
 | |
| 			// ReadByte
 | |
| 			b, err := rb.ReadByte()
 | |
| 			if err != nil {
 | |
| 				readErr = err
 | |
| 				break
 | |
| 			}
 | |
| 			readBytes++
 | |
| 			read.Write([]byte{b})
 | |
| 			debugln("READ 2\t", 1, readBytes)
 | |
| 
 | |
| 			// TryRead
 | |
| 			n, err = rb.TryRead(buf[:readRng.Intn(len(buf))])
 | |
| 			readBytes += n
 | |
| 			read.Write(buf[:n])
 | |
| 			if err != nil && err != ErrAcquireLock && err != ErrIsEmpty {
 | |
| 				readErr = err
 | |
| 				break
 | |
| 			}
 | |
| 			debugln("READ 3\t", n, readBytes)
 | |
| 			if doSleep && readRng.Intn(20) == 0 {
 | |
| 				time.Sleep(time.Duration(readRng.Intn(maxSleep)))
 | |
| 			}
 | |
| 		}
 | |
| 	}()
 | |
| 
 | |
| 	// Writer
 | |
| 	{
 | |
| 		writeRng := rand.New(rand.NewSource(2))
 | |
| 		buf := make([]byte, 64<<10)
 | |
| 		for i := 0; i < 500; i++ {
 | |
| 			writeRng.Read(buf)
 | |
| 			// Write
 | |
| 			n, err := rb.Write(buf[:writeRng.Intn(len(buf))])
 | |
| 			if err != nil {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			wroteBytes += n
 | |
| 			wrote.Write(buf[:n])
 | |
| 			debugln("WRITE 1\t", n, wroteBytes)
 | |
| 
 | |
| 			// WriteString
 | |
| 			n, err = rb.WriteString(string(buf[:writeRng.Intn(len(buf))]))
 | |
| 			if err != nil {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			wroteBytes += n
 | |
| 			wrote.Write(buf[:n])
 | |
| 			debugln("WRITE 2\t", writeRng.Intn(len(buf)), wroteBytes)
 | |
| 
 | |
| 			// WriteByte
 | |
| 			err = rb.WriteByte(buf[0])
 | |
| 			if err != nil {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			wroteBytes++
 | |
| 			wrote.Write(buf[:1])
 | |
| 			debugln("WRITE 3\t", 1, wroteBytes)
 | |
| 
 | |
| 			// TryWrite
 | |
| 			n, err = rb.TryWrite(buf[:writeRng.Intn(len(buf))])
 | |
| 			if err != nil && err != ErrAcquireLock && err != ErrTooMuchDataToWrite && err != ErrIsFull {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			wroteBytes += n
 | |
| 			wrote.Write(buf[:n])
 | |
| 			debugln("WRITE 4\t", n, wroteBytes)
 | |
| 
 | |
| 			// TryWriteByte
 | |
| 			err = rb.TryWriteByte(buf[0])
 | |
| 			if err != nil && err != ErrAcquireLock && err != ErrTooMuchDataToWrite && err != ErrIsFull {
 | |
| 				t.Fatalf("write failed: %v", err)
 | |
| 			}
 | |
| 			if err == nil {
 | |
| 				wroteBytes++
 | |
| 				wrote.Write(buf[:1])
 | |
| 				debugln("WRITE 5\t", 1, wroteBytes)
 | |
| 			}
 | |
| 			if doSleep && writeRng.Intn(10) == 0 {
 | |
| 				time.Sleep(time.Duration(writeRng.Intn(maxSleep)))
 | |
| 			}
 | |
| 		}
 | |
| 		if err := rb.Flush(); err != nil {
 | |
| 			t.Fatalf("flush failed: %v", err)
 | |
| 		}
 | |
| 		rb.CloseWriter()
 | |
| 	}
 | |
| 	wg.Wait()
 | |
| 	if !errors.Is(readErr, io.EOF) {
 | |
| 		t.Fatalf("expect io.EOF but got %v", readErr)
 | |
| 	}
 | |
| 	if readBytes != wroteBytes {
 | |
| 		a, b := readBuf.Bytes(), wroteBuf.Bytes()
 | |
| 		if debug && !bytes.Equal(a, b) {
 | |
| 			common := len(a)
 | |
| 			for i := range a {
 | |
| 				if a[i] != b[i] {
 | |
| 					t.Errorf("%x != %x", a[i], b[i])
 | |
| 					common = i
 | |
| 					break
 | |
| 				}
 | |
| 			}
 | |
| 			a, b = a[common:], b[common:]
 | |
| 			if len(a) > 64 {
 | |
| 				a = a[:64]
 | |
| 			}
 | |
| 			if len(b) > 64 {
 | |
| 				b = b[:64]
 | |
| 			}
 | |
| 			t.Errorf("after %d common bytes, difference \nread: %x\nwrote:%x", common, a, b)
 | |
| 		}
 | |
| 		t.Fatalf("expect read %d bytes but got %d", wroteBytes, readBytes)
 | |
| 	}
 | |
| 	if readHash.Sum32() != wroteHash.Sum32() {
 | |
| 		t.Fatalf("expect read hash 0x%08x but got 0x%08x", readHash.Sum32(), wroteHash.Sum32())
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRingBuffer_ByteInterface(t *testing.T) {
 | |
| 	defer timeout(5 * time.Second)()
 | |
| 	rb := New(2)
 | |
| 
 | |
| 	// write one
 | |
| 	err := rb.WriteByte('a')
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("WriteByte failed: %v", err)
 | |
| 	}
 | |
| 	if rb.Length() != 1 {
 | |
| 		t.Fatalf("expect len 1 byte but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 1 {
 | |
| 		t.Fatalf("expect free 1 byte but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte{'a'}) {
 | |
| 		t.Fatalf("expect a but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is false but got true")
 | |
| 	}
 | |
| 
 | |
| 	// write to, isFull
 | |
| 	err = rb.WriteByte('b')
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("WriteByte failed: %v", err)
 | |
| 	}
 | |
| 	if rb.Length() != 2 {
 | |
| 		t.Fatalf("expect len 2 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 byte but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte{'a', 'b'}) {
 | |
| 		t.Fatalf("expect a but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if !rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is true but got false")
 | |
| 	}
 | |
| 
 | |
| 	// write
 | |
| 	err = rb.WriteByte('c')
 | |
| 	if err == nil {
 | |
| 		t.Fatalf("expect ErrIsFull but got nil")
 | |
| 	}
 | |
| 	if rb.Length() != 2 {
 | |
| 		t.Fatalf("expect len 2 bytes but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 0 {
 | |
| 		t.Fatalf("expect free 0 byte but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte{'a', 'b'}) {
 | |
| 		t.Fatalf("expect a but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if !rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is true but got false")
 | |
| 	}
 | |
| 
 | |
| 	// read one
 | |
| 	b, err := rb.ReadByte()
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("ReadByte failed: %v", err)
 | |
| 	}
 | |
| 	if b != 'a' {
 | |
| 		t.Fatalf("expect a but got %c. r.w=%d, r.r=%d", b, rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Length() != 1 {
 | |
| 		t.Fatalf("expect len 1 byte but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 1 {
 | |
| 		t.Fatalf("expect free 1 byte but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if !bytes.Equal(rb.Bytes(nil), []byte{'b'}) {
 | |
| 		t.Fatalf("expect a but got %s. r.w=%d, r.r=%d", rb.Bytes(nil), rb.w, rb.r)
 | |
| 	}
 | |
| 	// check empty or full
 | |
| 	if rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is false but got true")
 | |
| 	}
 | |
| 	if rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is false but got true")
 | |
| 	}
 | |
| 
 | |
| 	// read two, empty
 | |
| 	b, err = rb.ReadByte()
 | |
| 	if err != nil {
 | |
| 		t.Fatalf("ReadByte failed: %v", err)
 | |
| 	}
 | |
| 	if b != 'b' {
 | |
| 		t.Fatalf("expect b but got %c. r.w=%d, r.r=%d", b, rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Length() != 0 {
 | |
| 		t.Fatalf("expect len 0 byte but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 2 {
 | |
| 		t.Fatalf("expect free 2 byte but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	// check empty or full
 | |
| 	if !rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is true but got false")
 | |
| 	}
 | |
| 	if rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is false but got true")
 | |
| 	}
 | |
| 
 | |
| 	// read three, error
 | |
| 	_, err = rb.ReadByte()
 | |
| 	if err == nil {
 | |
| 		t.Fatalf("expect ErrIsEmpty but got nil")
 | |
| 	}
 | |
| 	if rb.Length() != 0 {
 | |
| 		t.Fatalf("expect len 0 byte but got %d. r.w=%d, r.r=%d", rb.Length(), rb.w, rb.r)
 | |
| 	}
 | |
| 	if rb.Free() != 2 {
 | |
| 		t.Fatalf("expect free 2 byte but got %d. r.w=%d, r.r=%d", rb.Free(), rb.w, rb.r)
 | |
| 	}
 | |
| 	// check empty or full
 | |
| 	if !rb.IsEmpty() {
 | |
| 		t.Fatalf("expect IsEmpty is true but got false")
 | |
| 	}
 | |
| 	if rb.IsFull() {
 | |
| 		t.Fatalf("expect IsFull is false but got true")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRingBufferCloseError(t *testing.T) {
 | |
| 	type testError1 struct{ error }
 | |
| 	type testError2 struct{ error }
 | |
| 
 | |
| 	rb := New(100)
 | |
| 	rb.CloseWithError(testError1{})
 | |
| 	if _, err := rb.Write(nil); err != (testError1{}) {
 | |
| 		t.Errorf("Write error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.Write([]byte{1}); err != (testError1{}) {
 | |
| 		t.Errorf("Write error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if err := rb.WriteByte(0); err != (testError1{}) {
 | |
| 		t.Errorf("Write error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.TryWrite(nil); err != (testError1{}) {
 | |
| 		t.Errorf("Write error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.TryWrite([]byte{1}); err != (testError1{}) {
 | |
| 		t.Errorf("Write error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if err := rb.TryWriteByte(0); err != (testError1{}) {
 | |
| 		t.Errorf("Write error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if err := rb.Flush(); err != (testError1{}) {
 | |
| 		t.Errorf("Write error: got %T, want testError1", err)
 | |
| 	}
 | |
| 
 | |
| 	rb.CloseWithError(testError2{})
 | |
| 	if _, err := rb.Write(nil); err != (testError1{}) {
 | |
| 		t.Errorf("Write error: got %T, want testError1", err)
 | |
| 	}
 | |
| 
 | |
| 	rb.Reset()
 | |
| 	rb.CloseWithError(testError1{})
 | |
| 	if _, err := rb.Read(nil); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.Read([]byte{0}); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.ReadByte(); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.TryRead(nil); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.TryRead([]byte{0}); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	rb.CloseWithError(testError2{})
 | |
| 	if _, err := rb.Read(nil); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.Read([]byte{0}); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.ReadByte(); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.TryRead(nil); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| 	if _, err := rb.TryRead([]byte{0}); err != (testError1{}) {
 | |
| 		t.Errorf("Read error: got %T, want testError1", err)
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func TestRingBufferCloseErrorUnblocks(t *testing.T) {
 | |
| 	const sz = 100
 | |
| 	rb := New(sz).SetBlocking(true)
 | |
| 
 | |
| 	testCancel := func(fn func()) {
 | |
| 		t.Helper()
 | |
| 		defer timeout(5 * time.Second)()
 | |
| 		rb.Reset()
 | |
| 		done := make(chan struct{})
 | |
| 		go func() {
 | |
| 			defer close(done)
 | |
| 			time.Sleep(10 * time.Millisecond)
 | |
| 			fn()
 | |
| 		}()
 | |
| 		rb.CloseWithError(errors.New("test error"))
 | |
| 		<-done
 | |
| 
 | |
| 		rb.Reset()
 | |
| 		done = make(chan struct{})
 | |
| 		go func() {
 | |
| 			defer close(done)
 | |
| 			fn()
 | |
| 		}()
 | |
| 		time.Sleep(10 * time.Millisecond)
 | |
| 		rb.CloseWithError(errors.New("test error"))
 | |
| 		<-done
 | |
| 	}
 | |
| 	testCancel(func() {
 | |
| 		rb.Write([]byte{sz + 5: 1})
 | |
| 	})
 | |
| 	testCancel(func() {
 | |
| 		rb.Write(make([]byte, sz))
 | |
| 		rb.WriteByte(0)
 | |
| 	})
 | |
| 	testCancel(func() {
 | |
| 		rb.Read([]byte{10: 1})
 | |
| 	})
 | |
| 	testCancel(func() {
 | |
| 		rb.ReadByte()
 | |
| 	})
 | |
| 	testCancel(func() {
 | |
| 		rb.Write(make([]byte, sz))
 | |
| 		rb.Flush()
 | |
| 	})
 | |
| }
 | |
| 
 | |
| func TestWriteAfterWriterClose(t *testing.T) {
 | |
| 	rb := New(100).SetBlocking(true)
 | |
| 
 | |
| 	done := make(chan error)
 | |
| 	go func() {
 | |
| 		defer close(done)
 | |
| 		_, err := rb.Write([]byte("hello"))
 | |
| 		if err != nil {
 | |
| 			t.Errorf("got error: %q; expected none", err)
 | |
| 		}
 | |
| 		rb.CloseWriter()
 | |
| 		_, err = rb.Write([]byte("world"))
 | |
| 		done <- err
 | |
| 		err = rb.WriteByte(0)
 | |
| 		done <- err
 | |
| 		_, err = rb.TryWrite([]byte("world"))
 | |
| 		done <- err
 | |
| 		err = rb.TryWriteByte(0)
 | |
| 		done <- err
 | |
| 	}()
 | |
| 
 | |
| 	buf := make([]byte, 100)
 | |
| 	n, err := io.ReadFull(rb, buf)
 | |
| 	if err != nil && err != io.ErrUnexpectedEOF {
 | |
| 		t.Fatalf("got: %q; want: %q", err, io.ErrUnexpectedEOF)
 | |
| 	}
 | |
| 	for writeErr := range done {
 | |
| 		if writeErr != ErrWriteOnClosed {
 | |
| 			t.Errorf("got: %q; want: %q", writeErr, ErrWriteOnClosed)
 | |
| 		} else {
 | |
| 			t.Log("ok")
 | |
| 		}
 | |
| 	}
 | |
| 	result := string(buf[0:n])
 | |
| 	if result != "hello" {
 | |
| 		t.Errorf("got: %q; want: %q", result, "hello")
 | |
| 	}
 | |
| }
 | |
| 
 | |
| func timeout(after time.Duration) (cancel func()) {
 | |
| 	c := time.After(after)
 | |
| 	cc := make(chan struct{})
 | |
| 	go func() {
 | |
| 		select {
 | |
| 		case <-cc:
 | |
| 			return
 | |
| 		case <-c:
 | |
| 			buf := make([]byte, 1<<20)
 | |
| 			stacklen := runtime.Stack(buf, true)
 | |
| 			fmt.Printf("=== Timeout, assuming deadlock ===\n*** goroutine dump...\n%s\n*** end\n", string(buf[:stacklen]))
 | |
| 			os.Exit(2)
 | |
| 		}
 | |
| 	}()
 | |
| 	return func() {
 | |
| 		close(cc)
 | |
| 	}
 | |
| }
 |