Merge "Add options to reflectutil DeepEqual"
diff --git a/profiles/roaming/roaminginit.go b/profiles/roaming/roaminginit.go
index 8b9eb01..3e6de0b 100644
--- a/profiles/roaming/roaminginit.go
+++ b/profiles/roaming/roaminginit.go
@@ -57,7 +57,7 @@
 		Addrs: ipc.ListenAddrs(lf.Addrs),
 		Proxy: lf.ListenProxy,
 	}
-	reservedDispatcher := debug.NewDispatcher(vlog.Log.LogDir(), sflag.NewAuthorizerOrDie())
+	reservedDispatcher := debug.NewDispatcher(vlog.Log.LogDir, sflag.NewAuthorizerOrDie())
 
 	ac := appcycle.New()
 
diff --git a/profiles/static/staticinit.go b/profiles/static/staticinit.go
index f477d21..966b0dc 100644
--- a/profiles/static/staticinit.go
+++ b/profiles/static/staticinit.go
@@ -41,7 +41,7 @@
 		Addrs: ipc.ListenAddrs(lf.Addrs),
 		Proxy: lf.ListenProxy,
 	}
-	reservedDispatcher := debug.NewDispatcher(vlog.Log.LogDir(), sflag.NewAuthorizerOrDie())
+	reservedDispatcher := debug.NewDispatcher(vlog.Log.LogDir, sflag.NewAuthorizerOrDie())
 
 	ac := appcycle.New()
 
diff --git a/runtimes/google/ipc/debug_test.go b/runtimes/google/ipc/debug_test.go
index e1bf356..e351242 100644
--- a/runtimes/google/ipc/debug_test.go
+++ b/runtimes/google/ipc/debug_test.go
@@ -30,7 +30,7 @@
 	pclient.AddToRoots(bclient)                    // Client recognizes "server" as a root of blessings.
 	pclient.BlessingStore().Set(bclient, "server") // Client presents bclient to server
 
-	debugDisp := debug.NewDispatcher(vlog.Log.LogDir(), nil)
+	debugDisp := debug.NewDispatcher(vlog.Log.LogDir, nil)
 
 	sm := manager.InternalNew(naming.FixedRoutingID(0x555555555))
 	defer sm.Shutdown()
diff --git a/services/identity/identityd/identityd_v23_test.go b/services/identity/identityd/identityd_v23_test.go
index 127b20c..aeedd6b 100644
--- a/services/identity/identityd/identityd_v23_test.go
+++ b/services/identity/identityd/identityd_v23_test.go
@@ -49,7 +49,7 @@
 			if err != nil {
 				i.Fatalf("ReadAll() failed: %v", err)
 			}
-			if want := "Received blessings"; strings.Contains(string(output), want) {
+			if want := "Received blessings"; !strings.Contains(string(output), want) {
 				i.Fatalf("failed to seek blessings: %v", string(output))
 			}
 			return
diff --git a/services/mgmt/application/applicationd/test.sh b/services/mgmt/application/applicationd/test.sh
index a729164..e671012 100755
--- a/services/mgmt/application/applicationd/test.sh
+++ b/services/mgmt/application/applicationd/test.sh
@@ -41,10 +41,10 @@
   "Binary": {
     "File": "foo",
     "Signature": {
-      "Purpose": "",
+      "Purpose": null,
       "Hash": "",
-      "R": "",
-      "S": ""
+      "R": null,
+      "S": null
     }
   },
   "Publisher": {
@@ -59,6 +59,7 @@
   # Match the application envelope.
   local -r ENVELOPE_GOT=$(shell::tmp_file)
   "${APPLICATION_BIN}" match "${APPLICATION}" "${PROFILE}" | tee "${ENVELOPE_GOT}" || shell_test::fail "line ${LINENO}: 'match' failed"
+
   cmp "${ENVELOPE_WANT}" "${ENVELOPE_GOT}" &> /dev/null || shell_test::fail "mismatching application envelopes"
 
   # Remove the application envelope.
diff --git a/services/mgmt/debug/dispatcher.go b/services/mgmt/debug/dispatcher.go
index 205ae58..4a8d9b0 100644
--- a/services/mgmt/debug/dispatcher.go
+++ b/services/mgmt/debug/dispatcher.go
@@ -15,14 +15,14 @@
 
 // dispatcher holds the state of the debug dispatcher.
 type dispatcher struct {
-	logsDir string // The root of the logs directory.
-	auth    security.Authorizer
+	logsDirFunc func() string // The function returns the root of the logs directory.
+	auth        security.Authorizer
 }
 
 var _ ipc.Dispatcher = (*dispatcher)(nil)
 
-func NewDispatcher(logsDir string, authorizer security.Authorizer) ipc.Dispatcher {
-	return &dispatcher{logsDir, authorizer}
+func NewDispatcher(logsDirFunc func() string, authorizer security.Authorizer) ipc.Dispatcher {
+	return &dispatcher{logsDirFunc, authorizer}
 }
 
 // The first part of the names of the objects served by this dispatcher.
@@ -49,7 +49,7 @@
 	}
 	switch parts[0] {
 	case "logs":
-		return logreaderimpl.NewLogFileService(d.logsDir, suffix), d.auth, nil
+		return logreaderimpl.NewLogFileService(d.logsDirFunc(), suffix), d.auth, nil
 	case "pprof":
 		return pprofimpl.NewPProfService(), d.auth, nil
 	case "stats":
diff --git a/services/mgmt/debug/dispatcher_test.go b/services/mgmt/debug/dispatcher_test.go
index aa21ced..f6c62d6 100644
--- a/services/mgmt/debug/dispatcher_test.go
+++ b/services/mgmt/debug/dispatcher_test.go
@@ -32,7 +32,7 @@
 	if len(logsDir) == 0 {
 		return "", nil, fmt.Errorf("logs directory missing")
 	}
-	disp := NewDispatcher(logsDir, nil)
+	disp := NewDispatcher(func() string { return logsDir }, nil)
 	server, err := veyron2.NewServer(ctx)
 	if err != nil {
 		return "", nil, fmt.Errorf("failed to start debug server: %v", err)
diff --git a/services/mgmt/device/impl/device_installer.go b/services/mgmt/device/impl/device_installer.go
index 25e0e8a..96075e0 100644
--- a/services/mgmt/device/impl/device_installer.go
+++ b/services/mgmt/device/impl/device_installer.go
@@ -227,27 +227,27 @@
 	if err := os.MkdirAll(logs, perm); err != nil {
 		return fmt.Errorf("MkdirAll(%v, %v) failed: %v", logs, perm, err)
 	}
+	stdoutLog, stderrLog := filepath.Join(logs, "STDOUT"), filepath.Join(logs, "STDERR")
 	// TODO(caprita): Switch all our generated bash scripts to use templates.
 	output := "#!/bin/bash\n"
-	output += fmt.Sprintf("readonly TIMESTAMP=$(%s)\n", dateCommand)
+	output += "if [ -z \"$DEVICE_MANAGER_DONT_REDIRECT_STDOUT_STDERR\" ]; then\n"
+	output += fmt.Sprintf("  TIMESTAMP=$(%s)\n", dateCommand)
+	output += fmt.Sprintf("  exec > %s-$TIMESTAMP 2> %s-$TIMESTAMP\n", stdoutLog, stderrLog)
+	output += "fi\n"
 	output += fmt.Sprintf("%s=%q ", consts.VeyronCredentials, principalDir)
 	// Escape the path to the binary; %q uses Go-syntax escaping, but it's
 	// close enough to Bash that we're using it as an approximation.
 	//
 	// TODO(caprita/rthellend): expose and use shellEscape (from
 	// veyron/tools/debug/impl.go) instead.
-	output += fmt.Sprintf("exec %q ", agent)
+	output += fmt.Sprintf("exec %q --log_dir=%q ", agent, logs)
 	if singleUser {
 		output += "--no_passphrase "
 	}
 	if !sessionMode {
 		output += fmt.Sprintf("--restart_exit_code=!0 ")
 	}
-	output += fmt.Sprintf("--additional_principals=%q ", keyDir)
-	stdoutLog, stderrLog := filepath.Join(logs, "STDERR"), filepath.Join(logs, "STDOUT")
-	// Write stdout and stderr both to the standard streams, and also to
-	// timestamped files.
-	output += fmt.Sprintf("%q > >(tee %s-$TIMESTAMP) 2> >(tee %s-$TIMESTAMP >&2)\n", currLink, stdoutLog, stderrLog)
+	output += fmt.Sprintf("--additional_principals=%q %q", keyDir, currLink)
 	path := filepath.Join(workspace, "agent_deviced.sh")
 	if err := ioutil.WriteFile(path, []byte(output), 0700); err != nil {
 		return fmt.Errorf("WriteFile(%v) failed: %v", path, err)
diff --git a/services/mgmt/device/impl/device_service.go b/services/mgmt/device/impl/device_service.go
index 897c17d..533e3ea 100644
--- a/services/mgmt/device/impl/device_service.go
+++ b/services/mgmt/device/impl/device_service.go
@@ -249,6 +249,7 @@
 func (s *deviceService) testDeviceManager(ctx *context.T, workspace string, envelope *application.Envelope) error {
 	path := filepath.Join(workspace, "deviced.sh")
 	cmd := exec.Command(path)
+	cmd.Env = []string{"DEVICE_MANAGER_DONT_REDIRECT_STDOUT_STDERR=1"}
 
 	for k, v := range map[string]*io.Writer{
 		"stdout": &cmd.Stdout,
@@ -384,8 +385,17 @@
 		return verror.New(ErrOperationFailed, nil)
 	}
 
+	if err := os.MkdirAll(logs, 0700); err != nil {
+		vlog.Errorf("MkdirAll(%v) failed: %v", logs, err)
+		return verror.New(ErrOperationFailed, nil)
+	}
+	stderrLog, stdoutLog := filepath.Join(logs, "STDERR"), filepath.Join(logs, "STDOUT")
+
 	output := "#!/bin/bash\n"
-	output += fmt.Sprintf("readonly TIMESTAMP=$(%s)\n", dateCommand)
+	output += "if [ -z \"$DEVICE_MANAGER_DONT_REDIRECT_STDOUT_STDERR\" ]; then\n"
+	output += fmt.Sprintf("  TIMESTAMP=$(%s)\n", dateCommand)
+	output += fmt.Sprintf("  exec > %s-$TIMESTAMP 2> %s-$TIMESTAMP\n", stdoutLog, stderrLog)
+	output += "fi\n"
 	output += strings.Join(config.QuoteEnv(append(envelope.Env, configSettings...)), " ") + " "
 	// Escape the path to the binary; %q uses Go-syntax escaping, but it's
 	// close enough to Bash that we're using it as an approximation.
@@ -393,15 +403,9 @@
 	// TODO(caprita/rthellend): expose and use shellEscape (from
 	// veyron/tools/debug/impl.go) instead.
 	output += fmt.Sprintf("exec %q", filepath.Join(workspace, "deviced")) + " "
+	output += fmt.Sprintf("--log_dir=%q ", logs)
 	output += strings.Join(envelope.Args, " ")
-	if err := os.MkdirAll(logs, 0700); err != nil {
-		vlog.Errorf("MkdirAll(%v) failed: %v", logs, err)
-		return verror.New(ErrOperationFailed, nil)
-	}
-	stderrLog, stdoutLog := filepath.Join(logs, "STDERR"), filepath.Join(logs, "STDOUT")
-	// Write stdout and stderr both to the standard streams, and also to
-	// timestamped files.
-	output += fmt.Sprintf(" > >(tee %s-$TIMESTAMP) 2> >(tee %s-$TIMESTAMP >&2)\n", stdoutLog, stderrLog)
+
 	path = filepath.Join(workspace, "deviced.sh")
 	if err := ioutil.WriteFile(path, []byte(output), 0700); err != nil {
 		vlog.Errorf("WriteFile(%v) failed: %v", path, err)
diff --git a/services/mgmt/device/impl/impl_test.go b/services/mgmt/device/impl/impl_test.go
index bd43d09..a26fbf4 100644
--- a/services/mgmt/device/impl/impl_test.go
+++ b/services/mgmt/device/impl/impl_test.go
@@ -69,6 +69,8 @@
 	testFlagName = "random_test_flag"
 	// VEYRON prefix is necessary to pass the env filtering.
 	testEnvVarName = "VEYRON_RANDOM_ENV_VALUE"
+
+	redirectEnv = "DEVICE_MANAGER_DONT_REDIRECT_STDOUT_STDERR"
 )
 
 var flagValue = flag.String(testFlagName, "default", "")
@@ -117,7 +119,7 @@
 		vlog.Fatalf("execScript expected %d arguments, got %d instead", want, got)
 	}
 	script := args[0]
-	osenv := []string{}
+	osenv := []string{redirectEnv + "=1"}
 	if env["PAUSE_BEFORE_STOP"] == "1" {
 		osenv = append(osenv, "PAUSE_BEFORE_STOP=1")
 	}
@@ -1008,6 +1010,8 @@
 	resolveExpectNotFound(t, ctx, "dm")
 	// Start the device manager.
 	stdout := make(simpleRW, 100)
+	defer os.Setenv(redirectEnv, os.Getenv(redirectEnv))
+	os.Setenv(redirectEnv, "1")
 	if err := impl.Start(dmDir, os.Stderr, stdout); err != nil {
 		t.Fatalf("Start failed: %v", err)
 	}
diff --git a/tools/vrun/testchild.sh b/tools/vrun/testchild.sh
index f6ec478..916ae52 100755
--- a/tools/vrun/testchild.sh
+++ b/tools/vrun/testchild.sh
@@ -5,6 +5,8 @@
 source "$(go list -f {{.Dir}} v.io/core/shell/lib)/shell_test.sh"
 
 main() {
+  shell_test::setup_mounttable
+
   local -r PINGPONG="$(shell_test::build_go_binary 'v.io/core/veyron/security/agent/pingpong')"
   local -r VRUN="$(shell_test::build_go_binary 'v.io/core/veyron/tools/vrun')"
   local -r PRINCIPAL="$(shell_test::build_go_binary 'v.io/core/veyron/tools/principal')"