Black Lives Matter. Support the Equal Justice Initiative.

Source file src/io/pipe_test.go

Documentation: io

     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  
     5  package io_test
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	. "io"
    11  	"sort"
    12  	"strings"
    13  	"testing"
    14  	"time"
    15  )
    16  
    17  func checkWrite(t *testing.T, w Writer, data []byte, c chan int) {
    18  	n, err := w.Write(data)
    19  	if err != nil {
    20  		t.Errorf("write: %v", err)
    21  	}
    22  	if n != len(data) {
    23  		t.Errorf("short write: %d != %d", n, len(data))
    24  	}
    25  	c <- 0
    26  }
    27  
    28  // Test a single read/write pair.
    29  func TestPipe1(t *testing.T) {
    30  	c := make(chan int)
    31  	r, w := Pipe()
    32  	var buf = make([]byte, 64)
    33  	go checkWrite(t, w, []byte("hello, world"), c)
    34  	n, err := r.Read(buf)
    35  	if err != nil {
    36  		t.Errorf("read: %v", err)
    37  	} else if n != 12 || string(buf[0:12]) != "hello, world" {
    38  		t.Errorf("bad read: got %q", buf[0:n])
    39  	}
    40  	<-c
    41  	r.Close()
    42  	w.Close()
    43  }
    44  
    45  func reader(t *testing.T, r Reader, c chan int) {
    46  	var buf = make([]byte, 64)
    47  	for {
    48  		n, err := r.Read(buf)
    49  		if err == EOF {
    50  			c <- 0
    51  			break
    52  		}
    53  		if err != nil {
    54  			t.Errorf("read: %v", err)
    55  		}
    56  		c <- n
    57  	}
    58  }
    59  
    60  // Test a sequence of read/write pairs.
    61  func TestPipe2(t *testing.T) {
    62  	c := make(chan int)
    63  	r, w := Pipe()
    64  	go reader(t, r, c)
    65  	var buf = make([]byte, 64)
    66  	for i := 0; i < 5; i++ {
    67  		p := buf[0 : 5+i*10]
    68  		n, err := w.Write(p)
    69  		if n != len(p) {
    70  			t.Errorf("wrote %d, got %d", len(p), n)
    71  		}
    72  		if err != nil {
    73  			t.Errorf("write: %v", err)
    74  		}
    75  		nn := <-c
    76  		if nn != n {
    77  			t.Errorf("wrote %d, read got %d", n, nn)
    78  		}
    79  	}
    80  	w.Close()
    81  	nn := <-c
    82  	if nn != 0 {
    83  		t.Errorf("final read got %d", nn)
    84  	}
    85  }
    86  
    87  type pipeReturn struct {
    88  	n   int
    89  	err error
    90  }
    91  
    92  // Test a large write that requires multiple reads to satisfy.
    93  func writer(w WriteCloser, buf []byte, c chan pipeReturn) {
    94  	n, err := w.Write(buf)
    95  	w.Close()
    96  	c <- pipeReturn{n, err}
    97  }
    98  
    99  func TestPipe3(t *testing.T) {
   100  	c := make(chan pipeReturn)
   101  	r, w := Pipe()
   102  	var wdat = make([]byte, 128)
   103  	for i := 0; i < len(wdat); i++ {
   104  		wdat[i] = byte(i)
   105  	}
   106  	go writer(w, wdat, c)
   107  	var rdat = make([]byte, 1024)
   108  	tot := 0
   109  	for n := 1; n <= 256; n *= 2 {
   110  		nn, err := r.Read(rdat[tot : tot+n])
   111  		if err != nil && err != EOF {
   112  			t.Fatalf("read: %v", err)
   113  		}
   114  
   115  		// only final two reads should be short - 1 byte, then 0
   116  		expect := n
   117  		if n == 128 {
   118  			expect = 1
   119  		} else if n == 256 {
   120  			expect = 0
   121  			if err != EOF {
   122  				t.Fatalf("read at end: %v", err)
   123  			}
   124  		}
   125  		if nn != expect {
   126  			t.Fatalf("read %d, expected %d, got %d", n, expect, nn)
   127  		}
   128  		tot += nn
   129  	}
   130  	pr := <-c
   131  	if pr.n != 128 || pr.err != nil {
   132  		t.Fatalf("write 128: %d, %v", pr.n, pr.err)
   133  	}
   134  	if tot != 128 {
   135  		t.Fatalf("total read %d != 128", tot)
   136  	}
   137  	for i := 0; i < 128; i++ {
   138  		if rdat[i] != byte(i) {
   139  			t.Fatalf("rdat[%d] = %d", i, rdat[i])
   140  		}
   141  	}
   142  }
   143  
   144  // Test read after/before writer close.
   145  
   146  type closer interface {
   147  	CloseWithError(error) error
   148  	Close() error
   149  }
   150  
   151  type pipeTest struct {
   152  	async          bool
   153  	err            error
   154  	closeWithError bool
   155  }
   156  
   157  func (p pipeTest) String() string {
   158  	return fmt.Sprintf("async=%v err=%v closeWithError=%v", p.async, p.err, p.closeWithError)
   159  }
   160  
   161  var pipeTests = []pipeTest{
   162  	{true, nil, false},
   163  	{true, nil, true},
   164  	{true, ErrShortWrite, true},
   165  	{false, nil, false},
   166  	{false, nil, true},
   167  	{false, ErrShortWrite, true},
   168  }
   169  
   170  func delayClose(t *testing.T, cl closer, ch chan int, tt pipeTest) {
   171  	time.Sleep(1 * time.Millisecond)
   172  	var err error
   173  	if tt.closeWithError {
   174  		err = cl.CloseWithError(tt.err)
   175  	} else {
   176  		err = cl.Close()
   177  	}
   178  	if err != nil {
   179  		t.Errorf("delayClose: %v", err)
   180  	}
   181  	ch <- 0
   182  }
   183  
   184  func TestPipeReadClose(t *testing.T) {
   185  	for _, tt := range pipeTests {
   186  		c := make(chan int, 1)
   187  		r, w := Pipe()
   188  		if tt.async {
   189  			go delayClose(t, w, c, tt)
   190  		} else {
   191  			delayClose(t, w, c, tt)
   192  		}
   193  		var buf = make([]byte, 64)
   194  		n, err := r.Read(buf)
   195  		<-c
   196  		want := tt.err
   197  		if want == nil {
   198  			want = EOF
   199  		}
   200  		if err != want {
   201  			t.Errorf("read from closed pipe: %v want %v", err, want)
   202  		}
   203  		if n != 0 {
   204  			t.Errorf("read on closed pipe returned %d", n)
   205  		}
   206  		if err = r.Close(); err != nil {
   207  			t.Errorf("r.Close: %v", err)
   208  		}
   209  	}
   210  }
   211  
   212  // Test close on Read side during Read.
   213  func TestPipeReadClose2(t *testing.T) {
   214  	c := make(chan int, 1)
   215  	r, _ := Pipe()
   216  	go delayClose(t, r, c, pipeTest{})
   217  	n, err := r.Read(make([]byte, 64))
   218  	<-c
   219  	if n != 0 || err != ErrClosedPipe {
   220  		t.Errorf("read from closed pipe: %v, %v want %v, %v", n, err, 0, ErrClosedPipe)
   221  	}
   222  }
   223  
   224  // Test write after/before reader close.
   225  
   226  func TestPipeWriteClose(t *testing.T) {
   227  	for _, tt := range pipeTests {
   228  		c := make(chan int, 1)
   229  		r, w := Pipe()
   230  		if tt.async {
   231  			go delayClose(t, r, c, tt)
   232  		} else {
   233  			delayClose(t, r, c, tt)
   234  		}
   235  		n, err := WriteString(w, "hello, world")
   236  		<-c
   237  		expect := tt.err
   238  		if expect == nil {
   239  			expect = ErrClosedPipe
   240  		}
   241  		if err != expect {
   242  			t.Errorf("write on closed pipe: %v want %v", err, expect)
   243  		}
   244  		if 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 := Pipe()
   257  	go delayClose(t, w, c, pipeTest{})
   258  	n, err := w.Write(make([]byte, 64))
   259  	<-c
   260  	if n != 0 || err != ErrClosedPipe {
   261  		t.Errorf("write to closed pipe: %v, %v want %v, %v", n, err, 0, 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  	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  	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 := ReadFull(r, buf)
   305  	if err != nil && err != ErrUnexpectedEOF {
   306  		t.Fatalf("got: %q; want: %q", err, 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 != ErrClosedPipe {
   315  		t.Errorf("got: %q; want: %q", writeErr, ErrClosedPipe)
   316  	}
   317  }
   318  
   319  func TestPipeCloseError(t *testing.T) {
   320  	type testError1 struct{ error }
   321  	type testError2 struct{ error }
   322  
   323  	r, w := Pipe()
   324  	r.CloseWithError(testError1{})
   325  	if _, err := w.Write(nil); err != (testError1{}) {
   326  		t.Errorf("Write error: got %T, want testError1", err)
   327  	}
   328  	r.CloseWithError(testError2{})
   329  	if _, err := w.Write(nil); err != (testError1{}) {
   330  		t.Errorf("Write error: got %T, want testError1", err)
   331  	}
   332  
   333  	r, w = Pipe()
   334  	w.CloseWithError(testError1{})
   335  	if _, err := r.Read(nil); err != (testError1{}) {
   336  		t.Errorf("Read error: got %T, want testError1", err)
   337  	}
   338  	w.CloseWithError(testError2{})
   339  	if _, err := r.Read(nil); err != (testError1{}) {
   340  		t.Errorf("Read error: got %T, want testError1", err)
   341  	}
   342  }
   343  
   344  func TestPipeConcurrent(t *testing.T) {
   345  	const (
   346  		input    = "0123456789abcdef"
   347  		count    = 8
   348  		readSize = 2
   349  	)
   350  
   351  	t.Run("Write", func(t *testing.T) {
   352  		r, w := Pipe()
   353  
   354  		for i := 0; i < count; i++ {
   355  			go func() {
   356  				time.Sleep(time.Millisecond) // Increase probability of race
   357  				if n, err := w.Write([]byte(input)); n != len(input) || err != nil {
   358  					t.Errorf("Write() = (%d, %v); want (%d, nil)", n, err, len(input))
   359  				}
   360  			}()
   361  		}
   362  
   363  		buf := make([]byte, count*len(input))
   364  		for i := 0; i < len(buf); i += readSize {
   365  			if n, err := r.Read(buf[i : i+readSize]); n != readSize || err != nil {
   366  				t.Errorf("Read() = (%d, %v); want (%d, nil)", n, err, readSize)
   367  			}
   368  		}
   369  
   370  		// Since each Write is fully gated, if multiple Read calls were needed,
   371  		// the contents of Write should still appear together in the output.
   372  		got := string(buf)
   373  		want := strings.Repeat(input, count)
   374  		if got != want {
   375  			t.Errorf("got: %q; want: %q", got, want)
   376  		}
   377  	})
   378  
   379  	t.Run("Read", func(t *testing.T) {
   380  		r, w := Pipe()
   381  
   382  		c := make(chan []byte, count*len(input)/readSize)
   383  		for i := 0; i < cap(c); i++ {
   384  			go func() {
   385  				time.Sleep(time.Millisecond) // Increase probability of race
   386  				buf := make([]byte, readSize)
   387  				if n, err := r.Read(buf); n != readSize || err != nil {
   388  					t.Errorf("Read() = (%d, %v); want (%d, nil)", n, err, readSize)
   389  				}
   390  				c <- buf
   391  			}()
   392  		}
   393  
   394  		for i := 0; i < count; i++ {
   395  			if n, err := w.Write([]byte(input)); n != len(input) || err != nil {
   396  				t.Errorf("Write() = (%d, %v); want (%d, nil)", n, err, len(input))
   397  			}
   398  		}
   399  
   400  		// Since each read is independent, the only guarantee about the output
   401  		// is that it is a permutation of the input in readSized groups.
   402  		got := make([]byte, 0, count*len(input))
   403  		for i := 0; i < cap(c); i++ {
   404  			got = append(got, (<-c)...)
   405  		}
   406  		got = sortBytesInGroups(got, readSize)
   407  		want := bytes.Repeat([]byte(input), count)
   408  		want = sortBytesInGroups(want, readSize)
   409  		if string(got) != string(want) {
   410  			t.Errorf("got: %q; want: %q", got, want)
   411  		}
   412  	})
   413  }
   414  
   415  func sortBytesInGroups(b []byte, n int) []byte {
   416  	var groups [][]byte
   417  	for len(b) > 0 {
   418  		groups = append(groups, b[:n])
   419  		b = b[n:]
   420  	}
   421  	sort.Slice(groups, func(i, j int) bool { return bytes.Compare(groups[i], groups[j]) < 0 })
   422  	return bytes.Join(groups, nil)
   423  }
   424  

View as plain text