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