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