blob: 635bac82205667705ddfe1c169eb7289b6ba3cfc [file] [log] [blame]
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001package signals
2
3import (
Cosmos Nicolaoucc581722014-10-07 12:45:39 -07004 "bufio"
Jiri Simsa5293dcb2014-05-10 09:56:38 -07005 "fmt"
Cosmos Nicolaoucc581722014-10-07 12:45:39 -07006 "io"
Jiri Simsa5293dcb2014-05-10 09:56:38 -07007 "os"
Cosmos Nicolaoucc581722014-10-07 12:45:39 -07008 "path/filepath"
9 "runtime"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070010 "syscall"
11 "testing"
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070012 "time"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070013
Jiri Simsa519c5072014-09-17 21:37:57 -070014 "veyron.io/veyron/veyron2"
15 "veyron.io/veyron/veyron2/ipc"
16 "veyron.io/veyron/veyron2/mgmt"
17 "veyron.io/veyron/veyron2/naming"
18 "veyron.io/veyron/veyron2/rt"
19 "veyron.io/veyron/veyron2/services/mgmt/appcycle"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070020
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070021 "veyron.io/veyron/veyron/lib/expect"
Asim Shankar95910b62014-10-31 22:02:29 -070022 "veyron.io/veyron/veyron/lib/flags/consts"
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070023 "veyron.io/veyron/veyron/lib/modules"
Asim Shankarc920db32014-10-16 19:18:21 -070024 "veyron.io/veyron/veyron/lib/testutil"
Jiri Simsa519c5072014-09-17 21:37:57 -070025 "veyron.io/veyron/veyron/lib/testutil/security"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070026 "veyron.io/veyron/veyron/profiles"
Jiri Simsa519c5072014-09-17 21:37:57 -070027 vflag "veyron.io/veyron/veyron/security/flag"
Bogdan Capritaa456f472014-12-10 10:18:03 -080028 "veyron.io/veyron/veyron/services/mgmt/device"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070029)
30
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070031// TestHelperProcess is boilerplate for the modules setup.
Jiri Simsa5293dcb2014-05-10 09:56:38 -070032func TestHelperProcess(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070033 modules.DispatchInTest()
Jiri Simsa5293dcb2014-05-10 09:56:38 -070034}
35
36func init() {
Asim Shankarc920db32014-10-16 19:18:21 -070037 testutil.Init()
Cosmos Nicolaou1e78ccc2014-10-09 08:10:26 -070038 modules.RegisterChild("handleDefaults", "", handleDefaults)
39 modules.RegisterChild("handleCustom", "", handleCustom)
40 modules.RegisterChild("handleCustomWithStop", "", handleCustomWithStop)
41 modules.RegisterChild("handleDefaultsIgnoreChan", "", handleDefaultsIgnoreChan)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070042}
43
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -080044func stopLoop(runtime veyron2.Runtime, stdin io.Reader, ch chan<- struct{}) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070045 scanner := bufio.NewScanner(stdin)
46 for scanner.Scan() {
47 switch scanner.Text() {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070048 case "close":
49 close(ch)
50 return
51 case "stop":
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -080052 runtime.AppCycle().Stop()
Jiri Simsa5293dcb2014-05-10 09:56:38 -070053 }
54 }
55}
56
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070057func program(stdin io.Reader, stdout io.Writer, signals ...os.Signal) {
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -080058 runtime, err := rt.New()
59 if err != nil {
60 panic(err)
61 }
62
Jiri Simsa5293dcb2014-05-10 09:56:38 -070063 closeStopLoop := make(chan struct{})
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -080064 go stopLoop(runtime, stdin, closeStopLoop)
65 wait := ShutdownOnSignals(runtime, signals...)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070066 fmt.Fprintf(stdout, "ready\n")
67 fmt.Fprintf(stdout, "received signal %s\n", <-wait)
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -080068 runtime.Cleanup()
Jiri Simsa5293dcb2014-05-10 09:56:38 -070069 <-closeStopLoop
70}
71
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070072func handleDefaults(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
73 program(stdin, stdout)
74 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -070075}
76
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070077func handleCustom(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
78 program(stdin, stdout, syscall.SIGABRT)
79 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -070080}
81
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070082func handleCustomWithStop(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
83 program(stdin, stdout, STOP, syscall.SIGABRT, syscall.SIGHUP)
84 return nil
Bogdan Caprita1002ba42014-06-06 19:24:40 -070085}
86
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070087func handleDefaultsIgnoreChan(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -080088 runtime, err := rt.New()
89 if err != nil {
90 panic(err)
91 }
92 defer runtime.Cleanup()
Jiri Simsa5293dcb2014-05-10 09:56:38 -070093 closeStopLoop := make(chan struct{})
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -080094 go stopLoop(runtime, stdin, closeStopLoop)
95 ShutdownOnSignals(runtime)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070096 fmt.Fprintf(stdout, "ready\n")
Jiri Simsa5293dcb2014-05-10 09:56:38 -070097 <-closeStopLoop
Cosmos Nicolaoucc581722014-10-07 12:45:39 -070098 return nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -070099}
100
101func isSignalInSet(sig os.Signal, set []os.Signal) bool {
102 for _, s := range set {
103 if sig == s {
104 return true
105 }
106 }
107 return false
108}
109
110func checkSignalIsDefault(t *testing.T, sig os.Signal) {
111 if !isSignalInSet(sig, defaultSignals()) {
112 t.Errorf("signal %s not in default signal set, as expected", sig)
113 }
114}
115
116func checkSignalIsNotDefault(t *testing.T, sig os.Signal) {
117 if isSignalInSet(sig, defaultSignals()) {
118 t.Errorf("signal %s unexpectedly in default signal set", sig)
119 }
120}
121
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700122func newShell(t *testing.T, command string) (*modules.Shell, modules.Handle, *expect.Session) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800123 sh, err := modules.NewShell(nil)
124 if err != nil {
125 t.Fatalf("unexpected error: %s", err)
126 }
Cosmos Nicolaou612ad382014-10-29 19:41:35 -0700127 handle, err := sh.Start(command, nil)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700128 if err != nil {
129 sh.Cleanup(os.Stderr, os.Stderr)
130 t.Fatalf("unexpected error: %s", err)
131 return nil, nil, nil
132 }
133 session := expect.NewSession(t, handle.Stdout(), time.Minute)
134 return sh, handle, session
135}
136
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700137// TestCleanShutdownSignal verifies that sending a signal to a child that
138// handles it by default causes the child to shut down cleanly.
139func TestCleanShutdownSignal(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700140 sh, h, s := newShell(t, "handleDefaults")
141 defer sh.Cleanup(os.Stderr, os.Stderr)
142 s.Expect("ready")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700143 checkSignalIsDefault(t, syscall.SIGINT)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700144 syscall.Kill(h.Pid(), syscall.SIGINT)
145 s.Expectf("received signal %s", syscall.SIGINT)
146 fmt.Fprintf(h.Stdin(), "close\n")
147 s.ExpectEOF()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700148}
149
150// TestCleanShutdownStop verifies that sending a stop comamnd to a child that
151// handles stop commands by default causes the child to shut down cleanly.
152func TestCleanShutdownStop(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700153 sh, h, s := newShell(t, "handleDefaults")
154 defer sh.Cleanup(os.Stderr, os.Stderr)
155 s.Expect("ready")
156 fmt.Fprintf(h.Stdin(), "stop\n")
157 s.Expectf("received signal %s", veyron2.LocalStop)
158 fmt.Fprintf(h.Stdin(), "close\n")
159 s.ExpectEOF()
160
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700161}
162
Bogdan Caprita1002ba42014-06-06 19:24:40 -0700163// TestCleanShutdownStopCustom verifies that sending a stop comamnd to a child
164// that handles stop command as part of a custom set of signals handled, causes
165// the child to shut down cleanly.
166func TestCleanShutdownStopCustom(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700167 sh, h, s := newShell(t, "handleCustomWithStop")
168 defer sh.Cleanup(os.Stderr, os.Stderr)
169 s.Expect("ready")
170 fmt.Fprintf(h.Stdin(), "stop\n")
171 s.Expectf("received signal %s", veyron2.LocalStop)
172 fmt.Fprintf(h.Stdin(), "close\n")
173 s.ExpectEOF()
174}
175
176func testExitStatus(t *testing.T, h modules.Handle, s *expect.Session, code int) {
177 s.ExpectEOF()
178 _, file, line, _ := runtime.Caller(1)
179 file = filepath.Base(file)
180 if got, want := h.Shutdown(os.Stdout, os.Stderr), fmt.Errorf("exit status %d", code); got.Error() != want.Error() {
181 t.Errorf("%s:%d: got %q, want %q", file, line, got, want)
182 }
Bogdan Caprita1002ba42014-06-06 19:24:40 -0700183}
184
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700185// TestStopNoHandler verifies that sending a stop command to a child that does
186// not handle stop commands causes the child to exit immediately.
187func TestStopNoHandler(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700188 sh, h, s := newShell(t, "handleCustom")
189 defer sh.Cleanup(os.Stderr, os.Stderr)
190 s.Expect("ready")
191 fmt.Fprintf(h.Stdin(), "stop\n")
192 testExitStatus(t, h, s, veyron2.UnhandledStopExitCode)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700193}
194
195// TestDoubleSignal verifies that sending a succession of two signals to a child
196// that handles these signals by default causes the child to exit immediately
197// upon receiving the second signal.
198func TestDoubleSignal(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700199 sh, h, s := newShell(t, "handleDefaults")
200 defer sh.Cleanup(os.Stderr, os.Stderr)
201 s.Expect("ready")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700202 checkSignalIsDefault(t, syscall.SIGTERM)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700203 syscall.Kill(h.Pid(), syscall.SIGTERM)
204 s.Expectf("received signal %s", syscall.SIGTERM)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700205 checkSignalIsDefault(t, syscall.SIGINT)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700206 syscall.Kill(h.Pid(), syscall.SIGINT)
207 testExitStatus(t, h, s, DoubleStopExitCode)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700208}
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.
213func TestSignalAndStop(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700214 sh, h, s := newShell(t, "handleDefaults")
215 defer sh.Cleanup(os.Stderr, os.Stderr)
216 s.Expect("ready")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700217 checkSignalIsDefault(t, syscall.SIGTERM)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700218 syscall.Kill(h.Pid(), syscall.SIGTERM)
219 s.Expectf("received signal %s", syscall.SIGTERM)
220 fmt.Fprintf(h.Stdin(), "stop\n")
221 testExitStatus(t, h, s, DoubleStopExitCode)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700222}
223
224// TestDoubleStop verifies that sending a succession of stop commands to a child
225// that handles stop commands by default causes the child to exit immediately
226// upon receiving the second stop command.
227func TestDoubleStop(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700228 sh, h, s := newShell(t, "handleDefaults")
229 defer sh.Cleanup(os.Stderr, os.Stderr)
230 s.Expect("ready")
231 fmt.Fprintf(h.Stdin(), "stop\n")
232 s.Expectf("received signal %s", veyron2.LocalStop)
233 fmt.Fprintf(h.Stdin(), "stop\n")
234 testExitStatus(t, h, s, DoubleStopExitCode)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700235}
236
237// TestSendUnhandledSignal verifies that sending a signal that the child does
238// not handle causes the child to exit as per the signal being sent.
239func TestSendUnhandledSignal(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700240 sh, h, s := newShell(t, "handleDefaults")
241 defer sh.Cleanup(os.Stderr, os.Stderr)
242 s.Expect("ready")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700243 checkSignalIsNotDefault(t, syscall.SIGABRT)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700244 syscall.Kill(h.Pid(), syscall.SIGABRT)
245 testExitStatus(t, h, s, 2)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700246}
247
248// TestDoubleSignalIgnoreChan verifies that, even if we ignore the channel that
249// ShutdownOnSignals returns, sending two signals should still cause the
250// process to exit (ensures that there is no dependency in ShutdownOnSignals
251// on having a goroutine read from the returned channel).
252func TestDoubleSignalIgnoreChan(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700253 sh, h, s := newShell(t, "handleDefaultsIgnoreChan")
254 defer sh.Cleanup(os.Stderr, os.Stderr)
255 s.Expect("ready")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700256 // Even if we ignore the channel that ShutdownOnSignals returns,
257 // sending two signals should still cause the process to exit.
258 checkSignalIsDefault(t, syscall.SIGTERM)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700259 syscall.Kill(h.Pid(), syscall.SIGTERM)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700260 checkSignalIsDefault(t, syscall.SIGINT)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700261 syscall.Kill(h.Pid(), syscall.SIGINT)
262 testExitStatus(t, h, s, DoubleStopExitCode)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700263}
264
265// TestHandlerCustomSignal verifies that sending a non-default signal to a
266// server that listens for that signal causes the server to shut down cleanly.
267func TestHandlerCustomSignal(t *testing.T) {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700268 sh, h, s := newShell(t, "handleCustom")
269 defer sh.Cleanup(os.Stderr, os.Stderr)
270 s.Expect("ready")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700271 checkSignalIsNotDefault(t, syscall.SIGABRT)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700272 syscall.Kill(h.Pid(), syscall.SIGABRT)
273 s.Expectf("received signal %s", syscall.SIGABRT)
274 fmt.Fprintf(h.Stdin(), "stop\n")
275 s.ExpectEOF()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700276}
Bogdan Caprita1002ba42014-06-06 19:24:40 -0700277
278// TestHandlerCustomSignalWithStop verifies that sending a custom stop signal
279// to a server that listens for that signal causes the server to shut down
280// cleanly, even when a STOP signal is also among the handled signals.
281func TestHandlerCustomSignalWithStop(t *testing.T) {
Jiri Simsa7fc6e872014-06-09 09:22:53 -0700282 for _, signal := range []syscall.Signal{syscall.SIGABRT, syscall.SIGHUP} {
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700283 sh, h, s := newShell(t, "handleCustomWithStop")
284 s.Expect("ready")
Bogdan Caprita1002ba42014-06-06 19:24:40 -0700285 checkSignalIsNotDefault(t, signal)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700286 syscall.Kill(h.Pid(), signal)
287 s.Expectf("received signal %s", signal)
288 fmt.Fprintf(h.Stdin(), "close\n")
289 s.ExpectEOF()
290 sh.Cleanup(os.Stderr, os.Stderr)
Bogdan Caprita1002ba42014-06-06 19:24:40 -0700291 }
292}
293
294// TestParseSignalsList verifies that ShutdownOnSignals correctly interprets
295// the input list of signals.
296func TestParseSignalsList(t *testing.T) {
297 list := []os.Signal{STOP, syscall.SIGTERM}
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -0800298 ShutdownOnSignals(nil, list...)
Bogdan Caprita1002ba42014-06-06 19:24:40 -0700299 if !isSignalInSet(syscall.SIGTERM, list) {
300 t.Errorf("signal %s not in signal set, as expected: %v", syscall.SIGTERM, list)
301 }
302 if !isSignalInSet(STOP, list) {
303 t.Errorf("signal %s not in signal set, as expected: %v", STOP, list)
304 }
305}
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700306
307type configServer struct {
308 ch chan<- string
309}
310
311func (c *configServer) Set(_ ipc.ServerContext, key, value string) error {
312 if key != mgmt.AppCycleManagerConfigKey {
313 return fmt.Errorf("Unexpected key: %v", key)
314 }
315 c.ch <- value
316 return nil
317
318}
319
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -0800320func createConfigServer(t *testing.T, runtime veyron2.Runtime) (ipc.Server, string, <-chan string) {
321 server, err := runtime.NewServer()
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700322 if err != nil {
323 t.Fatalf("Got error: %v", err)
324 }
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700325 ch := make(chan string)
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800326 var ep []naming.Endpoint
Cosmos Nicolaouf8d4c2b2014-10-23 22:36:38 -0700327 if ep, err = server.Listen(profiles.LocalListenSpec); err != nil {
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700328 t.Fatalf("Got error: %v", err)
329 }
Bogdan Capritaa456f472014-12-10 10:18:03 -0800330 if err := server.Serve("", device.ConfigServer(&configServer{ch}), vflag.NewAuthorizerOrDie()); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700331 t.Fatalf("Got error: %v", err)
332 }
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800333 return server, naming.JoinAddressName(ep[0].String(), ""), ch
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700334
335}
336
337// TestCleanRemoteShutdown verifies that remote shutdown works correctly.
338func TestCleanRemoteShutdown(t *testing.T) {
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -0800339 runtime, err := rt.New()
340 if err != nil {
341 panic(err)
342 }
343 defer runtime.Cleanup()
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700344
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800345 sh, err := modules.NewShell(nil)
346 if err != nil {
347 t.Fatalf("unexpected error: %s", err)
348 }
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700349 defer sh.Cleanup(os.Stderr, os.Stderr)
350
Asim Shankar88292912014-10-09 19:41:07 -0700351 // Set the child process up with a blessing from the parent so that
352 // the default authorization works for RPCs between the two.
Ankur77cd9e82014-12-15 12:59:59 -0800353 childcreds, _ := security.ForkCredentials(runtime.Principal(), "child")
Asim Shankar88292912014-10-09 19:41:07 -0700354 defer os.RemoveAll(childcreds)
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -0800355 configServer, configServiceName, ch := createConfigServer(t, runtime)
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700356 defer configServer.Stop()
Asim Shankar95910b62014-10-31 22:02:29 -0700357 sh.SetVar(consts.VeyronCredentials, childcreds)
Jiri Simsa37893392014-11-07 10:55:45 -0800358 sh.SetConfigKey(mgmt.ParentNameConfigKey, configServiceName)
359 sh.SetConfigKey(mgmt.ProtocolConfigKey, "tcp")
360 sh.SetConfigKey(mgmt.AddressConfigKey, "127.0.0.1:0")
Cosmos Nicolaou612ad382014-10-29 19:41:35 -0700361 h, err := sh.Start("handleDefaults", nil)
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700362 if err != nil {
363 t.Fatalf("unexpected error: %s", err)
364 }
365 s := expect.NewSession(t, h.Stdout(), time.Minute)
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700366 appCycleName := <-ch
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700367 s.Expect("ready")
Todd Wang702385a2014-11-07 01:54:08 -0800368 appCycle := appcycle.AppCycleClient(appCycleName)
Matt Rosencrantzc7fecf12014-11-27 19:58:43 -0800369 stream, err := appCycle.Stop(runtime.NewContext())
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700370 if err != nil {
371 t.Fatalf("Got error: %v", err)
372 }
Shyam Jayaraman97b9dca2014-07-31 13:30:46 -0700373 rStream := stream.RecvStream()
374 if rStream.Advance() || rStream.Err() != nil {
375 t.Errorf("Expected EOF, got (%v, %v) instead: ", rStream.Value(), rStream.Err())
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700376 }
377 if err := stream.Finish(); err != nil {
378 t.Fatalf("Got error: %v", err)
379 }
Cosmos Nicolaoucc581722014-10-07 12:45:39 -0700380 s.Expectf("received signal %s", veyron2.RemoteStop)
381 fmt.Fprintf(h.Stdin(), "close\n")
382 s.ExpectEOF()
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700383}