blob: 5271ce19646ce31ef355e6beb86d2a8c04c9372e [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// 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 Nicolaou4a77c192015-02-08 15:29:18 -08005package v23tests_test
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -08006
7import (
8 "bytes"
James Ring79a9ceb2015-02-09 13:25:54 -08009 "crypto/sha1"
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080010 "fmt"
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -080011 "os"
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080012 "regexp"
13 "strings"
14 "syscall"
15 "testing"
16 "time"
17
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070018 "v.io/v23/naming"
19 "v.io/v23/security"
Cosmos Nicolaoue3b19322015-06-18 16:05:08 -070020
Todd Wang8123b5e2015-05-14 18:44:43 -070021 "v.io/x/ref"
Cosmos Nicolaoue3b19322015-06-18 16:05:08 -070022 "v.io/x/ref/internal/logger"
Suharsh Sivakumardcc11d72015-05-11 12:19:20 -070023 _ "v.io/x/ref/runtime/factories/generic"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070024 "v.io/x/ref/test"
25 "v.io/x/ref/test/modules"
26 "v.io/x/ref/test/testutil"
27 "v.io/x/ref/test/v23tests"
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080028)
29
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080030func TestBinaryFromPath(t *testing.T) {
Cosmos Nicolaou4a77c192015-02-08 15:29:18 -080031 env := v23tests.New(t)
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080032 defer env.Cleanup()
33
34 bash := env.BinaryFromPath("/bin/bash")
35 if want, got := "hello world\n", bash.Start("-c", "echo hello world").Output(); want != got {
36 t.Fatalf("unexpected output, want %s, got %s", want, got)
37 }
38
39 inv := bash.Start("-c", "echo hello world")
40 var buf bytes.Buffer
41 inv.WaitOrDie(&buf, nil)
42 if want, got := "hello world\n", buf.String(); want != got {
43 t.Fatalf("unexpected output, want %s, got %s", want, got)
44 }
45}
46
47func TestMountTable(t *testing.T) {
Cosmos Nicolaou4a77c192015-02-08 15:29:18 -080048 env := v23tests.New(t)
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080049 defer env.Cleanup()
50
Asim Shankarf32d24d2015-04-01 16:34:26 -070051 v23tests.RunRootMT(env, "--v23.tcp.address=127.0.0.1:0")
Cosmos Nicolaou42a17362015-03-10 16:40:18 -070052 proxyBin := env.BuildV23Pkg("v.io/x/ref/services/proxy/proxyd")
Matt Rosencrantzbca49812015-03-01 21:32:54 -080053 nsBin := env.BuildGoPkg("v.io/x/ref/cmd/namespace")
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080054
Todd Wang8123b5e2015-05-14 18:44:43 -070055 mt, ok := env.GetVar(ref.EnvNamespacePrefix)
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080056 if !ok || len(mt) == 0 {
57 t.Fatalf("expected a mount table name")
58 }
59
Asim Shankarf32d24d2015-04-01 16:34:26 -070060 proxy := proxyBin.Start("--v23.tcp.address=127.0.0.1:0", "-name=proxyd")
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080061 proxyName := proxy.ExpectVar("NAME")
62 proxyAddress, _ := naming.SplitAddressName(proxyName)
63
64 re := regexp.MustCompile("proxyd (.*) \\(.*")
65 for i := 0; i < 10; i++ {
66 time.Sleep(100 * time.Millisecond)
67 inv := nsBin.Start("glob", "...")
Cosmos Nicolaoub2599e22015-03-25 13:59:37 -070068 line, _ := inv.ReadAll()
69 parts := re.FindStringSubmatch(line)
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080070 if len(parts) == 2 {
Ryan Browne7970b62015-03-10 15:26:31 -070071 if want, got := security.JoinPatternName("root/child", proxyAddress), parts[1]; got != want {
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080072 t.Fatalf("got: %v, want: %v", got, want)
73 } else {
74 break
75 }
76 }
77 }
78 if got, want := proxy.Exists(), true; got != want {
79 t.Fatalf("got: %v, want: %v", got, want)
80 }
81}
82
83// The next set of tests are a complicated dance to test the correct
84// detection and logging of failed integration tests. The complication
85// is that we need to run these tests in a child process so that we
86// can examine their output, but not in the parent process. We use the
87// modules framework to do so, with the added twist that we need access
88// to an instance of testing.T which we obtain via a global variable.
Cosmos Nicolaou01007a02015-02-11 15:38:38 -080089func IntegrationTestInChild(i *v23tests.T) {
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -080090 fmt.Println("Hello")
91 sleep := i.BinaryFromPath("/bin/sleep")
92 sleep.Start("3600")
93 s2 := sleep.Start("6400")
94 sleep.Start("21600")
95 s2.Kill(syscall.SIGTERM)
96 s2.Wait(nil, nil)
97 i.FailNow()
98 panic("should never get here")
99}
100
101var globalT *testing.T
102
103func TestHelperProcess(t *testing.T) {
Todd Wang95873902015-05-22 14:21:30 -0700104 if modules.IsChildProcess() {
105 globalT = t
106 if err := modules.Dispatch(); err != nil {
107 t.Errorf("modules.Dispatch failed: %v", err)
108 }
109 }
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800110}
111
Todd Wang95873902015-05-22 14:21:30 -0700112var RunIntegrationTestInChild = modules.Register(func(env *modules.Env, args ...string) error {
Cosmos Nicolaou4a77c192015-02-08 15:29:18 -0800113 v23tests.RunTest(globalT, IntegrationTestInChild)
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800114 return nil
Todd Wang95873902015-05-22 14:21:30 -0700115}, "RunIntegrationTestInChild")
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800116
117func init() {
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -0700118 test.Init()
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800119}
120
121func TestDeferHandling(t *testing.T) {
Cosmos Nicolaou9e909842015-03-17 11:58:59 -0700122 sh, _ := modules.NewShell(nil, nil, testing.Verbose(), t)
Todd Wang95873902015-05-22 14:21:30 -0700123 child, err := sh.Start(nil, RunIntegrationTestInChild, "--test.run=TestHelperProcess", "--v23.tests")
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800124 if err != nil {
125 t.Fatal(err)
126 }
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700127 child.Expect("Hello")
128 child.ExpectRE("--- FAIL: TestHelperProcess", -1)
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800129 for _, e := range []string{
130 ".* 0: /bin/sleep: shutdown status: has not been shutdown",
131 ".* 1: /bin/sleep: shutdown status: signal: terminated",
132 ".* 2: /bin/sleep: shutdown status: has not been shutdown",
133 } {
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700134 child.ExpectRE(e, -1)
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800135 }
136 var stderr bytes.Buffer
137 if err := child.Shutdown(nil, &stderr); err != nil {
138 if !strings.Contains(err.Error(), "exit status 1") {
139 t.Fatal(err)
140 }
141 }
Cosmos Nicolaoue3b19322015-06-18 16:05:08 -0700142 logger.Global().Infof("Child\n=============\n%s", stderr.String())
143 logger.Global().Infof("-----------------")
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800144}
James Ring79a9ceb2015-02-09 13:25:54 -0800145
146func TestInputRedirection(t *testing.T) {
Jiri Simsa95ab2972015-07-01 12:35:57 -0700147 testutil.InitRandGenerator(t.Logf)
James Ring79a9ceb2015-02-09 13:25:54 -0800148 env := v23tests.New(t)
149 defer env.Cleanup()
150
151 echo := env.BinaryFromPath("/bin/echo")
152 cat := env.BinaryFromPath("/bin/cat")
153
154 if want, got := "Hello, world!\n", cat.WithStdin(echo.Start("Hello, world!").Stdout()).Start().Output(); want != got {
Cosmos Nicolaoud61e5a82015-02-22 16:32:48 -0800155 t.Fatalf("unexpected output, got %q, want %q", got, want)
James Ring79a9ceb2015-02-09 13:25:54 -0800156 }
157
158 // Read something from a file.
159 {
160 want := "Hello from a file!"
Cosmos Nicolaou93dd88b2015-02-19 15:10:53 -0800161 f := env.NewTempFile()
James Ring79a9ceb2015-02-09 13:25:54 -0800162 f.WriteString(want)
163 f.Seek(0, 0)
164 if got := cat.WithStdin(f).Start().Output(); want != got {
Cosmos Nicolaoud61e5a82015-02-22 16:32:48 -0800165 t.Fatalf("unexpected output, got %q, want %q", got, want)
James Ring79a9ceb2015-02-09 13:25:54 -0800166 }
167 }
168
169 // Try it again with 1Mb.
170 {
171 want := testutil.RandomBytes(1 << 20)
172 expectedSum := sha1.Sum(want)
Cosmos Nicolaou93dd88b2015-02-19 15:10:53 -0800173 f := env.NewTempFile()
James Ring79a9ceb2015-02-09 13:25:54 -0800174 f.Write(want)
175 f.Seek(0, 0)
176 got := cat.WithStdin(f).Start().Output()
177 if len(got) != len(want) {
178 t.Fatalf("length mismatch, got %d but wanted %d", len(want), len(got))
179 }
180 actualSum := sha1.Sum([]byte(got))
181 if actualSum != expectedSum {
182 t.Fatalf("SHA-1 mismatch, got %x but wanted %x", actualSum, expectedSum)
183 }
184 }
185}
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800186
187func TestDirStack(t *testing.T) {
188 env := v23tests.New(t)
189 defer env.Cleanup()
190
191 home := os.Getenv("HOME")
192 if len(home) == 0 {
193 t.Fatalf("failed to read HOME environment variable")
194 }
195
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800196 getwd := func() string {
197 cwd, err := os.Getwd()
198 if err != nil {
199 t.Fatalf("Getwd() failed: %v", err)
200 }
201 return cwd
202 }
203
204 cwd := getwd()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800205 if got, want := env.Pushd("/"), cwd; got != want {
206 t.Fatalf("got %v, want %v", got, want)
207 }
208 if got, want := env.Pushd(home), "/"; got != want {
209 t.Fatalf("got %v, want %v", got, want)
210 }
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800211 tcwd := getwd()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800212 if got, want := tcwd, home; got != want {
213 t.Fatalf("got %v, want %v", got, want)
214 }
215 if got, want := env.Popd(), "/"; got != want {
216 t.Fatalf("got %v, want %v", got, want)
217 }
218 if got, want := env.Popd(), cwd; got != want {
219 t.Fatalf("got %v, want %v", got, want)
220 }
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800221 ncwd := getwd()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800222 if got, want := ncwd, cwd; got != want {
223 t.Fatalf("got %v, want %v", got, want)
224 }
225}
226
227func TestRun(t *testing.T) {
228 env := v23tests.New(t)
229 defer env.Cleanup()
230
231 if got, want := env.Run("/bin/echo", "hello world"), "hello world"; got != want {
232 t.Fatalf("got %v, want %v", got, want)
233 }
234
235 echo := env.BinaryFromPath("/bin/echo")
236 if got, want := echo.Run("hello", "world"), "hello world"; got != want {
237 t.Fatalf("got %v, want %v", got, want)
238 }
Robert Kroeger1123a082015-05-07 11:01:14 -0700239
240 sadEcho := echo.WithPrefixArgs("sad")
241 if got, want := sadEcho.Run("hello", "world"), "sad hello world"; got != want {
242 t.Fatalf("got %v, want %v", got, want)
243 }
244
245 happyEcho := echo.WithPrefixArgs("happy")
246 if got, want := happyEcho.Run("hello", "world"), "happy hello world"; got != want {
247 t.Fatalf("got %v, want %v", got, want)
248 }
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800249}
250
251type mockT struct {
252 msg string
253 failed bool
254}
255
256func (m *mockT) Error(args ...interface{}) {
257 m.msg = fmt.Sprint(args...)
258 m.failed = true
259}
260
261func (m *mockT) Errorf(format string, args ...interface{}) {
262 m.msg = fmt.Sprintf(format, args...)
263 m.failed = true
264}
265
266func (m *mockT) Fail() { panic("Fail") }
267
268func (m *mockT) FailNow() { panic("FailNow") }
269
270func (m *mockT) Failed() bool { return m.failed }
271
272func (m *mockT) Fatal(args ...interface{}) {
273 panic(fmt.Sprint(args...))
274}
275
276func (m *mockT) Fatalf(format string, args ...interface{}) {
277 panic(fmt.Sprintf(format, args...))
278}
279
280func (m *mockT) Log(args ...interface{}) {}
281
282func (m *mockT) Logf(format string, args ...interface{}) {}
283
284func (m *mockT) Skip(args ...interface{}) {}
285
286func (m *mockT) SkipNow() {}
287
288func (m *mockT) Skipf(format string, args ...interface{}) {}
289
290func (m *mockT) Skipped() bool { return false }
291
292func TestRunFailFromPath(t *testing.T) {
293 mock := &mockT{}
294 env := v23tests.New(mock)
295 defer env.Cleanup()
296
297 defer func() {
298 msg := recover().(string)
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800299 // this, and the tests below are intended to ensure that line #s
300 // are captured and reported correctly.
Cosmos Nicolaoue3b19322015-06-18 16:05:08 -0700301 if got, want := msg, "v23tests_test.go:308"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800302 t.Fatalf("%q does not contain %q", got, want)
303 }
304 if got, want := msg, "fork/exec /bin/echox: no such file or directory"; !strings.Contains(got, want) {
305 t.Fatalf("%q does not contain %q", got, want)
306 }
307 }()
308 env.Run("/bin/echox", "hello world")
309}
310
311func TestRunFail(t *testing.T) {
312 mock := &mockT{}
313 env := v23tests.New(mock)
314 defer env.Cleanup()
315
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700316 // Fail fast.
317 sh := env.Shell()
318 opts := sh.DefaultStartOpts()
319 opts.StartTimeout = 100 * time.Millisecond
320 sh.SetDefaultStartOpts(opts)
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800321 defer func() {
322 msg := recover().(string)
Cosmos Nicolaoue3b19322015-06-18 16:05:08 -0700323 if got, want := msg, "v23tests_test.go:330"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800324 t.Fatalf("%q does not contain %q", got, want)
325 }
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700326 if got, want := msg, "StartWithOpts"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800327 t.Fatalf("%q does not contain %q", got, want)
328 }
329 }()
Asim Shankarf32d24d2015-04-01 16:34:26 -0700330 v23tests.RunRootMT(env, "--xxv23.tcp.address=127.0.0.1:0")
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800331}
332
333func TestWaitTimeout(t *testing.T) {
334 env := v23tests.New(&mockT{})
335 defer env.Cleanup()
336
337 iterations := 0
338 sleeper := func() (interface{}, error) {
339 iterations++
340 return nil, nil
341 }
342
343 defer func() {
344 if iterations == 0 {
345 t.Fatalf("our sleeper didn't get to run")
346 }
Cosmos Nicolaoue3b19322015-06-18 16:05:08 -0700347 if got, want := recover().(string), "v23tests_test.go:351: timed out"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800348 t.Fatalf("%q does not contain %q", got, want)
349 }
350 }()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800351 env.WaitFor(sleeper, time.Millisecond, 50*time.Millisecond)
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800352}
353
354func TestWaitAsyncTimeout(t *testing.T) {
355 env := v23tests.New(&mockT{})
356 defer env.Cleanup()
357
358 iterations := 0
359 sleeper := func() (interface{}, error) {
360 time.Sleep(time.Minute)
361 iterations++
362 return nil, nil
363 }
364
365 defer func() {
366 if iterations != 0 {
367 t.Fatalf("our sleeper got to run")
368 }
Cosmos Nicolaoue3b19322015-06-18 16:05:08 -0700369 if got, want := recover().(string), "v23tests_test.go:373: timed out"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800370 t.Fatalf("%q does not contain %q", got, want)
371 }
372 }()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800373 env.WaitForAsync(sleeper, time.Millisecond, 50*time.Millisecond)
374}
375
376func TestWaitFor(t *testing.T) {
377 env := v23tests.New(t)
378 defer env.Cleanup()
379 iterations := 0
380 countIn5s := func() (interface{}, error) {
381 iterations++
382 if iterations%5 == 0 {
383 return iterations, nil
384 }
385 return nil, nil
386 }
387
388 r := env.WaitFor(countIn5s, time.Millisecond, 50*time.Millisecond)
389 if got, want := r.(int), 5; got != want {
390 env.Fatalf("got %d, want %d", got, want)
391 }
392
393 r = env.WaitForAsync(countIn5s, time.Millisecond, 50*time.Millisecond)
394 if got, want := r.(int), 10; got != want {
395 env.Fatalf("got %d, want %d", got, want)
396 }
397}
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800398
399func builder(t *testing.T) (string, string) {
400 env := v23tests.New(t)
401 defer env.Cleanup()
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -0700402 bin := env.BuildGoPkg("v.io/x/ref/test/v23tests")
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800403 return env.BinDir(), bin.Path()
404}
405
406func TestCachedBuild(t *testing.T) {
407 cleanup := v23tests.UseSharedBinDir()
408 defer cleanup()
409 defer os.Setenv("V23_BIN_DIR", "")
410
411 bin1, path1 := builder(t)
412 bin2, path2 := builder(t)
413
414 if bin1 != bin2 {
415 t.Fatalf("caching failed, bin dirs differ: %q != %q", bin1, bin2)
416 }
417
418 if path1 != path2 {
419 t.Fatalf("caching failed, paths differ: %q != %q", path1, path2)
420 }
421}
422
423func TestUncachedBuild(t *testing.T) {
424 bin1, path1 := builder(t)
425 bin2, path2 := builder(t)
426
427 if bin1 == bin2 {
428 t.Fatalf("failed, bin dirs are the same: %q != %q", bin1, bin2)
429 }
430
431 if path1 == path2 {
432 t.Fatalf("failed, paths are the same: %q != %q", path1, path2)
433 }
434}
Cosmos Nicolaouefa946c2015-06-08 18:49:45 -0700435
436func TestShutdownAndCleanupTogetherDontHang(t *testing.T) {
437 env := v23tests.New(t)
438 defer env.Cleanup()
439
440 bash := env.BinaryFromPath("/bin/bash")
441 if want, got := "hello world\n", bash.Start("-c", "echo hello world").Output(); want != got {
442 t.Fatalf("unexpected output, want %s, got %s", want, got)
443 }
444
445 inv := bash.Start("-c", "echo hello world")
446 var buf bytes.Buffer
447 inv.Shutdown(&buf, nil)
448 if want, got := "hello world\n", buf.String(); want != got {
449 t.Fatalf("unexpected output, want %s, got %s", want, got)
450 }
451 // Make sure that we can call Shutdown and Cleanup without hanging.
452}