github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/os/timeout_test.go (about) 1 // Copyright 2017 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 // +build !nacl 6 // +build !plan9 7 // +build !windows 8 9 package os_test 10 11 import ( 12 "fmt" 13 "internal/poll" 14 "io" 15 "io/ioutil" 16 "math/rand" 17 "os" 18 "runtime" 19 "sync" 20 "testing" 21 "time" 22 ) 23 24 func TestNonpollableDeadline(t *testing.T) { 25 // On BSD systems regular files seem to be pollable, 26 // so just run this test on Linux. 27 if runtime.GOOS != "linux" { 28 t.Skipf("skipping on %s", runtime.GOOS) 29 } 30 31 f, err := ioutil.TempFile("", "ostest") 32 if err != nil { 33 t.Fatal(err) 34 } 35 defer os.Remove(f.Name()) 36 defer f.Close() 37 deadline := time.Now().Add(10 * time.Second) 38 if err := f.SetDeadline(deadline); err != os.ErrNoDeadline { 39 t.Errorf("SetDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline) 40 } 41 if err := f.SetReadDeadline(deadline); err != os.ErrNoDeadline { 42 t.Errorf("SetReadDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline) 43 } 44 if err := f.SetWriteDeadline(deadline); err != os.ErrNoDeadline { 45 t.Errorf("SetWriteDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline) 46 } 47 } 48 49 // noDeadline is a zero time.Time value, which cancels a deadline. 50 var noDeadline time.Time 51 52 var readTimeoutTests = []struct { 53 timeout time.Duration 54 xerrs [2]error // expected errors in transition 55 }{ 56 // Tests that read deadlines work, even if there's data ready 57 // to be read. 58 {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}}, 59 60 {50 * time.Millisecond, [2]error{nil, poll.ErrTimeout}}, 61 } 62 63 func TestReadTimeout(t *testing.T) { 64 t.Parallel() 65 66 r, w, err := os.Pipe() 67 if err != nil { 68 t.Fatal(err) 69 } 70 defer r.Close() 71 defer w.Close() 72 73 if _, err := w.Write([]byte("READ TIMEOUT TEST")); err != nil { 74 t.Fatal(err) 75 } 76 77 for i, tt := range readTimeoutTests { 78 if err := r.SetReadDeadline(time.Now().Add(tt.timeout)); err != nil { 79 t.Fatalf("#%d: %v", i, err) 80 } 81 var b [1]byte 82 for j, xerr := range tt.xerrs { 83 for { 84 n, err := r.Read(b[:]) 85 if xerr != nil { 86 if !os.IsTimeout(err) { 87 t.Fatalf("#%d/%d: %v", i, j, err) 88 } 89 } 90 if err == nil { 91 time.Sleep(tt.timeout / 3) 92 continue 93 } 94 if n != 0 { 95 t.Fatalf("#%d/%d: read %d; want 0", i, j, n) 96 } 97 break 98 } 99 } 100 } 101 } 102 103 func TestReadTimeoutMustNotReturn(t *testing.T) { 104 t.Parallel() 105 106 r, w, err := os.Pipe() 107 if err != nil { 108 t.Fatal(err) 109 } 110 defer r.Close() 111 defer w.Close() 112 113 max := time.NewTimer(100 * time.Millisecond) 114 defer max.Stop() 115 ch := make(chan error) 116 go func() { 117 if err := r.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { 118 t.Error(err) 119 } 120 if err := r.SetWriteDeadline(time.Now().Add(-5 * time.Second)); err != nil { 121 t.Error(err) 122 } 123 if err := r.SetReadDeadline(noDeadline); err != nil { 124 t.Error(err) 125 } 126 var b [1]byte 127 _, err := r.Read(b[:]) 128 ch <- err 129 }() 130 131 select { 132 case err := <-ch: 133 t.Fatalf("expected Read to not return, but it returned with %v", err) 134 case <-max.C: 135 w.Close() 136 err := <-ch // wait for tester goroutine to stop 137 if os.IsTimeout(err) { 138 t.Fatal(err) 139 } 140 } 141 } 142 143 var writeTimeoutTests = []struct { 144 timeout time.Duration 145 xerrs [2]error // expected errors in transition 146 }{ 147 // Tests that write deadlines work, even if there's buffer 148 // space available to write. 149 {-5 * time.Second, [2]error{poll.ErrTimeout, poll.ErrTimeout}}, 150 151 {10 * time.Millisecond, [2]error{nil, poll.ErrTimeout}}, 152 } 153 154 func TestWriteTimeout(t *testing.T) { 155 t.Parallel() 156 157 for i, tt := range writeTimeoutTests { 158 t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { 159 r, w, err := os.Pipe() 160 if err != nil { 161 t.Fatal(err) 162 } 163 defer r.Close() 164 defer w.Close() 165 166 if err := w.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil { 167 t.Fatalf("%v", err) 168 } 169 for j, xerr := range tt.xerrs { 170 for { 171 n, err := w.Write([]byte("WRITE TIMEOUT TEST")) 172 if xerr != nil { 173 if !os.IsTimeout(err) { 174 t.Fatalf("%d: %v", j, err) 175 } 176 } 177 if err == nil { 178 time.Sleep(tt.timeout / 3) 179 continue 180 } 181 if n != 0 { 182 t.Fatalf("%d: wrote %d; want 0", j, n) 183 } 184 break 185 } 186 } 187 }) 188 } 189 } 190 191 func TestWriteTimeoutMustNotReturn(t *testing.T) { 192 t.Parallel() 193 194 r, w, err := os.Pipe() 195 if err != nil { 196 t.Fatal(err) 197 } 198 defer r.Close() 199 defer w.Close() 200 201 max := time.NewTimer(100 * time.Millisecond) 202 defer max.Stop() 203 ch := make(chan error) 204 go func() { 205 if err := w.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { 206 t.Error(err) 207 } 208 if err := w.SetReadDeadline(time.Now().Add(-5 * time.Second)); err != nil { 209 t.Error(err) 210 } 211 if err := w.SetWriteDeadline(noDeadline); err != nil { 212 t.Error(err) 213 } 214 var b [1]byte 215 for { 216 if _, err := w.Write(b[:]); err != nil { 217 ch <- err 218 break 219 } 220 } 221 }() 222 223 select { 224 case err := <-ch: 225 t.Fatalf("expected Write to not return, but it returned with %v", err) 226 case <-max.C: 227 r.Close() 228 err := <-ch // wait for tester goroutine to stop 229 if os.IsTimeout(err) { 230 t.Fatal(err) 231 } 232 } 233 } 234 235 func timeoutReader(r *os.File, d, min, max time.Duration, ch chan<- error) { 236 var err error 237 defer func() { ch <- err }() 238 239 t0 := time.Now() 240 if err = r.SetReadDeadline(time.Now().Add(d)); err != nil { 241 return 242 } 243 b := make([]byte, 256) 244 var n int 245 n, err = r.Read(b) 246 t1 := time.Now() 247 if n != 0 || err == nil || !os.IsTimeout(err) { 248 err = fmt.Errorf("Read did not return (0, timeout): (%d, %v)", n, err) 249 return 250 } 251 if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() { 252 err = fmt.Errorf("Read took %s; expected %s", dt, d) 253 return 254 } 255 } 256 257 func TestReadTimeoutFluctuation(t *testing.T) { 258 t.Parallel() 259 260 r, w, err := os.Pipe() 261 if err != nil { 262 t.Fatal(err) 263 } 264 defer r.Close() 265 defer w.Close() 266 267 max := time.NewTimer(time.Second) 268 defer max.Stop() 269 ch := make(chan error) 270 go timeoutReader(r, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch) 271 272 select { 273 case <-max.C: 274 t.Fatal("Read took over 1s; expected 0.1s") 275 case err := <-ch: 276 if !os.IsTimeout(err) { 277 t.Fatal(err) 278 } 279 } 280 } 281 282 func timeoutWriter(w *os.File, d, min, max time.Duration, ch chan<- error) { 283 var err error 284 defer func() { ch <- err }() 285 286 t0 := time.Now() 287 if err = w.SetWriteDeadline(time.Now().Add(d)); err != nil { 288 return 289 } 290 var n int 291 for { 292 n, err = w.Write([]byte("TIMEOUT WRITER")) 293 if err != nil { 294 break 295 } 296 } 297 t1 := time.Now() 298 if err == nil || !os.IsTimeout(err) { 299 err = fmt.Errorf("Write did not return (any, timeout): (%d, %v)", n, err) 300 return 301 } 302 if dt := t1.Sub(t0); min > dt || dt > max && !testing.Short() { 303 err = fmt.Errorf("Write took %s; expected %s", dt, d) 304 return 305 } 306 } 307 308 func TestWriteTimeoutFluctuation(t *testing.T) { 309 t.Parallel() 310 311 r, w, err := os.Pipe() 312 if err != nil { 313 t.Fatal(err) 314 } 315 defer r.Close() 316 defer w.Close() 317 318 d := time.Second 319 max := time.NewTimer(d) 320 defer max.Stop() 321 ch := make(chan error) 322 go timeoutWriter(w, 100*time.Millisecond, 50*time.Millisecond, 250*time.Millisecond, ch) 323 324 select { 325 case <-max.C: 326 t.Fatalf("Write took over %v; expected 0.1s", d) 327 case err := <-ch: 328 if !os.IsTimeout(err) { 329 t.Fatal(err) 330 } 331 } 332 } 333 334 func TestVariousDeadlines(t *testing.T) { 335 t.Parallel() 336 testVariousDeadlines(t) 337 } 338 339 func TestVariousDeadlines1Proc(t *testing.T) { 340 // Cannot use t.Parallel - modifies global GOMAXPROCS. 341 if testing.Short() { 342 t.Skip("skipping in short mode") 343 } 344 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) 345 testVariousDeadlines(t) 346 } 347 348 func TestVariousDeadlines4Proc(t *testing.T) { 349 // Cannot use t.Parallel - modifies global GOMAXPROCS. 350 if testing.Short() { 351 t.Skip("skipping in short mode") 352 } 353 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 354 testVariousDeadlines(t) 355 } 356 357 type neverEnding byte 358 359 func (b neverEnding) Read(p []byte) (int, error) { 360 for i := range p { 361 p[i] = byte(b) 362 } 363 return len(p), nil 364 } 365 366 func testVariousDeadlines(t *testing.T) { 367 type result struct { 368 n int64 369 err error 370 d time.Duration 371 } 372 373 handler := func(w *os.File, pasvch chan result) { 374 // The writer, with no timeouts of its own, 375 // sending bytes to clients as fast as it can. 376 t0 := time.Now() 377 n, err := io.Copy(w, neverEnding('a')) 378 dt := time.Since(t0) 379 pasvch <- result{n, err, dt} 380 } 381 382 for _, timeout := range []time.Duration{ 383 1 * time.Nanosecond, 384 2 * time.Nanosecond, 385 5 * time.Nanosecond, 386 50 * time.Nanosecond, 387 100 * time.Nanosecond, 388 200 * time.Nanosecond, 389 500 * time.Nanosecond, 390 750 * time.Nanosecond, 391 1 * time.Microsecond, 392 5 * time.Microsecond, 393 25 * time.Microsecond, 394 250 * time.Microsecond, 395 500 * time.Microsecond, 396 1 * time.Millisecond, 397 5 * time.Millisecond, 398 100 * time.Millisecond, 399 250 * time.Millisecond, 400 500 * time.Millisecond, 401 1 * time.Second, 402 } { 403 numRuns := 3 404 if testing.Short() { 405 numRuns = 1 406 if timeout > 500*time.Microsecond { 407 continue 408 } 409 } 410 for run := 0; run < numRuns; run++ { 411 t.Run(fmt.Sprintf("%v-%d", timeout, run+1), func(t *testing.T) { 412 r, w, err := os.Pipe() 413 if err != nil { 414 t.Fatal(err) 415 } 416 defer r.Close() 417 defer w.Close() 418 419 pasvch := make(chan result) 420 go handler(w, pasvch) 421 422 tooLong := 5 * time.Second 423 max := time.NewTimer(tooLong) 424 defer max.Stop() 425 actvch := make(chan result) 426 go func() { 427 t0 := time.Now() 428 if err := r.SetDeadline(t0.Add(timeout)); err != nil { 429 t.Error(err) 430 } 431 n, err := io.Copy(ioutil.Discard, r) 432 dt := time.Since(t0) 433 r.Close() 434 actvch <- result{n, err, dt} 435 }() 436 437 select { 438 case res := <-actvch: 439 if os.IsTimeout(res.err) { 440 t.Logf("good client timeout after %v, reading %d bytes", res.d, res.n) 441 } else { 442 t.Fatalf("client Copy = %d, %v; want timeout", res.n, res.err) 443 } 444 case <-max.C: 445 t.Fatalf("timeout (%v) waiting for client to timeout (%v) reading", tooLong, timeout) 446 } 447 448 select { 449 case res := <-pasvch: 450 t.Logf("writer in %v wrote %d: %v", res.d, res.n, res.err) 451 case <-max.C: 452 t.Fatalf("timeout waiting for writer to finish writing") 453 } 454 }) 455 } 456 } 457 } 458 459 func TestReadWriteDeadlineRace(t *testing.T) { 460 t.Parallel() 461 462 N := 1000 463 if testing.Short() { 464 N = 50 465 } 466 467 r, w, err := os.Pipe() 468 if err != nil { 469 t.Fatal(err) 470 } 471 defer r.Close() 472 defer w.Close() 473 474 var wg sync.WaitGroup 475 wg.Add(3) 476 go func() { 477 defer wg.Done() 478 tic := time.NewTicker(2 * time.Microsecond) 479 defer tic.Stop() 480 for i := 0; i < N; i++ { 481 if err := r.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil { 482 break 483 } 484 if err := w.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil { 485 break 486 } 487 <-tic.C 488 } 489 }() 490 go func() { 491 defer wg.Done() 492 var b [1]byte 493 for i := 0; i < N; i++ { 494 _, err := r.Read(b[:]) 495 if err != nil && !os.IsTimeout(err) { 496 t.Error("Read returned non-timeout error", err) 497 } 498 } 499 }() 500 go func() { 501 defer wg.Done() 502 var b [1]byte 503 for i := 0; i < N; i++ { 504 _, err := w.Write(b[:]) 505 if err != nil && !os.IsTimeout(err) { 506 t.Error("Write returned non-timeout error", err) 507 } 508 } 509 }() 510 wg.Wait() // wait for tester goroutine to stop 511 } 512 513 // TestRacyRead tests that it is safe to mutate the input Read buffer 514 // immediately after cancelation has occurred. 515 func TestRacyRead(t *testing.T) { 516 t.Parallel() 517 518 r, w, err := os.Pipe() 519 if err != nil { 520 t.Fatal(err) 521 } 522 defer r.Close() 523 defer w.Close() 524 525 var wg sync.WaitGroup 526 defer wg.Wait() 527 528 go io.Copy(w, rand.New(rand.NewSource(0))) 529 530 r.SetReadDeadline(time.Now().Add(time.Millisecond)) 531 for i := 0; i < 10; i++ { 532 wg.Add(1) 533 go func() { 534 defer wg.Done() 535 536 b1 := make([]byte, 1024) 537 b2 := make([]byte, 1024) 538 for j := 0; j < 100; j++ { 539 _, err := r.Read(b1) 540 copy(b1, b2) // Mutate b1 to trigger potential race 541 if err != nil { 542 if !os.IsTimeout(err) { 543 t.Error(err) 544 } 545 r.SetReadDeadline(time.Now().Add(time.Millisecond)) 546 } 547 } 548 }() 549 } 550 } 551 552 // TestRacyWrite tests that it is safe to mutate the input Write buffer 553 // immediately after cancelation has occurred. 554 func TestRacyWrite(t *testing.T) { 555 t.Parallel() 556 557 r, w, err := os.Pipe() 558 if err != nil { 559 t.Fatal(err) 560 } 561 defer r.Close() 562 defer w.Close() 563 564 var wg sync.WaitGroup 565 defer wg.Wait() 566 567 go io.Copy(ioutil.Discard, r) 568 569 w.SetWriteDeadline(time.Now().Add(time.Millisecond)) 570 for i := 0; i < 10; i++ { 571 wg.Add(1) 572 go func() { 573 defer wg.Done() 574 575 b1 := make([]byte, 1024) 576 b2 := make([]byte, 1024) 577 for j := 0; j < 100; j++ { 578 _, err := w.Write(b1) 579 copy(b1, b2) // Mutate b1 to trigger potential race 580 if err != nil { 581 if !os.IsTimeout(err) { 582 t.Error(err) 583 } 584 w.SetWriteDeadline(time.Now().Add(time.Millisecond)) 585 } 586 } 587 }() 588 } 589 }