github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/os/signal/signal_test.go (about)

     1  // Copyright 2009 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 darwin dragonfly freebsd linux netbsd openbsd solaris
     6  
     7  package signal
     8  
     9  import (
    10  	"flag"
    11  	"io/ioutil"
    12  	"os"
    13  	"os/exec"
    14  	"runtime"
    15  	"strconv"
    16  	"syscall"
    17  	"testing"
    18  	"time"
    19  )
    20  
    21  func waitSig(t *testing.T, c <-chan os.Signal, sig os.Signal) {
    22  	select {
    23  	case s := <-c:
    24  		if s != sig {
    25  			t.Fatalf("signal was %v, want %v", s, sig)
    26  		}
    27  	case <-time.After(1 * time.Second):
    28  		t.Fatalf("timeout waiting for %v", sig)
    29  	}
    30  }
    31  
    32  // Test that basic signal handling works.
    33  func TestSignal(t *testing.T) {
    34  	// Ask for SIGHUP
    35  	c := make(chan os.Signal, 1)
    36  	Notify(c, syscall.SIGHUP)
    37  	defer Stop(c)
    38  
    39  	// Send this process a SIGHUP
    40  	t.Logf("sighup...")
    41  	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
    42  	waitSig(t, c, syscall.SIGHUP)
    43  
    44  	// Ask for everything we can get.
    45  	c1 := make(chan os.Signal, 1)
    46  	Notify(c1)
    47  
    48  	// Send this process a SIGWINCH
    49  	t.Logf("sigwinch...")
    50  	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
    51  	waitSig(t, c1, syscall.SIGWINCH)
    52  
    53  	// Send two more SIGHUPs, to make sure that
    54  	// they get delivered on c1 and that not reading
    55  	// from c does not block everything.
    56  	t.Logf("sighup...")
    57  	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
    58  	waitSig(t, c1, syscall.SIGHUP)
    59  	t.Logf("sighup...")
    60  	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
    61  	waitSig(t, c1, syscall.SIGHUP)
    62  
    63  	// The first SIGHUP should be waiting for us on c.
    64  	waitSig(t, c, syscall.SIGHUP)
    65  }
    66  
    67  func TestStress(t *testing.T) {
    68  	dur := 3 * time.Second
    69  	if testing.Short() {
    70  		dur = 100 * time.Millisecond
    71  	}
    72  	defer runtime.GOMAXPROCS(runtime.GOMAXPROCS(4))
    73  	done := make(chan bool)
    74  	finished := make(chan bool)
    75  	go func() {
    76  		sig := make(chan os.Signal, 1)
    77  		Notify(sig, syscall.SIGUSR1)
    78  		defer Stop(sig)
    79  	Loop:
    80  		for {
    81  			select {
    82  			case <-sig:
    83  			case <-done:
    84  				break Loop
    85  			}
    86  		}
    87  		finished <- true
    88  	}()
    89  	go func() {
    90  	Loop:
    91  		for {
    92  			select {
    93  			case <-done:
    94  				break Loop
    95  			default:
    96  				syscall.Kill(syscall.Getpid(), syscall.SIGUSR1)
    97  				runtime.Gosched()
    98  			}
    99  		}
   100  		finished <- true
   101  	}()
   102  	time.Sleep(dur)
   103  	close(done)
   104  	<-finished
   105  	<-finished
   106  	// When run with 'go test -cpu=1,2,4' SIGUSR1 from this test can slip
   107  	// into subsequent TestSignal() causing failure.
   108  	// Sleep for a while to reduce the possibility of the failure.
   109  	time.Sleep(10 * time.Millisecond)
   110  }
   111  
   112  func testCancel(t *testing.T, ignore bool) {
   113  	// Send SIGWINCH. By default this signal should be ignored.
   114  	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
   115  	time.Sleep(100 * time.Millisecond)
   116  
   117  	// Ask to be notified on c1 when a SIGWINCH is received.
   118  	c1 := make(chan os.Signal, 1)
   119  	Notify(c1, syscall.SIGWINCH)
   120  	defer Stop(c1)
   121  
   122  	// Ask to be notified on c2 when a SIGHUP is received.
   123  	c2 := make(chan os.Signal, 1)
   124  	Notify(c2, syscall.SIGHUP)
   125  	defer Stop(c2)
   126  
   127  	// Send this process a SIGWINCH and wait for notification on c1.
   128  	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
   129  	waitSig(t, c1, syscall.SIGWINCH)
   130  
   131  	// Send this process a SIGHUP and wait for notification on c2.
   132  	syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
   133  	waitSig(t, c2, syscall.SIGHUP)
   134  
   135  	// Ignore, or reset the signal handlers for, SIGWINCH and SIGHUP.
   136  	if ignore {
   137  		Ignore(syscall.SIGWINCH, syscall.SIGHUP)
   138  	} else {
   139  		Reset(syscall.SIGWINCH, syscall.SIGHUP)
   140  	}
   141  
   142  	// Send this process a SIGWINCH. It should be ignored.
   143  	syscall.Kill(syscall.Getpid(), syscall.SIGWINCH)
   144  
   145  	// If ignoring, Send this process a SIGHUP. It should be ignored.
   146  	if ignore {
   147  		syscall.Kill(syscall.Getpid(), syscall.SIGHUP)
   148  	}
   149  
   150  	select {
   151  	case s := <-c1:
   152  		t.Fatalf("unexpected signal %v", s)
   153  	case <-time.After(100 * time.Millisecond):
   154  		// nothing to read - good
   155  	}
   156  
   157  	select {
   158  	case s := <-c2:
   159  		t.Fatalf("unexpected signal %v", s)
   160  	case <-time.After(100 * time.Millisecond):
   161  		// nothing to read - good
   162  	}
   163  
   164  	// Reset the signal handlers for all signals.
   165  	Reset()
   166  }
   167  
   168  // Test that Reset cancels registration for listed signals on all channels.
   169  func TestReset(t *testing.T) {
   170  	testCancel(t, false)
   171  }
   172  
   173  // Test that Ignore cancels registration for listed signals on all channels.
   174  func TestIgnore(t *testing.T) {
   175  	testCancel(t, true)
   176  }
   177  
   178  var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop")
   179  
   180  // Test that Stop cancels the channel's registrations.
   181  func TestStop(t *testing.T) {
   182  	sigs := []syscall.Signal{
   183  		syscall.SIGWINCH,
   184  		syscall.SIGHUP,
   185  		syscall.SIGUSR1,
   186  	}
   187  
   188  	for _, sig := range sigs {
   189  		// Send the signal.
   190  		// If it's SIGWINCH, we should not see it.
   191  		// If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
   192  		if sig == syscall.SIGWINCH || (sig == syscall.SIGHUP && *sendUncaughtSighup == 1) {
   193  			syscall.Kill(syscall.Getpid(), sig)
   194  		}
   195  		time.Sleep(100 * time.Millisecond)
   196  
   197  		// Ask for signal
   198  		c := make(chan os.Signal, 1)
   199  		Notify(c, sig)
   200  		defer Stop(c)
   201  
   202  		// Send this process that signal
   203  		syscall.Kill(syscall.Getpid(), sig)
   204  		waitSig(t, c, sig)
   205  
   206  		Stop(c)
   207  		select {
   208  		case s := <-c:
   209  			t.Fatalf("unexpected signal %v", s)
   210  		case <-time.After(100 * time.Millisecond):
   211  			// nothing to read - good
   212  		}
   213  
   214  		// Send the signal.
   215  		// If it's SIGWINCH, we should not see it.
   216  		// If it's SIGHUP, maybe we'll die. Let the flag tell us what to do.
   217  		if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 {
   218  			syscall.Kill(syscall.Getpid(), sig)
   219  		}
   220  
   221  		select {
   222  		case s := <-c:
   223  			t.Fatalf("unexpected signal %v", s)
   224  		case <-time.After(100 * time.Millisecond):
   225  			// nothing to read - good
   226  		}
   227  	}
   228  }
   229  
   230  // Test that when run under nohup, an uncaught SIGHUP does not kill the program,
   231  // but a
   232  func TestNohup(t *testing.T) {
   233  	// Ugly: ask for SIGHUP so that child will not have no-hup set
   234  	// even if test is running under nohup environment.
   235  	// We have no intention of reading from c.
   236  	c := make(chan os.Signal, 1)
   237  	Notify(c, syscall.SIGHUP)
   238  
   239  	// When run without nohup, the test should crash on an uncaught SIGHUP.
   240  	// When run under nohup, the test should ignore uncaught SIGHUPs,
   241  	// because the runtime is not supposed to be listening for them.
   242  	// Either way, TestStop should still be able to catch them when it wants them
   243  	// and then when it stops wanting them, the original behavior should resume.
   244  	//
   245  	// send_uncaught_sighup=1 sends the SIGHUP before starting to listen for SIGHUPs.
   246  	// send_uncaught_sighup=2 sends the SIGHUP after no longer listening for SIGHUPs.
   247  	//
   248  	// Both should fail without nohup and succeed with nohup.
   249  
   250  	for i := 1; i <= 2; i++ {
   251  		out, err := exec.Command(os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput()
   252  		if err == nil {
   253  			t.Fatalf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out)
   254  		}
   255  	}
   256  
   257  	Stop(c)
   258  
   259  	// Skip the nohup test below when running in tmux on darwin, since nohup
   260  	// doesn't work correctly there. See issue #5135.
   261  	if runtime.GOOS == "darwin" && os.Getenv("TMUX") != "" {
   262  		t.Skip("Skipping nohup test due to running in tmux on darwin")
   263  	}
   264  
   265  	// Again, this time with nohup, assuming we can find it.
   266  	_, err := os.Stat("/usr/bin/nohup")
   267  	if err != nil {
   268  		t.Skip("cannot find nohup; skipping second half of test")
   269  	}
   270  
   271  	for i := 1; i <= 2; i++ {
   272  		os.Remove("nohup.out")
   273  		out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput()
   274  
   275  		data, _ := ioutil.ReadFile("nohup.out")
   276  		os.Remove("nohup.out")
   277  		if err != nil {
   278  			t.Fatalf("ran test with -send_uncaught_sighup=%d under nohup and it failed: expected success.\nError: %v\nOutput:\n%s%s", i, err, out, data)
   279  		}
   280  	}
   281  }
   282  
   283  // Test that SIGCONT works (issue 8953).
   284  func TestSIGCONT(t *testing.T) {
   285  	c := make(chan os.Signal, 1)
   286  	Notify(c, syscall.SIGCONT)
   287  	defer Stop(c)
   288  	syscall.Kill(syscall.Getpid(), syscall.SIGCONT)
   289  	waitSig(t, c, syscall.SIGCONT)
   290  }