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 }