Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 1 | package impl_test |
| 2 | |
| 3 | import ( |
| 4 | "fmt" |
Bogdan Caprita | d2b9f03 | 2014-10-10 17:43:29 -0700 | [diff] [blame] | 5 | "io/ioutil" |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 6 | "os" |
Bogdan Caprita | d2b9f03 | 2014-10-10 17:43:29 -0700 | [diff] [blame] | 7 | "path/filepath" |
Robert Kroeger | 1cb4a0d | 2014-10-20 11:55:38 -0700 | [diff] [blame] | 8 | "reflect" |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 9 | "runtime" |
Robert Kroeger | 1cb4a0d | 2014-10-20 11:55:38 -0700 | [diff] [blame] | 10 | "sort" |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 11 | "strings" |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 12 | "testing" |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 13 | "time" |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 14 | |
Jiri Simsa | 764efb7 | 2014-12-25 20:57:03 -0800 | [diff] [blame] | 15 | "v.io/core/veyron2" |
| 16 | "v.io/core/veyron2/ipc" |
| 17 | "v.io/core/veyron2/naming" |
| 18 | "v.io/core/veyron2/security" |
| 19 | "v.io/core/veyron2/services/mgmt/device" |
| 20 | "v.io/core/veyron2/verror" |
| 21 | "v.io/core/veyron2/verror2" |
| 22 | "v.io/core/veyron2/vlog" |
Cosmos Nicolaou | d6c3c9c | 2014-09-30 15:42:53 -0700 | [diff] [blame] | 23 | |
Jiri Simsa | 764efb7 | 2014-12-25 20:57:03 -0800 | [diff] [blame] | 24 | "v.io/core/veyron/lib/expect" |
| 25 | "v.io/core/veyron/lib/flags/consts" |
| 26 | "v.io/core/veyron/lib/modules" |
| 27 | "v.io/core/veyron/lib/modules/core" |
| 28 | tsecurity "v.io/core/veyron/lib/testutil/security" |
| 29 | _ "v.io/core/veyron/profiles/static" |
| 30 | "v.io/core/veyron/services/mgmt/device/impl" |
| 31 | "v.io/core/veyron2/services/mgmt/application" |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 32 | ) |
| 33 | |
Bogdan Caprita | 916e99f | 2014-11-24 15:47:19 -0800 | [diff] [blame] | 34 | const ( |
| 35 | // Setting this environment variable to any non-empty value avoids |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 36 | // removing the device manager's workspace for successful test runs (for |
Bogdan Caprita | 916e99f | 2014-11-24 15:47:19 -0800 | [diff] [blame] | 37 | // failed test runs, this is already the case). This is useful when |
| 38 | // developing test cases. |
Bogdan Caprita | 9c4aa22 | 2014-12-10 14:46:30 -0800 | [diff] [blame] | 39 | preserveDMWorkspaceEnv = "VEYRON_TEST_PRESERVE_DM_WORKSPACE" |
Bogdan Caprita | 916e99f | 2014-11-24 15:47:19 -0800 | [diff] [blame] | 40 | |
| 41 | // TODO(caprita): Set the timeout in a more principled manner. |
| 42 | expectTimeout = 20 * time.Second |
Bogdan Caprita | 4ea9b03 | 2014-12-27 14:56:51 -0800 | [diff] [blame^] | 43 | stopTimeout = 20 // In seconds. |
Bogdan Caprita | 916e99f | 2014-11-24 15:47:19 -0800 | [diff] [blame] | 44 | ) |
Bogdan Caprita | d2b9f03 | 2014-10-10 17:43:29 -0700 | [diff] [blame] | 45 | |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 46 | func loc(d int) string { |
| 47 | _, file, line, _ := runtime.Caller(d + 1) |
| 48 | return fmt.Sprintf("%s:%d", filepath.Base(file), line) |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 49 | } |
| 50 | |
Bogdan Caprita | 916e99f | 2014-11-24 15:47:19 -0800 | [diff] [blame] | 51 | func startRootMT(t *testing.T, sh *modules.Shell) (string, modules.Handle) { |
Cosmos Nicolaou | 612ad38 | 2014-10-29 19:41:35 -0700 | [diff] [blame] | 52 | h, err := sh.Start(core.RootMTCommand, nil, "--", "--veyron.tcp.address=127.0.0.1:0") |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 53 | if err != nil { |
| 54 | t.Fatalf("failed to start root mount table: %s", err) |
| 55 | } |
Bogdan Caprita | 916e99f | 2014-11-24 15:47:19 -0800 | [diff] [blame] | 56 | s := expect.NewSession(t, h.Stdout(), expectTimeout) |
Cosmos Nicolaou | 28dabfc | 2014-12-15 22:51:07 -0800 | [diff] [blame] | 57 | s.ExpectVar("PID") |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 58 | rootName := s.ExpectVar("MT_NAME") |
| 59 | if t.Failed() { |
| 60 | t.Fatalf("failed to read mt name: %s", s.Error()) |
| 61 | } |
Bogdan Caprita | 916e99f | 2014-11-24 15:47:19 -0800 | [diff] [blame] | 62 | return rootName, h |
Bogdan Caprita | b9501d1 | 2014-10-10 15:02:03 -0700 | [diff] [blame] | 63 | } |
| 64 | |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 65 | func credentialsForChild(blessing string) (string, []string) { |
Ankur | 77cd9e8 | 2014-12-15 12:59:59 -0800 | [diff] [blame] | 66 | creds, _ := tsecurity.ForkCredentials(globalRT.Principal(), blessing) |
Asim Shankar | 95910b6 | 2014-10-31 22:02:29 -0700 | [diff] [blame] | 67 | return creds, []string{consts.VeyronCredentials + "=" + creds} |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 68 | } |
| 69 | |
Matt Rosencrantz | c13446b | 2014-12-03 10:37:00 -0800 | [diff] [blame] | 70 | // setNSRoots sets the roots for the local runtime's namespace. |
| 71 | func setNSRoots(t *testing.T, roots ...string) { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 72 | if err := globalRT.Namespace().SetRoots(roots...); err != nil { |
Matt Rosencrantz | c13446b | 2014-12-03 10:37:00 -0800 | [diff] [blame] | 73 | t.Fatalf("%s: SetRoots(%v) failed with %v", loc(2), roots, err) |
Bogdan Caprita | 54cf3ef | 2014-11-21 10:38:52 -0800 | [diff] [blame] | 74 | } |
| 75 | } |
| 76 | |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 77 | func createShellAndMountTable(t *testing.T) (*modules.Shell, func()) { |
Cosmos Nicolaou | 344cc4a | 2014-11-26 15:38:43 -0800 | [diff] [blame] | 78 | sh, err := modules.NewShell(nil) |
| 79 | if err != nil { |
| 80 | t.Fatalf("unexpected error: %s", err) |
| 81 | } |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 82 | // The shell, will, by default share credentials with its children. |
Asim Shankar | 95910b6 | 2014-10-31 22:02:29 -0700 | [diff] [blame] | 83 | sh.ClearVar(consts.VeyronCredentials) |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 84 | |
Bogdan Caprita | 916e99f | 2014-11-24 15:47:19 -0800 | [diff] [blame] | 85 | mtName, mtHandle := startRootMT(t, sh) |
Bogdan Caprita | e577ef0 | 2014-11-28 17:33:18 -0800 | [diff] [blame] | 86 | vlog.VI(1).Infof("Started shell mounttable with name %v", mtName) |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 87 | // Make sure the root mount table is the last process to be shutdown |
| 88 | // since the others will likely want to communicate with it during |
| 89 | // their shutdown process |
| 90 | sh.Forget(mtHandle) |
| 91 | |
Bogdan Caprita | 54cf3ef | 2014-11-21 10:38:52 -0800 | [diff] [blame] | 92 | // TODO(caprita): Define a GetNamespaceRootsCommand in modules/core and |
| 93 | // use that? |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 94 | oldNamespaceRoots := globalRT.Namespace().Roots() |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 95 | fn := func() { |
| 96 | vlog.VI(1).Info("------------ CLEANUP ------------") |
| 97 | vlog.VI(1).Info("---------------------------------") |
Bogdan Caprita | e577ef0 | 2014-11-28 17:33:18 -0800 | [diff] [blame] | 98 | vlog.VI(1).Info("--(cleaning up shell)------------") |
| 99 | if err := sh.Cleanup(os.Stdout, os.Stderr); err != nil { |
| 100 | t.Fatalf("sh.Cleanup failed with %v", err) |
| 101 | } |
| 102 | vlog.VI(1).Info("--(done cleaning up shell)-------") |
| 103 | vlog.VI(1).Info("--(shutting down root mt)--------") |
| 104 | if err := mtHandle.Shutdown(os.Stdout, os.Stderr); err != nil { |
| 105 | t.Fatalf("mtHandle.Shutdown failed with %v", err) |
| 106 | } |
| 107 | vlog.VI(1).Info("--(done shutting down root mt)---") |
| 108 | vlog.VI(1).Info("--------- DONE CLEANUP ----------") |
Matt Rosencrantz | c13446b | 2014-12-03 10:37:00 -0800 | [diff] [blame] | 109 | setNSRoots(t, oldNamespaceRoots...) |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 110 | } |
Matt Rosencrantz | c13446b | 2014-12-03 10:37:00 -0800 | [diff] [blame] | 111 | setNSRoots(t, mtName) |
Asim Shankar | 95910b6 | 2014-10-31 22:02:29 -0700 | [diff] [blame] | 112 | sh.SetVar(consts.NamespaceRootPrefix, mtName) |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 113 | return sh, fn |
| 114 | } |
| 115 | |
| 116 | func runShellCommand(t *testing.T, sh *modules.Shell, env []string, cmd string, args ...string) (modules.Handle, *expect.Session) { |
Cosmos Nicolaou | 612ad38 | 2014-10-29 19:41:35 -0700 | [diff] [blame] | 117 | h, err := sh.Start(cmd, env, args...) |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 118 | if err != nil { |
| 119 | t.Fatalf("%s: failed to start %q: %s", loc(1), cmd, err) |
| 120 | return nil, nil |
| 121 | } |
Bogdan Caprita | 916e99f | 2014-11-24 15:47:19 -0800 | [diff] [blame] | 122 | s := expect.NewSession(t, h.Stdout(), expectTimeout) |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 123 | s.SetVerbosity(testing.Verbose()) |
| 124 | return h, s |
| 125 | } |
| 126 | |
| 127 | func envelopeFromShell(sh *modules.Shell, env []string, cmd, title string, args ...string) application.Envelope { |
| 128 | args, nenv := sh.CommandEnvelope(cmd, env, args...) |
| 129 | return application.Envelope{ |
| 130 | Title: title, |
| 131 | Args: args[1:], |
| 132 | // TODO(caprita): revisit how the environment is sanitized for arbirary |
| 133 | // apps. |
| 134 | Env: impl.VeyronEnvironment(nenv), |
| 135 | Binary: mockBinaryRepoName, |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 136 | } |
| 137 | } |
| 138 | |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 139 | // setupRootDir sets up and returns the local filesystem location that the |
| 140 | // device manager is told to use, as well as a cleanup function. |
Bogdan Caprita | d2b9f03 | 2014-10-10 17:43:29 -0700 | [diff] [blame] | 141 | func setupRootDir(t *testing.T) (string, func()) { |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 142 | rootDir, err := ioutil.TempDir("", "devicemanager") |
Bogdan Caprita | d2b9f03 | 2014-10-10 17:43:29 -0700 | [diff] [blame] | 143 | if err != nil { |
| 144 | t.Fatalf("Failed to set up temporary dir for test: %v", err) |
| 145 | } |
| 146 | // On some operating systems (e.g. darwin) os.TempDir() can return a |
| 147 | // symlink. To avoid having to account for this eventuality later, |
| 148 | // evaluate the symlink. |
| 149 | rootDir, err = filepath.EvalSymlinks(rootDir) |
| 150 | if err != nil { |
| 151 | vlog.Fatalf("EvalSymlinks(%v) failed: %v", rootDir, err) |
| 152 | } |
| 153 | return rootDir, func() { |
Bogdan Caprita | 9c4aa22 | 2014-12-10 14:46:30 -0800 | [diff] [blame] | 154 | if t.Failed() || os.Getenv(preserveDMWorkspaceEnv) != "" { |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 155 | t.Logf("You can examine the device manager workspace at %v", rootDir) |
Bogdan Caprita | d2b9f03 | 2014-10-10 17:43:29 -0700 | [diff] [blame] | 156 | } else { |
| 157 | os.RemoveAll(rootDir) |
| 158 | } |
| 159 | } |
| 160 | } |
| 161 | |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 162 | func newServer() (ipc.Server, string) { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 163 | server, err := globalRT.NewServer() |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 164 | if err != nil { |
| 165 | vlog.Fatalf("NewServer() failed: %v", err) |
| 166 | } |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 167 | spec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{"tcp", "127.0.0.1:0"}}} |
Cosmos Nicolaou | 28dabfc | 2014-12-15 22:51:07 -0800 | [diff] [blame] | 168 | endpoints, err := server.Listen(spec) |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 169 | if err != nil { |
Cosmos Nicolaou | ae8dd21 | 2014-12-13 23:43:08 -0800 | [diff] [blame] | 170 | vlog.Fatalf("Listen(%s) failed: %v", spec, err) |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 171 | } |
Cosmos Nicolaou | 28dabfc | 2014-12-15 22:51:07 -0800 | [diff] [blame] | 172 | return server, endpoints[0].String() |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 173 | } |
| 174 | |
Bogdan Caprita | 474ad11 | 2014-12-03 19:24:12 -0800 | [diff] [blame] | 175 | // resolveExpectNotFound verifies that the given name is not in the mounttable. |
Bogdan Caprita | bce0a63 | 2014-09-03 16:15:26 -0700 | [diff] [blame] | 176 | func resolveExpectNotFound(t *testing.T, name string) { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 177 | if results, err := globalRT.Namespace().Resolve(globalRT.NewContext(), name); err == nil { |
Bogdan Caprita | 474ad11 | 2014-12-03 19:24:12 -0800 | [diff] [blame] | 178 | t.Fatalf("%s: Resolve(%v) succeeded with results %v when it was expected to fail", loc(1), name, results) |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 179 | } else if expectErr := naming.ErrNoSuchName.ID; !verror2.Is(err, expectErr) { |
Bogdan Caprita | 474ad11 | 2014-12-03 19:24:12 -0800 | [diff] [blame] | 180 | t.Fatalf("%s: Resolve(%v) failed with error %v, expected error ID %v", loc(1), name, err, expectErr) |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 181 | } |
| 182 | } |
| 183 | |
| 184 | // resolve looks up the given name in the mounttable. |
Bogdan Caprita | bce0a63 | 2014-09-03 16:15:26 -0700 | [diff] [blame] | 185 | func resolve(t *testing.T, name string, replicas int) []string { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 186 | results, err := globalRT.Namespace().Resolve(globalRT.NewContext(), name) |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 187 | if err != nil { |
| 188 | t.Fatalf("Resolve(%v) failed: %v", name, err) |
| 189 | } |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 190 | |
| 191 | filteredResults := []string{} |
| 192 | for _, r := range results { |
| 193 | if strings.Index(r, "@tcp") != -1 { |
| 194 | filteredResults = append(filteredResults, r) |
| 195 | } |
| 196 | } |
| 197 | // We are going to get a websocket and a tcp endpoint for each replica. |
| 198 | if want, got := replicas, len(filteredResults); want != got { |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 199 | t.Fatalf("Resolve(%v) expected %d result(s), got %d instead", name, want, got) |
| 200 | } |
Shyam Jayaraman | dbae76b | 2014-11-17 12:51:29 -0800 | [diff] [blame] | 201 | return filteredResults |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 202 | } |
| 203 | |
| 204 | // The following set of functions are convenience wrappers around Update and |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 205 | // Revert for device manager. |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 206 | |
Bogdan Caprita | a456f47 | 2014-12-10 10:18:03 -0800 | [diff] [blame] | 207 | func deviceStub(name string) device.DeviceClientMethods { |
Bogdan Caprita | 9c4aa22 | 2014-12-10 14:46:30 -0800 | [diff] [blame] | 208 | deviceName := naming.Join(name, "device") |
Bogdan Caprita | a456f47 | 2014-12-10 10:18:03 -0800 | [diff] [blame] | 209 | return device.DeviceClient(deviceName) |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 210 | } |
| 211 | |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 212 | func updateDeviceExpectError(t *testing.T, name string, errID verror.ID) { |
| 213 | if err := deviceStub(name).Update(globalRT.NewContext()); !verror2.Is(err, errID) { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 214 | t.Fatalf("%s: Update(%v) expected to fail with %v, got %v instead", loc(1), name, errID, err) |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 215 | } |
| 216 | } |
| 217 | |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 218 | func updateDevice(t *testing.T, name string) { |
| 219 | if err := deviceStub(name).Update(globalRT.NewContext()); err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 220 | t.Fatalf("%s: Update(%v) failed: %v", loc(1), name, err) |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 221 | } |
| 222 | } |
| 223 | |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 224 | func revertDeviceExpectError(t *testing.T, name string, errID verror.ID) { |
| 225 | if err := deviceStub(name).Revert(globalRT.NewContext()); !verror2.Is(err, errID) { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 226 | t.Fatalf("%s: Revert(%v) expected to fail with %v, got %v instead", loc(1), name, errID, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 227 | } |
| 228 | } |
| 229 | |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 230 | func revertDevice(t *testing.T, name string) { |
| 231 | if err := deviceStub(name).Revert(globalRT.NewContext()); err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 232 | t.Fatalf("%s: Revert(%v) failed: %v", loc(1), name, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 233 | } |
| 234 | } |
| 235 | |
Bogdan Caprita | 4ea9b03 | 2014-12-27 14:56:51 -0800 | [diff] [blame^] | 236 | func stopDevice(t *testing.T, name string) { |
| 237 | if err := deviceStub(name).Stop(globalRT.NewContext(), stopTimeout); err != nil { |
| 238 | t.Fatalf("%s: Stop(%v) failed: %v", loc(1), name, err) |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | func suspendDevice(t *testing.T, name string) { |
| 243 | if err := deviceStub(name).Suspend(globalRT.NewContext()); err != nil { |
| 244 | t.Fatalf("%s: Suspend(%v) failed: %v", loc(1), name, err) |
| 245 | } |
| 246 | } |
| 247 | |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 248 | // The following set of functions are convenience wrappers around various app |
| 249 | // management methods. |
| 250 | |
Robert Kroeger | 362ff89 | 2014-09-29 14:23:47 -0700 | [diff] [blame] | 251 | func ort(opt []veyron2.Runtime) veyron2.Runtime { |
| 252 | if len(opt) > 0 { |
| 253 | return opt[0] |
| 254 | } else { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 255 | return globalRT |
Robert Kroeger | 362ff89 | 2014-09-29 14:23:47 -0700 | [diff] [blame] | 256 | } |
| 257 | } |
| 258 | |
Bogdan Caprita | a456f47 | 2014-12-10 10:18:03 -0800 | [diff] [blame] | 259 | func appStub(nameComponents ...string) device.ApplicationClientMethods { |
Bogdan Caprita | 9c4aa22 | 2014-12-10 14:46:30 -0800 | [diff] [blame] | 260 | appsName := "dm//apps" |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 261 | appName := naming.Join(append([]string{appsName}, nameComponents...)...) |
Bogdan Caprita | a456f47 | 2014-12-10 10:18:03 -0800 | [diff] [blame] | 262 | return device.ApplicationClient(appName) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 263 | } |
| 264 | |
Robert Kroeger | 362ff89 | 2014-09-29 14:23:47 -0700 | [diff] [blame] | 265 | func installApp(t *testing.T, opt ...veyron2.Runtime) string { |
Todd Wang | 702385a | 2014-11-07 01:54:08 -0800 | [diff] [blame] | 266 | appID, err := appStub().Install(ort(opt).NewContext(), mockApplicationRepoName) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 267 | if err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 268 | t.Fatalf("%s: Install failed: %v", loc(1), err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 269 | } |
| 270 | return appID |
| 271 | } |
| 272 | |
Bogdan Caprita | 2692910 | 2014-11-07 11:56:56 -0800 | [diff] [blame] | 273 | type granter struct { |
| 274 | ipc.CallOpt |
| 275 | p security.Principal |
| 276 | extension string |
| 277 | } |
| 278 | |
| 279 | func (g *granter) Grant(other security.Blessings) (security.Blessings, error) { |
| 280 | return g.p.Bless(other.PublicKey(), g.p.BlessingStore().Default(), g.extension, security.UnconstrainedUse()) |
| 281 | } |
| 282 | |
Bogdan Caprita | 730bde1 | 2014-11-08 15:35:43 -0800 | [diff] [blame] | 283 | func startAppImpl(t *testing.T, appID, grant string, opt ...veyron2.Runtime) (string, error) { |
| 284 | var opts []ipc.CallOpt |
| 285 | if grant != "" { |
| 286 | opts = append(opts, &granter{p: ort(opt).Principal(), extension: grant}) |
| 287 | } |
| 288 | if instanceIDs, err := appStub(appID).Start(ort(opt).NewContext(), opts...); err != nil { |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 289 | return "", err |
| 290 | } else { |
| 291 | if want, got := 1, len(instanceIDs); want != got { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 292 | t.Fatalf("%s: Start(%v): expected %v instance ids, got %v instead", loc(1), appID, want, got) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 293 | } |
| 294 | return instanceIDs[0], nil |
| 295 | } |
| 296 | } |
| 297 | |
Robert Kroeger | 362ff89 | 2014-09-29 14:23:47 -0700 | [diff] [blame] | 298 | func startApp(t *testing.T, appID string, opt ...veyron2.Runtime) string { |
Bogdan Caprita | 730bde1 | 2014-11-08 15:35:43 -0800 | [diff] [blame] | 299 | instanceID, err := startAppImpl(t, appID, "forapp", opt...) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 300 | if err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 301 | t.Fatalf("%s: Start(%v) failed: %v", loc(1), appID, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 302 | } |
| 303 | return instanceID |
| 304 | } |
| 305 | |
Robert Kroeger | 362ff89 | 2014-09-29 14:23:47 -0700 | [diff] [blame] | 306 | func startAppExpectError(t *testing.T, appID string, expectedError verror.ID, opt ...veyron2.Runtime) { |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 307 | if _, err := startAppImpl(t, appID, "forapp", opt...); err == nil || !verror2.Is(err, expectedError) { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 308 | t.Fatalf("%s: Start(%v) expected to fail with %v, got %v instead", loc(1), appID, expectedError, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 309 | } |
| 310 | } |
| 311 | |
Robert Kroeger | 362ff89 | 2014-09-29 14:23:47 -0700 | [diff] [blame] | 312 | func stopApp(t *testing.T, appID, instanceID string, opt ...veyron2.Runtime) { |
Bogdan Caprita | 4ea9b03 | 2014-12-27 14:56:51 -0800 | [diff] [blame^] | 313 | if err := appStub(appID, instanceID).Stop(ort(opt).NewContext(), stopTimeout); err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 314 | t.Fatalf("%s: Stop(%v/%v) failed: %v", loc(1), appID, instanceID, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 315 | } |
| 316 | } |
| 317 | |
Robert Kroeger | 362ff89 | 2014-09-29 14:23:47 -0700 | [diff] [blame] | 318 | func suspendApp(t *testing.T, appID, instanceID string, opt ...veyron2.Runtime) { |
Todd Wang | 702385a | 2014-11-07 01:54:08 -0800 | [diff] [blame] | 319 | if err := appStub(appID, instanceID).Suspend(ort(opt).NewContext()); err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 320 | t.Fatalf("%s: Suspend(%v/%v) failed: %v", loc(1), appID, instanceID, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 321 | } |
| 322 | } |
| 323 | |
Robert Kroeger | 362ff89 | 2014-09-29 14:23:47 -0700 | [diff] [blame] | 324 | func resumeApp(t *testing.T, appID, instanceID string, opt ...veyron2.Runtime) { |
Todd Wang | 702385a | 2014-11-07 01:54:08 -0800 | [diff] [blame] | 325 | if err := appStub(appID, instanceID).Resume(ort(opt).NewContext()); err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 326 | t.Fatalf("%s: Resume(%v/%v) failed: %v", loc(1), appID, instanceID, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 327 | } |
| 328 | } |
| 329 | |
Robert Kroeger | 1ce0bd7 | 2014-10-22 13:57:14 -0700 | [diff] [blame] | 330 | func resumeAppExpectError(t *testing.T, appID, instanceID string, expectedError verror.ID, opt ...veyron2.Runtime) { |
Todd Wang | 34ed4c6 | 2014-11-26 15:15:52 -0800 | [diff] [blame] | 331 | if err := appStub(appID, instanceID).Resume(ort(opt).NewContext()); err == nil || !verror2.Is(err, expectedError) { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 332 | t.Fatalf("%s: Resume(%v/%v) expected to fail with %v, got %v instead", loc(1), appID, instanceID, expectedError, err) |
Robert Kroeger | 1ce0bd7 | 2014-10-22 13:57:14 -0700 | [diff] [blame] | 333 | } |
| 334 | } |
| 335 | |
Robert Kroeger | 362ff89 | 2014-09-29 14:23:47 -0700 | [diff] [blame] | 336 | func updateApp(t *testing.T, appID string, opt ...veyron2.Runtime) { |
Todd Wang | 702385a | 2014-11-07 01:54:08 -0800 | [diff] [blame] | 337 | if err := appStub(appID).Update(ort(opt).NewContext()); err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 338 | t.Fatalf("%s: Update(%v) failed: %v", loc(1), appID, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 339 | } |
| 340 | } |
| 341 | |
| 342 | func updateAppExpectError(t *testing.T, appID string, expectedError verror.ID) { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 343 | if err := appStub(appID).Update(globalRT.NewContext()); err == nil || !verror2.Is(err, expectedError) { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 344 | t.Fatalf("%s: Update(%v) expected to fail with %v, got %v instead", loc(1), appID, expectedError, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 345 | } |
| 346 | } |
| 347 | |
| 348 | func revertApp(t *testing.T, appID string) { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 349 | if err := appStub(appID).Revert(globalRT.NewContext()); err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 350 | t.Fatalf("%s: Revert(%v) failed: %v", loc(1), appID, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 351 | } |
| 352 | } |
| 353 | |
| 354 | func revertAppExpectError(t *testing.T, appID string, expectedError verror.ID) { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 355 | if err := appStub(appID).Revert(globalRT.NewContext()); err == nil || !verror2.Is(err, expectedError) { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 356 | t.Fatalf("%s: Revert(%v) expected to fail with %v, got %v instead", loc(1), appID, expectedError, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 357 | } |
| 358 | } |
| 359 | |
| 360 | func uninstallApp(t *testing.T, appID string) { |
Matt Rosencrantz | 5180d16 | 2014-12-03 13:48:40 -0800 | [diff] [blame] | 361 | if err := appStub(appID).Uninstall(globalRT.NewContext()); err != nil { |
Cosmos Nicolaou | ad2793f | 2014-10-27 16:24:15 -0700 | [diff] [blame] | 362 | t.Fatalf("%s: Uninstall(%v) failed: %v", loc(1), appID, err) |
Bogdan Caprita | 48bbd14 | 2014-09-04 16:07:23 -0700 | [diff] [blame] | 363 | } |
Bogdan Caprita | c87a914 | 2014-07-21 10:38:13 -0700 | [diff] [blame] | 364 | } |
Robert Kroeger | 1cb4a0d | 2014-10-20 11:55:38 -0700 | [diff] [blame] | 365 | |
| 366 | // Code to make Association lists sortable. |
Bogdan Caprita | a456f47 | 2014-12-10 10:18:03 -0800 | [diff] [blame] | 367 | type byIdentity []device.Association |
Robert Kroeger | 1cb4a0d | 2014-10-20 11:55:38 -0700 | [diff] [blame] | 368 | |
| 369 | func (a byIdentity) Len() int { return len(a) } |
| 370 | func (a byIdentity) Swap(i, j int) { a[i], a[j] = a[j], a[i] } |
| 371 | func (a byIdentity) Less(i, j int) bool { return a[i].IdentityName < a[j].IdentityName } |
| 372 | |
Bogdan Caprita | a456f47 | 2014-12-10 10:18:03 -0800 | [diff] [blame] | 373 | func compareAssociations(t *testing.T, got, expected []device.Association) { |
Robert Kroeger | 1cb4a0d | 2014-10-20 11:55:38 -0700 | [diff] [blame] | 374 | sort.Sort(byIdentity(got)) |
| 375 | sort.Sort(byIdentity(expected)) |
| 376 | if !reflect.DeepEqual(got, expected) { |
| 377 | t.Fatalf("ListAssociations() got %v, expected %v", got, expected) |
| 378 | } |
| 379 | } |
Robert Kroeger | 94ec756 | 2014-10-28 17:58:44 -0700 | [diff] [blame] | 380 | |
| 381 | // generateSuidHelperScript builds a script to execute the test target as |
| 382 | // a suidhelper instance and returns the path to the script. |
| 383 | func generateSuidHelperScript(t *testing.T, root string) string { |
| 384 | output := "#!/bin/bash\n" |
| 385 | output += "VEYRON_SUIDHELPER_TEST=1" |
| 386 | output += " " |
Bogdan Caprita | 069341a | 2014-12-09 22:59:17 -0800 | [diff] [blame] | 387 | output += "exec " + os.Args[0] + " -minuid=1 -test.run=TestSuidHelper $*" |
Robert Kroeger | 94ec756 | 2014-10-28 17:58:44 -0700 | [diff] [blame] | 388 | output += "\n" |
| 389 | |
| 390 | vlog.VI(1).Infof("script\n%s", output) |
| 391 | |
| 392 | if err := os.MkdirAll(root, 0755); err != nil { |
| 393 | t.Fatalf("MkdirAll failed: %v", err) |
| 394 | } |
Bogdan Caprita | 2b21936 | 2014-12-09 17:03:33 -0800 | [diff] [blame] | 395 | // Helper does not need to live under the device manager's root dir, but |
Robert Kroeger | 94ec756 | 2014-10-28 17:58:44 -0700 | [diff] [blame] | 396 | // we put it there for convenience. |
| 397 | path := filepath.Join(root, "helper.sh") |
| 398 | if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil { |
| 399 | t.Fatalf("WriteFile(%v) failed: %v", path, err) |
| 400 | } |
| 401 | return path |
| 402 | } |