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