...

Source file src/os/timeout_test.go

Documentation: 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  //go:build !js && !plan9 && !windows
		 6  // +build !js,!plan9,!windows
		 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  	// On BSD systems regular files seem to be pollable,
		25  	// so just run this test on Linux.
		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  // noDeadline is a zero time.Time value, which cancels a deadline.
		49  var noDeadline time.Time
		50  
		51  var readTimeoutTests = []struct {
		52  	timeout time.Duration
		53  	xerrs	 [2]error // expected errors in transition
		54  }{
		55  	// Tests that read deadlines work, even if there's data ready
		56  	// to be read.
		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 // wait for tester goroutine to stop
	 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 // expected errors in transition
	 145  }{
	 146  	// Tests that write deadlines work, even if there's buffer
	 147  	// space available to write.
	 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 // wait for tester goroutine to stop
	 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  	// Cannot use t.Parallel - modifies global GOMAXPROCS.
	 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  	// Cannot use t.Parallel - modifies global GOMAXPROCS.
	 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  		// The writer, with no timeouts of its own,
	 374  		// sending bytes to clients as fast as it can.
	 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() // wait for tester goroutine to stop
	 510  }
	 511  
	 512  // TestRacyRead tests that it is safe to mutate the input Read buffer
	 513  // immediately after cancellation has occurred.
	 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) // Mutate b1 to trigger potential race
	 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  // TestRacyWrite tests that it is safe to mutate the input Write buffer
	 552  // immediately after cancellation has occurred.
	 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) // Mutate b1 to trigger potential race
	 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  // Closing a TTY while reading from it should not hang.	Issue 23943.
	 591  func TestTTYClose(t *testing.T) {
	 592  	// Ignore SIGTTIN in case we are running in the background.
	 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  	// Give the goroutine a chance to enter the read.
	 607  	// It doesn't matter much if it occasionally fails to do so,
	 608  	// we won't be testing what we want to test but the test will pass.
	 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  	// On some systems the goroutines may now be hanging.
	 624  	// There's not much we can do about that.
	 625  }
	 626  

View as plain text