blob: 2f5e89c9f17936914ab40c99381be42cdb4cacc8 [file] [log] [blame]
Bogdan Capritac87a9142014-07-21 10:38:13 -07001package impl_test
2
3import (
4 "fmt"
Bogdan Capritad2b9f032014-10-10 17:43:29 -07005 "io/ioutil"
Bogdan Capritac87a9142014-07-21 10:38:13 -07006 "os"
Bogdan Capritad2b9f032014-10-10 17:43:29 -07007 "path/filepath"
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -07008 "reflect"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07009 "runtime"
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -070010 "sort"
Shyam Jayaramandbae76b2014-11-17 12:51:29 -080011 "strings"
Bogdan Capritac87a9142014-07-21 10:38:13 -070012 "testing"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070013 "time"
Bogdan Capritac87a9142014-07-21 10:38:13 -070014
Jiri Simsa764efb72014-12-25 20:57:03 -080015 "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 Nicolaoud6c3c9c2014-09-30 15:42:53 -070023
Jiri Simsa764efb72014-12-25 20:57:03 -080024 "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 Capritac87a9142014-07-21 10:38:13 -070032)
33
Bogdan Caprita916e99f2014-11-24 15:47:19 -080034const (
35 // Setting this environment variable to any non-empty value avoids
Bogdan Caprita2b219362014-12-09 17:03:33 -080036 // removing the device manager's workspace for successful test runs (for
Bogdan Caprita916e99f2014-11-24 15:47:19 -080037 // failed test runs, this is already the case). This is useful when
38 // developing test cases.
Bogdan Caprita9c4aa222014-12-10 14:46:30 -080039 preserveDMWorkspaceEnv = "VEYRON_TEST_PRESERVE_DM_WORKSPACE"
Bogdan Caprita916e99f2014-11-24 15:47:19 -080040
41 // TODO(caprita): Set the timeout in a more principled manner.
42 expectTimeout = 20 * time.Second
Bogdan Caprita4ea9b032014-12-27 14:56:51 -080043 stopTimeout = 20 // In seconds.
Bogdan Caprita916e99f2014-11-24 15:47:19 -080044)
Bogdan Capritad2b9f032014-10-10 17:43:29 -070045
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070046func loc(d int) string {
47 _, file, line, _ := runtime.Caller(d + 1)
48 return fmt.Sprintf("%s:%d", filepath.Base(file), line)
Bogdan Capritac87a9142014-07-21 10:38:13 -070049}
50
Bogdan Caprita916e99f2014-11-24 15:47:19 -080051func startRootMT(t *testing.T, sh *modules.Shell) (string, modules.Handle) {
Cosmos Nicolaou612ad382014-10-29 19:41:35 -070052 h, err := sh.Start(core.RootMTCommand, nil, "--", "--veyron.tcp.address=127.0.0.1:0")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070053 if err != nil {
54 t.Fatalf("failed to start root mount table: %s", err)
55 }
Bogdan Caprita916e99f2014-11-24 15:47:19 -080056 s := expect.NewSession(t, h.Stdout(), expectTimeout)
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -080057 s.ExpectVar("PID")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070058 rootName := s.ExpectVar("MT_NAME")
59 if t.Failed() {
60 t.Fatalf("failed to read mt name: %s", s.Error())
61 }
Bogdan Caprita916e99f2014-11-24 15:47:19 -080062 return rootName, h
Bogdan Capritab9501d12014-10-10 15:02:03 -070063}
64
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070065func credentialsForChild(blessing string) (string, []string) {
Ankur77cd9e82014-12-15 12:59:59 -080066 creds, _ := tsecurity.ForkCredentials(globalRT.Principal(), blessing)
Asim Shankar95910b62014-10-31 22:02:29 -070067 return creds, []string{consts.VeyronCredentials + "=" + creds}
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070068}
69
Matt Rosencrantzc13446b2014-12-03 10:37:00 -080070// setNSRoots sets the roots for the local runtime's namespace.
71func setNSRoots(t *testing.T, roots ...string) {
Matt Rosencrantz5180d162014-12-03 13:48:40 -080072 if err := globalRT.Namespace().SetRoots(roots...); err != nil {
Matt Rosencrantzc13446b2014-12-03 10:37:00 -080073 t.Fatalf("%s: SetRoots(%v) failed with %v", loc(2), roots, err)
Bogdan Caprita54cf3ef2014-11-21 10:38:52 -080074 }
75}
76
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070077func createShellAndMountTable(t *testing.T) (*modules.Shell, func()) {
Cosmos Nicolaou344cc4a2014-11-26 15:38:43 -080078 sh, err := modules.NewShell(nil)
79 if err != nil {
80 t.Fatalf("unexpected error: %s", err)
81 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070082 // The shell, will, by default share credentials with its children.
Asim Shankar95910b62014-10-31 22:02:29 -070083 sh.ClearVar(consts.VeyronCredentials)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070084
Bogdan Caprita916e99f2014-11-24 15:47:19 -080085 mtName, mtHandle := startRootMT(t, sh)
Bogdan Capritae577ef02014-11-28 17:33:18 -080086 vlog.VI(1).Infof("Started shell mounttable with name %v", mtName)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070087 // 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 Caprita54cf3ef2014-11-21 10:38:52 -080092 // TODO(caprita): Define a GetNamespaceRootsCommand in modules/core and
93 // use that?
Matt Rosencrantz5180d162014-12-03 13:48:40 -080094 oldNamespaceRoots := globalRT.Namespace().Roots()
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070095 fn := func() {
96 vlog.VI(1).Info("------------ CLEANUP ------------")
97 vlog.VI(1).Info("---------------------------------")
Bogdan Capritae577ef02014-11-28 17:33:18 -080098 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 Rosencrantzc13446b2014-12-03 10:37:00 -0800109 setNSRoots(t, oldNamespaceRoots...)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700110 }
Matt Rosencrantzc13446b2014-12-03 10:37:00 -0800111 setNSRoots(t, mtName)
Asim Shankar95910b62014-10-31 22:02:29 -0700112 sh.SetVar(consts.NamespaceRootPrefix, mtName)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700113 return sh, fn
114}
115
116func runShellCommand(t *testing.T, sh *modules.Shell, env []string, cmd string, args ...string) (modules.Handle, *expect.Session) {
Cosmos Nicolaou612ad382014-10-29 19:41:35 -0700117 h, err := sh.Start(cmd, env, args...)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700118 if err != nil {
119 t.Fatalf("%s: failed to start %q: %s", loc(1), cmd, err)
120 return nil, nil
121 }
Bogdan Caprita916e99f2014-11-24 15:47:19 -0800122 s := expect.NewSession(t, h.Stdout(), expectTimeout)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700123 s.SetVerbosity(testing.Verbose())
124 return h, s
125}
126
127func 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 Capritac87a9142014-07-21 10:38:13 -0700136 }
137}
138
Bogdan Caprita2b219362014-12-09 17:03:33 -0800139// 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 Capritad2b9f032014-10-10 17:43:29 -0700141func setupRootDir(t *testing.T) (string, func()) {
Bogdan Caprita2b219362014-12-09 17:03:33 -0800142 rootDir, err := ioutil.TempDir("", "devicemanager")
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700143 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 Caprita9c4aa222014-12-10 14:46:30 -0800154 if t.Failed() || os.Getenv(preserveDMWorkspaceEnv) != "" {
Bogdan Caprita2b219362014-12-09 17:03:33 -0800155 t.Logf("You can examine the device manager workspace at %v", rootDir)
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700156 } else {
157 os.RemoveAll(rootDir)
158 }
159 }
160}
161
Bogdan Capritac87a9142014-07-21 10:38:13 -0700162func newServer() (ipc.Server, string) {
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800163 server, err := globalRT.NewServer()
Bogdan Capritac87a9142014-07-21 10:38:13 -0700164 if err != nil {
165 vlog.Fatalf("NewServer() failed: %v", err)
166 }
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800167 spec := ipc.ListenSpec{Addrs: ipc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800168 endpoints, err := server.Listen(spec)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700169 if err != nil {
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800170 vlog.Fatalf("Listen(%s) failed: %v", spec, err)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700171 }
Cosmos Nicolaou28dabfc2014-12-15 22:51:07 -0800172 return server, endpoints[0].String()
Bogdan Capritac87a9142014-07-21 10:38:13 -0700173}
174
Bogdan Caprita474ad112014-12-03 19:24:12 -0800175// resolveExpectNotFound verifies that the given name is not in the mounttable.
Bogdan Capritabce0a632014-09-03 16:15:26 -0700176func resolveExpectNotFound(t *testing.T, name string) {
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800177 if results, err := globalRT.Namespace().Resolve(globalRT.NewContext(), name); err == nil {
Bogdan Caprita474ad112014-12-03 19:24:12 -0800178 t.Fatalf("%s: Resolve(%v) succeeded with results %v when it was expected to fail", loc(1), name, results)
Todd Wang34ed4c62014-11-26 15:15:52 -0800179 } else if expectErr := naming.ErrNoSuchName.ID; !verror2.Is(err, expectErr) {
Bogdan Caprita474ad112014-12-03 19:24:12 -0800180 t.Fatalf("%s: Resolve(%v) failed with error %v, expected error ID %v", loc(1), name, err, expectErr)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700181 }
182}
183
184// resolve looks up the given name in the mounttable.
Bogdan Capritabce0a632014-09-03 16:15:26 -0700185func resolve(t *testing.T, name string, replicas int) []string {
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800186 results, err := globalRT.Namespace().Resolve(globalRT.NewContext(), name)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700187 if err != nil {
188 t.Fatalf("Resolve(%v) failed: %v", name, err)
189 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800190
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 Capritac87a9142014-07-21 10:38:13 -0700199 t.Fatalf("Resolve(%v) expected %d result(s), got %d instead", name, want, got)
200 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800201 return filteredResults
Bogdan Capritac87a9142014-07-21 10:38:13 -0700202}
203
204// The following set of functions are convenience wrappers around Update and
Bogdan Caprita2b219362014-12-09 17:03:33 -0800205// Revert for device manager.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700206
Bogdan Capritaa456f472014-12-10 10:18:03 -0800207func deviceStub(name string) device.DeviceClientMethods {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800208 deviceName := naming.Join(name, "device")
Bogdan Capritaa456f472014-12-10 10:18:03 -0800209 return device.DeviceClient(deviceName)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700210}
211
Bogdan Caprita2b219362014-12-09 17:03:33 -0800212func updateDeviceExpectError(t *testing.T, name string, errID verror.ID) {
213 if err := deviceStub(name).Update(globalRT.NewContext()); !verror2.Is(err, errID) {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700214 t.Fatalf("%s: Update(%v) expected to fail with %v, got %v instead", loc(1), name, errID, err)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700215 }
216}
217
Bogdan Caprita2b219362014-12-09 17:03:33 -0800218func updateDevice(t *testing.T, name string) {
219 if err := deviceStub(name).Update(globalRT.NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700220 t.Fatalf("%s: Update(%v) failed: %v", loc(1), name, err)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700221 }
222}
223
Bogdan Caprita2b219362014-12-09 17:03:33 -0800224func revertDeviceExpectError(t *testing.T, name string, errID verror.ID) {
225 if err := deviceStub(name).Revert(globalRT.NewContext()); !verror2.Is(err, errID) {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700226 t.Fatalf("%s: Revert(%v) expected to fail with %v, got %v instead", loc(1), name, errID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700227 }
228}
229
Bogdan Caprita2b219362014-12-09 17:03:33 -0800230func revertDevice(t *testing.T, name string) {
231 if err := deviceStub(name).Revert(globalRT.NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700232 t.Fatalf("%s: Revert(%v) failed: %v", loc(1), name, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700233 }
234}
235
Bogdan Caprita4ea9b032014-12-27 14:56:51 -0800236func 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
242func 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 Caprita48bbd142014-09-04 16:07:23 -0700248// The following set of functions are convenience wrappers around various app
249// management methods.
250
Robert Kroeger362ff892014-09-29 14:23:47 -0700251func ort(opt []veyron2.Runtime) veyron2.Runtime {
252 if len(opt) > 0 {
253 return opt[0]
254 } else {
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800255 return globalRT
Robert Kroeger362ff892014-09-29 14:23:47 -0700256 }
257}
258
Bogdan Capritaa456f472014-12-10 10:18:03 -0800259func appStub(nameComponents ...string) device.ApplicationClientMethods {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800260 appsName := "dm//apps"
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700261 appName := naming.Join(append([]string{appsName}, nameComponents...)...)
Bogdan Capritaa456f472014-12-10 10:18:03 -0800262 return device.ApplicationClient(appName)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700263}
264
Robert Kroeger362ff892014-09-29 14:23:47 -0700265func installApp(t *testing.T, opt ...veyron2.Runtime) string {
Todd Wang702385a2014-11-07 01:54:08 -0800266 appID, err := appStub().Install(ort(opt).NewContext(), mockApplicationRepoName)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700267 if err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700268 t.Fatalf("%s: Install failed: %v", loc(1), err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700269 }
270 return appID
271}
272
Bogdan Caprita26929102014-11-07 11:56:56 -0800273type granter struct {
274 ipc.CallOpt
275 p security.Principal
276 extension string
277}
278
279func (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 Caprita730bde12014-11-08 15:35:43 -0800283func 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 Caprita48bbd142014-09-04 16:07:23 -0700289 return "", err
290 } else {
291 if want, got := 1, len(instanceIDs); want != got {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700292 t.Fatalf("%s: Start(%v): expected %v instance ids, got %v instead", loc(1), appID, want, got)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700293 }
294 return instanceIDs[0], nil
295 }
296}
297
Robert Kroeger362ff892014-09-29 14:23:47 -0700298func startApp(t *testing.T, appID string, opt ...veyron2.Runtime) string {
Bogdan Caprita730bde12014-11-08 15:35:43 -0800299 instanceID, err := startAppImpl(t, appID, "forapp", opt...)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700300 if err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700301 t.Fatalf("%s: Start(%v) failed: %v", loc(1), appID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700302 }
303 return instanceID
304}
305
Robert Kroeger362ff892014-09-29 14:23:47 -0700306func startAppExpectError(t *testing.T, appID string, expectedError verror.ID, opt ...veyron2.Runtime) {
Todd Wang34ed4c62014-11-26 15:15:52 -0800307 if _, err := startAppImpl(t, appID, "forapp", opt...); err == nil || !verror2.Is(err, expectedError) {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700308 t.Fatalf("%s: Start(%v) expected to fail with %v, got %v instead", loc(1), appID, expectedError, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700309 }
310}
311
Robert Kroeger362ff892014-09-29 14:23:47 -0700312func stopApp(t *testing.T, appID, instanceID string, opt ...veyron2.Runtime) {
Bogdan Caprita4ea9b032014-12-27 14:56:51 -0800313 if err := appStub(appID, instanceID).Stop(ort(opt).NewContext(), stopTimeout); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700314 t.Fatalf("%s: Stop(%v/%v) failed: %v", loc(1), appID, instanceID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700315 }
316}
317
Robert Kroeger362ff892014-09-29 14:23:47 -0700318func suspendApp(t *testing.T, appID, instanceID string, opt ...veyron2.Runtime) {
Todd Wang702385a2014-11-07 01:54:08 -0800319 if err := appStub(appID, instanceID).Suspend(ort(opt).NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700320 t.Fatalf("%s: Suspend(%v/%v) failed: %v", loc(1), appID, instanceID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700321 }
322}
323
Robert Kroeger362ff892014-09-29 14:23:47 -0700324func resumeApp(t *testing.T, appID, instanceID string, opt ...veyron2.Runtime) {
Todd Wang702385a2014-11-07 01:54:08 -0800325 if err := appStub(appID, instanceID).Resume(ort(opt).NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700326 t.Fatalf("%s: Resume(%v/%v) failed: %v", loc(1), appID, instanceID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700327 }
328}
329
Robert Kroeger1ce0bd72014-10-22 13:57:14 -0700330func resumeAppExpectError(t *testing.T, appID, instanceID string, expectedError verror.ID, opt ...veyron2.Runtime) {
Todd Wang34ed4c62014-11-26 15:15:52 -0800331 if err := appStub(appID, instanceID).Resume(ort(opt).NewContext()); err == nil || !verror2.Is(err, expectedError) {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700332 t.Fatalf("%s: Resume(%v/%v) expected to fail with %v, got %v instead", loc(1), appID, instanceID, expectedError, err)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -0700333 }
334}
335
Robert Kroeger362ff892014-09-29 14:23:47 -0700336func updateApp(t *testing.T, appID string, opt ...veyron2.Runtime) {
Todd Wang702385a2014-11-07 01:54:08 -0800337 if err := appStub(appID).Update(ort(opt).NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700338 t.Fatalf("%s: Update(%v) failed: %v", loc(1), appID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700339 }
340}
341
342func updateAppExpectError(t *testing.T, appID string, expectedError verror.ID) {
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800343 if err := appStub(appID).Update(globalRT.NewContext()); err == nil || !verror2.Is(err, expectedError) {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700344 t.Fatalf("%s: Update(%v) expected to fail with %v, got %v instead", loc(1), appID, expectedError, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700345 }
346}
347
348func revertApp(t *testing.T, appID string) {
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800349 if err := appStub(appID).Revert(globalRT.NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700350 t.Fatalf("%s: Revert(%v) failed: %v", loc(1), appID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700351 }
352}
353
354func revertAppExpectError(t *testing.T, appID string, expectedError verror.ID) {
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800355 if err := appStub(appID).Revert(globalRT.NewContext()); err == nil || !verror2.Is(err, expectedError) {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700356 t.Fatalf("%s: Revert(%v) expected to fail with %v, got %v instead", loc(1), appID, expectedError, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700357 }
358}
359
360func uninstallApp(t *testing.T, appID string) {
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800361 if err := appStub(appID).Uninstall(globalRT.NewContext()); err != nil {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700362 t.Fatalf("%s: Uninstall(%v) failed: %v", loc(1), appID, err)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700363 }
Bogdan Capritac87a9142014-07-21 10:38:13 -0700364}
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700365
366// Code to make Association lists sortable.
Bogdan Capritaa456f472014-12-10 10:18:03 -0800367type byIdentity []device.Association
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700368
369func (a byIdentity) Len() int { return len(a) }
370func (a byIdentity) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
371func (a byIdentity) Less(i, j int) bool { return a[i].IdentityName < a[j].IdentityName }
372
Bogdan Capritaa456f472014-12-10 10:18:03 -0800373func compareAssociations(t *testing.T, got, expected []device.Association) {
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700374 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 Kroeger94ec7562014-10-28 17:58:44 -0700380
381// generateSuidHelperScript builds a script to execute the test target as
382// a suidhelper instance and returns the path to the script.
383func generateSuidHelperScript(t *testing.T, root string) string {
384 output := "#!/bin/bash\n"
385 output += "VEYRON_SUIDHELPER_TEST=1"
386 output += " "
Bogdan Caprita069341a2014-12-09 22:59:17 -0800387 output += "exec " + os.Args[0] + " -minuid=1 -test.run=TestSuidHelper $*"
Robert Kroeger94ec7562014-10-28 17:58:44 -0700388 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 Caprita2b219362014-12-09 17:03:33 -0800395 // Helper does not need to live under the device manager's root dir, but
Robert Kroeger94ec7562014-10-28 17:58:44 -0700396 // 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}