Merge "tools/naming/simulator: port test.sh to go integration tests."
diff --git a/services/mgmt/device/impl/device_installer.go b/services/mgmt/device/impl/device_installer.go
index ee59788..25e0e8a 100644
--- a/services/mgmt/device/impl/device_installer.go
+++ b/services/mgmt/device/impl/device_installer.go
@@ -15,6 +15,9 @@
 //       base/                 - initial installation of device manager
 //         deviced             - link to deviced (self)
 //         deviced.sh          - script to start the device manager
+//       device-data/
+//         persistent-args     - list of persistent arguments for the device
+//                               manager (json encoded)
 //       logs/                 - device manager logs will go here
 //     current                 - set as <Config.CurrentLink>
 //     agent_deviced.sh        - script to launch device manager under agent
@@ -156,6 +159,9 @@
 		// device manager in a different way.
 		Env: VeyronEnvironment(env),
 	}
+	if err := savePersistentArgs(root, envelope.Args); err != nil {
+		return err
+	}
 	if err := linkSelf(deviceDir, "deviced"); err != nil {
 		return err
 	}
diff --git a/services/mgmt/device/impl/device_service.go b/services/mgmt/device/impl/device_service.go
index d570d3e..629a283 100644
--- a/services/mgmt/device/impl/device_service.go
+++ b/services/mgmt/device/impl/device_service.go
@@ -21,6 +21,8 @@
 //         data
 //         signature
 //	 associated.accounts
+//       persistent-args       - list of persistent arguments for the device
+//                               manager (json encoded)
 //
 // The device manager is always expected to be started through the symbolic link
 // passed in as config.CurrentLink, which is monitored by an init daemon. This
@@ -139,6 +141,32 @@
 	return info, nil
 }
 
+func savePersistentArgs(root string, args []string) error {
+	dir := filepath.Join(root, "device-manager", "device-data")
+	if err := os.MkdirAll(dir, 0700); err != nil {
+		return fmt.Errorf("MkdirAll(%q) failed: %v", dir)
+	}
+	data, err := json.Marshal(args)
+	if err != nil {
+		return fmt.Errorf("Marshal(%v) failed: %v", args, err)
+	}
+	fileName := filepath.Join(dir, "persistent-args")
+	return ioutil.WriteFile(fileName, data, 0600)
+}
+
+func loadPersistentArgs(root string) ([]string, error) {
+	fileName := filepath.Join(root, "device-manager", "device-data", "persistent-args")
+	bytes, err := ioutil.ReadFile(fileName)
+	if err != nil {
+		return nil, err
+	}
+	args := []string{}
+	if err := json.Unmarshal(bytes, &args); err != nil {
+		return nil, fmt.Errorf("json.Unmarshal(%v) failed: %v", bytes, err)
+	}
+	return args, nil
+}
+
 func (s *deviceService) Claim(ctx ipc.ServerContext) error {
 	return s.disp.claimDeviceManager(ctx)
 }
@@ -355,6 +383,10 @@
 		vlog.Errorf("app title mismatch. Got %q, expected %q.", envelope.Title, application.DeviceManagerTitle)
 		return verror2.Make(ErrAppTitleMismatch, ctx)
 	}
+	// Read and merge persistent args, if present.
+	if args, err := loadPersistentArgs(s.config.Root); err == nil {
+		envelope.Args = append(envelope.Args, args...)
+	}
 	if s.config.Envelope != nil && reflect.DeepEqual(envelope, s.config.Envelope) {
 		return verror2.Make(ErrUpdateNoOp, ctx)
 	}
diff --git a/tools/mgmt/test.sh b/tools/mgmt/test.sh
index 0cf9890..7a28463 100755
--- a/tools/mgmt/test.sh
+++ b/tools/mgmt/test.sh
@@ -113,6 +113,9 @@
   cd "${WORKDIR}"
   build
 
+  local -r APPLICATIOND_NAME="applicationd"
+  local -r DEVICED_APP_NAME="${APPLICATIOND_NAME}/deviced/test"
+
   BIN_STAGING_DIR=$(shell::tmp_dir)
   cp "${AGENTD_BIN}" "${SUIDHELPER_BIN}" "${INITHELPER_BIN}" "${DEVICEMANAGER_BIN}" "${BIN_STAGING_DIR}"
   shell_test::setup_server_test
@@ -123,9 +126,9 @@
   export VANADIUM_DEVICE_DIR="${DM_INSTALL_DIR}/dm"
 
   if [[ "${WITH_SUID}" == "--with_suid" ]]; then
-    "${DEVICE_SCRIPT}" install "${BIN_STAGING_DIR}" --veyron.tcp.address=127.0.0.1:0
+    "${DEVICE_SCRIPT}" install "${BIN_STAGING_DIR}" --origin="${DEVICED_APP_NAME}" -- --veyron.tcp.address=127.0.0.1:0
   else
-      "${DEVICE_SCRIPT}" install "${BIN_STAGING_DIR}" --single_user -- --veyron.tcp.address=127.0.0.1:0
+    "${DEVICE_SCRIPT}" install "${BIN_STAGING_DIR}" --single_user --origin="${DEVICED_APP_NAME}" -- --veyron.tcp.address=127.0.0.1:0
   fi
 
   "${VRUN}" "${DEVICE_SCRIPT}" start
@@ -147,6 +150,7 @@
     shell_test::fail "line ${LINENO}: store set failed"
 
   # Claim the device as "alice/myworkstation".
+  echo ">> Claiming the device manager"
   "${DEVICE_BIN}" claim "${DM_NAME}/device" myworkstation
 
   if [[ "${WITH_SUID}" == "--with_suid" ]]; then
@@ -172,6 +176,7 @@
   # Upload a binary to the binary server.  The binary we upload is binaryd
   # itself.
   local -r SAMPLE_APP_BIN_NAME="${BINARYD_NAME}/testapp"
+  echo ">> Uploading ${SAMPLE_APP_BIN_NAME}"
   "${BINARY_BIN}" upload "${SAMPLE_APP_BIN_NAME}" "${BINARYD_BIN}"
 
   # Verify that the binary we uploaded is shown by glob.
@@ -180,7 +185,6 @@
 
   # Start an application server under the blessing "alice/myworkstation/applicationd" so that
   # the device ("alice/myworkstation") can talk to it.
-  local -r APPLICATIOND_NAME="applicationd"
   shell_test::start_server "${VRUN}" --name=myworkstation/applicationd "${APPLICATIOND_BIN}" --name="${APPLICATIOND_NAME}" \
     --store="$(shell::tmp_dir)" --veyron.tcp.address=127.0.0.1:0 \
     || shell_test::fail "line ${LINENO} failed to start applicationd"
@@ -188,6 +192,7 @@
   # Upload an envelope for our test app.
   local -r SAMPLE_APP_NAME="${APPLICATIOND_NAME}/testapp/v0"
   local -r APP_PUBLISH_NAME="testbinaryd"
+  echo ">> Uploading ${SAMPLE_APP_NAME}"
   echo "{\"Title\":\"BINARYD\", \"Args\":[\"--name=${APP_PUBLISH_NAME}\", \"--root_dir=./binstore\", \"--veyron.tcp.address=127.0.0.1:0\"], \"Binary\":\"${SAMPLE_APP_BIN_NAME}\", \"Env\":[]}" > ./app.envelope && \
     "${APPLICATION_BIN}" put "${SAMPLE_APP_NAME}" "${DEVICE_PROFILE}" ./app.envelope && rm ./app.envelope
 
@@ -196,6 +201,7 @@
     "BINARYD" "${LINENO}"
 
   # Install the app on the device.
+  echo ">> Installing ${SAMPLE_APP_NAME}"
   local -r INSTALLATION_NAME=$("${DEVICE_BIN}" install "${DM_NAME}/apps" "${SAMPLE_APP_NAME}" | sed -e 's/Successfully installed: "//' | sed -e 's/"//')
 
   # Verify that the installation shows up when globbing the device manager.
@@ -203,6 +209,7 @@
     "${INSTALLATION_NAME}" "${LINENO}"
 
   # Start an instance of the app, granting it blessing extension myapp.
+  echo ">> Starting ${INSTALLATION_NAME}"
   local -r INSTANCE_NAME=$("${DEVICE_BIN}" start "${INSTALLATION_NAME}" myapp | sed -e 's/Successfully started: "//' | sed -e 's/"//')
   wait_for_mountentry "${NAMESPACE_BIN}" "5" "${APP_PUBLISH_NAME}"
 
@@ -216,12 +223,41 @@
     "Default blessings: alice/myapp/BINARYD" "${LINENO}"
 
   # Stop the instance.
+  echo ">> Stopping ${INSTANCE_NAME}"
   "${DEVICE_BIN}" stop "${INSTANCE_NAME}"
 
   # Verify that logs, but not stats, show up when globbing the stopped instance.
   shell_test::assert_eq "$("${NAMESPACE_BIN}" glob "${INSTANCE_NAME}/stats/...")" "" "${LINENO}"
   shell_test::assert_ne "$("${NAMESPACE_BIN}" glob "${INSTANCE_NAME}/logs/...")" "" "${LINENO}"
 
+  # Upload a deviced binary.
+  local -r DEVICED_APP_BIN_NAME="${BINARYD_NAME}/deviced"
+  echo ">> Uploading ${DEVICEMANAGER_BIN}"
+  "${BINARY_BIN}" upload "${DEVICED_APP_BIN_NAME}" "${DEVICEMANAGER_BIN}"
+
+  # Upload a device manager envelope.
+  echo ">> Uploading ${DEVICED_APP_NAME}"
+  echo "{\"Title\":\"device manager\", \"Binary\":\"${DEVICED_APP_BIN_NAME}\"}" > ./deviced.envelope && \
+    "${APPLICATION_BIN}" put "${DEVICED_APP_NAME}" "${DEVICE_PROFILE}" ./deviced.envelope && rm ./deviced.envelope
+
+  # Update the device manager.
+  echo ">> Updating device manager"
+  "${DEVICE_BIN}" update "${DM_NAME}/device"
+  DM_EP=$(wait_for_mountentry "${NAMESPACE_BIN}" 5 "${DM_NAME}" "${DM_EP}")
+
+  # Verify that device manager is still published under the expected name
+  # (hostname).
+  shell_test::assert_ne "$("${NAMESPACE_BIN}" glob "${DM_NAME}")" "" "${LINENO}"
+
+  # Revert the device manager.
+  echo ">> Reverting device manager"
+  "${DEVICE_BIN}" revert "${DM_NAME}/device"
+  DM_EP=$(wait_for_mountentry "${NAMESPACE_BIN}" 5 "${DM_NAME}" "${DM_EP}")
+
+  # Verify that device manager is still published under the expected name
+  # (hostname).
+  shell_test::assert_ne "$("${NAMESPACE_BIN}" glob "${DM_NAME}")" "" "${LINENO}"
+
   # Restart the device manager.
   "${DEVICE_BIN}" suspend "${DM_NAME}/device"
   wait_for_mountentry "${NAMESPACE_BIN}" "5" "${DM_NAME}" "{DM_EP}"