github.com/mtsmfm/go/src@v0.0.0-20221020090648-44bdcb9f8fde/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 7 package os_test 8 9 import ( 10 "fmt" 11 "io" 12 "math/rand" 13 "os" 14 "os/signal" 15 "runtime" 16 "sync" 17 "syscall" 18 "testing" 19 "time" 20 ) 21 22 func TestNonpollableDeadline(t *testing.T) { 23 // On BSD systems regular files seem to be pollable, 24 // so just run this test on Linux. 25 if runtime.GOOS != "linux" { 26 t.Skipf("skipping on %s", runtime.GOOS) 27 } 28 29 f, err := os.CreateTemp("", "ostest") 30 if err != nil { 31 t.Fatal(err) 32 } 33 defer os.Remove(f.Name()) 34 defer f.Close() 35 deadline := time.Now().Add(10 * time.Second) 36 if err := f.SetDeadline(deadline); err != os.ErrNoDeadline { 37 t.Errorf("SetDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline) 38 } 39 if err := f.SetReadDeadline(deadline); err != os.ErrNoDeadline { 40 t.Errorf("SetReadDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline) 41 } 42 if err := f.SetWriteDeadline(deadline); err != os.ErrNoDeadline { 43 t.Errorf("SetWriteDeadline on file returned %v, wanted %v", err, os.ErrNoDeadline) 44 } 45 } 46 47 // noDeadline is a zero time.Time value, which cancels a deadline. 48 var noDeadline time.Time 49 50 var readTimeoutTests = []struct { 51 timeout time.Duration 52 xerrs [2]error // expected errors in transition 53 }{ 54 // Tests that read deadlines work, even if there's data ready 55 // to be read. 56 {-5 * time.Second, [2]error{os.ErrDeadlineExceeded, os.ErrDeadlineExceeded}}, 57 58 {50 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}}, 59 } 60 61 // There is a very similar copy of this in net/timeout_test.go. 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 // There is a very similar copy of this in net/timeout_test.go. 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{os.ErrDeadlineExceeded, os.ErrDeadlineExceeded}}, 150 151 {10 * time.Millisecond, [2]error{nil, os.ErrDeadlineExceeded}}, 152 } 153 154 // There is a very similar copy of this in net/timeout_test.go. 155 func TestWriteTimeout(t *testing.T) { 156 t.Parallel() 157 158 for i, tt := range writeTimeoutTests { 159 t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) { 160 r, w, err := os.Pipe() 161 if err != nil { 162 t.Fatal(err) 163 } 164 defer r.Close() 165 defer w.Close() 166 167 if err := w.SetWriteDeadline(time.Now().Add(tt.timeout)); err != nil { 168 t.Fatalf("%v", err) 169 } 170 for j, xerr := range tt.xerrs { 171 for { 172 n, err := w.Write([]byte("WRITE TIMEOUT TEST")) 173 if xerr != nil { 174 if !isDeadlineExceeded(err) { 175 t.Fatalf("%d: %v", j, err) 176 } 177 } 178 if err == nil { 179 time.Sleep(tt.timeout / 3) 180 continue 181 } 182 if n != 0 { 183 t.Fatalf("%d: wrote %d; want 0", j, n) 184 } 185 break 186 } 187 } 188 }) 189 } 190 } 191 192 // There is a very similar copy of this in net/timeout_test.go. 193 func TestWriteTimeoutMustNotReturn(t *testing.T) { 194 t.Parallel() 195 196 r, w, err := os.Pipe() 197 if err != nil { 198 t.Fatal(err) 199 } 200 defer r.Close() 201 defer w.Close() 202 203 max := time.NewTimer(100 * time.Millisecond) 204 defer max.Stop() 205 ch := make(chan error) 206 go func() { 207 if err := w.SetDeadline(time.Now().Add(-5 * time.Second)); err != nil { 208 t.Error(err) 209 } 210 if err := w.SetReadDeadline(time.Now().Add(-5 * time.Second)); err != nil { 211 t.Error(err) 212 } 213 if err := w.SetWriteDeadline(noDeadline); err != nil { 214 t.Error(err) 215 } 216 var b [1]byte 217 for { 218 if _, err := w.Write(b[:]); err != nil { 219 ch <- err 220 break 221 } 222 } 223 }() 224 225 select { 226 case err := <-ch: 227 t.Fatalf("expected Write to not return, but it returned with %v", err) 228 case <-max.C: 229 r.Close() 230 err := <-ch // wait for tester goroutine to stop 231 if os.IsTimeout(err) { 232 t.Fatal(err) 233 } 234 } 235 } 236 237 const ( 238 // minDynamicTimeout is the minimum timeout to attempt for 239 // tests that automatically increase timeouts until success. 240 // 241 // Lower values may allow tests to succeed more quickly if the value is close 242 // to the true minimum, but may require more iterations (and waste more time 243 // and CPU power on failed attempts) if the timeout is too low. 244 minDynamicTimeout = 1 * time.Millisecond 245 246 // maxDynamicTimeout is the maximum timeout to attempt for 247 // tests that automatically increase timeouts until succeess. 248 // 249 // This should be a strict upper bound on the latency required to hit a 250 // timeout accurately, even on a slow or heavily-loaded machine. If a test 251 // would increase the timeout beyond this value, the test fails. 252 maxDynamicTimeout = 4 * time.Second 253 ) 254 255 // timeoutUpperBound returns the maximum time that we expect a timeout of 256 // duration d to take to return the caller. 257 func timeoutUpperBound(d time.Duration) time.Duration { 258 switch runtime.GOOS { 259 case "openbsd", "netbsd": 260 // NetBSD and OpenBSD seem to be unable to reliably hit deadlines even when 261 // the absolute durations are long. 262 // In https://build.golang.org/log/c34f8685d020b98377dd4988cd38f0c5bd72267e, 263 // we observed that an openbsd-amd64-68 builder took 4.090948779s for a 264 // 2.983020682s timeout (37.1% overhead). 265 // (See https://go.dev/issue/50189 for further detail.) 266 // Give them lots of slop to compensate. 267 return d * 3 / 2 268 } 269 // Other platforms seem to hit their deadlines more reliably, 270 // at least when they are long enough to cover scheduling jitter. 271 return d * 11 / 10 272 } 273 274 // nextTimeout returns the next timeout to try after an operation took the given 275 // actual duration with a timeout shorter than that duration. 276 func nextTimeout(actual time.Duration) (next time.Duration, ok bool) { 277 if actual >= maxDynamicTimeout { 278 return maxDynamicTimeout, false 279 } 280 // Since the previous attempt took actual, we can't expect to beat that 281 // duration by any significant margin. Try the next attempt with an arbitrary 282 // factor above that, so that our growth curve is at least exponential. 283 next = actual * 5 / 4 284 if next > maxDynamicTimeout { 285 return maxDynamicTimeout, true 286 } 287 return next, true 288 } 289 290 // There is a very similar copy of this in net/timeout_test.go. 291 func TestReadTimeoutFluctuation(t *testing.T) { 292 t.Parallel() 293 294 r, w, err := os.Pipe() 295 if err != nil { 296 t.Fatal(err) 297 } 298 defer r.Close() 299 defer w.Close() 300 301 d := minDynamicTimeout 302 b := make([]byte, 256) 303 for { 304 t.Logf("SetReadDeadline(+%v)", d) 305 t0 := time.Now() 306 deadline := t0.Add(d) 307 if err = r.SetReadDeadline(deadline); err != nil { 308 t.Fatalf("SetReadDeadline(%v): %v", deadline, err) 309 } 310 var n int 311 n, err = r.Read(b) 312 t1 := time.Now() 313 314 if n != 0 || err == nil || !isDeadlineExceeded(err) { 315 t.Errorf("Read did not return (0, timeout): (%d, %v)", n, err) 316 } 317 318 actual := t1.Sub(t0) 319 if t1.Before(deadline) { 320 t.Errorf("Read took %s; expected at least %s", actual, d) 321 } 322 if t.Failed() { 323 return 324 } 325 if want := timeoutUpperBound(d); actual > want { 326 next, ok := nextTimeout(actual) 327 if !ok { 328 t.Fatalf("Read took %s; expected at most %v", actual, want) 329 } 330 // Maybe this machine is too slow to reliably schedule goroutines within 331 // the requested duration. Increase the timeout and try again. 332 t.Logf("Read took %s (expected %s); trying with longer timeout", actual, d) 333 d = next 334 continue 335 } 336 337 break 338 } 339 } 340 341 // There is a very similar copy of this in net/timeout_test.go. 342 func TestWriteTimeoutFluctuation(t *testing.T) { 343 t.Parallel() 344 345 r, w, err := os.Pipe() 346 if err != nil { 347 t.Fatal(err) 348 } 349 defer r.Close() 350 defer w.Close() 351 352 d := minDynamicTimeout 353 for { 354 t.Logf("SetWriteDeadline(+%v)", d) 355 t0 := time.Now() 356 deadline := t0.Add(d) 357 if err = w.SetWriteDeadline(deadline); err != nil { 358 t.Fatalf("SetWriteDeadline(%v): %v", deadline, err) 359 } 360 var n int64 361 for { 362 var dn int 363 dn, err = w.Write([]byte("TIMEOUT TRANSMITTER")) 364 n += int64(dn) 365 if err != nil { 366 break 367 } 368 } 369 t1 := time.Now() 370 371 if err == nil || !isDeadlineExceeded(err) { 372 t.Fatalf("Write did not return (any, timeout): (%d, %v)", n, err) 373 } 374 375 actual := t1.Sub(t0) 376 if t1.Before(deadline) { 377 t.Errorf("Write took %s; expected at least %s", actual, d) 378 } 379 if t.Failed() { 380 return 381 } 382 if want := timeoutUpperBound(d); actual > want { 383 if n > 0 { 384 // SetWriteDeadline specifies a time “after which I/O operations fail 385 // instead of blocking”. However, the kernel's send buffer is not yet 386 // full, we may be able to write some arbitrary (but finite) number of 387 // bytes to it without blocking. 388 t.Logf("Wrote %d bytes into send buffer; retrying until buffer is full", n) 389 if d <= maxDynamicTimeout/2 { 390 // We don't know how long the actual write loop would have taken if 391 // the buffer were full, so just guess and double the duration so that 392 // the next attempt can make twice as much progress toward filling it. 393 d *= 2 394 } 395 } else if next, ok := nextTimeout(actual); !ok { 396 t.Fatalf("Write took %s; expected at most %s", actual, want) 397 } else { 398 // Maybe this machine is too slow to reliably schedule goroutines within 399 // the requested duration. Increase the timeout and try again. 400 t.Logf("Write took %s (expected %s); trying with longer timeout", actual, d) 401 d = next 402 } 403 continue 404 } 405 406 break 407 } 408 } 409 410 // There is a very similar copy of this in net/timeout_test.go. 411 func TestVariousDeadlines(t *testing.T) { 412 t.Parallel() 413 testVariousDeadlines(t) 414 } 415 416 // There is a very similar copy of this in net/timeout_test.go. 417 func TestVariousDeadlines1Proc(t *testing.T) { 418 // Cannot use t.Parallel - modifies global GOMAXPROCS. 419 if testing.Short() { 420 t.Skip("skipping in short mode") 421 } 422 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(1)) 423 testVariousDeadlines(t) 424 } 425 426 // There is a very similar copy of this in net/timeout_test.go. 427 func TestVariousDeadlines4Proc(t *testing.T) { 428 // Cannot use t.Parallel - modifies global GOMAXPROCS. 429 if testing.Short() { 430 t.Skip("skipping in short mode") 431 } 432 defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4)) 433 testVariousDeadlines(t) 434 } 435 436 type neverEnding byte 437 438 func (b neverEnding) Read(p []byte) (int, error) { 439 for i := range p { 440 p[i] = byte(b) 441 } 442 return len(p), nil 443 } 444 445 func testVariousDeadlines(t *testing.T) { 446 type result struct { 447 n int64 448 err error 449 d time.Duration 450 } 451 452 handler := func(w *os.File, pasvch chan result) { 453 // The writer, with no timeouts of its own, 454 // sending bytes to clients as fast as it can. 455 t0 := time.Now() 456 n, err := io.Copy(w, neverEnding('a')) 457 dt := time.Since(t0) 458 pasvch <- result{n, err, dt} 459 } 460 461 for _, timeout := range []time.Duration{ 462 1 * time.Nanosecond, 463 2 * time.Nanosecond, 464 5 * time.Nanosecond, 465 50 * time.Nanosecond, 466 100 * time.Nanosecond, 467 200 * time.Nanosecond, 468 500 * time.Nanosecond, 469 750 * time.Nanosecond, 470 1 * time.Microsecond, 471 5 * time.Microsecond, 472 25 * time.Microsecond, 473 250 * time.Microsecond, 474 500 * time.Microsecond, 475 1 * time.Millisecond, 476 5 * time.Millisecond, 477 100 * time.Millisecond, 478 250 * time.Millisecond, 479 500 * time.Millisecond, 480 1 * time.Second, 481 } { 482 numRuns := 3 483 if testing.Short() { 484 numRuns = 1 485 if timeout > 500*time.Microsecond { 486 continue 487 } 488 } 489 for run := 0; run < numRuns; run++ { 490 t.Run(fmt.Sprintf("%v-%d", timeout, run+1), func(t *testing.T) { 491 r, w, err := os.Pipe() 492 if err != nil { 493 t.Fatal(err) 494 } 495 defer r.Close() 496 defer w.Close() 497 498 pasvch := make(chan result) 499 go handler(w, pasvch) 500 501 tooLong := 5 * time.Second 502 max := time.NewTimer(tooLong) 503 defer max.Stop() 504 actvch := make(chan result) 505 go func() { 506 t0 := time.Now() 507 if err := r.SetDeadline(t0.Add(timeout)); err != nil { 508 t.Error(err) 509 } 510 n, err := io.Copy(io.Discard, r) 511 dt := time.Since(t0) 512 r.Close() 513 actvch <- result{n, err, dt} 514 }() 515 516 select { 517 case res := <-actvch: 518 if !isDeadlineExceeded(err) { 519 t.Logf("good client timeout after %v, reading %d bytes", res.d, res.n) 520 } else { 521 t.Fatalf("client Copy = %d, %v; want timeout", res.n, res.err) 522 } 523 case <-max.C: 524 t.Fatalf("timeout (%v) waiting for client to timeout (%v) reading", tooLong, timeout) 525 } 526 527 select { 528 case res := <-pasvch: 529 t.Logf("writer in %v wrote %d: %v", res.d, res.n, res.err) 530 case <-max.C: 531 t.Fatalf("timeout waiting for writer to finish writing") 532 } 533 }) 534 } 535 } 536 } 537 538 // There is a very similar copy of this in net/timeout_test.go. 539 func TestReadWriteDeadlineRace(t *testing.T) { 540 t.Parallel() 541 542 N := 1000 543 if testing.Short() { 544 N = 50 545 } 546 547 r, w, err := os.Pipe() 548 if err != nil { 549 t.Fatal(err) 550 } 551 defer r.Close() 552 defer w.Close() 553 554 var wg sync.WaitGroup 555 wg.Add(3) 556 go func() { 557 defer wg.Done() 558 tic := time.NewTicker(2 * time.Microsecond) 559 defer tic.Stop() 560 for i := 0; i < N; i++ { 561 if err := r.SetReadDeadline(time.Now().Add(2 * time.Microsecond)); err != nil { 562 break 563 } 564 if err := w.SetWriteDeadline(time.Now().Add(2 * time.Microsecond)); err != nil { 565 break 566 } 567 <-tic.C 568 } 569 }() 570 go func() { 571 defer wg.Done() 572 var b [1]byte 573 for i := 0; i < N; i++ { 574 _, err := r.Read(b[:]) 575 if err != nil && !isDeadlineExceeded(err) { 576 t.Error("Read returned non-timeout error", err) 577 } 578 } 579 }() 580 go func() { 581 defer wg.Done() 582 var b [1]byte 583 for i := 0; i < N; i++ { 584 _, err := w.Write(b[:]) 585 if err != nil && !isDeadlineExceeded(err) { 586 t.Error("Write returned non-timeout error", err) 587 } 588 } 589 }() 590 wg.Wait() // wait for tester goroutine to stop 591 } 592 593 // TestRacyRead tests that it is safe to mutate the input Read buffer 594 // immediately after cancellation has occurred. 595 func TestRacyRead(t *testing.T) { 596 t.Parallel() 597 598 r, w, err := os.Pipe() 599 if err != nil { 600 t.Fatal(err) 601 } 602 defer r.Close() 603 defer w.Close() 604 605 var wg sync.WaitGroup 606 defer wg.Wait() 607 608 go io.Copy(w, rand.New(rand.NewSource(0))) 609 610 r.SetReadDeadline(time.Now().Add(time.Millisecond)) 611 for i := 0; i < 10; i++ { 612 wg.Add(1) 613 go func() { 614 defer wg.Done() 615 616 b1 := make([]byte, 1024) 617 b2 := make([]byte, 1024) 618 for j := 0; j < 100; j++ { 619 _, err := r.Read(b1) 620 copy(b1, b2) // Mutate b1 to trigger potential race 621 if err != nil { 622 if !isDeadlineExceeded(err) { 623 t.Error(err) 624 } 625 r.SetReadDeadline(time.Now().Add(time.Millisecond)) 626 } 627 } 628 }() 629 } 630 } 631 632 // TestRacyWrite tests that it is safe to mutate the input Write buffer 633 // immediately after cancellation has occurred. 634 func TestRacyWrite(t *testing.T) { 635 t.Parallel() 636 637 r, w, err := os.Pipe() 638 if err != nil { 639 t.Fatal(err) 640 } 641 defer r.Close() 642 defer w.Close() 643 644 var wg sync.WaitGroup 645 defer wg.Wait() 646 647 go io.Copy(io.Discard, r) 648 649 w.SetWriteDeadline(time.Now().Add(time.Millisecond)) 650 for i := 0; i < 10; i++ { 651 wg.Add(1) 652 go func() { 653 defer wg.Done() 654 655 b1 := make([]byte, 1024) 656 b2 := make([]byte, 1024) 657 for j := 0; j < 100; j++ { 658 _, err := w.Write(b1) 659 copy(b1, b2) // Mutate b1 to trigger potential race 660 if err != nil { 661 if !isDeadlineExceeded(err) { 662 t.Error(err) 663 } 664 w.SetWriteDeadline(time.Now().Add(time.Millisecond)) 665 } 666 } 667 }() 668 } 669 } 670 671 // Closing a TTY while reading from it should not hang. Issue 23943. 672 func TestTTYClose(t *testing.T) { 673 // Ignore SIGTTIN in case we are running in the background. 674 signal.Ignore(syscall.SIGTTIN) 675 defer signal.Reset(syscall.SIGTTIN) 676 677 f, err := os.Open("/dev/tty") 678 if err != nil { 679 t.Skipf("skipping because opening /dev/tty failed: %v", err) 680 } 681 682 go func() { 683 var buf [1]byte 684 f.Read(buf[:]) 685 }() 686 687 // Give the goroutine a chance to enter the read. 688 // It doesn't matter much if it occasionally fails to do so, 689 // we won't be testing what we want to test but the test will pass. 690 time.Sleep(time.Millisecond) 691 692 c := make(chan bool) 693 go func() { 694 defer close(c) 695 f.Close() 696 }() 697 698 select { 699 case <-c: 700 case <-time.After(time.Second): 701 t.Error("timed out waiting for close") 702 } 703 704 // On some systems the goroutines may now be hanging. 705 // There's not much we can do about that. 706 }