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