blob: 0a3bccdca656922d623535993119d2c7d6be01c6 [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Bogdan Caprita5420f172014-10-10 15:58:14 -07005// TODO(caprita): This file is becoming unmanageable; split into several test
6// files.
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -07007// TODO(rjkroege): Add a more extensive unit test case to exercise AccessList logic.
Bogdan Caprita5420f172014-10-10 15:58:14 -07008
Jiri Simsa70c32052014-06-18 11:38:21 -07009package impl_test
Jiri Simsa5293dcb2014-05-10 09:56:38 -070010
11import (
Bogdan Caprita1e379132014-08-03 23:02:31 -070012 "crypto/md5"
13 "encoding/base64"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070014 "fmt"
Jiri Simsa70c32052014-06-18 11:38:21 -070015 "io/ioutil"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070016 "os"
Robin Thellend9e523a62014-10-07 16:19:53 -070017 "path"
Jiri Simsa70c32052014-06-18 11:38:21 -070018 "path/filepath"
Robin Thellend09929f42014-10-01 10:18:13 -070019 "reflect"
Jiri Simsa70c32052014-06-18 11:38:21 -070020 "strings"
Bogdan Caprita78b62162014-08-21 15:35:08 -070021 "syscall"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070022 "testing"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070023 "time"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070024
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070025 "v.io/x/lib/vlog"
26
Jiri Simsa6ac95222015-02-23 16:11:49 -080027 "v.io/v23"
28 "v.io/v23/context"
Jiri Simsa6ac95222015-02-23 16:11:49 -080029 "v.io/v23/naming"
30 "v.io/v23/security"
Todd Wang387d8a42015-03-30 17:09:05 -070031 "v.io/v23/security/access"
Todd Wang94c9d0b2015-04-01 14:27:00 -070032 "v.io/v23/services/application"
33 "v.io/v23/services/device"
34 "v.io/v23/services/repository"
Jiri Simsa6ac95222015-02-23 16:11:49 -080035 "v.io/v23/verror"
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070036
Asim Shankar59b8b692015-03-30 01:23:36 -070037 "v.io/x/ref/envvar"
Todd Wang712eeef2015-04-03 17:13:50 -070038 "v.io/x/ref/lib/mgmt"
Todd Wangcd4b3cc2015-04-06 16:42:02 -070039 "v.io/x/ref/services/device/internal/config"
40 "v.io/x/ref/services/device/internal/impl"
Robert Kroeger22fcb032015-04-30 07:40:11 -070041 "v.io/x/ref/services/device/internal/impl/utiltest"
Todd Wangfb939032015-04-08 16:42:44 -070042 "v.io/x/ref/services/internal/binarylib"
Todd Wang5fc36442015-04-07 15:15:27 -070043 "v.io/x/ref/services/internal/servicetest"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070044 "v.io/x/ref/test"
45 "v.io/x/ref/test/expect"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070046 "v.io/x/ref/test/testutil"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070047)
48
Suharsh Sivakumar9d17e4a2015-02-02 22:42:16 -080049func TestMain(m *testing.M) {
Robert Kroegeref27d6e2015-05-01 16:58:59 -070050 utiltest.TestMainImpl(m)
Suharsh Sivakumar9d17e4a2015-02-02 22:42:16 -080051}
52
Robert Kroegerdd07b362014-09-18 17:34:42 -070053// TestSuidHelper is testing boilerplate for suidhelper that does not
Suharsh Sivakumard1cc6e02015-03-16 13:58:49 -070054// create a runtime because the suidhelper is not a Vanadium application.
Robert Kroegerdd07b362014-09-18 17:34:42 -070055func TestSuidHelper(t *testing.T) {
Robert Kroegeref27d6e2015-05-01 16:58:59 -070056 utiltest.TestSuidHelperImpl(t)
Arup Mukherjee746444f2015-04-16 19:13:24 -070057}
58
Bogdan Caprita2b219362014-12-09 17:03:33 -080059// TODO(rjkroege): generateDeviceManagerScript and generateSuidHelperScript have
60// code similarity that might benefit from refactoring.
61// generateDeviceManagerScript is very similar in behavior to generateScript in
Bogdan Capritaa456f472014-12-10 10:18:03 -080062// device_invoker.go. However, we chose to re-implement it here for two
63// reasons: (1) avoid making generateScript public; and (2) how the test choses
64// to invoke the device manager subprocess the first time should be independent
65// of how device manager implementation sets up its updated versions.
Bogdan Caprita2b219362014-12-09 17:03:33 -080066func generateDeviceManagerScript(t *testing.T, root string, args, env []string) string {
Bogdan Capritafffcc972015-04-17 17:57:09 -070067 env = impl.VanadiumEnvironment(env)
Bogdan Capritac87a9142014-07-21 10:38:13 -070068 output := "#!/bin/bash\n"
Bogdan Caprita069341a2014-12-09 22:59:17 -080069 output += strings.Join(config.QuoteEnv(env), " ") + " exec "
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070070 output += strings.Join(args, " ")
Bogdan Capritac87a9142014-07-21 10:38:13 -070071 if err := os.MkdirAll(filepath.Join(root, "factory"), 0755); err != nil {
72 t.Fatalf("MkdirAll failed: %v", err)
73 }
74 // Why pigeons? To show that the name we choose for the initial script
Bogdan Caprita2b219362014-12-09 17:03:33 -080075 // doesn't matter and in particular is independent of how device manager
76 // names its updated version scripts (deviced.sh).
Bogdan Capritac87a9142014-07-21 10:38:13 -070077 path := filepath.Join(root, "factory", "pigeons.sh")
78 if err := ioutil.WriteFile(path, []byte(output), 0755); err != nil {
79 t.Fatalf("WriteFile(%v) failed: %v", path, err)
80 }
81 return path
82}
83
Bogdan Caprita2b219362014-12-09 17:03:33 -080084// TestDeviceManagerUpdateAndRevert makes the device manager go through the
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070085// motions of updating itself to newer versions (twice), and reverting itself
86// back (twice). It also checks that update and revert fail when they're
Bogdan Caprita2b050322015-04-17 09:04:03 -070087// supposed to. The initial device manager is running 'by hand' via a module
88// command. Further versions are running through the soft link that the device
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070089// manager itself updates.
Bogdan Caprita2b219362014-12-09 17:03:33 -080090func TestDeviceManagerUpdateAndRevert(t *testing.T) {
Robert Kroeger6e2efd92015-05-01 18:47:28 -070091 ctx, shutdown := utiltest.InitForTest()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080092 defer shutdown()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -080093
Todd Wang5fc36442015-04-07 15:15:27 -070094 sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, v23.GetPrincipal(ctx))
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -070095 defer deferFn()
96
97 // Set up mock application and binary repositories.
Robert Kroeger22fcb032015-04-30 07:40:11 -070098 envelope, cleanup := utiltest.StartMockRepos(t, ctx)
Bogdan Capritac87a9142014-07-21 10:38:13 -070099 defer cleanup()
Bogdan Capritac87a9142014-07-21 10:38:13 -0700100
Todd Wang5fc36442015-04-07 15:15:27 -0700101 root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
Bogdan Caprita080a7302014-08-20 15:35:37 -0700102 defer cleanup()
Arup Mukherjee31b77c82015-03-04 10:48:33 -0800103 if err := impl.SaveCreatorInfo(root); err != nil {
104 t.Fatal(err)
105 }
Jiri Simsae0fc61a2014-07-30 14:41:55 -0700106
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700107 // Current link does not have to live in the root dir, but it's
108 // convenient to put it there so we have everything in one place.
109 currLink := filepath.Join(root, "current_link")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700110
Bogdan Caprita2b050322015-04-17 09:04:03 -0700111 // Since the device manager will be restarting, use the
Asim Shankar23dac322015-02-14 12:42:26 -0800112 // VeyronCredentials environment variable to maintain the same set of
113 // credentials across runs.
114 // Without this, authentication/authorizatin state - such as the blessings
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700115 // of the device manager and the signatures used for AccessList integrity checks
Asim Shankar23dac322015-02-14 12:42:26 -0800116 // - will not carry over between updates to the binary, which would not
117 // be reflective of intended use.
118 dmCreds, err := ioutil.TempDir("", "TestDeviceManagerUpdateAndRevert")
119 if err != nil {
120 t.Fatal(err)
121 }
122 defer os.RemoveAll(dmCreds)
Asim Shankar59b8b692015-03-30 01:23:36 -0700123 dmEnv := []string{fmt.Sprintf("%v=%v", envvar.Credentials, dmCreds)}
Robert Kroeger22fcb032015-04-30 07:40:11 -0700124 dmArgs := []string{"factoryDM", root, "unused_helper", utiltest.MockApplicationRepoName, currLink}
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700125 args, env := sh.CommandEnvelope(utiltest.DeviceManagerCmd, dmEnv, dmArgs...)
Bogdan Caprita2b219362014-12-09 17:03:33 -0800126 scriptPathFactory := generateDeviceManagerScript(t, root, args, env)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700127
128 if err := os.Symlink(scriptPathFactory, currLink); err != nil {
129 t.Fatalf("Symlink(%q, %q) failed: %v", scriptPathFactory, currLink, err)
130 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700131
Bogdan Caprita2b219362014-12-09 17:03:33 -0800132 // We instruct the initial device manager that we run to pause before
Bogdan Capritac87a9142014-07-21 10:38:13 -0700133 // stopping its service, so that we get a chance to verify that
134 // attempting an update while another one is ongoing will fail.
Asim Shankar23dac322015-02-14 12:42:26 -0800135 dmPauseBeforeStopEnv := append(dmEnv, "PAUSE_BEFORE_STOP=1")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700136
Bogdan Caprita2b219362014-12-09 17:03:33 -0800137 // Start the initial version of the device manager, the so-called
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700138 // "factory" version. We use the modules-generated command to start it.
Bogdan Caprita2b219362014-12-09 17:03:33 -0800139 // We could have also used the scriptPathFactory to start it, but this
Bogdan Caprita2b050322015-04-17 09:04:03 -0700140 // demonstrates that the initial device manager could be running by hand
Bogdan Caprita2b219362014-12-09 17:03:33 -0800141 // as long as the right initial configuration is passed into the device
142 // manager implementation.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700143 dmh := servicetest.RunCommand(t, sh, dmPauseBeforeStopEnv, utiltest.DeviceManagerCmd, dmArgs...)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700144 defer func() {
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800145 syscall.Kill(dmh.Pid(), syscall.SIGINT)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700146 utiltest.VerifyNoRunningProcesses(t)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700147 }()
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700148
Todd Wang5fc36442015-04-07 15:15:27 -0700149 servicetest.ReadPID(t, dmh)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700150 utiltest.Resolve(t, ctx, "claimable", 1)
Asim Shankar23dac322015-02-14 12:42:26 -0800151 // Brand new device manager must be claimed first.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700152 utiltest.ClaimDevice(t, ctx, "claimable", "factoryDM", "mydevice", utiltest.NoPairingToken)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700153 // Simulate an invalid envelope in the application repository.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700154 *envelope = utiltest.EnvelopeFromShell(sh, dmPauseBeforeStopEnv, utiltest.DeviceManagerCmd, "bogus", dmArgs...)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700155
Robert Kroeger22fcb032015-04-30 07:40:11 -0700156 utiltest.UpdateDeviceExpectError(t, ctx, "factoryDM", impl.ErrAppTitleMismatch.ID)
157 utiltest.RevertDeviceExpectError(t, ctx, "factoryDM", impl.ErrUpdateNoOp.ID)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700158
Bogdan Caprita2b219362014-12-09 17:03:33 -0800159 // Set up a second version of the device manager. The information in the
160 // envelope will be used by the device manager to stage the next
161 // version.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700162 *envelope = utiltest.EnvelopeFromShell(sh, dmEnv, utiltest.DeviceManagerCmd, application.DeviceManagerTitle, "v2DM")
Robert Kroeger22fcb032015-04-30 07:40:11 -0700163 utiltest.UpdateDevice(t, ctx, "factoryDM")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700164
165 // Current link should have been updated to point to v2.
166 evalLink := func() string {
167 path, err := filepath.EvalSymlinks(currLink)
168 if err != nil {
169 t.Fatalf("EvalSymlinks(%v) failed: %v", currLink, err)
170 }
171 return path
172 }
173 scriptPathV2 := evalLink()
174 if scriptPathFactory == scriptPathV2 {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700175 t.Fatalf("current link didn't change")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700176 }
177
Robert Kroeger22fcb032015-04-30 07:40:11 -0700178 utiltest.UpdateDeviceExpectError(t, ctx, "factoryDM", impl.ErrOperationInProgress.ID)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700179
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800180 dmh.CloseStdin()
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700181
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700182 dmh.Expect("restart handler")
183 dmh.Expect("factoryDM terminated")
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800184 dmh.Shutdown(os.Stderr, os.Stderr)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700185
Bogdan Caprita2b219362014-12-09 17:03:33 -0800186 // A successful update means the device manager has stopped itself. We
Bogdan Capritac87a9142014-07-21 10:38:13 -0700187 // relaunch it from the current link.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700188 utiltest.ResolveExpectNotFound(t, ctx, "v2DM") // Ensure a clean slate.
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700189
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700190 dmh = servicetest.RunCommand(t, sh, dmEnv, utiltest.ExecScriptCmd, currLink)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700191
Todd Wang5fc36442015-04-07 15:15:27 -0700192 servicetest.ReadPID(t, dmh)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700193 utiltest.Resolve(t, ctx, "v2DM", 1) // Current link should have been launching v2.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700194
Bogdan Caprita2b219362014-12-09 17:03:33 -0800195 // Try issuing an update without changing the envelope in the
196 // application repository: this should fail, and current link should be
197 // unchanged.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700198 utiltest.UpdateDeviceExpectError(t, ctx, "v2DM", impl.ErrUpdateNoOp.ID)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700199 if evalLink() != scriptPathV2 {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700200 t.Fatalf("script changed")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700201 }
202
Adam Sadovskyb1f9e3c2015-04-08 11:03:49 -0700203 // Try issuing an update with a binary that has a different major version
204 // number. It should fail.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700205 utiltest.ResolveExpectNotFound(t, ctx, "v2.5DM") // Ensure a clean slate.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700206 *envelope = utiltest.EnvelopeFromShell(sh, dmEnv, utiltest.DeviceManagerV10Cmd, application.DeviceManagerTitle, "v2.5DM")
Robert Kroeger22fcb032015-04-30 07:40:11 -0700207 utiltest.UpdateDeviceExpectError(t, ctx, "v2DM", impl.ErrOperationFailed.ID)
Arup Mukherjee31b77c82015-03-04 10:48:33 -0800208
Arup Mukherjee045a5552015-03-12 11:10:05 -0700209 if evalLink() != scriptPathV2 {
210 t.Fatalf("script changed")
Arup Mukherjee31b77c82015-03-04 10:48:33 -0800211 }
212
Bogdan Caprita2b219362014-12-09 17:03:33 -0800213 // Create a third version of the device manager and issue an update.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700214 *envelope = utiltest.EnvelopeFromShell(sh, dmEnv, utiltest.DeviceManagerCmd, application.DeviceManagerTitle, "v3DM")
Robert Kroeger22fcb032015-04-30 07:40:11 -0700215 utiltest.UpdateDevice(t, ctx, "v2DM")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700216
217 scriptPathV3 := evalLink()
218 if scriptPathV3 == scriptPathV2 {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700219 t.Fatalf("current link didn't change")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700220 }
221
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700222 dmh.Expect("restart handler")
223 dmh.Expect("v2DM terminated")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700224
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800225 dmh.Shutdown(os.Stderr, os.Stderr)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700226
Robert Kroeger22fcb032015-04-30 07:40:11 -0700227 utiltest.ResolveExpectNotFound(t, ctx, "v3DM") // Ensure a clean slate.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700228
Bogdan Caprita2b219362014-12-09 17:03:33 -0800229 // Re-lanuch the device manager from current link. We instruct the
230 // device manager to pause before stopping its server, so that we can
231 // verify that a second revert fails while a revert is in progress.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700232 dmh = servicetest.RunCommand(t, sh, dmPauseBeforeStopEnv, utiltest.ExecScriptCmd, currLink)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700233
Todd Wang5fc36442015-04-07 15:15:27 -0700234 servicetest.ReadPID(t, dmh)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700235 utiltest.Resolve(t, ctx, "v3DM", 1) // Current link should have been launching v3.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700236
Bogdan Caprita2b219362014-12-09 17:03:33 -0800237 // Revert the device manager to its previous version (v2).
Robert Kroeger22fcb032015-04-30 07:40:11 -0700238 utiltest.RevertDevice(t, ctx, "v3DM")
239 utiltest.RevertDeviceExpectError(t, ctx, "v3DM", impl.ErrOperationInProgress.ID) // Revert already in progress.
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800240 dmh.CloseStdin()
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700241 dmh.Expect("restart handler")
242 dmh.Expect("v3DM terminated")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700243 if evalLink() != scriptPathV2 {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700244 t.Fatalf("current link was not reverted correctly")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700245 }
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800246 dmh.Shutdown(os.Stderr, os.Stderr)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700247
Robert Kroeger22fcb032015-04-30 07:40:11 -0700248 utiltest.ResolveExpectNotFound(t, ctx, "v2DM") // Ensure a clean slate.
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700249
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700250 dmh = servicetest.RunCommand(t, sh, dmEnv, utiltest.ExecScriptCmd, currLink)
Todd Wang5fc36442015-04-07 15:15:27 -0700251 servicetest.ReadPID(t, dmh)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700252 utiltest.Resolve(t, ctx, "v2DM", 1) // Current link should have been launching v2.
Bogdan Capritac87a9142014-07-21 10:38:13 -0700253
Bogdan Caprita2b219362014-12-09 17:03:33 -0800254 // Revert the device manager to its previous version (factory).
Robert Kroeger22fcb032015-04-30 07:40:11 -0700255 utiltest.RevertDevice(t, ctx, "v2DM")
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700256 dmh.Expect("restart handler")
257 dmh.Expect("v2DM terminated")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700258 if evalLink() != scriptPathFactory {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700259 t.Fatalf("current link was not reverted correctly")
Bogdan Capritac87a9142014-07-21 10:38:13 -0700260 }
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800261 dmh.Shutdown(os.Stderr, os.Stderr)
Bogdan Capritac87a9142014-07-21 10:38:13 -0700262
Robert Kroeger22fcb032015-04-30 07:40:11 -0700263 utiltest.ResolveExpectNotFound(t, ctx, "factoryDM") // Ensure a clean slate.
Robert Kroegerebfb62a2014-12-10 14:42:09 -0800264
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700265 dmh = servicetest.RunCommand(t, sh, dmEnv, utiltest.ExecScriptCmd, currLink)
Todd Wang5fc36442015-04-07 15:15:27 -0700266 servicetest.ReadPID(t, dmh)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700267 utiltest.Resolve(t, ctx, "factoryDM", 1) // Current link should have been launching factory version.
268 utiltest.ShutdownDevice(t, ctx, "factoryDM")
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700269 dmh.Expect("factoryDM terminated")
270 dmh.ExpectEOF()
Bogdan Caprita4ea9b032014-12-27 14:56:51 -0800271
Bogdan Caprita2b050322015-04-17 09:04:03 -0700272 // Re-launch the device manager, to exercise the behavior of Stop.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700273 utiltest.ResolveExpectNotFound(t, ctx, "factoryDM") // Ensure a clean slate.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700274 dmh = servicetest.RunCommand(t, sh, dmEnv, utiltest.ExecScriptCmd, currLink)
Todd Wang5fc36442015-04-07 15:15:27 -0700275 servicetest.ReadPID(t, dmh)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700276 utiltest.Resolve(t, ctx, "factoryDM", 1)
277 utiltest.KillDevice(t, ctx, "factoryDM")
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700278 dmh.Expect("restart handler")
279 dmh.Expect("factoryDM terminated")
280 dmh.ExpectEOF()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700281}
Bogdan Caprita1e379132014-08-03 23:02:31 -0700282
Robert Kroeger124a04f2015-02-03 17:32:32 -0800283func instanceDirForApp(root, appID, instanceID string) string {
Bogdan Caprita1e379132014-08-03 23:02:31 -0700284 applicationDirName := func(title string) string {
285 h := md5.New()
286 h.Write([]byte(title))
287 hash := strings.TrimRight(base64.URLEncoding.EncodeToString(h.Sum(nil)), "=")
288 return "app-" + hash
289 }
290 components := strings.Split(appID, "/")
291 appTitle, installationID := components[0], components[1]
Robert Kroeger124a04f2015-02-03 17:32:32 -0800292 return filepath.Join(root, applicationDirName(appTitle), "installation-"+installationID, "instances", "instance-"+instanceID)
293}
294
295func verifyAppWorkspace(t *testing.T, root, appID, instanceID string) {
296 // HACK ALERT: for now, we peek inside the device manager's directory
297 // structure (which ought to be opaque) to check for what the app has
298 // written to its local root.
299 //
300 // TODO(caprita): add support to device manager to browse logs/app local
301 // root.
302 rootDir := filepath.Join(instanceDirForApp(root, appID, instanceID), "root")
Bogdan Caprita1e379132014-08-03 23:02:31 -0700303 testFile := filepath.Join(rootDir, "testfile")
304 if read, err := ioutil.ReadFile(testFile); err != nil {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700305 t.Fatalf("Failed to read %v: %v", testFile, err)
Bogdan Caprita1e379132014-08-03 23:02:31 -0700306 } else if want, got := "goodbye world", string(read); want != got {
Jiri Simsa6351ee72014-08-18 16:44:41 -0700307 t.Fatalf("Expected to read %v, got %v instead", want, got)
Bogdan Caprita1e379132014-08-03 23:02:31 -0700308 }
309 // END HACK
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700310}
Bogdan Caprita78b62162014-08-21 15:35:08 -0700311
Bogdan Caprita2b050322015-04-17 09:04:03 -0700312// TestLifeOfAnApp installs an app, instantiates, runs, kills, and deletes
313// several instances, and performs updates.
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700314func TestLifeOfAnApp(t *testing.T) {
Robert Kroeger6e2efd92015-05-01 18:47:28 -0700315 ctx, shutdown := utiltest.InitForTest()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800316 defer shutdown()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800317
Todd Wang5fc36442015-04-07 15:15:27 -0700318 sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700319 defer deferFn()
320
321 // Set up mock application and binary repositories.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700322 envelope, cleanup := utiltest.StartMockRepos(t, ctx)
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700323 defer cleanup()
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700324
Todd Wang5fc36442015-04-07 15:15:27 -0700325 root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700326 defer cleanup()
Arup Mukherjee31b77c82015-03-04 10:48:33 -0800327 if err := impl.SaveCreatorInfo(root); err != nil {
328 t.Fatal(err)
329 }
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700330
Robert Kroegerdd07b362014-09-18 17:34:42 -0700331 // Create a script wrapping the test target that implements suidhelper.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700332 helperPath := utiltest.GenerateSuidHelperScript(t, root)
Robert Kroegerdd07b362014-09-18 17:34:42 -0700333
Bogdan Caprita2b219362014-12-09 17:03:33 -0800334 // Set up the device manager. Since we won't do device manager updates,
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700335 // don't worry about its application envelope and current link.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700336 dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
Todd Wang5fc36442015-04-07 15:15:27 -0700337 servicetest.ReadPID(t, dmh)
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700338 utiltest.ClaimDevice(t, ctx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700339
340 // Create the local server that the app uses to let us know it's ready.
Robert Kroeger658e0912015-04-30 10:30:57 -0700341 pingCh, cleanup := utiltest.SetupPingServer(t, ctx)
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700342 defer cleanup()
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700343
Robert Kroeger22fcb032015-04-30 07:40:11 -0700344 utiltest.Resolve(t, ctx, "pingserver", 1)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700345
Bogdan Capritabce0a632014-09-03 16:15:26 -0700346 // Create an envelope for a first version of the app.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700347 *envelope = utiltest.EnvelopeFromShell(sh, []string{utiltest.TestEnvVarName + "=env-val-envelope"}, utiltest.AppCmd, "google naps", fmt.Sprintf("--%s=flag-val-envelope", utiltest.TestFlagName), "appV1")
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700348
Bogdan Caprita17666dd2015-01-14 09:27:46 -0800349 // Install the app. The config-specified flag value for testFlagName
Bogdan Caprita8964d3f2015-02-02 13:47:39 -0800350 // should override the value specified in the envelope above, and the
351 // config-specified value for origin should override the value in the
352 // Install rpc argument.
Asim Shankar59b8b692015-03-30 01:23:36 -0700353 mtName, ok := sh.GetVar(envvar.NamespacePrefix)
Bogdan Caprita8964d3f2015-02-02 13:47:39 -0800354 if !ok {
355 t.Fatalf("failed to get namespace root var from shell")
356 }
357 // This rooted name should be equivalent to the relative name "ar", but
358 // we want to test that the config override for origin works.
359 rootedAppRepoName := naming.Join(mtName, "ar")
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700360 appID := utiltest.InstallApp(t, ctx, device.Config{utiltest.TestFlagName: "flag-val-install", mgmt.AppOriginConfigKey: rootedAppRepoName})
Robert Kroeger22fcb032015-04-30 07:40:11 -0700361 v1 := utiltest.VerifyState(t, ctx, device.InstallationStateActive, appID)
362 installationDebug := utiltest.Debug(t, ctx, appID)
Bogdan Capritad8373a12015-01-28 19:52:37 -0800363 // We spot-check a couple pieces of information we expect in the debug
364 // output.
365 // TODO(caprita): Is there a way to verify more without adding brittle
366 // logic that assumes too much about the format? This may be one
367 // argument in favor of making the output of Debug a struct instead of
368 // free-form string.
Bogdan Caprita8964d3f2015-02-02 13:47:39 -0800369 if !strings.Contains(installationDebug, fmt.Sprintf("Origin: %v", rootedAppRepoName)) {
Bogdan Capritad8373a12015-01-28 19:52:37 -0800370 t.Fatalf("debug response doesn't contain expected info: %v", installationDebug)
371 }
372 if !strings.Contains(installationDebug, "Config: map[random_test_flag:flag-val-install]") {
373 t.Fatalf("debug response doesn't contain expected info: %v", installationDebug)
374 }
Bogdan Caprita730bde12014-11-08 15:35:43 -0800375
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700376 // Start requires the caller to bless the app instance.
Robin Thellend3480f8e2015-03-13 09:50:41 -0700377 expectedErr := "bless failed"
Robert Kroeger22fcb032015-04-30 07:40:11 -0700378 if _, err := utiltest.LaunchAppImpl(t, ctx, appID, ""); err == nil || err.Error() != expectedErr {
Robin Thellend3480f8e2015-03-13 09:50:41 -0700379 t.Fatalf("Start(%v) expected to fail with %v, got %v instead", appID, expectedErr, err)
Bogdan Caprita730bde12014-11-08 15:35:43 -0800380 }
381
Bogdan Capritabce0a632014-09-03 16:15:26 -0700382 // Start an instance of the app.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700383 instance1ID := utiltest.LaunchApp(t, ctx, appID)
384 if v := utiltest.VerifyState(t, ctx, device.InstanceStateRunning, appID, instance1ID); v != v1 {
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700385 t.Fatalf("Instance version expected to be %v, got %v instead", v1, v)
386 }
Robert Kroeger627a1152014-10-01 14:57:55 -0700387
Robert Kroeger22fcb032015-04-30 07:40:11 -0700388 instanceDebug := utiltest.Debug(t, ctx, appID, instance1ID)
Suharsh Sivakumar4bbe8ed2015-04-09 14:21:44 -0700389 // Verify the apps default blessings.
390 if !strings.Contains(instanceDebug, fmt.Sprintf("Default Blessings %s/forapp", test.TestBlessing)) {
Bogdan Capritad8373a12015-01-28 19:52:37 -0800391 t.Fatalf("debug response doesn't contain expected info: %v", instanceDebug)
392 }
393
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700394 // Wait until the app pings us that it's ready.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700395 pingCh.VerifyPingArgs(t, utiltest.UserName(t), "flag-val-install", "env-val-envelope")
Robert Kroeger627a1152014-10-01 14:57:55 -0700396
Robert Kroeger22fcb032015-04-30 07:40:11 -0700397 v1EP1 := utiltest.Resolve(t, ctx, "appV1", 1)[0]
Bogdan Capritabce0a632014-09-03 16:15:26 -0700398
Bogdan Caprita2b050322015-04-17 09:04:03 -0700399 // Stop the app instance.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700400 utiltest.KillApp(t, ctx, appID, instance1ID)
401 utiltest.VerifyState(t, ctx, device.InstanceStateNotRunning, appID, instance1ID)
402 utiltest.ResolveExpectNotFound(t, ctx, "appV1")
Bogdan Capritabce0a632014-09-03 16:15:26 -0700403
Robert Kroeger22fcb032015-04-30 07:40:11 -0700404 utiltest.RunApp(t, ctx, appID, instance1ID)
405 utiltest.VerifyState(t, ctx, device.InstanceStateRunning, appID, instance1ID)
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700406 pingCh.VerifyPingArgs(t, utiltest.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 -0700407 oldV1EP1 := v1EP1
Robert Kroeger22fcb032015-04-30 07:40:11 -0700408 if v1EP1 = utiltest.Resolve(t, ctx, "appV1", 1)[0]; v1EP1 == oldV1EP1 {
Bogdan Caprita2b050322015-04-17 09:04:03 -0700409 t.Fatalf("Expected a new endpoint for the app after kill/run")
Bogdan Capritabce0a632014-09-03 16:15:26 -0700410 }
411
412 // Start a second instance.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700413 instance2ID := utiltest.LaunchApp(t, ctx, appID)
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700414 pingCh.VerifyPingArgs(t, utiltest.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 -0700415
Bogdan Capritabce0a632014-09-03 16:15:26 -0700416 // There should be two endpoints mounted as "appV1", one for each
417 // instance of the app.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700418 endpoints := utiltest.Resolve(t, ctx, "appV1", 2)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700419 v1EP2 := endpoints[0]
420 if endpoints[0] == v1EP1 {
421 v1EP2 = endpoints[1]
422 if v1EP2 == v1EP1 {
423 t.Fatalf("Both endpoints are the same")
424 }
425 } else if endpoints[1] != v1EP1 {
426 t.Fatalf("Second endpoint should have been v1EP1: %v, %v", endpoints, v1EP1)
427 }
Bogdan Caprita268b4192014-08-28 10:04:44 -0700428
Bogdan Caprita2b050322015-04-17 09:04:03 -0700429 // TODO(caprita): verify various non-standard combinations (kill when
430 // canceled; run while still running).
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700431
Bogdan Caprita2b050322015-04-17 09:04:03 -0700432 // Kill the first instance.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700433 utiltest.KillApp(t, ctx, appID, instance1ID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700434 // Only the second instance should still be running and mounted.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700435 if want, got := v1EP2, utiltest.Resolve(t, ctx, "appV1", 1)[0]; want != got {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700436 t.Fatalf("Resolve(%v): want: %v, got %v", "appV1", want, got)
437 }
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700438
Bogdan Capritabce0a632014-09-03 16:15:26 -0700439 // Updating the installation to itself is a no-op.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700440 utiltest.UpdateAppExpectError(t, ctx, appID, impl.ErrUpdateNoOp.ID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700441
442 // Updating the installation should not work with a mismatched title.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700443 *envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "bogus")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700444
Robert Kroeger22fcb032015-04-30 07:40:11 -0700445 utiltest.UpdateAppExpectError(t, ctx, appID, impl.ErrAppTitleMismatch.ID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700446
447 // Create a second version of the app and update the app to it.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700448 *envelope = utiltest.EnvelopeFromShell(sh, []string{utiltest.TestEnvVarName + "=env-val-envelope"}, utiltest.AppCmd, "google naps", "appV2")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700449
Robert Kroeger22fcb032015-04-30 07:40:11 -0700450 utiltest.UpdateApp(t, ctx, appID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700451
Robert Kroeger22fcb032015-04-30 07:40:11 -0700452 v2 := utiltest.VerifyState(t, ctx, device.InstallationStateActive, appID)
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700453 if v1 == v2 {
454 t.Fatalf("Version did not change for %v: %v", appID, v1)
455 }
456
Bogdan Capritabce0a632014-09-03 16:15:26 -0700457 // Second instance should still be running.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700458 if want, got := v1EP2, utiltest.Resolve(t, ctx, "appV1", 1)[0]; want != got {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700459 t.Fatalf("Resolve(%v): want: %v, got %v", "appV1", want, got)
460 }
Robert Kroeger22fcb032015-04-30 07:40:11 -0700461 if v := utiltest.VerifyState(t, ctx, device.InstanceStateRunning, appID, instance2ID); v != v1 {
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700462 t.Fatalf("Instance version expected to be %v, got %v instead", v1, v)
463 }
Bogdan Capritabce0a632014-09-03 16:15:26 -0700464
465 // Resume first instance.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700466 utiltest.RunApp(t, ctx, appID, instance1ID)
467 if v := utiltest.VerifyState(t, ctx, device.InstanceStateRunning, appID, instance1ID); v != v1 {
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700468 t.Fatalf("Instance version expected to be %v, got %v instead", v1, v)
469 }
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700470 pingCh.VerifyPingArgs(t, utiltest.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 -0700471 // Both instances should still be running the first version of the app.
472 // Check that the mounttable contains two endpoints, one of which is
473 // v1EP2.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700474 endpoints = utiltest.Resolve(t, ctx, "appV1", 2)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700475 if endpoints[0] == v1EP2 {
476 if endpoints[1] == v1EP2 {
477 t.Fatalf("Both endpoints are the same")
478 }
479 } else if endpoints[1] != v1EP2 {
480 t.Fatalf("Second endpoint should have been v1EP2: %v, %v", endpoints, v1EP2)
481 }
482
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800483 // Trying to update first instance while it's running should fail.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700484 utiltest.UpdateInstanceExpectError(t, ctx, appID, instance1ID, impl.ErrInvalidOperation.ID)
Bogdan Caprita2b050322015-04-17 09:04:03 -0700485 // Stop first instance and try again.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700486 utiltest.KillApp(t, ctx, appID, instance1ID)
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800487 // Only the second instance should still be running and mounted.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700488 if want, got := v1EP2, utiltest.Resolve(t, ctx, "appV1", 1)[0]; want != got {
Bogdan Capritabce0a632014-09-03 16:15:26 -0700489 t.Fatalf("Resolve(%v): want: %v, got %v", "appV1", want, got)
490 }
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800491 // Update succeeds now.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700492 utiltest.UpdateInstance(t, ctx, appID, instance1ID)
493 if v := utiltest.VerifyState(t, ctx, device.InstanceStateNotRunning, appID, instance1ID); v != v2 {
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700494 t.Fatalf("Instance version expected to be %v, got %v instead", v2, v)
495 }
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800496 // Resume the first instance and verify it's running v2 now.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700497 utiltest.RunApp(t, ctx, appID, instance1ID)
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700498 pingCh.VerifyPingArgs(t, utiltest.UserName(t), "flag-val-install", "env-val-envelope")
Robert Kroeger22fcb032015-04-30 07:40:11 -0700499 utiltest.Resolve(t, ctx, "appV1", 1)
500 utiltest.Resolve(t, ctx, "appV2", 1)
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800501
502 // Stop first instance.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700503 utiltest.TerminateApp(t, ctx, appID, instance1ID)
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800504 verifyAppWorkspace(t, root, appID, instance1ID)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700505 utiltest.ResolveExpectNotFound(t, ctx, "appV2")
Bogdan Capritabce0a632014-09-03 16:15:26 -0700506
507 // Start a third instance.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700508 instance3ID := utiltest.LaunchApp(t, ctx, appID)
509 if v := utiltest.VerifyState(t, ctx, device.InstanceStateRunning, appID, instance3ID); v != v2 {
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700510 t.Fatalf("Instance version expected to be %v, got %v instead", v2, v)
511 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700512 // Wait until the app pings us that it's ready.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700513 pingCh.VerifyPingArgs(t, utiltest.UserName(t), "flag-val-install", "env-val-envelope")
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700514
Robert Kroeger22fcb032015-04-30 07:40:11 -0700515 utiltest.Resolve(t, ctx, "appV2", 1)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700516
517 // Stop second instance.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700518 utiltest.TerminateApp(t, ctx, appID, instance2ID)
519 utiltest.ResolveExpectNotFound(t, ctx, "appV1")
Bogdan Capritabce0a632014-09-03 16:15:26 -0700520
521 // Stop third instance.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700522 utiltest.TerminateApp(t, ctx, appID, instance3ID)
523 utiltest.ResolveExpectNotFound(t, ctx, "appV2")
Bogdan Caprita9a59b8c2014-08-22 14:21:10 -0700524
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700525 // Revert the app.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700526 utiltest.RevertApp(t, ctx, appID)
527 if v := utiltest.VerifyState(t, ctx, device.InstallationStateActive, appID); v != v1 {
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700528 t.Fatalf("Installation version expected to be %v, got %v instead", v1, v)
529 }
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700530
Bogdan Caprita2b050322015-04-17 09:04:03 -0700531 // Start a fourth instance. It should be running from version 1.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700532 instance4ID := utiltest.LaunchApp(t, ctx, appID)
533 if v := utiltest.VerifyState(t, ctx, device.InstanceStateRunning, appID, instance4ID); v != v1 {
Bogdan Capritab7f5d772015-03-24 16:37:59 -0700534 t.Fatalf("Instance version expected to be %v, got %v instead", v1, v)
535 }
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700536 pingCh.VerifyPingArgs(t, utiltest.UserName(t), "flag-val-install", "env-val-envelope") // Wait until the app pings us that it's ready.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700537 utiltest.Resolve(t, ctx, "appV1", 1)
538 utiltest.TerminateApp(t, ctx, appID, instance4ID)
539 utiltest.ResolveExpectNotFound(t, ctx, "appV1")
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700540
541 // We are already on the first version, no further revert possible.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700542 utiltest.RevertAppExpectError(t, ctx, appID, impl.ErrUpdateNoOp.ID)
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700543
Bogdan Caprita8c776b22014-08-28 17:29:07 -0700544 // Uninstall the app.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700545 utiltest.UninstallApp(t, ctx, appID)
546 utiltest.VerifyState(t, ctx, device.InstallationStateUninstalled, appID)
Bogdan Caprita8c776b22014-08-28 17:29:07 -0700547
Bogdan Capritabce0a632014-09-03 16:15:26 -0700548 // Updating the installation should no longer be allowed.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700549 utiltest.UpdateAppExpectError(t, ctx, appID, impl.ErrInvalidOperation.ID)
Bogdan Capritabce0a632014-09-03 16:15:26 -0700550
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700551 // Reverting the installation should no longer be allowed.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700552 utiltest.RevertAppExpectError(t, ctx, appID, impl.ErrInvalidOperation.ID)
Bogdan Caprita53b7b7e2014-09-03 20:51:16 -0700553
Bogdan Caprita8c776b22014-08-28 17:29:07 -0700554 // Starting new instances should no longer be allowed.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700555 utiltest.LaunchAppExpectError(t, ctx, appID, impl.ErrInvalidOperation.ID)
Bogdan Caprita8c776b22014-08-28 17:29:07 -0700556
Bogdan Caprita2b050322015-04-17 09:04:03 -0700557 // Make sure that Kill will actually kill an app that doesn't exit
558 // cleanly Do this by installing, instantiating, running, and killing
559 // hangingApp, which sleeps (rather than exits) after being asked to
560 // Stop()
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700561 *envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.HangingAppCmd, "hanging ap", "hAppV1")
Robert Kroeger22fcb032015-04-30 07:40:11 -0700562 hAppID := utiltest.InstallApp(t, ctx)
563 hInstanceID := utiltest.LaunchApp(t, ctx, hAppID)
Robert Kroeger658e0912015-04-30 10:30:57 -0700564 hangingPid := pingCh.WaitForPingArgs(t).Pid
Arup Mukherjee746444f2015-04-16 19:13:24 -0700565 if err := syscall.Kill(hangingPid, 0); err != nil && err != syscall.EPERM {
566 t.Fatalf("Pid of hanging app (%v) is not live", hangingPid)
567 }
Robert Kroeger22fcb032015-04-30 07:40:11 -0700568 utiltest.KillApp(t, ctx, hAppID, hInstanceID)
Arup Mukherjee746444f2015-04-16 19:13:24 -0700569 pidIsAlive := true
570 for i := 0; i < 10 && pidIsAlive; i++ {
571 if err := syscall.Kill(hangingPid, 0); err == nil || err == syscall.EPERM {
572 time.Sleep(time.Second) // pid is still alive
573 } else {
574 pidIsAlive = false
575 }
576 }
577 if pidIsAlive {
578 t.Fatalf("Pid of hanging app (%d) has not exited after Stop() call", hangingPid)
579 }
580
Bogdan Caprita2b219362014-12-09 17:03:33 -0800581 // Cleanly shut down the device manager.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700582 defer utiltest.VerifyNoRunningProcesses(t)
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800583 syscall.Kill(dmh.Pid(), syscall.SIGINT)
Cosmos Nicolaou42a17362015-03-10 16:40:18 -0700584 dmh.Expect("dm terminated")
585 dmh.ExpectEOF()
Bogdan Caprita1e379132014-08-03 23:02:31 -0700586}
Gautham82bb9952014-08-28 14:11:51 -0700587
gauthamtcb03d132015-02-05 18:05:22 -0800588func startRealBinaryRepository(t *testing.T, ctx *context.T, von string) func() {
Todd Wang1f7a6c62015-04-03 17:05:09 -0700589 rootDir, err := binarylib.SetupRootDir("")
Robin Thellend875f2592014-12-02 10:29:37 -0800590 if err != nil {
Todd Wang1f7a6c62015-04-03 17:05:09 -0700591 t.Fatalf("binarylib.SetupRootDir failed: %v", err)
Robin Thellend875f2592014-12-02 10:29:37 -0800592 }
Todd Wang1f7a6c62015-04-03 17:05:09 -0700593 state, err := binarylib.NewState(rootDir, "", 3)
Robin Thellend875f2592014-12-02 10:29:37 -0800594 if err != nil {
Todd Wang1f7a6c62015-04-03 17:05:09 -0700595 t.Fatalf("binarylib.NewState failed: %v", err)
Robin Thellend875f2592014-12-02 10:29:37 -0800596 }
Todd Wang5fc36442015-04-07 15:15:27 -0700597 server, _ := servicetest.NewServer(ctx)
Todd Wang1f7a6c62015-04-03 17:05:09 -0700598 d, err := binarylib.NewDispatcher(v23.GetPrincipal(ctx), state)
Robert Kroeger8d7a0ef2015-01-14 17:38:40 -0800599 if err != nil {
600 t.Fatalf("server.NewDispatcher failed: %v", err)
601 }
gauthamtcb03d132015-02-05 18:05:22 -0800602 if err := server.ServeDispatcher(von, d); err != nil {
Robin Thellend875f2592014-12-02 10:29:37 -0800603 t.Fatalf("server.ServeDispatcher failed: %v", err)
604 }
Robin Thellend875f2592014-12-02 10:29:37 -0800605 return func() {
606 if err := server.Stop(); err != nil {
607 t.Fatalf("server.Stop failed: %v", err)
608 }
Jiri Simsa432cc2e2014-12-08 15:53:38 -0800609 if err := os.RemoveAll(rootDir); err != nil {
610 t.Fatalf("os.RemoveAll(%q) failed: %v", rootDir, err)
Robin Thellend875f2592014-12-02 10:29:37 -0800611 }
612 }
613}
614
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800615type simpleRW chan []byte
616
617func (s simpleRW) Write(p []byte) (n int, err error) {
618 s <- p
619 return len(p), nil
620}
621func (s simpleRW) Read(p []byte) (n int, err error) {
622 return copy(p, <-s), nil
623}
624
625// TestDeviceManagerInstallation verifies the 'self install' and 'uninstall'
Bogdan Capritaa40d3382014-12-19 16:30:26 -0800626// functionality of the device manager: it runs SelfInstall in a child process,
627// then runs the executable from the soft link that the installation created.
628// This should bring up a functioning device manager. In the end it runs
629// Uninstall and verifies that the installation is gone.
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800630func TestDeviceManagerInstallation(t *testing.T) {
Robert Kroeger6e2efd92015-05-01 18:47:28 -0700631 ctx, shutdown := utiltest.InitForTest()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800632 defer shutdown()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800633
Todd Wang5fc36442015-04-07 15:15:27 -0700634 sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700635 defer deferFn()
Todd Wang5fc36442015-04-07 15:15:27 -0700636 testDir, cleanup := servicetest.SetupRootDir(t, "devicemanager")
Bogdan Caprita5420f172014-10-10 15:58:14 -0700637 defer cleanup()
Arup Mukherjee31b77c82015-03-04 10:48:33 -0800638 // No need to call SaveCreatorInfo() here because that's part of SelfInstall below
Bogdan Caprita5420f172014-10-10 15:58:14 -0700639
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800640 // Create a script wrapping the test target that implements suidhelper.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700641 suidHelperPath := utiltest.GenerateSuidHelperScript(t, testDir)
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800642 // Create a dummy script mascarading as the security agent.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700643 agentPath := utiltest.GenerateAgentScript(t, testDir)
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800644 initHelperPath := ""
Bogdan Caprita5420f172014-10-10 15:58:14 -0700645
Bogdan Caprita2b219362014-12-09 17:03:33 -0800646 // Create an 'envelope' for the device manager that we can pass to the
647 // installer, to ensure that the device manager that the installer
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800648 // configures can run.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700649 dmargs, dmenv := sh.CommandEnvelope(utiltest.DeviceManagerCmd, nil, "dm")
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800650 dmDir := filepath.Join(testDir, "dm")
Bogdan Caprita29a3b352015-01-16 16:28:49 -0800651 // TODO(caprita): Add test logic when initMode = true.
652 singleUser, sessionMode, initMode := true, true, false
Robin Thellendd9ffea92015-01-29 09:47:37 -0800653 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 -0800654 t.Fatalf("SelfInstall failed: %v", err)
655 }
Bogdan Caprita5420f172014-10-10 15:58:14 -0700656
Robert Kroeger22fcb032015-04-30 07:40:11 -0700657 utiltest.ResolveExpectNotFound(t, ctx, "dm")
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800658 // Start the device manager.
659 stdout := make(simpleRW, 100)
Robert Kroeger658e0912015-04-30 10:30:57 -0700660 defer os.Setenv(utiltest.RedirectEnv, os.Getenv(utiltest.RedirectEnv))
661 os.Setenv(utiltest.RedirectEnv, "1")
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800662 if err := impl.Start(dmDir, os.Stderr, stdout); err != nil {
663 t.Fatalf("Start failed: %v", err)
664 }
Todd Wang5fc36442015-04-07 15:15:27 -0700665 dms := expect.NewSession(t, stdout, servicetest.ExpectTimeout)
666 servicetest.ReadPID(t, dms)
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700667 utiltest.ClaimDevice(t, ctx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700668 utiltest.RevertDeviceExpectError(t, ctx, "dm", impl.ErrUpdateNoOp.ID) // No previous version available.
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700669
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800670 // Stop the device manager.
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800671 if err := impl.Stop(ctx, dmDir, os.Stderr, os.Stdout); err != nil {
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800672 t.Fatalf("Stop failed: %v", err)
673 }
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800674 dms.Expect("dm terminated")
Bogdan Capritaa40d3382014-12-19 16:30:26 -0800675
676 // Uninstall.
Robert Kroeger38cc2d82015-02-09 17:54:12 -0800677 if err := impl.Uninstall(dmDir, suidHelperPath, os.Stderr, os.Stdout); err != nil {
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800678 t.Fatalf("Uninstall failed: %v", err)
Bogdan Capritaa40d3382014-12-19 16:30:26 -0800679 }
Bogdan Capritac7e72b62015-01-07 19:22:23 -0800680 // Ensure that the installation is gone.
681 if files, err := ioutil.ReadDir(dmDir); err != nil || len(files) > 0 {
682 var finfo []string
683 for _, f := range files {
684 finfo = append(finfo, f.Name())
685 }
686 t.Fatalf("ReadDir returned (%v, %v)", err, finfo)
Bogdan Capritaa40d3382014-12-19 16:30:26 -0800687 }
Bogdan Caprita5420f172014-10-10 15:58:14 -0700688}
689
Bogdan Caprita2b219362014-12-09 17:03:33 -0800690func TestDeviceManagerGlobAndDebug(t *testing.T) {
Robert Kroeger6e2efd92015-05-01 18:47:28 -0700691 ctx, shutdown := utiltest.InitForTest()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800692 defer shutdown()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800693
Todd Wang5fc36442015-04-07 15:15:27 -0700694 sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700695 defer deferFn()
696
697 // Set up mock application and binary repositories.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700698 envelope, cleanup := utiltest.StartMockRepos(t, ctx)
Robin Thellend9e523a62014-10-07 16:19:53 -0700699 defer cleanup()
Robin Thellend9e523a62014-10-07 16:19:53 -0700700
Todd Wang5fc36442015-04-07 15:15:27 -0700701 root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
Robin Thellend09929f42014-10-01 10:18:13 -0700702 defer cleanup()
Arup Mukherjee31b77c82015-03-04 10:48:33 -0800703 if err := impl.SaveCreatorInfo(root); err != nil {
704 t.Fatal(err)
705 }
Robin Thellend09929f42014-10-01 10:18:13 -0700706
Bogdan Caprita962d5e02014-10-28 18:36:09 -0700707 // Create a script wrapping the test target that implements suidhelper.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700708 helperPath := utiltest.GenerateSuidHelperScript(t, root)
Bogdan Caprita962d5e02014-10-28 18:36:09 -0700709
Bogdan Caprita2b219362014-12-09 17:03:33 -0800710 // Set up the device manager. Since we won't do device manager updates,
Robin Thellend09929f42014-10-01 10:18:13 -0700711 // don't worry about its application envelope and current link.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700712 dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
Todd Wang5fc36442015-04-07 15:15:27 -0700713 pid := servicetest.ReadPID(t, dmh)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700714 defer syscall.Kill(pid, syscall.SIGINT)
Robin Thellend09929f42014-10-01 10:18:13 -0700715
Robin Thellend9e523a62014-10-07 16:19:53 -0700716 // Create the local server that the app uses to let us know it's ready.
Robert Kroeger658e0912015-04-30 10:30:57 -0700717 pingCh, cleanup := utiltest.SetupPingServer(t, ctx)
Bogdan Capritad2b9f032014-10-10 17:43:29 -0700718 defer cleanup()
Robin Thellend09929f42014-10-01 10:18:13 -0700719
Robin Thellend9e523a62014-10-07 16:19:53 -0700720 // Create the envelope for the first version of the app.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700721 *envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps", "appV1")
Robin Thellend9e523a62014-10-07 16:19:53 -0700722
Asim Shankar23dac322015-02-14 12:42:26 -0800723 // Device must be claimed before applications can be installed.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700724 utiltest.ClaimDevice(t, ctx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
Robin Thellend9e523a62014-10-07 16:19:53 -0700725 // Install the app.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700726 appID := utiltest.InstallApp(t, ctx)
Bogdan Caprita43bc7372014-12-03 21:51:12 -0800727 install1ID := path.Base(appID)
Robin Thellend9e523a62014-10-07 16:19:53 -0700728
729 // Start an instance of the app.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700730 instance1ID := utiltest.LaunchApp(t, ctx, appID)
731 defer utiltest.TerminateApp(t, ctx, appID, instance1ID)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700732
733 // Wait until the app pings us that it's ready.
Robert Kroeger658e0912015-04-30 10:30:57 -0700734 pingCh.WaitForPingArgs(t)
Robin Thellend9e523a62014-10-07 16:19:53 -0700735
Robert Kroeger22fcb032015-04-30 07:40:11 -0700736 app2ID := utiltest.InstallApp(t, ctx)
Bogdan Caprita43bc7372014-12-03 21:51:12 -0800737 install2ID := path.Base(app2ID)
738
Arup Mukherjee504a1e62015-02-25 11:09:56 -0800739 // Base name of argv[0] that the app should have when it executes
740 // It will be path.Base(envelope.Title + "@" + envelope.Binary.File + "/app").
741 // Note the suffix, which ensures that the result is always "app" at the moment.
742 // Someday in future we may remove that and have binary names that reflect the app name.
743 const appName = "app"
744
Robert Kroeger22fcb032015-04-30 07:40:11 -0700745 testcases := []utiltest.GlobTestVector{
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800746 {"dm", "...", []string{
Robin Thellend9e523a62014-10-07 16:19:53 -0700747 "",
748 "apps",
749 "apps/google naps",
Bogdan Caprita43bc7372014-12-03 21:51:12 -0800750 "apps/google naps/" + install1ID,
751 "apps/google naps/" + install1ID + "/" + instance1ID,
752 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs",
753 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs/STDERR-<timestamp>",
754 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs/STDOUT-<timestamp>",
Arup Mukherjee504a1e62015-02-25 11:09:56 -0800755 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs/" + appName + ".INFO",
756 "apps/google naps/" + install1ID + "/" + instance1ID + "/logs/" + appName + ".<*>.INFO.<timestamp>",
Bogdan Caprita43bc7372014-12-03 21:51:12 -0800757 "apps/google naps/" + install1ID + "/" + instance1ID + "/pprof",
758 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats",
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700759 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats/rpc",
Bogdan Caprita43bc7372014-12-03 21:51:12 -0800760 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats/system",
761 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats/system/start-time-rfc1123",
762 "apps/google naps/" + install1ID + "/" + instance1ID + "/stats/system/start-time-unix",
763 "apps/google naps/" + install2ID,
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800764 "device",
Robin Thellend9e523a62014-10-07 16:19:53 -0700765 }},
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800766 {"dm/apps", "*", []string{"google naps"}},
767 {"dm/apps/google naps", "*", []string{install1ID, install2ID}},
768 {"dm/apps/google naps/" + install1ID, "*", []string{instance1ID}},
769 {"dm/apps/google naps/" + install1ID + "/" + instance1ID, "*", []string{"logs", "pprof", "stats"}},
770 {"dm/apps/google naps/" + install1ID + "/" + instance1ID + "/logs", "*", []string{
Robin Thellend58647322014-10-28 12:07:47 -0700771 "STDERR-<timestamp>",
772 "STDOUT-<timestamp>",
Arup Mukherjee504a1e62015-02-25 11:09:56 -0800773 appName + ".INFO",
774 appName + ".<*>.INFO.<timestamp>",
Robin Thellend58647322014-10-28 12:07:47 -0700775 }},
Bogdan Caprita9c4aa222014-12-10 14:46:30 -0800776 {"dm/apps/google naps/" + install1ID + "/" + instance1ID + "/stats/system", "start-time*", []string{"start-time-rfc1123", "start-time-unix"}},
Robin Thellend09929f42014-10-01 10:18:13 -0700777 }
Robin Thellend4c5266e2014-10-27 13:19:29 -0700778
Robert Kroeger22fcb032015-04-30 07:40:11 -0700779 res := utiltest.NewGlobTestRegexHelper(appName)
Robin Thellendb9dd9bb2014-10-29 13:54:08 -0700780
Robert Kroeger22fcb032015-04-30 07:40:11 -0700781 utiltest.VerifyGlob(t, ctx, appName, testcases, res)
782 utiltest.VerifyLog(t, ctx, "dm", "apps/google naps", install1ID, instance1ID, "logs", "*")
783 utiltest.VerifyStatsValues(t, ctx, "dm", "apps/google naps", install1ID, instance1ID, "stats/system/start-time*")
784 utiltest.VerifyPProfCmdLine(t, ctx, appName, "dm", "apps/google naps", install1ID, instance1ID, "pprof")
Robin Thellend4c5266e2014-10-27 13:19:29 -0700785}
786
Bogdan Capritab4d1dfd2015-02-26 11:18:34 -0800787// TODO(caprita): We need better test coverage for how updating/reverting apps
788// affects the package configured for the app.
Bogdan Caprita2b219362014-12-09 17:03:33 -0800789func TestDeviceManagerPackages(t *testing.T) {
Robert Kroeger6e2efd92015-05-01 18:47:28 -0700790 ctx, shutdown := utiltest.InitForTest()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800791 defer shutdown()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800792
Todd Wang5fc36442015-04-07 15:15:27 -0700793 sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
Robin Thellend875f2592014-12-02 10:29:37 -0800794 defer deferFn()
795
796 // Set up mock application and binary repositories.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700797 envelope, cleanup := utiltest.StartMockRepos(t, ctx)
Robin Thellend875f2592014-12-02 10:29:37 -0800798 defer cleanup()
799
gauthamtcb03d132015-02-05 18:05:22 -0800800 binaryVON := "realbin"
801 defer startRealBinaryRepository(t, ctx, binaryVON)()
802
803 // upload package to binary repository
804 tmpdir, err := ioutil.TempDir("", "test-package-")
805 if err != nil {
806 t.Fatalf("ioutil.TempDir failed: %v", err)
807 }
808 defer os.RemoveAll(tmpdir)
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800809 createFile := func(name, contents string) {
810 if err := ioutil.WriteFile(filepath.Join(tmpdir, name), []byte(contents), 0600); err != nil {
811 t.Fatalf("ioutil.WriteFile failed: %v", err)
812 }
gauthamtcb03d132015-02-05 18:05:22 -0800813 }
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800814 createFile("hello.txt", "Hello World!")
Todd Wang5fc36442015-04-07 15:15:27 -0700815 if _, err := binarylib.UploadFromDir(ctx, naming.Join(binaryVON, "testpkg"), tmpdir); err != nil {
816 t.Fatalf("binarylib.UploadFromDir failed: %v", err)
gauthamtcb03d132015-02-05 18:05:22 -0800817 }
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800818 createAndUpload := func(von, contents string) {
819 createFile("tempfile", contents)
Todd Wang5fc36442015-04-07 15:15:27 -0700820 if _, err := binarylib.UploadFromFile(ctx, naming.Join(binaryVON, von), filepath.Join(tmpdir, "tempfile")); err != nil {
821 t.Fatalf("binarylib.UploadFromFile failed: %v", err)
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800822 }
Bogdan Caprita2751d672015-02-06 13:43:47 -0800823 }
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800824 createAndUpload("testfile", "Goodbye World!")
825 createAndUpload("leftshark", "Left shark")
826 createAndUpload("rightshark", "Right shark")
827 createAndUpload("beachball", "Beach ball")
Robin Thellend875f2592014-12-02 10:29:37 -0800828
Todd Wang5fc36442015-04-07 15:15:27 -0700829 root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
Robin Thellend875f2592014-12-02 10:29:37 -0800830 defer cleanup()
Arup Mukherjee31b77c82015-03-04 10:48:33 -0800831 if err := impl.SaveCreatorInfo(root); err != nil {
832 t.Fatal(err)
833 }
Robin Thellend875f2592014-12-02 10:29:37 -0800834
Robin Thellend875f2592014-12-02 10:29:37 -0800835 // Create a script wrapping the test target that implements suidhelper.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700836 helperPath := utiltest.GenerateSuidHelperScript(t, root)
Robin Thellend875f2592014-12-02 10:29:37 -0800837
Bogdan Caprita2b219362014-12-09 17:03:33 -0800838 // Set up the device manager. Since we won't do device manager updates,
Robin Thellend875f2592014-12-02 10:29:37 -0800839 // don't worry about its application envelope and current link.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700840 dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
Todd Wang5fc36442015-04-07 15:15:27 -0700841 pid := servicetest.ReadPID(t, dmh)
Robin Thellend875f2592014-12-02 10:29:37 -0800842 defer syscall.Kill(pid, syscall.SIGINT)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700843 defer utiltest.VerifyNoRunningProcesses(t)
Robin Thellend875f2592014-12-02 10:29:37 -0800844
845 // Create the local server that the app uses to let us know it's ready.
Robert Kroeger658e0912015-04-30 10:30:57 -0700846 pingCh, cleanup := utiltest.SetupPingServer(t, ctx)
Robin Thellend875f2592014-12-02 10:29:37 -0800847 defer cleanup()
848
849 // Create the envelope for the first version of the app.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700850 *envelope = utiltest.EnvelopeFromShell(sh, nil, utiltest.AppCmd, "google naps", "appV1")
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800851 envelope.Packages = map[string]application.SignedFile{
852 "test": application.SignedFile{
gauthamt3dbef0c2015-02-10 12:26:02 -0800853 File: "realbin/testpkg",
854 },
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800855 "test2": application.SignedFile{
gauthamt3dbef0c2015-02-10 12:26:02 -0800856 File: "realbin/testfile",
857 },
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800858 "shark": application.SignedFile{
859 File: "realbin/leftshark",
860 },
Robin Thellend875f2592014-12-02 10:29:37 -0800861 }
862
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800863 // These are install-time overrides for packages.
864 // Specifically, we override the 'shark' package and add a new
865 // 'ball' package on top of what's specified in the envelope.
866 packages := application.Packages{
867 "shark": application.SignedFile{
868 File: "realbin/rightshark",
869 },
870 "ball": application.SignedFile{
871 File: "realbin/beachball",
872 },
873 }
Asim Shankar23dac322015-02-14 12:42:26 -0800874 // Device must be claimed before apps can be installed.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700875 utiltest.ClaimDevice(t, ctx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
Robin Thellend875f2592014-12-02 10:29:37 -0800876 // Install the app.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700877 appID := utiltest.InstallApp(t, ctx, packages)
Robin Thellend875f2592014-12-02 10:29:37 -0800878
879 // Start an instance of the app.
Robert Kroeger22fcb032015-04-30 07:40:11 -0700880 instance1ID := utiltest.LaunchApp(t, ctx, appID)
881 defer utiltest.TerminateApp(t, ctx, appID, instance1ID)
Robin Thellend875f2592014-12-02 10:29:37 -0800882
883 // Wait until the app pings us that it's ready.
Robert Kroeger658e0912015-04-30 10:30:57 -0700884 pingCh.WaitForPingArgs(t)
Robin Thellend875f2592014-12-02 10:29:37 -0800885
Bogdan Caprita2751d672015-02-06 13:43:47 -0800886 for _, c := range []struct {
887 path, content string
888 }{
889 {
890 filepath.Join("test", "hello.txt"),
891 "Hello World!",
892 },
893 {
894 "test2",
895 "Goodbye World!",
896 },
Bogdan Capritac25a48c2015-02-12 13:45:51 -0800897 {
898 "shark",
899 "Right shark",
900 },
901 {
902 "ball",
903 "Beach ball",
904 },
Bogdan Caprita2751d672015-02-06 13:43:47 -0800905 } {
906 // Ask the app to cat the file.
907 file := filepath.Join("packages", c.path)
908 name := "appV1"
Robert Kroeger658e0912015-04-30 10:30:57 -0700909 content, err := utiltest.Cat(ctx, name, file)
Bogdan Caprita2751d672015-02-06 13:43:47 -0800910 if err != nil {
Robert Kroeger658e0912015-04-30 10:30:57 -0700911 t.Errorf("utiltest.Cat(%q, %q) failed: %v", name, file, err)
Bogdan Caprita2751d672015-02-06 13:43:47 -0800912 }
913 if expected := c.content; content != expected {
914 t.Errorf("unexpected content: expected %q, got %q", expected, content)
915 }
Robin Thellend875f2592014-12-02 10:29:37 -0800916 }
917}
918
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800919func listAndVerifyAssociations(t *testing.T, ctx *context.T, stub device.DeviceClientMethods, expected []device.Association) {
920 assocs, err := stub.ListAssociations(ctx)
Robert Kroeger362ff892014-09-29 14:23:47 -0700921 if err != nil {
922 t.Fatalf("ListAssociations failed %v", err)
923 }
Robert Kroeger22fcb032015-04-30 07:40:11 -0700924 utiltest.CompareAssociations(t, assocs, expected)
Robert Kroeger362ff892014-09-29 14:23:47 -0700925}
926
Bogdan Caprita2b219362014-12-09 17:03:33 -0800927// TODO(rjkroege): Verify that associations persist across restarts once
928// permanent storage is added.
Robert Kroeger362ff892014-09-29 14:23:47 -0700929func TestAccountAssociation(t *testing.T) {
Robert Kroeger6e2efd92015-05-01 18:47:28 -0700930 ctx, shutdown := utiltest.InitForTest()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800931 defer shutdown()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -0800932
Todd Wang5fc36442015-04-07 15:15:27 -0700933 sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700934 defer deferFn()
Robert Kroeger362ff892014-09-29 14:23:47 -0700935
Todd Wang5fc36442015-04-07 15:15:27 -0700936 root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
Robert Kroeger362ff892014-09-29 14:23:47 -0700937 defer cleanup()
Arup Mukherjee31b77c82015-03-04 10:48:33 -0800938 if err := impl.SaveCreatorInfo(root); err != nil {
939 t.Fatal(err)
940 }
Robert Kroeger362ff892014-09-29 14:23:47 -0700941
Asim Shankar263c73b2015-03-19 18:31:26 -0700942 // By default, the two processes (selfCtx and octx) will have blessings
943 // generated based on the username/machine name running this process.
944 // Since these blessings will appear in AccessLists, give them
945 // recognizable names.
Asim Shankar4a698282015-03-21 21:59:18 -0700946 idp := testutil.NewIDProvider("root")
Robert Kroeger22fcb032015-04-30 07:40:11 -0700947 selfCtx := utiltest.CtxWithNewPrincipal(t, ctx, idp, "self")
948 otherCtx := utiltest.CtxWithNewPrincipal(t, selfCtx, idp, "other")
Asim Shankar263c73b2015-03-19 18:31:26 -0700949 // Both the "external" processes must recognize the root mounttable's
950 // blessings, otherwise they will not talk to it.
951 for _, c := range []*context.T{selfCtx, otherCtx} {
952 v23.GetPrincipal(c).AddToRoots(v23.GetPrincipal(ctx).BlessingStore().Default())
953 }
Robert Kroeger362ff892014-09-29 14:23:47 -0700954
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700955 dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, "unused_helper", "unused_app_repo_name", "unused_curr_link")
Todd Wang5fc36442015-04-07 15:15:27 -0700956 pid := servicetest.ReadPID(t, dmh)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700957 defer syscall.Kill(pid, syscall.SIGINT)
Robert Kroeger22fcb032015-04-30 07:40:11 -0700958 defer utiltest.VerifyNoRunningProcesses(t)
Robert Kroeger362ff892014-09-29 14:23:47 -0700959
Bogdan Caprita2b219362014-12-09 17:03:33 -0800960 // Attempt to list associations on the device manager without having
Robert Kroeger362ff892014-09-29 14:23:47 -0700961 // claimed it.
Bogdan Capritae8073682015-04-25 15:37:53 -0700962 if list, err := device.DeviceClient("claimable").ListAssociations(otherCtx); err == nil {
Asim Shankar23dac322015-02-14 12:42:26 -0800963 t.Fatalf("ListAssociations should fail on unclaimed device manager but did not: (%v, %v)", list, err)
Robert Kroeger362ff892014-09-29 14:23:47 -0700964 }
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -0700965
Bogdan Caprita2b219362014-12-09 17:03:33 -0800966 // self claims the device manager.
Robert Kroegeref27d6e2015-05-01 16:58:59 -0700967 utiltest.ClaimDevice(t, selfCtx, "claimable", "dm", "alice", utiltest.NoPairingToken)
Robert Kroeger362ff892014-09-29 14:23:47 -0700968
969 vlog.VI(2).Info("Verify that associations start out empty.")
Bogdan Capritae8073682015-04-25 15:37:53 -0700970 deviceStub := device.DeviceClient("dm/device")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800971 listAndVerifyAssociations(t, selfCtx, deviceStub, []device.Association(nil))
Robert Kroeger362ff892014-09-29 14:23:47 -0700972
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800973 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/self", "root/other"}, "alice_system_account"); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -0700974 t.Fatalf("ListAssociations failed %v", err)
975 }
976 vlog.VI(2).Info("Added association should appear.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800977 listAndVerifyAssociations(t, selfCtx, deviceStub, []device.Association{
Robert Kroeger362ff892014-09-29 14:23:47 -0700978 {
979 "root/self",
980 "alice_system_account",
981 },
982 {
983 "root/other",
984 "alice_system_account",
985 },
986 })
987
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800988 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/self", "root/other"}, "alice_other_account"); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -0700989 t.Fatalf("AssociateAccount failed %v", err)
990 }
991 vlog.VI(2).Info("Change the associations and the change should appear.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -0800992 listAndVerifyAssociations(t, selfCtx, deviceStub, []device.Association{
Robert Kroeger362ff892014-09-29 14:23:47 -0700993 {
994 "root/self",
995 "alice_other_account",
996 },
997 {
998 "root/other",
999 "alice_other_account",
1000 },
1001 })
1002
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001003 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/other"}, ""); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001004 t.Fatalf("AssociateAccount failed %v", err)
1005 }
1006 vlog.VI(2).Info("Verify that we can remove an association.")
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001007 listAndVerifyAssociations(t, selfCtx, deviceStub, []device.Association{
Robert Kroeger362ff892014-09-29 14:23:47 -07001008 {
1009 "root/self",
1010 "alice_other_account",
1011 },
1012 })
1013}
1014
Robert Kroeger362ff892014-09-29 14:23:47 -07001015func TestAppWithSuidHelper(t *testing.T) {
Robert Kroeger6e2efd92015-05-01 18:47:28 -07001016 ctx, shutdown := utiltest.InitForTest()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001017 defer shutdown()
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001018
Asim Shankarb547ea92015-02-17 18:49:45 -08001019 // Identity provider used to ensure that all processes recognize each
1020 // others' blessings.
Asim Shankar4a698282015-03-21 21:59:18 -07001021 idp := testutil.NewIDProvider("root")
Jiri Simsa6ac95222015-02-23 16:11:49 -08001022 if err := idp.Bless(v23.GetPrincipal(ctx), "self"); err != nil {
Asim Shankarb547ea92015-02-17 18:49:45 -08001023 t.Fatal(err)
1024 }
1025
Todd Wang5fc36442015-04-07 15:15:27 -07001026 sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001027 defer deferFn()
1028
1029 // Set up mock application and binary repositories.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001030 envelope, cleanup := utiltest.StartMockRepos(t, ctx)
Robert Kroeger362ff892014-09-29 14:23:47 -07001031 defer cleanup()
Robert Kroeger362ff892014-09-29 14:23:47 -07001032
Todd Wang5fc36442015-04-07 15:15:27 -07001033 root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
Robert Kroeger362ff892014-09-29 14:23:47 -07001034 defer cleanup()
Arup Mukherjee31b77c82015-03-04 10:48:33 -08001035 if err := impl.SaveCreatorInfo(root); err != nil {
1036 t.Fatal(err)
1037 }
Robert Kroeger362ff892014-09-29 14:23:47 -07001038
Matt Rosencrantzfa3082c2015-01-22 21:39:04 -08001039 selfCtx := ctx
Robert Kroeger22fcb032015-04-30 07:40:11 -07001040 otherCtx := utiltest.CtxWithNewPrincipal(t, selfCtx, idp, "other")
Robert Kroeger362ff892014-09-29 14:23:47 -07001041
Bogdan Caprita2b219362014-12-09 17:03:33 -08001042 // Create a script wrapping the test target that implements suidhelper.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001043 helperPath := utiltest.GenerateSuidHelperScript(t, root)
Robert Kroeger362ff892014-09-29 14:23:47 -07001044
Robert Kroegeref27d6e2015-05-01 16:58:59 -07001045 dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "-mocksetuid", "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
Todd Wang5fc36442015-04-07 15:15:27 -07001046 pid := servicetest.ReadPID(t, dmh)
Cosmos Nicolaouad2793f2014-10-27 16:24:15 -07001047 defer syscall.Kill(pid, syscall.SIGINT)
Robert Kroeger22fcb032015-04-30 07:40:11 -07001048 defer utiltest.VerifyNoRunningProcesses(t)
Asim Shankar23dac322015-02-14 12:42:26 -08001049 // Claim the devicemanager with selfCtx as root/self/alice
Robert Kroegeref27d6e2015-05-01 16:58:59 -07001050 utiltest.ClaimDevice(t, selfCtx, "claimable", "dm", "alice", utiltest.NoPairingToken)
Robert Kroeger362ff892014-09-29 14:23:47 -07001051
Asim Shankar23dac322015-02-14 12:42:26 -08001052 deviceStub := device.DeviceClient("dm/device")
Robert Kroeger362ff892014-09-29 14:23:47 -07001053
Bogdan Caprita2b219362014-12-09 17:03:33 -08001054 // Create the local server that the app uses to tell us which system
1055 // name the device manager wished to run it as.
Robert Kroeger658e0912015-04-30 10:30:57 -07001056 pingCh, cleanup := utiltest.SetupPingServer(t, ctx)
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001057 defer cleanup()
Robert Kroeger362ff892014-09-29 14:23:47 -07001058
Bogdan Caprita26929102014-11-07 11:56:56 -08001059 // Create an envelope for a first version of the app.
Robert Kroegeref27d6e2015-05-01 16:58:59 -07001060 *envelope = utiltest.EnvelopeFromShell(sh, []string{utiltest.TestEnvVarName + "=env-var"}, utiltest.AppCmd, "google naps", fmt.Sprintf("--%s=flag-val-envelope", utiltest.TestFlagName), "appV1")
Robert Kroeger362ff892014-09-29 14:23:47 -07001061
1062 // Install and start the app as root/self.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001063 appID := utiltest.InstallApp(t, selfCtx)
Robert Kroeger362ff892014-09-29 14:23:47 -07001064
Robert Kroeger2595b762015-04-07 14:13:40 -07001065 vlog.VI(2).Infof("Validate that the created app has the right permission lists.")
Robert Kroeger22fcb032015-04-30 07:40:11 -07001066 perms, _, err := utiltest.AppStub(appID).GetPermissions(selfCtx)
Robert Kroeger2595b762015-04-07 14:13:40 -07001067 if err != nil {
1068 t.Fatalf("GetPermissions on appID: %v failed %v", appID, err)
1069 }
1070 expected := make(access.Permissions)
1071 for _, tag := range access.AllTypicalTags() {
1072 expected[string(tag)] = access.AccessList{In: []security.BlessingPattern{"root/self/$"}}
1073 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -07001074 if got, want := perms.Normalize(), expected.Normalize(); !reflect.DeepEqual(got, want) {
Robert Kroeger2595b762015-04-07 14:13:40 -07001075 t.Errorf("got %#v, expected %#v", got, want)
1076 }
1077
Bogdan Caprita2b219362014-12-09 17:03:33 -08001078 // Start an instance of the app but this time it should fail: we do not
1079 // have an associated uname for the invoking identity.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001080 utiltest.LaunchAppExpectError(t, selfCtx, appID, verror.ErrNoAccess.ID)
Robert Kroeger362ff892014-09-29 14:23:47 -07001081
Bogdan Caprita17666dd2015-01-14 09:27:46 -08001082 // Create an association for selfCtx
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001083 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/self"}, testUserName); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001084 t.Fatalf("AssociateAccount failed %v", err)
1085 }
1086
Robert Kroeger22fcb032015-04-30 07:40:11 -07001087 instance1ID := utiltest.LaunchApp(t, selfCtx, appID)
Robert Kroeger658e0912015-04-30 10:30:57 -07001088 pingCh.VerifyPingArgs(t, testUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001089 utiltest.TerminateApp(t, selfCtx, appID, instance1ID)
Robert Kroeger362ff892014-09-29 14:23:47 -07001090
1091 vlog.VI(2).Infof("other attempting to run an app without access. Should fail.")
Robert Kroeger22fcb032015-04-30 07:40:11 -07001092 utiltest.LaunchAppExpectError(t, otherCtx, appID, verror.ErrNoAccess.ID)
Robert Kroeger362ff892014-09-29 14:23:47 -07001093
Robert Kroegeracc778b2014-11-03 17:17:21 -08001094 // Self will now let other also install apps.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001095 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/other"}, testUserName); err != nil {
Robert Kroeger362ff892014-09-29 14:23:47 -07001096 t.Fatalf("AssociateAccount failed %v", err)
1097 }
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -07001098 // Add Start to the AccessList list for root/other.
1099 newAccessList, _, err := deviceStub.GetPermissions(selfCtx)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001100 if err != nil {
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -07001101 t.Fatalf("GetPermissions failed %v", err)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001102 }
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -07001103 newAccessList.Add("root/other", string(access.Write))
1104 if err := deviceStub.SetPermissions(selfCtx, newAccessList, ""); err != nil {
1105 t.Fatalf("SetPermissions failed %v", err)
Robert Kroeger362ff892014-09-29 14:23:47 -07001106 }
1107
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -07001108 // With the introduction of per installation and per instance AccessLists,
Bogdan Caprita2b219362014-12-09 17:03:33 -08001109 // while other now has administrator permissions on the device manager,
1110 // other doesn't have execution permissions for the app. So this will
1111 // fail.
Robert Kroegeracc778b2014-11-03 17:17:21 -08001112 vlog.VI(2).Infof("other attempting to run an app still without access. Should fail.")
Robert Kroeger22fcb032015-04-30 07:40:11 -07001113 utiltest.LaunchAppExpectError(t, otherCtx, appID, verror.ErrNoAccess.ID)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001114
1115 // But self can give other permissions to start applications.
1116 vlog.VI(2).Infof("self attempting to give other permission to start %s", appID)
Robert Kroeger22fcb032015-04-30 07:40:11 -07001117 newAccessList, _, err = utiltest.AppStub(appID).GetPermissions(selfCtx)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001118 if err != nil {
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -07001119 t.Fatalf("GetPermissions on appID: %v failed %v", appID, err)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001120 }
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -07001121 newAccessList.Add("root/other", string(access.Read))
Robert Kroeger22fcb032015-04-30 07:40:11 -07001122 if err = utiltest.AppStub(appID).SetPermissions(selfCtx, newAccessList, ""); err != nil {
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -07001123 t.Fatalf("SetPermissions on appID: %v failed: %v", appID, err)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001124 }
1125
Robert Kroeger362ff892014-09-29 14:23:47 -07001126 vlog.VI(2).Infof("other attempting to run an app with access. Should succeed.")
Robert Kroeger22fcb032015-04-30 07:40:11 -07001127 instance2ID := utiltest.LaunchApp(t, otherCtx, appID)
Robert Kroeger658e0912015-04-30 10:30:57 -07001128 pingCh.VerifyPingArgs(t, testUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Robert Kroeger2595b762015-04-07 14:13:40 -07001129
1130 vlog.VI(2).Infof("Validate that created instance has the right permissions.")
1131 expected = make(access.Permissions)
1132 for _, tag := range access.AllTypicalTags() {
1133 expected[string(tag)] = access.AccessList{In: []security.BlessingPattern{"root/other/$"}}
1134 }
Robert Kroeger22fcb032015-04-30 07:40:11 -07001135 perms, _, err = utiltest.AppStub(appID, instance2ID).GetPermissions(selfCtx)
Robert Kroeger2595b762015-04-07 14:13:40 -07001136 if err != nil {
1137 t.Fatalf("GetPermissions on instance %v/%v failed: %v", appID, instance2ID, err)
1138 }
Adam Sadovskya4d4a692015-04-20 11:36:49 -07001139 if got, want := perms.Normalize(), expected.Normalize(); !reflect.DeepEqual(got, want) {
Robert Kroeger2595b762015-04-07 14:13:40 -07001140 t.Errorf("got %#v, expected %#v ", got, want)
1141 }
1142
1143 // Shutdown the app.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001144 utiltest.KillApp(t, otherCtx, appID, instance2ID)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001145
Bogdan Caprita2b050322015-04-17 09:04:03 -07001146 vlog.VI(2).Infof("Verify that Run with the same systemName works.")
Robert Kroeger22fcb032015-04-30 07:40:11 -07001147 utiltest.RunApp(t, otherCtx, appID, instance2ID)
Robert Kroeger658e0912015-04-30 10:30:57 -07001148 pingCh.VerifyPingArgs(t, testUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001149 utiltest.KillApp(t, otherCtx, appID, instance2ID)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001150
Robert Kroegeracc778b2014-11-03 17:17:21 -08001151 vlog.VI(2).Infof("Verify that other can install and run applications.")
Robert Kroeger22fcb032015-04-30 07:40:11 -07001152 otherAppID := utiltest.InstallApp(t, otherCtx)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001153
1154 vlog.VI(2).Infof("other attempting to run an app that other installed. Should succeed.")
Robert Kroeger22fcb032015-04-30 07:40:11 -07001155 instance4ID := utiltest.LaunchApp(t, otherCtx, otherAppID)
Robert Kroeger658e0912015-04-30 10:30:57 -07001156 pingCh.VerifyPingArgs(t, testUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Robert Kroegeracc778b2014-11-03 17:17:21 -08001157
1158 // Clean up.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001159 utiltest.TerminateApp(t, otherCtx, otherAppID, instance4ID)
Robert Kroegeracc778b2014-11-03 17:17:21 -08001160
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001161 // Change the associated system name.
Matt Rosencrantzf1c3b442015-01-12 17:53:08 -08001162 if err := deviceStub.AssociateAccount(selfCtx, []string{"root/other"}, anotherTestUserName); err != nil {
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001163 t.Fatalf("AssociateAccount failed %v", err)
1164 }
1165
Bogdan Caprita2b050322015-04-17 09:04:03 -07001166 vlog.VI(2).Infof("Show that Run with a different systemName fails.")
Robert Kroeger22fcb032015-04-30 07:40:11 -07001167 utiltest.RunAppExpectError(t, otherCtx, appID, instance2ID, verror.ErrNoAccess.ID)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001168
1169 // Clean up.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001170 utiltest.DeleteApp(t, otherCtx, appID, instance2ID)
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001171
1172 vlog.VI(2).Infof("Show that Start with different systemName works.")
Robert Kroeger22fcb032015-04-30 07:40:11 -07001173 instance3ID := utiltest.LaunchApp(t, otherCtx, appID)
Robert Kroeger658e0912015-04-30 10:30:57 -07001174 pingCh.VerifyPingArgs(t, anotherTestUserName, "flag-val-envelope", "env-var") // Wait until the app pings us that it's ready.
Robert Kroeger1ce0bd72014-10-22 13:57:14 -07001175
1176 // Clean up.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001177 utiltest.TerminateApp(t, otherCtx, appID, instance3ID)
Robert Kroeger362ff892014-09-29 14:23:47 -07001178}
gauthamtcb03d132015-02-05 18:05:22 -08001179
1180func TestDownloadSignatureMatch(t *testing.T) {
Robert Kroeger6e2efd92015-05-01 18:47:28 -07001181 ctx, shutdown := utiltest.InitForTest()
gauthamtcb03d132015-02-05 18:05:22 -08001182 defer shutdown()
gauthamtcb03d132015-02-05 18:05:22 -08001183
Todd Wang5fc36442015-04-07 15:15:27 -07001184 sh, deferFn := servicetest.CreateShellAndMountTable(t, ctx, nil)
gauthamtcb03d132015-02-05 18:05:22 -08001185 defer deferFn()
1186
gauthamt3dbef0c2015-02-10 12:26:02 -08001187 binaryVON := "binary"
1188 pkgVON := naming.Join(binaryVON, "testpkg")
gauthamtcb03d132015-02-05 18:05:22 -08001189 defer startRealBinaryRepository(t, ctx, binaryVON)()
1190
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -07001191 up := testutil.RandomBytes(testutil.Intn(5 << 20))
gauthamtcb03d132015-02-05 18:05:22 -08001192 mediaInfo := repository.MediaInfo{Type: "application/octet-stream"}
Todd Wang5fc36442015-04-07 15:15:27 -07001193 sig, err := binarylib.Upload(ctx, naming.Join(binaryVON, "testbinary"), up, mediaInfo)
gauthamtcb03d132015-02-05 18:05:22 -08001194 if err != nil {
1195 t.Fatalf("Upload(%v) failed:%v", binaryVON, err)
1196 }
1197
gauthamt3dbef0c2015-02-10 12:26:02 -08001198 // Upload packages for this application
1199 tmpdir, err := ioutil.TempDir("", "test-package-")
1200 if err != nil {
1201 t.Fatalf("ioutil.TempDir failed: %v", err)
1202 }
1203 defer os.RemoveAll(tmpdir)
Cosmos Nicolaoua18a1eb2015-03-12 13:15:01 -07001204 pkgContents := testutil.RandomBytes(testutil.Intn(5 << 20))
gauthamt3dbef0c2015-02-10 12:26:02 -08001205 if err := ioutil.WriteFile(filepath.Join(tmpdir, "pkg.txt"), pkgContents, 0600); err != nil {
1206 t.Fatalf("ioutil.WriteFile failed: %v", err)
1207 }
Todd Wang5fc36442015-04-07 15:15:27 -07001208 pkgSig, err := binarylib.UploadFromDir(ctx, pkgVON, tmpdir)
gauthamt3dbef0c2015-02-10 12:26:02 -08001209 if err != nil {
Todd Wang5fc36442015-04-07 15:15:27 -07001210 t.Fatalf("binarylib.UploadFromDir failed: %v", err)
gauthamt3dbef0c2015-02-10 12:26:02 -08001211 }
1212
gauthamtcb03d132015-02-05 18:05:22 -08001213 // Start the application repository
Robert Kroeger22fcb032015-04-30 07:40:11 -07001214 envelope, serverStop := utiltest.StartApplicationRepository(ctx)
gauthamtcb03d132015-02-05 18:05:22 -08001215 defer serverStop()
1216
Todd Wang5fc36442015-04-07 15:15:27 -07001217 root, cleanup := servicetest.SetupRootDir(t, "devicemanager")
gauthamtcb03d132015-02-05 18:05:22 -08001218 defer cleanup()
Arup Mukherjee31b77c82015-03-04 10:48:33 -08001219 if err := impl.SaveCreatorInfo(root); err != nil {
1220 t.Fatal(err)
1221 }
gauthamtcb03d132015-02-05 18:05:22 -08001222
1223 // Create a script wrapping the test target that implements suidhelper.
Robert Kroeger22fcb032015-04-30 07:40:11 -07001224 helperPath := utiltest.GenerateSuidHelperScript(t, root)
gauthamtcb03d132015-02-05 18:05:22 -08001225
1226 // Set up the device manager. Since we won't do device manager updates,
1227 // don't worry about its application envelope and current link.
Robert Kroegeref27d6e2015-05-01 16:58:59 -07001228 dmh := servicetest.RunCommand(t, sh, nil, utiltest.DeviceManagerCmd, "dm", root, helperPath, "unused_app_repo_name", "unused_curr_link")
Todd Wang5fc36442015-04-07 15:15:27 -07001229 pid := servicetest.ReadPID(t, dmh)
gauthamtcb03d132015-02-05 18:05:22 -08001230 defer syscall.Kill(pid, syscall.SIGINT)
Robert Kroegeref27d6e2015-05-01 16:58:59 -07001231 utiltest.ClaimDevice(t, ctx, "claimable", "dm", "mydevice", utiltest.NoPairingToken)
gauthamtcb03d132015-02-05 18:05:22 -08001232
Jiri Simsa6ac95222015-02-23 16:11:49 -08001233 publisher, err := v23.GetPrincipal(ctx).BlessSelf("publisher")
gauthamtcb03d132015-02-05 18:05:22 -08001234 if err != nil {
1235 t.Fatalf("Failed to generate publisher blessings:%v", err)
1236 }
1237 *envelope = application.Envelope{
Bogdan Capritac25a48c2015-02-12 13:45:51 -08001238 Binary: application.SignedFile{
1239 File: naming.Join(binaryVON, "testbinary"),
1240 Signature: *sig,
1241 },
Asim Shankarb07ec692015-02-27 23:40:44 -08001242 Publisher: publisher,
Bogdan Capritac25a48c2015-02-12 13:45:51 -08001243 Packages: map[string]application.SignedFile{
1244 "pkg": application.SignedFile{
gauthamt3dbef0c2015-02-10 12:26:02 -08001245 File: pkgVON,
1246 Signature: *pkgSig,
1247 },
1248 },
gauthamtcb03d132015-02-05 18:05:22 -08001249 }
Robert Kroeger22fcb032015-04-30 07:40:11 -07001250 if _, err := utiltest.AppStub().Install(ctx, utiltest.MockApplicationRepoName, device.Config{}, nil); err != nil {
gauthamtcb03d132015-02-05 18:05:22 -08001251 t.Fatalf("Failed to Install app:%v", err)
1252 }
gauthamt3dbef0c2015-02-10 12:26:02 -08001253
gauthamtcb03d132015-02-05 18:05:22 -08001254 // Verify that when the binary is corrupted, signature verification fails.
1255 up[0] = up[0] ^ 0xFF
Todd Wang5fc36442015-04-07 15:15:27 -07001256 if err := binarylib.Delete(ctx, naming.Join(binaryVON, "testbinary")); err != nil {
gauthamtcb03d132015-02-05 18:05:22 -08001257 t.Fatalf("Delete(%v) failed:%v", binaryVON, err)
1258 }
Todd Wang5fc36442015-04-07 15:15:27 -07001259 if _, err := binarylib.Upload(ctx, naming.Join(binaryVON, "testbinary"), up, mediaInfo); err != nil {
gauthamtcb03d132015-02-05 18:05:22 -08001260 t.Fatalf("Upload(%v) failed:%v", binaryVON, err)
1261 }
Robert Kroeger22fcb032015-04-30 07:40:11 -07001262 if _, err := utiltest.AppStub().Install(ctx, utiltest.MockApplicationRepoName, device.Config{}, nil); verror.ErrorID(err) != impl.ErrOperationFailed.ID {
Asim Shankarb547ea92015-02-17 18:49:45 -08001263 t.Fatalf("Failed to verify signature mismatch for binary:%v. Got errorid=%v[%v], want errorid=%v", binaryVON, verror.ErrorID(err), err, impl.ErrOperationFailed.ID)
gauthamtcb03d132015-02-05 18:05:22 -08001264 }
gauthamt3dbef0c2015-02-10 12:26:02 -08001265
1266 // Restore the binary and verify that installation succeeds.
1267 up[0] = up[0] ^ 0xFF
Todd Wang5fc36442015-04-07 15:15:27 -07001268 if err := binarylib.Delete(ctx, naming.Join(binaryVON, "testbinary")); err != nil {
gauthamt3dbef0c2015-02-10 12:26:02 -08001269 t.Fatalf("Delete(%v) failed:%v", binaryVON, err)
1270 }
Todd Wang5fc36442015-04-07 15:15:27 -07001271 if _, err := binarylib.Upload(ctx, naming.Join(binaryVON, "testbinary"), up, mediaInfo); err != nil {
gauthamt3dbef0c2015-02-10 12:26:02 -08001272 t.Fatalf("Upload(%v) failed:%v", binaryVON, err)
1273 }
Robert Kroeger22fcb032015-04-30 07:40:11 -07001274 if _, err := utiltest.AppStub().Install(ctx, utiltest.MockApplicationRepoName, device.Config{}, nil); err != nil {
gauthamt3dbef0c2015-02-10 12:26:02 -08001275 t.Fatalf("Failed to Install app:%v", err)
1276 }
1277
1278 // Verify that when the package contents are corrupted, signature verification fails.
1279 pkgContents[0] = pkgContents[0] ^ 0xFF
Todd Wang5fc36442015-04-07 15:15:27 -07001280 if err := binarylib.Delete(ctx, pkgVON); err != nil {
gauthamt3dbef0c2015-02-10 12:26:02 -08001281 t.Fatalf("Delete(%v) failed:%v", pkgVON, err)
1282 }
1283 if err := os.Remove(filepath.Join(tmpdir, "pkg.txt")); err != nil {
1284 t.Fatalf("Remove(%v) failed:%v", filepath.Join(tmpdir, "pkg.txt"), err)
1285 }
1286 if err := ioutil.WriteFile(filepath.Join(tmpdir, "pkg.txt"), pkgContents, 0600); err != nil {
1287 t.Fatalf("ioutil.WriteFile failed: %v", err)
1288 }
Todd Wang5fc36442015-04-07 15:15:27 -07001289 if _, err = binarylib.UploadFromDir(ctx, pkgVON, tmpdir); err != nil {
1290 t.Fatalf("binarylib.UploadFromDir failed: %v", err)
gauthamt3dbef0c2015-02-10 12:26:02 -08001291 }
Robert Kroeger22fcb032015-04-30 07:40:11 -07001292 if _, err := utiltest.AppStub().Install(ctx, utiltest.MockApplicationRepoName, device.Config{}, nil); verror.ErrorID(err) != impl.ErrOperationFailed.ID {
gauthamt3dbef0c2015-02-10 12:26:02 -08001293 t.Fatalf("Failed to verify signature mismatch for package:%v", pkgVON)
1294 }
gauthamtcb03d132015-02-05 18:05:22 -08001295}