blob: 7dd1c06eab55feec1dacccc552a40ebdbcb7845f [file] [log] [blame]
Bogdan Caprita5420f172014-10-10 15:58:14 -07001// TODO(caprita): This file is becoming unmanageable; split into several test
2// files.
Robert Kroegeracc778b2014-11-03 17:17:21 -08003// TODO(rjkroege): Add a more extensive unit test case to exercise ACL logic.
Bogdan Caprita5420f172014-10-10 15:58:14 -07004
Jiri Simsa70c32052014-06-18 11:38:21 -07005package impl_test
Jiri Simsa5293dcb2014-05-10 09:56:38 -07006
7import (
Asim Shankar88292912014-10-09 19:41:07 -07008 "bytes"
Bogdan Caprita1e379132014-08-03 23:02:31 -07009 "crypto/md5"
10 "encoding/base64"
Asim Shankar88292912014-10-09 19:41:07 -070011 "encoding/hex"
Robert Kroeger627a1152014-10-01 14:57:55 -070012 "encoding/json"
Bogdan Capritac7e72b62015-01-07 19:22:23 -080013 "flag"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070014 "fmt"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070015 "io"
Jiri Simsa70c32052014-06-18 11:38:21 -070016 "io/ioutil"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070017 "os"
Bogdan Capritac87a9142014-07-21 10:38:13 -070018 goexec "os/exec"
Robert Kroeger627a1152014-10-01 14:57:55 -070019 "os/user"
Robin Thellend9e523a62014-10-07 16:19:53 -070020 "path"
Jiri Simsa70c32052014-06-18 11:38:21 -070021 "path/filepath"
Robin Thellend09929f42014-10-01 10:18:13 -070022 "reflect"
Robin Thellend4c5266e2014-10-27 13:19:29 -070023 "regexp"
Robin Thellend09929f42014-10-01 10:18:13 -070024 "sort"
Jiri Simsa70c32052014-06-18 11:38:21 -070025 "strings"
Bogdan Caprita78b62162014-08-21 15:35:08 -070026 "syscall"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070027 "testing"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070028 "time"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070029
Jiri Simsa764efb72014-12-25 20:57:03 -080030 "v.io/core/veyron2"
31 "v.io/core/veyron2/context"
32 "v.io/core/veyron2/ipc"
33 "v.io/core/veyron2/naming"
Jiri Simsa764efb72014-12-25 20:57:03 -080034 "v.io/core/veyron2/security"
35 "v.io/core/veyron2/services/mgmt/application"
36 "v.io/core/veyron2/services/mgmt/device"
37 "v.io/core/veyron2/services/mgmt/logreader"
38 "v.io/core/veyron2/services/mgmt/pprof"
39 "v.io/core/veyron2/services/mgmt/stats"
40 "v.io/core/veyron2/services/security/access"
Jiri Simsa764efb72014-12-25 20:57:03 -080041 verror "v.io/core/veyron2/verror2"
42 "v.io/core/veyron2/vlog"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070043
Bogdan Capritac7e72b62015-01-07 19:22:23 -080044 "v.io/core/veyron/lib/expect"
Jiri Simsa764efb72014-12-25 20:57:03 -080045 "v.io/core/veyron/lib/modules"
46 "v.io/core/veyron/lib/signals"
47 "v.io/core/veyron/lib/testutil"
48 tsecurity "v.io/core/veyron/lib/testutil/security"
49 binaryimpl "v.io/core/veyron/services/mgmt/binary/impl"
50 "v.io/core/veyron/services/mgmt/device/config"
51 "v.io/core/veyron/services/mgmt/device/impl"
52 libbinary "v.io/core/veyron/services/mgmt/lib/binary"
Robert Kroegerebfb62a2014-12-10 14:42:09 -080053 mgmttest "v.io/core/veyron/services/mgmt/lib/testutil"
Jiri Simsa764efb72014-12-25 20:57:03 -080054 suidhelper "v.io/core/veyron/services/mgmt/suidhelper/impl"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070055)
56
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070057const (
Bogdan Caprita17666dd2015-01-14 09:27:46 -080058 // Modules command names.
Bogdan Caprita2b219362014-12-09 17:03:33 -080059 execScriptCmd = "execScriptCmd"
60 deviceManagerCmd = "deviceManager"
61 appCmd = "app"
62 installerCmd = "installer"
Bogdan Capritaa40d3382014-12-19 16:30:26 -080063 uninstallerCmd = "uninstaller"
Bogdan Caprita17666dd2015-01-14 09:27:46 -080064
65 testFlagName = "random_test_flag"
66 // VEYRON prefix is necessary to pass the env filtering.
67 testEnvVarName = "VEYRON_RANDOM_ENV_VALUE"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070068)
Robert Kroegerdd07b362014-09-18 17:34:42 -070069
Bogdan Caprita17666dd2015-01-14 09:27:46 -080070var flagValue = flag.String(testFlagName, "default", "")
71
Robert Kroegerdd07b362014-09-18 17:34:42 -070072func init() {
Bogdan Capritac7e72b62015-01-07 19:22:23 -080073 // The installer sets this flag on the installed device manager, so we
74 // need to ensure it's defined.
75 flag.String("name", "", "")
76
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070077 modules.RegisterChild(execScriptCmd, "", execScript)
Bogdan Caprita2b219362014-12-09 17:03:33 -080078 modules.RegisterChild(deviceManagerCmd, "", deviceManager)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070079 modules.RegisterChild(appCmd, "", app)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070080 testutil.Init()
81
82 if modules.IsModulesProcess() {
Robert Kroegerdd07b362014-09-18 17:34:42 -070083 return
84 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070085}
86
87// TestHelperProcess is the entrypoint for the modules commands in a
88// a test subprocess.
89func TestHelperProcess(t *testing.T) {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070090 modules.DispatchInTest()
Robert Kroegerdd07b362014-09-18 17:34:42 -070091}
92
93// TestSuidHelper is testing boilerplate for suidhelper that does not
Matt Rosencrantz5180d162014-12-03 13:48:40 -080094// create a runtime because the suidhelper is not a Veyron application.
Robert Kroegerdd07b362014-09-18 17:34:42 -070095func TestSuidHelper(t *testing.T) {
96 if os.Getenv("VEYRON_SUIDHELPER_TEST") != "1" {
97 return
98 }
99 vlog.VI(1).Infof("TestSuidHelper starting")
100
101 if err := suidhelper.Run(os.Environ()); err != nil {
102 vlog.Fatalf("Failed to Run() setuidhelper: %v", err)
103 }
Bogdan Capritac87a9142014-07-21 10:38:13 -0700104}
105
106// execScript launches the script passed as argument.
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700107func execScript(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
108 args = args[1:]
Bogdan Capritac87a9142014-07-21 10:38:13 -0700109 if want, got := 1, len(args); want != got {
110 vlog.Fatalf("execScript expected %d arguments, got %d instead", want, got)
111 }
112 script := args[0]
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700113 osenv := []string{}
114 if env["PAUSE_BEFORE_STOP"] == "1" {
115 osenv = append(osenv, "PAUSE_BEFORE_STOP=1")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700116 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700117
Bogdan Capritac87a9142014-07-21 10:38:13 -0700118 cmd := goexec.Cmd{
119 Path: script,
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700120 Env: osenv,
121 Stdin: stdin,
122 Stderr: stderr,
123 Stdout: stdout,
Bogdan Capritac87a9142014-07-21 10:38:13 -0700124 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700125
126 return cmd.Run()
Bogdan Capritac87a9142014-07-21 10:38:13 -0700127}
128
Bogdan Caprita2b219362014-12-09 17:03:33 -0800129// deviceManager sets up a device manager server. It accepts the name to
130// publish the server under as an argument. Additional arguments can optionally
131// specify device manager config settings.
132func deviceManager(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800133 ctx, shutdown := veyron2.Init()
134
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700135 args = args[1:]
Bogdan Capritac87a9142014-07-21 10:38:13 -0700136 if len(args) == 0 {
Bogdan Caprita2b219362014-12-09 17:03:33 -0800137 vlog.Fatalf("deviceManager expected at least an argument")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700138 }
139 publishName := args[0]
Bogdan Caprita78b62162014-08-21 15:35:08 -0700140 args = args[1:]
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800141 defer fmt.Fprintf(stdout, "%v terminated\n", publishName)
142 defer vlog.VI(1).Infof("%v terminated", publishName)
143 defer shutdown()
144 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
145
146 server, endpoint := mgmttest.NewServer(ctx)
David Why Use Two When One Will Do Presotto8b4dbbf2014-11-06 10:50:14 -0800147 name := naming.JoinAddressName(endpoint, "")
Bogdan Caprita2b219362014-12-09 17:03:33 -0800148 vlog.VI(1).Infof("Device manager name: %v", name)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700149
150 // Satisfy the contract described in doc.go by passing the config state
Bogdan Caprita2b219362014-12-09 17:03:33 -0800151 // through to the device manager dispatcher constructor.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700152 configState, err := config.Load()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700153 if err != nil {
Bogdan Capritac87a9142014-07-21 10:38:13 -0700154 vlog.Fatalf("Failed to decode config state: %v", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700155 }
Bogdan Capritac87a9142014-07-21 10:38:13 -0700156 configState.Name = name
157
158 // This exemplifies how to override or set specific config fields, if,
Bogdan Caprita2b219362014-12-09 17:03:33 -0800159 // for example, the device manager is invoked 'by hand' instead of via a
160 // script prepared by a previous version of the device manager.
Bogdan Caprita78b62162014-08-21 15:35:08 -0700161 if len(args) > 0 {
Bogdan Caprita962d5e02014-10-28 18:36:09 -0700162 if want, got := 4, len(args); want != got {
Bogdan Capritac87a9142014-07-21 10:38:13 -0700163 vlog.Fatalf("expected %d additional arguments, got %d instead", want, got)
164 }
Bogdan Caprita962d5e02014-10-28 18:36:09 -0700165 configState.Root, configState.Helper, configState.Origin, configState.CurrentLink = args[0], args[1], args[2], args[3]
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700166 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800167 dispatcher, err := impl.NewDispatcher(veyron2.GetPrincipal(ctx), configState, func() { fmt.Println("restart handler") })
Bogdan Capritac87a9142014-07-21 10:38:13 -0700168 if err != nil {
Bogdan Caprita2b219362014-12-09 17:03:33 -0800169 vlog.Fatalf("Failed to create device manager dispatcher: %v", err)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700170 }
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800171 if err := server.ServeDispatcher(publishName, dispatcher); err != nil {
Bogdan Capritac87a9142014-07-21 10:38:13 -0700172 vlog.Fatalf("Serve(%v) failed: %v", publishName, err)
173 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800174 impl.InvokeCallback(ctx, name)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700175
176 fmt.Fprintf(stdout, "ready:%d\n", os.Getpid())
Bogdan Capritac87a9142014-07-21 10:38:13 -0700177
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800178 <-signals.ShutdownOnSignals(ctx)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700179
180 if val, present := env["PAUSE_BEFORE_STOP"]; present && val == "1" {
181 modules.WaitForEOF(stdin)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700182 }
Bogdan Caprita78b62162014-08-21 15:35:08 -0700183 if dispatcher.Leaking() {
Bogdan Caprita2b219362014-12-09 17:03:33 -0800184 vlog.Fatalf("device manager leaking resources")
Bogdan Caprita78b62162014-08-21 15:35:08 -0700185 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700186 return nil
187}
188
Bogdan Caprita1e379132014-08-03 23:02:31 -0700189// appService defines a test service that the test app should be running.
190// TODO(caprita): Use this to make calls to the app and verify how Suspend/Stop
191// interact with an active service.
192type appService struct{}
193
Todd Wang1fe7cdd2014-11-12 12:51:49 -0800194func (appService) Echo(_ ipc.ServerContext, message string) (string, error) {
Bogdan Caprita1e379132014-08-03 23:02:31 -0700195 return message, nil
196}
197
Robin Thellend875f2592014-12-02 10:29:37 -0800198func (appService) Cat(_ ipc.ServerContext, file string) (string, error) {
199 if file == "" || file[0] == filepath.Separator || file[0] == '.' {
200 return "", fmt.Errorf("illegal file name: %q", file)
201 }
202 bytes, err := ioutil.ReadFile(file)
203 if err != nil {
204 return "", err
205 }
206 return string(bytes), nil
207}
208
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800209type pingArgs struct {
Bogdan Capritae1960f52015-01-14 09:57:19 -0800210 Username, FlagValue, EnvValue string
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800211}
212
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800213func ping(ctx *context.T) {
Bogdan Capritae1960f52015-01-14 09:57:19 -0800214 helperEnv := os.Getenv(suidhelper.SavedArgs)
215 d := json.NewDecoder(strings.NewReader(helperEnv))
216 var savedArgs suidhelper.ArgsSavedForTest
217 if err := d.Decode(&savedArgs); err != nil {
218 vlog.Fatalf("Failed to decode preserved argument %v: %v", helperEnv, err)
219 }
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800220 args := &pingArgs{
Bogdan Capritae1960f52015-01-14 09:57:19 -0800221 // TODO(rjkroege): Consider validating additional parameters
222 // from helper.
223 Username: savedArgs.Uname,
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800224 FlagValue: *flagValue,
225 EnvValue: os.Getenv(testEnvVarName),
226 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800227 client := veyron2.GetClient(ctx)
228 if call, err := client.StartCall(ctx, "pingserver", "Ping", []interface{}{args}); err != nil {
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700229 vlog.Fatalf("StartCall failed: %v", err)
Todd Wang702385a2014-11-07 01:54:08 -0800230 } else if err := call.Finish(); err != nil {
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700231 vlog.Fatalf("Finish failed: %v", err)
232 }
233}
234
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800235func cat(ctx *context.T, name, file string) (string, error) {
236 ctx, cancel := context.WithTimeout(ctx, time.Minute)
Robin Thellend875f2592014-12-02 10:29:37 -0800237 defer cancel()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800238 client := veyron2.GetClient(ctx)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800239 call, err := client.StartCall(ctx, name, "Cat", []interface{}{file})
Robin Thellend875f2592014-12-02 10:29:37 -0800240 if err != nil {
241 return "", err
242 }
243 var content string
244 if ferr := call.Finish(&content, &err); ferr != nil {
245 err = ferr
246 }
247 return content, err
248}
249
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700250func app(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800251 ctx, shutdown := veyron2.Init()
252 defer shutdown()
253 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
254
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700255 args = args[1:]
Bogdan Caprita1e379132014-08-03 23:02:31 -0700256 if expected, got := 1, len(args); expected != got {
257 vlog.Fatalf("Unexpected number of arguments: expected %d, got %d", expected, got)
258 }
259 publishName := args[0]
260
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800261 server, _ := mgmttest.NewServer(ctx)
Bogdan Caprita1e379132014-08-03 23:02:31 -0700262 defer server.Stop()
Cosmos Nicolaou92dba582014-11-05 17:24:10 -0800263 if err := server.Serve(publishName, new(appService), nil); err != nil {
Bogdan Caprita1e379132014-08-03 23:02:31 -0700264 vlog.Fatalf("Serve(%v) failed: %v", publishName, err)
265 }
Cosmos Nicolaoue3391532014-11-25 19:08:32 -0800266 // Some of our tests look for log files, so make sure they are flushed
267 // to ensure that at least the files exist.
268 vlog.FlushLog()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800269 ping(ctx)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700270
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800271 <-signals.ShutdownOnSignals(ctx)
Bogdan Caprita1e379132014-08-03 23:02:31 -0700272 if err := ioutil.WriteFile("testfile", []byte("goodbye world"), 0600); err != nil {
273 vlog.Fatalf("Failed to write testfile: %v", err)
274 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700275 return nil
Bogdan Caprita1e379132014-08-03 23:02:31 -0700276}
277
Bogdan Caprita2b219362014-12-09 17:03:33 -0800278// TODO(rjkroege): generateDeviceManagerScript and generateSuidHelperScript have
279// code similarity that might benefit from refactoring.
280// generateDeviceManagerScript is very similar in behavior to generateScript in
Bogdan Capritaa456f472014-12-10 10:18:03 -0800281// device_invoker.go. However, we chose to re-implement it here for two
282// reasons: (1) avoid making generateScript public; and (2) how the test choses
283// to invoke the device manager subprocess the first time should be independent
284// of how device manager implementation sets up its updated versions.
Bogdan Caprita2b219362014-12-09 17:03:33 -0800285func generateDeviceManagerScript(t *testing.T, root string, args, env []string) string {
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700286 env = impl.VeyronEnvironment(env)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700287 output := "#!/bin/bash\n"
Bogdan Caprita069341a2014-12-09 22:59:17 -0800288 output += strings.Join(config.QuoteEnv(env), " ") + " exec "
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700289 output += strings.Join(args, " ")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700290 if err := os.MkdirAll(filepath.Join(root, "factory"), 0755); err != nil {
291 t.Fatalf("MkdirAll failed: %v", err)
292 }
293 // Why pigeons? To show that the name we choose for the initial script
Bogdan Caprita2b219362014-12-09 17:03:33 -0800294 // doesn't matter and in particular is independent of how device manager
295 // names its updated version scripts (deviced.sh).
Bogdan Capritac87a9142014-07-21 10:38:13 -0700296 path := filepath.Join(root, "factory", "pigeons.sh")
297 if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
298 t.Fatalf("WriteFile(%v) failed: %v", path, err)
299 }
300 return path
301}
302
Bogdan Caprita2b219362014-12-09 17:03:33 -0800303// TestDeviceManagerUpdateAndRevert makes the device manager go through the
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700304// motions of updating itself to newer versions (twice), and reverting itself
305// back (twice). It also checks that update and revert fail when they're
Bogdan Caprita2b219362014-12-09 17:03:33 -0800306// supposed to. The initial device manager is started 'by hand' via a module
307// command. Further versions are started through the soft link that the device
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700308// manager itself updates.
Bogdan Caprita2b219362014-12-09 17:03:33 -0800309func TestDeviceManagerUpdateAndRevert(t *testing.T) {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800310 ctx, shutdown := veyron2.Init()
311 defer shutdown()
Matt Rosencrantz2ae60cb2015-01-22 23:30:26 -0800312 ctx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-principal"))
313 if err != nil {
314 panic(err)
315 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800316 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
317
318 sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, veyron2.GetPrincipal(ctx))
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700319 defer deferFn()
320
321 // Set up mock application and binary repositories.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800322 envelope, cleanup := startMockRepos(t, ctx)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700323 defer cleanup()
Bogdan Capritac87a9142014-07-21 10:38:13 -0700324
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800325 root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
Bogdan Caprita080a7302014-08-20 15:35:37 -0700326 defer cleanup()
Jiri Simsae0fc61a2014-07-30 14:41:55 -0700327
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700328 // Current link does not have to live in the root dir, but it's
329 // convenient to put it there so we have everything in one place.
330 currLink := filepath.Join(root, "current_link")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700331
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800332 dmArgs := []string{"factoryDM", root, "unused_helper", mockApplicationRepoName, currLink}
Ryan Browna08a2212015-01-15 15:40:10 -0800333 args, env := sh.CommandEnvelope(deviceManagerCmd, nil, dmArgs...)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700334
Bogdan Caprita2b219362014-12-09 17:03:33 -0800335 scriptPathFactory := generateDeviceManagerScript(t, root, args, env)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700336
337 if err := os.Symlink(scriptPathFactory, currLink); err != nil {
338 t.Fatalf("Symlink(%q, %q) failed: %v", scriptPathFactory, currLink, err)
339 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700340
Bogdan Caprita2b219362014-12-09 17:03:33 -0800341 // We instruct the initial device manager that we run to pause before
Bogdan Capritac87a9142014-07-21 10:38:13 -0700342 // stopping its service, so that we get a chance to verify that
343 // attempting an update while another one is ongoing will fail.
Ryan Browna08a2212015-01-15 15:40:10 -0800344 dmPauseBeforeStopEnv := []string{"PAUSE_BEFORE_STOP=1"}
Bogdan Capritac87a9142014-07-21 10:38:13 -0700345
Bogdan Caprita2b219362014-12-09 17:03:33 -0800346 // Start the initial version of the device manager, the so-called
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700347 // "factory" version. We use the modules-generated command to start it.
Bogdan Caprita2b219362014-12-09 17:03:33 -0800348 // We could have also used the scriptPathFactory to start it, but this
349 // demonstrates that the initial device manager could be started by hand
350 // as long as the right initial configuration is passed into the device
351 // manager implementation.
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800352 dmh, dms := mgmttest.RunShellCommand(t, sh, dmPauseBeforeStopEnv, deviceManagerCmd, dmArgs...)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700353 defer func() {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800354 syscall.Kill(dmh.Pid(), syscall.SIGINT)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700355 }()
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700356
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800357 mgmttest.ReadPID(t, dms)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800358 resolve(t, ctx, "factoryDM", 1) // Verify the device manager has published itself.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700359
360 // Simulate an invalid envelope in the application repository.
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800361 *envelope = envelopeFromShell(sh, dmPauseBeforeStopEnv, deviceManagerCmd, "bogus", dmArgs...)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700362
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800363 updateDeviceExpectError(t, ctx, "factoryDM", impl.ErrAppTitleMismatch.ID)
364 revertDeviceExpectError(t, ctx, "factoryDM", impl.ErrUpdateNoOp.ID)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700365
Bogdan Caprita2b219362014-12-09 17:03:33 -0800366 // Set up a second version of the device manager. The information in the
367 // envelope will be used by the device manager to stage the next
368 // version.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800369 crDir, crEnv := mgmttest.CredentialsForChild(ctx, "child")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700370 defer os.RemoveAll(crDir)
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800371 *envelope = envelopeFromShell(sh, crEnv, deviceManagerCmd, application.DeviceManagerTitle, "v2DM")
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800372 updateDevice(t, ctx, "factoryDM")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700373
374 // Current link should have been updated to point to v2.
375 evalLink := func() string {
376 path, err := filepath.EvalSymlinks(currLink)
377 if err != nil {
378 t.Fatalf("EvalSymlinks(%v) failed: %v", currLink, err)
379 }
380 return path
381 }
382 scriptPathV2 := evalLink()
383 if scriptPathFactory == scriptPathV2 {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700384 t.Fatalf("current link didn't change")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700385 }
386
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800387 updateDeviceExpectError(t, ctx, "factoryDM", impl.ErrOperationInProgress.ID)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700388
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800389 dmh.CloseStdin()
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700390
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800391 dms.Expect("restart handler")
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800392 dms.Expect("factoryDM terminated")
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800393 dmh.Shutdown(os.Stderr, os.Stderr)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700394
Bogdan Caprita2b219362014-12-09 17:03:33 -0800395 // A successful update means the device manager has stopped itself. We
Bogdan Capritac87a9142014-07-21 10:38:13 -0700396 // relaunch it from the current link.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800397 resolveExpectNotFound(t, ctx, "v2DM") // Ensure a clean slate.
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700398
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800399 dmh, dms = mgmttest.RunShellCommand(t, sh, nil, execScriptCmd, currLink)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700400
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800401 mgmttest.ReadPID(t, dms)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800402 resolve(t, ctx, "v2DM", 1) // Current link should have been launching v2.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700403
Bogdan Caprita2b219362014-12-09 17:03:33 -0800404 // Try issuing an update without changing the envelope in the
405 // application repository: this should fail, and current link should be
406 // unchanged.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800407 updateDeviceExpectError(t, ctx, "v2DM", impl.ErrUpdateNoOp.ID)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700408 if evalLink() != scriptPathV2 {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700409 t.Fatalf("script changed")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700410 }
411
Bogdan Caprita2b219362014-12-09 17:03:33 -0800412 // Create a third version of the device manager and issue an update.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800413 crDir, crEnv = mgmttest.CredentialsForChild(ctx, "child")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700414 defer os.RemoveAll(crDir)
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800415 *envelope = envelopeFromShell(sh, crEnv, deviceManagerCmd, application.DeviceManagerTitle, "v3DM")
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800416 updateDevice(t, ctx, "v2DM")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700417
418 scriptPathV3 := evalLink()
419 if scriptPathV3 == scriptPathV2 {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700420 t.Fatalf("current link didn't change")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700421 }
422
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800423 dms.Expect("restart handler")
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800424 dms.Expect("v2DM terminated")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700425
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800426 dmh.Shutdown(os.Stderr, os.Stderr)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700427
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800428 resolveExpectNotFound(t, ctx, "v3DM") // Ensure a clean slate.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700429
Bogdan Caprita2b219362014-12-09 17:03:33 -0800430 // Re-lanuch the device manager from current link. We instruct the
431 // device manager to pause before stopping its server, so that we can
432 // verify that a second revert fails while a revert is in progress.
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800433 dmh, dms = mgmttest.RunShellCommand(t, sh, dmPauseBeforeStopEnv, execScriptCmd, currLink)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700434
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800435 mgmttest.ReadPID(t, dms)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800436 resolve(t, ctx, "v3DM", 1) // Current link should have been launching v3.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700437
Bogdan Caprita2b219362014-12-09 17:03:33 -0800438 // Revert the device manager to its previous version (v2).
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800439 revertDevice(t, ctx, "v3DM")
440 revertDeviceExpectError(t, ctx, "v3DM", impl.ErrOperationInProgress.ID) // Revert already in progress.
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800441 dmh.CloseStdin()
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800442 dms.Expect("restart handler")
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800443 dms.Expect("v3DM terminated")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700444 if evalLink() != scriptPathV2 {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700445 t.Fatalf("current link was not reverted correctly")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700446 }
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800447 dmh.Shutdown(os.Stderr, os.Stderr)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700448
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800449 resolveExpectNotFound(t, ctx, "v2DM") // Ensure a clean slate.
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700450
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800451 dmh, dms = mgmttest.RunShellCommand(t, sh, nil, execScriptCmd, currLink)
452 mgmttest.ReadPID(t, dms)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800453 resolve(t, ctx, "v2DM", 1) // Current link should have been launching v2.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700454
Bogdan Caprita2b219362014-12-09 17:03:33 -0800455 // Revert the device manager to its previous version (factory).
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800456 revertDevice(t, ctx, "v2DM")
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800457 dms.Expect("restart handler")
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800458 dms.Expect("v2DM terminated")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700459 if evalLink() != scriptPathFactory {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700460 t.Fatalf("current link was not reverted correctly")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700461 }
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800462 dmh.Shutdown(os.Stderr, os.Stderr)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700463
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800464 resolveExpectNotFound(t, ctx, "factoryDM") // Ensure a clean slate.
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800465
466 dmh, dms = mgmttest.RunShellCommand(t, sh, nil, execScriptCmd, currLink)
467 mgmttest.ReadPID(t, dms)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800468 resolve(t, ctx, "factoryDM", 1) // Current link should have been launching factory version.
469 stopDevice(t, ctx, "factoryDM")
470 dms.Expect("factoryDM terminated")
Bogdan Caprita4ea9b032014-12-27 14:56:51 -0800471 dms.ExpectEOF()
472
473 // Re-launch the device manager, to exercise the behavior of Suspend.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800474 resolveExpectNotFound(t, ctx, "factoryDM") // Ensure a clean slate.
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800475 dmh, dms = mgmttest.RunShellCommand(t, sh, nil, execScriptCmd, currLink)
476 mgmttest.ReadPID(t, dms)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800477 resolve(t, ctx, "factoryDM", 1)
478 suspendDevice(t, ctx, "factoryDM")
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800479 dms.Expect("restart handler")
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800480 dms.Expect("factoryDM terminated")
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800481 dms.ExpectEOF()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700482}
Bogdan Caprita1e379132014-08-03 23:02:31 -0700483
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800484type pingServer chan<- pingArgs
Bogdan Caprita1e379132014-08-03 23:02:31 -0700485
Bogdan Caprita916e99f2014-11-24 15:47:19 -0800486// TODO(caprita): Set the timeout in a more principled manner.
Bogdan Capritaa5dd9892015-01-02 11:16:25 -0800487const pingTimeout = 60 * time.Second
Bogdan Caprita916e99f2014-11-24 15:47:19 -0800488
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800489func (p pingServer) Ping(_ ipc.ServerContext, arg pingArgs) {
Robert Kroeger627a1152014-10-01 14:57:55 -0700490 p <- arg
491}
Bogdan Caprita1e379132014-08-03 23:02:31 -0700492
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700493// setupPingServer creates a server listening for a ping from a child app; it
494// returns a channel on which the app's ping message is returned, and a cleanup
495// function.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800496func setupPingServer(t *testing.T, ctx *context.T) (<-chan pingArgs, func()) {
497 server, _ := mgmttest.NewServer(ctx)
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800498 pingCh := make(chan pingArgs, 1)
Robin Thellend888f8cf2014-12-15 16:19:10 -0800499 if err := server.Serve("pingserver", pingServer(pingCh), &openAuthorizer{}); err != nil {
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700500 t.Fatalf("Serve(%q, <dispatcher>) failed: %v", "pingserver", err)
501 }
502 return pingCh, func() {
503 if err := server.Stop(); err != nil {
504 t.Fatalf("Stop() failed: %v", err)
505 }
506 }
507}
508
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700509func verifyAppWorkspace(t *testing.T, root, appID, instanceID string) {
Bogdan Caprita2b219362014-12-09 17:03:33 -0800510 // HACK ALERT: for now, we peek inside the device manager's directory
Bogdan Caprita1e379132014-08-03 23:02:31 -0700511 // structure (which ought to be opaque) to check for what the app has
512 // written to its local root.
513 //
Bogdan Caprita2b219362014-12-09 17:03:33 -0800514 // TODO(caprita): add support to device manager to browse logs/app local
Bogdan Caprita1e379132014-08-03 23:02:31 -0700515 // root.
516 applicationDirName := func(title string) string {
517 h := md5.New()
518 h.Write([]byte(title))
519 hash := strings.TrimRight(base64.URLEncoding.EncodeToString(h.Sum(nil)), "=")
520 return "app-" + hash
521 }
522 components := strings.Split(appID, "/")
523 appTitle, installationID := components[0], components[1]
Bogdan Caprita268b4192014-08-28 10:04:44 -0700524 instanceDir := filepath.Join(root, applicationDirName(appTitle), "installation-"+installationID, "instances", "instance-"+instanceID)
Bogdan Caprita1e379132014-08-03 23:02:31 -0700525 rootDir := filepath.Join(instanceDir, "root")
526 testFile := filepath.Join(rootDir, "testfile")
527 if read, err := ioutil.ReadFile(testFile); err != nil {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700528 t.Fatalf("Failed to read %v: %v", testFile, err)
Bogdan Caprita1e379132014-08-03 23:02:31 -0700529 } else if want, got := "goodbye world", string(read); want != got {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700530 t.Fatalf("Expected to read %v, got %v instead", want, got)
Bogdan Caprita1e379132014-08-03 23:02:31 -0700531 }
532 // END HACK
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700533}
Bogdan Caprita78b62162014-08-21 15:35:08 -0700534
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800535func verifyPingArgs(t *testing.T, pingCh <-chan pingArgs, username, flagValue, envValue string) {
536 var args pingArgs
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700537 select {
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800538 case args = <-pingCh:
Bogdan Caprita916e99f2014-11-24 15:47:19 -0800539 case <-time.After(pingTimeout):
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800540 t.Fatalf(testutil.FormatLogLine(2, "failed to get ping"))
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700541 }
Bogdan Capritae1960f52015-01-14 09:57:19 -0800542 wantArgs := pingArgs{
543 Username: username,
544 FlagValue: flagValue,
545 EnvValue: envValue,
Robert Kroeger627a1152014-10-01 14:57:55 -0700546 }
Bogdan Capritae1960f52015-01-14 09:57:19 -0800547 if !reflect.DeepEqual(args, wantArgs) {
548 t.Fatalf(testutil.FormatLogLine(2, "got ping args %q, expected %q", args, wantArgs))
Robert Kroeger627a1152014-10-01 14:57:55 -0700549 }
550}
551
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700552// TestAppLifeCycle installs an app, starts it, suspends it, resumes it, and
553// then stops it.
554func TestAppLifeCycle(t *testing.T) {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800555 ctx, shutdown := veyron2.Init()
556 defer shutdown()
Matt Rosencrantz2ae60cb2015-01-22 23:30:26 -0800557 ctx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-principal"))
558 if err != nil {
559 panic(err)
560 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800561 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
562
563 sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700564 defer deferFn()
565
566 // Set up mock application and binary repositories.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800567 envelope, cleanup := startMockRepos(t, ctx)
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700568 defer cleanup()
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700569
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800570 root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700571 defer cleanup()
572
Robert Kroegerdd07b362014-09-18 17:34:42 -0700573 // Create a script wrapping the test target that implements suidhelper.
Bogdan Caprita962d5e02014-10-28 18:36:09 -0700574 helperPath := generateSuidHelperScript(t, root)
Robert Kroegerdd07b362014-09-18 17:34:42 -0700575
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800576 crDir, crEnv := mgmttest.CredentialsForChild(ctx, "devicemanager")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700577 defer os.RemoveAll(crDir)
578
Bogdan Caprita2b219362014-12-09 17:03:33 -0800579 // Set up the device manager. Since we won't do device manager updates,
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700580 // don't worry about its application envelope and current link.
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800581 dmh, dms := mgmttest.RunShellCommand(t, sh, crEnv, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
582 mgmttest.ReadPID(t, dms)
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700583
584 // Create the local server that the app uses to let us know it's ready.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800585 pingCh, cleanup := setupPingServer(t, ctx)
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700586 defer cleanup()
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700587
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800588 resolve(t, ctx, "pingserver", 1)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700589
Bogdan Capritabce0a632014-09-03 16:15:26 -0700590 // Create an envelope for a first version of the app.
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800591 *envelope = envelopeFromShell(sh, []string{testEnvVarName + "=env-val-envelope"}, appCmd, "google naps", fmt.Sprintf("--%s=flag-val-envelope", testFlagName), "appV1")
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700592
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800593 // Install the app. The config-specified flag value for testFlagName
594 // should override the value specified in the envelope above.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800595 appID := installApp(t, ctx, device.Config{testFlagName: "flag-val-install"})
Bogdan Capritad8373a12015-01-28 19:52:37 -0800596 installationDebug := debug(t, ctx, appID)
597 // We spot-check a couple pieces of information we expect in the debug
598 // output.
599 // TODO(caprita): Is there a way to verify more without adding brittle
600 // logic that assumes too much about the format? This may be one
601 // argument in favor of making the output of Debug a struct instead of
602 // free-form string.
603 if !strings.Contains(installationDebug, "Origin: ar") {
604 t.Fatalf("debug response doesn't contain expected info: %v", installationDebug)
605 }
606 if !strings.Contains(installationDebug, "Config: map[random_test_flag:flag-val-install]") {
607 t.Fatalf("debug response doesn't contain expected info: %v", installationDebug)
608 }
Bogdan Caprita730bde12014-11-08 15:35:43 -0800609
610 // Start requires the caller to grant a blessing for the app instance.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800611 if _, err := startAppImpl(t, ctx, appID, ""); err == nil || !verror.Is(err, impl.ErrInvalidBlessing.ID) {
Todd Wang34ed4c62014-11-26 15:15:52 -0800612 t.Fatalf("Start(%v) expected to fail with %v, got %v instead", appID, impl.ErrInvalidBlessing.ID, err)
Bogdan Caprita730bde12014-11-08 15:35:43 -0800613 }
614
Bogdan Capritabce0a632014-09-03 16:15:26 -0700615 // Start an instance of the app.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800616 instance1ID := startApp(t, ctx, appID)
Robert Kroeger627a1152014-10-01 14:57:55 -0700617
Bogdan Capritad8373a12015-01-28 19:52:37 -0800618 instanceDebug := debug(t, ctx, appID, instance1ID)
619 if !strings.Contains(instanceDebug, "Blessing Store: Default blessings: test-principal/forapp/google naps") {
620 t.Fatalf("debug response doesn't contain expected info: %v", instanceDebug)
621 }
622
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700623 // Wait until the app pings us that it's ready.
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800624 verifyPingArgs(t, pingCh, userName(t), "flag-val-install", "env-val-envelope")
Robert Kroeger627a1152014-10-01 14:57:55 -0700625
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800626 v1EP1 := resolve(t, ctx, "appV1", 1)[0]
Bogdan Capritabce0a632014-09-03 16:15:26 -0700627
628 // Suspend the app instance.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800629 suspendApp(t, ctx, appID, instance1ID)
630 resolveExpectNotFound(t, ctx, "appV1")
Bogdan Capritabce0a632014-09-03 16:15:26 -0700631
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800632 resumeApp(t, ctx, appID, instance1ID)
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800633 verifyPingArgs(t, pingCh, userName(t), "flag-val-install", "env-val-envelope") // Wait until the app pings us that it's ready.
Bogdan Capritabce0a632014-09-03 16:15:26 -0700634 oldV1EP1 := v1EP1
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800635 if v1EP1 = resolve(t, ctx, "appV1", 1)[0]; v1EP1 == oldV1EP1 {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700636 t.Fatalf("Expected a new endpoint for the app after suspend/resume")
637 }
638
639 // Start a second instance.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800640 instance2ID := startApp(t, ctx, appID)
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800641 verifyPingArgs(t, pingCh, userName(t), "flag-val-install", "env-val-envelope") // Wait until the app pings us that it's ready.
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700642
Bogdan Capritabce0a632014-09-03 16:15:26 -0700643 // There should be two endpoints mounted as "appV1", one for each
644 // instance of the app.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800645 endpoints := resolve(t, ctx, "appV1", 2)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700646 v1EP2 := endpoints[0]
647 if endpoints[0] == v1EP1 {
648 v1EP2 = endpoints[1]
649 if v1EP2 == v1EP1 {
650 t.Fatalf("Both endpoints are the same")
651 }
652 } else if endpoints[1] != v1EP1 {
653 t.Fatalf("Second endpoint should have been v1EP1: %v, %v", endpoints, v1EP1)
654 }
Bogdan Caprita268b4192014-08-28 10:04:44 -0700655
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700656 // TODO(caprita): test Suspend and Resume, and verify various
657 // non-standard combinations (suspend when stopped; resume while still
658 // running; stop while suspended).
659
Bogdan Capritabce0a632014-09-03 16:15:26 -0700660 // Suspend the first instance.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800661 suspendApp(t, ctx, appID, instance1ID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700662 // Only the second instance should still be running and mounted.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800663 if want, got := v1EP2, resolve(t, ctx, "appV1", 1)[0]; want != got {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700664 t.Fatalf("Resolve(%v): want: %v, got %v", "appV1", want, got)
665 }
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700666
Bogdan Capritabce0a632014-09-03 16:15:26 -0700667 // Updating the installation to itself is a no-op.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800668 updateAppExpectError(t, ctx, appID, impl.ErrUpdateNoOp.ID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700669
670 // Updating the installation should not work with a mismatched title.
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700671 *envelope = envelopeFromShell(sh, nil, appCmd, "bogus")
672
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800673 updateAppExpectError(t, ctx, appID, impl.ErrAppTitleMismatch.ID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700674
675 // Create a second version of the app and update the app to it.
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800676 *envelope = envelopeFromShell(sh, []string{testEnvVarName + "=env-val-envelope"}, appCmd, "google naps", "appV2")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700677
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800678 updateApp(t, ctx, appID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700679
680 // Second instance should still be running.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800681 if want, got := v1EP2, resolve(t, ctx, "appV1", 1)[0]; want != got {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700682 t.Fatalf("Resolve(%v): want: %v, got %v", "appV1", want, got)
683 }
684
685 // Resume first instance.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800686 resumeApp(t, ctx, appID, instance1ID)
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800687 verifyPingArgs(t, pingCh, userName(t), "flag-val-install", "env-val-envelope") // Wait until the app pings us that it's ready.
Bogdan Capritabce0a632014-09-03 16:15:26 -0700688 // Both instances should still be running the first version of the app.
689 // Check that the mounttable contains two endpoints, one of which is
690 // v1EP2.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800691 endpoints = resolve(t, ctx, "appV1", 2)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700692 if endpoints[0] == v1EP2 {
693 if endpoints[1] == v1EP2 {
694 t.Fatalf("Both endpoints are the same")
695 }
696 } else if endpoints[1] != v1EP2 {
697 t.Fatalf("Second endpoint should have been v1EP2: %v, %v", endpoints, v1EP2)
698 }
699
700 // Stop first instance.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800701 stopApp(t, ctx, appID, instance1ID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700702 verifyAppWorkspace(t, root, appID, instance1ID)
703
704 // Only second instance is still running.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800705 if want, got := v1EP2, resolve(t, ctx, "appV1", 1)[0]; want != got {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700706 t.Fatalf("Resolve(%v): want: %v, got %v", "appV1", want, got)
707 }
708
709 // Start a third instance.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800710 instance3ID := startApp(t, ctx, appID)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700711 // Wait until the app pings us that it's ready.
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800712 verifyPingArgs(t, pingCh, userName(t), "flag-val-install", "env-val-envelope")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700713
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800714 resolve(t, ctx, "appV2", 1)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700715
716 // Stop second instance.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800717 stopApp(t, ctx, appID, instance2ID)
718 resolveExpectNotFound(t, ctx, "appV1")
Bogdan Capritabce0a632014-09-03 16:15:26 -0700719
720 // Stop third instance.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800721 stopApp(t, ctx, appID, instance3ID)
722 resolveExpectNotFound(t, ctx, "appV2")
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700723
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700724 // Revert the app.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800725 revertApp(t, ctx, appID)
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700726
727 // Start a fourth instance. It should be started from version 1.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800728 instance4ID := startApp(t, ctx, appID)
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800729 verifyPingArgs(t, pingCh, userName(t), "flag-val-install", "env-val-envelope") // Wait until the app pings us that it's ready.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800730 resolve(t, ctx, "appV1", 1)
731 stopApp(t, ctx, appID, instance4ID)
732 resolveExpectNotFound(t, ctx, "appV1")
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700733
734 // We are already on the first version, no further revert possible.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800735 revertAppExpectError(t, ctx, appID, impl.ErrUpdateNoOp.ID)
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700736
Bogdan Caprita8c776b22014-08-28 17:29:07 -0700737 // Uninstall the app.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800738 uninstallApp(t, ctx, appID)
Bogdan Caprita8c776b22014-08-28 17:29:07 -0700739
Bogdan Capritabce0a632014-09-03 16:15:26 -0700740 // Updating the installation should no longer be allowed.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800741 updateAppExpectError(t, ctx, appID, impl.ErrInvalidOperation.ID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700742
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700743 // Reverting the installation should no longer be allowed.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800744 revertAppExpectError(t, ctx, appID, impl.ErrInvalidOperation.ID)
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700745
Bogdan Caprita8c776b22014-08-28 17:29:07 -0700746 // Starting new instances should no longer be allowed.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800747 startAppExpectError(t, ctx, appID, impl.ErrInvalidOperation.ID)
Bogdan Caprita8c776b22014-08-28 17:29:07 -0700748
Bogdan Caprita2b219362014-12-09 17:03:33 -0800749 // Cleanly shut down the device manager.
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800750 syscall.Kill(dmh.Pid(), syscall.SIGINT)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800751 dms.Expect("dm terminated")
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800752 dms.ExpectEOF()
Bogdan Caprita1e379132014-08-03 23:02:31 -0700753}
Gautham82bb9952014-08-28 14:11:51 -0700754
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800755func startRealBinaryRepository(t *testing.T, ctx *context.T) func() {
Jiri Simsa432cc2e2014-12-08 15:53:38 -0800756 rootDir, err := binaryimpl.SetupRootDir("")
Robin Thellend875f2592014-12-02 10:29:37 -0800757 if err != nil {
Jiri Simsa432cc2e2014-12-08 15:53:38 -0800758 t.Fatalf("binaryimpl.SetupRootDir failed: %v", err)
Robin Thellend875f2592014-12-02 10:29:37 -0800759 }
Jiri Simsa432cc2e2014-12-08 15:53:38 -0800760 state, err := binaryimpl.NewState(rootDir, "", 3)
Robin Thellend875f2592014-12-02 10:29:37 -0800761 if err != nil {
762 t.Fatalf("binaryimpl.NewState failed: %v", err)
763 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800764 server, _ := mgmttest.NewServer(ctx)
Robin Thellend875f2592014-12-02 10:29:37 -0800765 name := "realbin"
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800766 d, err := binaryimpl.NewDispatcher(veyron2.GetPrincipal(ctx), state)
Robert Kroeger8d7a0ef2015-01-14 17:38:40 -0800767 if err != nil {
768 t.Fatalf("server.NewDispatcher failed: %v", err)
769 }
770 if err := server.ServeDispatcher(name, d); err != nil {
Robin Thellend875f2592014-12-02 10:29:37 -0800771 t.Fatalf("server.ServeDispatcher failed: %v", err)
772 }
773
774 tmpdir, err := ioutil.TempDir("", "test-package-")
775 if err != nil {
776 t.Fatalf("ioutil.TempDir failed: %v", err)
777 }
778 defer os.RemoveAll(tmpdir)
779 if err := ioutil.WriteFile(filepath.Join(tmpdir, "hello.txt"), []byte("Hello World!"), 0600); err != nil {
780 t.Fatalf("ioutil.WriteFile failed: %v", err)
781 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800782 if err := libbinary.UploadFromDir(ctx, naming.Join(name, "testpkg"), tmpdir); err != nil {
Robin Thellend875f2592014-12-02 10:29:37 -0800783 t.Fatalf("libbinary.UploadFromDir failed: %v", err)
784 }
785 return func() {
786 if err := server.Stop(); err != nil {
787 t.Fatalf("server.Stop failed: %v", err)
788 }
Jiri Simsa432cc2e2014-12-08 15:53:38 -0800789 if err := os.RemoveAll(rootDir); err != nil {
790 t.Fatalf("os.RemoveAll(%q) failed: %v", rootDir, err)
Robin Thellend875f2592014-12-02 10:29:37 -0800791 }
792 }
793}
794
Bogdan Caprita2b219362014-12-09 17:03:33 -0800795// TestDeviceManagerClaim claims a devicemanager and tests ACL permissions on
796// its methods.
797func TestDeviceManagerClaim(t *testing.T) {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800798 ctx, shutdown := veyron2.Init()
799 defer shutdown()
Matt Rosencrantz2ae60cb2015-01-22 23:30:26 -0800800 ctx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-principal"))
801 if err != nil {
802 panic(err)
803 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800804 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
805
806 sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700807 defer deferFn()
808
809 // Set up mock application and binary repositories.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800810 envelope, cleanup := startMockRepos(t, ctx)
Gautham82bb9952014-08-28 14:11:51 -0700811 defer cleanup()
Gautham82bb9952014-08-28 14:11:51 -0700812
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800813 root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
Gautham82bb9952014-08-28 14:11:51 -0700814 defer cleanup()
815
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800816 crDir, crEnv := mgmttest.CredentialsForChild(ctx, "devicemanager")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700817 defer os.RemoveAll(crDir)
818
Bogdan Caprita962d5e02014-10-28 18:36:09 -0700819 // Create a script wrapping the test target that implements suidhelper.
820 helperPath := generateSuidHelperScript(t, root)
821
Bogdan Caprita2b219362014-12-09 17:03:33 -0800822 // Set up the device manager. Since we won't do device manager updates,
Gautham82bb9952014-08-28 14:11:51 -0700823 // don't worry about its application envelope and current link.
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800824 _, dms := mgmttest.RunShellCommand(t, sh, crEnv, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
825 pid := mgmttest.ReadPID(t, dms)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700826 defer syscall.Kill(pid, syscall.SIGINT)
Gautham82bb9952014-08-28 14:11:51 -0700827
Bogdan Caprita26929102014-11-07 11:56:56 -0800828 *envelope = envelopeFromShell(sh, nil, appCmd, "google naps", "trapp")
Gautham82bb9952014-08-28 14:11:51 -0700829
Robin Thellend888f8cf2014-12-15 16:19:10 -0800830 deviceStub := device.DeviceClient("dm/device")
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800831
832 claimantCtx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("claimant"))
833 if err != nil {
834 t.Fatalf("Could not create claimant principal: %v", err)
835 }
836 octx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("other"))
837 if err != nil {
838 t.Fatalf("Could not create other principal: %v", err)
839 }
Matt Rosencrantz5180d162014-12-03 13:48:40 -0800840
Bogdan Caprita2b219362014-12-09 17:03:33 -0800841 // Devicemanager should have open ACLs before we claim it and so an
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800842 // Install from octx should succeed.
843 installApp(t, octx)
Robin Thellend888f8cf2014-12-15 16:19:10 -0800844 // Claim the devicemanager with claimantRT as <defaultblessing>/mydevice
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800845 if err := deviceStub.Claim(claimantCtx, &granter{p: veyron2.GetPrincipal(claimantCtx), extension: "mydevice"}); err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700846 t.Fatal(err)
Gautham82bb9952014-08-28 14:11:51 -0700847 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700848
Robin Thellend888f8cf2014-12-15 16:19:10 -0800849 // Installation should succeed since claimantRT is now the "owner" of
850 // the devicemanager.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800851 appID := installApp(t, claimantCtx)
Bogdan Capritab9501d12014-10-10 15:02:03 -0700852
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800853 // octx should be unable to install though, since the ACLs have
Bogdan Caprita2b219362014-12-09 17:03:33 -0800854 // changed now.
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800855 installAppExpectError(t, octx, verror.NoAccess.ID)
Bogdan Capritab9501d12014-10-10 15:02:03 -0700856
Bogdan Capritab9501d12014-10-10 15:02:03 -0700857 // Create the local server that the app uses to let us know it's ready.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800858 pingCh, cleanup := setupPingServer(t, ctx)
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700859 defer cleanup()
Bogdan Capritab9501d12014-10-10 15:02:03 -0700860
861 // Start an instance of the app.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800862 instanceID := startApp(t, claimantCtx, appID)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700863
864 // Wait until the app pings us that it's ready.
865 select {
866 case <-pingCh:
Bogdan Caprita916e99f2014-11-24 15:47:19 -0800867 case <-time.After(pingTimeout):
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700868 t.Fatalf("failed to get ping")
869 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800870 resolve(t, ctx, "trapp", 1)
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800871 suspendApp(t, claimantCtx, appID, instanceID)
Bogdan Capritab9501d12014-10-10 15:02:03 -0700872
Bogdan Caprita2b219362014-12-09 17:03:33 -0800873 // TODO(gauthamt): Test that ACLs persist across devicemanager restarts
Gautham82bb9952014-08-28 14:11:51 -0700874}
Gautham6fe61e52014-09-16 13:58:17 -0700875
Bogdan Caprita2b219362014-12-09 17:03:33 -0800876func TestDeviceManagerUpdateACL(t *testing.T) {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800877 ctx, shutdown := veyron2.Init()
878 defer shutdown()
Matt Rosencrantz2ae60cb2015-01-22 23:30:26 -0800879 ctx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-principal"))
880 if err != nil {
881 panic(err)
882 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800883 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
884
885 sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700886 defer deferFn()
887
888 // Set up mock application and binary repositories.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800889 envelope, cleanup := startMockRepos(t, ctx)
Gautham6fe61e52014-09-16 13:58:17 -0700890 defer cleanup()
Gautham6fe61e52014-09-16 13:58:17 -0700891
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800892 root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
Gautham6fe61e52014-09-16 13:58:17 -0700893 defer cleanup()
894
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800895 // The two "processes"/runtimes which will act as IPC clients to
896 // the devicemanager process.
897 selfCtx := ctx
898 octx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal())
899 if err != nil {
900 t.Fatalf("Could not create other principal: %v", err)
901 }
902
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800903 // By default, selfCtx and octx will have blessings generated based on
Bogdan Caprita2b219362014-12-09 17:03:33 -0800904 // the username/machine name running this process. Since these blessings
905 // will appear in ACLs, give them recognizable names.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800906 idp := tsecurity.NewIDProvider("root")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800907 if err := idp.Bless(veyron2.GetPrincipal(selfCtx), "self"); err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700908 t.Fatal(err)
909 }
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800910 if err := idp.Bless(veyron2.GetPrincipal(octx), "other"); err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700911 t.Fatal(err)
912 }
913
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800914 crDir, crEnv := mgmttest.CredentialsForChild(ctx, "devicemanager")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700915 defer os.RemoveAll(crDir)
916
Bogdan Caprita2b219362014-12-09 17:03:33 -0800917 // Set up the device manager. Since we won't do device manager updates,
Gautham6fe61e52014-09-16 13:58:17 -0700918 // don't worry about its application envelope and current link.
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800919 _, dms := mgmttest.RunShellCommand(t, sh, crEnv, deviceManagerCmd, "dm", root, "unused_helper", "unused_app_repo_name", "unused_curr_link")
920 pid := mgmttest.ReadPID(t, dms)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700921 defer syscall.Kill(pid, syscall.SIGINT)
Gautham6fe61e52014-09-16 13:58:17 -0700922
923 // Create an envelope for an app.
Bogdan Caprita26929102014-11-07 11:56:56 -0800924 *envelope = envelopeFromShell(sh, nil, appCmd, "google naps")
Gautham6fe61e52014-09-16 13:58:17 -0700925
Robert Kroegere95ed6d2015-01-14 17:41:04 -0800926 // On an unclaimed device manager, there will be no ACLs.
927 deviceStub := device.DeviceClient("dm/device")
928 if _, _, err := deviceStub.GetACL(selfCtx); err == nil {
929 t.Fatalf("GetACL should have failed but didn't.")
Gautham6fe61e52014-09-16 13:58:17 -0700930 }
931
Bogdan Caprita2b219362014-12-09 17:03:33 -0800932 // Claim the devicemanager as "root/self/mydevice"
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800933 if err := deviceStub.Claim(selfCtx, &granter{p: veyron2.GetPrincipal(selfCtx), extension: "mydevice"}); err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700934 t.Fatal(err)
Gautham6fe61e52014-09-16 13:58:17 -0700935 }
Asim Shankar68885192014-11-26 12:48:35 -0800936 expectedACL := make(access.TaggedACLMap)
937 for _, tag := range access.AllTypicalTags() {
938 expectedACL[string(tag)] = access.ACL{In: []security.BlessingPattern{"root/self/mydevice"}}
939 }
Gautham6fe61e52014-09-16 13:58:17 -0700940 var b bytes.Buffer
Asim Shankar68885192014-11-26 12:48:35 -0800941 if err := expectedACL.WriteTo(&b); err != nil {
942 t.Fatalf("Failed to save ACL:%v", err)
Gautham6fe61e52014-09-16 13:58:17 -0700943 }
944 md5hash := md5.Sum(b.Bytes())
945 expectedETAG := hex.EncodeToString(md5hash[:])
Robert Kroegere95ed6d2015-01-14 17:41:04 -0800946 acl, etag, err := deviceStub.GetACL(selfCtx)
947 if err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700948 t.Fatal(err)
Gautham6fe61e52014-09-16 13:58:17 -0700949 }
950 if etag != expectedETAG {
951 t.Fatalf("getACL expected:%v(%v), got:%v(%v)", expectedACL, expectedETAG, acl, etag)
952 }
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800953 // Install from octx should fail, since it does not match the ACL.
954 installAppExpectError(t, octx, verror.NoAccess.ID)
955
Asim Shankar68885192014-11-26 12:48:35 -0800956 newACL := make(access.TaggedACLMap)
957 for _, tag := range access.AllTypicalTags() {
958 newACL.Add("root/other", string(tag))
959 }
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800960 if err := deviceStub.SetACL(selfCtx, newACL, "invalid"); err == nil {
Gautham6fe61e52014-09-16 13:58:17 -0700961 t.Fatalf("SetACL should have failed with invalid etag")
962 }
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800963 if err := deviceStub.SetACL(selfCtx, newACL, etag); err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700964 t.Fatal(err)
Gautham6fe61e52014-09-16 13:58:17 -0700965 }
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800966 // Install should now fail with selfCtx, which no longer matches the
967 // ACLs but succeed with octx, which does.
968 installAppExpectError(t, selfCtx, verror.NoAccess.ID)
969 installApp(t, octx)
Gautham6fe61e52014-09-16 13:58:17 -0700970}
Robin Thellend09929f42014-10-01 10:18:13 -0700971
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800972type simpleRW chan []byte
973
974func (s simpleRW) Write(p []byte) (n int, err error) {
975 s <- p
976 return len(p), nil
977}
978func (s simpleRW) Read(p []byte) (n int, err error) {
979 return copy(p, <-s), nil
980}
981
982// TestDeviceManagerInstallation verifies the 'self install' and 'uninstall'
Bogdan Capritaa40d3382014-12-19 16:30:26 -0800983// functionality of the device manager: it runs SelfInstall in a child process,
984// then runs the executable from the soft link that the installation created.
985// This should bring up a functioning device manager. In the end it runs
986// Uninstall and verifies that the installation is gone.
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800987func TestDeviceManagerInstallation(t *testing.T) {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800988 ctx, shutdown := veyron2.Init()
989 defer shutdown()
Matt Rosencrantz2ae60cb2015-01-22 23:30:26 -0800990 ctx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-principal"))
991 if err != nil {
992 panic(err)
993 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800994 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
995
996 sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700997 defer deferFn()
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -0800998 testDir, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
Bogdan Caprita5420f172014-10-10 15:58:14 -0700999 defer cleanup()
1000
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001001 // Create a script wrapping the test target that implements suidhelper.
Bogdan Caprita29a3b352015-01-16 16:28:49 -08001002 suidHelperPath := generateSuidHelperScript(t, testDir)
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001003 // Create a dummy script mascarading as the security agent.
1004 agentPath := generateAgentScript(t, testDir)
Bogdan Caprita29a3b352015-01-16 16:28:49 -08001005 initHelperPath := ""
Bogdan Caprita5420f172014-10-10 15:58:14 -07001006
Bogdan Caprita2b219362014-12-09 17:03:33 -08001007 // Create an 'envelope' for the device manager that we can pass to the
1008 // installer, to ensure that the device manager that the installer
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001009 // configures can run.
1010 dmargs, dmenv := sh.CommandEnvelope(deviceManagerCmd, nil, "dm")
1011 dmDir := filepath.Join(testDir, "dm")
Bogdan Caprita29a3b352015-01-16 16:28:49 -08001012 // TODO(caprita): Add test logic when initMode = true.
1013 singleUser, sessionMode, initMode := true, true, false
1014 if err := impl.SelfInstall(dmDir, suidHelperPath, agentPath, initHelperPath, singleUser, sessionMode, initMode, dmargs[1:], dmenv, os.Stderr, os.Stdout); err != nil {
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001015 t.Fatalf("SelfInstall failed: %v", err)
1016 }
Bogdan Caprita5420f172014-10-10 15:58:14 -07001017
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001018 resolveExpectNotFound(t, ctx, "dm")
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001019 // Start the device manager.
1020 stdout := make(simpleRW, 100)
1021 if err := impl.Start(dmDir, os.Stderr, stdout); err != nil {
1022 t.Fatalf("Start failed: %v", err)
1023 }
1024 dms := expect.NewSession(t, stdout, mgmttest.ExpectTimeout)
1025 mgmttest.ReadPID(t, dms)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001026 resolve(t, ctx, "dm", 1)
1027 revertDeviceExpectError(t, ctx, "dm", impl.ErrUpdateNoOp.ID) // No previous version available.
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001028
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001029 // Stop the device manager.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001030 if err := impl.Stop(ctx, dmDir, os.Stderr, os.Stdout); err != nil {
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001031 t.Fatalf("Stop failed: %v", err)
1032 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001033 dms.Expect("dm terminated")
Bogdan Capritaa40d3382014-12-19 16:30:26 -08001034
1035 // Uninstall.
Bogdan Caprita29a3b352015-01-16 16:28:49 -08001036 if err := impl.Uninstall(dmDir, os.Stderr, os.Stdout); err != nil {
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001037 t.Fatalf("Uninstall failed: %v", err)
Bogdan Capritaa40d3382014-12-19 16:30:26 -08001038 }
Bogdan Capritac7e72b62015-01-07 19:22:23 -08001039 // Ensure that the installation is gone.
1040 if files, err := ioutil.ReadDir(dmDir); err != nil || len(files) > 0 {
1041 var finfo []string
1042 for _, f := range files {
1043 finfo = append(finfo, f.Name())
1044 }
1045 t.Fatalf("ReadDir returned (%v, %v)", err, finfo)
Bogdan Capritaa40d3382014-12-19 16:30:26 -08001046 }
Bogdan Caprita5420f172014-10-10 15:58:14 -07001047}
1048
Bogdan Caprita2b219362014-12-09 17:03:33 -08001049func TestDeviceManagerGlobAndDebug(t *testing.T) {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001050 ctx, shutdown := veyron2.Init()
1051 defer shutdown()
Matt Rosencrantz2ae60cb2015-01-22 23:30:26 -08001052 ctx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-principal"))
1053 if err != nil {
1054 panic(err)
1055 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001056 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
1057
1058 sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001059 defer deferFn()
1060
1061 // Set up mock application and binary repositories.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001062 envelope, cleanup := startMockRepos(t, ctx)
Robin Thellend9e523a62014-10-07 16:19:53 -07001063 defer cleanup()
Robin Thellend9e523a62014-10-07 16:19:53 -07001064
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -08001065 root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
Robin Thellend09929f42014-10-01 10:18:13 -07001066 defer cleanup()
1067
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001068 crDir, crEnv := mgmttest.CredentialsForChild(ctx, "devicemanager")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001069 defer os.RemoveAll(crDir)
1070
Bogdan Caprita962d5e02014-10-28 18:36:09 -07001071 // Create a script wrapping the test target that implements suidhelper.
1072 helperPath := generateSuidHelperScript(t, root)
1073
Bogdan Caprita2b219362014-12-09 17:03:33 -08001074 // Set up the device manager. Since we won't do device manager updates,
Robin Thellend09929f42014-10-01 10:18:13 -07001075 // don't worry about its application envelope and current link.
Robert Kroegerebfb62a2014-12-10 14:42:09 -08001076 _, dms := mgmttest.RunShellCommand(t, sh, crEnv, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
1077 pid := mgmttest.ReadPID(t, dms)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001078 defer syscall.Kill(pid, syscall.SIGINT)
Robin Thellend09929f42014-10-01 10:18:13 -07001079
Robin Thellend9e523a62014-10-07 16:19:53 -07001080 // Create the local server that the app uses to let us know it's ready.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001081 pingCh, cleanup := setupPingServer(t, ctx)
Bogdan Capritad2b9f032014-10-10 17:43:29 -07001082 defer cleanup()
Robin Thellend09929f42014-10-01 10:18:13 -07001083
Robin Thellend9e523a62014-10-07 16:19:53 -07001084 // Create the envelope for the first version of the app.
Bogdan Caprita26929102014-11-07 11:56:56 -08001085 *envelope = envelopeFromShell(sh, nil, appCmd, "google naps", "appV1")
Robin Thellend9e523a62014-10-07 16:19:53 -07001086
1087 // Install the app.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001088 appID := installApp(t, ctx)
Bogdan Caprita43bc7372014-12-03 21:51:12 -08001089 install1ID := path.Base(appID)
Robin Thellend9e523a62014-10-07 16:19:53 -07001090
1091 // Start an instance of the app.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001092 instance1ID := startApp(t, ctx, appID)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001093
1094 // Wait until the app pings us that it's ready.
1095 select {
1096 case <-pingCh:
Bogdan Caprita916e99f2014-11-24 15:47:19 -08001097 case <-time.After(pingTimeout):
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001098 t.Fatalf("failed to get ping")
1099 }
Robin Thellend9e523a62014-10-07 16:19:53 -07001100
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001101 app2ID := installApp(t, ctx)
Bogdan Caprita43bc7372014-12-03 21:51:12 -08001102 install2ID := path.Base(app2ID)
1103
Robin Thellend9e523a62014-10-07 16:19:53 -07001104 testcases := []struct {
1105 name, pattern string
1106 expected []string
1107 }{
Bogdan Caprita9c4aa222014-12-10 14:46:30 -08001108 {"dm", "...", []string{
Robin Thellend9e523a62014-10-07 16:19:53 -07001109 "",
1110 "apps",
1111 "apps/google naps",
Bogdan Caprita43bc7372014-12-03 21:51:12 -08001112 "apps/google naps/" + install1ID,
1113 "apps/google naps/" + install1ID + "/" + instance1ID,
1114 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs",
1115 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs/STDERR-<timestamp>",
1116 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs/STDOUT-<timestamp>",
1117 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs/bin.INFO",
1118 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs/bin.<*>.INFO.<timestamp>",
1119 "apps/google naps/" + install1ID + "/" + instance1ID + "/pprof",
1120 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats",
1121 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats/ipc",
1122 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats/system",
1123 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats/system/start-time-rfc1123",
1124 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats/system/start-time-unix",
1125 "apps/google naps/" + install2ID,
Bogdan Caprita9c4aa222014-12-10 14:46:30 -08001126 "device",
Robin Thellend9e523a62014-10-07 16:19:53 -07001127 }},
Bogdan Caprita9c4aa222014-12-10 14:46:30 -08001128 {"dm/apps", "*", []string{"google naps"}},
1129 {"dm/apps/google naps", "*", []string{install1ID, install2ID}},
1130 {"dm/apps/google naps/" + install1ID, "*", []string{instance1ID}},
1131 {"dm/apps/google naps/" + install1ID + "/" + instance1ID, "*", []string{"logs", "pprof", "stats"}},
1132 {"dm/apps/google naps/" + install1ID + "/" + instance1ID + "/logs", "*", []string{
Robin Thellend58647322014-10-28 12:07:47 -07001133 "STDERR-<timestamp>",
1134 "STDOUT-<timestamp>",
1135 "bin.INFO",
1136 "bin.<*>.INFO.<timestamp>",
1137 }},
Bogdan Caprita9c4aa222014-12-10 14:46:30 -08001138 {"dm/apps/google naps/" + install1ID + "/" + instance1ID + "/stats/system", "start-time*", []string{"start-time-rfc1123", "start-time-unix"}},
Robin Thellend09929f42014-10-01 10:18:13 -07001139 }
Robin Thellend58647322014-10-28 12:07:47 -07001140 logFileTimeStampRE := regexp.MustCompile("(STDOUT|STDERR)-[0-9]+$")
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001141 logFileTrimInfoRE := regexp.MustCompile(`bin\..*\.INFO\.[0-9.-]+$`)
Robin Thellend58647322014-10-28 12:07:47 -07001142 logFileRemoveErrorFatalWarningRE := regexp.MustCompile("(ERROR|FATAL|WARNING)")
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001143 statsTrimRE := regexp.MustCompile("/stats/(ipc|system(/start-time.*)?)$")
Robin Thellend9e523a62014-10-07 16:19:53 -07001144 for _, tc := range testcases {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001145 results, err := testutil.GlobName(ctx, tc.name, tc.pattern)
Robin Thellend5c95a6c2014-11-10 13:06:56 -08001146 if err != nil {
1147 t.Errorf("unexpected glob error for (%q, %q): %v", tc.name, tc.pattern, err)
1148 continue
1149 }
Robin Thellend58647322014-10-28 12:07:47 -07001150 filteredResults := []string{}
1151 for _, name := range results {
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001152 // Keep only the stats object names that match this RE.
1153 if strings.Contains(name, "/stats/") && !statsTrimRE.MatchString(name) {
1154 continue
1155 }
1156 // Remove ERROR, WARNING, FATAL log files because
1157 // they're not consistently there.
Robin Thellend58647322014-10-28 12:07:47 -07001158 if logFileRemoveErrorFatalWarningRE.MatchString(name) {
1159 continue
1160 }
1161 name = logFileTimeStampRE.ReplaceAllString(name, "$1-<timestamp>")
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001162 name = logFileTrimInfoRE.ReplaceAllString(name, "bin.<*>.INFO.<timestamp>")
Robin Thellend58647322014-10-28 12:07:47 -07001163 filteredResults = append(filteredResults, name)
Robin Thellend9e523a62014-10-07 16:19:53 -07001164 }
Robin Thellend12937a22014-10-29 17:53:23 -07001165 sort.Strings(filteredResults)
1166 sort.Strings(tc.expected)
Robin Thellend58647322014-10-28 12:07:47 -07001167 if !reflect.DeepEqual(filteredResults, tc.expected) {
1168 t.Errorf("unexpected result for (%q, %q). Got %q, want %q", tc.name, tc.pattern, filteredResults, tc.expected)
Robin Thellend9e523a62014-10-07 16:19:53 -07001169 }
Robin Thellend09929f42014-10-01 10:18:13 -07001170 }
Robin Thellend4c5266e2014-10-27 13:19:29 -07001171
Robin Thellend58647322014-10-28 12:07:47 -07001172 // Call Size() on the log file objects.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001173 files, err := testutil.GlobName(ctx, "dm", "apps/google naps/"+install1ID+"/"+instance1ID+"/logs/*")
Robin Thellend5c95a6c2014-11-10 13:06:56 -08001174 if err != nil {
1175 t.Errorf("unexpected glob error: %v", err)
1176 }
Robin Thellend12937a22014-10-29 17:53:23 -07001177 if want, got := 4, len(files); got < want {
1178 t.Errorf("Unexpected number of matches. Got %d, want at least %d", got, want)
1179 }
Robin Thellend4c5266e2014-10-27 13:19:29 -07001180 for _, file := range files {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -08001181 name := naming.Join("dm", file)
Todd Wang702385a2014-11-07 01:54:08 -08001182 c := logreader.LogFileClient(name)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001183 if _, err := c.Size(ctx); err != nil {
Robin Thellend4c5266e2014-10-27 13:19:29 -07001184 t.Errorf("Size(%q) failed: %v", name, err)
1185 }
1186 }
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001187
1188 // Call Value() on some of the stats objects.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001189 objects, err := testutil.GlobName(ctx, "dm", "apps/google naps/"+install1ID+"/"+instance1ID+"/stats/system/start-time*")
Robin Thellend5c95a6c2014-11-10 13:06:56 -08001190 if err != nil {
1191 t.Errorf("unexpected glob error: %v", err)
1192 }
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001193 if want, got := 2, len(objects); got != want {
1194 t.Errorf("Unexpected number of matches. Got %d, want %d", got, want)
1195 }
1196 for _, obj := range objects {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -08001197 name := naming.Join("dm", obj)
Todd Wang702385a2014-11-07 01:54:08 -08001198 c := stats.StatsClient(name)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001199 if _, err := c.Value(ctx); err != nil {
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001200 t.Errorf("Value(%q) failed: %v", name, err)
1201 }
1202 }
1203
1204 // Call CmdLine() on the pprof object.
1205 {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -08001206 name := "dm/apps/google naps/" + install1ID + "/" + instance1ID + "/pprof"
Todd Wang702385a2014-11-07 01:54:08 -08001207 c := pprof.PProfClient(name)
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001208 v, err := c.CmdLine(ctx)
Robin Thellendb9dd9bb2014-10-29 13:54:08 -07001209 if err != nil {
1210 t.Errorf("CmdLine(%q) failed: %v", name, err)
1211 }
1212 if len(v) == 0 {
1213 t.Fatalf("Unexpected empty cmdline: %v", v)
1214 }
1215 if got, want := filepath.Base(v[0]), "bin"; got != want {
1216 t.Errorf("Unexpected value for argv[0]. Got %v, want %v", got, want)
1217 }
1218 }
Robin Thellend4c5266e2014-10-27 13:19:29 -07001219}
1220
Bogdan Caprita2b219362014-12-09 17:03:33 -08001221func TestDeviceManagerPackages(t *testing.T) {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001222 ctx, shutdown := veyron2.Init()
1223 defer shutdown()
Matt Rosencrantz2ae60cb2015-01-22 23:30:26 -08001224 ctx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-principal"))
1225 if err != nil {
1226 panic(err)
1227 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001228 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
1229
1230 sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
Robin Thellend875f2592014-12-02 10:29:37 -08001231 defer deferFn()
1232
1233 // Set up mock application and binary repositories.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001234 envelope, cleanup := startMockRepos(t, ctx)
Robin Thellend875f2592014-12-02 10:29:37 -08001235 defer cleanup()
1236
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001237 defer startRealBinaryRepository(t, ctx)()
Robin Thellend875f2592014-12-02 10:29:37 -08001238
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -08001239 root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
Robin Thellend875f2592014-12-02 10:29:37 -08001240 defer cleanup()
1241
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001242 crDir, crEnv := mgmttest.CredentialsForChild(ctx, "devicemanager")
Robin Thellend875f2592014-12-02 10:29:37 -08001243 defer os.RemoveAll(crDir)
1244
1245 // Create a script wrapping the test target that implements suidhelper.
1246 helperPath := generateSuidHelperScript(t, root)
1247
Bogdan Caprita2b219362014-12-09 17:03:33 -08001248 // Set up the device manager. Since we won't do device manager updates,
Robin Thellend875f2592014-12-02 10:29:37 -08001249 // don't worry about its application envelope and current link.
Robert Kroegerebfb62a2014-12-10 14:42:09 -08001250 _, dms := mgmttest.RunShellCommand(t, sh, crEnv, deviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
1251 pid := mgmttest.ReadPID(t, dms)
Robin Thellend875f2592014-12-02 10:29:37 -08001252 defer syscall.Kill(pid, syscall.SIGINT)
1253
1254 // Create the local server that the app uses to let us know it's ready.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001255 pingCh, cleanup := setupPingServer(t, ctx)
Robin Thellend875f2592014-12-02 10:29:37 -08001256 defer cleanup()
1257
1258 // Create the envelope for the first version of the app.
1259 *envelope = envelopeFromShell(sh, nil, appCmd, "google naps", "appV1")
1260 (*envelope).Packages = map[string]string{
1261 "test": "realbin/testpkg",
1262 }
1263
1264 // Install the app.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001265 appID := installApp(t, ctx)
Robin Thellend875f2592014-12-02 10:29:37 -08001266
1267 // Start an instance of the app.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001268 startApp(t, ctx, appID)
Robin Thellend875f2592014-12-02 10:29:37 -08001269
1270 // Wait until the app pings us that it's ready.
1271 select {
1272 case <-pingCh:
1273 case <-time.After(pingTimeout):
1274 t.Fatalf("failed to get ping")
1275 }
1276
1277 // Ask the app to cat a file from the package.
1278 file := filepath.Join("packages", "test", "hello.txt")
1279 name := "appV1"
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001280 content, err := cat(ctx, name, file)
Robin Thellend875f2592014-12-02 10:29:37 -08001281 if err != nil {
1282 t.Errorf("cat(%q, %q) failed: %v", name, file, err)
1283 }
1284 if expected := "Hello World!"; content != expected {
1285 t.Errorf("unexpected content: expected %q, got %q", expected, content)
1286 }
1287}
1288
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001289func listAndVerifyAssociations(t *testing.T, ctx *context.T, stub device.DeviceClientMethods, expected []device.Association) {
1290 assocs, err := stub.ListAssociations(ctx)
Robert Kroeger362ff892014-09-29 14:23:47 -07001291 if err != nil {
1292 t.Fatalf("ListAssociations failed %v", err)
1293 }
Robert Kroeger1cb4a0d2014-10-20 11:55:38 -07001294 compareAssociations(t, assocs, expected)
Robert Kroeger362ff892014-09-29 14:23:47 -07001295}
1296
Bogdan Caprita2b219362014-12-09 17:03:33 -08001297// TODO(rjkroege): Verify that associations persist across restarts once
1298// permanent storage is added.
Robert Kroeger362ff892014-09-29 14:23:47 -07001299func TestAccountAssociation(t *testing.T) {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001300 ctx, shutdown := veyron2.Init()
1301 defer shutdown()
Matt Rosencrantz2ae60cb2015-01-22 23:30:26 -08001302 ctx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-principal"))
1303 if err != nil {
1304 panic(err)
1305 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001306 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
1307
1308 sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001309 defer deferFn()
Robert Kroeger362ff892014-09-29 14:23:47 -07001310
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -08001311 root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
Robert Kroeger362ff892014-09-29 14:23:47 -07001312 defer cleanup()
1313
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001314 // The two "processes"/contexts which will act as IPC clients to
1315 // the devicemanager process.
1316 selfCtx := ctx
1317 otherCtx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal())
1318 if err != nil {
1319 t.Fatalf("Could not create other principal: %v", err)
1320 }
1321
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001322 // By default, selfCtx and otherCtx will have blessings generated based
1323 // on the username/machine name running this process. Since these
1324 // blessings will appear in test expecations, give them readable names.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001325 idp := tsecurity.NewIDProvider("root")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001326 if err := idp.Bless(veyron2.GetPrincipal(selfCtx), "self"); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001327 t.Fatal(err)
1328 }
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001329 if err := idp.Bless(veyron2.GetPrincipal(otherCtx), "other"); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001330 t.Fatal(err)
1331 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001332 crFile, crEnv := mgmttest.CredentialsForChild(ctx, "devicemanager")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001333 defer os.RemoveAll(crFile)
Robert Kroeger362ff892014-09-29 14:23:47 -07001334
Robert Kroegerebfb62a2014-12-10 14:42:09 -08001335 _, dms := mgmttest.RunShellCommand(t, sh, crEnv, deviceManagerCmd, "dm", root, "unused_helper", "unused_app_repo_name", "unused_curr_link")
1336 pid := mgmttest.ReadPID(t, dms)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001337 defer syscall.Kill(pid, syscall.SIGINT)
Robert Kroeger362ff892014-09-29 14:23:47 -07001338
Bogdan Caprita9c4aa222014-12-10 14:46:30 -08001339 deviceStub := device.DeviceClient("dm//device")
Robert Kroeger362ff892014-09-29 14:23:47 -07001340
Bogdan Caprita2b219362014-12-09 17:03:33 -08001341 // Attempt to list associations on the device manager without having
Robert Kroeger362ff892014-09-29 14:23:47 -07001342 // claimed it.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001343 if list, err := deviceStub.ListAssociations(otherCtx); err != nil || list != nil {
Bogdan Caprita2b219362014-12-09 17:03:33 -08001344 t.Fatalf("ListAssociations should fail on unclaimed device manager but did not: %v", err)
Robert Kroeger362ff892014-09-29 14:23:47 -07001345 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001346
Bogdan Caprita2b219362014-12-09 17:03:33 -08001347 // self claims the device manager.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001348 if err := deviceStub.Claim(selfCtx, &granter{p: veyron2.GetPrincipal(selfCtx), extension: "alice"}); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001349 t.Fatalf("Claim failed: %v", err)
1350 }
1351
1352 vlog.VI(2).Info("Verify that associations start out empty.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001353 listAndVerifyAssociations(t, selfCtx, deviceStub, []device.Association(nil))
Robert Kroeger362ff892014-09-29 14:23:47 -07001354
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001355 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/self", "root/other"}, "alice_system_account"); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001356 t.Fatalf("ListAssociations failed %v", err)
1357 }
1358 vlog.VI(2).Info("Added association should appear.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001359 listAndVerifyAssociations(t, selfCtx, deviceStub, []device.Association{
Robert Kroeger362ff892014-09-29 14:23:47 -07001360 {
1361 "root/self",
1362 "alice_system_account",
1363 },
1364 {
1365 "root/other",
1366 "alice_system_account",
1367 },
1368 })
1369
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001370 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/self", "root/other"}, "alice_other_account"); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001371 t.Fatalf("AssociateAccount failed %v", err)
1372 }
1373 vlog.VI(2).Info("Change the associations and the change should appear.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001374 listAndVerifyAssociations(t, selfCtx, deviceStub, []device.Association{
Robert Kroeger362ff892014-09-29 14:23:47 -07001375 {
1376 "root/self",
1377 "alice_other_account",
1378 },
1379 {
1380 "root/other",
1381 "alice_other_account",
1382 },
1383 })
1384
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001385 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/other"}, ""); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001386 t.Fatalf("AssociateAccount failed %v", err)
1387 }
1388 vlog.VI(2).Info("Verify that we can remove an association.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001389 listAndVerifyAssociations(t, selfCtx, deviceStub, []device.Association{
Robert Kroeger362ff892014-09-29 14:23:47 -07001390 {
1391 "root/self",
1392 "alice_other_account",
1393 },
1394 })
1395}
1396
Bogdan Caprita2b219362014-12-09 17:03:33 -08001397// userName is a helper function to determine the system name that the test is
1398// running under.
Robert Kroeger362ff892014-09-29 14:23:47 -07001399func userName(t *testing.T) string {
1400 u, err := user.Current()
1401 if err != nil {
1402 t.Fatalf("user.Current() failed: %v", err)
1403 }
1404 return u.Username
1405}
1406
1407func TestAppWithSuidHelper(t *testing.T) {
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001408 ctx, shutdown := veyron2.Init()
1409 defer shutdown()
Matt Rosencrantz2ae60cb2015-01-22 23:30:26 -08001410 ctx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal("test-principal"))
1411 if err != nil {
1412 panic(err)
1413 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001414 veyron2.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
1415
1416 sh, deferFn := mgmttest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001417 defer deferFn()
1418
1419 // Set up mock application and binary repositories.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001420 envelope, cleanup := startMockRepos(t, ctx)
Robert Kroeger362ff892014-09-29 14:23:47 -07001421 defer cleanup()
Robert Kroeger362ff892014-09-29 14:23:47 -07001422
Robert Kroegerd6e1d1a2014-12-10 15:08:45 -08001423 root, cleanup := mgmttest.SetupRootDir(t, "devicemanager")
Robert Kroeger362ff892014-09-29 14:23:47 -07001424 defer cleanup()
1425
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001426 // The two "processes"/runtimes which will act as IPC clients to
1427 // the devicemanager process.
1428 selfCtx := ctx
1429 otherCtx, err := veyron2.SetPrincipal(ctx, tsecurity.NewPrincipal())
1430 if err != nil {
1431 t.Fatalf("Could not create other principal: %v", err)
1432 }
Robert Kroeger362ff892014-09-29 14:23:47 -07001433
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001434 // By default, selfCtx and otherCtx will have blessings generated based
1435 // on the username/machine name running this process. Since these
1436 // blessings can appear in debugging output, give them recognizable
1437 // names.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001438 idp := tsecurity.NewIDProvider("root")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001439 if err := idp.Bless(veyron2.GetPrincipal(selfCtx), "self"); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001440 t.Fatal(err)
1441 }
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001442 if err := idp.Bless(veyron2.GetPrincipal(otherCtx), "other"); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001443 t.Fatal(err)
1444 }
1445
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001446 crDir, crEnv := mgmttest.CredentialsForChild(ctx, "devicemanager")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001447 defer os.RemoveAll(crDir)
1448
Bogdan Caprita2b219362014-12-09 17:03:33 -08001449 // Create a script wrapping the test target that implements suidhelper.
Bogdan Caprita962d5e02014-10-28 18:36:09 -07001450 helperPath := generateSuidHelperScript(t, root)
Robert Kroeger362ff892014-09-29 14:23:47 -07001451
Robert Kroegerebfb62a2014-12-10 14:42:09 -08001452 _, dms := mgmttest.RunShellCommand(t, sh, crEnv, deviceManagerCmd, "-mocksetuid", "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
1453 pid := mgmttest.ReadPID(t, dms)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001454 defer syscall.Kill(pid, syscall.SIGINT)
Robert Kroeger362ff892014-09-29 14:23:47 -07001455
Bogdan Caprita9c4aa222014-12-10 14:46:30 -08001456 deviceStub := device.DeviceClient("dm//device")
Robert Kroeger362ff892014-09-29 14:23:47 -07001457
Bogdan Caprita2b219362014-12-09 17:03:33 -08001458 // Create the local server that the app uses to tell us which system
1459 // name the device manager wished to run it as.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001460 pingCh, cleanup := setupPingServer(t, ctx)
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001461 defer cleanup()
Robert Kroeger362ff892014-09-29 14:23:47 -07001462
Bogdan Caprita26929102014-11-07 11:56:56 -08001463 // Create an envelope for a first version of the app.
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001464 *envelope = envelopeFromShell(sh, []string{testEnvVarName + "=env-var"}, appCmd, "google naps", fmt.Sprintf("--%s=flag-val-envelope", testFlagName), "appV1")
Robert Kroeger362ff892014-09-29 14:23:47 -07001465
1466 // Install and start the app as root/self.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001467 appID := installApp(t, selfCtx)
Robert Kroeger362ff892014-09-29 14:23:47 -07001468
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001469 // Claim the devicemanager with selfCtx as root/self/alice
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001470 if err := deviceStub.Claim(selfCtx, &granter{p: veyron2.GetPrincipal(selfCtx), extension: "alice"}); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001471 t.Fatal(err)
1472 }
1473
Bogdan Caprita2b219362014-12-09 17:03:33 -08001474 // Start an instance of the app but this time it should fail: we do not
1475 // have an associated uname for the invoking identity.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001476 startAppExpectError(t, selfCtx, appID, verror.NoAccess.ID)
Robert Kroeger362ff892014-09-29 14:23:47 -07001477
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001478 // Create an association for selfCtx
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001479 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/self"}, testUserName); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001480 t.Fatalf("AssociateAccount failed %v", err)
1481 }
1482
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001483 instance1ID := startApp(t, selfCtx, appID)
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001484 verifyPingArgs(t, pingCh, testUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001485 stopApp(t, selfCtx, appID, instance1ID)
Robert Kroeger362ff892014-09-29 14:23:47 -07001486
1487 vlog.VI(2).Infof("other attempting to run an app without access. Should fail.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001488 startAppExpectError(t, otherCtx, appID, verror.NoAccess.ID)
Robert Kroeger362ff892014-09-29 14:23:47 -07001489
Robert Kroegeracc778b2014-11-03 17:17:21 -08001490 // Self will now let other also install apps.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001491 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/other"}, testUserName); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001492 t.Fatalf("AssociateAccount failed %v", err)
1493 }
1494 // Add Start to the ACL list for root/other.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001495 newACL, _, err := deviceStub.GetACL(selfCtx)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001496 if err != nil {
1497 t.Fatalf("GetACL failed %v", err)
1498 }
Asim Shankar68885192014-11-26 12:48:35 -08001499 newACL.Add("root/other", string(access.Write))
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001500 if err := deviceStub.SetACL(selfCtx, newACL, ""); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001501 t.Fatalf("SetACL failed %v", err)
1502 }
1503
Bogdan Caprita2b219362014-12-09 17:03:33 -08001504 // With the introduction of per installation and per instance ACLs,
1505 // while other now has administrator permissions on the device manager,
1506 // other doesn't have execution permissions for the app. So this will
1507 // fail.
Robert Kroegeracc778b2014-11-03 17:17:21 -08001508 vlog.VI(2).Infof("other attempting to run an app still without access. Should fail.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001509 startAppExpectError(t, otherCtx, appID, verror.NoAccess.ID)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001510
1511 // But self can give other permissions to start applications.
1512 vlog.VI(2).Infof("self attempting to give other permission to start %s", appID)
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001513 newACL, _, err = appStub(appID).GetACL(selfCtx)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001514 if err != nil {
1515 t.Fatalf("GetACL on appID: %v failed %v", appID, err)
1516 }
Asim Shankar68885192014-11-26 12:48:35 -08001517 newACL.Add("root/other", string(access.Read))
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001518 if err = appStub(appID).SetACL(selfCtx, newACL, ""); err != nil {
Robert Kroegeracc778b2014-11-03 17:17:21 -08001519 t.Fatalf("SetACL on appID: %v failed: %v", appID, err)
1520 }
1521
Robert Kroeger362ff892014-09-29 14:23:47 -07001522 vlog.VI(2).Infof("other attempting to run an app with access. Should succeed.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001523 instance2ID := startApp(t, otherCtx, appID)
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001524 verifyPingArgs(t, pingCh, testUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001525 suspendApp(t, otherCtx, appID, instance2ID)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001526
1527 vlog.VI(2).Infof("Verify that Resume with the same systemName works.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001528 resumeApp(t, otherCtx, appID, instance2ID)
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001529 verifyPingArgs(t, pingCh, testUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001530 suspendApp(t, otherCtx, appID, instance2ID)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001531
Robert Kroegeracc778b2014-11-03 17:17:21 -08001532 vlog.VI(2).Infof("Verify that other can install and run applications.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001533 otherAppID := installApp(t, otherCtx)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001534
1535 vlog.VI(2).Infof("other attempting to run an app that other installed. Should succeed.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001536 instance4ID := startApp(t, otherCtx, otherAppID)
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001537 verifyPingArgs(t, pingCh, testUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Robert Kroegeracc778b2014-11-03 17:17:21 -08001538
1539 // Clean up.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001540 stopApp(t, otherCtx, otherAppID, instance4ID)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001541
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001542 // Change the associated system name.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001543 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/other"}, anotherTestUserName); err != nil {
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001544 t.Fatalf("AssociateAccount failed %v", err)
1545 }
1546
1547 vlog.VI(2).Infof("Show that Resume with a different systemName fails.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001548 resumeAppExpectError(t, otherCtx, appID, instance2ID, verror.NoAccess.ID)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001549
1550 // Clean up.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001551 stopApp(t, otherCtx, appID, instance2ID)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001552
1553 vlog.VI(2).Infof("Show that Start with different systemName works.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001554 instance3ID := startApp(t, otherCtx, appID)
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001555 verifyPingArgs(t, pingCh, anotherTestUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001556
1557 // Clean up.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001558 stopApp(t, otherCtx, appID, instance3ID)
Robert Kroeger362ff892014-09-29 14:23:47 -07001559}