github.com/coreos/mantle@v0.13.0/lang/bufpipe/pipe_test.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  // Licensed under the same terms as Go itself:
     5  // https://github.com/golang/go/blob/master/LICENSE
     6  
     7  package bufpipe
     8  
     9  import (
    10  	"fmt"
    11  	"io"
    12  	"testing"
    13  	"time"
    14  )
    15  
    16  func checkWrite(t *testing.T, w io.Writer, data []byte, c chan int) {
    17  	n, err := w.Write(data)
    18  	if err != nil {
    19  		t.Errorf("write: %v", err)
    20  	}
    21  	if n != len(data) {
    22  		t.Errorf("short write: %d != %d", n, len(data))
    23  	}
    24  	c <- 0
    25  }
    26  
    27  // Test a single read/write pair.
    28  func TestPipe1(t *testing.T) {
    29  	c := make(chan int)
    30  	r, w := Pipe()
    31  	var buf = make([]byte, 64)
    32  	go checkWrite(t, w, []byte("hello, world"), c)
    33  	n, err := r.Read(buf)
    34  	if err != nil {
    35  		t.Errorf("read: %v", err)
    36  	} else if n != 12 || string(buf[0:12]) != "hello, world" {
    37  		t.Errorf("bad read: got %q", buf[0:n])
    38  	}
    39  	<-c
    40  	r.Close()
    41  	w.Close()
    42  }
    43  
    44  func reader(t *testing.T, r io.Reader, c chan int) {
    45  	var buf = make([]byte, 64)
    46  	for {
    47  		n, err := r.Read(buf)
    48  		if err == io.EOF {
    49  			c <- 0
    50  			break
    51  		}
    52  		if err != nil {
    53  			t.Errorf("read: %v", err)
    54  		}
    55  		c <- n
    56  	}
    57  }
    58  
    59  // Test a sequence of read/write pairs.
    60  func TestPipe2(t *testing.T) {
    61  	c := make(chan int)
    62  	r, w := Pipe()
    63  	go reader(t, r, c)
    64  	var buf = make([]byte, 64)
    65  	for i := 0; i < 5; i++ {
    66  		p := buf[0 : 5+i*10]
    67  		n, err := w.Write(p)
    68  		if n != len(p) {
    69  			t.Errorf("wrote %d, got %d", len(p), n)
    70  		}
    71  		if err != nil {
    72  			t.Errorf("write: %v", err)
    73  		}
    74  		nn := <-c
    75  		if nn != n {
    76  			t.Errorf("wrote %d, read got %d", n, nn)
    77  		}
    78  	}
    79  	w.Close()
    80  	nn := <-c
    81  	if nn != 0 {
    82  		t.Errorf("final read got %d", nn)
    83  	}
    84  }
    85  
    86  type pipeReturn struct {
    87  	n   int
    88  	err error
    89  }
    90  
    91  // Test a large write that requires multiple reads to satisfy.
    92  func writer(w io.WriteCloser, buf []byte, c chan pipeReturn) {
    93  	n, err := w.Write(buf)
    94  	w.Close()
    95  	c <- pipeReturn{n, err}
    96  }
    97  
    98  func TestPipe3(t *testing.T) {
    99  	c := make(chan pipeReturn)
   100  	r, w := Pipe()
   101  	var wdat = make([]byte, 128)
   102  	for i := 0; i < len(wdat); i++ {
   103  		wdat[i] = byte(i)
   104  	}
   105  	go writer(w, wdat, c)
   106  	var rdat = make([]byte, 1024)
   107  	tot := 0
   108  	for n := 1; n <= 256; n *= 2 {
   109  		nn, err := r.Read(rdat[tot : tot+n])
   110  		if err != nil && err != io.EOF {
   111  			t.Fatalf("read: %v", err)
   112  		}
   113  
   114  		// only final two reads should be short - 1 byte, then 0
   115  		expect := n
   116  		if n == 128 {
   117  			expect = 1
   118  		} else if n == 256 {
   119  			expect = 0
   120  			if err != io.EOF {
   121  				t.Fatalf("read at end: %v", err)
   122  			}
   123  		}
   124  		if nn != expect {
   125  			t.Fatalf("read %d, expected %d, got %d", n, expect, nn)
   126  		}
   127  		tot += nn
   128  	}
   129  	pr := <-c
   130  	if pr.n != 128 || pr.err != nil {
   131  		t.Fatalf("write 128: %d, %v", pr.n, pr.err)
   132  	}
   133  	if tot != 128 {
   134  		t.Fatalf("total read %d != 128", tot)
   135  	}
   136  	for i := 0; i < 128; i++ {
   137  		if rdat[i] != byte(i) {
   138  			t.Fatalf("rdat[%d] = %d", i, rdat[i])
   139  		}
   140  	}
   141  }
   142  
   143  // Test read after/before writer close.
   144  
   145  type closer interface {
   146  	CloseWithError(error) error
   147  	Close() error
   148  }
   149  
   150  type pipeTest struct {
   151  	async          bool
   152  	err            error
   153  	closeWithError bool
   154  }
   155  
   156  func (p pipeTest) String() string {
   157  	return fmt.Sprintf("async=%v err=%v closeWithError=%v", p.async, p.err, p.closeWithError)
   158  }
   159  
   160  var pipeTests = []pipeTest{
   161  	{true, nil, false},
   162  	{true, nil, true},
   163  	{true, io.ErrShortWrite, true},
   164  	{false, nil, false},
   165  	{false, nil, true},
   166  	{false, io.ErrShortWrite, true},
   167  }
   168  
   169  func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
   170  	time.Sleep(1 * time.Millisecond)
   171  	var err error
   172  	if tt.closeWithError {
   173  		err = cl.CloseWithError(tt.err)
   174  	} else {
   175  		err = cl.Close()
   176  	}
   177  	if err != nil {
   178  		t.Errorf("delayClose: %v", err)
   179  	}
   180  	ch <- 0
   181  }
   182  
   183  func TestPipeReadClose(t *testing.T) {
   184  	for _, tt := range pipeTests {
   185  		c := make(chan int, 1)
   186  		r, w := Pipe()
   187  		if tt.async {
   188  			go delayClose(t, w, c, tt)
   189  		} else {
   190  			delayClose(t, w, c, tt)
   191  		}
   192  		var buf = make([]byte, 64)
   193  		n, err := r.Read(buf)
   194  		<-c
   195  		want := tt.err
   196  		if want == nil {
   197  			want = io.EOF
   198  		}
   199  		if err != want {
   200  			t.Errorf("read from closed pipe: %v want %v", err, want)
   201  		}
   202  		if n != 0 {
   203  			t.Errorf("read on closed pipe returned %d", n)
   204  		}
   205  		if err = r.Close(); err != nil {
   206  			t.Errorf("r.Close: %v", err)
   207  		}
   208  	}
   209  }
   210  
   211  // Test close on Read side during Read.
   212  func TestPipeReadClose2(t *testing.T) {
   213  	c := make(chan int, 1)
   214  	r, _ := Pipe()
   215  	go delayClose(t, r, c, pipeTest{})
   216  	n, err := r.Read(make([]byte, 64))
   217  	<-c
   218  	if n != 0 || err != io.ErrClosedPipe {
   219  		t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, io.ErrClosedPipe)
   220  	}
   221  }
   222  
   223  // Test write after/before reader close.
   224  
   225  func TestPipeWriteClose(t *testing.T) {
   226  	bigbuf := make([]byte, minBufferSize+1)
   227  	for _, tt := range pipeTests {
   228  		c := make(chan int, 1)
   229  		r, w := FixedPipe(minBufferSize)
   230  		if tt.async {
   231  			go delayClose(t, r, c, tt)
   232  		} else {
   233  			delayClose(t, r, c, tt)
   234  		}
   235  		n, err := w.Write(bigbuf)
   236  		<-c
   237  		expect := tt.err
   238  		if expect == nil {
   239  			expect = io.ErrClosedPipe
   240  		}
   241  		if err != expect {
   242  			t.Errorf("write on closed pipe: %v want %v", err, expect)
   243  		}
   244  		if !tt.async && n != 0 {
   245  			t.Errorf("write on closed pipe returned %d", n)
   246  		}
   247  		if err = w.Close(); err != nil {
   248  			t.Errorf("w.Close: %v", err)
   249  		}
   250  	}
   251  }
   252  
   253  // Test close on Write side during Write.
   254  func TestPipeWriteClose2(t *testing.T) {
   255  	c := make(chan int, 1)
   256  	_, w := FixedPipe(minBufferSize)
   257  	go delayClose(t, w, c, pipeTest{})
   258  	_, err := w.Write(make([]byte, minBufferSize+1))
   259  	<-c
   260  	if err != io.ErrClosedPipe {
   261  		t.Errorf("write to closed pipe: %v want %v", err, io.ErrClosedPipe)
   262  	}
   263  }
   264  
   265  func TestWriteEmpty(t *testing.T) {
   266  	r, w := Pipe()
   267  	go func() {
   268  		w.Write([]byte{})
   269  		w.Close()
   270  	}()
   271  	var b [2]byte
   272  	io.ReadFull(r, b[0:2])
   273  	r.Close()
   274  }
   275  
   276  func TestWriteNil(t *testing.T) {
   277  	r, w := Pipe()
   278  	go func() {
   279  		w.Write(nil)
   280  		w.Close()
   281  	}()
   282  	var b [2]byte
   283  	io.ReadFull(r, b[0:2])
   284  	r.Close()
   285  }
   286  
   287  func TestWriteAfterWriterClose(t *testing.T) {
   288  	r, w := Pipe()
   289  
   290  	done := make(chan bool)
   291  	var writeErr error
   292  	go func() {
   293  		_, err := w.Write([]byte("hello"))
   294  		if err != nil {
   295  			t.Errorf("got error: %q; expected none", err)
   296  		}
   297  		w.Close()
   298  		_, writeErr = w.Write([]byte("world"))
   299  		done <- true
   300  	}()
   301  
   302  	buf := make([]byte, 100)
   303  	var result string
   304  	n, err := io.ReadFull(r, buf)
   305  	if err != nil && err != io.ErrUnexpectedEOF {
   306  		t.Fatalf("got: %q; want: %q", err, io.ErrUnexpectedEOF)
   307  	}
   308  	result = string(buf[0:n])
   309  	<-done
   310  
   311  	if result != "hello" {
   312  		t.Errorf("got: %q; want: %q", result, "hello")
   313  	}
   314  	if writeErr != io.ErrClosedPipe {
   315  		t.Errorf("got: %q; want: %q", writeErr, io.ErrClosedPipe)
   316  	}
   317  }