veyron/tools/naming/simulator: reworked to use new modules and to be more useful.

Change-Id: Ieef4412b995b289957326cc06f2c48990ba99112
diff --git a/lib/modules/core/core.go b/lib/modules/core/core.go
index 980313e..98a6656 100644
--- a/lib/modules/core/core.go
+++ b/lib/modules/core/core.go
@@ -53,6 +53,10 @@
 	ResolveMTCommand         = "resolveMT"
 	EchoServerCommand        = "echoServer"
 	EchoClientCommand        = "echoClient"
+	SleepCommand             = "sleep"
+	TimeCommand              = "time"
+	MountCommand             = "mount"
+	NamespaceCacheCommand    = "cache"
 )
 
 // NewShell returns a new Shell instance with the core commands installed.
@@ -77,6 +81,14 @@
 	resolves name to obtain a mount table address`)
 	shell.AddFunction(SetNamespaceRootsCommand, setNamespaceRoots, `<name>...
 	set the in-process namespace roots to <name>...`)
+	shell.AddFunction(SleepCommand, sleep, `[duration]
+	sleep for a time (in go time.Duration format): defaults to 1s`)
+	shell.AddFunction(TimeCommand, now, `
+	prints the current time`)
+	shell.AddFunction(NamespaceCacheCommand, namespaceCache, `on|off
+	turns the namespace cache on or off`)
+	shell.AddFunction(MountCommand, mountServer, `<mountpoint> <server> <ttl>
+	invokes namespace.Mount(<mountpoint>, <server>, <ttl>)`)
 	shell.AddSubprocess(EchoClientCommand, `<name> <message>...
 	invokes name.Echo(message)`)
 	shell.AddSubprocess(EchoServerCommand, `<name> <text>
diff --git a/lib/modules/core/echo.go b/lib/modules/core/echo.go
index ae37372..55bc787 100644
--- a/lib/modules/core/echo.go
+++ b/lib/modules/core/echo.go
@@ -8,6 +8,7 @@
 	"veyron.io/veyron/veyron2/ipc"
 	"veyron.io/veyron/veyron2/naming"
 	"veyron.io/veyron/veyron2/rt"
+	"veyron.io/veyron/veyron2/security"
 
 	"veyron.io/veyron/veyron/lib/modules"
 )
@@ -17,19 +18,29 @@
 	modules.RegisterChild(EchoClientCommand, echoClient)
 }
 
+type treeDispatcher struct{ id string }
+
+func (d treeDispatcher) Lookup(suffix, method string) (ipc.Invoker, security.Authorizer, error) {
+	return ipc.ReflectInvoker(&echoServerObject{d.id, suffix}), nil, nil
+}
+
 type echoServerObject struct {
-	id string
+	id, suffix string
 }
 
 func (es *echoServerObject) Echo(call ipc.ServerCall, m string) (string, error) {
-	return es.id + ": " + m + "\n", nil
+	if len(es.suffix) > 0 {
+		return fmt.Sprintf("%s.%s: %s\n", es.id, es.suffix, m), nil
+	}
+	return fmt.Sprintf("%s: %s\n", es.id, m), nil
 }
 
 func echoServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
 	if len(args) != 2 {
 		return fmt.Errorf("wrong # args")
 	}
-	id, mountPoint := args[0], args[1]
+	id, mp := args[0], args[1]
+	disp := &treeDispatcher{id: id}
 	server, err := rt.R().NewServer()
 	if err != nil {
 		return err
@@ -39,7 +50,7 @@
 	if err != nil {
 		return err
 	}
-	if err := server.Serve(mountPoint, ipc.LeafDispatcher(&echoServerObject{id: id}, nil)); err != nil {
+	if err := server.Serve(mp, disp); err != nil {
 		return err
 	}
 	fmt.Fprintf(stdout, "NAME=%s\n", naming.MakeTerminal(naming.JoinAddressName(ep.String(), "")))
@@ -50,7 +61,6 @@
 }
 
 func echoClient(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
-
 	if len(args) < 2 {
 		return fmt.Errorf("wrong # args")
 	}
diff --git a/lib/modules/core/misc.go b/lib/modules/core/misc.go
new file mode 100644
index 0000000..e0c1496
--- /dev/null
+++ b/lib/modules/core/misc.go
@@ -0,0 +1,64 @@
+package core
+
+import (
+	"fmt"
+	"io"
+	"time"
+
+	"veyron.io/veyron/veyron2/naming"
+	"veyron.io/veyron/veyron2/rt"
+)
+
+func sleep(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	d := time.Second
+	if len(args) > 0 {
+		var err error
+		if d, err = time.ParseDuration(args[0]); err != nil {
+			return err
+		}
+	}
+	fmt.Fprintf(stdout, "Sleeping for %s", d)
+	// TODO(cnicolaou): we should probably also listen for stdin closing
+	// and return before the sleep completes.
+	time.Sleep(d)
+	return nil
+}
+
+func now(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	fmt.Fprintf(stdout, "%s\n", time.Now())
+	return nil
+}
+
+func mountServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	if len(args) != 3 {
+		return fmt.Errorf("wrong # args")
+	}
+	mp, server, ttlstr := args[0], args[1], args[2]
+	ttl, err := time.ParseDuration(ttlstr)
+	if err != nil {
+		return fmt.Errorf("failed to parse time from %q", ttlstr)
+	}
+	ns := rt.R().Namespace()
+	if err := ns.Mount(rt.R().NewContext(), mp, server, ttl); err != nil {
+		return err
+	}
+	fmt.Fprintf(stdout, "Mount(%s, %s, %s)\n", mp, server, ttl)
+	return nil
+}
+
+func namespaceCache(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+	if len(args) != 1 {
+		return fmt.Errorf("wrong # args")
+	}
+	disable := true
+	switch args[0] {
+	case "on":
+		disable = false
+	case "off":
+		disable = true
+	default:
+		return fmt.Errorf("arg must be 'on' or 'off'")
+	}
+	rt.R().Namespace().CacheCtl(naming.DisableCache(disable))
+	return nil
+}
diff --git a/lib/modules/core/mounttable.go b/lib/modules/core/mounttable.go
index 1c523e0..8d63006 100644
--- a/lib/modules/core/mounttable.go
+++ b/lib/modules/core/mounttable.go
@@ -58,6 +58,7 @@
 	}
 	name := naming.JoinAddressName(ep.String(), "")
 	fmt.Fprintf(stdout, "MT_NAME=%s\n", name)
+	fmt.Fprintf(stdout, "MT_ADDR=%s\n", ep.String())
 	fmt.Fprintf(stdout, "PID=%d\n", os.Getpid())
 	modules.WaitForEOF(stdin)
 	return nil
@@ -82,7 +83,7 @@
 				output += fmt.Sprintf("R%d=%s[", entry, n.Name)
 				t := ""
 				for _, s := range n.Servers {
-					output += fmt.Sprintf("%s:%ss, ", s.Server, s.TTL)
+					t += fmt.Sprintf("%s:%s, ", s.Server, s.TTL)
 				}
 				t = strings.TrimSuffix(t, ", ")
 				output += fmt.Sprintf("%s]\n", t)
@@ -110,6 +111,7 @@
 	name := args[0]
 	servers, err := fn(rt.R().NewContext(), name)
 	if err != nil {
+		fmt.Fprintf(stdout, "RN=0\n")
 		return err
 	}
 	fmt.Fprintf(stdout, "RN=%d\n", len(servers))
diff --git a/lib/modules/exec.go b/lib/modules/exec.go
index 20137b1..e2e35db 100644
--- a/lib/modules/exec.go
+++ b/lib/modules/exec.go
@@ -54,8 +54,9 @@
 	return fl
 }
 
-// IsTestSubprocess returns true if it is called in via -run=TestHelperProcess
-// which normally only ever happens for subprocess run from tests.
+// IsTestHelperProces returns true if it is called in via
+// -run=TestHelperProcess which normally only ever happens for subprocesses
+// run from tests.
 func IsTestHelperProcess() bool {
 	runFlag := flag.Lookup("test.run")
 	if runFlag == nil {
@@ -188,7 +189,7 @@
 	return eh.cmd.Wait()
 }
 
-const shellEntryPoint = "VEYRON_SHELL_HELPER_PROCESS_ENTRY_POINT"
+const ShellEntryPoint = "VEYRON_SHELL_HELPER_PROCESS_ENTRY_POINT"
 
 func RegisterChild(name string, main Main) {
 	child.Lock()
@@ -208,9 +209,9 @@
 }
 
 func (child *childRegistrar) dispatch() error {
-	command := os.Getenv(shellEntryPoint)
+	command := os.Getenv(ShellEntryPoint)
 	if len(command) == 0 {
-		return fmt.Errorf("Failed to find entrypoint %q", shellEntryPoint)
+		return fmt.Errorf("Failed to find entrypoint %q", ShellEntryPoint)
 	}
 	child.Lock()
 	m := child.mains[command]
diff --git a/lib/modules/func.go b/lib/modules/func.go
index f44127b..319a673 100644
--- a/lib/modules/func.go
+++ b/lib/modules/func.go
@@ -70,6 +70,9 @@
 
 		err := main(stdin, stdout, stderr, sh.mergeOSEnv(), args...)
 		if err != nil {
+			// Print the error to stdout to ensure that anyone reading
+			// only stdout sees the error.
+			fmt.Fprintf(stdout, "%s\n", err)
 			fmt.Fprintf(stderr, "%s\n", err)
 		}
 
diff --git a/lib/modules/modules_internal_test.go b/lib/modules/modules_internal_test.go
index 920538d..000819b 100644
--- a/lib/modules/modules_internal_test.go
+++ b/lib/modules/modules_internal_test.go
@@ -31,6 +31,7 @@
 
 func TestState(t *testing.T) {
 	sh := NewShell()
+
 	sh.AddSubprocess("echonotregistered", "[args]*")
 	sh.AddSubprocess("echos", "[args]*")
 	sh.AddFunction("echof", Echo, "[args]*")
diff --git a/lib/modules/shell.go b/lib/modules/shell.go
index 2e35c97..561e3b2 100644
--- a/lib/modules/shell.go
+++ b/lib/modules/shell.go
@@ -129,7 +129,7 @@
 	if !child.hasCommand(name) {
 		vlog.Infof("Warning: %q is not registered with modules.Dispatcher", name)
 	}
-	entryPoint := shellEntryPoint + "=" + name
+	entryPoint := ShellEntryPoint + "=" + name
 	sh.mu.Lock()
 	sh.cmds[name] = &commandDesc{func() command { return newExecHandle(entryPoint) }, help}
 	sh.mu.Unlock()