blob: 0ac22f6eec667104d5f7b1490a5d2ec3e1a624f8 [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"
19 "v.io/core/veyron2/verror"
20 "v.io/core/veyron2/verror2"
21 "v.io/core/veyron2/vlog"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070022
Jiri Simsa764efb72014-12-25 20:57:03 -080023 "v.io/core/veyron/lib/modules"
Bogdan Capritac7e72b62015-01-07 19:22:23 -080024 "v.io/core/veyron/lib/testutil"
Jiri Simsa764efb72014-12-25 20:57:03 -080025 _ "v.io/core/veyron/profiles/static"
26 "v.io/core/veyron/services/mgmt/device/impl"
Bogdan Capritac87a9142014-07-21 10:38:13 -070027)
28
Bogdan Caprita916e99f2014-11-24 15:47:19 -080029const (
Bogdan Caprita916e99f2014-11-24 15:47:19 -080030 // TODO(caprita): Set the timeout in a more principled manner.
Robert Kroegerebfb62a2014-12-10 14:42:09 -080031 stopTimeout = 20 // In seconds.
Bogdan Caprita916e99f2014-11-24 15:47:19 -080032)
Bogdan Capritad2b9f032014-10-10 17:43:29 -070033
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070034func envelopeFromShell(sh *modules.Shell, env []string, cmd, title string, args ...string) application.Envelope {
35 args, nenv := sh.CommandEnvelope(cmd, env, args...)
36 return application.Envelope{
37 Title: title,
38 Args: args[1:],
39 // TODO(caprita): revisit how the environment is sanitized for arbirary
40 // apps.
41 Env: impl.VeyronEnvironment(nenv),
42 Binary: mockBinaryRepoName,
Bogdan Capritac87a9142014-07-21 10:38:13 -070043 }
44}
45
Bogdan Caprita474ad112014-12-03 19:24:12 -080046// resolveExpectNotFound verifies that the given name is not in the mounttable.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080047func resolveExpectNotFound(t *testing.T, ctx *context.T, name string) {
48 if me, err := veyron2.GetNamespace(ctx).Resolve(ctx, name); err == nil {
49 t.Fatalf(testutil.FormatLogLine(2, "Resolve(%v) succeeded with results %v when it was expected to fail", name, me.Names))
Todd Wang34ed4c62014-11-26 15:15:52 -080050 } else if expectErr := naming.ErrNoSuchName.ID; !verror2.Is(err, expectErr) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -080051 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 -070052 }
53}
54
55// resolve looks up the given name in the mounttable.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080056func resolve(t *testing.T, ctx *context.T, name string, replicas int) []string {
57 me, err := veyron2.GetNamespace(ctx).Resolve(ctx, name)
Bogdan Capritac87a9142014-07-21 10:38:13 -070058 if err != nil {
59 t.Fatalf("Resolve(%v) failed: %v", name, err)
60 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -080061
62 filteredResults := []string{}
David Why Use Two When One Will Do Presotto8de85852015-01-21 11:05:09 -080063 for _, r := range me.Names() {
Shyam Jayaramandbae76b2014-11-17 12:51:29 -080064 if strings.Index(r, "@tcp") != -1 {
65 filteredResults = append(filteredResults, r)
66 }
67 }
68 // We are going to get a websocket and a tcp endpoint for each replica.
69 if want, got := replicas, len(filteredResults); want != got {
Bogdan Capritac87a9142014-07-21 10:38:13 -070070 t.Fatalf("Resolve(%v) expected %d result(s), got %d instead", name, want, got)
71 }
Shyam Jayaramandbae76b2014-11-17 12:51:29 -080072 return filteredResults
Bogdan Capritac87a9142014-07-21 10:38:13 -070073}
74
75// The following set of functions are convenience wrappers around Update and
Bogdan Caprita2b219362014-12-09 17:03:33 -080076// Revert for device manager.
Bogdan Capritac87a9142014-07-21 10:38:13 -070077
Bogdan Capritaa456f472014-12-10 10:18:03 -080078func deviceStub(name string) device.DeviceClientMethods {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -080079 deviceName := naming.Join(name, "device")
Bogdan Capritaa456f472014-12-10 10:18:03 -080080 return device.DeviceClient(deviceName)
Bogdan Capritac87a9142014-07-21 10:38:13 -070081}
82
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080083func updateDeviceExpectError(t *testing.T, ctx *context.T, name string, errID verror.ID) {
84 if err := deviceStub(name).Update(ctx); !verror2.Is(err, errID) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -080085 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 -070086 }
87}
88
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080089func updateDevice(t *testing.T, ctx *context.T, name string) {
90 if err := deviceStub(name).Update(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -080091 t.Fatalf(testutil.FormatLogLine(2, "Update(%v) failed: %v", name, err))
Bogdan Capritac87a9142014-07-21 10:38:13 -070092 }
93}
94
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080095func revertDeviceExpectError(t *testing.T, ctx *context.T, name string, errID verror.ID) {
96 if err := deviceStub(name).Revert(ctx); !verror2.Is(err, errID) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -080097 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 -070098 }
99}
100
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800101func revertDevice(t *testing.T, ctx *context.T, name string) {
102 if err := deviceStub(name).Revert(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800103 t.Fatalf(testutil.FormatLogLine(2, "Revert(%v) failed: %v", name, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700104 }
105}
106
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800107func stopDevice(t *testing.T, ctx *context.T, name string) {
108 if err := deviceStub(name).Stop(ctx, stopTimeout); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800109 t.Fatalf(testutil.FormatLogLine(1+1, "%s: Stop(%v) failed: %v", name, err))
Bogdan Caprita4ea9b032014-12-27 14:56:51 -0800110 }
111}
112
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800113func suspendDevice(t *testing.T, ctx *context.T, name string) {
114 if err := deviceStub(name).Suspend(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800115 t.Fatalf(testutil.FormatLogLine(1+1, "%s: Suspend(%v) failed: %v", name, err))
Bogdan Caprita4ea9b032014-12-27 14:56:51 -0800116 }
117}
118
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700119// The following set of functions are convenience wrappers around various app
120// management methods.
121
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800122func ocfg(opt []interface{}) device.Config {
123 for _, o := range opt {
124 if c, ok := o.(device.Config); ok {
125 return c
126 }
127 }
128 return device.Config{}
129}
130
Bogdan Capritaa456f472014-12-10 10:18:03 -0800131func appStub(nameComponents ...string) device.ApplicationClientMethods {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800132 appsName := "dm//apps"
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700133 appName := naming.Join(append([]string{appsName}, nameComponents...)...)
Bogdan Capritaa456f472014-12-10 10:18:03 -0800134 return device.ApplicationClient(appName)
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700135}
136
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800137func installApp(t *testing.T, ctx *context.T, opt ...interface{}) string {
138 appID, err := appStub().Install(ctx, mockApplicationRepoName, ocfg(opt))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700139 if err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800140 t.Fatalf(testutil.FormatLogLine(2, "Install failed: %v", err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700141 }
142 return appID
143}
144
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800145func installAppExpectError(t *testing.T, ctx *context.T, expectedError verror.ID, opt ...interface{}) {
146 if _, err := appStub().Install(ctx, mockApplicationRepoName, ocfg(opt)); err == nil || !verror2.Is(err, expectedError) {
147 t.Fatalf(testutil.FormatLogLine(2, "Install expected to fail with %v, got %v instead", expectedError, err))
148 }
149}
150
Bogdan Caprita26929102014-11-07 11:56:56 -0800151type granter struct {
152 ipc.CallOpt
153 p security.Principal
154 extension string
155}
156
157func (g *granter) Grant(other security.Blessings) (security.Blessings, error) {
158 return g.p.Bless(other.PublicKey(), g.p.BlessingStore().Default(), g.extension, security.UnconstrainedUse())
159}
160
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800161func startAppImpl(t *testing.T, ctx *context.T, appID, grant string) (string, error) {
Bogdan Caprita730bde12014-11-08 15:35:43 -0800162 var opts []ipc.CallOpt
163 if grant != "" {
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800164 opts = append(opts, &granter{p: veyron2.GetPrincipal(ctx), extension: grant})
Bogdan Caprita730bde12014-11-08 15:35:43 -0800165 }
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800166 if instanceIDs, err := appStub(appID).Start(ctx, opts...); err != nil {
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700167 return "", err
168 } else {
169 if want, got := 1, len(instanceIDs); want != got {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800170 t.Fatalf(testutil.FormatLogLine(2, "Start(%v): expected %v instance ids, got %v instead", appID, want, got))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700171 }
172 return instanceIDs[0], nil
173 }
174}
175
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800176func startApp(t *testing.T, ctx *context.T, appID string) string {
177 instanceID, err := startAppImpl(t, ctx, appID, "forapp")
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700178 if err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800179 t.Fatalf(testutil.FormatLogLine(2, "Start(%v) failed: %v", appID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700180 }
181 return instanceID
182}
183
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800184func startAppExpectError(t *testing.T, ctx *context.T, appID string, expectedError verror.ID) {
185 if _, err := startAppImpl(t, ctx, appID, "forapp"); err == nil || !verror2.Is(err, expectedError) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800186 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 -0700187 }
188}
189
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800190func stopApp(t *testing.T, ctx *context.T, appID, instanceID string) {
191 if err := appStub(appID, instanceID).Stop(ctx, stopTimeout); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800192 t.Fatalf(testutil.FormatLogLine(2, "Stop(%v/%v) failed: %v", appID, instanceID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700193 }
194}
195
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800196func suspendApp(t *testing.T, ctx *context.T, appID, instanceID string) {
197 if err := appStub(appID, instanceID).Suspend(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800198 t.Fatalf(testutil.FormatLogLine(2, "Suspend(%v/%v) failed: %v", appID, instanceID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700199 }
200}
201
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800202func resumeApp(t *testing.T, ctx *context.T, appID, instanceID string) {
203 if err := appStub(appID, instanceID).Resume(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800204 t.Fatalf(testutil.FormatLogLine(2, "Resume(%v/%v) failed: %v", appID, instanceID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700205 }
206}
207
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800208func resumeAppExpectError(t *testing.T, ctx *context.T, appID, instanceID string, expectedError verror.ID) {
209 if err := appStub(appID, instanceID).Resume(ctx); err == nil || !verror2.Is(err, expectedError) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800210 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 -0700211 }
212}
213
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800214func updateApp(t *testing.T, ctx *context.T, appID string) {
215 if err := appStub(appID).Update(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800216 t.Fatalf(testutil.FormatLogLine(2, "Update(%v) failed: %v", appID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700217 }
218}
219
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800220func updateAppExpectError(t *testing.T, ctx *context.T, appID string, expectedError verror.ID) {
221 if err := appStub(appID).Update(ctx); err == nil || !verror2.Is(err, expectedError) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800222 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 -0700223 }
224}
225
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800226func revertApp(t *testing.T, ctx *context.T, appID string) {
227 if err := appStub(appID).Revert(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800228 t.Fatalf(testutil.FormatLogLine(2, "Revert(%v) failed: %v", appID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700229 }
230}
231
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800232func revertAppExpectError(t *testing.T, ctx *context.T, appID string, expectedError verror.ID) {
233 if err := appStub(appID).Revert(ctx); err == nil || !verror2.Is(err, expectedError) {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800234 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 -0700235 }
236}
237
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800238func uninstallApp(t *testing.T, ctx *context.T, appID string) {
239 if err := appStub(appID).Uninstall(ctx); err != nil {
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800240 t.Fatalf(testutil.FormatLogLine(2, "Uninstall(%v) failed: %v", appID, err))
Bogdan Caprita48bbd142014-09-04 16:07:23 -0700241 }
Bogdan Capritac87a9142014-07-21 10:38:13 -0700242}
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700243
244// Code to make Association lists sortable.
Bogdan Capritaa456f472014-12-10 10:18:03 -0800245type byIdentity []device.Association
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700246
247func (a byIdentity) Len() int { return len(a) }
248func (a byIdentity) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
249func (a byIdentity) Less(i, j int) bool { return a[i].IdentityName < a[j].IdentityName }
250
Bogdan Capritaa456f472014-12-10 10:18:03 -0800251func compareAssociations(t *testing.T, got, expected []device.Association) {
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -0700252 sort.Sort(byIdentity(got))
253 sort.Sort(byIdentity(expected))
254 if !reflect.DeepEqual(got, expected) {
255 t.Fatalf("ListAssociations() got %v, expected %v", got, expected)
256 }
257}
Robert Kroeger94ec7562014-10-28 17:58:44 -0700258
259// generateSuidHelperScript builds a script to execute the test target as
260// a suidhelper instance and returns the path to the script.
261func generateSuidHelperScript(t *testing.T, root string) string {
262 output := "#!/bin/bash\n"
263 output += "VEYRON_SUIDHELPER_TEST=1"
264 output += " "
Bogdan Caprita069341a2014-12-09 22:59:17 -0800265 output += "exec " + os.Args[0] + " -minuid=1 -test.run=TestSuidHelper $*"
Robert Kroeger94ec7562014-10-28 17:58:44 -0700266 output += "\n"
267
268 vlog.VI(1).Infof("script\n%s", output)
269
270 if err := os.MkdirAll(root, 0755); err != nil {
271 t.Fatalf("MkdirAll failed: %v", err)
272 }
Robert Kroeger94ec7562014-10-28 17:58:44 -0700273 path := filepath.Join(root, "helper.sh")
274 if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
275 t.Fatalf("WriteFile(%v) failed: %v", path, err)
276 }
277 return path
278}
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800279
280// generateAgentScript creates a simple script that acts as the security agent
281// for tests. It blackholes arguments meant for the agent.
282func generateAgentScript(t *testing.T, root string) string {
283 output := `
284#!/bin/bash
285ARGS=$*
286for ARG in ${ARGS[@]}; do
287 if [[ ${ARG} = -- ]]; then
288 ARGS=(${ARGS[@]/$ARG})
289 break
290 elif [[ ${ARG} == --* ]]; then
291 ARGS=(${ARGS[@]/$ARG})
292 else
293 break
294 fi
295done
296
297exec ${ARGS[@]}
298`
299 if err := os.MkdirAll(root, 0755); err != nil {
300 t.Fatalf("MkdirAll failed: %v", err)
301 }
302 path := filepath.Join(root, "agenthelper.sh")
303 if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
304 t.Fatalf("WriteFile(%v) failed: %v", path, err)
305 }
306 return path
307}