github.com/kdevb0x/go@v0.0.0-20180115030120-39687051e9e7/src/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 !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  }