blob: c8d655f2351c5167083c1b8c21b0ffe1ed49cfb3 [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) {
James Ring2de9d832015-09-01 14:37:41 -0700122 t.Skip("http://v.io/i/686 -- test is flaky in Go1.5")
Cosmos Nicolaou9e909842015-03-17 11:58:59 -0700123 sh, _ := modules.NewShell(nil, nil, testing.Verbose(), t)
Todd Wang95873902015-05-22 14:21:30 -0700124 child, err := sh.Start(nil, RunIntegrationTestInChild, "--test.run=TestHelperProcess", "--v23.tests")
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800125 if err != nil {
126 t.Fatal(err)
127 }
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700128 child.Expect("Hello")
129 child.ExpectRE("--- FAIL: TestHelperProcess", -1)
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800130 for _, e := range []string{
131 ".* 0: /bin/sleep: shutdown status: has not been shutdown",
132 ".* 1: /bin/sleep: shutdown status: signal: terminated",
133 ".* 2: /bin/sleep: shutdown status: has not been shutdown",
134 } {
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700135 child.ExpectRE(e, -1)
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800136 }
137 var stderr bytes.Buffer
138 if err := child.Shutdown(nil, &stderr); err != nil {
139 if !strings.Contains(err.Error(), "exit status 1") {
140 t.Fatal(err)
141 }
142 }
Cosmos Nicolaoue3b19322015-06-18 16:05:08 -0700143 logger.Global().Infof("Child\n=============\n%s", stderr.String())
144 logger.Global().Infof("-----------------")
Cosmos Nicolaoucc5a4a82015-02-07 23:09:28 -0800145}
James Ring79a9ceb2015-02-09 13:25:54 -0800146
147func TestInputRedirection(t *testing.T) {
Jiri Simsa95ab2972015-07-01 12:35:57 -0700148 testutil.InitRandGenerator(t.Logf)
James Ring79a9ceb2015-02-09 13:25:54 -0800149 env := v23tests.New(t)
150 defer env.Cleanup()
151
152 echo := env.BinaryFromPath("/bin/echo")
153 cat := env.BinaryFromPath("/bin/cat")
154
155 if want, got := "Hello, world!\n", cat.WithStdin(echo.Start("Hello, world!").Stdout()).Start().Output(); want != got {
Cosmos Nicolaoud61e5a82015-02-22 16:32:48 -0800156 t.Fatalf("unexpected output, got %q, want %q", got, want)
James Ring79a9ceb2015-02-09 13:25:54 -0800157 }
158
159 // Read something from a file.
160 {
161 want := "Hello from a file!"
Cosmos Nicolaou93dd88b2015-02-19 15:10:53 -0800162 f := env.NewTempFile()
James Ring79a9ceb2015-02-09 13:25:54 -0800163 f.WriteString(want)
164 f.Seek(0, 0)
165 if got := cat.WithStdin(f).Start().Output(); want != got {
Cosmos Nicolaoud61e5a82015-02-22 16:32:48 -0800166 t.Fatalf("unexpected output, got %q, want %q", got, want)
James Ring79a9ceb2015-02-09 13:25:54 -0800167 }
168 }
169
170 // Try it again with 1Mb.
171 {
172 want := testutil.RandomBytes(1 << 20)
173 expectedSum := sha1.Sum(want)
Cosmos Nicolaou93dd88b2015-02-19 15:10:53 -0800174 f := env.NewTempFile()
James Ring79a9ceb2015-02-09 13:25:54 -0800175 f.Write(want)
176 f.Seek(0, 0)
177 got := cat.WithStdin(f).Start().Output()
178 if len(got) != len(want) {
179 t.Fatalf("length mismatch, got %d but wanted %d", len(want), len(got))
180 }
181 actualSum := sha1.Sum([]byte(got))
182 if actualSum != expectedSum {
183 t.Fatalf("SHA-1 mismatch, got %x but wanted %x", actualSum, expectedSum)
184 }
185 }
186}
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800187
188func TestDirStack(t *testing.T) {
189 env := v23tests.New(t)
190 defer env.Cleanup()
191
192 home := os.Getenv("HOME")
193 if len(home) == 0 {
194 t.Fatalf("failed to read HOME environment variable")
195 }
196
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800197 getwd := func() string {
198 cwd, err := os.Getwd()
199 if err != nil {
200 t.Fatalf("Getwd() failed: %v", err)
201 }
202 return cwd
203 }
204
205 cwd := getwd()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800206 if got, want := env.Pushd("/"), cwd; got != want {
207 t.Fatalf("got %v, want %v", got, want)
208 }
209 if got, want := env.Pushd(home), "/"; got != want {
210 t.Fatalf("got %v, want %v", got, want)
211 }
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800212 tcwd := getwd()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800213 if got, want := tcwd, home; got != want {
214 t.Fatalf("got %v, want %v", got, want)
215 }
216 if got, want := env.Popd(), "/"; got != want {
217 t.Fatalf("got %v, want %v", got, want)
218 }
219 if got, want := env.Popd(), cwd; got != want {
220 t.Fatalf("got %v, want %v", got, want)
221 }
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800222 ncwd := getwd()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800223 if got, want := ncwd, cwd; got != want {
224 t.Fatalf("got %v, want %v", got, want)
225 }
226}
227
228func TestRun(t *testing.T) {
229 env := v23tests.New(t)
230 defer env.Cleanup()
231
232 if got, want := env.Run("/bin/echo", "hello world"), "hello world"; got != want {
233 t.Fatalf("got %v, want %v", got, want)
234 }
235
236 echo := env.BinaryFromPath("/bin/echo")
237 if got, want := echo.Run("hello", "world"), "hello world"; got != want {
238 t.Fatalf("got %v, want %v", got, want)
239 }
Robert Kroeger1123a082015-05-07 11:01:14 -0700240
241 sadEcho := echo.WithPrefixArgs("sad")
242 if got, want := sadEcho.Run("hello", "world"), "sad hello world"; got != want {
243 t.Fatalf("got %v, want %v", got, want)
244 }
245
246 happyEcho := echo.WithPrefixArgs("happy")
247 if got, want := happyEcho.Run("hello", "world"), "happy hello world"; got != want {
248 t.Fatalf("got %v, want %v", got, want)
249 }
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800250}
251
252type mockT struct {
253 msg string
254 failed bool
255}
256
257func (m *mockT) Error(args ...interface{}) {
258 m.msg = fmt.Sprint(args...)
259 m.failed = true
260}
261
262func (m *mockT) Errorf(format string, args ...interface{}) {
263 m.msg = fmt.Sprintf(format, args...)
264 m.failed = true
265}
266
267func (m *mockT) Fail() { panic("Fail") }
268
269func (m *mockT) FailNow() { panic("FailNow") }
270
271func (m *mockT) Failed() bool { return m.failed }
272
273func (m *mockT) Fatal(args ...interface{}) {
274 panic(fmt.Sprint(args...))
275}
276
277func (m *mockT) Fatalf(format string, args ...interface{}) {
278 panic(fmt.Sprintf(format, args...))
279}
280
281func (m *mockT) Log(args ...interface{}) {}
282
283func (m *mockT) Logf(format string, args ...interface{}) {}
284
285func (m *mockT) Skip(args ...interface{}) {}
286
287func (m *mockT) SkipNow() {}
288
289func (m *mockT) Skipf(format string, args ...interface{}) {}
290
291func (m *mockT) Skipped() bool { return false }
292
293func TestRunFailFromPath(t *testing.T) {
294 mock := &mockT{}
295 env := v23tests.New(mock)
296 defer env.Cleanup()
297
298 defer func() {
299 msg := recover().(string)
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800300 // this, and the tests below are intended to ensure that line #s
301 // are captured and reported correctly.
James Ring02577e82015-09-01 15:13:37 -0700302 if got, want := msg, "v23tests_test.go:309"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800303 t.Fatalf("%q does not contain %q", got, want)
304 }
305 if got, want := msg, "fork/exec /bin/echox: no such file or directory"; !strings.Contains(got, want) {
306 t.Fatalf("%q does not contain %q", got, want)
307 }
308 }()
309 env.Run("/bin/echox", "hello world")
310}
311
312func TestRunFail(t *testing.T) {
313 mock := &mockT{}
314 env := v23tests.New(mock)
315 defer env.Cleanup()
316
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700317 // Fail fast.
318 sh := env.Shell()
319 opts := sh.DefaultStartOpts()
320 opts.StartTimeout = 100 * time.Millisecond
321 sh.SetDefaultStartOpts(opts)
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800322 defer func() {
323 msg := recover().(string)
James Ring02577e82015-09-01 15:13:37 -0700324 if got, want := msg, "v23tests_test.go:331"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800325 t.Fatalf("%q does not contain %q", got, want)
326 }
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700327 if got, want := msg, "StartWithOpts"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800328 t.Fatalf("%q does not contain %q", got, want)
329 }
330 }()
Asim Shankarf32d24d2015-04-01 16:34:26 -0700331 v23tests.RunRootMT(env, "--xxv23.tcp.address=127.0.0.1:0")
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800332}
333
334func TestWaitTimeout(t *testing.T) {
335 env := v23tests.New(&mockT{})
336 defer env.Cleanup()
337
338 iterations := 0
339 sleeper := func() (interface{}, error) {
340 iterations++
341 return nil, nil
342 }
343
344 defer func() {
345 if iterations == 0 {
346 t.Fatalf("our sleeper didn't get to run")
347 }
James Ring02577e82015-09-01 15:13:37 -0700348 if got, want := recover().(string), "v23tests_test.go:352: timed out"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800349 t.Fatalf("%q does not contain %q", got, want)
350 }
351 }()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800352 env.WaitFor(sleeper, time.Millisecond, 50*time.Millisecond)
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800353}
354
355func TestWaitAsyncTimeout(t *testing.T) {
356 env := v23tests.New(&mockT{})
357 defer env.Cleanup()
358
359 iterations := 0
360 sleeper := func() (interface{}, error) {
361 time.Sleep(time.Minute)
362 iterations++
363 return nil, nil
364 }
365
366 defer func() {
367 if iterations != 0 {
368 t.Fatalf("our sleeper got to run")
369 }
James Ring02577e82015-09-01 15:13:37 -0700370 if got, want := recover().(string), "v23tests_test.go:374: timed out"; !strings.Contains(got, want) {
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800371 t.Fatalf("%q does not contain %q", got, want)
372 }
373 }()
Cosmos Nicolaoud3b1cb12015-02-20 00:06:33 -0800374 env.WaitForAsync(sleeper, time.Millisecond, 50*time.Millisecond)
375}
376
377func TestWaitFor(t *testing.T) {
378 env := v23tests.New(t)
379 defer env.Cleanup()
380 iterations := 0
381 countIn5s := func() (interface{}, error) {
382 iterations++
383 if iterations%5 == 0 {
384 return iterations, nil
385 }
386 return nil, nil
387 }
388
389 r := env.WaitFor(countIn5s, time.Millisecond, 50*time.Millisecond)
390 if got, want := r.(int), 5; got != want {
391 env.Fatalf("got %d, want %d", got, want)
392 }
393
394 r = env.WaitForAsync(countIn5s, time.Millisecond, 50*time.Millisecond)
395 if got, want := r.(int), 10; got != want {
396 env.Fatalf("got %d, want %d", got, want)
397 }
398}
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800399
400func builder(t *testing.T) (string, string) {
401 env := v23tests.New(t)
402 defer env.Cleanup()
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -0700403 bin := env.BuildGoPkg("v.io/x/ref/test/v23tests")
Cosmos Nicolaoua6fef892015-02-20 23:09:03 -0800404 return env.BinDir(), bin.Path()
405}
406
407func TestCachedBuild(t *testing.T) {
408 cleanup := v23tests.UseSharedBinDir()
409 defer cleanup()
410 defer os.Setenv("V23_BIN_DIR", "")
411
412 bin1, path1 := builder(t)
413 bin2, path2 := builder(t)
414
415 if bin1 != bin2 {
416 t.Fatalf("caching failed, bin dirs differ: %q != %q", bin1, bin2)
417 }
418
419 if path1 != path2 {
420 t.Fatalf("caching failed, paths differ: %q != %q", path1, path2)
421 }
422}
423
424func TestUncachedBuild(t *testing.T) {
425 bin1, path1 := builder(t)
426 bin2, path2 := builder(t)
427
428 if bin1 == bin2 {
429 t.Fatalf("failed, bin dirs are the same: %q != %q", bin1, bin2)
430 }
431
432 if path1 == path2 {
433 t.Fatalf("failed, paths are the same: %q != %q", path1, path2)
434 }
435}
Cosmos Nicolaouefa946c2015-06-08 18:49:45 -0700436
437func TestShutdownAndCleanupTogetherDontHang(t *testing.T) {
438 env := v23tests.New(t)
439 defer env.Cleanup()
440
441 bash := env.BinaryFromPath("/bin/bash")
442 if want, got := "hello world\n", bash.Start("-c", "echo hello world").Output(); want != got {
443 t.Fatalf("unexpected output, want %s, got %s", want, got)
444 }
445
446 inv := bash.Start("-c", "echo hello world")
447 var buf bytes.Buffer
448 inv.Shutdown(&buf, nil)
449 if want, got := "hello world\n", buf.String(); want != got {
450 t.Fatalf("unexpected output, want %s, got %s", want, got)
451 }
452 // Make sure that we can call Shutdown and Cleanup without hanging.
453}