ref: Change test/modules registration mechanism.

Previously modules registration and usage looked like this:

func foo(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
...
}

func init() {
modules.RegisterChild("foo", "", foo)
}

func TestFoo(t *testing.T) {
sh, err := modules.NewShell(...)
h, err := sh.Start("foo", nil, ...)
...
}

The new modules registration and usage looks like this:

var foo = modules.Register(func(env *modules.Env, args ...string) error {
...
}, "foo")

func TestFoo(t *testing.T) {
sh, err := modules.NewShell(...)
h, err := sh.Start(nil, foo, ...)
...
}

The main change is that Register now returns a modules.Program,
which is typically captured in a global variable, and is used as
the argument to Shell.Start.  This makes it easy to write the
registration manually, and we also have a more obvious linkage
between program registration and the Start call through the
program variable, rather than using strings.

Since registration was annoying to write manually, we used to
have 'v23 test generate' detect the functions and automatically
add the modules.RegisterChild call.  With the new mechanism, the
registration is simple to write manually, so 'v23 test generate'
has been simplified to remove the detection logic.

In fact the Program returned by modules.Register now must be
captured, so that it can be passed to Shell.Start; this forces
the linkage between Register and Start to be obvious.

Also removed the modules Help mechanism, since it wasn't being
used, and has questionable utility.  In its place, added logic to
dump all registered programs when program lookups fail.

MultiPart: 3/5

Change-Id: I6442c6959a4cb27fc1515f6ea14a4018ceb9f6b8
diff --git a/runtime/internal/rpc/resolve_test.go b/runtime/internal/rpc/resolve_test.go
index 73ace16..08b400a 100644
--- a/runtime/internal/rpc/resolve_test.go
+++ b/runtime/internal/rpc/resolve_test.go
@@ -7,7 +7,6 @@
 import (
 	"flag"
 	"fmt"
-	"io"
 	"os"
 	"testing"
 	"time"
@@ -66,7 +65,7 @@
 	fake.InjectRuntime(runtime, ctx, shutdown)
 }
 
-func rootMountTable(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+var rootMT = modules.Register(func(env *modules.Env, args ...string) error {
 	setupRuntime()
 	ctx, shutdown := v23.Init()
 	defer shutdown()
@@ -88,16 +87,16 @@
 	if err := server.ServeDispatcher(mp, mt); err != nil {
 		return fmt.Errorf("root failed: %s", err)
 	}
-	fmt.Fprintf(stdout, "PID=%d\n", os.Getpid())
+	fmt.Fprintf(env.Stdout, "PID=%d\n", os.Getpid())
 	for _, ep := range eps {
-		fmt.Fprintf(stdout, "MT_NAME=%s\n", ep.Name())
+		fmt.Fprintf(env.Stdout, "MT_NAME=%s\n", ep.Name())
 	}
-	modules.WaitForEOF(stdin)
+	modules.WaitForEOF(env.Stdin)
 	return nil
-}
+}, "rootMT")
 
 func startMT(t *testing.T, sh *modules.Shell) string {
-	h, err := sh.Start("rootMountTable", nil)
+	h, err := sh.Start(nil, rootMT)
 	if err != nil {
 		t.Fatalf("unexpected error for root mt: %s", err)
 	}
diff --git a/runtime/internal/rpc/stream/manager/manager_test.go b/runtime/internal/rpc/stream/manager/manager_test.go
index 2c20fcb..b2a5cad 100644
--- a/runtime/internal/rpc/stream/manager/manager_test.go
+++ b/runtime/internal/rpc/stream/manager/manager_test.go
@@ -37,11 +37,6 @@
 	"v.io/x/ref/test/testutil"
 )
 
-func init() {
-	modules.RegisterChild("runServer", "", runServer)
-	modules.RegisterChild("runRLimitedServer", "", runRLimitedServer)
-}
-
 // We write our own TestMain here instead of relying on v23 test generate because
 // we need to set runtime.GOMAXPROCS.
 func TestMain(m *testing.M) {
@@ -51,13 +46,7 @@
 	// condition that occurs when closing the server; also, using 1 cpu
 	// introduces less variance in the behavior of the test.
 	runtime.GOMAXPROCS(1)
-	if modules.IsModulesChildProcess() {
-		if err := modules.Dispatch(); err != nil {
-			fmt.Fprintf(os.Stderr, "modules.Dispatch failed: %v\n", err)
-			os.Exit(1)
-		}
-		return
-	}
+	modules.DispatchAndExitIfChild()
 	os.Exit(m.Run())
 }
 
@@ -676,7 +665,7 @@
 		t.Fatalf("unexpected error: %s", err)
 	}
 	defer sh.Cleanup(nil, nil)
-	h, err := sh.Start("runServer", nil, protocol, "127.0.0.1:0")
+	h, err := sh.Start(nil, runServer, protocol, "127.0.0.1:0")
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -697,7 +686,7 @@
 		t.Fatal("Expected client.Dial to fail since server is dead")
 	}
 
-	h, err = sh.Start("runServer", nil, protocol, ep.Addr().String())
+	h, err = sh.Start(nil, runServer, protocol, ep.Addr().String())
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -714,34 +703,36 @@
 	}
 }
 
-func runServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+var runServer = modules.Register(runServerFunc, "runServer")
+
+func runServerFunc(env *modules.Env, args ...string) error {
 	server := InternalNew(naming.FixedRoutingID(0x55555555))
 	principal := testutil.NewPrincipal("test")
 	_, ep, err := server.Listen(args[0], args[1], principal, principal.BlessingStore().Default())
 	if err != nil {
-		fmt.Fprintln(stderr, err)
+		fmt.Fprintln(env.Stderr, err)
 		return err
 	}
-	fmt.Fprintf(stdout, "ENDPOINT=%v\n", ep)
+	fmt.Fprintf(env.Stdout, "ENDPOINT=%v\n", ep)
 	// Live forever (till the process is explicitly killed)
-	modules.WaitForEOF(stdin)
+	modules.WaitForEOF(env.Stdin)
 	return nil
 }
 
-func runRLimitedServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+var runRLimitedServer = modules.Register(func(env *modules.Env, args ...string) error {
 	var rlimit syscall.Rlimit
 	if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil {
-		fmt.Fprintln(stderr, err)
+		fmt.Fprintln(env.Stderr, err)
 		return err
 	}
 	rlimit.Cur = 9
 	if err := syscall.Setrlimit(syscall.RLIMIT_NOFILE, &rlimit); err != nil {
-		fmt.Fprintln(stderr, err)
+		fmt.Fprintln(env.Stderr, err)
 		return err
 	}
-	fmt.Fprintf(stdout, "RLIMIT_NOFILE=%d\n", rlimit.Cur)
-	return runServer(stdin, stdout, stderr, env, args...)
-}
+	fmt.Fprintf(env.Stdout, "RLIMIT_NOFILE=%d\n", rlimit.Cur)
+	return runServerFunc(env, args...)
+}, "runRLimitedServer")
 
 func readLine(f stream.Flow) (string, error) {
 	var result bytes.Buffer
@@ -873,7 +864,7 @@
 		t.Fatal(err)
 	}
 	defer sh.Cleanup(nil, nil)
-	h, err := sh.Start("runRLimitedServer", nil, "--logtostderr=true", "tcp", "127.0.0.1:0")
+	h, err := sh.Start(nil, runRLimitedServer, "--logtostderr=true", "tcp", "127.0.0.1:0")
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/runtime/internal/rpc/stream/proxy/v23_internal_test.go b/runtime/internal/rpc/stream/proxy/v23_internal_test.go
index 84bea54..73903ec 100644
--- a/runtime/internal/rpc/stream/proxy/v23_internal_test.go
+++ b/runtime/internal/rpc/stream/proxy/v23_internal_test.go
@@ -4,12 +4,15 @@
 
 // This file was auto-generated via go generate.
 // DO NOT UPDATE MANUALLY
+
 package proxy
 
-import "testing"
-import "os"
+import (
+	"os"
+	"testing"
 
-import "v.io/x/ref/test"
+	"v.io/x/ref/test"
+)
 
 func TestMain(m *testing.M) {
 	test.Init()
diff --git a/runtime/internal/rpc/stream/vc/v23_internal_test.go b/runtime/internal/rpc/stream/vc/v23_internal_test.go
index 945d8c4..a48d6f6 100644
--- a/runtime/internal/rpc/stream/vc/v23_internal_test.go
+++ b/runtime/internal/rpc/stream/vc/v23_internal_test.go
@@ -4,12 +4,15 @@
 
 // This file was auto-generated via go generate.
 // DO NOT UPDATE MANUALLY
+
 package vc
 
-import "testing"
-import "os"
+import (
+	"os"
+	"testing"
 
-import "v.io/x/ref/test"
+	"v.io/x/ref/test"
+)
 
 func TestMain(m *testing.M) {
 	test.Init()
diff --git a/runtime/internal/rpc/stream/vif/v23_internal_test.go b/runtime/internal/rpc/stream/vif/v23_internal_test.go
index 161553c..70e47de 100644
--- a/runtime/internal/rpc/stream/vif/v23_internal_test.go
+++ b/runtime/internal/rpc/stream/vif/v23_internal_test.go
@@ -4,12 +4,15 @@
 
 // This file was auto-generated via go generate.
 // DO NOT UPDATE MANUALLY
+
 package vif
 
-import "testing"
-import "os"
+import (
+	"os"
+	"testing"
 
-import "v.io/x/ref/test"
+	"v.io/x/ref/test"
+)
 
 func TestMain(m *testing.M) {
 	test.Init()
diff --git a/runtime/internal/rpc/test/client_test.go b/runtime/internal/rpc/test/client_test.go
index a1e9013..2f0157f 100644
--- a/runtime/internal/rpc/test/client_test.go
+++ b/runtime/internal/rpc/test/client_test.go
@@ -6,7 +6,6 @@
 
 import (
 	"fmt"
-	"io"
 	"net"
 	"os"
 	"path/filepath"
@@ -38,15 +37,15 @@
 
 //go:generate v23 test generate .
 
-func rootMT(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+var rootMT = modules.Register(func(env *modules.Env, args ...string) error {
 	seclevel := options.SecurityConfidential
 	if len(args) == 1 && args[0] == "nosec" {
 		seclevel = options.SecurityNone
 	}
-	return runRootMT(stdin, stdout, stderr, seclevel, env, args...)
-}
+	return runRootMT(seclevel, env, args...)
+}, "rootMT")
 
-func runRootMT(stdin io.Reader, stdout, stderr io.Writer, seclevel options.SecurityLevel, env map[string]string, args ...string) error {
+func runRootMT(seclevel options.SecurityLevel, env *modules.Env, args ...string) error {
 	ctx, shutdown := v23.Init()
 	defer shutdown()
 
@@ -66,11 +65,11 @@
 	if err := server.ServeDispatcher("", mt); err != nil {
 		return fmt.Errorf("root failed: %s", err)
 	}
-	fmt.Fprintf(stdout, "PID=%d\n", os.Getpid())
+	fmt.Fprintf(env.Stdout, "PID=%d\n", os.Getpid())
 	for _, ep := range eps {
-		fmt.Fprintf(stdout, "MT_NAME=%s\n", ep.Name())
+		fmt.Fprintf(env.Stdout, "MT_NAME=%s\n", ep.Name())
 	}
-	modules.WaitForEOF(stdin)
+	modules.WaitForEOF(env.Stdin)
 	return nil
 }
 
@@ -100,7 +99,7 @@
 	return nil
 }
 
-func echoServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+var echoServer = modules.Register(func(env *modules.Env, args ...string) error {
 	ctx, shutdown := v23.Init()
 	defer shutdown()
 
@@ -118,15 +117,15 @@
 	if err := server.ServeDispatcher(mp, disp); err != nil {
 		return err
 	}
-	fmt.Fprintf(stdout, "PID=%d\n", os.Getpid())
+	fmt.Fprintf(env.Stdout, "PID=%d\n", os.Getpid())
 	for _, ep := range eps {
-		fmt.Fprintf(stdout, "NAME=%s\n", ep.Name())
+		fmt.Fprintf(env.Stdout, "NAME=%s\n", ep.Name())
 	}
-	modules.WaitForEOF(stdin)
+	modules.WaitForEOF(env.Stdin)
 	return nil
-}
+}, "echoServer")
 
-func echoClient(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+var echoClient = modules.Register(func(env *modules.Env, args ...string) error {
 	ctx, shutdown := v23.Init()
 	defer shutdown()
 
@@ -138,10 +137,10 @@
 		if err := client.Call(ctx, name, "Echo", []interface{}{a}, []interface{}{&r}); err != nil {
 			return err
 		}
-		fmt.Fprintf(stdout, r)
+		fmt.Fprintf(env.Stdout, r)
 	}
 	return nil
-}
+}, "echoClient")
 
 func newCtx() (*context.T, v23.Shutdown) {
 	ctx, shutdown := test.InitForTest()
@@ -154,7 +153,7 @@
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
-	root, err := sh.Start("rootMT", nil, args...)
+	root, err := sh.Start(nil, rootMT, args...)
 	if err != nil {
 		t.Fatalf("unexpected error for root mt: %s", err)
 	}
@@ -174,7 +173,7 @@
 }
 
 func runClient(t *testing.T, sh *modules.Shell) error {
-	clt, err := sh.Start("echoClient", nil, "echoServer", "a message")
+	clt, err := sh.Start(nil, echoClient, "echoServer", "a message")
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -202,7 +201,7 @@
 
 	sh, fn := runMountTable(t, ctx)
 	defer fn()
-	srv, err := sh.Start("echoServer", nil, "echoServer", "echoServer")
+	srv, err := sh.Start(nil, echoServer, "echoServer", "echoServer")
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -508,7 +507,7 @@
 	logErr("client does not trust server", err)
 }
 
-func childPing(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+var childPing = modules.Register(func(env *modules.Env, args ...string) error {
 	ctx, shutdown := test.InitForTest()
 	defer shutdown()
 	v23.GetNamespace(ctx).CacheCtl(naming.DisableCache(true))
@@ -518,9 +517,9 @@
 	if err := v23.GetClient(ctx).Call(ctx, name, "Ping", nil, []interface{}{&got}); err != nil {
 		fmt.Errorf("unexpected error: %s", err)
 	}
-	fmt.Fprintf(stdout, "RESULT=%s\n", got)
+	fmt.Fprintf(env.Stdout, "RESULT=%s\n", got)
 	return nil
-}
+}, "childPing")
 
 func initServer(t *testing.T, ctx *context.T, opts ...rpc.ServerOpt) (string, func()) {
 	server, err := v23.NewServer(ctx, opts...)
@@ -654,7 +653,7 @@
 	// backoff of some minutes.
 	startServer := func() {
 		time.Sleep(100 * time.Millisecond)
-		srv, _ := sh.Start("echoServer", nil, "message", name)
+		srv, _ := sh.Start(nil, echoServer, "message", name)
 		s := expect.NewSession(t, srv.Stdout(), time.Minute)
 		s.ExpectVar("PID")
 		s.ExpectVar("NAME")
@@ -686,7 +685,7 @@
 	name, fn := initServer(t, ctx)
 	defer fn()
 
-	srv, err := sh.Start("childPing", nil, name)
+	srv, err := sh.Start(nil, childPing, name)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -814,7 +813,7 @@
 		t.Fatalf("unexpected error: %s", err)
 	}
 	defer sh.Cleanup(os.Stderr, os.Stderr)
-	server, err := sh.Start("echoServer", nil, "--v23.tcp.address=127.0.0.1:0", "mymessage", "")
+	server, err := sh.Start(nil, echoServer, "--v23.tcp.address=127.0.0.1:0", "mymessage", "")
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
@@ -852,7 +851,7 @@
 	// Resurrect the server with the same address, verify client
 	// re-establishes the connection. This is racy if another
 	// process grabs the port.
-	server, err = sh.Start("echoServer", nil, "--v23.tcp.address="+ep.Address, "mymessage again", "")
+	server, err = sh.Start(nil, echoServer, "--v23.tcp.address="+ep.Address, "mymessage again", "")
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/runtime/internal/rpc/test/proxy_test.go b/runtime/internal/rpc/test/proxy_test.go
index 05e1c36..9a6c7b8 100644
--- a/runtime/internal/rpc/test/proxy_test.go
+++ b/runtime/internal/rpc/test/proxy_test.go
@@ -6,7 +6,6 @@
 
 import (
 	"fmt"
-	"io"
 	"os"
 	"reflect"
 	"sort"
@@ -49,7 +48,7 @@
 	return ctx, shutdown
 }
 
-func proxyServer(stdin io.Reader, stdout, stderr io.Writer, env map[string]string, args ...string) error {
+var proxyServer = modules.Register(func(env *modules.Env, args ...string) error {
 	ctx, shutdown := v23.Init()
 	defer shutdown()
 
@@ -58,11 +57,11 @@
 	listenSpec := rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}}
 	proxyShutdown, proxyEp, err := proxy.New(ctx, listenSpec, security.AllowEveryone())
 	if err != nil {
-		fmt.Fprintf(stderr, "%s\n", verror.DebugString(err))
+		fmt.Fprintf(env.Stderr, "%s\n", verror.DebugString(err))
 		return err
 	}
 	defer proxyShutdown()
-	fmt.Fprintf(stdout, "PID=%d\n", os.Getpid())
+	fmt.Fprintf(env.Stdout, "PID=%d\n", os.Getpid())
 	if expected > 0 {
 		pub := publisher.New(ctx, v23.GetNamespace(ctx), time.Minute)
 		defer pub.WaitForStop()
@@ -84,11 +83,11 @@
 			time.Sleep(delay)
 		}
 	}
-	fmt.Fprintf(stdout, "PROXY_NAME=%s\n", proxyEp.Name())
-	modules.WaitForEOF(stdin)
-	fmt.Fprintf(stdout, "DONE\n")
+	fmt.Fprintf(env.Stdout, "PROXY_NAME=%s\n", proxyEp.Name())
+	modules.WaitForEOF(env.Stdin)
+	fmt.Fprintf(env.Stdout, "DONE\n")
 	return nil
-}
+}, "")
 
 type testServer struct{}
 
@@ -121,7 +120,7 @@
 		t.Fatalf("unexpected error: %s", err)
 	}
 	h.sh = sh
-	p, err := sh.Start("proxyServer", nil, args...)
+	p, err := sh.Start(nil, proxyServer, args...)
 	if err != nil {
 		t.Fatalf("unexpected error: %s", err)
 	}
diff --git a/runtime/internal/rpc/test/v23_internal_test.go b/runtime/internal/rpc/test/v23_internal_test.go
index 0862cd2..d7274da 100644
--- a/runtime/internal/rpc/test/v23_internal_test.go
+++ b/runtime/internal/rpc/test/v23_internal_test.go
@@ -4,31 +4,19 @@
 
 // This file was auto-generated via go generate.
 // DO NOT UPDATE MANUALLY
+
 package test
 
-import "fmt"
-import "testing"
-import "os"
+import (
+	"os"
+	"testing"
 
-import "v.io/x/ref/test"
-import "v.io/x/ref/test/modules"
-
-func init() {
-	modules.RegisterChild("rootMT", ``, rootMT)
-	modules.RegisterChild("echoServer", ``, echoServer)
-	modules.RegisterChild("echoClient", ``, echoClient)
-	modules.RegisterChild("childPing", ``, childPing)
-	modules.RegisterChild("proxyServer", ``, proxyServer)
-}
+	"v.io/x/ref/test"
+	"v.io/x/ref/test/modules"
+)
 
 func TestMain(m *testing.M) {
 	test.Init()
-	if modules.IsModulesChildProcess() {
-		if err := modules.Dispatch(); err != nil {
-			fmt.Fprintf(os.Stderr, "modules.Dispatch failed: %v\n", err)
-			os.Exit(1)
-		}
-		return
-	}
+	modules.DispatchAndExitIfChild()
 	os.Exit(m.Run())
 }
diff --git a/runtime/internal/rpc/v23_test.go b/runtime/internal/rpc/v23_test.go
index b874fc4..fac4210 100644
--- a/runtime/internal/rpc/v23_test.go
+++ b/runtime/internal/rpc/v23_test.go
@@ -4,27 +4,19 @@
 
 // This file was auto-generated via go generate.
 // DO NOT UPDATE MANUALLY
+
 package rpc_test
 
-import "fmt"
-import "testing"
-import "os"
+import (
+	"os"
+	"testing"
 
-import "v.io/x/ref/test"
-import "v.io/x/ref/test/modules"
-
-func init() {
-	modules.RegisterChild("rootMountTable", ``, rootMountTable)
-}
+	"v.io/x/ref/test"
+	"v.io/x/ref/test/modules"
+)
 
 func TestMain(m *testing.M) {
 	test.Init()
-	if modules.IsModulesChildProcess() {
-		if err := modules.Dispatch(); err != nil {
-			fmt.Fprintf(os.Stderr, "modules.Dispatch failed: %v\n", err)
-			os.Exit(1)
-		}
-		return
-	}
+	modules.DispatchAndExitIfChild()
 	os.Exit(m.Run())
 }