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