blob: 9647474144439c3f94de3cb65c00f769af6f396e [file] [log] [blame]
Bogdan Capritac87a9142014-07-21 10:38:13 -07001package impl_test
2
3import (
Bogdan Capritad2b9f032014-10-10 17:43:29 -07004 "io/ioutil"
Bogdan Capritac87a9142014-07-21 10:38:13 -07005 "os"
Bogdan Capritad2b9f032014-10-10 17:43:29 -07006 "path/filepath"
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -07007 "reflect"
8 "sort"
Shyam Jayaramandbae76b2014-11-17 12:51:29 -08009 "strings"
Bogdan Capritac87a9142014-07-21 10:38:13 -070010 "testing"
11
Jiri Simsa764efb72014-12-25 20:57:03 -080012 "v.io/core/veyron2"
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -080013 "v.io/core/veyron2/context"
Jiri Simsa764efb72014-12-25 20:57:03 -080014 "v.io/core/veyron2/ipc"
15 "v.io/core/veyron2/naming"
16 "v.io/core/veyron2/security"
Robert Kroegerebfb62a2014-12-10 14:42:09 -080017 "v.io/core/veyron2/services/mgmt/application"
Jiri Simsa764efb72014-12-25 20:57:03 -080018 "v.io/core/veyron2/services/mgmt/device"
Todd Wang15776512015-02-10 16:52:55 -080019 verror "v.io/core/veyron2/verror2"
Jiri Simsa764efb72014-12-25 20:57:03 -080020 "v.io/core/veyron2/vlog"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070021
Jiri Simsa764efb72014-12-25 20:57:03 -080022 "v.io/core/veyron/lib/modules"
Bogdan Capritac7e72b62015-01-07 19:22:23 -080023 "v.io/core/veyron/lib/testutil"
Jiri Simsa764efb72014-12-25 20:57:03 -080024 _ "v.io/core/veyron/profiles/static"
25 "v.io/core/veyron/services/mgmt/device/impl"
Bogdan Capritac87a9142014-07-21 10:38:13 -070026)
27
Bogdan Caprita916e99f2014-11-24 15:47:19 -080028const (
Bogdan Caprita916e99f2014-11-24 15:47:19 -080029 // TODO(caprita): Set the timeout in a more principled manner.
Robert Kroegerebfb62a2014-12-10 14:42:09 -080030 stopTimeout = 20 // In seconds.
Bogdan Caprita916e99f2014-11-24 15:47:19 -080031)
Bogdan Capritad2b9f032014-10-10 17:43:29 -070032
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070033func envelopeFromShell(sh *modules.Shell, env []string, cmd, title string, args ...string) application.Envelope {
34 args, nenv := sh.CommandEnvelope(cmd, env, args...)
35 return application.Envelope{
36 Title: title,
37 Args: args[1:],
38 // TODO(caprita): revisit how the environment is sanitized for arbirary
39 // apps.
40 Env: impl.VeyronEnvironment(nenv),
41 Binary: mockBinaryRepoName,
Bogdan Capritac87a9142014-07-21 10:38:13 -070042 }
43}
44
Bogdan Caprita474ad112014-12-03 19:24:12 -080045// resolveExpectNotFound verifies that the given name is not in the mounttable.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080046func resolveExpectNotFound(t *testing.T, ctx *context.T, name string) {
47 if me, err := veyron2.GetNamespace(ctx).Resolve(ctx, name); err == nil {
48 t.Fatalf(testutil.FormatLogLine(2, "Resolve(%v) succeeded with results %v when it was expected to fail", name, me.Names))
Todd Wang15776512015-02-10 16:52:55 -080049 } else if expectErr := naming.ErrNoSuchName.ID; !verror.Is(err, expectErr) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -080050 t.Fatalf(testutil.FormatLogLine(2, "Resolve(%v) failed with error %v, expected error ID %v", name, err, expectErr))
Bogdan Capritac87a9142014-07-21 10:38:13 -070051 }
52}
53
54// resolve looks up the given name in the mounttable.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080055func resolve(t *testing.T, ctx *context.T, name string, replicas int) []string {
56 me, err := veyron2.GetNamespace(ctx).Resolve(ctx, name)
Bogdan Capritac87a9142014-07-21 10:38:13 -070057 if err != nil {
58 t.Fatalf("Resolve(%v) failed: %v", name, err)
59 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -080060
61 filteredResults := []string{}
David Why Use Two When One Will Do Presotto8de85852015-01-21 11:05:09 -080062 for _, r := range me.Names() {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -080063 if strings.Index(r, "@tcp") != -1 {
64 filteredResults = append(filteredResults, r)
65 }
66 }
67 // We are going to get a websocket and a tcp endpoint for each replica.
68 if want, got := replicas, len(filteredResults); want != got {
Bogdan Capritac87a9142014-07-21 10:38:13 -070069 t.Fatalf("Resolve(%v) expected %d result(s), got %d instead", name, want, got)
70 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -080071 return filteredResults
Bogdan Capritac87a9142014-07-21 10:38:13 -070072}
73
74// The following set of functions are convenience wrappers around Update and
Bogdan Caprita2b219362014-12-09 17:03:33 -080075// Revert for device manager.
Bogdan Capritac87a9142014-07-21 10:38:13 -070076
Bogdan Capritaa456f472014-12-10 10:18:03 -080077func deviceStub(name string) device.DeviceClientMethods {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -080078 deviceName := naming.Join(name, "device")
Bogdan Capritaa456f472014-12-10 10:18:03 -080079 return device.DeviceClient(deviceName)
Bogdan Capritac87a9142014-07-21 10:38:13 -070080}
81
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080082func updateDeviceExpectError(t *testing.T, ctx *context.T, name string, errID verror.ID) {
Todd Wang15776512015-02-10 16:52:55 -080083 if err := deviceStub(name).Update(ctx); !verror.Is(err, errID) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -080084 t.Fatalf(testutil.FormatLogLine(2, "Update(%v) expected to fail with %v, got %v instead", name, errID, err))
Bogdan Capritac87a9142014-07-21 10:38:13 -070085 }
86}
87
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080088func updateDevice(t *testing.T, ctx *context.T, name string) {
89 if err := deviceStub(name).Update(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -080090 t.Fatalf(testutil.FormatLogLine(2, "Update(%v) failed: %v", name, err))
Bogdan Capritac87a9142014-07-21 10:38:13 -070091 }
92}
93
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080094func revertDeviceExpectError(t *testing.T, ctx *context.T, name string, errID verror.ID) {
Todd Wang15776512015-02-10 16:52:55 -080095 if err := deviceStub(name).Revert(ctx); !verror.Is(err, errID) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -080096 t.Fatalf(testutil.FormatLogLine(2, "Revert(%v) expected to fail with %v, got %v instead", name, errID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -070097 }
98}
99
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800100func revertDevice(t *testing.T, ctx *context.T, name string) {
101 if err := deviceStub(name).Revert(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800102 t.Fatalf(testutil.FormatLogLine(2, "Revert(%v) failed: %v", name, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700103 }
104}
105
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800106func stopDevice(t *testing.T, ctx *context.T, name string) {
107 if err := deviceStub(name).Stop(ctx, stopTimeout); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800108 t.Fatalf(testutil.FormatLogLine(1+1, "%s: Stop(%v) failed: %v", name, err))
Bogdan Caprita4ea9b032014-12-27 14:56:51 -0800109 }
110}
111
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800112func suspendDevice(t *testing.T, ctx *context.T, name string) {
113 if err := deviceStub(name).Suspend(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800114 t.Fatalf(testutil.FormatLogLine(1+1, "%s: Suspend(%v) failed: %v", name, err))
Bogdan Caprita4ea9b032014-12-27 14:56:51 -0800115 }
116}
117
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700118// The following set of functions are convenience wrappers around various app
119// management methods.
120
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800121func ocfg(opt []interface{}) device.Config {
122 for _, o := range opt {
123 if c, ok := o.(device.Config); ok {
124 return c
125 }
126 }
127 return device.Config{}
128}
129
Bogdan Capritaa456f472014-12-10 10:18:03 -0800130func appStub(nameComponents ...string) device.ApplicationClientMethods {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800131 appsName := "dm//apps"
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700132 appName := naming.Join(append([]string{appsName}, nameComponents...)...)
Bogdan Capritaa456f472014-12-10 10:18:03 -0800133 return device.ApplicationClient(appName)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700134}
135
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800136func installApp(t *testing.T, ctx *context.T, opt ...interface{}) string {
137 appID, err := appStub().Install(ctx, mockApplicationRepoName, ocfg(opt))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700138 if err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800139 t.Fatalf(testutil.FormatLogLine(2, "Install failed: %v", err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700140 }
141 return appID
142}
143
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800144func installAppExpectError(t *testing.T, ctx *context.T, expectedError verror.ID, opt ...interface{}) {
Todd Wang15776512015-02-10 16:52:55 -0800145 if _, err := appStub().Install(ctx, mockApplicationRepoName, ocfg(opt)); err == nil || !verror.Is(err, expectedError) {
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800146 t.Fatalf(testutil.FormatLogLine(2, "Install expected to fail with %v, got %v instead", expectedError, err))
147 }
148}
149
Bogdan Caprita26929102014-11-07 11:56:56 -0800150type granter struct {
151 ipc.CallOpt
152 p security.Principal
153 extension string
154}
155
156func (g *granter) Grant(other security.Blessings) (security.Blessings, error) {
157 return g.p.Bless(other.PublicKey(), g.p.BlessingStore().Default(), g.extension, security.UnconstrainedUse())
158}
159
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800160func startAppImpl(t *testing.T, ctx *context.T, appID, grant string) (string, error) {
Bogdan Caprita730bde12014-11-08 15:35:43 -0800161 var opts []ipc.CallOpt
162 if grant != "" {
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800163 opts = append(opts, &granter{p: veyron2.GetPrincipal(ctx), extension: grant})
Bogdan Caprita730bde12014-11-08 15:35:43 -0800164 }
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800165 if instanceIDs, err := appStub(appID).Start(ctx, opts...); err != nil {
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700166 return "", err
167 } else {
168 if want, got := 1, len(instanceIDs); want != got {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800169 t.Fatalf(testutil.FormatLogLine(2, "Start(%v): expected %v instance ids, got %v instead", appID, want, got))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700170 }
171 return instanceIDs[0], nil
172 }
173}
174
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800175func startApp(t *testing.T, ctx *context.T, appID string) string {
176 instanceID, err := startAppImpl(t, ctx, appID, "forapp")
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700177 if err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800178 t.Fatalf(testutil.FormatLogLine(2, "Start(%v) failed: %v", appID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700179 }
180 return instanceID
181}
182
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800183func startAppExpectError(t *testing.T, ctx *context.T, appID string, expectedError verror.ID) {
Todd Wang15776512015-02-10 16:52:55 -0800184 if _, err := startAppImpl(t, ctx, appID, "forapp"); err == nil || !verror.Is(err, expectedError) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800185 t.Fatalf(testutil.FormatLogLine(2, "Start(%v) expected to fail with %v, got %v instead", appID, expectedError, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700186 }
187}
188
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800189func stopApp(t *testing.T, ctx *context.T, appID, instanceID string) {
190 if err := appStub(appID, instanceID).Stop(ctx, stopTimeout); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800191 t.Fatalf(testutil.FormatLogLine(2, "Stop(%v/%v) failed: %v", appID, instanceID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700192 }
193}
194
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800195func suspendApp(t *testing.T, ctx *context.T, appID, instanceID string) {
196 if err := appStub(appID, instanceID).Suspend(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800197 t.Fatalf(testutil.FormatLogLine(2, "Suspend(%v/%v) failed: %v", appID, instanceID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700198 }
199}
200
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800201func resumeApp(t *testing.T, ctx *context.T, appID, instanceID string) {
202 if err := appStub(appID, instanceID).Resume(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800203 t.Fatalf(testutil.FormatLogLine(2, "Resume(%v/%v) failed: %v", appID, instanceID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700204 }
205}
206
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800207func resumeAppExpectError(t *testing.T, ctx *context.T, appID, instanceID string, expectedError verror.ID) {
Todd Wang15776512015-02-10 16:52:55 -0800208 if err := appStub(appID, instanceID).Resume(ctx); err == nil || !verror.Is(err, expectedError) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800209 t.Fatalf(testutil.FormatLogLine(2, "Resume(%v/%v) expected to fail with %v, got %v instead", appID, instanceID, expectedError, err))
Robert Kroeger1ce0bd72014-10-22 13:57:14 -0700210 }
211}
212
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800213func updateApp(t *testing.T, ctx *context.T, appID string) {
214 if err := appStub(appID).Update(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800215 t.Fatalf(testutil.FormatLogLine(2, "Update(%v) failed: %v", appID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700216 }
217}
218
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800219func updateAppExpectError(t *testing.T, ctx *context.T, appID string, expectedError verror.ID) {
Todd Wang15776512015-02-10 16:52:55 -0800220 if err := appStub(appID).Update(ctx); err == nil || !verror.Is(err, expectedError) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800221 t.Fatalf(testutil.FormatLogLine(2, "Update(%v) expected to fail with %v, got %v instead", appID, expectedError, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700222 }
223}
224
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800225func revertApp(t *testing.T, ctx *context.T, appID string) {
226 if err := appStub(appID).Revert(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800227 t.Fatalf(testutil.FormatLogLine(2, "Revert(%v) failed: %v", appID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700228 }
229}
230
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800231func revertAppExpectError(t *testing.T, ctx *context.T, appID string, expectedError verror.ID) {
Todd Wang15776512015-02-10 16:52:55 -0800232 if err := appStub(appID).Revert(ctx); err == nil || !verror.Is(err, expectedError) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800233 t.Fatalf(testutil.FormatLogLine(2, "Revert(%v) expected to fail with %v, got %v instead", appID, expectedError, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700234 }
235}
236
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800237func uninstallApp(t *testing.T, ctx *context.T, appID string) {
238 if err := appStub(appID).Uninstall(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800239 t.Fatalf(testutil.FormatLogLine(2, "Uninstall(%v) failed: %v", appID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700240 }
Bogdan Capritac87a9142014-07-21 10:38:13 -0700241}
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700242
Bogdan Capritad8373a12015-01-28 19:52:37 -0800243func debug(t *testing.T, ctx *context.T, nameComponents ...string) string {
244 dbg, err := appStub(nameComponents...).Debug(ctx)
245 if err != nil {
246 t.Fatalf(testutil.FormatLogLine(2, "Debug(%v) failed: %v", nameComponents, err))
247 }
248 return dbg
249}
250
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700251// Code to make Association lists sortable.
Bogdan Capritaa456f472014-12-10 10:18:03 -0800252type byIdentity []device.Association
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700253
254func (a byIdentity) Len() int { return len(a) }
255func (a byIdentity) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
256func (a byIdentity) Less(i, j int) bool { return a[i].IdentityName < a[j].IdentityName }
257
Bogdan Capritaa456f472014-12-10 10:18:03 -0800258func compareAssociations(t *testing.T, got, expected []device.Association) {
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700259 sort.Sort(byIdentity(got))
260 sort.Sort(byIdentity(expected))
261 if !reflect.DeepEqual(got, expected) {
262 t.Fatalf("ListAssociations() got %v, expected %v", got, expected)
263 }
264}
Robert Kroeger94ec7562014-10-28 17:58:44 -0700265
266// generateSuidHelperScript builds a script to execute the test target as
267// a suidhelper instance and returns the path to the script.
268func generateSuidHelperScript(t *testing.T, root string) string {
269 output := "#!/bin/bash\n"
270 output += "VEYRON_SUIDHELPER_TEST=1"
271 output += " "
Bogdan Caprita069341a2014-12-09 22:59:17 -0800272 output += "exec " + os.Args[0] + " -minuid=1 -test.run=TestSuidHelper $*"
Robert Kroeger94ec7562014-10-28 17:58:44 -0700273 output += "\n"
274
275 vlog.VI(1).Infof("script\n%s", output)
276
277 if err := os.MkdirAll(root, 0755); err != nil {
278 t.Fatalf("MkdirAll failed: %v", err)
279 }
Robert Kroeger94ec7562014-10-28 17:58:44 -0700280 path := filepath.Join(root, "helper.sh")
281 if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
282 t.Fatalf("WriteFile(%v) failed: %v", path, err)
283 }
284 return path
285}
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800286
287// generateAgentScript creates a simple script that acts as the security agent
288// for tests. It blackholes arguments meant for the agent.
289func generateAgentScript(t *testing.T, root string) string {
290 output := `
291#!/bin/bash
292ARGS=$*
293for ARG in ${ARGS[@]}; do
294 if [[ ${ARG} = -- ]]; then
295 ARGS=(${ARGS[@]/$ARG})
296 break
297 elif [[ ${ARG} == --* ]]; then
298 ARGS=(${ARGS[@]/$ARG})
299 else
300 break
301 fi
302done
303
304exec ${ARGS[@]}
305`
306 if err := os.MkdirAll(root, 0755); err != nil {
307 t.Fatalf("MkdirAll failed: %v", err)
308 }
309 path := filepath.Join(root, "agenthelper.sh")
310 if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
311 t.Fatalf("WriteFile(%v) failed: %v", path, err)
312 }
313 return path
314}