github.com/c9s/go@v0.0.0-20180120015821-984e81f64e0c/src/io/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 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 != (testError2{}) { 330 t.Errorf("Write error: got %T, want testError2", 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 != (testError2{}) { 340 t.Errorf("Read error: got %T, want testError2", 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 }