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