Source file
src/os/timeout_test.go
1
2
3
4
5
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
24
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
48 var noDeadline time.Time
49
50 var readTimeoutTests = []struct {
51 timeout time.Duration
52 xerrs [2]error
53 }{
54
55
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
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
144 }{
145
146
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
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
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
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
373
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()
509 }
510
511
512
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)
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
551
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)
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
590 func TestTTYClose(t *testing.T) {
591
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
606
607
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
623
624 }
625
View as plain text