blob: d9ec550eb065a37138b699efebc2b432995c9afd [file] [log] [blame]
Robert Kroegerebfb62a2014-12-10 14:42:09 -08001package testutil
2
3import (
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -08004 "io/ioutil"
Robert Kroegerebfb62a2014-12-10 14:42:09 -08005 "os"
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -08006 "path/filepath"
Robert Kroegerebfb62a2014-12-10 14:42:09 -08007 "strconv"
8 "testing"
9
10 "v.io/core/veyron2"
11 "v.io/core/veyron2/ipc"
12 "v.io/core/veyron2/rt"
13 "v.io/core/veyron2/vlog"
14
15 "v.io/core/veyron/lib/expect"
16 "v.io/core/veyron/lib/flags/consts"
17 "v.io/core/veyron/lib/modules"
18 "v.io/core/veyron/lib/modules/core"
19 "v.io/core/veyron/lib/testutil"
20 "v.io/core/veyron/lib/testutil/security"
21)
22
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -080023const (
24 // Setting this environment variable to any non-empty value avoids
25 // removing the generated workspace for successful test runs (for
26 // failed test runs, this is already the case). This is useful when
27 // developing test cases.
28 preserveWorkspaceEnv = "VEYRON_TEST_PRESERVE_WORKSPACE"
29)
30
Robert Kroegerebfb62a2014-12-10 14:42:09 -080031// StartRootMT sets up a root mount table for tests.
32func StartRootMT(t *testing.T, sh *modules.Shell) (string, modules.Handle) {
33 h, err := sh.Start(core.RootMTCommand, nil, "--", "--veyron.tcp.address=127.0.0.1:0")
34 if err != nil {
35 t.Fatalf("failed to start root mount table: %s", err)
36 }
37 s := expect.NewSession(t, h.Stdout(), ExpectTimeout)
38 s.ExpectVar("PID")
39 rootName := s.ExpectVar("MT_NAME")
40 if t.Failed() {
41 t.Fatalf("failed to read mt name: %s", s.Error())
42 }
43 return rootName, h
44}
45
46// CredentialsForChild creates credentials for a child process.
47func CredentialsForChild(rt veyron2.Runtime, blessing string) (string, []string) {
48 creds, _ := security.ForkCredentials(rt.Principal(), blessing)
49 return creds, []string{consts.VeyronCredentials + "=" + creds}
50}
51
52// SetNSRoots sets the roots for the local runtime's namespace.
53func SetNSRoots(t *testing.T, rt veyron2.Runtime, roots ...string) {
54 if err := rt.Namespace().SetRoots(roots...); err != nil {
55 t.Fatalf(testutil.FormatLogLine(3, "SetRoots(%v) failed with %v", roots, err))
56 }
57}
58
59// CreateShellAndMountTable builds a new modules shell and its
60// associated mount table.
61func CreateShellAndMountTable(t *testing.T, rt veyron2.Runtime) (*modules.Shell, func()) {
62 sh, err := modules.NewShell(nil)
63 if err != nil {
64 t.Fatalf("unexpected error: %s", err)
65 }
66 // The shell, will, by default share credentials with its children.
67 sh.ClearVar(consts.VeyronCredentials)
68
69 mtName, mtHandle := StartRootMT(t, sh)
70 vlog.VI(1).Infof("Started shell mounttable with name %v", mtName)
71 // Make sure the root mount table is the last process to be shutdown
72 // since the others will likely want to communicate with it during
73 // their shutdown process
74 sh.Forget(mtHandle)
75
76 // TODO(caprita): Define a GetNamespaceRootsCommand in modules/core and
77 // use that?
78 oldNamespaceRoots := rt.Namespace().Roots()
79 fn := func() {
80 vlog.VI(1).Info("------------ CLEANUP ------------")
81 vlog.VI(1).Info("---------------------------------")
82 vlog.VI(1).Info("--(cleaning up shell)------------")
83 if err := sh.Cleanup(os.Stdout, os.Stderr); err != nil {
84 t.Fatalf("sh.Cleanup failed with %v", err)
85 }
86 vlog.VI(1).Info("--(done cleaning up shell)-------")
87 vlog.VI(1).Info("--(shutting down root mt)--------")
88 if err := mtHandle.Shutdown(os.Stdout, os.Stderr); err != nil {
89 t.Fatalf("mtHandle.Shutdown failed with %v", err)
90 }
91 vlog.VI(1).Info("--(done shutting down root mt)---")
92 vlog.VI(1).Info("--------- DONE CLEANUP ----------")
93 SetNSRoots(t, rt, oldNamespaceRoots...)
94 }
95 SetNSRoots(t, rt, mtName)
96 sh.SetVar(consts.NamespaceRootPrefix, mtName)
97 return sh, fn
98}
99
100// RunShellCommand runs an external command using the modules system.
101func RunShellCommand(t *testing.T, sh *modules.Shell, env []string, cmd string, args ...string) (modules.Handle, *expect.Session) {
102 h, err := sh.Start(cmd, env, args...)
103 if err != nil {
104 t.Fatalf(testutil.FormatLogLine(2, "failed to start %q: %s", cmd, err))
105 return nil, nil
106 }
107 s := expect.NewSession(t, h.Stdout(), ExpectTimeout)
108 s.SetVerbosity(testing.Verbose())
109 return h, s
110}
111
112// NewServer creates a new server.
113func NewServer(rt veyron2.Runtime) (ipc.Server, string) {
114 server, err := rt.NewServer()
115 if err != nil {
116 vlog.Fatalf("NewServer() failed: %v", err)
117 }
118 spec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
119 endpoints, err := server.Listen(spec)
120 if err != nil {
121 vlog.Fatalf("Listen(%s) failed: %v", spec, err)
122 }
123 return server, endpoints[0].String()
124}
125
126// NewRuntime makes an instance of the runtime.
127func NewRuntime(t *testing.T, ort veyron2.Runtime, opts ...veyron2.ROpt) veyron2.Runtime {
128 runtime, err := rt.New(opts...)
129 if err != nil {
130 t.Fatalf("rt.New() failed: %v", err)
131 }
132 runtime.Namespace().SetRoots(ort.Namespace().Roots()[0])
133 return runtime
134}
135
136// ReadPID waits for the "ready:<PID>" line from the child and parses out the
137// PID of the child.
138func ReadPID(t *testing.T, s *expect.Session) int {
139 m := s.ExpectRE("ready:([0-9]+)", -1)
140 if len(m) == 1 && len(m[0]) == 2 {
141 pid, err := strconv.Atoi(m[0][1])
142 if err != nil {
143 t.Fatalf(testutil.FormatLogLine(2, "Atoi(%q) failed: %v", m[0][1], err))
144 }
145 return pid
146 }
147 t.Fatalf(testutil.FormatLogLine(2, "failed to extract pid: %v", m))
148 return 0
149}
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800150
151// SetupRootDir sets up and returns a directory for the root and returns
152// a cleanup function.
153func SetupRootDir(t *testing.T, prefix string) (string, func()) {
154 rootDir, err := ioutil.TempDir("", prefix)
155 if err != nil {
156 t.Fatalf("Failed to set up temporary dir for test: %v", err)
157 }
158 // On some operating systems (e.g. darwin) os.TempDir() can return a
159 // symlink. To avoid having to account for this eventuality later,
160 // evaluate the symlink.
161 rootDir, err = filepath.EvalSymlinks(rootDir)
162 if err != nil {
163 vlog.Fatalf("EvalSymlinks(%v) failed: %v", rootDir, err)
164 }
165
166 return rootDir, func() {
167 if t.Failed() || os.Getenv(preserveWorkspaceEnv) != "" {
168 t.Logf("You can examine the %s workspace at %v", prefix, rootDir)
169 } else {
170 os.RemoveAll(rootDir)
171 }
172 }
173}