blob: 915f26f6e1f01d65051955cd3240f62ae6995b9e [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
Jiri Simsa6ac95222015-02-23 16:11:49 -080010 "v.io/v23"
11 "v.io/v23/context"
12 "v.io/v23/ipc"
13 "v.io/v23/security"
Jiri Simsa337af232015-02-27 14:36:46 -080014 "v.io/x/lib/vlog"
Robert Kroegerebfb62a2014-12-10 14:42:09 -080015
Jiri Simsaffceefa2015-02-28 11:03:34 -080016 "v.io/x/ref/lib/flags/consts"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070017 "v.io/x/ref/test/modules"
18 "v.io/x/ref/test/modules/core"
19 "v.io/x/ref/test/testutil"
Robert Kroegerebfb62a2014-12-10 14:42:09 -080020)
21
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -080022const (
23 // Setting this environment variable to any non-empty value avoids
24 // removing the generated workspace for successful test runs (for
25 // failed test runs, this is already the case). This is useful when
26 // developing test cases.
27 preserveWorkspaceEnv = "VEYRON_TEST_PRESERVE_WORKSPACE"
28)
29
Asim Shankar11b530a2015-03-11 22:40:52 -070030// startRootMT sets up a root mount table for tests.
31func startRootMT(t *testing.T, sh *modules.Shell) (string, modules.Handle) {
Suharsh Sivakumar9d17e4a2015-02-02 22:42:16 -080032 h, err := sh.Start(core.RootMTCommand, nil, "--veyron.tcp.address=127.0.0.1:0")
Robert Kroegerebfb62a2014-12-10 14:42:09 -080033 if err != nil {
34 t.Fatalf("failed to start root mount table: %s", err)
35 }
Cosmos Nicolaou42a17362015-03-10 16:40:18 -070036 h.ExpectVar("PID")
37 rootName := h.ExpectVar("MT_NAME")
Robert Kroegerebfb62a2014-12-10 14:42:09 -080038 if t.Failed() {
Cosmos Nicolaou42a17362015-03-10 16:40:18 -070039 t.Fatalf("failed to read mt name: %s", h.Error())
Robert Kroegerebfb62a2014-12-10 14:42:09 -080040 }
41 return rootName, h
42}
43
Asim Shankar11b530a2015-03-11 22:40:52 -070044// setNSRoots sets the roots for the local runtime's namespace.
45func setNSRoots(t *testing.T, ctx *context.T, roots ...string) {
Jiri Simsa6ac95222015-02-23 16:11:49 -080046 ns := v23.GetNamespace(ctx)
Matt Rosencrantz6edab562015-01-12 11:07:55 -080047 if err := ns.SetRoots(roots...); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -080048 t.Fatalf(testutil.FormatLogLine(3, "SetRoots(%v) failed with %v", roots, err))
49 }
50}
51
52// CreateShellAndMountTable builds a new modules shell and its
53// associated mount table.
Ryan Browna08a2212015-01-15 15:40:10 -080054func CreateShellAndMountTable(t *testing.T, ctx *context.T, p security.Principal) (*modules.Shell, func()) {
Cosmos Nicolaou9e909842015-03-17 11:58:59 -070055 sh, err := modules.NewShell(ctx, p, testing.Verbose(), t)
Robert Kroegerebfb62a2014-12-10 14:42:09 -080056 if err != nil {
57 t.Fatalf("unexpected error: %s", err)
58 }
Cosmos Nicolaou42a17362015-03-10 16:40:18 -070059 opts := sh.DefaultStartOpts()
60 opts.ExpectTimeout = ExpectTimeout
61 sh.SetDefaultStartOpts(opts)
Robert Kroegerebfb62a2014-12-10 14:42:09 -080062 // The shell, will, by default share credentials with its children.
63 sh.ClearVar(consts.VeyronCredentials)
64
Asim Shankar11b530a2015-03-11 22:40:52 -070065 mtName, mtHandle := startRootMT(t, sh)
Robert Kroegerebfb62a2014-12-10 14:42:09 -080066 vlog.VI(1).Infof("Started shell mounttable with name %v", mtName)
67 // Make sure the root mount table is the last process to be shutdown
68 // since the others will likely want to communicate with it during
69 // their shutdown process
70 sh.Forget(mtHandle)
71
72 // TODO(caprita): Define a GetNamespaceRootsCommand in modules/core and
73 // use that?
Matt Rosencrantz6edab562015-01-12 11:07:55 -080074
Jiri Simsa6ac95222015-02-23 16:11:49 -080075 oldNamespaceRoots := v23.GetNamespace(ctx).Roots()
Robert Kroegerebfb62a2014-12-10 14:42:09 -080076 fn := func() {
77 vlog.VI(1).Info("------------ CLEANUP ------------")
78 vlog.VI(1).Info("---------------------------------")
79 vlog.VI(1).Info("--(cleaning up shell)------------")
80 if err := sh.Cleanup(os.Stdout, os.Stderr); err != nil {
Robert Kroeger74645172015-02-11 14:22:21 -080081 t.Fatalf(testutil.FormatLogLine(2, "sh.Cleanup failed with %v", err))
Robert Kroegerebfb62a2014-12-10 14:42:09 -080082 }
83 vlog.VI(1).Info("--(done cleaning up shell)-------")
84 vlog.VI(1).Info("--(shutting down root mt)--------")
85 if err := mtHandle.Shutdown(os.Stdout, os.Stderr); err != nil {
Robert Kroeger74645172015-02-11 14:22:21 -080086 t.Fatalf(testutil.FormatLogLine(2, "mtHandle.Shutdown failed with %v", err))
Robert Kroegerebfb62a2014-12-10 14:42:09 -080087 }
88 vlog.VI(1).Info("--(done shutting down root mt)---")
89 vlog.VI(1).Info("--------- DONE CLEANUP ----------")
Asim Shankar11b530a2015-03-11 22:40:52 -070090 setNSRoots(t, ctx, oldNamespaceRoots...)
Robert Kroegerebfb62a2014-12-10 14:42:09 -080091 }
Asim Shankar11b530a2015-03-11 22:40:52 -070092 setNSRoots(t, ctx, mtName)
Robert Kroegerebfb62a2014-12-10 14:42:09 -080093 sh.SetVar(consts.NamespaceRootPrefix, mtName)
94 return sh, fn
95}
96
Cosmos Nicolaou42a17362015-03-10 16:40:18 -070097// RunCommand runs a modules command.
98func RunCommand(t *testing.T, sh *modules.Shell, env []string, cmd string, args ...string) modules.Handle {
Asim Shankar11b530a2015-03-11 22:40:52 -070099 h, err := sh.StartWithOpts(sh.DefaultStartOpts(), env, cmd, args...)
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800100 if err != nil {
101 t.Fatalf(testutil.FormatLogLine(2, "failed to start %q: %s", cmd, err))
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700102 return nil
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800103 }
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700104 h.SetVerbosity(testing.Verbose())
105 return h
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800106}
107
108// NewServer creates a new server.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800109func NewServer(ctx *context.T) (ipc.Server, string) {
Jiri Simsa6ac95222015-02-23 16:11:49 -0800110 server, err := v23.NewServer(ctx)
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800111 if err != nil {
112 vlog.Fatalf("NewServer() failed: %v", err)
113 }
114 spec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
115 endpoints, err := server.Listen(spec)
116 if err != nil {
117 vlog.Fatalf("Listen(%s) failed: %v", spec, err)
118 }
119 return server, endpoints[0].String()
120}
121
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800122// ReadPID waits for the "ready:<PID>" line from the child and parses out the
123// PID of the child.
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700124func ReadPID(t *testing.T, h modules.ExpectSession) int {
125 m := h.ExpectRE("ready:([0-9]+)", -1)
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800126 if len(m) == 1 && len(m[0]) == 2 {
127 pid, err := strconv.Atoi(m[0][1])
128 if err != nil {
129 t.Fatalf(testutil.FormatLogLine(2, "Atoi(%q) failed: %v", m[0][1], err))
130 }
131 return pid
132 }
133 t.Fatalf(testutil.FormatLogLine(2, "failed to extract pid: %v", m))
134 return 0
135}
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800136
137// SetupRootDir sets up and returns a directory for the root and returns
138// a cleanup function.
139func SetupRootDir(t *testing.T, prefix string) (string, func()) {
140 rootDir, err := ioutil.TempDir("", prefix)
141 if err != nil {
142 t.Fatalf("Failed to set up temporary dir for test: %v", err)
143 }
144 // On some operating systems (e.g. darwin) os.TempDir() can return a
145 // symlink. To avoid having to account for this eventuality later,
146 // evaluate the symlink.
147 rootDir, err = filepath.EvalSymlinks(rootDir)
148 if err != nil {
149 vlog.Fatalf("EvalSymlinks(%v) failed: %v", rootDir, err)
150 }
151
152 return rootDir, func() {
153 if t.Failed() || os.Getenv(preserveWorkspaceEnv) != "" {
154 t.Logf("You can examine the %s workspace at %v", prefix, rootDir)
155 } else {
156 os.RemoveAll(rootDir)
157 }
158 }
159}