blob: c4e546e2996497fab2de996cb03fdd80241f8b4b [file] [log] [blame]
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -07001package exec_test
Jiri Simsa5293dcb2014-05-10 09:56:38 -07002
3import (
4 "fmt"
5 "io"
6 "log"
7 "os"
8 "os/exec"
Cosmos Nicolaou1c18c1c2014-10-08 16:37:10 -07009 "strings"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070010 "sync"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070011 "testing"
12 "time"
13
Jiri Simsa764efb72014-12-25 20:57:03 -080014 vexec "v.io/core/veyron/lib/exec"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070015 // Use mock timekeeper to avoid actually sleeping during the test.
Jiri Simsa764efb72014-12-25 20:57:03 -080016 "v.io/core/veyron/lib/testutil/timekeeper"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070017)
18
Jiri Simsac199bc12014-05-30 12:52:24 -070019// We always expect there to be exactly three open file descriptors
20// when the test starts out: STDIN, STDOUT, and STDERR. This
21// assumption is tested in init below, and in the rare cases where it
22// is wrong, we bail out.
Jiri Simsa5293dcb2014-05-10 09:56:38 -070023const baselineOpenFiles = 3
24
25func init() {
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -070026 if os.Getenv("GO_WANT_HELPER_PROCESS_EXEC") == "1" {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070027 return
28 }
29 if want, got := baselineOpenFiles, openFiles(); want != got {
Jiri Simsac199bc12014-05-30 12:52:24 -070030 message := `Test expected to start with %d open files, found %d instead.
31This can happen if parent process has any open file descriptors,
32e.g. pipes, that are being inherited.`
33 panic(fmt.Errorf(message, want, got))
Jiri Simsa5293dcb2014-05-10 09:56:38 -070034 }
35}
36
Jiri Simsac199bc12014-05-30 12:52:24 -070037// These tests need to run a subprocess and we reuse this same test
38// binary to do so. A fake test 'TestHelperProcess' contains the code
39// we need to run in the child and we simply run this same binary with
40// a test.run= arg that runs just that test. This idea was taken from
41// the tests for os/exec.
Jiri Simsa5293dcb2014-05-10 09:56:38 -070042func helperCommand(s ...string) *exec.Cmd {
43 cs := []string{"-test.run=TestHelperProcess", "--"}
44 cs = append(cs, s...)
45 cmd := exec.Command(os.Args[0], cs...)
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -070046 cmd.Env = append([]string{"GO_WANT_HELPER_PROCESS_EXEC=1"}, os.Environ()...)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070047 return cmd
48}
49
Jiri Simsa5293dcb2014-05-10 09:56:38 -070050func openFiles() int {
51 f, err := os.Open("/dev/null")
52 if err != nil {
53 panic("Failed to open /dev/null\n")
54 }
55 n := f.Fd()
56 f.Close()
57 return int(n)
58}
59
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -070060func clean(t *testing.T, ph ...*vexec.ParentHandle) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070061 for _, p := range ph {
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -070062 alreadyClean := !p.Exists()
Jiri Simsa5293dcb2014-05-10 09:56:38 -070063 p.Clean()
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -070064 if !alreadyClean && p.Exists() {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070065 t.Errorf("child process left behind even after calling Clean")
66 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -070067 }
68 if want, got := baselineOpenFiles, openFiles(); want != got {
69 t.Errorf("Leaking file descriptors: expect %d, got %d", want, got)
70 }
71}
72
73func read(ch chan bool, r io.Reader, m string) {
74 buf := make([]byte, 4096*4)
75 n, err := r.Read(buf)
76 if err != nil {
77 log.Printf("failed to read message: error %s, expecting '%s'\n",
78 err, m)
79 ch <- false
80 return
81 }
82 g := string(buf[:n])
83 b := g == m
84 if !b {
85 log.Printf("read '%s', not '%s'\n", g, m)
86 }
87 ch <- b
88}
89
90func expectMessage(r io.Reader, m string) bool {
91 ch := make(chan bool, 1)
92 go read(ch, r, m)
93 select {
94 case b := <-ch:
95 return b
96 case <-time.After(5 * time.Second):
97 log.Printf("expectMessage: timeout\n")
98 return false
99 }
100 panic("unreachable")
101}
102
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700103func TestConfigExchange(t *testing.T) {
104 cmd := helperCommand("testConfig")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700105 stderr, _ := cmd.StderrPipe()
Cosmos Nicolaou486d3492014-09-30 22:21:20 -0700106 cfg := vexec.NewConfig()
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700107 cfg.Set("foo", "bar")
108 ph := vexec.NewParentHandle(cmd, vexec.ConfigOpt{cfg})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700109 err := ph.Start()
110 if err != nil {
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700111 t.Fatalf("testConfig: start: %v", err)
Jiri Simsac199bc12014-05-30 12:52:24 -0700112 }
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700113 serialized, err := cfg.Serialize()
114 if err != nil {
115 t.Fatalf("testConfig: failed to serialize config: %v", err)
116 }
117 if !expectMessage(stderr, serialized) {
Jiri Simsac199bc12014-05-30 12:52:24 -0700118 t.Errorf("unexpected output from child")
119 } else {
120 if err = cmd.Wait(); err != nil {
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700121 t.Errorf("testConfig: wait: %v", err)
Jiri Simsac199bc12014-05-30 12:52:24 -0700122 }
123 }
124 clean(t, ph)
125}
126
127func TestSecretExchange(t *testing.T) {
128 cmd := helperCommand("testSecret")
129 stderr, _ := cmd.StderrPipe()
130 ph := vexec.NewParentHandle(cmd, vexec.SecretOpt("dummy_secret"))
131 err := ph.Start()
132 if err != nil {
133 t.Fatalf("testSecretTest: start: %v", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700134 }
135 if !expectMessage(stderr, "dummy_secret") {
136 t.Errorf("unexpected output from child")
137 } else {
138 if err = cmd.Wait(); err != nil {
Jiri Simsac199bc12014-05-30 12:52:24 -0700139 t.Errorf("testSecretTest: wait: %v", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700140 }
141 }
142 clean(t, ph)
143}
144
145func TestNoVersion(t *testing.T) {
146 // Make sure that Init correctly tests for the presence of VEXEC_VERSION
Jiri Simsa84059da2014-06-02 17:22:05 -0700147 _, err := vexec.GetChildHandle()
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700148 if err != vexec.ErrNoVersion {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700149 t.Errorf("Should be missing Version")
150 }
151}
152
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700153func waitForReady(t *testing.T, cmd *exec.Cmd, name string, delay int, ph *vexec.ParentHandle) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700154 err := ph.Start()
155 if err != nil {
156 t.Fatalf("%s: start: %v", name, err)
157 return err
158 }
159 return ph.WaitForReady(time.Duration(delay) * time.Second)
160}
161
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700162func readyHelperCmd(t *testing.T, cmd *exec.Cmd, name, result string) *vexec.ParentHandle {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700163 stderr, err := cmd.StderrPipe()
164 if err != nil {
165 t.Fatalf("%s: failed to get stderr pipe\n", name)
166 }
Jiri Simsac199bc12014-05-30 12:52:24 -0700167 ph := vexec.NewParentHandle(cmd)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700168 if err := waitForReady(t, cmd, name, 4, ph); err != nil {
169 t.Errorf("%s: WaitForReady: %v (%v)", name, err, ph)
170 return nil
171 }
172 if !expectMessage(stderr, result) {
173 t.Errorf("%s: failed to read '%s' from child\n", name, result)
174 }
175 return ph
176}
177
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700178func readyHelper(t *testing.T, name, test, result string) *vexec.ParentHandle {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700179 cmd := helperCommand(test)
180 return readyHelperCmd(t, cmd, name, result)
181}
182
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700183func testMany(t *testing.T, name, test, result string) []*vexec.ParentHandle {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700184 nprocs := 10
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700185 ph := make([]*vexec.ParentHandle, nprocs)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700186 cmd := make([]*exec.Cmd, nprocs)
187 stderr := make([]io.ReadCloser, nprocs)
188 controlReaders := make([]io.ReadCloser, nprocs)
189 var done sync.WaitGroup
190 for i := 0; i < nprocs; i++ {
191 cmd[i] = helperCommand(test)
192 // The control pipe is used to signal the child when to wake up.
193 controlRead, controlWrite, err := os.Pipe()
194 if err != nil {
195 t.Errorf("Failed to create control pipe: %v", err)
196 return nil
197 }
198 controlReaders[i] = controlRead
199 cmd[i].ExtraFiles = append(cmd[i].ExtraFiles, controlRead)
200 stderr[i], _ = cmd[i].StderrPipe()
201 tk := timekeeper.NewManualTime()
Jiri Simsac199bc12014-05-30 12:52:24 -0700202 ph[i] = vexec.NewParentHandle(cmd[i], vexec.TimeKeeperOpt{tk})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700203 done.Add(1)
204 go func() {
205 // For simulated slow children, wait until the parent
206 // starts waiting, and then wake up the child.
207 if test == "testReadySlow" {
208 <-tk.Requests()
209 tk.AdvanceTime(3 * time.Second)
210 if _, err = controlWrite.Write([]byte("wake")); err != nil {
211 t.Errorf("Failed to write to control pipe: %v", err)
212 }
213 }
214 controlWrite.Close()
215 done.Done()
216 }()
217 if err := ph[i].Start(); err != nil {
218 t.Errorf("%s: Failed to start child %d: %s\n", name, i, err)
219 }
220 }
221 for i := 0; i < nprocs; i++ {
222 if err := ph[i].WaitForReady(5 * time.Second); err != nil {
223 t.Errorf("%s: Failed to wait for child %d: %s\n", name, i, err)
224 }
225 controlReaders[i].Close()
226 }
227 for i := 0; i < nprocs; i++ {
228 if !expectMessage(stderr[i], result) {
229 t.Errorf("%s: Failed to read message from child %d\n", name, i)
230 }
231 }
232 done.Wait()
233 return ph
234}
235
236func TestToReadyMany(t *testing.T) {
237 clean(t, testMany(t, "TestToReadyMany", "testReady", ".")...)
238}
239
240func TestToReadySlowMany(t *testing.T) {
241 clean(t, testMany(t, "TestToReadySlowMany", "testReadySlow", "..")...)
242}
243
244func TestToReady(t *testing.T) {
245 ph := readyHelper(t, "TestToReady", "testReady", ".")
246 clean(t, ph)
247}
248
Cosmos Nicolaou1c18c1c2014-10-08 16:37:10 -0700249func TestToFail(t *testing.T) {
250 name := "testFail"
251 cmd := helperCommand(name, "failed", "to", "start")
252 ph := vexec.NewParentHandle(cmd)
253 err := waitForReady(t, cmd, name, 4, ph)
254 if err == nil || err.Error() != "failed to start" {
255 t.Errorf("unexpected error: %v", err)
256 }
257}
258
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700259func TestNeverReady(t *testing.T) {
260 name := "testNeverReady"
261 result := "never ready"
262 cmd := helperCommand(name)
263 stderr, _ := cmd.StderrPipe()
Jiri Simsac199bc12014-05-30 12:52:24 -0700264 ph := vexec.NewParentHandle(cmd)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700265 err := waitForReady(t, cmd, name, 1, ph)
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700266 if err != vexec.ErrTimeout {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700267 t.Errorf("Failed to get timeout: got %v\n", err)
268 } else {
269 // block waiting for error from child
270 if !expectMessage(stderr, result) {
271 t.Errorf("%s: failed to read '%s' from child\n", name, result)
272 }
273 }
274 clean(t, ph)
275}
276
277func TestTooSlowToReady(t *testing.T) {
278 name := "testTooSlowToReady"
279 result := "write status_wr: broken pipe"
280 cmd := helperCommand(name)
281 // The control pipe is used to signal the child when to wake up.
282 controlRead, controlWrite, err := os.Pipe()
283 if err != nil {
284 t.Errorf("Failed to create control pipe: %v", err)
285 return
286 }
287 cmd.ExtraFiles = append(cmd.ExtraFiles, controlRead)
288 stderr, _ := cmd.StderrPipe()
289 tk := timekeeper.NewManualTime()
Jiri Simsac199bc12014-05-30 12:52:24 -0700290 ph := vexec.NewParentHandle(cmd, vexec.TimeKeeperOpt{tk})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700291 defer clean(t, ph)
292 defer controlWrite.Close()
293 defer controlRead.Close()
294 // Wait for the parent to start waiting, then simulate a timeout.
295 go func() {
296 toWait := <-tk.Requests()
297 tk.AdvanceTime(toWait)
298 }()
299 err = waitForReady(t, cmd, name, 1, ph)
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700300 if err != vexec.ErrTimeout {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700301 t.Errorf("Failed to get timeout: got %v\n", err)
302 } else {
303 // After the parent timed out, wake up the child and let it
304 // proceed.
305 if _, err = controlWrite.Write([]byte("wake")); err != nil {
306 t.Errorf("Failed to write to control pipe: %v", err)
307 } else {
308 // block waiting for error from child
309 if !expectMessage(stderr, result) {
310 t.Errorf("%s: failed to read '%s' from child\n", name, result)
311 }
312 }
313 }
314}
315
316func TestToReadySlow(t *testing.T) {
317 name := "TestToReadySlow"
318 cmd := helperCommand("testReadySlow")
319 // The control pipe is used to signal the child when to wake up.
320 controlRead, controlWrite, err := os.Pipe()
321 if err != nil {
322 t.Errorf("Failed to create control pipe: %v", err)
323 return
324 }
325 cmd.ExtraFiles = append(cmd.ExtraFiles, controlRead)
326 stderr, err := cmd.StderrPipe()
327 if err != nil {
328 t.Fatalf("%s: failed to get stderr pipe", name)
329 }
330 tk := timekeeper.NewManualTime()
Jiri Simsac199bc12014-05-30 12:52:24 -0700331 ph := vexec.NewParentHandle(cmd, vexec.TimeKeeperOpt{tk})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700332 defer clean(t, ph)
333 defer controlWrite.Close()
334 defer controlRead.Close()
335 // Wait for the parent to start waiting, simulate a short wait (but not
336 // enough to timeout the parent), then wake up the child.
337 go func() {
338 <-tk.Requests()
339 tk.AdvanceTime(2 * time.Second)
340 if _, err = controlWrite.Write([]byte("wake")); err != nil {
341 t.Errorf("Failed to write to control pipe: %v", err)
342 }
343 }()
344 if err := waitForReady(t, cmd, name, 4, ph); err != nil {
345 t.Errorf("%s: WaitForReady: %v (%v)", name, err, ph)
346 return
347 }
348 // After the child has replied, simulate a timeout on the server by
349 // advacing the time more; at this point, however, the timeout should no
350 // longer occur since the child already replied.
351 tk.AdvanceTime(2 * time.Second)
352 if result := ".."; !expectMessage(stderr, result) {
353 t.Errorf("%s: failed to read '%s' from child\n", name, result)
354 }
355}
356
357func TestToCompletion(t *testing.T) {
358 ph := readyHelper(t, "TestToCompletion", "testSuccess", "...ok")
359 e := ph.Wait(time.Second)
360 if e != nil {
361 t.Errorf("Wait failed: err %s\n", e)
362 }
363 clean(t, ph)
364}
365
366func TestToCompletionError(t *testing.T) {
367 ph := readyHelper(t, "TestToCompletionError", "testError", "...err")
368 e := ph.Wait(time.Second)
369 if e == nil {
370 t.Errorf("Wait failed: err %s\n", e)
371 }
372 clean(t, ph)
373}
374
375func TestExtraFiles(t *testing.T) {
376 cmd := helperCommand("testExtraFiles")
377 rd, wr, err := os.Pipe()
378 if err != nil {
379 t.Fatalf("Failed to create pipe: %s\n", err)
380 }
381 cmd.ExtraFiles = append(cmd.ExtraFiles, rd)
382 msg := "hello there..."
383 fmt.Fprintf(wr, msg)
384 ph := readyHelperCmd(t, cmd, "TestExtraFiles", "child: "+msg)
385 if ph == nil {
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700386 t.Fatalf("Failed to get vexec.ParentHandle\n")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700387 }
388 e := ph.Wait(1 * time.Second)
389 if e != nil {
390 t.Errorf("Wait failed: err %s\n", e)
391 }
392 rd.Close()
393 wr.Close()
394 clean(t, ph)
395}
396
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700397func TestExitEarly(t *testing.T) {
398 name := "exitEarly"
399 cmd := helperCommand(name)
400 tk := timekeeper.NewManualTime()
401 ph := vexec.NewParentHandle(cmd, vexec.TimeKeeperOpt{tk})
402 err := ph.Start()
403 if err != nil {
404 t.Fatalf("%s: start: %v", name, err)
405 }
406 e := ph.Wait(time.Second)
407 if e == nil || e.Error() != "exit status 1" {
408 t.Errorf("Unexpected value for error: %v\n", e)
409 }
410 clean(t, ph)
411}
412
Bogdan Caprita650b1622014-11-21 15:11:05 -0800413func TestWaitAndCleanRace(t *testing.T) {
Bogdan Caprita90380122014-12-10 16:43:51 -0800414 name := "testReadyAndHang"
415 cmd := helperCommand(name)
Bogdan Caprita650b1622014-11-21 15:11:05 -0800416 tk := timekeeper.NewManualTime()
417 ph := vexec.NewParentHandle(cmd, vexec.TimeKeeperOpt{tk})
Bogdan Caprita90380122014-12-10 16:43:51 -0800418 if err := waitForReady(t, cmd, name, 1, ph); err != nil {
419 t.Errorf("%s: WaitForReady: %v (%v)", name, err, ph)
Bogdan Caprita650b1622014-11-21 15:11:05 -0800420 }
421 go func() {
422 // Wait for the ph.Wait below to block, then advance the time
423 // s.t. the Wait times out.
424 <-tk.Requests()
425 tk.AdvanceTime(2 * time.Second)
426 }()
427 if got, want := ph.Wait(time.Second), vexec.ErrTimeout; got == nil || got.Error() != want.Error() {
Bogdan Caprita90380122014-12-10 16:43:51 -0800428 t.Errorf("Wait returned %v, wanted %v instead", got, want)
Bogdan Caprita650b1622014-11-21 15:11:05 -0800429 }
430 if got, want := ph.Clean(), "signal: killed"; got == nil || got.Error() != want {
Bogdan Caprita90380122014-12-10 16:43:51 -0800431 t.Errorf("Wait returned %v, wanted %v instead", got, want)
Bogdan Caprita650b1622014-11-21 15:11:05 -0800432 }
433}
434
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700435func verifyNoExecVariable() {
436 version := os.Getenv(vexec.VersionVariable)
437 if len(version) != 0 {
Bogdan Caprita90380122014-12-10 16:43:51 -0800438 log.Fatalf("Version variable %q has a value: %s", vexec.VersionVariable, version)
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700439 }
440}
441
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700442// TestHelperProcess isn't a real test; it's used as a helper process
443// for the other tests.
444func TestHelperProcess(*testing.T) {
445 // Return immediately if this is not run as the child helper
446 // for the other tests.
Cosmos Nicolaouee7abc22014-05-27 10:50:03 -0700447 if os.Getenv("GO_WANT_HELPER_PROCESS_EXEC") != "1" {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700448 return
449 }
450 defer os.Exit(0)
451
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700452 version := os.Getenv(vexec.VersionVariable)
453 if len(version) == 0 {
Bogdan Caprita90380122014-12-10 16:43:51 -0800454 log.Fatalf("Version variable %q has no value", vexec.VersionVariable)
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700455 }
456
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700457 // Write errors to stderr or using log. since the parent
458 // process is reading stderr.
459 args := os.Args
460 for len(args) > 0 {
461 if args[0] == "--" {
462 args = args[1:]
463 break
464 }
465 args = args[1:]
466 }
467
468 if len(args) == 0 {
Bogdan Caprita90380122014-12-10 16:43:51 -0800469 log.Fatal("No command")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700470 }
471
472 cmd, args := args[0], args[1:]
473
474 switch cmd {
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700475 case "exitEarly":
476 _, err := vexec.GetChildHandle()
477 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800478 log.Fatal(err)
Cosmos Nicolaou4e213d72014-10-26 22:21:52 -0700479 }
480 os.Exit(1)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700481 case "testNeverReady":
Jiri Simsa84059da2014-06-02 17:22:05 -0700482 _, err := vexec.GetChildHandle()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700483 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800484 log.Fatal(err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700485 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700486 verifyNoExecVariable()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700487 fmt.Fprintf(os.Stderr, "never ready")
488 case "testTooSlowToReady":
Jiri Simsa84059da2014-06-02 17:22:05 -0700489 ch, err := vexec.GetChildHandle()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700490 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800491 log.Fatal(err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700492 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700493 verifyNoExecVariable()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700494 // Wait for the parent to tell us when it's ok to proceed.
495 controlPipe := ch.NewExtraFile(0, "control_rd")
496 for {
497 buf := make([]byte, 100)
498 n, err := controlPipe.Read(buf)
499 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800500 log.Fatal(err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700501 }
502 if n > 0 {
503 break
504 }
505 }
506 // SetReady should return an error since the parent has
507 // timed out on us and we'd be writing to a closed pipe.
508 if err := ch.SetReady(); err != nil {
509 fmt.Fprintf(os.Stderr, "%s", err)
510 } else {
511 fmt.Fprintf(os.Stderr, "didn't get the expected error")
512 }
Cosmos Nicolaou1c18c1c2014-10-08 16:37:10 -0700513 case "testFail":
514 ch, err := vexec.GetChildHandle()
515 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800516 log.Fatal(err)
Cosmos Nicolaou1c18c1c2014-10-08 16:37:10 -0700517 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700518 verifyNoExecVariable()
Cosmos Nicolaou1c18c1c2014-10-08 16:37:10 -0700519 if err := ch.SetFailed(fmt.Errorf("%s", strings.Join(args, " "))); err != nil {
520
521 fmt.Fprintf(os.Stderr, "%s\n", err)
522 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700523 case "testReady":
Jiri Simsa84059da2014-06-02 17:22:05 -0700524 ch, err := vexec.GetChildHandle()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700525 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800526 log.Fatal(err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700527 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700528 verifyNoExecVariable()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700529 ch.SetReady()
530 fmt.Fprintf(os.Stderr, ".")
531 case "testReadySlow":
Jiri Simsa84059da2014-06-02 17:22:05 -0700532 ch, err := vexec.GetChildHandle()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700533 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800534 log.Fatal(err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700535 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700536 verifyNoExecVariable()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700537 // Wait for the parent to tell us when it's ok to proceed.
538 controlPipe := ch.NewExtraFile(0, "control_rd")
539 for {
540 buf := make([]byte, 100)
541 n, err := controlPipe.Read(buf)
542 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800543 log.Fatal(err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700544 }
545 if n > 0 {
546 break
547 }
548 }
549 ch.SetReady()
550 fmt.Fprintf(os.Stderr, "..")
Bogdan Caprita90380122014-12-10 16:43:51 -0800551 case "testReadyAndHang":
552 ch, err := vexec.GetChildHandle()
553 if err != nil {
554 log.Fatal(err)
555 }
556 verifyNoExecVariable()
557 ch.SetReady()
558 <-time.After(time.Minute)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700559 case "testSuccess", "testError":
Jiri Simsa84059da2014-06-02 17:22:05 -0700560 ch, err := vexec.GetChildHandle()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700561 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800562 log.Fatal(err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700563 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700564 verifyNoExecVariable()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700565 ch.SetReady()
566 rc := make(chan int)
567 go func() {
568 if cmd == "testError" {
569 fmt.Fprintf(os.Stderr, "...err")
570 rc <- 1
571 } else {
572 fmt.Fprintf(os.Stderr, "...ok")
573 rc <- 0
574 }
575 }()
576 r := <-rc
577 os.Exit(r)
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700578 case "testConfig":
Jiri Simsa84059da2014-06-02 17:22:05 -0700579 ch, err := vexec.GetChildHandle()
Jiri Simsac199bc12014-05-30 12:52:24 -0700580 if err != nil {
581 log.Fatalf("%v", err)
582 } else {
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700583 verifyNoExecVariable()
Bogdan Capritaa4d9ee42014-06-20 16:42:53 -0700584 serialized, err := ch.Config.Serialize()
585 if err != nil {
586 log.Fatalf("%v", err)
587 }
588 fmt.Fprintf(os.Stderr, "%s", serialized)
Jiri Simsac199bc12014-05-30 12:52:24 -0700589 }
590 case "testSecret":
Jiri Simsa84059da2014-06-02 17:22:05 -0700591 ch, err := vexec.GetChildHandle()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700592 if err != nil {
593 log.Fatalf("%s", err)
594 } else {
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700595 verifyNoExecVariable()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700596 fmt.Fprintf(os.Stderr, "%s", ch.Secret)
597 }
598 case "testExtraFiles":
Jiri Simsa84059da2014-06-02 17:22:05 -0700599 ch, err := vexec.GetChildHandle()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700600 if err != nil {
Bogdan Caprita90380122014-12-10 16:43:51 -0800601 log.Fatalf("error.... %s\n", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700602 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700603 verifyNoExecVariable()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700604 err = ch.SetReady()
605 rd := ch.NewExtraFile(0, "read")
606 buf := make([]byte, 1024)
607 if n, err := rd.Read(buf); err != nil {
608 fmt.Fprintf(os.Stderr, "child: error %s\n", err)
609 } else {
610 fmt.Fprintf(os.Stderr, "child: %s", string(buf[:n]))
611 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700612 }
613}