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 | |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 5 | package modules_test |
| 6 | |
| 7 | import ( |
| 8 | "bufio" |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 9 | "bytes" |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 10 | "fmt" |
| 11 | "io" |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 12 | "io/ioutil" |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 13 | "math/rand" |
Cosmos Nicolaou | 1e78ccc | 2014-10-09 08:10:26 -0700 | [diff] [blame] | 14 | "os" |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 15 | "reflect" |
Cosmos Nicolaou | 5339a7b | 2014-11-18 17:28:00 -0800 | [diff] [blame] | 16 | "sort" |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 17 | "strconv" |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 18 | "strings" |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 19 | "syscall" |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 20 | "testing" |
| 21 | "time" |
| 22 | |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 23 | "v.io/v23" |
Mike Burrows | ccca2f4 | 2015-03-27 13:57:29 -0700 | [diff] [blame] | 24 | "v.io/v23/verror" |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 25 | |
Asim Shankar | 59b8b69 | 2015-03-30 01:23:36 -0700 | [diff] [blame] | 26 | "v.io/x/ref/envvar" |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 27 | "v.io/x/ref/lib/exec" |
| 28 | execconsts "v.io/x/ref/lib/exec/consts" |
Jiri Simsa | ffceefa | 2015-02-28 11:03:34 -0800 | [diff] [blame] | 29 | _ "v.io/x/ref/profiles" |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 30 | vsecurity "v.io/x/ref/security" |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 31 | "v.io/x/ref/test" |
| 32 | "v.io/x/ref/test/modules" |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 33 | "v.io/x/ref/test/testutil" |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 34 | ) |
| 35 | |
| 36 | func init() { |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 37 | modules.RegisterChild("envtest", "envtest: <variables to print>...", PrintFromEnv) |
| 38 | modules.RegisterChild("printenv", "printenv", PrintEnv) |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 39 | modules.RegisterChild("printblessing", "printblessing", PrintBlessing) |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 40 | modules.RegisterChild("echos", "[args]*", Echo) |
| 41 | modules.RegisterChild("errortestChild", "", ErrorMain) |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 42 | modules.RegisterChild("ignores_stdin", "", ignoresStdin) |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 43 | modules.RegisterChild("pipeProc", "", pipeEcho) |
| 44 | modules.RegisterChild("lifo", "", lifo) |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 45 | |
| 46 | modules.RegisterFunction("envtestf", "envtest: <variables to print>...", PrintFromEnv) |
| 47 | modules.RegisterFunction("echof", "[args]*", Echo) |
| 48 | modules.RegisterFunction("errortestFunc", "", ErrorMain) |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 49 | modules.RegisterFunction("pipeFunc", "", pipeEcho) |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 50 | } |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 51 | |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 52 | // We must call Testmain ourselves because using v23 test generate |
| 53 | // creates an import cycle for this package. |
| 54 | func TestMain(m *testing.M) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 55 | test.Init() |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 56 | if modules.IsModulesChildProcess() { |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 57 | if err := modules.Dispatch(); err != nil { |
| 58 | fmt.Fprintf(os.Stderr, "modules.Dispatch failed: %v\n", err) |
| 59 | os.Exit(1) |
| 60 | } |
| 61 | return |
| 62 | } |
| 63 | os.Exit(m.Run()) |
| 64 | } |
| 65 | |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 66 | func ignoresStdin(io.Reader, io.Writer, io.Writer, map[string]string, ...string) error { |
| 67 | <-time.After(time.Minute) |
| 68 | return nil |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 69 | } |
| 70 | |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 71 | func Echo(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error { |
| 72 | for _, a := range args { |
| 73 | fmt.Fprintf(stdout, "stdout: %s\n", a) |
| 74 | fmt.Fprintf(stderr, "stderr: %s\n", a) |
| 75 | } |
| 76 | return nil |
| 77 | } |
| 78 | |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 79 | func pipeEcho(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error { |
| 80 | scanner := bufio.NewScanner(stdin) |
| 81 | for scanner.Scan() { |
| 82 | fmt.Fprintf(stdout, "%p: %s\n", pipeEcho, scanner.Text()) |
| 83 | } |
| 84 | return nil |
| 85 | } |
| 86 | |
| 87 | func lifo(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error { |
| 88 | scanner := bufio.NewScanner(stdin) |
| 89 | scanner.Scan() |
| 90 | msg := scanner.Text() |
| 91 | modules.WaitForEOF(stdin) |
| 92 | fmt.Fprintf(stdout, "%p: %s\n", lifo, msg) |
| 93 | return nil |
| 94 | } |
| 95 | |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 96 | func PrintBlessing(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] | 97 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 98 | defer shutdown() |
| 99 | |
Jiri Simsa | 6ac9522 | 2015-02-23 16:11:49 -0800 | [diff] [blame] | 100 | blessing := v23.GetPrincipal(ctx).BlessingStore().Default() |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 101 | fmt.Fprintf(stdout, "%s", blessing) |
| 102 | return nil |
| 103 | } |
| 104 | |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 105 | func PrintFromEnv(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error { |
Suharsh Sivakumar | 9d17e4a | 2015-02-02 22:42:16 -0800 | [diff] [blame] | 106 | for _, a := range args { |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 107 | if v := env[a]; len(v) > 0 { |
Cosmos Nicolaou | 74cc9b2 | 2014-10-23 15:25:35 -0700 | [diff] [blame] | 108 | fmt.Fprintf(stdout, "%s\n", a+"="+v) |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 109 | } else { |
| 110 | fmt.Fprintf(stderr, "missing %s\n", a) |
| 111 | } |
| 112 | } |
| 113 | modules.WaitForEOF(stdin) |
| 114 | fmt.Fprintf(stdout, "done\n") |
| 115 | return nil |
| 116 | } |
| 117 | |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 118 | const printEnvArgPrefix = "PRINTENV_ARG=" |
| 119 | |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 120 | func PrintEnv(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error { |
| 121 | for _, a := range args { |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 122 | fmt.Fprintf(stdout, "%s%s\n", printEnvArgPrefix, a) |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 123 | } |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 124 | for k, v := range env { |
Cosmos Nicolaou | 74cc9b2 | 2014-10-23 15:25:35 -0700 | [diff] [blame] | 125 | fmt.Fprintf(stdout, "%q\n", k+"="+v) |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 126 | } |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 127 | return nil |
| 128 | } |
| 129 | |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 130 | func ErrorMain(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error { |
| 131 | return fmt.Errorf("an error") |
| 132 | } |
| 133 | |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 134 | func waitForInput(scanner *bufio.Scanner) bool { |
| 135 | ch := make(chan struct{}) |
| 136 | go func(ch chan<- struct{}) { |
| 137 | scanner.Scan() |
| 138 | ch <- struct{}{} |
| 139 | }(ch) |
| 140 | select { |
| 141 | case <-ch: |
| 142 | return true |
| 143 | case <-time.After(10 * time.Second): |
| 144 | return false |
| 145 | } |
| 146 | } |
| 147 | |
| 148 | func testCommand(t *testing.T, sh *modules.Shell, name, key, val string) { |
Cosmos Nicolaou | 612ad38 | 2014-10-29 19:41:35 -0700 | [diff] [blame] | 149 | h, err := sh.Start(name, nil, key) |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 150 | if err != nil { |
| 151 | t.Fatalf("unexpected error: %s", err) |
| 152 | } |
| 153 | defer func() { |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 154 | var stdout, stderr bytes.Buffer |
| 155 | sh.Cleanup(&stdout, &stderr) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 156 | want := "" |
| 157 | if testing.Verbose() { |
| 158 | want = "---- Shell Cleanup ----\n" |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 159 | } |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 160 | if got := stdout.String(); got != "" && got != want { |
| 161 | t.Errorf("got %q, want %q", got, want) |
| 162 | } |
| 163 | if got := stderr.String(); got != "" && got != want { |
| 164 | t.Errorf("got %q, want %q", got, want) |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 165 | } |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 166 | }() |
| 167 | scanner := bufio.NewScanner(h.Stdout()) |
| 168 | if !waitForInput(scanner) { |
| 169 | t.Errorf("timeout") |
| 170 | return |
| 171 | } |
| 172 | if got, want := scanner.Text(), key+"="+val; got != want { |
| 173 | t.Errorf("got %q, want %q", got, want) |
| 174 | } |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 175 | h.CloseStdin() |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 176 | if !waitForInput(scanner) { |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 177 | t.Fatalf("timeout") |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 178 | return |
| 179 | } |
| 180 | if got, want := scanner.Text(), "done"; got != want { |
| 181 | t.Errorf("got %q, want %q", got, want) |
| 182 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 183 | if err := h.Shutdown(nil, nil); err != nil { |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 184 | t.Fatalf("unexpected error: %s", err) |
| 185 | } |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 186 | } |
| 187 | |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 188 | func getBlessing(t *testing.T, sh *modules.Shell, env ...string) string { |
| 189 | h, err := sh.Start("printblessing", env) |
| 190 | if err != nil { |
| 191 | t.Fatalf("unexpected error: %s", err) |
| 192 | } |
| 193 | scanner := bufio.NewScanner(h.Stdout()) |
| 194 | if !waitForInput(scanner) { |
| 195 | t.Errorf("timeout") |
| 196 | return "" |
| 197 | } |
| 198 | return scanner.Text() |
| 199 | } |
| 200 | |
Ryan Brown | 61d6938 | 2015-02-25 11:13:39 -0800 | [diff] [blame] | 201 | func getCustomBlessing(t *testing.T, sh *modules.Shell, creds *modules.CustomCredentials) string { |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 202 | h, err := sh.StartWithOpts(sh.DefaultStartOpts().WithCustomCredentials(creds), nil, "printblessing") |
Ryan Brown | 61d6938 | 2015-02-25 11:13:39 -0800 | [diff] [blame] | 203 | if err != nil { |
| 204 | t.Fatalf("unexpected error: %s", err) |
| 205 | } |
| 206 | scanner := bufio.NewScanner(h.Stdout()) |
| 207 | if !waitForInput(scanner) { |
| 208 | t.Errorf("timeout") |
| 209 | return "" |
| 210 | } |
| 211 | return scanner.Text() |
| 212 | } |
| 213 | |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 214 | func TestChild(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 215 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 216 | defer shutdown() |
| 217 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 218 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 219 | if err != nil { |
| 220 | t.Fatalf("unexpected error: %s", err) |
| 221 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 222 | defer sh.Cleanup(nil, nil) |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 223 | key, val := "simpleVar", "foo & bar" |
| 224 | sh.SetVar(key, val) |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 225 | testCommand(t, sh, "envtest", key, val) |
| 226 | } |
| 227 | |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 228 | func TestAgent(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, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 233 | if err != nil { |
| 234 | t.Fatalf("unexpected error: %s", err) |
| 235 | } |
| 236 | defer sh.Cleanup(os.Stdout, os.Stderr) |
| 237 | a := getBlessing(t, sh) |
| 238 | b := getBlessing(t, sh) |
| 239 | if a != b { |
| 240 | t.Errorf("Expected same blessing for children, got %s and %s", a, b) |
| 241 | } |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 242 | } |
| 243 | |
| 244 | func TestCustomPrincipal(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 245 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 246 | defer shutdown() |
| 247 | |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 248 | p, err := vsecurity.NewPrincipal() |
| 249 | if err != nil { |
| 250 | t.Fatal(err) |
| 251 | } |
| 252 | b, err := p.BlessSelf("myshell") |
| 253 | if err != nil { |
| 254 | t.Fatal(err) |
| 255 | } |
| 256 | if err := vsecurity.SetDefaultBlessings(p, b); err != nil { |
| 257 | t.Fatal(err) |
| 258 | } |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 259 | cleanDebug := p.BlessingStore().DebugString() |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 260 | sh, err := modules.NewShell(ctx, p, testing.Verbose(), t) |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 261 | if err != nil { |
| 262 | t.Fatalf("unexpected error: %s", err) |
| 263 | } |
| 264 | defer sh.Cleanup(os.Stdout, os.Stderr) |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 265 | if got, want := getBlessing(t, sh), "myshell/child"; got != want { |
| 266 | t.Errorf("Bad blessing. Got %q, want %q", got, want) |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 267 | } |
| 268 | newDebug := p.BlessingStore().DebugString() |
| 269 | if cleanDebug != newDebug { |
| 270 | t.Errorf("Shell modified custom principal. Was:\n%q\nNow:\n%q", cleanDebug, newDebug) |
| 271 | } |
| 272 | } |
| 273 | |
Ryan Brown | 61d6938 | 2015-02-25 11:13:39 -0800 | [diff] [blame] | 274 | func TestCustomCredentials(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 275 | ctx, shutdown := test.InitForTest() |
Ryan Brown | 61d6938 | 2015-02-25 11:13:39 -0800 | [diff] [blame] | 276 | defer shutdown() |
| 277 | |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 278 | root := testutil.NewIDProvider("myshell") |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 279 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Ryan Brown | 61d6938 | 2015-02-25 11:13:39 -0800 | [diff] [blame] | 280 | if err != nil { |
| 281 | t.Fatal(err) |
| 282 | } |
| 283 | defer sh.Cleanup(os.Stdout, os.Stderr) |
| 284 | |
| 285 | newCreds := func(ext string) *modules.CustomCredentials { |
| 286 | p, err := sh.NewCustomCredentials() |
| 287 | if err != nil { |
| 288 | t.Fatal(err) |
| 289 | } |
| 290 | b, err := root.NewBlessings(p.Principal(), ext) |
| 291 | if err != nil { |
| 292 | t.Fatal(err) |
| 293 | } |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 294 | if err := vsecurity.SetDefaultBlessings(p.Principal(), b); err != nil { |
| 295 | t.Fatal(err) |
| 296 | } |
Ryan Brown | 61d6938 | 2015-02-25 11:13:39 -0800 | [diff] [blame] | 297 | return p |
| 298 | } |
| 299 | |
| 300 | a := newCreds("a") |
| 301 | cleanDebug := a.Principal().BlessingStore().DebugString() |
| 302 | |
| 303 | blessing := getCustomBlessing(t, sh, a) |
| 304 | if blessing != "myshell/a" { |
| 305 | t.Errorf("Bad blessing. Expected myshell/a, go %q", blessing) |
| 306 | } |
| 307 | |
| 308 | b := newCreds("bar") |
| 309 | blessing = getCustomBlessing(t, sh, b) |
| 310 | if blessing != "myshell/bar" { |
| 311 | t.Errorf("Bad blessing. Expected myshell/bar, go %q", blessing) |
| 312 | } |
| 313 | |
| 314 | // Make sure we can re-use credentials |
| 315 | blessing = getCustomBlessing(t, sh, a) |
| 316 | if blessing != "myshell/a" { |
| 317 | t.Errorf("Bad blessing. Expected myshell/a, go %q", blessing) |
| 318 | } |
| 319 | |
| 320 | newDebug := a.Principal().BlessingStore().DebugString() |
| 321 | if cleanDebug != newDebug { |
| 322 | t.Errorf("Shell modified custom principal. Was:\n%q\nNow:\n%q", cleanDebug, newDebug) |
| 323 | } |
| 324 | } |
| 325 | |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 326 | func createCredentials(blessing string) (string, error) { |
| 327 | dir, err := ioutil.TempDir("", "TestNoAgent_v23_credentials") |
| 328 | if err != nil { |
| 329 | return "", err |
| 330 | } |
| 331 | p, err := vsecurity.CreatePersistentPrincipal(dir, nil) |
| 332 | if err != nil { |
| 333 | os.RemoveAll(dir) |
| 334 | return "", err |
| 335 | } |
| 336 | b, err := p.BlessSelf(blessing) |
| 337 | if err != nil { |
| 338 | os.RemoveAll(dir) |
| 339 | return "", err |
| 340 | } |
| 341 | if err := vsecurity.SetDefaultBlessings(p, b); err != nil { |
| 342 | os.RemoveAll(dir) |
| 343 | return "", err |
| 344 | } |
| 345 | return dir, nil |
| 346 | } |
| 347 | |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 348 | func TestNoAgent(t *testing.T) { |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 349 | const noagent = "noagent" |
| 350 | creds, err := createCredentials(noagent) |
| 351 | if err != nil { |
| 352 | t.Fatal(err) |
| 353 | } |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 354 | defer os.RemoveAll(creds) |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 355 | sh, err := modules.NewShell(nil, nil, testing.Verbose(), t) |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 356 | if err != nil { |
| 357 | t.Fatalf("unexpected error: %s", err) |
| 358 | } |
| 359 | defer sh.Cleanup(os.Stdout, os.Stderr) |
Asim Shankar | 59b8b69 | 2015-03-30 01:23:36 -0700 | [diff] [blame] | 360 | if got, want := getBlessing(t, sh, fmt.Sprintf("%s=%s", envvar.Credentials, creds)), noagent; got != want { |
Asim Shankar | 4a69828 | 2015-03-21 21:59:18 -0700 | [diff] [blame] | 361 | t.Errorf("Bad blessing. Got %q, want %q", got, want) |
Ryan Brown | a08a221 | 2015-01-15 15:40:10 -0800 | [diff] [blame] | 362 | } |
| 363 | } |
| 364 | |
Cosmos Nicolaou | 1e78ccc | 2014-10-09 08:10:26 -0700 | [diff] [blame] | 365 | func TestChildNoRegistration(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 366 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 367 | defer shutdown() |
| 368 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 369 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 370 | if err != nil { |
| 371 | t.Fatalf("unexpected error: %s", err) |
| 372 | } |
Cosmos Nicolaou | 1e78ccc | 2014-10-09 08:10:26 -0700 | [diff] [blame] | 373 | defer sh.Cleanup(os.Stderr, os.Stderr) |
| 374 | key, val := "simpleVar", "foo & bar" |
| 375 | sh.SetVar(key, val) |
| 376 | testCommand(t, sh, "envtest", key, val) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 377 | _, err = sh.Start("non-existent-command", nil, "random", "args") |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 378 | if err == nil { |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 379 | fmt.Fprintf(os.Stderr, "Failed: %v\n", err) |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 380 | t.Fatalf("expected error") |
Cosmos Nicolaou | 1e78ccc | 2014-10-09 08:10:26 -0700 | [diff] [blame] | 381 | } |
| 382 | } |
| 383 | |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 384 | func TestFunction(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 385 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 386 | defer shutdown() |
| 387 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 388 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 389 | if err != nil { |
| 390 | t.Fatalf("unexpected error: %s", err) |
| 391 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 392 | defer sh.Cleanup(nil, nil) |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 393 | key, val := "simpleVar", "foo & bar & baz" |
| 394 | sh.SetVar(key, val) |
Cosmos Nicolaou | 1e78ccc | 2014-10-09 08:10:26 -0700 | [diff] [blame] | 395 | testCommand(t, sh, "envtestf", key, val) |
Cosmos Nicolaou | 6261384 | 2014-08-25 21:57:37 -0700 | [diff] [blame] | 396 | } |
| 397 | |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 398 | func TestErrorChild(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 399 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 400 | defer shutdown() |
| 401 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 402 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 403 | if err != nil { |
| 404 | t.Fatalf("unexpected error: %s", err) |
| 405 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 406 | defer sh.Cleanup(nil, nil) |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 407 | h, err := sh.Start("errortestChild", nil) |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 408 | if err != nil { |
| 409 | t.Fatalf("unexpected error: %s", err) |
| 410 | } |
Suharsh Sivakumar | d19c95d | 2015-02-19 14:44:50 -0800 | [diff] [blame] | 411 | if got, want := h.Shutdown(nil, nil), "exit status 1"; got == nil || got.Error() != want { |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 412 | t.Errorf("got %q, want %q", got, want) |
| 413 | } |
| 414 | } |
| 415 | |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 416 | func testShutdown(t *testing.T, sh *modules.Shell, command string, isfunc bool) { |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 417 | result := "" |
| 418 | args := []string{"a", "b c", "ddd"} |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 419 | if _, err := sh.Start(command, nil, args...); err != nil { |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 420 | t.Fatalf("unexpected error: %s", err) |
| 421 | } |
| 422 | var stdoutBuf bytes.Buffer |
| 423 | var stderrBuf bytes.Buffer |
| 424 | sh.Cleanup(&stdoutBuf, &stderrBuf) |
Suharsh Sivakumar | 9d17e4a | 2015-02-02 22:42:16 -0800 | [diff] [blame] | 425 | var stdoutOutput, stderrOutput string |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 426 | for _, a := range args { |
| 427 | stdoutOutput += fmt.Sprintf("stdout: %s\n", a) |
| 428 | stderrOutput += fmt.Sprintf("stderr: %s\n", a) |
| 429 | } |
| 430 | if got, want := stdoutBuf.String(), stdoutOutput+result; got != want { |
| 431 | t.Errorf("got %q want %q", got, want) |
| 432 | } |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 433 | if !isfunc { |
| 434 | stderrBuf.ReadString('\n') // Skip past the random # generator output |
| 435 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 436 | if got, want := stderrBuf.String(), stderrOutput; got != want { |
| 437 | t.Errorf("got %q want %q", got, want) |
| 438 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 439 | } |
| 440 | |
| 441 | func TestShutdownSubprocess(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 442 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 443 | defer shutdown() |
| 444 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 445 | sh, err := modules.NewShell(ctx, nil, false, t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 446 | if err != nil { |
| 447 | t.Fatalf("unexpected error: %s", err) |
| 448 | } |
Robin Thellend | cf140c0 | 2014-12-08 14:56:24 -0800 | [diff] [blame] | 449 | defer sh.Cleanup(nil, nil) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 450 | testShutdown(t, sh, "echos", false) |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 451 | } |
| 452 | |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 453 | // TestShutdownSubprocessIgnoresStdin verifies that Shutdown doesn't wait |
| 454 | // forever if a child does not die upon closing stdin; but instead times out and |
| 455 | // returns an appropriate error. |
| 456 | func TestShutdownSubprocessIgnoresStdin(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 457 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 458 | defer shutdown() |
| 459 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 460 | sh, err := modules.NewShell(ctx, nil, false, t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 461 | if err != nil { |
| 462 | t.Fatalf("unexpected error: %s", err) |
| 463 | } |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 464 | opts := sh.DefaultStartOpts() |
| 465 | opts.ShutdownTimeout = time.Second |
| 466 | h, err := sh.StartWithOpts(opts, nil, "ignores_stdin") |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 467 | if err != nil { |
| 468 | t.Fatalf("unexpected error: %s", err) |
| 469 | } |
| 470 | var stdoutBuf, stderrBuf bytes.Buffer |
Mike Burrows | ccca2f4 | 2015-03-27 13:57:29 -0700 | [diff] [blame] | 471 | if err := sh.Cleanup(&stdoutBuf, &stderrBuf); err == nil || verror.ErrorID(err) != exec.ErrTimeout.ID { |
| 472 | t.Errorf("unexpected error in Cleanup: got %v, want %v", err, exec.ErrTimeout.ID) |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 473 | } |
| 474 | if err := syscall.Kill(h.Pid(), syscall.SIGINT); err != nil { |
| 475 | t.Errorf("Kill failed: %v", err) |
| 476 | } |
| 477 | } |
| 478 | |
| 479 | // TestStdoutRace exemplifies a potential race between reading from child's |
| 480 | // stdout and closing stdout in Wait (called by Shutdown). |
| 481 | // |
| 482 | // NOTE: triggering the actual --race failure is hard, even if the |
| 483 | // implementation inappropriately sets stdout to the file that is to be closed |
| 484 | // in Wait. |
| 485 | func TestStdoutRace(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 486 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 487 | defer shutdown() |
| 488 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 489 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 490 | if err != nil { |
| 491 | t.Fatalf("unexpected error: %s", err) |
| 492 | } |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 493 | opts := sh.DefaultStartOpts() |
| 494 | opts.ShutdownTimeout = time.Second |
| 495 | h, err := sh.StartWithOpts(opts, nil, "ignores_stdin") |
Bogdan Caprita | 490a451 | 2014-11-20 21:12:19 -0800 | [diff] [blame] | 496 | if err != nil { |
| 497 | t.Fatalf("unexpected error: %s", err) |
| 498 | } |
| 499 | ch := make(chan error, 1) |
| 500 | go func() { |
| 501 | buf := make([]byte, 5) |
| 502 | // This will block since the child is not writing anything on |
| 503 | // stdout. |
| 504 | _, err := h.Stdout().Read(buf) |
| 505 | ch <- err |
| 506 | }() |
| 507 | // Give the goroutine above a chance to run, so that we're blocked on |
| 508 | // stdout.Read. |
| 509 | <-time.After(time.Second) |
| 510 | // Cleanup should close stdout, and unblock the goroutine. |
| 511 | sh.Cleanup(nil, nil) |
| 512 | if got, want := <-ch, io.EOF; got != want { |
| 513 | t.Errorf("Expected %v, got %v instead", want, got) |
| 514 | } |
| 515 | |
| 516 | if err := syscall.Kill(h.Pid(), syscall.SIGINT); err != nil { |
| 517 | t.Errorf("Kill failed: %v", err) |
| 518 | } |
| 519 | } |
| 520 | |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 521 | func TestShutdownFunction(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 522 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 523 | defer shutdown() |
| 524 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 525 | sh, err := modules.NewShell(ctx, nil, false, t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 526 | if err != nil { |
| 527 | t.Fatalf("unexpected error: %s", err) |
| 528 | } |
Robin Thellend | cf140c0 | 2014-12-08 14:56:24 -0800 | [diff] [blame] | 529 | defer sh.Cleanup(nil, nil) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 530 | testShutdown(t, sh, "echof", true) |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 531 | } |
| 532 | |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 533 | func TestErrorFunc(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 534 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 535 | defer shutdown() |
| 536 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 537 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 538 | if err != nil { |
| 539 | t.Fatalf("unexpected error: %s", err) |
| 540 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 541 | defer sh.Cleanup(nil, nil) |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 542 | h, err := sh.Start("errortestFunc", nil) |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 543 | if err != nil { |
| 544 | t.Fatalf("unexpected error: %s", err) |
| 545 | } |
Cosmos Nicolaou | bbae388 | 2014-10-02 22:58:19 -0700 | [diff] [blame] | 546 | if got, want := h.Shutdown(nil, nil), "an error"; got != nil && got.Error() != want { |
Cosmos Nicolaou | 66afced | 2014-09-15 22:12:43 -0700 | [diff] [blame] | 547 | t.Errorf("got %q, want %q", got, want) |
| 548 | } |
| 549 | } |
| 550 | |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 551 | func find(want string, in []string) bool { |
| 552 | for _, a := range in { |
| 553 | if a == want { |
| 554 | return true |
| 555 | } |
| 556 | } |
| 557 | return false |
| 558 | } |
| 559 | |
| 560 | func TestEnvelope(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 561 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 562 | defer shutdown() |
| 563 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 564 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 565 | if err != nil { |
| 566 | t.Fatalf("unexpected error: %s", err) |
| 567 | } |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 568 | defer sh.Cleanup(nil, nil) |
| 569 | sh.SetVar("a", "1") |
| 570 | sh.SetVar("b", "2") |
| 571 | args := []string{"oh", "ah"} |
Cosmos Nicolaou | 612ad38 | 2014-10-29 19:41:35 -0700 | [diff] [blame] | 572 | h, err := sh.Start("printenv", nil, args...) |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 573 | if err != nil { |
| 574 | t.Fatalf("unexpected error: %s", err) |
| 575 | } |
| 576 | scanner := bufio.NewScanner(h.Stdout()) |
| 577 | childArgs, childEnv := []string{}, []string{} |
| 578 | for scanner.Scan() { |
| 579 | o := scanner.Text() |
| 580 | if strings.HasPrefix(o, printEnvArgPrefix) { |
| 581 | childArgs = append(childArgs, strings.TrimPrefix(o, printEnvArgPrefix)) |
| 582 | } else { |
| 583 | childEnv = append(childEnv, o) |
| 584 | } |
| 585 | } |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 586 | shArgs, shEnv := sh.CommandEnvelope("printenv", nil, args...) |
Cosmos Nicolaou | 74cc9b2 | 2014-10-23 15:25:35 -0700 | [diff] [blame] | 587 | for i, ev := range shEnv { |
| 588 | shEnv[i] = fmt.Sprintf("%q", ev) |
| 589 | } |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 590 | for _, want := range args { |
| 591 | if !find(want, childArgs) { |
| 592 | t.Errorf("failed to find %q in %s", want, childArgs) |
| 593 | } |
| 594 | if !find(want, shArgs) { |
| 595 | t.Errorf("failed to find %q in %s", want, shArgs) |
| 596 | } |
| 597 | } |
| 598 | |
| 599 | for _, want := range shEnv { |
| 600 | if !find(want, childEnv) { |
Cosmos Nicolaou | 74cc9b2 | 2014-10-23 15:25:35 -0700 | [diff] [blame] | 601 | t.Errorf("failed to find %s in %#v", want, childEnv) |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 602 | } |
| 603 | } |
Ankur | 9f95794 | 2014-11-24 16:34:18 -0800 | [diff] [blame] | 604 | |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 605 | for _, want := range childEnv { |
Cosmos Nicolaou | a6fef89 | 2015-02-20 23:09:03 -0800 | [diff] [blame] | 606 | if want == "\""+execconsts.ExecVersionVariable+"=\"" { |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 607 | continue |
| 608 | } |
| 609 | if !find(want, shEnv) { |
Cosmos Nicolaou | 74cc9b2 | 2014-10-23 15:25:35 -0700 | [diff] [blame] | 610 | t.Errorf("failed to find %s in %#v", want, shEnv) |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 611 | } |
| 612 | } |
| 613 | } |
| 614 | |
| 615 | func TestEnvMerge(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 616 | ctx, shutdown := test.InitForTest() |
Suharsh Sivakumar | 19fbf99 | 2015-01-23 11:02:27 -0800 | [diff] [blame] | 617 | defer shutdown() |
| 618 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 619 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 620 | if err != nil { |
| 621 | t.Fatalf("unexpected error: %s", err) |
| 622 | } |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 623 | defer sh.Cleanup(nil, nil) |
| 624 | sh.SetVar("a", "1") |
| 625 | os.Setenv("a", "wrong, should be 1") |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 626 | sh.SetVar("b", "2 also wrong") |
| 627 | os.Setenv("b", "wrong, should be 2") |
Cosmos Nicolaou | 612ad38 | 2014-10-29 19:41:35 -0700 | [diff] [blame] | 628 | h, err := sh.Start("printenv", []string{"b=2"}) |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 629 | if err != nil { |
| 630 | t.Fatalf("unexpected error: %s", err) |
| 631 | } |
| 632 | scanner := bufio.NewScanner(h.Stdout()) |
| 633 | for scanner.Scan() { |
| 634 | o := scanner.Text() |
| 635 | if strings.HasPrefix(o, "a=") { |
| 636 | if got, want := o, "a=1"; got != want { |
Cosmos Nicolaou | 2cb05fb | 2014-10-23 13:37:32 -0700 | [diff] [blame] | 637 | t.Errorf("got: %q, want %q", got, want) |
| 638 | } |
| 639 | } |
| 640 | if strings.HasPrefix(o, "b=") { |
| 641 | if got, want := o, "b=2"; got != want { |
| 642 | t.Errorf("got: %q, want %q", got, want) |
Cosmos Nicolaou | e664f3f | 2014-10-20 17:40:05 -0700 | [diff] [blame] | 643 | } |
| 644 | } |
| 645 | } |
| 646 | } |
| 647 | |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 648 | func TestSetEntryPoint(t *testing.T) { |
| 649 | env := map[string]string{"a": "a", "b": "b"} |
| 650 | nenv := modules.SetEntryPoint(env, "eg1") |
| 651 | if got, want := len(nenv), 3; got != want { |
| 652 | t.Errorf("got %d, want %d", got, want) |
| 653 | } |
| 654 | nenv = modules.SetEntryPoint(env, "eg2") |
| 655 | if got, want := len(nenv), 3; got != want { |
| 656 | t.Errorf("got %d, want %d", got, want) |
| 657 | } |
Cosmos Nicolaou | 5339a7b | 2014-11-18 17:28:00 -0800 | [diff] [blame] | 658 | sort.Strings(nenv) |
Asim Shankar | 59b8b69 | 2015-03-30 01:23:36 -0700 | [diff] [blame] | 659 | if got, want := nenv, []string{"V23_SHELL_HELPER_PROCESS_ENTRY_POINT=eg2", "a=a", "b=b"}; !reflect.DeepEqual(got, want) { |
Cosmos Nicolaou | d4f0056 | 2014-11-17 20:35:48 -0800 | [diff] [blame] | 660 | t.Errorf("got %d, want %d", got, want) |
| 661 | } |
| 662 | } |
| 663 | |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 664 | func TestNoExec(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 665 | ctx, shutdown := test.InitForTest() |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 666 | defer shutdown() |
| 667 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 668 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 669 | if err != nil { |
| 670 | t.Fatalf("unexpected error: %s", err) |
| 671 | } |
| 672 | defer sh.Cleanup(nil, nil) |
| 673 | h, err := sh.StartWithOpts(sh.DefaultStartOpts().NoExecCommand(), nil, "/bin/echo", "hello", "world") |
| 674 | if err != nil { |
| 675 | t.Fatalf("unexpected error: %s", err) |
| 676 | } |
| 677 | scanner := bufio.NewScanner(h.Stdout()) |
| 678 | scanner.Scan() |
| 679 | if got, want := scanner.Text(), "hello world"; got != want { |
| 680 | t.Fatalf("got %v, want %v", got, want) |
| 681 | } |
| 682 | } |
| 683 | |
| 684 | func TestExternal(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 685 | ctx, shutdown := test.InitForTest() |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 686 | defer shutdown() |
| 687 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 688 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 689 | if err != nil { |
| 690 | t.Fatalf("unexpected error: %s", err) |
| 691 | } |
| 692 | defer sh.Cleanup(nil, nil) |
| 693 | cookie := strconv.Itoa(rand.Int()) |
| 694 | sh.SetConfigKey("cookie", cookie) |
| 695 | h, err := sh.StartWithOpts(sh.DefaultStartOpts().ExternalCommand(), nil, os.Args[0], "--test.run=TestExternalTestHelper") |
| 696 | if err != nil { |
| 697 | t.Fatalf("unexpected error: %s", err) |
| 698 | } |
| 699 | scanner := bufio.NewScanner(h.Stdout()) |
| 700 | scanner.Scan() |
| 701 | if got, want := scanner.Text(), fmt.Sprintf("cookie: %s", cookie); got != want { |
| 702 | h.Shutdown(os.Stderr, os.Stderr) |
| 703 | t.Fatalf("got %v, want %v", got, want) |
| 704 | } |
| 705 | } |
| 706 | |
| 707 | // TestExternalTestHelper is used by TestExternal above and has not utility |
| 708 | // as a test in it's own right. |
| 709 | func TestExternalTestHelper(t *testing.T) { |
| 710 | child, err := exec.GetChildHandle() |
| 711 | if err != nil { |
| 712 | return |
| 713 | } |
| 714 | child.SetReady() |
| 715 | val, err := child.Config.Get("cookie") |
| 716 | if err != nil { |
| 717 | t.Fatalf("failed to get child handle: %s", err) |
| 718 | } |
| 719 | fmt.Printf("cookie: %s\n", val) |
| 720 | } |
| 721 | |
| 722 | func TestPipe(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 723 | ctx, shutdown := test.InitForTest() |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 724 | defer shutdown() |
| 725 | |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 726 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 727 | if err != nil { |
| 728 | t.Fatalf("unexpected error: %s", err) |
| 729 | } |
| 730 | defer sh.Cleanup(nil, nil) |
| 731 | |
| 732 | for _, cmd := range []string{"pipeProc", "pipeFunc"} { |
| 733 | r, w, err := os.Pipe() |
| 734 | if err != nil { |
| 735 | t.Fatal(err) |
| 736 | } |
| 737 | opts := sh.DefaultStartOpts() |
| 738 | opts.Stdin = r |
| 739 | h, err := sh.StartWithOpts(opts, nil, cmd) |
| 740 | if err != nil { |
| 741 | t.Fatal(err) |
| 742 | } |
| 743 | cookie := strconv.Itoa(rand.Int()) |
| 744 | go func(w *os.File, s string) { |
| 745 | fmt.Fprintf(w, "hello world\n") |
| 746 | fmt.Fprintf(w, "%s\n", s) |
| 747 | w.Close() |
| 748 | }(w, cookie) |
| 749 | |
| 750 | scanner := bufio.NewScanner(h.Stdout()) |
| 751 | want := []string{ |
| 752 | fmt.Sprintf("%p: hello world", pipeEcho), |
| 753 | fmt.Sprintf("%p: %s", pipeEcho, cookie), |
| 754 | } |
| 755 | i := 0 |
| 756 | for scanner.Scan() { |
| 757 | if got, want := scanner.Text(), want[i]; got != want { |
| 758 | t.Fatalf("%s: got %v, want %v", cmd, got, want) |
| 759 | } |
| 760 | i++ |
| 761 | } |
| 762 | if got, want := i, 2; got != want { |
| 763 | t.Fatalf("%s: got %v, want %v", cmd, got, want) |
| 764 | } |
| 765 | if err := h.Shutdown(os.Stderr, os.Stderr); err != nil { |
| 766 | t.Fatal(err) |
| 767 | } |
| 768 | r.Close() |
| 769 | } |
| 770 | } |
| 771 | |
| 772 | func TestLIFO(t *testing.T) { |
Cosmos Nicolaou | 1381f8a | 2015-03-13 09:40:34 -0700 | [diff] [blame] | 773 | ctx, shutdown := test.InitForTest() |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 774 | defer shutdown() |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 775 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 776 | if err != nil { |
| 777 | t.Fatalf("unexpected error: %s", err) |
| 778 | } |
| 779 | defer sh.Cleanup(nil, nil) |
| 780 | |
| 781 | cases := []string{"a", "b", "c"} |
| 782 | for _, msg := range cases { |
| 783 | h, err := sh.Start("lifo", nil) |
| 784 | if err != nil { |
| 785 | t.Fatal(err) |
| 786 | } |
| 787 | fmt.Fprintf(h.Stdin(), "%s\n", msg) |
| 788 | } |
| 789 | var buf bytes.Buffer |
| 790 | if err := sh.Cleanup(&buf, nil); err != nil { |
| 791 | t.Fatal(err) |
| 792 | } |
| 793 | lines := strings.Split(strings.TrimRight(buf.String(), "\n"), "\n") |
| 794 | if got, want := len(lines), len(cases); got != want { |
| 795 | t.Fatalf("got %v, want %v", got, want) |
| 796 | } |
| 797 | sort.Sort(sort.Reverse(sort.StringSlice(cases))) |
| 798 | for i, msg := range cases { |
| 799 | if got, want := lines[i], fmt.Sprintf("%p: %s", lifo, msg); got != want { |
| 800 | t.Fatalf("got %v, want %v", got, want) |
| 801 | } |
| 802 | } |
| 803 | } |
| 804 | |
| 805 | func TestStartOpts(t *testing.T) { |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 806 | sh, err := modules.NewShell(nil, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 807 | if err != nil { |
| 808 | t.Fatalf("unexpected error: %s", err) |
| 809 | } |
| 810 | opts := modules.StartOpts{ |
| 811 | External: true, |
| 812 | } |
| 813 | sh.SetDefaultStartOpts(opts) |
| 814 | def := sh.DefaultStartOpts() |
| 815 | if got, want := def.External, opts.External; got != want { |
| 816 | t.Fatalf("got %v, want %v", got, want) |
| 817 | } |
| 818 | def.External = false |
| 819 | if got, want := def, (modules.StartOpts{}); !reflect.DeepEqual(got, want) { |
| 820 | t.Fatalf("got %v, want %v", got, want) |
| 821 | } |
| 822 | |
| 823 | // Verify that the shell retains a copy. |
| 824 | opts.External = false |
| 825 | opts.ExecProtocol = true |
| 826 | def = sh.DefaultStartOpts() |
| 827 | if got, want := def.External, true; got != want { |
| 828 | t.Fatalf("got %v, want %v", got, want) |
| 829 | } |
| 830 | if got, want := def.ExecProtocol, false; got != want { |
| 831 | t.Fatalf("got %v, want %v", got, want) |
| 832 | } |
| 833 | |
| 834 | sh.SetDefaultStartOpts(opts) |
| 835 | def = sh.DefaultStartOpts() |
| 836 | if got, want := def.ExecProtocol, true; got != want { |
| 837 | t.Fatalf("got %v, want %v", got, want) |
| 838 | } |
| 839 | } |
| 840 | |
| 841 | func TestEmbeddedSession(t *testing.T) { |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 842 | sh, err := modules.NewShell(nil, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 42a1736 | 2015-03-10 16:40:18 -0700 | [diff] [blame] | 843 | if err != nil { |
| 844 | t.Fatalf("unexpected error: %s", err) |
| 845 | } |
| 846 | def := sh.DefaultStartOpts() |
| 847 | if def.ExpectTesting == nil { |
| 848 | t.Fatalf("ExpectTesting should be non nil") |
| 849 | } |
| 850 | } |
Cosmos Nicolaou | 52e9a22 | 2015-03-16 21:57:16 -0700 | [diff] [blame] | 851 | |
| 852 | func TestCredentialsAndNoExec(t *testing.T) { |
| 853 | ctx, shutdown := test.InitForTest() |
| 854 | defer shutdown() |
Cosmos Nicolaou | 9e90984 | 2015-03-17 11:58:59 -0700 | [diff] [blame] | 855 | sh, err := modules.NewShell(ctx, nil, testing.Verbose(), t) |
Cosmos Nicolaou | 52e9a22 | 2015-03-16 21:57:16 -0700 | [diff] [blame] | 856 | if err != nil { |
| 857 | t.Fatalf("unexpected error: %s", err) |
| 858 | } |
| 859 | opts := sh.DefaultStartOpts() |
| 860 | opts = opts.NoExecCommand() |
| 861 | creds, err := sh.NewCustomCredentials() |
| 862 | if err != nil { |
| 863 | t.Fatalf("unexpected error: %s", err) |
| 864 | } |
| 865 | opts = opts.WithCustomCredentials(creds) |
| 866 | h, err := sh.StartWithOpts(opts, nil, "echos", "a") |
| 867 | |
| 868 | if got, want := err, modules.ErrNoExecAndCustomCreds; got != want { |
| 869 | t.Fatalf("got %v, want %v", got, want) |
| 870 | } |
| 871 | if got, want := h, modules.Handle(nil); got != want { |
| 872 | t.Fatalf("got %v, want %v", got, want) |
| 873 | } |
| 874 | } |