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