Jiri Simsa | d7616c9 | 2015-03-24 23:44:30 -0700 | [diff] [blame] | 1 | // Copyright 2015 The Vanadium 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 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 5 | package signals |
| 6 | |
| 7 | import ( |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 8 | "bufio" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 9 | "fmt" |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 10 | "io" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 11 | "os" |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 12 | "path/filepath" |
| 13 | "runtime" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 14 | "syscall" |
| 15 | "testing" |
| 16 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 17 | "v.io/v23" |
| 18 | "v.io/v23/context" |
Matt Rosencrantz | 94502cf | 2015-03-18 09:43:44 -0700 | [diff] [blame] | 19 | "v.io/v23/rpc" |
Todd Wang | 94c9d0b | 2015-04-01 14:27:00 -0700 | [diff] [blame] | 20 | "v.io/v23/services/appcycle" |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 21 | "v.io/v23/vtrace" |
Todd Wang | 712eeef | 2015-04-03 17:13:50 -0700 | [diff] [blame] | 22 | "v.io/x/ref/lib/mgmt" |
Todd Wang | b351149 | 2015-04-07 23:32:34 -0700 | [diff] [blame] | 23 | "v.io/x/ref/lib/security/securityflag" |
Todd Wang | cd4b3cc | 2015-04-06 16:42:02 -0700 | [diff] [blame] | 24 | "v.io/x/ref/services/device" |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 25 | "v.io/x/ref/test" |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 26 | "v.io/x/ref/test/modules" |
Todd Wang | b351149 | 2015-04-07 23:32:34 -0700 | [diff] [blame] | 27 | |
Suharsh Sivakumar | dcc11d7 | 2015-05-11 12:19:20 -0700 | [diff] [blame] | 28 | _ "v.io/x/ref/runtime/factories/generic" |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 29 | ) |
| 30 | |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 31 | //go:generate v23 test generate |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 32 | |
Suharsh Sivakumar | d68949c | 2015-01-26 10:32:23 -0800 | [diff] [blame] | 33 | func stopLoop(stop func(), stdin io.Reader, ch chan<- struct{}) { |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 34 | scanner := bufio.NewScanner(stdin) |
| 35 | for scanner.Scan() { |
| 36 | switch scanner.Text() { |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 37 | case "close": |
| 38 | close(ch) |
| 39 | return |
| 40 | case "stop": |
Suharsh Sivakumar | d68949c | 2015-01-26 10:32:23 -0800 | [diff] [blame] | 41 | stop() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 42 | } |
| 43 | } |
| 44 | } |
| 45 | |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 46 | func program(stdin io.Reader, stdout io.Writer, signals ...os.Signal) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 47 | ctx, shutdown := test.V23Init() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 48 | closeStopLoop := make(chan struct{}) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 49 | // obtain ac here since stopLoop may execute after shutdown is called below |
| 50 | ac := v23.GetAppCycle(ctx) |
| 51 | go stopLoop(func() { ac.Stop(ctx) }, stdin, closeStopLoop) |
Suharsh Sivakumar | 946f64d | 2015-01-08 10:48:13 -0800 | [diff] [blame] | 52 | wait := ShutdownOnSignals(ctx, signals...) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 53 | fmt.Fprintf(stdout, "ready\n") |
| 54 | fmt.Fprintf(stdout, "received signal %s\n", <-wait) |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 55 | shutdown() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 56 | <-closeStopLoop |
| 57 | } |
| 58 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 59 | var handleDefaults = modules.Register(func(env *modules.Env, args ...string) error { |
| 60 | program(env.Stdin, env.Stdout) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 61 | return nil |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 62 | }, "handleDefaults") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 63 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 64 | var handleCustom = modules.Register(func(env *modules.Env, args ...string) error { |
| 65 | program(env.Stdin, env.Stdout, syscall.SIGABRT) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 66 | return nil |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 67 | }, "handleCustom") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 68 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 69 | var handleCustomWithStop = modules.Register(func(env *modules.Env, args ...string) error { |
| 70 | program(env.Stdin, env.Stdout, STOP, syscall.SIGABRT, syscall.SIGHUP) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 71 | return nil |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 72 | }, "handleCustomWithStop") |
Bogdan Caprita | 1002ba4 | 2014-06-06 19:24:40 -0700 | [diff] [blame] | 73 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 74 | var handleDefaultsIgnoreChan = modules.Register(func(env *modules.Env, args ...string) error { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 75 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 76 | defer shutdown() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 77 | closeStopLoop := make(chan struct{}) |
Cosmos Nicolaou | e9c622d | 2015-07-10 11:09:42 -0700 | [diff] [blame] | 78 | // obtain ac here since stopLoop may execute after shutdown is called below |
| 79 | ac := v23.GetAppCycle(ctx) |
| 80 | go stopLoop(func() { ac.Stop(ctx) }, env.Stdin, closeStopLoop) |
Suharsh Sivakumar | 946f64d | 2015-01-08 10:48:13 -0800 | [diff] [blame] | 81 | ShutdownOnSignals(ctx) |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 82 | fmt.Fprintf(env.Stdout, "ready\n") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 83 | <-closeStopLoop |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 84 | return nil |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 85 | }, "handleDefaultsIgnoreChan") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 86 | |
| 87 | func isSignalInSet(sig os.Signal, set []os.Signal) bool { |
| 88 | for _, s := range set { |
| 89 | if sig == s { |
| 90 | return true |
| 91 | } |
| 92 | } |
| 93 | return false |
| 94 | } |
| 95 | |
| 96 | func checkSignalIsDefault(t *testing.T, sig os.Signal) { |
| 97 | if !isSignalInSet(sig, defaultSignals()) { |
| 98 | t.Errorf("signal %s not in default signal set, as expected", sig) |
| 99 | } |
| 100 | } |
| 101 | |
| 102 | func checkSignalIsNotDefault(t *testing.T, sig os.Signal) { |
| 103 | if isSignalInSet(sig, defaultSignals()) { |
| 104 | t.Errorf("signal %s unexpectedly in default signal set", sig) |
| 105 | } |
| 106 | } |
| 107 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 108 | func newShell(t *testing.T, ctx *context.T, prog modules.Program) (*modules.Shell, modules.Handle) { |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 109 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 110 | if err != nil { |
| 111 | t.Fatalf("unexpected error: %s", err) |
| 112 | } |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 113 | handle, err := sh.Start(nil, prog) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 114 | if err != nil { |
| 115 | sh.Cleanup(os.Stderr, os.Stderr) |
| 116 | t.Fatalf("unexpected error: %s", err) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 117 | return nil, nil |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 118 | } |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 119 | return sh, handle |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 120 | } |
| 121 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 122 | // TestCleanShutdownSignal verifies that sending a signal to a child that |
| 123 | // handles it by default causes the child to shut down cleanly. |
| 124 | func TestCleanShutdownSignal(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 125 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 126 | defer shutdown() |
| 127 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 128 | sh, h := newShell(t, ctx, handleDefaults) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 129 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 130 | h.Expect("ready") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 131 | checkSignalIsDefault(t, syscall.SIGINT) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 132 | syscall.Kill(h.Pid(), syscall.SIGINT) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 133 | h.Expectf("received signal %s", syscall.SIGINT) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 134 | fmt.Fprintf(h.Stdin(), "close\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 135 | h.ExpectEOF() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 136 | } |
| 137 | |
| 138 | // TestCleanShutdownStop verifies that sending a stop comamnd to a child that |
| 139 | // handles stop commands by default causes the child to shut down cleanly. |
| 140 | func TestCleanShutdownStop(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 141 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 142 | defer shutdown() |
| 143 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 144 | sh, h := newShell(t, ctx, handleDefaults) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 145 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 146 | h.Expect("ready") |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 147 | fmt.Fprintf(h.Stdin(), "stop\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 148 | h.Expectf("received signal %s", v23.LocalStop) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 149 | fmt.Fprintf(h.Stdin(), "close\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 150 | h.ExpectEOF() |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 151 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 152 | } |
| 153 | |
Bogdan Caprita | 1002ba4 | 2014-06-06 19:24:40 -0700 | [diff] [blame] | 154 | // TestCleanShutdownStopCustom verifies that sending a stop comamnd to a child |
| 155 | // that handles stop command as part of a custom set of signals handled, causes |
| 156 | // the child to shut down cleanly. |
| 157 | func TestCleanShutdownStopCustom(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 158 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 159 | defer shutdown() |
| 160 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 161 | sh, h := newShell(t, ctx, handleCustomWithStop) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 162 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 163 | h.Expect("ready") |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 164 | fmt.Fprintf(h.Stdin(), "stop\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 165 | h.Expectf("received signal %s", v23.LocalStop) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 166 | fmt.Fprintf(h.Stdin(), "close\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 167 | h.ExpectEOF() |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 168 | } |
| 169 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 170 | func testExitStatus(t *testing.T, h modules.Handle, code int) { |
| 171 | h.ExpectEOF() |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 172 | _, file, line, _ := runtime.Caller(1) |
| 173 | file = filepath.Base(file) |
| 174 | if got, want := h.Shutdown(os.Stdout, os.Stderr), fmt.Errorf("exit status %d", code); got.Error() != want.Error() { |
| 175 | t.Errorf("%s:%d: got %q, want %q", file, line, got, want) |
| 176 | } |
Bogdan Caprita | 1002ba4 | 2014-06-06 19:24:40 -0700 | [diff] [blame] | 177 | } |
| 178 | |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 179 | // TestStopNoHandler verifies that sending a stop command to a child that does |
| 180 | // not handle stop commands causes the child to exit immediately. |
| 181 | func TestStopNoHandler(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 182 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 183 | defer shutdown() |
| 184 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 185 | sh, h := newShell(t, ctx, handleCustom) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 186 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 187 | h.Expect("ready") |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 188 | fmt.Fprintf(h.Stdin(), "stop\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 189 | testExitStatus(t, h, v23.UnhandledStopExitCode) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 190 | } |
| 191 | |
| 192 | // TestDoubleSignal verifies that sending a succession of two signals to a child |
| 193 | // that handles these signals by default causes the child to exit immediately |
| 194 | // upon receiving the second signal. |
| 195 | func TestDoubleSignal(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 196 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 197 | defer shutdown() |
| 198 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 199 | sh, h := newShell(t, ctx, handleDefaults) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 200 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 201 | h.Expect("ready") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 202 | checkSignalIsDefault(t, syscall.SIGTERM) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 203 | syscall.Kill(h.Pid(), syscall.SIGTERM) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 204 | h.Expectf("received signal %s", syscall.SIGTERM) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 205 | checkSignalIsDefault(t, syscall.SIGINT) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 206 | syscall.Kill(h.Pid(), syscall.SIGINT) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 207 | testExitStatus(t, h, DoubleStopExitCode) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 208 | } |
| 209 | |
| 210 | // TestSignalAndStop verifies that sending a signal followed by a stop command |
| 211 | // to a child that handles these by default causes the child to exit immediately |
| 212 | // upon receiving the stop command. |
| 213 | func TestSignalAndStop(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 214 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 215 | defer shutdown() |
| 216 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 217 | sh, h := newShell(t, ctx, handleDefaults) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 218 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 219 | h.Expect("ready") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 220 | checkSignalIsDefault(t, syscall.SIGTERM) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 221 | syscall.Kill(h.Pid(), syscall.SIGTERM) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 222 | h.Expectf("received signal %s", syscall.SIGTERM) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 223 | fmt.Fprintf(h.Stdin(), "stop\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 224 | testExitStatus(t, h, DoubleStopExitCode) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 225 | } |
| 226 | |
| 227 | // TestDoubleStop verifies that sending a succession of stop commands to a child |
| 228 | // that handles stop commands by default causes the child to exit immediately |
| 229 | // upon receiving the second stop command. |
| 230 | func TestDoubleStop(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 231 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 232 | defer shutdown() |
| 233 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 234 | sh, h := newShell(t, ctx, handleDefaults) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 235 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 236 | h.Expect("ready") |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 237 | fmt.Fprintf(h.Stdin(), "stop\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 238 | h.Expectf("received signal %s", v23.LocalStop) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 239 | fmt.Fprintf(h.Stdin(), "stop\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 240 | testExitStatus(t, h, DoubleStopExitCode) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 241 | } |
| 242 | |
| 243 | // TestSendUnhandledSignal verifies that sending a signal that the child does |
| 244 | // not handle causes the child to exit as per the signal being sent. |
| 245 | func TestSendUnhandledSignal(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 246 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 247 | defer shutdown() |
| 248 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 249 | sh, h := newShell(t, ctx, handleDefaults) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 250 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 251 | h.Expect("ready") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 252 | checkSignalIsNotDefault(t, syscall.SIGABRT) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 253 | syscall.Kill(h.Pid(), syscall.SIGABRT) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 254 | testExitStatus(t, h, 2) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 255 | } |
| 256 | |
| 257 | // TestDoubleSignalIgnoreChan verifies that, even if we ignore the channel that |
| 258 | // ShutdownOnSignals returns, sending two signals should still cause the |
| 259 | // process to exit (ensures that there is no dependency in ShutdownOnSignals |
| 260 | // on having a goroutine read from the returned channel). |
| 261 | func TestDoubleSignalIgnoreChan(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 262 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 263 | defer shutdown() |
| 264 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 265 | sh, h := newShell(t, ctx, handleDefaultsIgnoreChan) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 266 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 267 | h.Expect("ready") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 268 | // Even if we ignore the channel that ShutdownOnSignals returns, |
| 269 | // sending two signals should still cause the process to exit. |
| 270 | checkSignalIsDefault(t, syscall.SIGTERM) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 271 | syscall.Kill(h.Pid(), syscall.SIGTERM) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 272 | checkSignalIsDefault(t, syscall.SIGINT) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 273 | syscall.Kill(h.Pid(), syscall.SIGINT) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 274 | testExitStatus(t, h, DoubleStopExitCode) |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 275 | } |
| 276 | |
| 277 | // TestHandlerCustomSignal verifies that sending a non-default signal to a |
| 278 | // server that listens for that signal causes the server to shut down cleanly. |
| 279 | func TestHandlerCustomSignal(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 280 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 281 | defer shutdown() |
| 282 | |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 283 | sh, h := newShell(t, ctx, handleCustom) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 284 | defer sh.Cleanup(os.Stderr, os.Stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 285 | h.Expect("ready") |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 286 | checkSignalIsNotDefault(t, syscall.SIGABRT) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 287 | syscall.Kill(h.Pid(), syscall.SIGABRT) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 288 | h.Expectf("received signal %s", syscall.SIGABRT) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 289 | fmt.Fprintf(h.Stdin(), "stop\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 290 | h.ExpectEOF() |
Jiri Simsa | 5293dcb | 2014-05-10 09:56:38 -0700 | [diff] [blame] | 291 | } |
Bogdan Caprita | 1002ba4 | 2014-06-06 19:24:40 -0700 | [diff] [blame] | 292 | |
| 293 | // TestHandlerCustomSignalWithStop verifies that sending a custom stop signal |
| 294 | // to a server that listens for that signal causes the server to shut down |
| 295 | // cleanly, even when a STOP signal is also among the handled signals. |
| 296 | func TestHandlerCustomSignalWithStop(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 297 | rootCtx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 298 | defer shutdown() |
| 299 | |
Jiri Simsa | 7fc6e87 | 2014-06-09 09:22:53 -0700 | [diff] [blame] | 300 | for _, signal := range []syscall.Signal{syscall.SIGABRT, syscall.SIGHUP} { |
Todd Wang | ad49204 | 2015-04-17 15:58:40 -0700 | [diff] [blame] | 301 | ctx, _ := vtrace.WithNewTrace(rootCtx) |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 302 | sh, h := newShell(t, ctx, handleCustomWithStop) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 303 | h.Expect("ready") |
Bogdan Caprita | 1002ba4 | 2014-06-06 19:24:40 -0700 | [diff] [blame] | 304 | checkSignalIsNotDefault(t, signal) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 305 | syscall.Kill(h.Pid(), signal) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 306 | h.Expectf("received signal %s", signal) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 307 | fmt.Fprintf(h.Stdin(), "close\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 308 | h.ExpectEOF() |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 309 | sh.Cleanup(os.Stderr, os.Stderr) |
Bogdan Caprita | 1002ba4 | 2014-06-06 19:24:40 -0700 | [diff] [blame] | 310 | } |
| 311 | } |
| 312 | |
| 313 | // TestParseSignalsList verifies that ShutdownOnSignals correctly interprets |
| 314 | // the input list of signals. |
| 315 | func TestParseSignalsList(t *testing.T) { |
| 316 | list := []os.Signal{STOP, syscall.SIGTERM} |
Matt Rosencrantz | c7fecf1 | 2014-11-27 19:58:43 -0800 | [diff] [blame] | 317 | ShutdownOnSignals(nil, list...) |
Bogdan Caprita | 1002ba4 | 2014-06-06 19:24:40 -0700 | [diff] [blame] | 318 | if !isSignalInSet(syscall.SIGTERM, list) { |
| 319 | t.Errorf("signal %s not in signal set, as expected: %v", syscall.SIGTERM, list) |
| 320 | } |
| 321 | if !isSignalInSet(STOP, list) { |
| 322 | t.Errorf("signal %s not in signal set, as expected: %v", STOP, list) |
| 323 | } |
| 324 | } |
Bogdan Caprita | a4d9ee4 | 2014-06-20 16:42:53 -0700 | [diff] [blame] | 325 | |
| 326 | type configServer struct { |
| 327 | ch chan<- string |
| 328 | } |
| 329 | |
Todd Wang | 54feabe | 2015-04-15 23:38:26 -0700 | [diff] [blame] | 330 | func (c *configServer) Set(_ *context.T, _ rpc.ServerCall, key, value string) error { |
Bogdan Caprita | a4d9ee4 | 2014-06-20 16:42:53 -0700 | [diff] [blame] | 331 | if key != mgmt.AppCycleManagerConfigKey { |
| 332 | return fmt.Errorf("Unexpected key: %v", key) |
| 333 | } |
| 334 | c.ch <- value |
| 335 | return nil |
| 336 | |
| 337 | } |
| 338 | |
Bogdan Caprita | a4d9ee4 | 2014-06-20 16:42:53 -0700 | [diff] [blame] | 339 | // TestCleanRemoteShutdown verifies that remote shutdown works correctly. |
| 340 | func TestCleanRemoteShutdown(t *testing.T) { |
Todd Wang | 60052d8 | 2015-05-22 15:00:10 -0700 | [diff] [blame] | 341 | ctx, shutdown := test.V23Init() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 342 | defer shutdown() |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 343 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 344 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 345 | if err != nil { |
| 346 | t.Fatalf("unexpected error: %s", err) |
| 347 | } |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 348 | defer sh.Cleanup(os.Stderr, os.Stderr) |
| 349 | |
Matt Rosencrantz | bb6295d | 2015-06-19 15:13:58 -0700 | [diff] [blame] | 350 | ch := make(chan string) |
Matt Rosencrantz | 53ac585 | 2015-09-04 15:14:54 -0700 | [diff] [blame] | 351 | ctx, server, err := v23.WithNewServer(ctx, "", device.ConfigServer(&configServer{ch}), securityflag.NewAuthorizerOrDie()) |
Matt Rosencrantz | bb6295d | 2015-06-19 15:13:58 -0700 | [diff] [blame] | 352 | if err != nil { |
| 353 | t.Fatalf("Got error: %v", err) |
| 354 | } |
| 355 | configServiceName := server.Status().Endpoints[0].Name() |
| 356 | |
Jiri Simsa | 3789339 | 2014-11-07 10:55:45 -0800 | [diff] [blame] | 357 | sh.SetConfigKey(mgmt.ParentNameConfigKey, configServiceName) |
| 358 | sh.SetConfigKey(mgmt.ProtocolConfigKey, "tcp") |
| 359 | sh.SetConfigKey(mgmt.AddressConfigKey, "127.0.0.1:0") |
Todd Wang | 9587390 | 2015-05-22 14:21:30 -0700 | [diff] [blame] | 360 | h, err := sh.Start(nil, handleDefaults) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 361 | if err != nil { |
| 362 | t.Fatalf("unexpected error: %s", err) |
| 363 | } |
Bogdan Caprita | a4d9ee4 | 2014-06-20 16:42:53 -0700 | [diff] [blame] | 364 | appCycleName := <-ch |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 365 | h.Expect("ready") |
Todd Wang | 702385a | 2014-11-07 01:54:08 -0800 | [diff] [blame] | 366 | appCycle := appcycle.AppCycleClient(appCycleName) |
Matt Rosencrantz | f541b77 | 2015-01-13 07:58:59 -0800 | [diff] [blame] | 367 | stream, err := appCycle.Stop(ctx) |
Bogdan Caprita | a4d9ee4 | 2014-06-20 16:42:53 -0700 | [diff] [blame] | 368 | if err != nil { |
| 369 | t.Fatalf("Got error: %v", err) |
| 370 | } |
Shyam Jayaraman | 97b9dca | 2014-07-31 13:30:46 -0700 | [diff] [blame] | 371 | rStream := stream.RecvStream() |
| 372 | if rStream.Advance() || rStream.Err() != nil { |
| 373 | t.Errorf("Expected EOF, got (%v, %v) instead: ", rStream.Value(), rStream.Err()) |
Bogdan Caprita | a4d9ee4 | 2014-06-20 16:42:53 -0700 | [diff] [blame] | 374 | } |
| 375 | if err := stream.Finish(); err != nil { |
| 376 | t.Fatalf("Got error: %v", err) |
| 377 | } |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 378 | h.Expectf("received signal %s", v23.RemoteStop) |
Cosmos Nicolaou | cc58172 | 2014-10-07 12:45:39 -0700 | [diff] [blame] | 379 | fmt.Fprintf(h.Stdin(), "close\n") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 380 | h.ExpectEOF() |
Bogdan Caprita | a4d9ee4 | 2014-06-20 16:42:53 -0700 | [diff] [blame] | 381 | } |