blob: cee9708e90b900d7e5ddd92c32980e04fbb270d8 [file] [log] [blame]
Cosmos Nicolaou62613842014-08-25 21:57:37 -07001package modules_test
2
3import (
4 "bufio"
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -07005 "bytes"
Ankur9f957942014-11-24 16:34:18 -08006 "errors"
Cosmos Nicolaou62613842014-08-25 21:57:37 -07007 "fmt"
8 "io"
Cosmos Nicolaou1e78ccc2014-10-09 08:10:26 -07009 "os"
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -080010 "reflect"
Cosmos Nicolaou5339a7b2014-11-18 17:28:00 -080011 "sort"
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070012 "strings"
Bogdan Caprita490a4512014-11-20 21:12:19 -080013 "syscall"
Cosmos Nicolaou62613842014-08-25 21:57:37 -070014 "testing"
15 "time"
16
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070017 "veyron.io/veyron/veyron/lib/exec"
Ankur9f957942014-11-24 16:34:18 -080018 "veyron.io/veyron/veyron/lib/flags/consts"
Jiri Simsa519c5072014-09-17 21:37:57 -070019 "veyron.io/veyron/veyron/lib/modules"
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070020 "veyron.io/veyron/veyron/lib/testutil"
Ankur9f957942014-11-24 16:34:18 -080021 tsecurity "veyron.io/veyron/veyron/lib/testutil/security"
22 _ "veyron.io/veyron/veyron/profiles"
23 vsecurity "veyron.io/veyron/veyron/security"
24
25 "veyron.io/veyron/veyron2/security"
Cosmos Nicolaou62613842014-08-25 21:57:37 -070026)
27
Ankur9f957942014-11-24 16:34:18 -080028const credentialsEnvPrefix = "\"" + consts.VeyronCredentials + "="
29
Cosmos Nicolaou62613842014-08-25 21:57:37 -070030func init() {
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -070031 testutil.Init()
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070032 modules.RegisterChild("envtest", "envtest: <variables to print>...", PrintFromEnv)
33 modules.RegisterChild("printenv", "printenv", PrintEnv)
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -080034 modules.RegisterChild("echos", "[args]*", Echo)
35 modules.RegisterChild("errortestChild", "", ErrorMain)
Bogdan Caprita490a4512014-11-20 21:12:19 -080036 modules.RegisterChild("ignores_stdin", "", ignoresStdin)
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -080037
38 modules.RegisterFunction("envtestf", "envtest: <variables to print>...", PrintFromEnv)
39 modules.RegisterFunction("echof", "[args]*", Echo)
40 modules.RegisterFunction("errortestFunc", "", ErrorMain)
Bogdan Caprita490a4512014-11-20 21:12:19 -080041}
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -080042
Bogdan Caprita490a4512014-11-20 21:12:19 -080043func ignoresStdin(io.Reader, io.Writer, io.Writer, map[string]string, ...string) error {
44 <-time.After(time.Minute)
45 return nil
Cosmos Nicolaou62613842014-08-25 21:57:37 -070046}
47
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070048func Echo(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
49 for _, a := range args {
50 fmt.Fprintf(stdout, "stdout: %s\n", a)
51 fmt.Fprintf(stderr, "stderr: %s\n", a)
52 }
53 return nil
54}
55
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070056func PrintFromEnv(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
57 for _, a := range args[1:] {
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070058 if v := env[a]; len(v) > 0 {
Cosmos Nicolaou74cc9b22014-10-23 15:25:35 -070059 fmt.Fprintf(stdout, "%s\n", a+"="+v)
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -070060 } else {
61 fmt.Fprintf(stderr, "missing %s\n", a)
62 }
63 }
64 modules.WaitForEOF(stdin)
65 fmt.Fprintf(stdout, "done\n")
66 return nil
67}
68
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070069const printEnvArgPrefix = "PRINTENV_ARG="
70
Cosmos Nicolaou62613842014-08-25 21:57:37 -070071func PrintEnv(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
72 for _, a := range args {
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070073 fmt.Fprintf(stdout, "%s%s\n", printEnvArgPrefix, a)
Cosmos Nicolaou62613842014-08-25 21:57:37 -070074 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070075 for k, v := range env {
Cosmos Nicolaou74cc9b22014-10-23 15:25:35 -070076 fmt.Fprintf(stdout, "%q\n", k+"="+v)
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -070077 }
Cosmos Nicolaou62613842014-08-25 21:57:37 -070078 return nil
79}
80
Cosmos Nicolaou66afced2014-09-15 22:12:43 -070081func ErrorMain(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
82 return fmt.Errorf("an error")
83}
84
Cosmos Nicolaou62613842014-08-25 21:57:37 -070085func waitForInput(scanner *bufio.Scanner) bool {
86 ch := make(chan struct{})
87 go func(ch chan<- struct{}) {
88 scanner.Scan()
89 ch <- struct{}{}
90 }(ch)
91 select {
92 case <-ch:
93 return true
94 case <-time.After(10 * time.Second):
95 return false
96 }
97}
98
99func testCommand(t *testing.T, sh *modules.Shell, name, key, val string) {
Cosmos Nicolaou612ad382014-10-29 19:41:35 -0700100 h, err := sh.Start(name, nil, key)
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700101 if err != nil {
102 t.Fatalf("unexpected error: %s", err)
103 }
104 defer func() {
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700105 var stdout, stderr bytes.Buffer
106 sh.Cleanup(&stdout, &stderr)
107 if len(stdout.String()) != 0 {
108 t.Errorf("unexpected stdout: %q", stdout.String())
109 }
110 if len(stderr.String()) != 0 {
111 t.Errorf("unexpected stderr: %q", stderr.String())
112 }
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700113 }()
114 scanner := bufio.NewScanner(h.Stdout())
115 if !waitForInput(scanner) {
116 t.Errorf("timeout")
117 return
118 }
119 if got, want := scanner.Text(), key+"="+val; got != want {
120 t.Errorf("got %q, want %q", got, want)
121 }
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700122 h.CloseStdin()
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700123 if !waitForInput(scanner) {
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -0700124 t.Fatalf("timeout")
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700125 return
126 }
127 if got, want := scanner.Text(), "done"; got != want {
128 t.Errorf("got %q, want %q", got, want)
129 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700130 if err := h.Shutdown(nil, nil); err != nil {
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700131 t.Fatalf("unexpected error: %s", err)
132 }
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700133}
134
135func TestChild(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800136 sh, err := modules.NewShell(nil)
137 if err != nil {
138 t.Fatalf("unexpected error: %s", err)
139 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700140 defer sh.Cleanup(nil, nil)
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700141 key, val := "simpleVar", "foo & bar"
142 sh.SetVar(key, val)
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700143 testCommand(t, sh, "envtest", key, val)
144}
145
Cosmos Nicolaou1e78ccc2014-10-09 08:10:26 -0700146func TestChildNoRegistration(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800147 sh, err := modules.NewShell(nil)
148 if err != nil {
149 t.Fatalf("unexpected error: %s", err)
150 }
Cosmos Nicolaou1e78ccc2014-10-09 08:10:26 -0700151 defer sh.Cleanup(os.Stderr, os.Stderr)
152 key, val := "simpleVar", "foo & bar"
153 sh.SetVar(key, val)
154 testCommand(t, sh, "envtest", key, val)
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800155 _, err = sh.Start("non-existent-command", nil, "random", "args")
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -0800156 if err == nil {
157 t.Fatalf("expected error")
Cosmos Nicolaou1e78ccc2014-10-09 08:10:26 -0700158 }
159}
160
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700161func TestFunction(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800162 sh, err := modules.NewShell(nil)
163 if err != nil {
164 t.Fatalf("unexpected error: %s", err)
165 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700166 defer sh.Cleanup(nil, nil)
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700167 key, val := "simpleVar", "foo & bar & baz"
168 sh.SetVar(key, val)
Cosmos Nicolaou1e78ccc2014-10-09 08:10:26 -0700169 testCommand(t, sh, "envtestf", key, val)
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700170}
171
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700172func TestErrorChild(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800173 sh, err := modules.NewShell(nil)
174 if err != nil {
175 t.Fatalf("unexpected error: %s", err)
176 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700177 defer sh.Cleanup(nil, nil)
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -0800178 h, err := sh.Start("errortestChild", nil)
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700179 if err != nil {
180 t.Fatalf("unexpected error: %s", err)
181 }
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -0700182 if got, want := h.Shutdown(nil, nil), "exit status 255"; got == nil || got.Error() != want {
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700183 t.Errorf("got %q, want %q", got, want)
184 }
185}
186
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -0800187func testShutdown(t *testing.T, sh *modules.Shell, command string, isfunc bool) {
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700188 result := ""
189 args := []string{"a", "b c", "ddd"}
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -0800190 if _, err := sh.Start(command, nil, args...); err != nil {
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700191 t.Fatalf("unexpected error: %s", err)
192 }
193 var stdoutBuf bytes.Buffer
194 var stderrBuf bytes.Buffer
195 sh.Cleanup(&stdoutBuf, &stderrBuf)
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -0800196 stdoutOutput, stderrOutput := "stdout: "+command+"\n", "stderr: "+command+"\n"
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700197 for _, a := range args {
198 stdoutOutput += fmt.Sprintf("stdout: %s\n", a)
199 stderrOutput += fmt.Sprintf("stderr: %s\n", a)
200 }
201 if got, want := stdoutBuf.String(), stdoutOutput+result; got != want {
202 t.Errorf("got %q want %q", got, want)
203 }
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -0700204 if !isfunc {
205 stderrBuf.ReadString('\n') // Skip past the random # generator output
206 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700207 if got, want := stderrBuf.String(), stderrOutput; got != want {
208 t.Errorf("got %q want %q", got, want)
209 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700210}
211
212func TestShutdownSubprocess(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800213 sh, err := modules.NewShell(nil)
214 if err != nil {
215 t.Fatalf("unexpected error: %s", err)
216 }
217 testShutdown(t, sh, "echos", false)
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700218}
219
Bogdan Caprita490a4512014-11-20 21:12:19 -0800220// TestShutdownSubprocessIgnoresStdin verifies that Shutdown doesn't wait
221// forever if a child does not die upon closing stdin; but instead times out and
222// returns an appropriate error.
223func TestShutdownSubprocessIgnoresStdin(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800224 sh, err := modules.NewShell(nil)
225 if err != nil {
226 t.Fatalf("unexpected error: %s", err)
227 }
Bogdan Caprita490a4512014-11-20 21:12:19 -0800228 sh.SetWaitTimeout(time.Second)
229 h, err := sh.Start("ignores_stdin", nil)
230 if err != nil {
231 t.Fatalf("unexpected error: %s", err)
232 }
233 var stdoutBuf, stderrBuf bytes.Buffer
234 if err := sh.Cleanup(&stdoutBuf, &stderrBuf); err == nil || err.Error() != exec.ErrTimeout.Error() {
235 t.Errorf("unexpected error in Cleanup: got %v, want %v", err, exec.ErrTimeout)
236 }
237 if err := syscall.Kill(h.Pid(), syscall.SIGINT); err != nil {
238 t.Errorf("Kill failed: %v", err)
239 }
240}
241
242// TestStdoutRace exemplifies a potential race between reading from child's
243// stdout and closing stdout in Wait (called by Shutdown).
244//
245// NOTE: triggering the actual --race failure is hard, even if the
246// implementation inappropriately sets stdout to the file that is to be closed
247// in Wait.
248func TestStdoutRace(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800249 sh, err := modules.NewShell(nil)
250 if err != nil {
251 t.Fatalf("unexpected error: %s", err)
252 }
Bogdan Caprita490a4512014-11-20 21:12:19 -0800253 sh.SetWaitTimeout(time.Second)
254 h, err := sh.Start("ignores_stdin", nil)
255 if err != nil {
256 t.Fatalf("unexpected error: %s", err)
257 }
258 ch := make(chan error, 1)
259 go func() {
260 buf := make([]byte, 5)
261 // This will block since the child is not writing anything on
262 // stdout.
263 _, err := h.Stdout().Read(buf)
264 ch <- err
265 }()
266 // Give the goroutine above a chance to run, so that we're blocked on
267 // stdout.Read.
268 <-time.After(time.Second)
269 // Cleanup should close stdout, and unblock the goroutine.
270 sh.Cleanup(nil, nil)
271 if got, want := <-ch, io.EOF; got != want {
272 t.Errorf("Expected %v, got %v instead", want, got)
273 }
274
275 if err := syscall.Kill(h.Pid(), syscall.SIGINT); err != nil {
276 t.Errorf("Kill failed: %v", err)
277 }
278}
279
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700280func TestShutdownFunction(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800281 sh, err := modules.NewShell(nil)
282 if err != nil {
283 t.Fatalf("unexpected error: %s", err)
284 }
285 testShutdown(t, sh, "echof", true)
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700286}
287
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700288func TestErrorFunc(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800289 sh, err := modules.NewShell(nil)
290 if err != nil {
291 t.Fatalf("unexpected error: %s", err)
292 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700293 defer sh.Cleanup(nil, nil)
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -0800294 h, err := sh.Start("errortestFunc", nil)
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700295 if err != nil {
296 t.Fatalf("unexpected error: %s", err)
297 }
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700298 if got, want := h.Shutdown(nil, nil), "an error"; got != nil && got.Error() != want {
Cosmos Nicolaou66afced2014-09-15 22:12:43 -0700299 t.Errorf("got %q, want %q", got, want)
300 }
301}
302
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700303func find(want string, in []string) bool {
304 for _, a := range in {
305 if a == want {
306 return true
307 }
308 }
309 return false
310}
311
312func TestEnvelope(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800313 sh, err := modules.NewShell(nil)
314 if err != nil {
315 t.Fatalf("unexpected error: %s", err)
316 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700317 defer sh.Cleanup(nil, nil)
318 sh.SetVar("a", "1")
319 sh.SetVar("b", "2")
320 args := []string{"oh", "ah"}
Cosmos Nicolaou612ad382014-10-29 19:41:35 -0700321 h, err := sh.Start("printenv", nil, args...)
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700322 if err != nil {
323 t.Fatalf("unexpected error: %s", err)
324 }
325 scanner := bufio.NewScanner(h.Stdout())
326 childArgs, childEnv := []string{}, []string{}
327 for scanner.Scan() {
328 o := scanner.Text()
329 if strings.HasPrefix(o, printEnvArgPrefix) {
330 childArgs = append(childArgs, strings.TrimPrefix(o, printEnvArgPrefix))
331 } else {
332 childEnv = append(childEnv, o)
333 }
334 }
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -0700335 shArgs, shEnv := sh.CommandEnvelope("printenv", nil, args...)
Cosmos Nicolaou74cc9b22014-10-23 15:25:35 -0700336 for i, ev := range shEnv {
337 shEnv[i] = fmt.Sprintf("%q", ev)
338 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700339 for _, want := range args {
340 if !find(want, childArgs) {
341 t.Errorf("failed to find %q in %s", want, childArgs)
342 }
343 if !find(want, shArgs) {
344 t.Errorf("failed to find %q in %s", want, shArgs)
345 }
346 }
347
Ankur9f957942014-11-24 16:34:18 -0800348 foundVeyronCredentials := false
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700349 for _, want := range shEnv {
Ankur9f957942014-11-24 16:34:18 -0800350 if strings.HasPrefix(want, credentialsEnvPrefix) {
351 foundVeyronCredentials = true
352 continue
353 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700354 if !find(want, childEnv) {
Cosmos Nicolaou74cc9b22014-10-23 15:25:35 -0700355 t.Errorf("failed to find %s in %#v", want, childEnv)
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700356 }
357 }
Ankur9f957942014-11-24 16:34:18 -0800358 if !foundVeyronCredentials {
359 t.Errorf("%v environment variable not set in command envelope", consts.VeyronCredentials)
360 }
361
362 foundVeyronCredentials = false
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700363 for _, want := range childEnv {
Cosmos Nicolaou74cc9b22014-10-23 15:25:35 -0700364 if want == "\""+exec.VersionVariable+"=\"" {
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700365 continue
366 }
Ankur9f957942014-11-24 16:34:18 -0800367 if strings.HasPrefix(want, credentialsEnvPrefix) {
368 foundVeyronCredentials = true
369 continue
370 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700371 if !find(want, shEnv) {
Cosmos Nicolaou74cc9b22014-10-23 15:25:35 -0700372 t.Errorf("failed to find %s in %#v", want, shEnv)
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700373 }
374 }
Ankur9f957942014-11-24 16:34:18 -0800375 if !foundVeyronCredentials {
376 t.Errorf("%v environment variable not set for command", consts.VeyronCredentials)
377 }
378}
379
380func TestEnvCredentials(t *testing.T) {
381 startChildAndGetCredentials := func(sh *modules.Shell, env []string) string {
382 h, err := sh.Start("printenv", env)
383 if err != nil {
384 t.Fatalf("unexpected error: %s", err)
385 }
386 defer h.Shutdown(os.Stderr, os.Stderr)
387 scanner := bufio.NewScanner(h.Stdout())
388 for scanner.Scan() {
389 o := scanner.Text()
390 if strings.HasPrefix(o, credentialsEnvPrefix) {
391 return strings.TrimSuffix(strings.TrimPrefix(o, credentialsEnvPrefix), "\"")
392 }
393 }
394 return ""
395 }
396 validateCredentials := func(dir string, wantBlessing string) error {
397 if len(dir) == 0 {
398 return errors.New("credentials directory not found")
399 }
400 p, err := vsecurity.LoadPersistentPrincipal(dir, nil)
401 if err != nil {
402 return err
403 }
404 def := p.BlessingStore().Default()
405 if blessingsSharedWithAll := p.BlessingStore().ForPeer("random_peer"); !reflect.DeepEqual(blessingsSharedWithAll, def) {
406 return fmt.Errorf("Blessing shared with all peers: %v is different from default Blessings: %v", blessingsSharedWithAll, def)
407 }
408 if got := def.ForContext(security.NewContext(&security.ContextParams{LocalPrincipal: p})); len(got) != 1 || got[0] != wantBlessing {
409 return fmt.Errorf("got blessings: %v, want exactly one blessing: %v", got, wantBlessing)
410 }
411 return nil
412 }
413
414 // Test child credentials when runtime is not initialized and VeyronCredentials
415 // is not set.
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800416 sh, err := modules.NewShell(nil)
417 if err != nil {
418 t.Fatalf("unexpected error: %s", err)
419 }
Ankur9f957942014-11-24 16:34:18 -0800420 defer sh.Cleanup(nil, nil)
421 if err := validateCredentials(startChildAndGetCredentials(sh, nil), "test-shell/child"); err != nil {
422 t.Fatal(err)
423 }
424
425 // Test that no two children have the same credentials directory.
426 if cred1, cred2 := startChildAndGetCredentials(sh, nil), startChildAndGetCredentials(sh, nil); cred1 == cred2 {
427 t.Fatalf("The same credentials directory %v was set for two children", cred1)
428 }
429
430 // Test child credentials when VeyronCredentials are set.
431 root := tsecurity.NewPrincipal("root")
432 old := os.Getenv(consts.VeyronCredentials)
433 defer os.Setenv(consts.VeyronCredentials, old)
434 dir := tsecurity.NewVeyronCredentials(root, "os")
435 defer os.RemoveAll(dir)
436 if err := os.Setenv(consts.VeyronCredentials, dir); err != nil {
437 t.Fatal(err)
438 }
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800439 sh, err = modules.NewShell(nil)
440 if err != nil {
441 t.Fatalf("unexpected error: %s", err)
442 }
Ankur9f957942014-11-24 16:34:18 -0800443 if err := validateCredentials(startChildAndGetCredentials(sh, nil), "root/os/child"); err != nil {
444 t.Fatal(err)
445 }
446 sh.Cleanup(nil, nil)
447
448 // Test that os VeyronCredentials are not deleted by the Cleanup.
449 if finfo, err := os.Stat(dir); err != nil || !finfo.IsDir() {
450 t.Fatalf("%q is not a directory", dir)
451 }
452
453 // Test that VeyronCredentials specified on the shell override the OS ones.
454 dir = tsecurity.NewVeyronCredentials(root, "shell")
455 defer os.RemoveAll(dir)
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800456 sh, err = modules.NewShell(nil)
457 if err != nil {
458 t.Fatalf("unexpected error: %s", err)
459 }
Ankur9f957942014-11-24 16:34:18 -0800460 sh.SetVar(consts.VeyronCredentials, dir)
461 if err := validateCredentials(startChildAndGetCredentials(sh, nil), "root/shell/child"); err != nil {
462 t.Fatal(err)
463 }
464 sh.ClearVar(consts.VeyronCredentials)
465 if credentials := startChildAndGetCredentials(sh, nil); len(credentials) != 0 {
466 t.Fatalf("found credentials %v set for child even when shell credentials were cleared", credentials)
467 }
468 anotherDir := tsecurity.NewVeyronCredentials(root, "anotherShell")
469 defer os.RemoveAll(anotherDir)
470 sh.SetVar(consts.VeyronCredentials, anotherDir)
471 if err := validateCredentials(startChildAndGetCredentials(sh, nil), "root/anotherShell/child"); err != nil {
472 t.Fatal(err)
473 }
474
475 // Test that VeyronCredentials specified as a parameter overrides the OS and
476 // shell ones.
477 dir = tsecurity.NewVeyronCredentials(root, "param")
478 defer os.RemoveAll(dir)
479 env := []string{consts.VeyronCredentials + "=" + dir}
480 if err := validateCredentials(startChildAndGetCredentials(sh, env), "root/param"); err != nil {
481 t.Fatal(err)
482 }
483
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700484}
485
486func TestEnvMerge(t *testing.T) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -0800487 sh, err := modules.NewShell(nil)
488 if err != nil {
489 t.Fatalf("unexpected error: %s", err)
490 }
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700491 defer sh.Cleanup(nil, nil)
492 sh.SetVar("a", "1")
493 os.Setenv("a", "wrong, should be 1")
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -0700494 sh.SetVar("b", "2 also wrong")
495 os.Setenv("b", "wrong, should be 2")
Cosmos Nicolaou612ad382014-10-29 19:41:35 -0700496 h, err := sh.Start("printenv", []string{"b=2"})
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700497 if err != nil {
498 t.Fatalf("unexpected error: %s", err)
499 }
500 scanner := bufio.NewScanner(h.Stdout())
501 for scanner.Scan() {
502 o := scanner.Text()
503 if strings.HasPrefix(o, "a=") {
504 if got, want := o, "a=1"; got != want {
Cosmos Nicolaou2cb05fb2014-10-23 13:37:32 -0700505 t.Errorf("got: %q, want %q", got, want)
506 }
507 }
508 if strings.HasPrefix(o, "b=") {
509 if got, want := o, "b=2"; got != want {
510 t.Errorf("got: %q, want %q", got, want)
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700511 }
512 }
513 }
514}
515
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -0800516func TestSetEntryPoint(t *testing.T) {
517 env := map[string]string{"a": "a", "b": "b"}
518 nenv := modules.SetEntryPoint(env, "eg1")
519 if got, want := len(nenv), 3; got != want {
520 t.Errorf("got %d, want %d", got, want)
521 }
522 nenv = modules.SetEntryPoint(env, "eg2")
523 if got, want := len(nenv), 3; got != want {
524 t.Errorf("got %d, want %d", got, want)
525 }
Cosmos Nicolaou5339a7b2014-11-18 17:28:00 -0800526 sort.Strings(nenv)
527 if got, want := nenv, []string{"VEYRON_SHELL_HELPER_PROCESS_ENTRY_POINT=eg2", "a=a", "b=b"}; !reflect.DeepEqual(got, want) {
Cosmos Nicolaoud4f00562014-11-17 20:35:48 -0800528 t.Errorf("got %d, want %d", got, want)
529 }
530}
531
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700532func TestHelperProcess(t *testing.T) {
Cosmos Nicolaoubbae3882014-10-02 22:58:19 -0700533 modules.DispatchInTest()
Cosmos Nicolaou62613842014-08-25 21:57:37 -0700534}
535
Cosmos Nicolaoue664f3f2014-10-20 17:40:05 -0700536// TODO(cnicolaou): test for error return from cleanup