Merge "Veyron.core: Stop using ServerContext as a contex.T"
diff --git a/services/mgmt/application/applicationd/test.sh b/services/mgmt/application/applicationd/test.sh
index c3a3d92..4621996 100755
--- a/services/mgmt/application/applicationd/test.sh
+++ b/services/mgmt/application/applicationd/test.sh
@@ -8,6 +8,9 @@
 
 source "$(go list -f {{.Dir}} veyron.io/veyron/shell/lib)/shell_test.sh"
 
+# Run the test under the security agent.
+shell_test::enable_agent "$@"
+
 readonly WORKDIR="${shell_test_WORK_DIR}"
 
 build() {
@@ -24,7 +27,7 @@
   # Start the application repository daemon.
   local -r REPO="applicationd-test-repo"
   local -r STORE=$(shell::tmp_dir)
-  shell_test::start_server "${APPLICATIOND_BIN}" --name="${REPO}" --store="${STORE}" --veyron.tcp.address=127.0.0.1:0 \
+  shell_test::start_server "${VRUN}" "${APPLICATIOND_BIN}" --name="${REPO}" --store="${STORE}" --veyron.tcp.address=127.0.0.1:0 \
     || shell_test::fail "line ${LINENO} failed to start applicationd"
 
   # Create an application envelope.
diff --git a/services/mgmt/binary/binaryd/test.sh b/services/mgmt/binary/binaryd/test.sh
index 602a643..8bc4402 100755
--- a/services/mgmt/binary/binaryd/test.sh
+++ b/services/mgmt/binary/binaryd/test.sh
@@ -8,6 +8,9 @@
 
 source "$(go list -f {{.Dir}} veyron.io/veyron/shell/lib)/shell_test.sh"
 
+# Run the test under the security agent.
+shell_test::enable_agent "$@"
+
 readonly WORKDIR="${shell_test_WORK_DIR}"
 
 build() {
@@ -23,7 +26,7 @@
 
   # Start the binary repository daemon.
   local -r REPO="binaryd-test-repo"
-  shell_test::start_server "${BINARYD_BIN}" --name="${REPO}" --veyron.tcp.address=127.0.0.1:0 --http=127.0.0.1:0 \
+  shell_test::start_server "${VRUN}" "${BINARYD_BIN}" --name="${REPO}" --veyron.tcp.address=127.0.0.1:0 --http=127.0.0.1:0 \
     || shell_test::fail "line ${LINENO} failed to start binaryd"
   local -r HTTP_ADDR=$(grep 'HTTP server at: "' "${START_SERVER_LOG_FILE}" | sed -e 's/^.*HTTP server at: "//' | sed -e 's/"$//')
 
diff --git a/services/mgmt/build/buildd/test.sh b/services/mgmt/build/buildd/test.sh
index b16b09b..90ee500 100755
--- a/services/mgmt/build/buildd/test.sh
+++ b/services/mgmt/build/buildd/test.sh
@@ -7,6 +7,9 @@
 
 source "$(go list -f {{.Dir}} veyron.io/veyron/shell/lib)/shell_test.sh"
 
+# Run the test under the security agent.
+shell_test::enable_agent "$@"
+
 readonly WORKDIR="${shell_test_WORK_DIR}"
 
 build() {
@@ -24,7 +27,7 @@
   local -r SERVER="buildd-test-server"
   local GO_BIN=$(which go)
   local -r GO_ROOT=$("${GO_BIN}" env GOROOT)
-  shell_test::start_server "${BUILDD_BIN}" --name="${SERVER}" --gobin="${GO_BIN}" --goroot="${GO_ROOT}" --veyron.tcp.address=127.0.0.1:0 \
+  shell_test::start_server "${VRUN}" "${BUILDD_BIN}" --name="${SERVER}" --gobin="${GO_BIN}" --goroot="${GO_ROOT}" --veyron.tcp.address=127.0.0.1:0 \
     || shell_test::fail "line ${LINENO} failed to start server"
 
   # Create and build a test source file.
diff --git a/services/mgmt/device/deviced/main.go b/services/mgmt/device/deviced/main.go
index e9221ba..d3b3581 100644
--- a/services/mgmt/device/deviced/main.go
+++ b/services/mgmt/device/deviced/main.go
@@ -18,6 +18,7 @@
 	publishAs   = flag.String("name", "", "name to publish the device manager at")
 	installSelf = flag.Bool("install_self", false, "perform installation using environment and command-line flags")
 	installFrom = flag.String("install_from", "", "if not-empty, perform installation from the provided application envelope object name")
+	uninstall   = flag.Bool("uninstall", false, "uninstall the installation specified via the config")
 )
 
 func main() {
@@ -45,6 +46,14 @@
 		return
 	}
 
+	if *uninstall {
+		if err := impl.Uninstall(); err != nil {
+			vlog.Errorf("Uninstall failed: %v", err)
+			os.Exit(1)
+		}
+		return
+	}
+
 	server, err := runtime.NewServer()
 	if err != nil {
 		vlog.Fatalf("NewServer() failed: %v", err)
diff --git a/services/mgmt/device/impl/device_installer.go b/services/mgmt/device/impl/device_installer.go
index 393d0b6..ac291c0 100644
--- a/services/mgmt/device/impl/device_installer.go
+++ b/services/mgmt/device/impl/device_installer.go
@@ -94,3 +94,23 @@
 	return updateLink(filepath.Join(deviceDir, "deviced.sh"), configState.CurrentLink)
 	// TODO(caprita): Update system management daemon.
 }
+
+// Uninstall undoes SelfInstall, removing the device manager's installation
+// directory and soft link.
+func Uninstall() error {
+	configState, err := config.Load()
+	if err != nil {
+		return fmt.Errorf("failed to load config: %v", err)
+	}
+
+	vlog.VI(1).Infof("Config for device manager: %v", configState)
+	configState.Name = "dummy" // Just so that Validate passes.
+	if err := configState.Validate(); err != nil {
+		return fmt.Errorf("invalid config %v: %v", configState, err)
+	}
+	if err := os.RemoveAll(configState.Root); err != nil {
+		return fmt.Errorf("RemoveAll(%v) failed: %v", configState.Root, err)
+	}
+	return os.Remove(configState.CurrentLink)
+	// TODO(caprita): Update system management daemon.
+}
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index 4f2e138..0a06551 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -61,6 +61,7 @@
 	deviceManagerCmd = "deviceManager"
 	appCmd           = "app"
 	installerCmd     = "installer"
+	uninstallerCmd   = "uninstaller"
 )
 
 func init() {
@@ -71,6 +72,7 @@
 	modules.RegisterChild(deviceManagerCmd, "", deviceManager)
 	modules.RegisterChild(appCmd, "", app)
 	modules.RegisterChild(installerCmd, "", install)
+	modules.RegisterChild(uninstallerCmd, "", uninstall)
 	testutil.Init()
 
 	if modules.IsModulesProcess() {
@@ -213,6 +215,15 @@
 	return nil
 }
 
+// uninstall uninstalls the device manager.
+func uninstall(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	if err := impl.Uninstall(); err != nil {
+		vlog.Fatalf("Uninstall failed: %v", err)
+		return err
+	}
+	return nil
+}
+
 // appService defines a test service that the test app should be running.
 // TODO(caprita): Use this to make calls to the app and verify how Suspend/Stop
 // interact with an active service.
@@ -950,20 +961,20 @@
 	}
 }
 
-// TestDeviceManagerInstall verifies the 'self install' functionality of the
-// device manager: it runs SelfInstall in a child process, then runs the
-// executable from the soft link that the installation created.  This should
-// bring up a functioning device manager.
-func TestDeviceManagerInstall(t *testing.T) {
+// TestDeviceManagerInstallUninstall verifies the 'self install' and 'uninstall'
+// functionality of the device manager: it runs SelfInstall in a child process,
+// then runs the executable from the soft link that the installation created.
+// This should bring up a functioning device manager.  In the end it runs
+// Uninstall and verifies that the installation is gone.
+func TestDeviceManagerInstallUninstall(t *testing.T) {
 	sh, deferFn := createShellAndMountTable(t)
 	defer deferFn()
 
-	root, cleanup := setupRootDir(t)
+	testDir, cleanup := setupRootDir(t)
 	defer cleanup()
 
-	// Current link does not have to live in the root dir, but it's
-	// convenient to put it there so we have everything in one place.
-	currLink := filepath.Join(root, "current_link")
+	root := filepath.Join(testDir, "root")
+	currLink := filepath.Join(testDir, "current_link")
 
 	// Create an 'envelope' for the device manager that we can pass to the
 	// installer, to ensure that the device manager that the installer
@@ -1006,6 +1017,18 @@
 	dms.Expect("dm terminating")
 	dms.ExpectEOF()
 	dmh.Shutdown(os.Stderr, os.Stderr)
+
+	// Uninstall.
+	uninstallerEnv := []string{config.RootEnv + "=" + root, config.CurrentLinkEnv + "=" + currLink, config.HelperEnv + "=" + "unused"}
+	uninstallerh, uninstallers := runShellCommand(t, sh, uninstallerEnv, uninstallerCmd)
+	uninstallers.ExpectEOF()
+	uninstallerh.Shutdown(os.Stderr, os.Stderr)
+	if _, err := os.Stat(currLink); err == nil || !os.IsNotExist(err) {
+		t.Fatalf("Stat(%v) returned %v", currLink, err)
+	}
+	if _, err := os.Stat(root); err == nil || !os.IsNotExist(err) {
+		t.Fatalf("Stat(%v) returned %v", root, err)
+	}
 }
 
 func TestDeviceManagerGlobAndDebug(t *testing.T) {
diff --git a/services/mgmt/profile/profiled/test.sh b/services/mgmt/profile/profiled/test.sh
index d7ea356..70f08eb 100755
--- a/services/mgmt/profile/profiled/test.sh
+++ b/services/mgmt/profile/profiled/test.sh
@@ -9,6 +9,9 @@
 
 source "$(go list -f {{.Dir}} veyron.io/veyron/shell/lib)/shell_test.sh"
 
+# Run the test under the security agent.
+shell_test::enable_agent "$@"
+
 readonly WORKDIR="${shell_test_WORK_DIR}"
 
 build() {
@@ -27,7 +30,7 @@
   # Start the profile repository daemon.
   local -r REPO="profiled-test-repo"
   local -r STORE=$(shell::tmp_dir)
-  shell_test::start_server "${PROFILED_BIN}" --name="${REPO}" --veyron.tcp.address=127.0.0.1:0 --store="${STORE}" \
+  shell_test::start_server "${VRUN}" "${PROFILED_BIN}" --name="${REPO}" --veyron.tcp.address=127.0.0.1:0 --store="${STORE}" \
     || shell_test::fail "line ${LINENO} failed to start server"
 
   # Create a profile.
diff --git a/services/mounttable/mounttabled/test.sh b/services/mounttable/mounttabled/test.sh
index f8fa27e..e9824ec 100755
--- a/services/mounttable/mounttabled/test.sh
+++ b/services/mounttable/mounttabled/test.sh
@@ -11,6 +11,9 @@
 
 source "$(go list -f {{.Dir}} veyron.io/veyron/shell/lib)/shell_test.sh"
 
+# Run the test under the security agent.
+shell_test::enable_agent "$@"
+
 readonly WORKDIR="${shell_test_WORK_DIR}"
 
 build() {
@@ -29,7 +32,7 @@
   local -r MTLOG="${WORKDIR}/mt.log"
 
   shell::run_server "${shell_test_DEFAULT_SERVER_TIMEOUT}" "${MTLOG}" "${MTLOG}" \
-    ${MOUNTTABLED_BIN} --veyron.tcp.address=127.0.0.1:0 -vmodule=publisher=2 --neighborhood_name="${NHNAME}" &> /dev/null \
+    "${VRUN}" "${MOUNTTABLED_BIN}" --veyron.tcp.address=127.0.0.1:0 -vmodule=publisher=2 --neighborhood_name="${NHNAME}" &> /dev/null \
     || shell_test::fail "line ${LINENO}: failed to start mounttabled"
   shell::timed_wait_for "${shell_test_DEFAULT_MESSAGE_TIMEOUT}" "${MTLOG}" "ipc pub: mount" \
     || shell_test::fail "line ${LINENO}: failed to mount mounttabled"
diff --git a/tools/debug/test.sh b/tools/debug/test.sh
index 4641010..7e6e0d8 100755
--- a/tools/debug/test.sh
+++ b/tools/debug/test.sh
@@ -7,6 +7,9 @@
 
 source "$(go list -f {{.Dir}} veyron.io/veyron/shell/lib)/shell_test.sh"
 
+# Run the test under the security agent.
+shell_test::enable_agent "$@"
+
 readonly WORKDIR="${shell_test_WORK_DIR}"
 readonly DEBUG_FLAGS="--veyron.vtrace.sample_rate=1"
 
@@ -29,15 +32,9 @@
   mkdir "tmp"
   export TMPDIR="${WORKDIR}/tmp"
 
-  export VEYRON_CREDENTIALS=$(shell::tmp_dir)
-  # Create specific VeyronCredentials for the debug command forked from the environment's
-  # VeyronCredentials.
-  export DEBUG_CREDENTIALS=$(shell_test::forkcredentials "${VEYRON_CREDENTIALS}" debug)
-
   shell_test::setup_server_test || shell_test::fail "setup_server_test failed"
   local -r EP="${NAMESPACE_ROOT}"
   unset NAMESPACE_ROOT
-  export VEYRON_CREDENTIALS="${DEBUG_CREDENTIALS}"
 
   # Test top level glob.
   local -r DBGLOG="${WORKDIR}/debug.log"
diff --git a/tools/mgmt/device/dmuninstall b/tools/mgmt/device/dmuninstall
new file mode 100755
index 0000000..ce12747
--- /dev/null
+++ b/tools/mgmt/device/dmuninstall
@@ -0,0 +1,53 @@
+#!/bin/bash
+#
+# Uninstalls device manager from the local machine.
+#
+# Usage:
+#
+# ./dmuninstall <install parent dir>
+
+set -e
+
+usage() {
+  echo "usage:"
+  echo "./dmuninstall [--single_user] <install parent dir>"
+}
+
+main() {
+  if [[ "$1" == "--single_user" ]]; then
+    local -r SINGLE_USER=true
+    shift
+  else
+    local -r SINGLE_USER=false
+  fi
+  local -r INSTALL_PARENT_DIR="$1"
+  if [[ -z "${INSTALL_PARENT_DIR}" ]]; then
+    echo 'No local install directory specified!'
+    usage
+    exit 1
+  fi
+  shift
+  local -r INSTALL_DIR="${INSTALL_PARENT_DIR}/device_manager"
+  if [[ ! -d "${INSTALL_DIR}" ]]; then
+    echo "${INSTALL_DIR} does not exist or is not a directory!"
+    exit 1
+  fi
+
+  # Tell the device manager to uninstall itself.
+  local -r DM_ROOT="${INSTALL_DIR}/dmroot"
+  echo "Uninstalling device manager from ${DM_ROOT} ..."
+
+  local -r BIN_INSTALL="${INSTALL_DIR}/bin"
+
+  VEYRON_DM_CURRENT="${INSTALL_DIR}/deviced.curr" VEYRON_DM_ROOT="${DM_ROOT}" VEYRON_DM_HELPER="unused" "${BIN_INSTALL}/deviced" --uninstall
+  echo "Device manager uninstalled."
+
+  if [[ ${SINGLE_USER} == false ]]; then
+    sudo rm -rf "${INSTALL_DIR}"
+  else
+    rm -rf "${INSTALL_DIR}"
+  fi
+  echo "Removed ${INSTALL_DIR}"
+}
+
+main "$@"
diff --git a/tools/mgmt/test.sh b/tools/mgmt/test.sh
index 4a4b055..0374601 100755
--- a/tools/mgmt/test.sh
+++ b/tools/mgmt/test.sh
@@ -19,6 +19,7 @@
   PRINCIPAL_BIN="$(shell_test::build_go_binary 'veyron.io/veyron/veyron/tools/principal')"
   DEBUG_BIN="$(shell_test::build_go_binary 'veyron.io/veyron/veyron/tools/debug')"
   DMINSTALL_SCRIPT="$(go list -f {{.Dir}} veyron.io/veyron/veyron/tools/mgmt/device)/dminstall"
+  DMUNINSTALL_SCRIPT="$(go list -f {{.Dir}} veyron.io/veyron/veyron/tools/mgmt/device)/dmuninstall"
 }
 
 # TODO(caprita): Move to shell_tesh.sh
@@ -44,11 +45,33 @@
     fi
     sleep 1
   done
-  bash
   echo "Timed out waiting for ${NAME} to appear in the mounttable."
   return 1
 }
 
+###############################################################################
+# Waits until the given process is gone, within a set timeout.
+# Arguments:
+#   pid of process
+#   timeout in seconds
+# Returns:
+#   0 if the pid is gone, and 1 if the timeout expires before that happens.
+###############################################################################
+wait_for_process_exit() {
+  local -r PID="$1"
+  local -r TIMEOUT="$2"
+  for i in $(seq 1 "${TIMEOUT}"); do
+    local RESULT=$(shell::check_result kill -0 "${PID}")
+    if [[ "${RESULT}" != "0" ]]; then
+      # Process is gone, can return early.
+      return 0
+    fi
+    sleep 1
+  done
+  echo "Timed out waiting for PID ${PID} to disappear."
+  return 1
+}
+
 main() {
   cd "${WORKDIR}"
   build
@@ -63,9 +86,11 @@
   # test.sh by hand and exercise the code that requires root privileges.
 
   # Install and start device manager.
-  shell_test::start_server "${DMINSTALL_SCRIPT}" --single_user $(shell::tmp_dir) \
+  DM_INSTALL_DIR=$(shell::tmp_dir)
+  shell_test::start_server "${DMINSTALL_SCRIPT}" --single_user "${DM_INSTALL_DIR}" \
     "${BIN_STAGING_DIR}" -- --veyron.tcp.address=127.0.0.1:0 || shell_test::fail "line ${LINENO} failed to start device manager"
   # Dump dminstall's log, just to provide visibility into its steps.
+  local -r DM_PID="${START_SERVER_PID}"
   cat "${START_SERVER_LOG_FILE}"
 
   local -r DM_NAME=$(hostname)
@@ -142,6 +167,15 @@
   shell_test::assert_eq "$("${NAMESPACE_BIN}" glob "${INSTANCE_NAME}/stats/...")" "" "${LINENO}"
   shell_test::assert_ne "$("${NAMESPACE_BIN}" glob "${INSTANCE_NAME}/logs/...")" "" "${LINENO}"
 
+  kill "${DM_PID}"
+  wait_for_process_exit "${DM_PID}" 5
+
+  "${DMUNINSTALL_SCRIPT}" --single_user "${DM_INSTALL_DIR}" \
+    || shell_test::fail "line ${LINENO} failed to uninstall device manager"
+
+  if [[ -n "$(ls -A "${DM_INSTALL_DIR}")" ]]; then
+    shell_test::fail "${DM_INSTALL_DIR} is not empty"
+  fi
   shell_test::pass
 }
 
diff --git a/tools/naming/simulator/test.sh b/tools/naming/simulator/test.sh
index 835859b..06668c7 100755
--- a/tools/naming/simulator/test.sh
+++ b/tools/naming/simulator/test.sh
@@ -4,6 +4,9 @@
 
 source "$(go list -f {{.Dir}} veyron.io/veyron/shell/lib)/shell_test.sh"
 
+# Run the test under the security agent.
+shell_test::enable_agent "$@"
+
 readonly WORKDIR="${shell_test_WORK_DIR}"
 
 main() {
@@ -16,7 +19,7 @@
   local file
   for file in "${DIR}"/*.scr; do
     echo "${file}"
-    "${SIMULATOR_BIN}" --interactive=false < "${file}" &> /dev/null || shell_test::fail "line ${LINENO}: failed for ${file}"
+    "${VRUN}" "${SIMULATOR_BIN}" --interactive=false < "${file}" &> /dev/null || shell_test::fail "line ${LINENO}: failed for ${file}"
   done
   shell_test::pass
 }