github.com/tcnksm/go@v0.0.0-20141208075154-439b32936367/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 var sendUncaughtSighup = flag.Int("send_uncaught_sighup", 0, "send uncaught SIGHUP during TestStop") 113 114 // Test that Stop cancels the channel's registrations. 115 func TestStop(t *testing.T) { 116 sigs := []syscall.Signal{ 117 syscall.SIGWINCH, 118 syscall.SIGHUP, 119 } 120 121 for _, sig := range sigs { 122 // Send the signal. 123 // If it's SIGWINCH, we should not see it. 124 // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. 125 if sig != syscall.SIGHUP || *sendUncaughtSighup == 1 { 126 syscall.Kill(syscall.Getpid(), sig) 127 } 128 time.Sleep(100 * time.Millisecond) 129 130 // Ask for signal 131 c := make(chan os.Signal, 1) 132 Notify(c, sig) 133 defer Stop(c) 134 135 // Send this process that signal 136 syscall.Kill(syscall.Getpid(), sig) 137 waitSig(t, c, sig) 138 139 Stop(c) 140 select { 141 case s := <-c: 142 t.Fatalf("unexpected signal %v", s) 143 case <-time.After(100 * time.Millisecond): 144 // nothing to read - good 145 } 146 147 // Send the signal. 148 // If it's SIGWINCH, we should not see it. 149 // If it's SIGHUP, maybe we'll die. Let the flag tell us what to do. 150 if sig != syscall.SIGHUP || *sendUncaughtSighup == 2 { 151 syscall.Kill(syscall.Getpid(), sig) 152 } 153 154 select { 155 case s := <-c: 156 t.Fatalf("unexpected signal %v", s) 157 case <-time.After(100 * time.Millisecond): 158 // nothing to read - good 159 } 160 } 161 } 162 163 // Test that when run under nohup, an uncaught SIGHUP does not kill the program, 164 // but a 165 func TestNohup(t *testing.T) { 166 // Ugly: ask for SIGHUP so that child will not have no-hup set 167 // even if test is running under nohup environment. 168 // We have no intention of reading from c. 169 c := make(chan os.Signal, 1) 170 Notify(c, syscall.SIGHUP) 171 172 // When run without nohup, the test should crash on an uncaught SIGHUP. 173 // When run under nohup, the test should ignore uncaught SIGHUPs, 174 // because the runtime is not supposed to be listening for them. 175 // Either way, TestStop should still be able to catch them when it wants them 176 // and then when it stops wanting them, the original behavior should resume. 177 // 178 // send_uncaught_sighup=1 sends the SIGHUP before starting to listen for SIGHUPs. 179 // send_uncaught_sighup=2 sends the SIGHUP after no longer listening for SIGHUPs. 180 // 181 // Both should fail without nohup and succeed with nohup. 182 183 for i := 1; i <= 2; i++ { 184 out, err := exec.Command(os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput() 185 if err == nil { 186 t.Fatalf("ran test with -send_uncaught_sighup=%d and it succeeded: expected failure.\nOutput:\n%s", i, out) 187 } 188 } 189 190 Stop(c) 191 192 // Again, this time with nohup, assuming we can find it. 193 _, err := os.Stat("/usr/bin/nohup") 194 if err != nil { 195 t.Skip("cannot find nohup; skipping second half of test") 196 } 197 198 for i := 1; i <= 2; i++ { 199 os.Remove("nohup.out") 200 out, err := exec.Command("/usr/bin/nohup", os.Args[0], "-test.run=TestStop", "-send_uncaught_sighup="+strconv.Itoa(i)).CombinedOutput() 201 202 data, _ := ioutil.ReadFile("nohup.out") 203 os.Remove("nohup.out") 204 if err != nil { 205 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) 206 } 207 } 208 }