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  }