ref/runtime/internal/rpc: Refactor many tests to use the public API.

This will help transition to the new RPC system.  The real runtime
already has the capability to switch back and forth between the new
and old systems, so moving these tests makes it easy to test.

Change-Id: I9ca580a927923e7d7c806df730ced1b14527fd23
diff --git a/envvar.go b/envvar.go
index 332d3e0..d6c074a 100644
--- a/envvar.go
+++ b/envvar.go
@@ -50,6 +50,11 @@
 	// to the url of the OAuth identity provider used by the principal
 	// seekblessings command.
 	EnvOAuthIdentityProvider = "V23_OAUTH_IDENTITY_PROVIDER"
+
+	// RPCTransitionStateVar is a temporary variable that determines how far along we
+	// are in the transition from old to new RPC systems.  It should be removed
+	// when the transition is complete.
+	RPCTransitionStateVar = "V23_RPC_TRANSITION_STATE"
 )
 
 // EnvNamespaceRoots returns the set of namespace roots to be used by the
@@ -87,3 +92,24 @@
 	}
 	return nil
 }
+
+type TransitionState int
+
+const (
+	None TransitionState = iota
+	XClients
+	XServers
+)
+
+func RPCTransitionState() TransitionState {
+	switch ts := os.Getenv(RPCTransitionStateVar); ts {
+	case "xclients":
+		return XClients
+	case "xservers":
+		return XServers
+	case "":
+		return None
+	default:
+		panic("Unknown transition state: " + ts)
+	}
+}
diff --git a/runtime/internal/rpc/benchmark/simple/main.go b/runtime/internal/rpc/benchmark/simple/main.go
index c904a7d..fb1d52c 100644
--- a/runtime/internal/rpc/benchmark/simple/main.go
+++ b/runtime/internal/rpc/benchmark/simple/main.go
@@ -14,13 +14,13 @@
 	"v.io/v23"
 	"v.io/v23/context"
 	"v.io/v23/naming"
+	"v.io/x/ref"
 	"v.io/x/ref/lib/security/securityflag"
 	_ "v.io/x/ref/runtime/factories/static"
 	"v.io/x/ref/runtime/internal/flow/flowtest"
 	fmanager "v.io/x/ref/runtime/internal/flow/manager"
 	"v.io/x/ref/runtime/internal/rpc/benchmark/internal"
 	"v.io/x/ref/runtime/internal/rpc/stream/manager"
-	"v.io/x/ref/runtime/internal/rt"
 	"v.io/x/ref/test"
 	"v.io/x/ref/test/benchmark"
 	"v.io/x/ref/test/testutil"
@@ -55,7 +55,7 @@
 	b.StopTimer()
 	b.ResetTimer()
 	for i := 0; i < b.N; i++ {
-		if rt.TransitionState >= rt.XServers {
+		if ref.RPCTransitionState() >= ref.XServers {
 			m := fmanager.New(nctx, naming.FixedRoutingID(0xc))
 			b.StartTimer()
 			_, err := m.Dial(nctx, serverEP, flowtest.BlessingsForPeer)
diff --git a/runtime/internal/rpc/cancel_test.go b/runtime/internal/rpc/cancel_test.go
deleted file mode 100644
index 9a11c07..0000000
--- a/runtime/internal/rpc/cancel_test.go
+++ /dev/null
@@ -1,126 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package rpc
-
-import (
-	"testing"
-
-	"v.io/v23"
-	"v.io/v23/context"
-	"v.io/v23/namespace"
-	"v.io/v23/naming"
-	"v.io/v23/rpc"
-	"v.io/v23/security"
-	"v.io/v23/verror"
-
-	"v.io/x/ref/runtime/internal/rpc/stream"
-	"v.io/x/ref/runtime/internal/rpc/stream/manager"
-	tnaming "v.io/x/ref/runtime/internal/testing/mocks/naming"
-)
-
-type canceld struct {
-	sm       stream.Manager
-	ns       namespace.T
-	name     string
-	child    string
-	started  chan struct{}
-	canceled chan struct{}
-	stop     func() error
-}
-
-func (c *canceld) Run(ctx *context.T, _ rpc.StreamServerCall) error {
-	close(c.started)
-
-	client, err := InternalNewClient(c.sm, c.ns)
-	if err != nil {
-		ctx.Error(err)
-		return err
-	}
-
-	ctx.Infof("Run: %s", c.child)
-	if c.child != "" {
-		if _, err = client.StartCall(ctx, c.child, "Run", []interface{}{}); err != nil {
-			ctx.Error(err)
-			return err
-		}
-	}
-
-	<-ctx.Done()
-	close(c.canceled)
-	return nil
-}
-
-func makeCanceld(ctx *context.T, ns namespace.T, name, child string) (*canceld, error) {
-	sm := manager.InternalNew(ctx, naming.FixedRoutingID(0x111111111))
-	s, err := testInternalNewServer(ctx, sm, ns)
-	if err != nil {
-		return nil, err
-	}
-
-	if _, err := s.Listen(listenSpec); err != nil {
-		return nil, err
-	}
-
-	c := &canceld{
-		sm:       sm,
-		ns:       ns,
-		name:     name,
-		child:    child,
-		started:  make(chan struct{}, 0),
-		canceled: make(chan struct{}, 0),
-		stop:     s.Stop,
-	}
-
-	if err := s.Serve(name, c, security.AllowEveryone()); err != nil {
-		return nil, err
-	}
-	ctx.Infof("Serving: %q", name)
-	return c, nil
-}
-
-// TestCancellationPropagation tests that cancellation propogates along an
-// RPC call chain without user intervention.
-func TestCancellationPropagation(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	var (
-		sm               = manager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-		ns               = tnaming.NewSimpleNamespace()
-		pclient, pserver = newClientServerPrincipals()
-		serverCtx, _     = v23.WithPrincipal(ctx, pserver)
-		clientCtx, _     = v23.WithPrincipal(ctx, pclient)
-	)
-	client, err := InternalNewClient(sm, ns)
-	if err != nil {
-		t.Error(err)
-	}
-
-	c1, err := makeCanceld(serverCtx, ns, "c1", "c2")
-	if err != nil {
-		t.Fatal("Can't start server:", err, verror.DebugString(err))
-	}
-	defer c1.stop()
-	c2, err := makeCanceld(serverCtx, ns, "c2", "")
-	if err != nil {
-		t.Fatal("Can't start server:", err)
-	}
-	defer c2.stop()
-
-	clientCtx, cancel := context.WithCancel(clientCtx)
-	_, err = client.StartCall(clientCtx, "c1", "Run", []interface{}{})
-	if err != nil {
-		t.Fatal("can't call: ", err)
-	}
-
-	<-c1.started
-	<-c2.started
-
-	ctx.Info("cancelling initial call")
-	cancel()
-
-	ctx.Info("waiting for children to be canceled")
-	<-c1.canceled
-	<-c2.canceled
-}
diff --git a/runtime/internal/rpc/client.go b/runtime/internal/rpc/client.go
index 64312d0..a7f427f 100644
--- a/runtime/internal/rpc/client.go
+++ b/runtime/internal/rpc/client.go
@@ -93,7 +93,7 @@
 
 var _ rpc.Client = (*client)(nil)
 
-func InternalNewClient(streamMgr stream.Manager, ns namespace.T, opts ...rpc.ClientOpt) (rpc.Client, error) {
+func DeprecatedNewClient(streamMgr stream.Manager, ns namespace.T, opts ...rpc.ClientOpt) (rpc.Client, error) {
 	c := &client{
 		streamMgr: streamMgr,
 		ns:        ns,
diff --git a/runtime/internal/rpc/debug_test.go b/runtime/internal/rpc/debug_test.go
deleted file mode 100644
index 24873ad..0000000
--- a/runtime/internal/rpc/debug_test.go
+++ /dev/null
@@ -1,135 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package rpc
-
-import (
-	"io"
-	"reflect"
-	"sort"
-	"testing"
-
-	"v.io/v23"
-	"v.io/v23/context"
-	"v.io/v23/naming"
-	"v.io/v23/options"
-	"v.io/v23/rpc"
-
-	"v.io/x/ref/lib/stats"
-	"v.io/x/ref/runtime/internal/rpc/stream/manager"
-	tnaming "v.io/x/ref/runtime/internal/testing/mocks/naming"
-	"v.io/x/ref/services/debug/debuglib"
-	"v.io/x/ref/test/testutil"
-)
-
-func TestDebugServer(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	// Setup the client and server principals, with the client willing to share its
-	// blessing with the server.
-	var (
-		pclient = testutil.NewPrincipal("client")
-		pserver = testutil.NewPrincipal("server")
-		bclient = bless(pserver, pclient, "client") // server/client blessing.
-		sctx, _ = v23.WithPrincipal(ctx, pserver)
-		cctx, _ = v23.WithPrincipal(ctx, pclient)
-	)
-	pclient.AddToRoots(bclient)                    // Client recognizes "server" as a root of blessings.
-	pclient.BlessingStore().Set(bclient, "server") // Client presents bclient to server
-
-	debugDisp := debuglib.NewDispatcher(nil)
-
-	sm := manager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-
-	server, err := testInternalNewServer(sctx, sm, ns, ReservedNameDispatcher{debugDisp})
-	if err != nil {
-		t.Fatalf("InternalNewServer failed: %v", err)
-	}
-	defer server.Stop()
-	eps, err := server.Listen(listenSpec)
-	if err != nil {
-		t.Fatalf("server.Listen failed: %v", err)
-	}
-	if err := server.Serve("", &testObject{}, nil); err != nil {
-		t.Fatalf("server.Serve failed: %v", err)
-	}
-
-	client, err := InternalNewClient(sm, ns)
-	if err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
-	}
-	defer client.Close()
-	ep := eps[0]
-	// Call the Foo method on ""
-	{
-		var value string
-		if err := client.Call(cctx, ep.Name(), "Foo", nil, []interface{}{&value}); err != nil {
-			t.Fatalf("client.Call failed: %v", err)
-		}
-		if want := "BAR"; value != want {
-			t.Errorf("unexpected value: Got %v, want %v", value, want)
-		}
-	}
-	// Call Value on __debug/stats/testing/foo
-	{
-		foo := stats.NewString("testing/foo")
-		foo.Set("The quick brown fox jumps over the lazy dog")
-		addr := naming.JoinAddressName(ep.String(), "__debug/stats/testing/foo")
-		var value string
-		if err := client.Call(cctx, addr, "Value", nil, []interface{}{&value}, options.Preresolved{}); err != nil {
-			t.Fatalf("client.Call failed: %v", err)
-		}
-		if want := foo.Value(); value != want {
-			t.Errorf("unexpected result: Got %v, want %v", value, want)
-		}
-	}
-
-	// Call Glob
-	testcases := []struct {
-		name, pattern string
-		expected      []string
-	}{
-		{"", "*", []string{}},
-		{"", "__*", []string{"__debug"}},
-		{"", "__*/*", []string{"__debug/logs", "__debug/pprof", "__debug/stats", "__debug/vtrace"}},
-		{"__debug", "*", []string{"logs", "pprof", "stats", "vtrace"}},
-	}
-	for _, tc := range testcases {
-		addr := naming.JoinAddressName(ep.String(), tc.name)
-		call, err := client.StartCall(cctx, addr, rpc.GlobMethod, []interface{}{tc.pattern}, options.Preresolved{})
-		if err != nil {
-			t.Fatalf("client.StartCall failed for %q: %v", tc.name, err)
-		}
-		results := []string{}
-		for {
-			var gr naming.GlobReply
-			if err := call.Recv(&gr); err != nil {
-				if err != io.EOF {
-					t.Fatalf("Recv failed for %q: %v. Results received thus far: %q", tc.name, err, results)
-				}
-				break
-			}
-			switch v := gr.(type) {
-			case naming.GlobReplyEntry:
-				results = append(results, v.Value.Name)
-			}
-		}
-		if err := call.Finish(); err != nil {
-			t.Fatalf("call.Finish failed for %q: %v", tc.name, err)
-		}
-		sort.Strings(results)
-		if !reflect.DeepEqual(tc.expected, results) {
-			t.Errorf("unexpected results for %q. Got %v, want %v", tc.name, results, tc.expected)
-		}
-	}
-}
-
-type testObject struct {
-}
-
-func (o testObject) Foo(*context.T, rpc.ServerCall) (string, error) {
-	return "BAR", nil
-}
diff --git a/runtime/internal/rpc/full_test.go b/runtime/internal/rpc/full_test.go
index cb24d94..4d06e25 100644
--- a/runtime/internal/rpc/full_test.go
+++ b/runtime/internal/rpc/full_test.go
@@ -5,11 +5,8 @@
 package rpc
 
 import (
-	"encoding/hex"
-	"errors"
 	"fmt"
 	"io"
-	"net"
 	"path/filepath"
 	"reflect"
 	"runtime"
@@ -19,8 +16,6 @@
 	"testing"
 	"time"
 
-	"v.io/x/lib/netstate"
-
 	"v.io/v23"
 	"v.io/v23/context"
 	"v.io/v23/i18n"
@@ -34,18 +29,14 @@
 	"v.io/v23/vdl"
 	"v.io/v23/verror"
 	"v.io/v23/vtrace"
-
 	"v.io/x/ref/lib/pubsub"
 	"v.io/x/ref/lib/stats"
-	"v.io/x/ref/runtime/internal/lib/publisher"
 	"v.io/x/ref/runtime/internal/lib/websocket"
-	inaming "v.io/x/ref/runtime/internal/naming"
 	_ "v.io/x/ref/runtime/internal/rpc/protocols/tcp"
 	_ "v.io/x/ref/runtime/internal/rpc/protocols/ws"
 	_ "v.io/x/ref/runtime/internal/rpc/protocols/wsh"
 	"v.io/x/ref/runtime/internal/rpc/stream"
 	imanager "v.io/x/ref/runtime/internal/rpc/stream/manager"
-	"v.io/x/ref/runtime/internal/rpc/stream/vc"
 	tnaming "v.io/x/ref/runtime/internal/testing/mocks/naming"
 	"v.io/x/ref/test/testutil"
 )
@@ -79,11 +70,11 @@
 }
 
 func testInternalNewServerWithPubsub(ctx *context.T, streamMgr stream.Manager, ns namespace.T, settingsPublisher *pubsub.Publisher, settingsStreamName string, opts ...rpc.ServerOpt) (DeprecatedServer, error) {
-	client, err := InternalNewClient(streamMgr, ns)
+	client, err := DeprecatedNewClient(streamMgr, ns)
 	if err != nil {
 		return nil, err
 	}
-	return InternalNewServer(ctx, streamMgr, ns, settingsPublisher, settingsStreamName, client, opts...)
+	return DeprecatedNewServer(ctx, streamMgr, ns, settingsPublisher, settingsStreamName, client, opts...)
 }
 
 func testInternalNewServer(ctx *context.T, streamMgr stream.Manager, ns namespace.T, opts ...rpc.ServerOpt) (DeprecatedServer, error) {
@@ -376,8 +367,8 @@
 		b.ep, b.server = startServerWS(t, ctx, server, b.sm, b.ns, b.name, testServerDisp{ts}, shouldUseWebsocket)
 	}
 	var err error
-	if b.client, err = InternalNewClient(b.sm, b.ns); err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
+	if b.client, err = DeprecatedNewClient(b.sm, b.ns); err != nil {
+		t.Fatalf("DeprecatedNewClient failed: %v", err)
 	}
 	return
 }
@@ -411,268 +402,6 @@
 	return sm
 }
 
-func TestMultipleCallsToServeAndName(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	ns := tnaming.NewSimpleNamespace()
-	sctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("server"))
-	server, err := testInternalNewServer(sctx, sm, ns)
-	if err != nil {
-		t.Errorf("InternalNewServer failed: %v", err)
-	}
-	_, err = server.Listen(listenSpec)
-	if err != nil {
-		t.Errorf("server.Listen failed: %v", err)
-	}
-
-	disp := &testServerDisp{&testServer{}}
-	if err := server.ServeDispatcher("mountpoint/server", disp); err != nil {
-		t.Errorf("server.ServeDispatcher failed: %v", err)
-	}
-
-	n1 := "mountpoint/server"
-	n2 := "should_appear_in_mt/server"
-	n3 := "should_appear_in_mt/server"
-	n4 := "should_not_appear_in_mt/server"
-
-	verifyMount(t, ctx, ns, n1)
-
-	if server.ServeDispatcher(n2, disp) == nil {
-		t.Errorf("server.ServeDispatcher should have failed")
-	}
-
-	if err := server.Serve(n2, &testServer{}, nil); err == nil {
-		t.Errorf("server.Serve should have failed")
-	}
-
-	if err := server.AddName(n3); err != nil {
-		t.Errorf("server.AddName failed: %v", err)
-	}
-
-	if err := server.AddName(n3); err != nil {
-		t.Errorf("server.AddName failed: %v", err)
-	}
-	verifyMount(t, ctx, ns, n2)
-	verifyMount(t, ctx, ns, n3)
-
-	server.RemoveName(n1)
-	verifyMountMissing(t, ctx, ns, n1)
-
-	server.RemoveName("some randome name")
-
-	if err := server.ServeDispatcher(n4, &testServerDisp{&testServer{}}); err == nil {
-		t.Errorf("server.ServeDispatcher should have failed")
-	}
-	verifyMountMissing(t, ctx, ns, n4)
-
-	if err := server.Stop(); err != nil {
-		t.Errorf("server.Stop failed: %v", err)
-	}
-
-	verifyMountMissing(t, ctx, ns, n1)
-	verifyMountMissing(t, ctx, ns, n2)
-	verifyMountMissing(t, ctx, ns, n3)
-}
-
-func TestRPCServerAuthorization(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-
-	const (
-		publicKeyErr        = "not matched by server key"
-		missingDischargeErr = "missing discharge"
-		expiryErr           = "is after expiry"
-		allowedErr          = "do not match any allowed server patterns"
-	)
-	type O []rpc.CallOpt // shorthand
-	var (
-		pprovider, pclient, pserver = testutil.NewPrincipal("root"), testutil.NewPrincipal(), testutil.NewPrincipal()
-		pdischarger                 = pprovider
-		now                         = time.Now()
-		noErrID                     verror.IDAction
-
-		// Third-party caveats on blessings presented by server.
-		cavTPValid   = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/dischargeserver", mkCaveat(security.NewExpiryCaveat(now.Add(24*time.Hour))))
-		cavTPExpired = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/dischargeserver", mkCaveat(security.NewExpiryCaveat(now.Add(-1*time.Second))))
-
-		// Server blessings.
-		bServer          = bless(pprovider, pserver, "server")
-		bServerExpired   = bless(pprovider, pserver, "expiredserver", mkCaveat(security.NewExpiryCaveat(time.Now().Add(-1*time.Second))))
-		bServerTPValid   = bless(pprovider, pserver, "serverWithTPCaveats", cavTPValid)
-		bServerTPExpired = bless(pprovider, pserver, "serverWithExpiredTPCaveats", cavTPExpired)
-		bOther           = bless(pprovider, pserver, "other")
-		bTwoBlessings, _ = security.UnionOfBlessings(bServer, bOther)
-
-		mgr   = imanager.InternalNew(ctx, naming.FixedRoutingID(0x1111111))
-		ns    = tnaming.NewSimpleNamespace()
-		tests = []struct {
-			server security.Blessings // blessings presented by the server to the client.
-			name   string             // name provided by the client to StartCall
-			opts   O                  // options provided to StartCall.
-			errID  verror.IDAction
-			err    string
-		}{
-			// Client accepts talking to the server only if the
-			// server presents valid blessings (and discharges)
-			// consistent with the ones published in the endpoint.
-			{bServer, "mountpoint/server", nil, noErrID, ""},
-			{bServerTPValid, "mountpoint/server", nil, noErrID, ""},
-
-			// Client will not talk to a server that presents
-			// expired blessings or is missing discharges.
-			{bServerExpired, "mountpoint/server", nil, verror.ErrNotTrusted, expiryErr},
-			{bServerTPExpired, "mountpoint/server", nil, verror.ErrNotTrusted, missingDischargeErr},
-
-			// Testing the AllowedServersPolicy option.
-			{bServer, "mountpoint/server", O{options.AllowedServersPolicy{"otherroot"}}, verror.ErrNotTrusted, allowedErr},
-			{bServer, "mountpoint/server", O{options.AllowedServersPolicy{"root"}}, noErrID, ""},
-			{bTwoBlessings, "mountpoint/server", O{options.AllowedServersPolicy{"root/other"}}, noErrID, ""},
-
-			// Test the ServerPublicKey option.
-			{bOther, "mountpoint/server", O{options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{
-				PublicKey: bOther.PublicKey(),
-			}}, noErrID, ""},
-			{bOther, "mountpoint/server", O{options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{
-				PublicKey: testutil.NewPrincipal("irrelevant").PublicKey(),
-			}}, verror.ErrNotTrusted, publicKeyErr},
-
-			// Test the "paranoid" names, where the pattern is provided in the name.
-			{bServer, "__(root/server)/mountpoint/server", nil, noErrID, ""},
-			{bServer, "__(root/other)/mountpoint/server", nil, verror.ErrNotTrusted, allowedErr},
-			{bTwoBlessings, "__(root/server)/mountpoint/server", O{options.AllowedServersPolicy{"root/other"}}, noErrID, ""},
-		}
-	)
-	// Start the discharge server.
-	_, dischargeServer := startServer(t, ctx, pdischarger, mgr, ns, "mountpoint/dischargeserver", testutil.LeafDispatcher(&dischargeServer{}, security.AllowEveryone()))
-	defer stopServer(t, ctx, dischargeServer, ns, "mountpoint/dischargeserver")
-
-	// Make the client and server principals trust root certificates from
-	// pprovider
-	pclient.AddToRoots(pprovider.BlessingStore().Default())
-	pserver.AddToRoots(pprovider.BlessingStore().Default())
-	// Set a blessing that the client is willing to share with servers
-	// (that are blessed by pprovider).
-	pclient.BlessingStore().Set(bless(pprovider, pclient, "client"), "root")
-
-	clientCtx, _ := v23.WithPrincipal(ctx, pclient)
-	client, err := InternalNewClient(mgr, ns)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer client.Close()
-
-	var server rpc.Server
-	stop := func() {
-		if server != nil {
-			stopServer(t, ctx, server, ns, "mountpoint/server")
-		}
-	}
-	defer stop()
-	for i, test := range tests {
-		stop() // Stop any server started in the previous test.
-		name := fmt.Sprintf("(#%d: Name:%q, Server:%q, opts:%v)", i, test.name, test.server, test.opts)
-		if err := pserver.BlessingStore().SetDefault(test.server); err != nil {
-			t.Fatalf("SetDefault failed on server's BlessingStore: %v", err)
-		}
-		if _, err := pserver.BlessingStore().Set(test.server, "root"); err != nil {
-			t.Fatalf("Set failed on server's BlessingStore: %v", err)
-		}
-		_, server = startServer(t, ctx, pserver, mgr, ns, "mountpoint/server", testServerDisp{&testServer{}})
-		clientCtx, cancel := context.WithCancel(clientCtx)
-		call, err := client.StartCall(clientCtx, test.name, "Method", nil, test.opts...)
-		if !matchesErrorPattern(err, test.errID, test.err) {
-			t.Errorf(`%s: client.StartCall: got error "%v", want to match "%v"`, name, err, test.err)
-		} else if call != nil {
-			blessings, proof := call.RemoteBlessings()
-			if proof.IsZero() {
-				t.Errorf("%s: Returned zero value for remote blessings", name)
-			}
-			// Currently all tests are configured so that the only
-			// blessings presented by the server that are
-			// recognized by the client match the pattern
-			// "root"
-			if len(blessings) < 1 || !security.BlessingPattern("root").MatchedBy(blessings...) {
-				t.Errorf("%s: Client sees server as %v, expected a single blessing matching root", name, blessings)
-			}
-		}
-		cancel()
-	}
-}
-
-func TestServerManInTheMiddleAttack(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	// Test scenario: A server mounts itself, but then some other service
-	// somehow "takes over" the network endpoint (a naughty router
-	// perhaps), thus trying to steal traffic.
-	var (
-		pclient        = testutil.NewPrincipal("client")
-		pserver        = testutil.NewPrincipal("server")
-		pattacker      = testutil.NewPrincipal("attacker")
-		attackerCtx, _ = v23.WithPrincipal(ctx, pattacker)
-		cctx, _        = v23.WithPrincipal(ctx, pclient)
-	)
-	// Client recognizes both the server and the attacker's blessings.
-	// (Though, it doesn't need to do the latter for the purposes of this
-	// test).
-	pclient.AddToRoots(pserver.BlessingStore().Default())
-	pclient.AddToRoots(pattacker.BlessingStore().Default())
-
-	// Start up the attacker's server.
-	attacker, err := testInternalNewServer(
-		attackerCtx,
-		imanager.InternalNew(ctx, naming.FixedRoutingID(0xaaaaaaaaaaaaaaaa)),
-		// (To prevent the attacker for legitimately mounting on the
-		// namespace that the client will use, provide it with a
-		// different namespace).
-		tnaming.NewSimpleNamespace(),
-	)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if _, err := attacker.Listen(listenSpec); err != nil {
-		t.Fatal(err)
-	}
-	if err := attacker.ServeDispatcher("mountpoint/server", testServerDisp{&testServer{}}); err != nil {
-		t.Fatal(err)
-	}
-	var ep naming.Endpoint
-	if status := attacker.Status(); len(status.Endpoints) < 1 {
-		t.Fatalf("Attacker server does not have an endpoint: %+v", status)
-	} else {
-		ep = status.Endpoints[0]
-	}
-
-	// The legitimate server would have mounted the same endpoint on the
-	// namespace, but with different blessings.
-	ns := tnaming.NewSimpleNamespace()
-	ep.(*inaming.Endpoint).Blessings = []string{"server"}
-	if err := ns.Mount(ctx, "mountpoint/server", ep.Name(), time.Hour); err != nil {
-		t.Fatal(err)
-	}
-
-	// The RPC call should fail because the blessings presented by the
-	// (attacker's) server are not consistent with the ones registered in
-	// the mounttable trusted by the client.
-	client, err := InternalNewClient(
-		imanager.InternalNew(cctx, naming.FixedRoutingID(0xcccccccccccccccc)),
-		ns)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer client.Close()
-	ctx, _ = v23.WithPrincipal(cctx, pclient)
-	if _, err := client.StartCall(cctx, "mountpoint/server", "Closure", nil); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
-		t.Errorf("Got error %v (errorid=%v), want errorid=%v", err, verror.ErrorID(err), verror.ErrNotTrusted.ID)
-	}
-	// But the RPC should succeed if the client explicitly
-	// decided to skip server authorization.
-	if _, err := client.StartCall(cctx, "mountpoint/server", "Closure", nil, options.SkipServerEndpointAuthorization{}); err != nil {
-		t.Errorf("Unexpected error(%v) when skipping server authorization", err)
-	}
-}
-
 type websocketMode bool
 type closeSendMode bool
 
@@ -684,206 +413,6 @@
 	noCloseSend closeSendMode = false
 )
 
-func TestRPC(t *testing.T) {
-	testRPC(t, closeSend, noWebsocket)
-}
-
-func TestRPCWithWebsocket(t *testing.T) {
-	testRPC(t, closeSend, useWebsocket)
-}
-
-// TestCloseSendOnFinish tests that Finish informs the server that no more
-// inputs will be sent by the client if CloseSend has not already done so.
-func TestRPCCloseSendOnFinish(t *testing.T) {
-	testRPC(t, noCloseSend, noWebsocket)
-}
-
-func TestRPCCloseSendOnFinishWithWebsocket(t *testing.T) {
-	testRPC(t, noCloseSend, useWebsocket)
-}
-
-func testRPC(t *testing.T, shouldCloseSend closeSendMode, shouldUseWebsocket websocketMode) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	type v []interface{}
-	type testcase struct {
-		name       string
-		method     string
-		args       v
-		streamArgs v
-		startErr   error
-		results    v
-		finishErr  error
-	}
-	var (
-		tests = []testcase{
-			{"mountpoint/server/suffix", "Closure", nil, nil, nil, nil, nil},
-			{"mountpoint/server/suffix", "Error", nil, nil, nil, nil, errMethod},
-
-			{"mountpoint/server/suffix", "Echo", v{"foo"}, nil, nil, v{`method:"Echo",suffix:"suffix",arg:"foo"`}, nil},
-			{"mountpoint/server/suffix/abc", "Echo", v{"bar"}, nil, nil, v{`method:"Echo",suffix:"suffix/abc",arg:"bar"`}, nil},
-
-			{"mountpoint/server/suffix", "EchoUser", v{"foo", userType("bar")}, nil, nil, v{`method:"EchoUser",suffix:"suffix",arg:"foo"`, userType("bar")}, nil},
-			{"mountpoint/server/suffix/abc", "EchoUser", v{"baz", userType("bla")}, nil, nil, v{`method:"EchoUser",suffix:"suffix/abc",arg:"baz"`, userType("bla")}, nil},
-			{"mountpoint/server/suffix", "Stream", v{"foo"}, v{userType("bar"), userType("baz")}, nil, v{`method:"Stream",suffix:"suffix",arg:"foo" bar baz`}, nil},
-			{"mountpoint/server/suffix/abc", "Stream", v{"123"}, v{userType("456"), userType("789")}, nil, v{`method:"Stream",suffix:"suffix/abc",arg:"123" 456 789`}, nil},
-			{"mountpoint/server/suffix", "EchoBlessings", nil, nil, nil, v{"[server]", "[client]"}, nil},
-			{"mountpoint/server/suffix", "EchoAndError", v{"bugs bunny"}, nil, nil, v{`method:"EchoAndError",suffix:"suffix",arg:"bugs bunny"`}, nil},
-			{"mountpoint/server/suffix", "EchoAndError", v{"error"}, nil, nil, nil, errMethod},
-			{"mountpoint/server/suffix", "EchoLang", nil, nil, nil, v{"foolang"}, nil},
-		}
-		name = func(t testcase) string {
-			return fmt.Sprintf("%s.%s(%v)", t.name, t.method, t.args)
-		}
-
-		pclient, pserver = newClientServerPrincipals()
-		b                = createBundleWS(t, ctx, pserver, &testServer{}, shouldUseWebsocket)
-	)
-	defer b.cleanup(t, ctx)
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	ctx = i18n.WithLangID(ctx, "foolang")
-	for _, test := range tests {
-		ctx.VI(1).Infof("%s client.StartCall", name(test))
-		vname := test.name
-		if shouldUseWebsocket {
-			var err error
-			vname, err = fakeWSName(ctx, b.ns, vname)
-			if err != nil && err != test.startErr {
-				t.Errorf(`%s ns.Resolve got error "%v", want "%v"`, name(test), err, test.startErr)
-				continue
-			}
-		}
-		call, err := b.client.StartCall(ctx, vname, test.method, test.args)
-		if err != test.startErr {
-			t.Errorf(`%s client.StartCall got error "%v", want "%v"`, name(test), err, test.startErr)
-			continue
-		}
-		for _, sarg := range test.streamArgs {
-			ctx.VI(1).Infof("%s client.Send(%v)", name(test), sarg)
-			if err := call.Send(sarg); err != nil {
-				t.Errorf(`%s call.Send(%v) got unexpected error "%v"`, name(test), sarg, err)
-			}
-			var u userType
-			if err := call.Recv(&u); err != nil {
-				t.Errorf(`%s call.Recv(%v) got unexpected error "%v"`, name(test), sarg, err)
-			}
-			if !reflect.DeepEqual(u, sarg) {
-				t.Errorf("%s call.Recv got value %v, want %v", name(test), u, sarg)
-			}
-		}
-		if shouldCloseSend {
-			ctx.VI(1).Infof("%s call.CloseSend", name(test))
-			// When the method does not involve streaming
-			// arguments, the server gets all the arguments in
-			// StartCall and then sends a response without
-			// (unnecessarily) waiting for a CloseSend message from
-			// the client.  If the server responds before the
-			// CloseSend call is made at the client, the CloseSend
-			// call will fail.  Thus, only check for errors on
-			// CloseSend if there are streaming arguments to begin
-			// with (i.e., only if the server is expected to wait
-			// for the CloseSend notification).
-			if err := call.CloseSend(); err != nil && len(test.streamArgs) > 0 {
-				t.Errorf(`%s call.CloseSend got unexpected error "%v"`, name(test), err)
-			}
-		}
-		ctx.VI(1).Infof("%s client.Finish", name(test))
-		results := makeResultPtrs(test.results)
-		err = call.Finish(results...)
-		if got, want := err, test.finishErr; (got == nil) != (want == nil) {
-			t.Errorf(`%s call.Finish got error "%v", want "%v'`, name(test), got, want)
-		} else if want != nil && verror.ErrorID(got) != verror.ErrorID(want) {
-			t.Errorf(`%s call.Finish got error "%v", want "%v"`, name(test), got, want)
-		}
-		checkResultPtrs(t, name(test), results, test.results)
-	}
-}
-
-func TestMultipleFinish(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	type v []interface{}
-	var (
-		pclient, pserver = newClientServerPrincipals()
-		b                = createBundle(t, ctx, pserver, &testServer{})
-	)
-	defer b.cleanup(t, ctx)
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	call, err := b.client.StartCall(ctx, "mountpoint/server/suffix", "Echo", v{"foo"})
-	if err != nil {
-		t.Fatalf(`client.StartCall got error "%v"`, err)
-	}
-	var results string
-	err = call.Finish(&results)
-	if err != nil {
-		t.Fatalf(`call.Finish got error "%v"`, err)
-	}
-	// Calling Finish a second time should result in a useful error.
-	if err = call.Finish(&results); !matchesErrorPattern(err, verror.ErrBadState, "Finish has already been called") {
-		t.Fatalf(`got "%v", want "%v"`, err, verror.ErrBadState)
-	}
-}
-
-// granter implements rpc.Granter.
-//
-// It returns the specified (security.Blessings, error) pair if either the
-// blessing or the error is specified. Otherwise it returns a blessing
-// derived from the local blessings of the current call.
-type granter struct {
-	rpc.CallOpt
-	b   security.Blessings
-	err error
-}
-
-func (g granter) Grant(ctx *context.T, call security.Call) (security.Blessings, error) {
-	if !g.b.IsZero() || g.err != nil {
-		return g.b, g.err
-	}
-	return call.LocalPrincipal().Bless(call.RemoteBlessings().PublicKey(), call.LocalBlessings(), "blessed", security.UnconstrainedUse())
-}
-
-func TestGranter(t *testing.T) {
-	var (
-		pclient, pserver = newClientServerPrincipals()
-		ctx, shutdown    = initForTest()
-		b                = createBundle(t, ctx, pserver, &testServer{})
-	)
-	defer shutdown()
-	defer b.cleanup(t, ctx)
-
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	tests := []struct {
-		granter                       rpc.Granter
-		startErrID, finishErrID       verror.IDAction
-		blessing, starterr, finisherr string
-	}{
-		{blessing: ""},
-		{granter: granter{b: bless(pclient, pserver, "blessed")}, blessing: "client/blessed"},
-		{granter: granter{err: errors.New("hell no")}, startErrID: verror.ErrNotTrusted, starterr: "hell no"},
-		{granter: granter{}, blessing: "client/blessed"},
-		{granter: granter{b: pclient.BlessingStore().Default()}, finishErrID: verror.ErrNoAccess, finisherr: "blessing granted not bound to this server"},
-	}
-	for i, test := range tests {
-		call, err := b.client.StartCall(ctx, "mountpoint/server/suffix", "EchoGrantedBlessings", []interface{}{"argument"}, test.granter)
-		if !matchesErrorPattern(err, test.startErrID, test.starterr) {
-			t.Errorf("%d: %+v: StartCall returned error %v", i, test, err)
-		}
-		if err != nil {
-			continue
-		}
-		var result, blessing string
-		if err = call.Finish(&result, &blessing); !matchesErrorPattern(err, test.finishErrID, test.finisherr) {
-			t.Errorf("%+v: Finish returned error %v", test, err)
-		}
-		if err != nil {
-			continue
-		}
-		if result != "argument" || blessing != test.blessing {
-			t.Errorf("%+v: Got (%q, %q)", test, result, blessing)
-		}
-	}
-}
-
 // dischargeTestServer implements the discharge service. Always fails to
 // issue a discharge, but records the impetus and traceid of the RPC call.
 type dischargeTestServer struct {
@@ -904,276 +433,6 @@
 	return impetus, traceid
 }
 
-func TestDischargeImpetusAndContextPropagation(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	var (
-		pserver     = testutil.NewPrincipal("server")
-		pdischarger = testutil.NewPrincipal("discharger")
-		pclient     = testutil.NewPrincipal("client")
-		pctx, _     = v23.WithPrincipal(ctx, pdischarger)
-		sctx, _     = v23.WithPrincipal(ctx, pserver)
-
-		sm = imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-		ns = tnaming.NewSimpleNamespace()
-	)
-
-	// Setup the client so that it shares a blessing with a third-party caveat with the server.
-	setClientBlessings := func(req security.ThirdPartyRequirements) security.Principal {
-		cav, err := security.NewPublicKeyCaveat(pdischarger.PublicKey(), "mountpoint/discharger", req, security.UnconstrainedUse())
-		if err != nil {
-			t.Fatalf("Failed to create ThirdPartyCaveat(%+v): %v", req, err)
-		}
-		b, err := pclient.BlessSelf("client_for_server", cav)
-		if err != nil {
-			t.Fatalf("BlessSelf failed: %v", err)
-		}
-		pclient.BlessingStore().Set(b, "server")
-		return pclient
-	}
-
-	// Initialize the client principal.
-	// It trusts both the application server and the discharger.
-	pclient.AddToRoots(pserver.BlessingStore().Default())
-	pclient.AddToRoots(pdischarger.BlessingStore().Default())
-
-	// Setup the discharge server.
-	var tester dischargeTestServer
-	dischargeServer, err := testInternalNewServer(pctx, sm, ns)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer dischargeServer.Stop()
-	if _, err := dischargeServer.Listen(listenSpec); err != nil {
-		t.Fatal(err)
-	}
-	if err := dischargeServer.Serve("mountpoint/discharger", &tester, &testServerAuthorizer{}); err != nil {
-		t.Fatal(err)
-	}
-
-	// Setup the application server.
-	appServer, err := testInternalNewServer(sctx, sm, ns)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer appServer.Stop()
-	eps, err := appServer.Listen(listenSpec)
-	if err != nil {
-		t.Fatal(err)
-	}
-	// TODO(bjornick,cnicolaou,ashankar): This is a hack to workaround the
-	// fact that a single Listen on the "tcp" protocol followed by a call
-	// to Serve(<name>, ...) transparently creates two endpoints (one for
-	// tcp, one for websockets) and maps both to <name> via a mount.
-	// Because all endpoints to a name are tried in a parallel, this
-	// transparency makes this test hard to follow (many discharge fetch
-	// attempts are made - one for VIF authentication, one for VC
-	// authentication and one for the actual RPC - and having them be made
-	// to two different endpoints in parallel leads to a lot of
-	// non-determinism). The last plan of record known by the author of
-	// this comment was to stop this sly creation of two endpoints and
-	// require that they be done explicitly. When that happens, this hack
-	// can go away, but till then, this workaround allows the test to be
-	// more predictable by ensuring there is only one VIF/VC/Flow to the
-	// server.
-	object := naming.JoinAddressName(eps[0].String(), "object") // instead of "mountpoint/object"
-	if err := appServer.Serve("mountpoint/object", &testServer{}, &testServerAuthorizer{}); err != nil {
-		t.Fatal(err)
-	}
-	tests := []struct {
-		Requirements security.ThirdPartyRequirements
-		Impetus      security.DischargeImpetus
-	}{
-		{ // No requirements, no impetus
-			Requirements: security.ThirdPartyRequirements{},
-			Impetus:      security.DischargeImpetus{},
-		},
-		{ // Require everything
-			Requirements: security.ThirdPartyRequirements{ReportServer: true, ReportMethod: true, ReportArguments: true},
-			Impetus:      security.DischargeImpetus{Server: []security.BlessingPattern{"server"}, Method: "Method", Arguments: []*vdl.Value{vdl.StringValue("argument")}},
-		},
-		{ // Require only the method name
-			Requirements: security.ThirdPartyRequirements{ReportMethod: true},
-			Impetus:      security.DischargeImpetus{Method: "Method"},
-		},
-	}
-
-	for _, test := range tests {
-		pclient := setClientBlessings(test.Requirements)
-		cctx, _ := v23.WithPrincipal(ctx, pclient)
-		client, err := InternalNewClient(sm, ns)
-		if err != nil {
-			t.Fatalf("InternalNewClient(%+v) failed: %v", test.Requirements, err)
-		}
-		defer client.Close()
-		tid := vtrace.GetSpan(cctx).Trace()
-		// StartCall should fetch the discharge, do not worry about finishing the RPC - do not care about that for this test.
-		if _, err := client.StartCall(cctx, object, "Method", []interface{}{"argument"}); err != nil {
-			t.Errorf("StartCall(%+v) failed: %v", test.Requirements, err)
-			continue
-		}
-		impetus, traceid := tester.Release()
-		// There should have been exactly 1 attempt to fetch discharges when making
-		// the RPC to the remote object.
-		if len(impetus) != 1 || len(traceid) != 1 {
-			t.Errorf("Test %+v: Got (%d, %d) (#impetus, #traceid), wanted exactly one", test.Requirements, len(impetus), len(traceid))
-			continue
-		}
-		// VC creation does not have any "impetus", it is established without
-		// knowledge of the context of the RPC. So ignore that.
-		//
-		// TODO(ashankar): Should the impetus of the RPC that initiated the
-		// VIF/VC creation be propagated?
-		if got, want := impetus[len(impetus)-1], test.Impetus; !reflect.DeepEqual(got, want) {
-			t.Errorf("Test %+v: Got impetus %v, want %v", test.Requirements, got, want)
-		}
-		// But the context used for all of this should be the same
-		// (thereby allowing debug traces to link VIF/VC creation with
-		// the RPC that initiated them).
-		for idx, got := range traceid {
-			if !reflect.DeepEqual(got, tid) {
-				t.Errorf("Test %+v: %d - Got trace id %q, want %q", test.Requirements, idx, hex.EncodeToString(got[:]), hex.EncodeToString(tid[:]))
-			}
-		}
-	}
-}
-
-func TestRPCClientAuthorization(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-
-	type v []interface{}
-	var (
-		// Principals
-		pclient, pserver = testutil.NewPrincipal("client"), testutil.NewPrincipal("server")
-		pdischarger      = testutil.NewPrincipal("discharger")
-
-		now = time.Now()
-
-		serverName          = "mountpoint/server"
-		dischargeServerName = "mountpoint/dischargeserver"
-
-		// Caveats on blessings to the client: First-party caveats
-		cavOnlyEcho = mkCaveat(security.NewMethodCaveat("Echo"))
-		cavExpired  = mkCaveat(security.NewExpiryCaveat(now.Add(-1 * time.Second)))
-		// Caveats on blessings to the client: Third-party caveats
-		cavTPValid   = mkThirdPartyCaveat(pdischarger.PublicKey(), dischargeServerName, mkCaveat(security.NewExpiryCaveat(now.Add(24*time.Hour))))
-		cavTPExpired = mkThirdPartyCaveat(pdischarger.PublicKey(), dischargeServerName, mkCaveat(security.NewExpiryCaveat(now.Add(-1*time.Second))))
-
-		// Client blessings that will be tested.
-		bServerClientOnlyEcho  = bless(pserver, pclient, "onlyecho", cavOnlyEcho)
-		bServerClientExpired   = bless(pserver, pclient, "expired", cavExpired)
-		bServerClientTPValid   = bless(pserver, pclient, "dischargeable_third_party_caveat", cavTPValid)
-		bServerClientTPExpired = bless(pserver, pclient, "expired_third_party_caveat", cavTPExpired)
-		bClient                = pclient.BlessingStore().Default()
-		bRandom, _             = pclient.BlessSelf("random")
-
-		mgr   = imanager.InternalNew(ctx, naming.FixedRoutingID(0x1111111))
-		ns    = tnaming.NewSimpleNamespace()
-		tests = []struct {
-			blessings  security.Blessings // Blessings used by the client
-			name       string             // object name on which the method is invoked
-			method     string
-			args       v
-			results    v
-			authorized bool // Whether or not the RPC should be authorized by the server.
-		}{
-			// There are three different authorization policies (security.Authorizer implementations)
-			// used by the server, depending on the suffix (see testServerDisp.Lookup):
-			// - nilAuth suffix: the default authorization policy (only delegates of or delegators of the server can call RPCs)
-			// - aclAuth suffix: the AccessList only allows blessings matching the patterns "server" or "client"
-			// - other suffixes: testServerAuthorizer allows any principal to call any method except "Unauthorized"
-
-			// Expired blessings should fail nilAuth and aclAuth (which care about names), but should succeed on
-			// other suffixes (which allow all blessings), unless calling the Unauthorized method.
-			{bServerClientExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
-			{bServerClientExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
-			{bServerClientExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
-			{bServerClientExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
-
-			// Same for blessings that should fail to obtain a discharge for the third party caveat.
-			{bServerClientTPExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
-			{bServerClientTPExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
-			{bServerClientTPExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
-			{bServerClientTPExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
-
-			// The "server/client" blessing (with MethodCaveat("Echo")) should satisfy all authorization policies
-			// when "Echo" is called.
-			{bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
-			{bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
-			{bServerClientOnlyEcho, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
-
-			// The "server/client" blessing (with MethodCaveat("Echo")) should satisfy no authorization policy
-			// when any other method is invoked, except for the testServerAuthorizer policy (which will
-			// not recognize the blessing "server/onlyecho", but it would authorize anyone anyway).
-			{bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Closure", nil, nil, false},
-			{bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Closure", nil, nil, false},
-			{bServerClientOnlyEcho, "mountpoint/server/suffix", "Closure", nil, nil, true},
-
-			// The "client" blessing doesn't satisfy the default authorization policy, but does satisfy
-			// the AccessList and the testServerAuthorizer policy.
-			{bClient, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
-			{bClient, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
-			{bClient, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
-			{bClient, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
-
-			// The "random" blessing does not satisfy either the default policy or the AccessList, but does
-			// satisfy testServerAuthorizer.
-			{bRandom, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
-			{bRandom, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
-			{bRandom, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
-			{bRandom, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
-
-			// The "server/dischargeable_third_party_caveat" blessing satisfies all policies.
-			// (the discharges should be fetched).
-			{bServerClientTPValid, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
-			{bServerClientTPValid, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
-			{bServerClientTPValid, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
-			{bServerClientTPValid, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
-		}
-	)
-
-	// Start the main server.
-	_, server := startServer(t, ctx, pserver, mgr, ns, serverName, testServerDisp{&testServer{}})
-	defer stopServer(t, ctx, server, ns, serverName)
-
-	// Start the discharge server.
-	_, dischargeServer := startServer(t, ctx, pdischarger, mgr, ns, dischargeServerName, testutil.LeafDispatcher(&dischargeServer{}, security.AllowEveryone()))
-	defer stopServer(t, ctx, dischargeServer, ns, dischargeServerName)
-
-	// The server should recognize the client principal as an authority on "client" and "random" blessings.
-	pserver.AddToRoots(bClient)
-	pserver.AddToRoots(bRandom)
-	// And the client needs to recognize the server's and discharger's blessings to decide which of its
-	// own blessings to share.
-	pclient.AddToRoots(pserver.BlessingStore().Default())
-	pclient.AddToRoots(pdischarger.BlessingStore().Default())
-	// Set a blessing on the client's blessing store to be presented to the discharge server.
-	pclient.BlessingStore().Set(pclient.BlessingStore().Default(), "discharger")
-	// testutil.NewPrincipal sets up a principal that shares blessings with all servers, undo that.
-	pclient.BlessingStore().Set(security.Blessings{}, security.AllPrincipals)
-
-	for i, test := range tests {
-		name := fmt.Sprintf("#%d: %q.%s(%v) by %v", i, test.name, test.method, test.args, test.blessings)
-		client, err := InternalNewClient(mgr, ns)
-		if err != nil {
-			t.Fatalf("InternalNewClient failed: %v", err)
-		}
-		defer client.Close()
-
-		pclient.BlessingStore().Set(test.blessings, "server")
-		ctx, _ := v23.WithPrincipal(ctx, pclient)
-		err = client.Call(ctx, test.name, test.method, test.args, makeResultPtrs(test.results))
-		if err != nil && test.authorized {
-			t.Errorf(`%s client.Call got error: "%v", wanted the RPC to succeed`, name, err)
-		} else if err == nil && !test.authorized {
-			t.Errorf("%s call.Finish succeeded, expected authorization failure", name)
-		} else if !test.authorized && verror.ErrorID(err) != verror.ErrNoAccess.ID {
-			t.Errorf("%s. call.Finish returned error %v(%v), wanted %v", name, verror.ErrorID(verror.Convert(verror.ErrNoAccess, nil, err)), err, verror.ErrNoAccess)
-		}
-	}
-}
-
 // singleBlessingStore implements security.BlessingStore. It is a
 // BlessingStore that marks the last blessing that was set on it as
 // shareable with any peer. It does not care about the public key that
@@ -1226,410 +485,6 @@
 	return &p.b
 }
 
-func TestRPCClientBlessingsPublicKey(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	var (
-		pprovider, pserver = testutil.NewPrincipal("root"), testutil.NewPrincipal("server")
-		pclient            = &singleBlessingPrincipal{Principal: testutil.NewPrincipal("client")}
-
-		bserver = bless(pprovider, pserver, "server")
-		bclient = bless(pprovider, pclient, "client")
-		bvictim = bless(pprovider, testutil.NewPrincipal("victim"), "victim")
-	)
-	// Make the client and server trust blessings from pprovider.
-	pclient.AddToRoots(pprovider.BlessingStore().Default())
-	pserver.AddToRoots(pprovider.BlessingStore().Default())
-
-	// Make the server present bserver to all clients and start the server.
-	pserver.BlessingStore().SetDefault(bserver)
-	b := createBundle(t, ctx, pserver, &testServer{})
-	defer b.cleanup(t, ctx)
-
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	tests := []struct {
-		blessings security.Blessings
-		errID     verror.IDAction
-		err       string
-	}{
-		{blessings: bclient},
-		// server disallows clients from authenticating with blessings not bound to
-		// the client principal's public key
-		{blessings: bvictim, errID: verror.ErrNoAccess, err: "bound to a different public key"},
-		{blessings: bserver, errID: verror.ErrNoAccess, err: "bound to a different public key"},
-	}
-	for i, test := range tests {
-		name := fmt.Sprintf("%d: Client RPCing with blessings %v", i, test.blessings)
-		pclient.BlessingStore().Set(test.blessings, "root")
-		if err := b.client.Call(ctx, "mountpoint/server/suffix", "Closure", nil, nil); !matchesErrorPattern(err, test.errID, test.err) {
-			t.Errorf("%v: client.Call returned error %v", name, err)
-			continue
-		}
-	}
-}
-
-func TestServerLocalBlessings(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	var (
-		pprovider, pclient, pserver = testutil.NewPrincipal("root"), testutil.NewPrincipal("client"), testutil.NewPrincipal("server")
-		pdischarger                 = pprovider
-
-		mgr = imanager.InternalNew(ctx, naming.FixedRoutingID(0x1111111))
-		ns  = tnaming.NewSimpleNamespace()
-
-		tpCav = mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/dischargeserver", mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour))))
-
-		bserver = bless(pprovider, pserver, "server", tpCav)
-		bclient = bless(pprovider, pclient, "client")
-	)
-	// Make the client and server principals trust root certificates from
-	// pprovider.
-	pclient.AddToRoots(pprovider.BlessingStore().Default())
-	pserver.AddToRoots(pprovider.BlessingStore().Default())
-
-	// Make the server present bserver to all clients.
-	pserver.BlessingStore().SetDefault(bserver)
-
-	// Start the server and the discharger.
-	_, server := startServer(t, ctx, pserver, mgr, ns, "mountpoint/server", testServerDisp{&testServer{}})
-	defer stopServer(t, ctx, server, ns, "mountpoint/server")
-
-	_, dischargeServer := startServer(t, ctx, pdischarger, mgr, ns, "mountpoint/dischargeserver", testutil.LeafDispatcher(&dischargeServer{}, security.AllowEveryone()))
-	defer stopServer(t, ctx, dischargeServer, ns, "mountpoint/dischargeserver")
-
-	// Make the client present bclient to all servers that are blessed
-	// by pprovider.
-	pclient.BlessingStore().Set(bclient, "root")
-	client, err := InternalNewClient(mgr, ns)
-	if err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
-	}
-	defer client.Close()
-
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	var gotServer, gotClient string
-	if err := client.Call(ctx, "mountpoint/server/suffix", "EchoBlessings", nil, []interface{}{&gotServer, &gotClient}); err != nil {
-		t.Fatalf("Finish failed: %v", err)
-	}
-	if wantServer, wantClient := "[root/server]", "[root/client]"; gotServer != wantServer || gotClient != wantClient {
-		t.Fatalf("EchoBlessings: got %v, %v want %v, %v", gotServer, gotClient, wantServer, wantClient)
-	}
-}
-
-func TestDischargePurgeFromCache(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-
-	var (
-		pserver     = testutil.NewPrincipal("server")
-		pdischarger = pserver // In general, the discharger can be a separate principal. In this test, it happens to be the server.
-		pclient     = testutil.NewPrincipal("client")
-		// Client is blessed with a third-party caveat. The discharger service issues discharges with a fakeTimeCaveat.
-		// This blessing is presented to "server".
-		bclient = bless(pserver, pclient, "client", mkThirdPartyCaveat(pdischarger.PublicKey(), "mountpoint/server/discharger", security.UnconstrainedUse()))
-
-		b = createBundle(t, ctx, pserver, &testServer{})
-	)
-	defer b.cleanup(t, ctx)
-	// Setup the client to recognize the server's blessing and present bclient to it.
-	pclient.AddToRoots(pserver.BlessingStore().Default())
-	pclient.BlessingStore().Set(bclient, "server")
-
-	var err error
-	if b.client, err = InternalNewClient(b.sm, b.ns); err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
-	}
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	call := func() error {
-		var got string
-		if err := b.client.Call(ctx, "mountpoint/server/aclAuth", "Echo", []interface{}{"batman"}, []interface{}{&got}); err != nil {
-			return err
-		}
-		if want := `method:"Echo",suffix:"aclAuth",arg:"batman"`; got != want {
-			return verror.Convert(verror.ErrBadArg, nil, fmt.Errorf("Got [%v] want [%v]", got, want))
-		}
-		return nil
-	}
-
-	// First call should succeed
-	if err := call(); err != nil {
-		t.Fatal(err)
-	}
-	// Advance virtual clock, which will invalidate the discharge
-	clock.Advance(1)
-	if err, want := call(), "not authorized"; !matchesErrorPattern(err, verror.ErrNoAccess, want) {
-		t.Errorf("Got error [%v] wanted to match pattern %q", err, want)
-	}
-	// But retrying will succeed since the discharge should be purged from cache and refreshed
-	if err := call(); err != nil {
-		t.Fatal(err)
-	}
-}
-
-type cancelTestServer struct {
-	started   chan struct{}
-	cancelled chan struct{}
-	t         *testing.T
-}
-
-func newCancelTestServer(t *testing.T) *cancelTestServer {
-	return &cancelTestServer{
-		started:   make(chan struct{}),
-		cancelled: make(chan struct{}),
-		t:         t,
-	}
-}
-
-func (s *cancelTestServer) CancelStreamReader(ctx *context.T, call rpc.StreamServerCall) error {
-	close(s.started)
-	var b []byte
-	if err := call.Recv(&b); err != io.EOF {
-		s.t.Errorf("Got error %v, want io.EOF", err)
-	}
-	<-ctx.Done()
-	close(s.cancelled)
-	return nil
-}
-
-// CancelStreamIgnorer doesn't read from it's input stream so all it's
-// buffers fill.  The intention is to show that call.Done() is closed
-// even when the stream is stalled.
-func (s *cancelTestServer) CancelStreamIgnorer(ctx *context.T, _ rpc.StreamServerCall) error {
-	close(s.started)
-	<-ctx.Done()
-	close(s.cancelled)
-	return nil
-}
-
-func waitForCancel(t *testing.T, ts *cancelTestServer, cancel context.CancelFunc) {
-	<-ts.started
-	cancel()
-	<-ts.cancelled
-}
-
-// TestCancel tests cancellation while the server is reading from a stream.
-func TestCancel(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	var (
-		ts               = newCancelTestServer(t)
-		pclient, pserver = newClientServerPrincipals()
-		b                = createBundle(t, ctx, pserver, ts)
-	)
-	defer b.cleanup(t, ctx)
-
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	ctx, cancel := context.WithCancel(ctx)
-	_, err := b.client.StartCall(ctx, "mountpoint/server/suffix", "CancelStreamReader", []interface{}{})
-	if err != nil {
-		t.Fatalf("Start call failed: %v", err)
-	}
-	waitForCancel(t, ts, cancel)
-}
-
-// TestCancelWithFullBuffers tests that even if the writer has filled the buffers and
-// the server is not reading that the cancel message gets through.
-func TestCancelWithFullBuffers(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	var (
-		ts               = newCancelTestServer(t)
-		pclient, pserver = newClientServerPrincipals()
-		b                = createBundle(t, ctx, pserver, ts)
-	)
-	defer b.cleanup(t, ctx)
-
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	ctx, cancel := context.WithCancel(ctx)
-	call, err := b.client.StartCall(ctx, "mountpoint/server/suffix", "CancelStreamIgnorer", []interface{}{})
-	if err != nil {
-		t.Fatalf("Start call failed: %v", err)
-	}
-	// Fill up all the write buffers to ensure that cancelling works even when the stream
-	// is blocked.
-	call.Send(make([]byte, vc.MaxSharedBytes))
-	call.Send(make([]byte, vc.DefaultBytesBufferedPerFlow))
-
-	waitForCancel(t, ts, cancel)
-}
-
-type streamRecvInGoroutineServer struct{ c chan error }
-
-func (s *streamRecvInGoroutineServer) RecvInGoroutine(_ *context.T, call rpc.StreamServerCall) error {
-	// Spawn a goroutine to read streaming data from the client.
-	go func() {
-		var i interface{}
-		for {
-			err := call.Recv(&i)
-			if err != nil {
-				s.c <- err
-				return
-			}
-		}
-	}()
-	// Imagine the server did some processing here and now that it is done,
-	// it does not care to see what else the client has to say.
-	return nil
-}
-
-func TestStreamReadTerminatedByServer(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	var (
-		pclient, pserver = newClientServerPrincipals()
-		s                = &streamRecvInGoroutineServer{c: make(chan error, 1)}
-		b                = createBundle(t, ctx, pserver, s)
-	)
-	defer b.cleanup(t, ctx)
-
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	call, err := b.client.StartCall(ctx, "mountpoint/server/suffix", "RecvInGoroutine", []interface{}{})
-	if err != nil {
-		t.Fatalf("StartCall failed: %v", err)
-	}
-
-	c := make(chan error, 1)
-	go func() {
-		for i := 0; true; i++ {
-			if err := call.Send(i); err != nil {
-				c <- err
-				return
-			}
-		}
-	}()
-
-	// The goroutine at the server executing "Recv" should have terminated
-	// with EOF.
-	if err := <-s.c; err != io.EOF {
-		t.Errorf("Got %v at server, want io.EOF", err)
-	}
-	// The client Send should have failed since the RPC has been
-	// terminated.
-	if err := <-c; err == nil {
-		t.Errorf("Client Send should fail as the server should have closed the flow")
-	}
-}
-
-// TestConnectWithIncompatibleServers tests that clients ignore incompatible endpoints.
-func TestConnectWithIncompatibleServers(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	var (
-		pclient, pserver = newClientServerPrincipals()
-		b                = createBundle(t, ctx, pserver, &testServer{})
-	)
-	defer b.cleanup(t, ctx)
-
-	// Publish some incompatible endpoints.
-	publisher := publisher.New(ctx, b.ns, publishPeriod)
-	defer publisher.WaitForStop()
-	defer publisher.Stop()
-	publisher.AddName("incompatible", false, false)
-	publisher.AddServer("/@2@tcp@localhost:10000@@1000000@2000000@@")
-	publisher.AddServer("/@2@tcp@localhost:10001@@2000000@3000000@@")
-
-	ctx, _ = v23.WithPrincipal(ctx, pclient)
-	_, err := b.client.StartCall(ctx, "incompatible/suffix", "Echo", []interface{}{"foo"}, options.NoRetry{})
-	if verror.ErrorID(err) != verror.ErrNoServers.ID {
-		t.Errorf("Expected error %v, found: %v", verror.ErrNoServers, err)
-	}
-
-	// Now add a server with a compatible endpoint and try again.
-	publisher.AddServer("/" + b.ep.String())
-	publisher.AddName("incompatible", false, false)
-
-	call, err := b.client.StartCall(ctx, "incompatible/suffix", "Echo", []interface{}{"foo"})
-	if err != nil {
-		t.Fatal(err)
-	}
-	var result string
-	if err = call.Finish(&result); err != nil {
-		t.Errorf("Unexpected error finishing call %v", err)
-	}
-	expected := `method:"Echo",suffix:"suffix",arg:"foo"`
-	if result != expected {
-		t.Errorf("Wrong result returned.  Got %s, wanted %s", result, expected)
-	}
-}
-
-func TestPreferredAddress(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-	pa := netstate.AddressChooserFunc(func(string, []net.Addr) ([]net.Addr, error) {
-		return []net.Addr{netstate.NewNetAddr("tcp", "1.1.1.1")}, nil
-	})
-	ctx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal("server"))
-	server, err := testInternalNewServer(ctx, sm, ns)
-	if err != nil {
-		t.Errorf("InternalNewServer failed: %v", err)
-	}
-	defer server.Stop()
-
-	spec := rpc.ListenSpec{
-		Addrs:          rpc.ListenAddrs{{"tcp", ":0"}},
-		AddressChooser: pa,
-	}
-	eps, err := server.Listen(spec)
-	if err != nil {
-		t.Errorf("unexpected error: %s", err)
-	}
-	iep := eps[0].(*inaming.Endpoint)
-	host, _, err := net.SplitHostPort(iep.Address)
-	if err != nil {
-		t.Errorf("unexpected error: %s", err)
-	}
-	if got, want := host, "1.1.1.1"; got != want {
-		t.Errorf("got %q, want %q", got, want)
-	}
-	// Won't override the specified address.
-	eps, err = server.Listen(listenSpec)
-	iep = eps[0].(*inaming.Endpoint)
-	host, _, err = net.SplitHostPort(iep.Address)
-	if err != nil {
-		t.Errorf("unexpected error: %s", err)
-	}
-	if got, want := host, "127.0.0.1"; got != want {
-		t.Errorf("got %q, want %q", got, want)
-	}
-}
-
-func TestPreferredAddressErrors(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-	paerr := netstate.AddressChooserFunc(func(_ string, a []net.Addr) ([]net.Addr, error) {
-		return nil, fmt.Errorf("oops")
-	})
-	ctx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal("server"))
-	server, err := testInternalNewServer(ctx, sm, ns)
-	if err != nil {
-		t.Errorf("InternalNewServer failed: %v", err)
-	}
-	defer server.Stop()
-	spec := rpc.ListenSpec{
-		Addrs:          rpc.ListenAddrs{{"tcp", ":0"}},
-		AddressChooser: paerr,
-	}
-	eps, err := server.Listen(spec)
-
-	if got, want := len(eps), 0; got != want {
-		t.Errorf("got %q, want %q", got, want)
-	}
-	status := server.Status()
-	if got, want := len(status.Errors), 1; got != want {
-		t.Errorf("got %q, want %q", got, want)
-	}
-	if got, want := status.Errors[0].Error(), "oops"; got != want {
-		t.Errorf("got %q, want %q", got, want)
-	}
-}
-
 func TestSecurityNone(t *testing.T) {
 	ctx, shutdown := initForTest()
 	defer shutdown()
@@ -1647,9 +502,9 @@
 	if err := server.ServeDispatcher("mp/server", disp); err != nil {
 		t.Fatalf("server.Serve failed: %v", err)
 	}
-	client, err := InternalNewClient(sm, ns)
+	client, err := DeprecatedNewClient(sm, ns)
 	if err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
+		t.Fatalf("DeprecatedNewClient failed: %v", err)
 	}
 	// When using SecurityNone, all authorization checks should be skipped, so
 	// unauthorized methods should be callable.
@@ -1680,9 +535,9 @@
 	if err := server.ServeDispatcher("mp/server", disp); err != nil {
 		t.Fatalf("server.Serve failed: %v", err)
 	}
-	client, err := InternalNewClient(sm, ns)
+	client, err := DeprecatedNewClient(sm, ns)
 	if err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
+		t.Fatalf("DeprecatedNewClient failed: %v", err)
 	}
 
 	// A call should fail if the principal in the ctx is nil and SecurityNone is not specified.
@@ -1696,25 +551,6 @@
 	}
 }
 
-func TestCallWithNilContext(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x66666666))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-	client, err := InternalNewClient(sm, ns)
-	if err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
-	}
-	call, err := client.StartCall(nil, "foo", "bar", []interface{}{}, options.SecurityNone)
-	if call != nil {
-		t.Errorf("Expected nil interface got: %#v", call)
-	}
-	if verror.ErrorID(err) != verror.ErrBadArg.ID {
-		t.Errorf("Expected a BadArg error, got: %s", err.Error())
-	}
-}
-
 func TestServerBlessingsOpt(t *testing.T) {
 	ctx, shutdown := initForTest()
 	defer shutdown()
@@ -1747,7 +583,7 @@
 	runClient := func(server string) ([]string, error) {
 		smc := imanager.InternalNew(ctx, naming.FixedRoutingID(0xc))
 		defer smc.Shutdown()
-		client, err := InternalNewClient(
+		client, err := DeprecatedNewClient(
 			smc,
 			ns)
 		if err != nil {
@@ -1817,7 +653,7 @@
 		}
 		smc := imanager.InternalNew(ctx, rid)
 		defer smc.Shutdown()
-		client, err := InternalNewClient(smc, ns)
+		client, err := DeprecatedNewClient(smc, ns)
 		if err != nil {
 			t.Fatalf("failed to create client: %v", err)
 		}
@@ -1882,7 +718,7 @@
 	}
 	sm := imanager.InternalNew(ctx, rid)
 
-	c, err := InternalNewClient(sm, ns)
+	c, err := DeprecatedNewClient(sm, ns)
 	if err != nil {
 		t.Fatalf("failed to create client: %v", err)
 	}
@@ -1932,7 +768,7 @@
 		}
 		smc := imanager.InternalNew(sctx, rid)
 		defer smc.Shutdown()
-		client, err := InternalNewClient(smc, ns)
+		client, err := DeprecatedNewClient(smc, ns)
 		if err != nil {
 			t.Fatalf("failed to create client: %v", err)
 		}
@@ -2011,7 +847,7 @@
 	defer runServer(t, sctx, ns, mountName, &testServer{}).Shutdown()
 
 	smc := imanager.InternalNew(sctx, naming.FixedRoutingID(0xc))
-	client, err := InternalNewClient(smc, ns)
+	client, err := DeprecatedNewClient(smc, ns)
 	if err != nil {
 		t.Fatal(err)
 	}
@@ -2082,7 +918,7 @@
 	}
 	smc := imanager.InternalNew(ctx, rid)
 	defer smc.Shutdown()
-	client, err := InternalNewClient(smc, ns)
+	client, err := DeprecatedNewClient(smc, ns)
 	if err != nil {
 		t.Fatalf("failed to create client: %v", err)
 	}
@@ -2134,3 +970,71 @@
 		return nil
 	})
 }
+
+func TestServerStates(t *testing.T) {
+	ctx, shutdown := initForTest()
+	defer shutdown()
+	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
+	defer sm.Shutdown()
+	ns := tnaming.NewSimpleNamespace()
+	sctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("test"))
+	expectBadState := func(err error) {
+		if verror.ErrorID(err) != verror.ErrBadState.ID {
+			t.Fatalf("%s: unexpected error: %v", loc(1), err)
+		}
+	}
+
+	expectNoError := func(err error) {
+		if err != nil {
+			t.Fatalf("%s: unexpected error: %v", loc(1), err)
+		}
+	}
+
+	server, err := testInternalNewServer(sctx, sm, ns)
+	expectNoError(err)
+	defer server.Stop()
+
+	expectState := func(s rpc.ServerState) {
+		if got, want := server.Status().State, s; got != want {
+			t.Fatalf("%s: got %s, want %s", loc(1), got, want)
+		}
+	}
+
+	expectState(rpc.ServerActive)
+
+	// Need to call Listen first.
+	err = server.Serve("", &testServer{}, nil)
+	expectBadState(err)
+	err = server.AddName("a")
+	expectBadState(err)
+
+	_, err = server.Listen(rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}})
+	expectNoError(err)
+
+	expectState(rpc.ServerActive)
+
+	err = server.Serve("", &testServer{}, nil)
+	expectNoError(err)
+
+	err = server.Serve("", &testServer{}, nil)
+	expectBadState(err)
+
+	expectState(rpc.ServerActive)
+
+	err = server.AddName("a")
+	expectNoError(err)
+
+	expectState(rpc.ServerActive)
+
+	server.RemoveName("a")
+
+	expectState(rpc.ServerActive)
+
+	err = server.Stop()
+	expectNoError(err)
+	err = server.Stop()
+	expectNoError(err)
+
+	err = server.AddName("a")
+	expectBadState(err)
+}
diff --git a/runtime/internal/rpc/roaming_test.go b/runtime/internal/rpc/roaming_test.go
new file mode 100644
index 0000000..95cecdd
--- /dev/null
+++ b/runtime/internal/rpc/roaming_test.go
@@ -0,0 +1,303 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rpc
+
+import (
+	"net"
+	"reflect"
+	"sort"
+	"testing"
+	"time"
+
+	"v.io/v23"
+	"v.io/v23/naming"
+	"v.io/v23/rpc"
+	"v.io/x/lib/netstate"
+	"v.io/x/lib/set"
+	"v.io/x/ref/lib/pubsub"
+	inaming "v.io/x/ref/runtime/internal/naming"
+	_ "v.io/x/ref/runtime/internal/rpc/protocols/tcp"
+	_ "v.io/x/ref/runtime/internal/rpc/protocols/ws"
+	_ "v.io/x/ref/runtime/internal/rpc/protocols/wsh"
+	imanager "v.io/x/ref/runtime/internal/rpc/stream/manager"
+	tnaming "v.io/x/ref/runtime/internal/testing/mocks/naming"
+	"v.io/x/ref/test/testutil"
+)
+
+// TODO(mattr): Transition this to using public API.
+func TestRoaming(t *testing.T) {
+	ctx, shutdown := initForTest()
+	defer shutdown()
+	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
+	defer sm.Shutdown()
+	ns := tnaming.NewSimpleNamespace()
+
+	publisher := pubsub.NewPublisher()
+	roaming := make(chan pubsub.Setting)
+	stop, err := publisher.CreateStream("TestRoaming", "TestRoaming", roaming)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() { publisher.Shutdown(); <-stop }()
+
+	nctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("test"))
+	server, err := testInternalNewServerWithPubsub(nctx, sm, ns, publisher, "TestRoaming")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer server.Stop()
+
+	ipv4And6 := netstate.AddressChooserFunc(func(network string, addrs []net.Addr) ([]net.Addr, error) {
+		accessible := netstate.ConvertToAddresses(addrs)
+		ipv4 := accessible.Filter(netstate.IsUnicastIPv4)
+		ipv6 := accessible.Filter(netstate.IsUnicastIPv6)
+		return append(ipv4.AsNetAddrs(), ipv6.AsNetAddrs()...), nil
+	})
+	spec := rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{
+			{"tcp", "*:0"},
+			{"tcp", ":0"},
+			{"tcp", ":0"},
+		},
+		AddressChooser: ipv4And6,
+	}
+
+	eps, err := server.Listen(spec)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if len(eps) == 0 {
+		t.Fatal("no endpoints listened on.")
+	}
+
+	if err = server.Serve("foo", &testServer{}, nil); err != nil {
+		t.Fatal(err)
+	}
+	setLeafEndpoints(eps)
+	if err = server.AddName("bar"); err != nil {
+		t.Fatal(err)
+	}
+
+	status := server.Status()
+	if got, want := status.Endpoints, eps; !cmpEndpoints(got, want) {
+		t.Fatalf("got %v, want %v", got, want)
+	}
+
+	if got, want := len(status.Mounts), len(eps)*2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+
+	n1 := netstate.NewNetAddr("ip", "1.1.1.1")
+	n2 := netstate.NewNetAddr("ip", "2.2.2.2")
+
+	watcher := make(chan rpc.NetworkChange, 10)
+	server.WatchNetwork(watcher)
+	defer close(watcher)
+
+	roaming <- NewAddAddrsSetting([]net.Addr{n1, n2})
+
+	waitForChange := func() *rpc.NetworkChange {
+		ctx.Infof("Waiting on %p", watcher)
+		select {
+		case c := <-watcher:
+			return &c
+		case <-time.After(time.Minute):
+			t.Fatalf("timedout: %s", loc(1))
+		}
+		return nil
+	}
+
+	// We expect 4 changes, one for each IP per usable listen spec addr.
+	change := waitForChange()
+	if got, want := len(change.Changed), 4; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+
+	nepsA := make([]naming.Endpoint, len(eps))
+	copy(nepsA, eps)
+	for _, p := range getUniqPorts(eps) {
+		nep1 := updateHost(eps[0], net.JoinHostPort("1.1.1.1", p))
+		nep2 := updateHost(eps[0], net.JoinHostPort("2.2.2.2", p))
+		nepsA = append(nepsA, []naming.Endpoint{nep1, nep2}...)
+	}
+
+	status = server.Status()
+	if got, want := status.Endpoints, nepsA; !cmpEndpoints(got, want) {
+		t.Fatalf("got %v, want %v [%d, %d]", got, want, len(got), len(want))
+	}
+
+	if got, want := len(status.Mounts), len(nepsA)*2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+	if got, want := len(status.Mounts.Servers()), len(nepsA); got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+
+	roaming <- NewRmAddrsSetting([]net.Addr{n1})
+
+	// We expect 2 changes, one for each usable listen spec addr.
+	change = waitForChange()
+	if got, want := len(change.Changed), 2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+
+	nepsR := make([]naming.Endpoint, len(eps))
+	copy(nepsR, eps)
+	for _, p := range getUniqPorts(eps) {
+		nep2 := updateHost(eps[0], net.JoinHostPort("2.2.2.2", p))
+		nepsR = append(nepsR, nep2)
+	}
+
+	status = server.Status()
+	if got, want := status.Endpoints, nepsR; !cmpEndpoints(got, want) {
+		t.Fatalf("got %v, want %v [%d, %d]", got, want, len(got), len(want))
+	}
+
+	// Remove all addresses to mimic losing all connectivity.
+	roaming <- NewRmAddrsSetting(getIPAddrs(nepsR))
+
+	// We expect changes for all of the current endpoints
+	change = waitForChange()
+	if got, want := len(change.Changed), len(nepsR); got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+
+	status = server.Status()
+	if got, want := len(status.Mounts), 0; got != want {
+		t.Fatalf("got %d, want %d: %v", got, want, status.Mounts)
+	}
+
+	roaming <- NewAddAddrsSetting([]net.Addr{n1})
+	// We expect 2 changes, one for each usable listen spec addr.
+	change = waitForChange()
+	if got, want := len(change.Changed), 2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+
+}
+
+func TestWatcherDeadlock(t *testing.T) {
+	ctx, shutdown := initForTest()
+	defer shutdown()
+	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
+	defer sm.Shutdown()
+	ns := tnaming.NewSimpleNamespace()
+
+	publisher := pubsub.NewPublisher()
+	roaming := make(chan pubsub.Setting)
+	stop, err := publisher.CreateStream("TestWatcherDeadlock", "TestWatcherDeadlock", roaming)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer func() { publisher.Shutdown(); <-stop }()
+
+	nctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("test"))
+	server, err := testInternalNewServerWithPubsub(nctx, sm, ns, publisher, "TestWatcherDeadlock")
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer server.Stop()
+
+	spec := rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{
+			{"tcp", ":0"},
+		},
+	}
+	eps, err := server.Listen(spec)
+	if err != nil {
+		t.Fatal(err)
+	}
+	if err = server.Serve("foo", &testServer{}, nil); err != nil {
+		t.Fatal(err)
+	}
+	setLeafEndpoints(eps)
+
+	// Set a watcher that we never read from - the intent is to make sure
+	// that the listener still listens to changes even though there is no
+	// goroutine to read from the watcher channel.
+	watcher := make(chan rpc.NetworkChange, 0)
+	server.WatchNetwork(watcher)
+	defer close(watcher)
+
+	// Remove all addresses to mimic losing all connectivity.
+	roaming <- NewRmAddrsSetting(getIPAddrs(eps))
+
+	// Add in two new addresses
+	n1 := netstate.NewNetAddr("ip", "1.1.1.1")
+	n2 := netstate.NewNetAddr("ip", "2.2.2.2")
+	roaming <- NewAddAddrsSetting([]net.Addr{n1, n2})
+
+	neps := make([]naming.Endpoint, 0, len(eps))
+	for _, p := range getUniqPorts(eps) {
+		nep1 := updateHost(eps[0], net.JoinHostPort("1.1.1.1", p))
+		nep2 := updateHost(eps[0], net.JoinHostPort("2.2.2.2", p))
+		neps = append(neps, []naming.Endpoint{nep1, nep2}...)
+	}
+	then := time.Now()
+	for {
+		status := server.Status()
+		if got, want := status.Endpoints, neps; cmpEndpoints(got, want) {
+			break
+		}
+		time.Sleep(100 * time.Millisecond)
+		if time.Now().Sub(then) > time.Minute {
+			t.Fatalf("timed out waiting for changes to take effect")
+		}
+	}
+}
+
+func updateHost(ep naming.Endpoint, address string) naming.Endpoint {
+	niep := *(ep).(*inaming.Endpoint)
+	niep.Address = address
+	return &niep
+}
+
+func getIPAddrs(eps []naming.Endpoint) []net.Addr {
+	hosts := map[string]struct{}{}
+	for _, ep := range eps {
+		iep := (ep).(*inaming.Endpoint)
+		h, _, _ := net.SplitHostPort(iep.Address)
+		if len(h) > 0 {
+			hosts[h] = struct{}{}
+		}
+	}
+	addrs := []net.Addr{}
+	for h, _ := range hosts {
+		addrs = append(addrs, netstate.NewNetAddr("ip", h))
+	}
+	return addrs
+}
+
+func cmpEndpoints(got, want []naming.Endpoint) bool {
+	if len(got) != len(want) {
+		return false
+	}
+	return reflect.DeepEqual(endpointToStrings(got), endpointToStrings(want))
+}
+
+func getUniqPorts(eps []naming.Endpoint) []string {
+	ports := map[string]struct{}{}
+	for _, ep := range eps {
+		iep := ep.(*inaming.Endpoint)
+		_, p, _ := net.SplitHostPort(iep.Address)
+		ports[p] = struct{}{}
+	}
+	return set.String.ToSlice(ports)
+}
+
+func endpointToStrings(eps []naming.Endpoint) []string {
+	r := []string{}
+	for _, ep := range eps {
+		r = append(r, ep.String())
+	}
+	sort.Strings(r)
+	return r
+}
+
+func setLeafEndpoints(eps []naming.Endpoint) {
+	for i := range eps {
+		eps[i].(*inaming.Endpoint).IsLeaf = true
+	}
+}
diff --git a/runtime/internal/rpc/server.go b/runtime/internal/rpc/server.go
index ecd7d00..c72439d 100644
--- a/runtime/internal/rpc/server.go
+++ b/runtime/internal/rpc/server.go
@@ -242,7 +242,7 @@
 
 var _ DeprecatedServer = (*server)(nil)
 
-func InternalNewServer(
+func DeprecatedNewServer(
 	ctx *context.T,
 	streamMgr stream.Manager,
 	ns namespace.T,
diff --git a/runtime/internal/rpc/server_test.go b/runtime/internal/rpc/server_test.go
deleted file mode 100644
index 3e8c3fc..0000000
--- a/runtime/internal/rpc/server_test.go
+++ /dev/null
@@ -1,687 +0,0 @@
-// Copyright 2015 The Vanadium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package rpc
-
-import (
-	"net"
-	"reflect"
-	"sort"
-	"testing"
-	"time"
-
-	"v.io/x/lib/netstate"
-	"v.io/x/lib/set"
-
-	"v.io/v23"
-	"v.io/v23/context"
-	"v.io/v23/naming"
-	"v.io/v23/options"
-	"v.io/v23/rpc"
-	"v.io/v23/security"
-	"v.io/v23/verror"
-
-	"v.io/x/ref/lib/pubsub"
-	inaming "v.io/x/ref/runtime/internal/naming"
-	imanager "v.io/x/ref/runtime/internal/rpc/stream/manager"
-	tnaming "v.io/x/ref/runtime/internal/testing/mocks/naming"
-	"v.io/x/ref/test/testutil"
-)
-
-type noMethodsType struct{ Field string }
-
-type fieldType struct {
-	unexported string
-}
-type noExportedFieldsType struct{}
-
-func (noExportedFieldsType) F(_ *context.T, _ rpc.ServerCall, f fieldType) error { return nil }
-
-type badObjectDispatcher struct{}
-
-func (badObjectDispatcher) Lookup(_ *context.T, suffix string) (interface{}, security.Authorizer, error) {
-	return noMethodsType{}, nil, nil
-}
-
-// TestBadObject ensures that Serve handles bad receiver objects gracefully (in
-// particular, it doesn't panic).
-func TestBadObject(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-	pclient, pserver := newClientServerPrincipals()
-	cctx, _ := v23.WithPrincipal(ctx, pclient)
-	sctx, _ := v23.WithPrincipal(ctx, pserver)
-	server, err := testInternalNewServer(sctx, sm, ns)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer server.Stop()
-
-	if _, err := server.Listen(listenSpec); err != nil {
-		t.Fatalf("Listen failed: %v", err)
-	}
-	if err := server.Serve("", nil, nil); err == nil {
-		t.Fatal("should have failed")
-	}
-	if err := server.Serve("", new(noMethodsType), nil); err == nil {
-		t.Fatal("should have failed")
-	}
-	if err := server.Serve("", new(noExportedFieldsType), nil); err == nil {
-		t.Fatal("should have failed")
-	}
-	if err := server.ServeDispatcher("servername", badObjectDispatcher{}); err != nil {
-		t.Fatalf("ServeDispatcher failed: %v", err)
-	}
-	client, err := InternalNewClient(sm, ns)
-	if err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
-	}
-	ctx, _ = context.WithDeadline(cctx, time.Now().Add(10*time.Second))
-	var result string
-	if err := client.Call(cctx, "servername", "SomeMethod", nil, []interface{}{&result}); err == nil {
-		// TODO(caprita): Check the error type rather than
-		// merely ensuring the test doesn't panic.
-		t.Fatalf("Call should have failed")
-	}
-}
-
-func TestServerArgs(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-	sctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("test"))
-	server, err := testInternalNewServer(sctx, sm, ns)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer server.Stop()
-	_, err = server.Listen(rpc.ListenSpec{})
-	if verror.ErrorID(err) != verror.ErrBadArg.ID {
-		t.Fatalf("expected a BadArg error: got %v", err)
-	}
-	_, err = server.Listen(rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "*:0"}}})
-	if verror.ErrorID(err) != verror.ErrBadArg.ID {
-		t.Fatalf("expected a BadArg error: got %v", err)
-	}
-	_, err = server.Listen(rpc.ListenSpec{
-		Addrs: rpc.ListenAddrs{
-			{"tcp", "*:0"},
-			{"tcp", "127.0.0.1:0"},
-		}})
-	if verror.ErrorID(err) == verror.ErrBadArg.ID {
-		t.Fatalf("expected a BadArg error: got %v", err)
-	}
-	status := server.Status()
-	if got, want := len(status.Errors), 1; got != want {
-		t.Fatalf("got %v, want %v", got, want)
-	}
-	_, err = server.Listen(rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "*:0"}}})
-	if verror.ErrorID(err) != verror.ErrBadArg.ID {
-		t.Fatalf("expected a BadArg error: got %v", err)
-	}
-	status = server.Status()
-	if got, want := len(status.Errors), 1; got != want {
-		t.Fatalf("got %v, want %v", got, want)
-	}
-}
-
-type statusServer struct{ ch chan struct{} }
-
-func (s *statusServer) Hang(*context.T, rpc.ServerCall) error {
-	s.ch <- struct{}{} // Notify the server has received a call.
-	<-s.ch             // Wait for the server to be ready to go.
-	return nil
-}
-
-func TestServerStatus(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-	principal := testutil.NewPrincipal("testServerStatus")
-	ctx, _ = v23.WithPrincipal(ctx, principal)
-	server, err := testInternalNewServer(ctx, sm, ns)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer server.Stop()
-
-	status := server.Status()
-	if got, want := status.State, rpc.ServerActive; got != want {
-		t.Fatalf("got %s, want %s", got, want)
-	}
-	server.Listen(rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}})
-	status = server.Status()
-	if got, want := status.State, rpc.ServerActive; got != want {
-		t.Fatalf("got %s, want %s", got, want)
-	}
-	serverChan := make(chan struct{})
-	err = server.Serve("test", &statusServer{serverChan}, nil)
-	if err != nil {
-		t.Fatalf(err.Error())
-	}
-	status = server.Status()
-	if got, want := status.State, rpc.ServerActive; got != want {
-		t.Fatalf("got %s, want %s", got, want)
-	}
-
-	progress := make(chan error)
-
-	client, err := InternalNewClient(sm, ns)
-	makeCall := func(ctx *context.T) {
-		call, err := client.StartCall(ctx, "test", "Hang", nil)
-		progress <- err
-		progress <- call.Finish()
-	}
-	go makeCall(ctx)
-
-	// Wait for RPC to start and the server has received the call.
-	if err := <-progress; err != nil {
-		t.Fatalf(err.Error())
-	}
-	<-serverChan
-
-	// Stop server asynchronously
-	go func() {
-		err = server.Stop()
-		if err != nil {
-			t.Fatalf(err.Error())
-		}
-	}()
-
-	// Server should enter 'ServerStopping' state.
-	then := time.Now()
-	for {
-		status = server.Status()
-		if got, want := status.State, rpc.ServerStopping; got != want {
-			if time.Now().Sub(then) > time.Minute {
-				t.Fatalf("got %s, want %s", got, want)
-			}
-		} else {
-			break
-		}
-		time.Sleep(100 * time.Millisecond)
-	}
-	// Server won't stop until the statusServer's hung method completes.
-	close(serverChan)
-	// Wait for RPC to finish
-	if err := <-progress; err != nil {
-		t.Fatalf(err.Error())
-	}
-
-	// Now that the RPC is done, the server should be able to stop.
-	then = time.Now()
-	for {
-		status = server.Status()
-		if got, want := status.State, rpc.ServerStopped; got != want {
-			if time.Now().Sub(then) > time.Minute {
-				t.Fatalf("got %s, want %s", got, want)
-			}
-		} else {
-			break
-		}
-		time.Sleep(100 * time.Millisecond)
-	}
-}
-
-func TestServerStates(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-	sctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("test"))
-	expectBadState := func(err error) {
-		if verror.ErrorID(err) != verror.ErrBadState.ID {
-			t.Fatalf("%s: unexpected error: %v", loc(1), err)
-		}
-	}
-
-	expectNoError := func(err error) {
-		if err != nil {
-			t.Fatalf("%s: unexpected error: %v", loc(1), err)
-		}
-	}
-
-	server, err := testInternalNewServer(sctx, sm, ns)
-	expectNoError(err)
-	defer server.Stop()
-
-	expectState := func(s rpc.ServerState) {
-		if got, want := server.Status().State, s; got != want {
-			t.Fatalf("%s: got %s, want %s", loc(1), got, want)
-		}
-	}
-
-	expectState(rpc.ServerActive)
-
-	// Need to call Listen first.
-	err = server.Serve("", &testServer{}, nil)
-	expectBadState(err)
-	err = server.AddName("a")
-	expectBadState(err)
-
-	_, err = server.Listen(rpc.ListenSpec{Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}}})
-	expectNoError(err)
-
-	expectState(rpc.ServerActive)
-
-	err = server.Serve("", &testServer{}, nil)
-	expectNoError(err)
-
-	err = server.Serve("", &testServer{}, nil)
-	expectBadState(err)
-
-	expectState(rpc.ServerActive)
-
-	err = server.AddName("a")
-	expectNoError(err)
-
-	expectState(rpc.ServerActive)
-
-	server.RemoveName("a")
-
-	expectState(rpc.ServerActive)
-
-	err = server.Stop()
-	expectNoError(err)
-	err = server.Stop()
-	expectNoError(err)
-
-	err = server.AddName("a")
-	expectBadState(err)
-}
-
-func TestMountStatus(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-	sctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("test"))
-
-	server, err := testInternalNewServer(sctx, sm, ns)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer server.Stop()
-
-	eps, err := server.Listen(rpc.ListenSpec{
-		Addrs: rpc.ListenAddrs{
-			{"tcp", "127.0.0.1:0"},
-			{"tcp", "127.0.0.1:0"},
-		}})
-	if err != nil {
-		t.Fatal(err)
-	}
-	if got, want := len(eps), 2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-	if err = server.Serve("foo", &testServer{}, nil); err != nil {
-		t.Fatal(err)
-	}
-	setLeafEndpoints(eps)
-	status := server.Status()
-	if got, want := len(status.Mounts), 2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-	servers := status.Mounts.Servers()
-	if got, want := len(servers), 2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-	if got, want := servers, endpointToStrings(eps); !reflect.DeepEqual(got, want) {
-		t.Fatalf("got %v, want %v", got, want)
-	}
-
-	// Add a second name and we should now see 4 mounts, 2 for each name.
-	if err := server.AddName("bar"); err != nil {
-		t.Fatal(err)
-	}
-	status = server.Status()
-	if got, want := len(status.Mounts), 4; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-	servers = status.Mounts.Servers()
-	if got, want := len(servers), 2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-	if got, want := servers, endpointToStrings(eps); !reflect.DeepEqual(got, want) {
-		t.Fatalf("got %v, want %v", got, want)
-	}
-	names := status.Mounts.Names()
-	if got, want := len(names), 2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-	serversPerName := map[string][]string{}
-	for _, ms := range status.Mounts {
-		serversPerName[ms.Name] = append(serversPerName[ms.Name], ms.Server)
-	}
-	if got, want := len(serversPerName), 2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-	for _, name := range []string{"foo", "bar"} {
-		if got, want := len(serversPerName[name]), 2; got != want {
-			t.Fatalf("got %d, want %d", got, want)
-		}
-	}
-}
-
-func updateHost(ep naming.Endpoint, address string) naming.Endpoint {
-	niep := *(ep).(*inaming.Endpoint)
-	niep.Address = address
-	return &niep
-}
-
-func getIPAddrs(eps []naming.Endpoint) []net.Addr {
-	hosts := map[string]struct{}{}
-	for _, ep := range eps {
-		iep := (ep).(*inaming.Endpoint)
-		h, _, _ := net.SplitHostPort(iep.Address)
-		if len(h) > 0 {
-			hosts[h] = struct{}{}
-		}
-	}
-	addrs := []net.Addr{}
-	for h, _ := range hosts {
-		addrs = append(addrs, netstate.NewNetAddr("ip", h))
-	}
-	return addrs
-}
-
-func endpointToStrings(eps []naming.Endpoint) []string {
-	r := []string{}
-	for _, ep := range eps {
-		r = append(r, ep.String())
-	}
-	sort.Strings(r)
-	return r
-}
-
-func cmpEndpoints(got, want []naming.Endpoint) bool {
-	if len(got) != len(want) {
-		return false
-	}
-	return reflect.DeepEqual(endpointToStrings(got), endpointToStrings(want))
-}
-
-func getUniqPorts(eps []naming.Endpoint) []string {
-	ports := map[string]struct{}{}
-	for _, ep := range eps {
-		iep := ep.(*inaming.Endpoint)
-		_, p, _ := net.SplitHostPort(iep.Address)
-		ports[p] = struct{}{}
-	}
-	return set.String.ToSlice(ports)
-}
-
-func TestRoaming(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-
-	publisher := pubsub.NewPublisher()
-	roaming := make(chan pubsub.Setting)
-	stop, err := publisher.CreateStream("TestRoaming", "TestRoaming", roaming)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer func() { publisher.Shutdown(); <-stop }()
-
-	nctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("test"))
-	server, err := testInternalNewServerWithPubsub(nctx, sm, ns, publisher, "TestRoaming")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer server.Stop()
-
-	ipv4And6 := netstate.AddressChooserFunc(func(network string, addrs []net.Addr) ([]net.Addr, error) {
-		accessible := netstate.ConvertToAddresses(addrs)
-		ipv4 := accessible.Filter(netstate.IsUnicastIPv4)
-		ipv6 := accessible.Filter(netstate.IsUnicastIPv6)
-		return append(ipv4.AsNetAddrs(), ipv6.AsNetAddrs()...), nil
-	})
-	spec := rpc.ListenSpec{
-		Addrs: rpc.ListenAddrs{
-			{"tcp", "*:0"},
-			{"tcp", ":0"},
-			{"tcp", ":0"},
-		},
-		AddressChooser: ipv4And6,
-	}
-
-	eps, err := server.Listen(spec)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if len(eps) == 0 {
-		t.Fatal(err)
-	}
-
-	if err = server.Serve("foo", &testServer{}, nil); err != nil {
-		t.Fatal(err)
-	}
-	setLeafEndpoints(eps)
-	if err = server.AddName("bar"); err != nil {
-		t.Fatal(err)
-	}
-
-	status := server.Status()
-	if got, want := status.Endpoints, eps; !cmpEndpoints(got, want) {
-		t.Fatalf("got %v, want %v", got, want)
-	}
-
-	if got, want := len(status.Mounts), len(eps)*2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-
-	n1 := netstate.NewNetAddr("ip", "1.1.1.1")
-	n2 := netstate.NewNetAddr("ip", "2.2.2.2")
-
-	watcher := make(chan rpc.NetworkChange, 10)
-	server.WatchNetwork(watcher)
-	defer close(watcher)
-
-	roaming <- NewAddAddrsSetting([]net.Addr{n1, n2})
-
-	waitForChange := func() *rpc.NetworkChange {
-		ctx.Infof("Waiting on %p", watcher)
-		select {
-		case c := <-watcher:
-			return &c
-		case <-time.After(time.Minute):
-			t.Fatalf("timedout: %s", loc(1))
-		}
-		return nil
-	}
-
-	// We expect 4 changes, one for each IP per usable listen spec addr.
-	change := waitForChange()
-	if got, want := len(change.Changed), 4; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-
-	nepsA := make([]naming.Endpoint, len(eps))
-	copy(nepsA, eps)
-	for _, p := range getUniqPorts(eps) {
-		nep1 := updateHost(eps[0], net.JoinHostPort("1.1.1.1", p))
-		nep2 := updateHost(eps[0], net.JoinHostPort("2.2.2.2", p))
-		nepsA = append(nepsA, []naming.Endpoint{nep1, nep2}...)
-	}
-
-	status = server.Status()
-	if got, want := status.Endpoints, nepsA; !cmpEndpoints(got, want) {
-		t.Fatalf("got %v, want %v [%d, %d]", got, want, len(got), len(want))
-	}
-
-	if got, want := len(status.Mounts), len(nepsA)*2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-	if got, want := len(status.Mounts.Servers()), len(nepsA); got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-
-	roaming <- NewRmAddrsSetting([]net.Addr{n1})
-
-	// We expect 2 changes, one for each usable listen spec addr.
-	change = waitForChange()
-	if got, want := len(change.Changed), 2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-
-	nepsR := make([]naming.Endpoint, len(eps))
-	copy(nepsR, eps)
-	for _, p := range getUniqPorts(eps) {
-		nep2 := updateHost(eps[0], net.JoinHostPort("2.2.2.2", p))
-		nepsR = append(nepsR, nep2)
-	}
-
-	status = server.Status()
-	if got, want := status.Endpoints, nepsR; !cmpEndpoints(got, want) {
-		t.Fatalf("got %v, want %v [%d, %d]", got, want, len(got), len(want))
-	}
-
-	// Remove all addresses to mimic losing all connectivity.
-	roaming <- NewRmAddrsSetting(getIPAddrs(nepsR))
-
-	// We expect changes for all of the current endpoints
-	change = waitForChange()
-	if got, want := len(change.Changed), len(nepsR); got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-
-	status = server.Status()
-	if got, want := len(status.Mounts), 0; got != want {
-		t.Fatalf("got %d, want %d: %v", got, want, status.Mounts)
-	}
-
-	roaming <- NewAddAddrsSetting([]net.Addr{n1})
-	// We expect 2 changes, one for each usable listen spec addr.
-	change = waitForChange()
-	if got, want := len(change.Changed), 2; got != want {
-		t.Fatalf("got %d, want %d", got, want)
-	}
-
-}
-
-func TestWatcherDeadlock(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-
-	publisher := pubsub.NewPublisher()
-	roaming := make(chan pubsub.Setting)
-	stop, err := publisher.CreateStream("TestWatcherDeadlock", "TestWatcherDeadlock", roaming)
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer func() { publisher.Shutdown(); <-stop }()
-
-	nctx, _ := v23.WithPrincipal(ctx, testutil.NewPrincipal("test"))
-	server, err := testInternalNewServerWithPubsub(nctx, sm, ns, publisher, "TestWatcherDeadlock")
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer server.Stop()
-
-	spec := rpc.ListenSpec{
-		Addrs: rpc.ListenAddrs{
-			{"tcp", ":0"},
-		},
-	}
-	eps, err := server.Listen(spec)
-	if err != nil {
-		t.Fatal(err)
-	}
-	if err = server.Serve("foo", &testServer{}, nil); err != nil {
-		t.Fatal(err)
-	}
-	setLeafEndpoints(eps)
-
-	// Set a watcher that we never read from - the intent is to make sure
-	// that the listener still listens to changes even though there is no
-	// goroutine to read from the watcher channel.
-	watcher := make(chan rpc.NetworkChange, 0)
-	server.WatchNetwork(watcher)
-	defer close(watcher)
-
-	// Remove all addresses to mimic losing all connectivity.
-	roaming <- NewRmAddrsSetting(getIPAddrs(eps))
-
-	// Add in two new addresses
-	n1 := netstate.NewNetAddr("ip", "1.1.1.1")
-	n2 := netstate.NewNetAddr("ip", "2.2.2.2")
-	roaming <- NewAddAddrsSetting([]net.Addr{n1, n2})
-
-	neps := make([]naming.Endpoint, 0, len(eps))
-	for _, p := range getUniqPorts(eps) {
-		nep1 := updateHost(eps[0], net.JoinHostPort("1.1.1.1", p))
-		nep2 := updateHost(eps[0], net.JoinHostPort("2.2.2.2", p))
-		neps = append(neps, []naming.Endpoint{nep1, nep2}...)
-	}
-	then := time.Now()
-	for {
-		status := server.Status()
-		if got, want := status.Endpoints, neps; cmpEndpoints(got, want) {
-			break
-		}
-		time.Sleep(100 * time.Millisecond)
-		if time.Now().Sub(then) > time.Minute {
-			t.Fatalf("timed out waiting for changes to take effect")
-		}
-	}
-}
-
-func TestIsLeafServerOption(t *testing.T) {
-	ctx, shutdown := initForTest()
-	defer shutdown()
-	sm := imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-	defer sm.Shutdown()
-	ns := tnaming.NewSimpleNamespace()
-	pclient, pserver := newClientServerPrincipals()
-	cctx, _ := v23.WithPrincipal(ctx, pclient)
-	sctx, _ := v23.WithPrincipal(ctx, pserver)
-	server, err := testInternalNewServer(sctx, sm, ns, options.IsLeaf(true))
-	if err != nil {
-		t.Fatal(err)
-	}
-	defer server.Stop()
-
-	disp := &testServerDisp{&testServer{}}
-
-	if _, err := server.Listen(listenSpec); err != nil {
-		t.Fatalf("Listen failed: %v", err)
-	}
-
-	if err := server.ServeDispatcher("leafserver", disp); err != nil {
-		t.Fatalf("ServeDispatcher failed: %v", err)
-	}
-	client, err := InternalNewClient(sm, ns)
-	if err != nil {
-		t.Fatalf("InternalNewClient failed: %v", err)
-	}
-	cctx, _ = context.WithDeadline(cctx, time.Now().Add(10*time.Second))
-	var result string
-	// we have set IsLeaf to true, sending any suffix to leafserver should result
-	// in an suffix was not expected error.
-	callErr := client.Call(cctx, "leafserver/unwantedSuffix", "Echo", []interface{}{"Mirror on the wall"}, []interface{}{&result})
-	if callErr == nil {
-		t.Fatalf("Call should have failed with suffix was not expected error")
-	}
-}
-
-func setLeafEndpoints(eps []naming.Endpoint) {
-	for i := range eps {
-		eps[i].(*inaming.Endpoint).IsLeaf = true
-	}
-}
diff --git a/runtime/internal/rpc/test/cancel_test.go b/runtime/internal/rpc/test/cancel_test.go
new file mode 100644
index 0000000..b363a33
--- /dev/null
+++ b/runtime/internal/rpc/test/cancel_test.go
@@ -0,0 +1,178 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package test
+
+import (
+	"io"
+	"testing"
+
+	"v.io/v23"
+	"v.io/v23/context"
+	"v.io/v23/rpc"
+	"v.io/v23/security"
+	"v.io/v23/verror"
+	"v.io/x/ref/runtime/internal/rpc/stream/vc"
+	"v.io/x/ref/test"
+)
+
+type canceld struct {
+	name     string
+	child    string
+	started  chan struct{}
+	canceled chan struct{}
+}
+
+func (c *canceld) Run(ctx *context.T, _ rpc.ServerCall) error {
+	close(c.started)
+	client := v23.GetClient(ctx)
+	ctx.Infof("Run: %s", c.child)
+	if c.child != "" {
+		if _, err := client.StartCall(ctx, c.child, "Run", []interface{}{}); err != nil {
+			ctx.Error(err)
+			return err
+		}
+	}
+	<-ctx.Done()
+	close(c.canceled)
+	return nil
+}
+
+func makeCanceld(ctx *context.T, name, child string) (*canceld, error) {
+	c := &canceld{
+		name:     name,
+		child:    child,
+		started:  make(chan struct{}, 0),
+		canceled: make(chan struct{}, 0),
+	}
+	_, _, err := v23.WithNewServer(ctx, name, c, security.AllowEveryone())
+	if err != nil {
+		return nil, err
+	}
+	ctx.Infof("Serving: %q", name)
+	return c, nil
+}
+
+// TestCancellationPropagation tests that cancellation propogates along an
+// RPC call chain without user intervention.
+func TestCancellationPropagation(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	c1, err := makeCanceld(ctx, "c1", "c2")
+	if err != nil {
+		t.Fatalf("Can't start server:", err, verror.DebugString(err))
+	}
+	c2, err := makeCanceld(ctx, "c2", "")
+	if err != nil {
+		t.Fatalf("Can't start server:", err)
+	}
+
+	ctx, cancel := context.WithCancel(ctx)
+	_, err = v23.GetClient(ctx).StartCall(ctx, "c1", "Run", []interface{}{})
+	if err != nil {
+		t.Fatalf("can't call: ", err)
+	}
+
+	<-c1.started
+	<-c2.started
+
+	ctx.Info("cancelling initial call")
+	cancel()
+
+	ctx.Info("waiting for children to be canceled")
+	<-c1.canceled
+	<-c2.canceled
+}
+
+type cancelTestServer struct {
+	started   chan struct{}
+	cancelled chan struct{}
+	t         *testing.T
+}
+
+func newCancelTestServer(t *testing.T) *cancelTestServer {
+	return &cancelTestServer{
+		started:   make(chan struct{}),
+		cancelled: make(chan struct{}),
+		t:         t,
+	}
+}
+
+func (s *cancelTestServer) CancelStreamReader(ctx *context.T, call rpc.StreamServerCall) error {
+	close(s.started)
+	var b []byte
+	if err := call.Recv(&b); err != io.EOF {
+		s.t.Errorf("Got error %v, want io.EOF", err)
+	}
+	<-ctx.Done()
+	close(s.cancelled)
+	return nil
+}
+
+// CancelStreamIgnorer doesn't read from it's input stream so all it's
+// buffers fill.  The intention is to show that call.Done() is closed
+// even when the stream is stalled.
+func (s *cancelTestServer) CancelStreamIgnorer(ctx *context.T, _ rpc.StreamServerCall) error {
+	close(s.started)
+	<-ctx.Done()
+	close(s.cancelled)
+	return nil
+}
+
+func waitForCancel(t *testing.T, ts *cancelTestServer, cancel context.CancelFunc) {
+	<-ts.started
+	cancel()
+	<-ts.cancelled
+}
+
+// TestCancel tests cancellation while the server is reading from a stream.
+func TestCancel(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	var (
+		sctx = withPrincipal(t, ctx, "server")
+		cctx = withPrincipal(t, ctx, "client")
+		ts   = newCancelTestServer(t)
+	)
+	_, _, err := v23.WithNewServer(sctx, "cancel", ts, security.AllowEveryone())
+	if err != nil {
+		t.Fatal(err)
+	}
+	cctx, cancel := context.WithCancel(cctx)
+	_, err = v23.GetClient(cctx).StartCall(cctx, "cancel", "CancelStreamReader", []interface{}{})
+	if err != nil {
+		t.Fatalf("Start call failed: %v", err)
+	}
+	waitForCancel(t, ts, cancel)
+}
+
+// TestCancelWithFullBuffers tests that even if the writer has filled the buffers and
+// the server is not reading that the cancel message gets through.
+func TestCancelWithFullBuffers(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	var (
+		sctx = withPrincipal(t, ctx, "server")
+		cctx = withPrincipal(t, ctx, "client")
+		ts   = newCancelTestServer(t)
+	)
+	_, _, err := v23.WithNewServer(sctx, "cancel", ts, security.AllowEveryone())
+	if err != nil {
+		t.Fatal(err)
+	}
+	cctx, cancel := context.WithCancel(cctx)
+	call, err := v23.GetClient(cctx).StartCall(cctx, "cancel", "CancelStreamIgnorer", []interface{}{})
+	if err != nil {
+		t.Fatalf("Start call failed: %v", err)
+	}
+
+	// Fill up all the write buffers to ensure that cancelling works even when the stream
+	// is blocked.
+	// TODO(mattr): Update for new RPC system.
+	call.Send(make([]byte, vc.MaxSharedBytes))
+	call.Send(make([]byte, vc.DefaultBytesBufferedPerFlow))
+
+	waitForCancel(t, ts, cancel)
+}
diff --git a/runtime/internal/rpc/test/debug_test.go b/runtime/internal/rpc/test/debug_test.go
new file mode 100644
index 0000000..f5a4155
--- /dev/null
+++ b/runtime/internal/rpc/test/debug_test.go
@@ -0,0 +1,115 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package test
+
+import (
+	"io"
+	"reflect"
+	"sort"
+	"testing"
+
+	"v.io/v23"
+	"v.io/v23/context"
+	"v.io/v23/naming"
+	"v.io/v23/rpc"
+	"v.io/x/ref/lib/stats"
+	irpc "v.io/x/ref/runtime/internal/rpc"
+	"v.io/x/ref/services/debug/debuglib"
+	"v.io/x/ref/test"
+	"v.io/x/ref/test/testutil"
+)
+
+func TestDebugServer(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	// Setup the client and server principals, with the client willing to share its
+	// blessing with the server.
+	var (
+		pclient = testutil.NewPrincipal()
+		cctx, _ = v23.WithPrincipal(ctx, pclient)
+	)
+	idp := testutil.IDProviderFromPrincipal(v23.GetPrincipal(ctx))
+	if err := idp.Bless(pclient, "client"); err != nil {
+		t.Fatal(err)
+	}
+	name := "testserver"
+	debugDisp := debuglib.NewDispatcher(nil)
+	_, _, err := v23.WithNewServer(ctx, name, &testObject{}, nil,
+		irpc.ReservedNameDispatcher{debugDisp})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Call the Foo method on ""
+	{
+		var value string
+		if err := v23.GetClient(cctx).Call(cctx, name, "Foo", nil, []interface{}{&value}); err != nil {
+			t.Fatalf("client.Call failed: %v", err)
+		}
+		if want := "BAR"; value != want {
+			t.Errorf("unexpected value: Got %v, want %v", value, want)
+		}
+	}
+	// Call Value on __debug/stats/testing/foo
+	{
+		foo := stats.NewString("testing/foo")
+		foo.Set("The quick brown fox jumps over the lazy dog")
+		fullname := naming.Join(name, "__debug/stats/testing/foo")
+		var value string
+		if err := v23.GetClient(cctx).Call(cctx, fullname, "Value", nil, []interface{}{&value}); err != nil {
+			t.Fatalf("client.Call failed: %v", err)
+		}
+		if want := foo.Value(); value != want {
+			t.Errorf("unexpected result: Got %v, want %v", value, want)
+		}
+	}
+
+	// Call Glob
+	testcases := []struct {
+		name, pattern string
+		expected      []string
+	}{
+		{"", "*", []string{}},
+		{"", "__*", []string{"__debug"}},
+		{"", "__*/*", []string{"__debug/logs", "__debug/pprof", "__debug/stats", "__debug/vtrace"}},
+		{"__debug", "*", []string{"logs", "pprof", "stats", "vtrace"}},
+	}
+	for _, tc := range testcases {
+		fullname := naming.Join(name, tc.name)
+		call, err := v23.GetClient(ctx).StartCall(cctx, fullname, rpc.GlobMethod, []interface{}{tc.pattern})
+		if err != nil {
+			t.Fatalf("client.StartCall failed for %q: %v", tc.name, err)
+		}
+		results := []string{}
+		for {
+			var gr naming.GlobReply
+			if err := call.Recv(&gr); err != nil {
+				if err != io.EOF {
+					t.Fatalf("Recv failed for %q: %v. Results received thus far: %q", tc.name, err, results)
+				}
+				break
+			}
+			switch v := gr.(type) {
+			case naming.GlobReplyEntry:
+				results = append(results, v.Value.Name)
+			}
+		}
+		if err := call.Finish(); err != nil {
+			t.Fatalf("call.Finish failed for %q: %v", tc.name, err)
+		}
+		sort.Strings(results)
+		if !reflect.DeepEqual(tc.expected, results) {
+			t.Errorf("unexpected results for %q. Got %v, want %v", tc.name, results, tc.expected)
+		}
+	}
+}
+
+type testObject struct {
+}
+
+func (o testObject) Foo(*context.T, rpc.ServerCall) (string, error) {
+	return "BAR", nil
+}
diff --git a/runtime/internal/rpc/test/full_test.go b/runtime/internal/rpc/test/full_test.go
new file mode 100644
index 0000000..7b5fe8c
--- /dev/null
+++ b/runtime/internal/rpc/test/full_test.go
@@ -0,0 +1,884 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package test
+
+import (
+	"encoding/hex"
+	"errors"
+	"fmt"
+	"io"
+	"net"
+	"reflect"
+	"testing"
+	"time"
+
+	"v.io/v23"
+	"v.io/v23/context"
+	"v.io/v23/i18n"
+	"v.io/v23/naming"
+	"v.io/v23/options"
+	"v.io/v23/rpc"
+	"v.io/v23/security"
+	"v.io/v23/vdl"
+	"v.io/v23/verror"
+	"v.io/v23/vtrace"
+	"v.io/x/lib/netstate"
+	vsecurity "v.io/x/ref/lib/security"
+	inaming "v.io/x/ref/runtime/internal/naming"
+	"v.io/x/ref/test"
+	"v.io/x/ref/test/testutil"
+)
+
+func TestAddRemoveName(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	_, s, err := v23.WithNewServer(ctx, "one", &testServer{}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	waitForNames(t, ctx, true, "one")
+	s.AddName("two")
+	s.AddName("three")
+	waitForNames(t, ctx, true, "one", "two", "three")
+	s.RemoveName("one")
+	waitForNames(t, ctx, false, "one")
+	s.RemoveName("two")
+	s.RemoveName("three")
+	waitForNames(t, ctx, false, "one", "two", "three")
+}
+
+func TestCallWithNilContext(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	call, err := v23.GetClient(ctx).StartCall(nil, "foo", "bar", []interface{}{}, options.SecurityNone)
+	if call != nil {
+		t.Errorf("Expected nil interface got: %#v", call)
+	}
+	if verror.ErrorID(err) != verror.ErrBadArg.ID {
+		t.Errorf("Expected a BadArg error, got: %s", err.Error())
+	}
+}
+
+func TestRPC(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}},
+	})
+	testRPC(t, ctx, true)
+}
+
+func TestRPCWithWebsocket(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{{"ws", "127.0.0.1:0"}},
+	})
+	testRPC(t, ctx, true)
+}
+
+// TestCloseSendOnFinish tests that Finish informs the server that no more
+// inputs will be sent by the client if CloseSend has not already done so.
+func TestRPCCloseSendOnFinish(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}},
+	})
+	testRPC(t, ctx, false)
+}
+
+func TestRPCCloseSendOnFinishWithWebsocket(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	ctx = v23.WithListenSpec(ctx, rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{{"ws", "127.0.0.1:0"}},
+	})
+	testRPC(t, ctx, false)
+}
+
+func testRPC(t *testing.T, ctx *context.T, shouldCloseSend bool) {
+	ctx = i18n.WithLangID(ctx, "foolang")
+	type v []interface{}
+	type testcase struct {
+		name       string
+		method     string
+		args       v
+		streamArgs v
+		startErr   error
+		results    v
+		finishErr  error
+	}
+	var (
+		tests = []testcase{
+			{"mountpoint/server/suffix", "Closure", nil, nil, nil, nil, nil},
+			{"mountpoint/server/suffix", "Error", nil, nil, nil, nil, errMethod},
+
+			{"mountpoint/server/suffix", "Echo", v{"foo"}, nil, nil, v{`method:"Echo",suffix:"suffix",arg:"foo"`}, nil},
+			{"mountpoint/server/suffix/abc", "Echo", v{"bar"}, nil, nil, v{`method:"Echo",suffix:"suffix/abc",arg:"bar"`}, nil},
+
+			{"mountpoint/server/suffix", "EchoUser", v{"foo", userType("bar")}, nil, nil, v{`method:"EchoUser",suffix:"suffix",arg:"foo"`, userType("bar")}, nil},
+			{"mountpoint/server/suffix/abc", "EchoUser", v{"baz", userType("bla")}, nil, nil, v{`method:"EchoUser",suffix:"suffix/abc",arg:"baz"`, userType("bla")}, nil},
+			{"mountpoint/server/suffix", "Stream", v{"foo"}, v{userType("bar"), userType("baz")}, nil, v{`method:"Stream",suffix:"suffix",arg:"foo" bar baz`}, nil},
+			{"mountpoint/server/suffix/abc", "Stream", v{"123"}, v{userType("456"), userType("789")}, nil, v{`method:"Stream",suffix:"suffix/abc",arg:"123" 456 789`}, nil},
+			{"mountpoint/server/suffix", "EchoBlessings", nil, nil, nil, v{"[test-blessing/server]", "[test-blessing/client]"}, nil},
+			{"mountpoint/server/suffix", "EchoAndError", v{"bugs bunny"}, nil, nil, v{`method:"EchoAndError",suffix:"suffix",arg:"bugs bunny"`}, nil},
+			{"mountpoint/server/suffix", "EchoAndError", v{"error"}, nil, nil, nil, errMethod},
+			{"mountpoint/server/suffix", "EchoLang", nil, nil, nil, v{"foolang"}, nil},
+		}
+		name = func(t testcase) string {
+			return fmt.Sprintf("%s.%s(%v)", t.name, t.method, t.args)
+		}
+		cctx = withPrincipal(t, ctx, "client")
+		sctx = withPrincipal(t, ctx, "server")
+	)
+	_, _, err := v23.WithNewDispatchingServer(sctx, "mountpoint/server", &testServerDisp{&testServer{}})
+	if err != nil {
+		t.Fatal(err)
+	}
+	client := v23.GetClient(cctx)
+	for _, test := range tests {
+		cctx.VI(1).Infof("%s client.StartCall", name(test))
+		call, err := client.StartCall(cctx, test.name, test.method, test.args)
+		if err != test.startErr {
+			t.Errorf(`%s client.StartCall got error "%v", want "%v"`,
+				name(test), err, test.startErr)
+			continue
+		}
+		for _, sarg := range test.streamArgs {
+			cctx.VI(1).Infof("%s client.Send(%v)", name(test), sarg)
+			if err := call.Send(sarg); err != nil {
+				t.Errorf(`%s call.Send(%v) got unexpected error "%v"`, name(test), sarg, err)
+			}
+			var u userType
+			if err := call.Recv(&u); err != nil {
+				t.Errorf(`%s call.Recv(%v) got unexpected error "%v"`, name(test), sarg, err)
+			}
+			if !reflect.DeepEqual(u, sarg) {
+				t.Errorf("%s call.Recv got value %v, want %v", name(test), u, sarg)
+			}
+		}
+		if shouldCloseSend {
+			cctx.VI(1).Infof("%s call.CloseSend", name(test))
+			// When the method does not involve streaming
+			// arguments, the server gets all the arguments in
+			// StartCall and then sends a response without
+			// (unnecessarily) waiting for a CloseSend message from
+			// the client.  If the server responds before the
+			// CloseSend call is made at the client, the CloseSend
+			// call will fail.  Thus, only check for errors on
+			// CloseSend if there are streaming arguments to begin
+			// with (i.e., only if the server is expected to wait
+			// for the CloseSend notification).
+			if err := call.CloseSend(); err != nil && len(test.streamArgs) > 0 {
+				t.Errorf(`%s call.CloseSend got unexpected error "%v"`, name(test), err)
+			}
+		}
+		cctx.VI(1).Infof("%s client.Finish", name(test))
+		results := makeResultPtrs(test.results)
+		err = call.Finish(results...)
+		if got, want := err, test.finishErr; (got == nil) != (want == nil) {
+			t.Errorf(`%s call.Finish got error "%v", want "%v'`, name(test), got, want)
+		} else if want != nil && verror.ErrorID(got) != verror.ErrorID(want) {
+			t.Errorf(`%s call.Finish got error "%v", want "%v"`, name(test), got, want)
+		}
+		checkResultPtrs(t, name(test), results, test.results)
+
+		// Calling Finish a second time should result in a useful error.
+		err = call.Finish(results...)
+		if !matchesErrorPattern(err, verror.ErrBadState, "FinishAlreadyCalled") {
+			t.Fatalf(`got "%v", want "%v"`, err, verror.ErrBadState)
+		}
+	}
+}
+
+func TestStreamReadTerminatedByServer(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	cctx := withPrincipal(t, ctx, "client")
+	sctx := withPrincipal(t, ctx, "server")
+
+	s := &streamRecvInGoroutineServer{c: make(chan error, 1)}
+	_, _, err := v23.WithNewDispatchingServer(sctx, "mountpoint/server", testServerDisp{s})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	call, err := v23.GetClient(cctx).StartCall(cctx, "mountpoint/server/suffix", "RecvInGoroutine", []interface{}{})
+	if err != nil {
+		t.Fatalf("StartCall failed: %v", err)
+	}
+
+	c := make(chan error, 1)
+	go func() {
+		for i := 0; true; i++ {
+			if err := call.Send(i); err != nil {
+				c <- err
+				return
+			}
+		}
+	}()
+
+	// The goroutine at the server executing "Recv" should have terminated
+	// with EOF.
+	if err := <-s.c; err != io.EOF {
+		t.Errorf("Got %v at server, want io.EOF", err)
+	}
+	// The client Send should have failed since the RPC has been
+	// terminated.
+	if err := <-c; err == nil {
+		t.Errorf("Client Send should fail as the server should have closed the flow")
+	}
+}
+
+func TestPreferredAddress(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	sctx := withPrincipal(t, ctx, "server")
+	pa := netstate.AddressChooserFunc(func(string, []net.Addr) ([]net.Addr, error) {
+		return []net.Addr{netstate.NewNetAddr("tcp", "1.1.1.1")}, nil
+	})
+	sctx = v23.WithListenSpec(sctx, rpc.ListenSpec{
+		Addrs:          rpc.ListenAddrs{{"tcp", ":0"}},
+		AddressChooser: pa,
+	})
+	_, server, err := v23.WithNewServer(sctx, "", &testServer{}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	iep := server.Status().Endpoints[0].(*inaming.Endpoint)
+	host, _, err := net.SplitHostPort(iep.Address)
+	if err != nil {
+		t.Errorf("unexpected error: %s", err)
+	}
+	if got, want := host, "1.1.1.1"; got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+}
+
+func TestPreferredAddressErrors(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	sctx := withPrincipal(t, ctx, "server")
+	paerr := netstate.AddressChooserFunc(func(_ string, a []net.Addr) ([]net.Addr, error) {
+		return nil, fmt.Errorf("oops")
+	})
+	sctx = v23.WithListenSpec(sctx, rpc.ListenSpec{
+		Addrs:          rpc.ListenAddrs{{"tcp", ":0"}},
+		AddressChooser: paerr,
+	})
+	_, server, err := v23.WithNewServer(sctx, "", &testServer{}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	status := server.Status()
+	if got, want := len(status.Endpoints), 0; got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+	if got, want := len(status.Errors), 1; got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+	if got, want := status.Errors[0].Error(), "oops"; got != want {
+		t.Errorf("got %q, want %q", got, want)
+	}
+}
+
+func TestGranter(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	cctx := withPrincipal(t, ctx, "client")
+	sctx := withPrincipal(t, ctx, "server")
+	_, _, err := v23.WithNewDispatchingServer(sctx, "mountpoint/server", &testServerDisp{&testServer{}})
+	if err != nil {
+		t.Fatal(err)
+	}
+	tests := []struct {
+		granter                       rpc.Granter
+		startErrID, finishErrID       verror.IDAction
+		blessing, starterr, finisherr string
+	}{
+		{blessing: ""},
+		{granter: granter{}, blessing: "test-blessing/client/blessed"},
+		{
+			granter:  granter{b: bless(t, cctx, sctx, "blessed")},
+			blessing: "test-blessing/client/blessed",
+		},
+		{
+			granter:    granter{err: errors.New("hell no")},
+			startErrID: verror.ErrNotTrusted,
+			starterr:   "hell no",
+		},
+		{
+			granter:     granter{b: v23.GetPrincipal(cctx).BlessingStore().Default()},
+			finishErrID: verror.ErrNoAccess,
+			finisherr:   "blessing granted not bound to this server",
+		},
+	}
+	for i, test := range tests {
+		call, err := v23.GetClient(cctx).StartCall(cctx,
+			"mountpoint/server/suffix",
+			"EchoGrantedBlessings",
+			[]interface{}{"argument"},
+			test.granter)
+		if !matchesErrorPattern(err, test.startErrID, test.starterr) {
+			t.Errorf("%d: %+v: StartCall returned error %v", i, test, err)
+		}
+		if err != nil {
+			continue
+		}
+		var result, blessing string
+		if err = call.Finish(&result, &blessing); !matchesErrorPattern(err, test.finishErrID, test.finisherr) {
+			t.Errorf("%+v: Finish returned error %v", test, err)
+		}
+		if err != nil {
+			continue
+		}
+		if result != "argument" || blessing != test.blessing {
+			t.Errorf("%+v: Got (%q, %q)", test, result, blessing)
+		}
+	}
+}
+
+func TestRPCClientAuthorization(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	type v []interface{}
+	var (
+		cctx                = withPrincipal(t, ctx, "client")
+		sctx                = withPrincipal(t, ctx, "server")
+		now                 = time.Now()
+		serverName          = "mountpoint/server"
+		dischargeServerName = "mountpoint/dischargeserver"
+
+		// Caveats on blessings to the client: First-party caveats
+		cavOnlyEcho = mkCaveat(security.NewMethodCaveat("Echo"))
+		cavExpired  = mkCaveat(security.NewExpiryCaveat(now.Add(-1 * time.Second)))
+		// Caveats on blessings to the client: Third-party caveats
+		cavTPValid = mkThirdPartyCaveat(
+			v23.GetPrincipal(ctx).PublicKey(),
+			dischargeServerName,
+			mkCaveat(security.NewExpiryCaveat(now.Add(24*time.Hour))))
+		cavTPExpired = mkThirdPartyCaveat(v23.GetPrincipal(ctx).PublicKey(),
+			dischargeServerName,
+			mkCaveat(security.NewExpiryCaveat(now.Add(-1*time.Second))))
+
+		// Client blessings that will be tested.
+		bServerClientOnlyEcho  = bless(t, sctx, cctx, "onlyecho", cavOnlyEcho)
+		bServerClientExpired   = bless(t, sctx, cctx, "expired", cavExpired)
+		bServerClientTPValid   = bless(t, sctx, cctx, "dischargeable_third_party_caveat", cavTPValid)
+		bServerClientTPExpired = bless(t, sctx, cctx, "expired_third_party_caveat", cavTPExpired)
+		bClient                = v23.GetPrincipal(cctx).BlessingStore().Default()
+		bRandom, _             = v23.GetPrincipal(cctx).BlessSelf("random")
+
+		tests = []struct {
+			blessings  security.Blessings // Blessings used by the client
+			name       string             // object name on which the method is invoked
+			method     string
+			args       v
+			results    v
+			authorized bool // Whether or not the RPC should be authorized by the server.
+		}{
+			// There are three different authorization policies
+			// (security.Authorizer implementations) used by the server,
+			// depending on the suffix (see testServerDisp.Lookup):
+			//
+			// - nilAuth suffix: the default authorization policy (only
+			// delegates of or delegators of the server can call RPCs)
+			//
+			// - aclAuth suffix: the AccessList only allows blessings
+			// matching the patterns "server" or "client"
+			//
+			// - other suffixes: testServerAuthorizer allows any principal
+			// to call any method except "Unauthorized"
+			//
+			// Expired blessings should fail nilAuth and aclAuth (which care
+			// about names), but should succeed on other suffixes (which
+			// allow all blessings), unless calling the Unauthorized method.
+			{bServerClientExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
+			{bServerClientExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
+			{bServerClientExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
+			{bServerClientExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
+
+			// Same for blessings that should fail to obtain a discharge for
+			// the third party caveat.
+			{bServerClientTPExpired, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
+			{bServerClientTPExpired, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
+			{bServerClientTPExpired, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
+			{bServerClientTPExpired, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
+
+			// The "server/client" blessing (with MethodCaveat("Echo"))
+			// should satisfy all authorization policies when "Echo" is
+			// called.
+			{bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
+			{bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
+			{bServerClientOnlyEcho, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
+
+			// The "server/client" blessing (with MethodCaveat("Echo"))
+			// should satisfy no authorization policy when any other method
+			// is invoked, except for the testServerAuthorizer policy (which
+			// will not recognize the blessing "server/onlyecho", but it
+			// would authorize anyone anyway).
+			{bServerClientOnlyEcho, "mountpoint/server/nilAuth", "Closure", nil, nil, false},
+			{bServerClientOnlyEcho, "mountpoint/server/aclAuth", "Closure", nil, nil, false},
+			{bServerClientOnlyEcho, "mountpoint/server/suffix", "Closure", nil, nil, true},
+
+			// The "client" blessing doesn't satisfy the default
+			// authorization policy, but does satisfy the AccessList and the
+			// testServerAuthorizer policy.
+			{bClient, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
+			{bClient, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
+			{bClient, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
+			{bClient, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
+
+			// The "random" blessing does not satisfy either the default
+			// policy or the AccessList, but does satisfy
+			// testServerAuthorizer.
+			{bRandom, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, false},
+			{bRandom, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, false},
+			{bRandom, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
+			{bRandom, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
+
+			// The "server/dischargeable_third_party_caveat" blessing satisfies all policies.
+			// (the discharges should be fetched).
+			{bServerClientTPValid, "mountpoint/server/nilAuth", "Echo", v{"foo"}, v{""}, true},
+			{bServerClientTPValid, "mountpoint/server/aclAuth", "Echo", v{"foo"}, v{""}, true},
+			{bServerClientTPValid, "mountpoint/server/suffix", "Echo", v{"foo"}, v{""}, true},
+			{bServerClientTPValid, "mountpoint/server/suffix", "Unauthorized", nil, v{""}, false},
+		}
+	)
+	// Start the discharge server.
+	_, _, err := v23.WithNewServer(ctx, dischargeServerName, &dischargeServer{}, security.AllowEveryone())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Start the main server.
+	_, _, err = v23.WithNewDispatchingServer(sctx, serverName, testServerDisp{&testServer{}})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// The server should recognize the client principal as an authority
+	// on "random" blessings.
+	v23.GetPrincipal(sctx).AddToRoots(bRandom)
+
+	// Set a blessing on the client's blessing store to be presented to
+	// the discharge server.
+	v23.GetPrincipal(cctx).BlessingStore().Set(
+		v23.GetPrincipal(cctx).BlessingStore().Default(), "test-blessing/$")
+
+	// testutil.NewPrincipal sets up a principal that shares blessings
+	// with all servers, undo that.
+	v23.GetPrincipal(cctx).BlessingStore().Set(
+		security.Blessings{}, security.AllPrincipals)
+
+	for i, test := range tests {
+		name := fmt.Sprintf("#%d: %q.%s(%v) by %v", i, test.name, test.method, test.args, test.blessings)
+		client := v23.GetClient(cctx)
+
+		v23.GetPrincipal(cctx).BlessingStore().Set(test.blessings, "test-blessing/server")
+		err = client.Call(cctx, test.name, test.method, test.args, makeResultPtrs(test.results))
+		if err != nil && test.authorized {
+			t.Errorf(`%s client.Call got error: "%v", wanted the RPC to succeed`, name, err)
+		} else if err == nil && !test.authorized {
+			t.Errorf("%s call.Finish succeeded, expected authorization failure", name)
+		} else if !test.authorized && verror.ErrorID(err) != verror.ErrNoAccess.ID {
+			t.Errorf("%s. call.Finish returned error %v(%v), wanted %v", name, verror.ErrorID(verror.Convert(verror.ErrNoAccess, nil, err)), err, verror.ErrNoAccess)
+		}
+	}
+}
+
+func TestRPCServerAuthorization(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	const (
+		publicKeyErr        = "not matched by server key"
+		missingDischargeErr = "missing discharge"
+		expiryErr           = "is after expiry"
+		allowedErr          = "do not match any allowed server patterns"
+	)
+	type O []rpc.CallOpt // shorthand
+	var (
+		sctx    = withPrincipal(t, ctx, "server")
+		now     = time.Now()
+		noErrID verror.IDAction
+
+		// Third-party caveats on blessings presented by server.
+		cavTPValid = mkThirdPartyCaveat(
+			v23.GetPrincipal(ctx).PublicKey(),
+			"mountpoint/dischargeserver",
+			mkCaveat(security.NewExpiryCaveat(now.Add(24*time.Hour))))
+
+		cavTPExpired = mkThirdPartyCaveat(
+			v23.GetPrincipal(ctx).PublicKey(),
+			"mountpoint/dischargeserver",
+			mkCaveat(security.NewExpiryCaveat(now.Add(-1*time.Second))))
+
+		// Server blessings.
+		bServer          = bless(t, ctx, sctx, "server")
+		bServerExpired   = bless(t, ctx, sctx, "expiredserver", mkCaveat(security.NewExpiryCaveat(time.Now().Add(-1*time.Second))))
+		bServerTPValid   = bless(t, ctx, sctx, "serverWithTPCaveats", cavTPValid)
+		bServerTPExpired = bless(t, ctx, sctx, "serverWithExpiredTPCaveats", cavTPExpired)
+		bOther           = bless(t, ctx, sctx, "other")
+		bTwoBlessings, _ = security.UnionOfBlessings(bServer, bOther)
+
+		tests = []struct {
+			server security.Blessings // blessings presented by the server to the client.
+			name   string             // name provided by the client to StartCall
+			opts   O                  // options provided to StartCall.
+			errID  verror.IDAction
+			err    string
+		}{
+			// Client accepts talking to the server only if the
+			// server presents valid blessings (and discharges)
+			// consistent with the ones published in the endpoint.
+			{bServer, "mountpoint/server", nil, noErrID, ""},
+			{bServerTPValid, "mountpoint/server", nil, noErrID, ""},
+
+			// Client will not talk to a server that presents
+			// expired blessings or is missing discharges.
+			{bServerExpired, "mountpoint/server", nil, verror.ErrNotTrusted, expiryErr},
+			{bServerTPExpired, "mountpoint/server", nil, verror.ErrNotTrusted, missingDischargeErr},
+
+			// Testing the AllowedServersPolicy option.
+			{bServer, "mountpoint/server", O{options.AllowedServersPolicy{"otherroot"}}, verror.ErrNotTrusted, allowedErr},
+			{bServer, "mountpoint/server", O{options.AllowedServersPolicy{"test-blessing"}}, noErrID, ""},
+			{bTwoBlessings, "mountpoint/server", O{options.AllowedServersPolicy{"test-blessing/other"}}, noErrID, ""},
+
+			// Test the ServerPublicKey option.
+			{bOther, "mountpoint/server", O{options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{
+				PublicKey: bOther.PublicKey(),
+			}}, noErrID, ""},
+			{bOther, "mountpoint/server", O{options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{
+				PublicKey: testutil.NewPrincipal("irrelevant").PublicKey(),
+			}}, verror.ErrNotTrusted, publicKeyErr},
+
+			// Test the "paranoid" names, where the pattern is provided in the name.
+			{bServer, "__(test-blessing/server)/mountpoint/server", nil, noErrID, ""},
+			{bServer, "__(test-blessing/other)/mountpoint/server", nil, verror.ErrNotTrusted, allowedErr},
+			{bTwoBlessings, "__(test-blessing/server)/mountpoint/server", O{options.AllowedServersPolicy{"test-blessing/other"}}, noErrID, ""},
+		}
+	)
+	// Start the discharge server.
+	_, _, err := v23.WithNewServer(ctx, "mountpoint/dischargeserver", &dischargeServer{}, security.AllowEveryone())
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	for i, test := range tests {
+		scctx, cancel := context.WithCancel(sctx)
+		name := fmt.Sprintf("(#%d: Name:%q, Server:%q, opts:%v)",
+			i, test.name, test.server, test.opts)
+		if err := vsecurity.SetDefaultBlessings(v23.GetPrincipal(sctx), test.server); err != nil {
+			t.Fatal(err)
+		}
+		_, s, err := v23.WithNewDispatchingServer(scctx, "mountpoint/server", &testServerDisp{&testServer{}})
+		if err != nil {
+			t.Fatal(err, v23.GetPrincipal(scctx).BlessingStore().Default())
+		}
+		call, err := v23.GetClient(ctx).StartCall(ctx, test.name, "Method", nil, test.opts...)
+		if !matchesErrorPattern(err, test.errID, test.err) {
+			t.Errorf(`%s: client.StartCall: got error "%v", want to match "%v"`,
+				name, err, test.err)
+		} else if call != nil {
+			blessings, proof := call.RemoteBlessings()
+			if proof.IsZero() {
+				t.Errorf("%s: Returned zero value for remote blessings", name)
+			}
+			// Currently all tests are configured so that the only
+			// blessings presented by the server that are
+			// recognized by the client match the pattern
+			// "test-blessing"
+			if len(blessings) < 1 || !security.BlessingPattern("test-blessing").MatchedBy(blessings...) {
+				t.Errorf("%s: Client sees server as %v, expected a single blessing matching test-blessing", name, blessings)
+			}
+		}
+		s.Stop()
+		cancel()
+	}
+}
+
+func TestServerManInTheMiddleAttack(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	// Test scenario: A server mounts itself, but then some other service
+	// somehow "takes over" the network endpoint (a naughty router
+	// perhaps), thus trying to steal traffic.
+	var (
+		cctx = withPrincipal(t, ctx, "client")
+		actx = withPrincipal(t, ctx, "attacker")
+	)
+	name := "mountpoint/server"
+	_, aserver, err := v23.WithNewDispatchingServer(actx, "", testServerDisp{&testServer{}})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// The legitimate server would have mounted the same endpoint on the
+	// namespace, but with different blessings.
+	ep := aserver.Status().Endpoints[0]
+	ep.(*inaming.Endpoint).Blessings = []string{"test-blessings/server"}
+	if err := v23.GetNamespace(actx).Mount(ctx, name, ep.Name(), time.Hour); err != nil {
+		t.Fatal(err)
+	}
+
+	// The RPC call should fail because the blessings presented by the
+	// (attacker's) server are not consistent with the ones registered in
+	// the mounttable trusted by the client.
+	if _, err := v23.GetClient(cctx).StartCall(cctx, "mountpoint/server", "Closure", nil); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
+		t.Errorf("Got error %v (errorid=%v), want errorid=%v", err, verror.ErrorID(err), verror.ErrNotTrusted.ID)
+	}
+	// But the RPC should succeed if the client explicitly
+	// decided to skip server authorization.
+	if err := v23.GetClient(ctx).Call(cctx, "mountpoint/server", "Closure", nil, nil, options.SkipServerEndpointAuthorization{}); err != nil {
+		t.Errorf("Unexpected error(%v) when skipping server authorization", err)
+	}
+}
+
+func TestDischargeImpetusAndContextPropagation(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	sctx := withPrincipal(t, ctx, "server")
+	cctx := withPrincipal(t, ctx, "client")
+
+	// Setup the client so that it shares a blessing with a third-party caveat with the server.
+	setClientBlessings := func(req security.ThirdPartyRequirements) {
+		cav, err := security.NewPublicKeyCaveat(
+			v23.GetPrincipal(ctx).PublicKey(),
+			"mountpoint/discharger",
+			req,
+			security.UnconstrainedUse())
+		if err != nil {
+			t.Fatalf("Failed to create ThirdPartyCaveat(%+v): %v", req, err)
+		}
+		b, err := v23.GetPrincipal(cctx).BlessSelf("client_for_server", cav)
+		if err != nil {
+			t.Fatalf("BlessSelf failed: %v", err)
+		}
+		v23.GetPrincipal(cctx).BlessingStore().Set(b, "test-blessing/server")
+	}
+
+	// Setup the discharge server.
+	var tester dischargeTestServer
+	_, _, err := v23.WithNewServer(ctx, "mountpoint/discharger", &tester, &testServerAuthorizer{})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// Setup the application server.
+	sctx = v23.WithListenSpec(sctx, rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{{"tcp", "127.0.0.1:0"}},
+	})
+	object := "mountpoint/object"
+	_, _, err = v23.WithNewServer(sctx, object, &testServer{}, &testServerAuthorizer{})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	tests := []struct {
+		Requirements security.ThirdPartyRequirements
+		Impetus      security.DischargeImpetus
+	}{
+		{ // No requirements, no impetus
+			Requirements: security.ThirdPartyRequirements{},
+			Impetus:      security.DischargeImpetus{},
+		},
+		{ // Require everything
+			Requirements: security.ThirdPartyRequirements{ReportServer: true, ReportMethod: true, ReportArguments: true},
+			Impetus:      security.DischargeImpetus{Server: []security.BlessingPattern{"test-blessing/server"}, Method: "Method", Arguments: []*vdl.Value{vdl.StringValue("argument")}},
+		},
+		{ // Require only the method name
+			Requirements: security.ThirdPartyRequirements{ReportMethod: true},
+			Impetus:      security.DischargeImpetus{Method: "Method"},
+		},
+	}
+
+	for _, test := range tests {
+		setClientBlessings(test.Requirements)
+		tid := vtrace.GetSpan(cctx).Trace()
+		// StartCall should fetch the discharge, do not worry about finishing the RPC - do not care about that for this test.
+		if _, err := v23.GetClient(cctx).StartCall(cctx, object, "Method", []interface{}{"argument"}); err != nil {
+			t.Errorf("StartCall(%+v) failed: %v", test.Requirements, err)
+			continue
+		}
+		impetus, traceid := tester.Release()
+		// There should have been exactly 1 attempt to fetch discharges when making
+		// the RPC to the remote object.
+		if len(impetus) != 1 || len(traceid) != 1 {
+			t.Errorf("Test %+v: Got (%d, %d) (#impetus, #traceid), wanted exactly one", test.Requirements, len(impetus), len(traceid))
+			continue
+		}
+		// VC creation does not have any "impetus", it is established without
+		// knowledge of the context of the RPC. So ignore that.
+		//
+		// TODO(ashankar): Should the impetus of the RPC that initiated the
+		// VIF/VC creation be propagated?
+		if got, want := impetus[len(impetus)-1], test.Impetus; !reflect.DeepEqual(got, want) {
+			t.Errorf("Test %+v: Got impetus %v, want %v", test.Requirements, got, want)
+		}
+		// But the context used for all of this should be the same
+		// (thereby allowing debug traces to link VIF/VC creation with
+		// the RPC that initiated them).
+		for idx, got := range traceid {
+			if !reflect.DeepEqual(got, tid) {
+				t.Errorf("Test %+v: %d - Got trace id %q, want %q", test.Requirements, idx, hex.EncodeToString(got[:]), hex.EncodeToString(tid[:]))
+			}
+		}
+	}
+}
+
+func TestRPCClientBlessingsPublicKey(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	sctx := withPrincipal(t, ctx, "server")
+	bserver := v23.GetPrincipal(sctx).BlessingStore().Default()
+	cctx := withPrincipal(t, ctx, "client")
+	bclient := v23.GetPrincipal(cctx).BlessingStore().Default()
+	cctx, err := v23.WithPrincipal(cctx,
+		&singleBlessingPrincipal{Principal: v23.GetPrincipal(cctx)})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	bvictim := v23.GetPrincipal(withPrincipal(t, ctx, "victim")).BlessingStore().Default()
+
+	_, s, err := v23.WithNewDispatchingServer(sctx, "", testServerDisp{&testServer{}})
+	if err != nil {
+		t.Fatal(err)
+	}
+	object := naming.Join(s.Status().Endpoints[0].Name(), "suffix")
+
+	tests := []struct {
+		blessings security.Blessings
+		errID     verror.IDAction
+		err       string
+	}{
+		{blessings: bclient},
+		// server disallows clients from authenticating with blessings not bound to
+		// the client principal's public key
+		{blessings: bvictim, errID: verror.ErrNoAccess, err: "bound to a different public key"},
+		{blessings: bserver, errID: verror.ErrNoAccess, err: "bound to a different public key"},
+	}
+	for i, test := range tests {
+		name := fmt.Sprintf("%d: Client RPCing with blessings %v", i, test.blessings)
+		v23.GetPrincipal(cctx).BlessingStore().Set(test.blessings, "test-blessings")
+		if err := v23.GetClient(cctx).Call(cctx, object, "Closure", nil, nil); !matchesErrorPattern(err, test.errID, test.err) {
+			t.Errorf("%v: client.Call returned error %v", name, err)
+			continue
+		}
+	}
+}
+
+func TestServerLocalBlessings(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	tpCav := mkThirdPartyCaveat(
+		v23.GetPrincipal(ctx).PublicKey(),
+		"mountpoint/dischargeserver",
+		mkCaveat(security.NewExpiryCaveat(time.Now().Add(time.Hour))))
+	sctx := withPrincipal(t, ctx, "server", tpCav)
+	cctx := withPrincipal(t, ctx, "client")
+
+	_, _, err := v23.WithNewServer(ctx, "mountpoint/dischargeserver", &dischargeServer{}, security.AllowEveryone())
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, _, err = v23.WithNewDispatchingServer(sctx, "mountpoint/server", testServerDisp{&testServer{}})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	var gotServer, gotClient string
+	if err := v23.GetClient(cctx).Call(cctx, "mountpoint/server/suffix", "EchoBlessings", nil, []interface{}{&gotServer, &gotClient}); err != nil {
+		t.Fatalf("Finish failed: %v", err)
+	}
+	if wantServer, wantClient := "[test-blessing/server]", "[test-blessing/client]"; gotServer != wantServer || gotClient != wantClient {
+		t.Fatalf("EchoBlessings: got %v, %v want %v, %v", gotServer, gotClient, wantServer, wantClient)
+	}
+}
+
+func TestDischargePurgeFromCache(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	sctx := withPrincipal(t, ctx, "server")
+	// Client is blessed with a third-party caveat. The discharger
+	// service issues discharges with a fakeTimeCaveat.  This blessing
+	// is presented to "server".
+	cctx := withPrincipal(t, ctx, "client",
+		mkThirdPartyCaveat(
+			v23.GetPrincipal(ctx).PublicKey(),
+			"mountpoint/dischargeserver",
+			security.UnconstrainedUse()))
+
+	_, _, err := v23.WithNewServer(ctx, "mountpoint/dischargeserver", &dischargeServer{}, security.AllowEveryone())
+	if err != nil {
+		t.Fatal(err)
+	}
+	_, _, err = v23.WithNewDispatchingServer(sctx, "mountpoint/server", testServerDisp{&testServer{}})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	call := func() error {
+		var got string
+		if err := v23.GetClient(cctx).Call(cctx, "mountpoint/server/aclAuth", "Echo", []interface{}{"batman"}, []interface{}{&got}); err != nil {
+			return err
+		}
+		if want := `method:"Echo",suffix:"aclAuth",arg:"batman"`; got != want {
+			return verror.Convert(verror.ErrBadArg, nil, fmt.Errorf("Got [%v] want [%v]", got, want))
+		}
+		return nil
+	}
+
+	// First call should succeed
+	if err := call(); err != nil {
+		t.Fatal(err)
+	}
+	// Advance virtual clock, which will invalidate the discharge
+	clock.Advance(1)
+	if err, want := call(), "not authorized"; !matchesErrorPattern(err, verror.ErrNoAccess, want) {
+		t.Errorf("Got error [%v] wanted to match pattern %q", err, want)
+	}
+	// But retrying will succeed since the discharge should be purged
+	// from cache and refreshed
+	if err := call(); err != nil {
+		t.Fatal(err)
+	}
+}
+
+func TestServerPublicKeyOpt(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	sctx := withPrincipal(t, ctx, "server")
+	cctx := withPrincipal(t, ctx, "client")
+	octx := withPrincipal(t, ctx, "other")
+
+	mountName := "mountpoint/default"
+	_, _, err := v23.WithNewDispatchingServer(sctx, mountName, testServerDisp{&testServer{}})
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	// The call should succeed when the server presents the same public as the opt...
+	if _, err = v23.GetClient(cctx).StartCall(cctx, mountName, "Closure", nil, options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{
+		PublicKey: v23.GetPrincipal(sctx).PublicKey(),
+	}); err != nil {
+		t.Errorf("Expected call to succeed but got %v", err)
+	}
+	// ...but fail if they differ.
+	if _, err = v23.GetClient(cctx).StartCall(cctx, mountName, "Closure", nil, options.SkipServerEndpointAuthorization{}, options.ServerPublicKey{
+		PublicKey: v23.GetPrincipal(octx).PublicKey(),
+	}); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
+		t.Errorf("got %v, want %v", verror.ErrorID(err), verror.ErrNotTrusted.ID)
+	}
+}
diff --git a/runtime/internal/rpc/test/proxy_test.go b/runtime/internal/rpc/test/proxy_test.go
index 46c5078..d2689f6 100644
--- a/runtime/internal/rpc/test/proxy_test.go
+++ b/runtime/internal/rpc/test/proxy_test.go
@@ -21,31 +21,16 @@
 	"v.io/v23/rpc"
 	"v.io/v23/security"
 	"v.io/v23/verror"
-	"v.io/v23/vtrace"
-	"v.io/x/ref/lib/flags"
+	"v.io/x/ref"
 	_ "v.io/x/ref/runtime/factories/generic"
 	"v.io/x/ref/runtime/internal/lib/publisher"
 	inaming "v.io/x/ref/runtime/internal/naming"
-	irpc "v.io/x/ref/runtime/internal/rpc"
-	imanager "v.io/x/ref/runtime/internal/rpc/stream/manager"
 	"v.io/x/ref/runtime/internal/rpc/stream/proxy"
-	tnaming "v.io/x/ref/runtime/internal/testing/mocks/naming"
-	ivtrace "v.io/x/ref/runtime/internal/vtrace"
+	"v.io/x/ref/test"
 	"v.io/x/ref/test/modules"
 	"v.io/x/ref/test/testutil"
 )
 
-func testContext() (*context.T, func()) {
-	ctx, shutdown := v23.Init()
-	ctx, _ = context.WithTimeout(ctx, 20*time.Second)
-	var err error
-	if ctx, err = ivtrace.Init(ctx, flags.VtraceFlags{}); err != nil {
-		panic(err)
-	}
-	ctx, _ = vtrace.WithNewTrace(ctx)
-	return ctx, shutdown
-}
-
 var proxyServer = modules.Register(func(env *modules.Env, args ...string) error {
 	ctx, shutdown := v23.Init()
 	defer shutdown()
@@ -87,24 +72,6 @@
 	return nil
 }, "")
 
-type testServer struct{}
-
-func (*testServer) Echo(_ *context.T, call rpc.ServerCall, arg string) (string, error) {
-	return fmt.Sprintf("method:%q,suffix:%q,arg:%q", "Echo", call.Suffix(), arg), nil
-}
-
-type testServerAuthorizer struct{}
-
-func (testServerAuthorizer) Authorize(*context.T, security.Call) error {
-	return nil
-}
-
-type testServerDisp struct{ server interface{} }
-
-func (t testServerDisp) Lookup(_ *context.T, suffix string) (interface{}, security.Authorizer, error) {
-	return t.server, testServerAuthorizer{}, nil
-}
-
 type proxyHandle struct {
 	ns    namespace.T
 	sh    *modules.Shell
@@ -166,33 +133,41 @@
 }
 
 func testProxy(t *testing.T, spec rpc.ListenSpec, args ...string) {
-	ctx, shutdown := testContext()
+	if ref.RPCTransitionState() >= ref.XServers {
+		// This test cannot pass under the new RPC system.  It expects
+		// to distinguish between proxy endpoints and non-proxy endpoints
+		// which the new system does not support.
+		t.SkipNow()
+	}
+	ctx, shutdown := test.V23Init()
 	defer shutdown()
 
 	var (
-		pserver   = testutil.NewPrincipal("server")
-		pclient   = testutil.NewPrincipal("client")
+		pserver   = testutil.NewPrincipal()
+		pclient   = testutil.NewPrincipal()
 		serverKey = pserver.PublicKey()
-		// We use different stream managers for the client and server
-		// to prevent VIF re-use (in other words, we want to test VIF
-		// creation from both the client and server end).
-		smserver = imanager.InternalNew(ctx, naming.FixedRoutingID(0x555555555))
-		smclient = imanager.InternalNew(ctx, naming.FixedRoutingID(0x444444444))
-		ns       = tnaming.NewSimpleNamespace()
+		ns        = v23.GetNamespace(ctx)
 	)
-	defer smserver.Shutdown()
-	defer smclient.Shutdown()
-	client, err := irpc.InternalNewClient(smserver, ns)
+	idp := testutil.IDProviderFromPrincipal(v23.GetPrincipal(ctx))
+	idp.Bless(pserver, "server")
+	idp.Bless(pclient, "client")
+	clientCtx, err := v23.WithPrincipal(ctx, pclient)
 	if err != nil {
 		t.Fatal(err)
 	}
-	defer client.Close()
-	serverCtx, _ := v23.WithPrincipal(ctx, pserver)
-	server, err := irpc.InternalNewServer(serverCtx, smserver, ns, nil, "", nil)
+	client := v23.GetClient(clientCtx)
+
+	serverCtx, err := v23.WithPrincipal(v23.WithListenSpec(ctx, spec), pserver)
 	if err != nil {
 		t.Fatal(err)
 	}
-	defer server.Stop()
+	_, server, err := v23.WithNewDispatchingServer(
+		serverCtx,
+		"mountpoint/server",
+		testServerDisp{&testServer{}})
+	if err != nil {
+		t.Fatal(err)
+	}
 
 	// The client must recognize the server's blessings, otherwise it won't
 	// communicate with it.
@@ -228,16 +203,21 @@
 		t.Fatalf("failed to lookup proxy")
 	}
 
-	eps, err := server.Listen(spec)
+	proxyAddr, _ := naming.SplitAddressName(addrs[0])
+	proxyEP, err := inaming.NewEndpoint(proxyAddr)
 	if err != nil {
-		t.Fatal(err)
-	}
-	if err := server.ServeDispatcher("mountpoint/server", testServerDisp{&testServer{}}); err != nil {
-		t.Fatal(err)
+		t.Fatalf("unexpected error for %q: %s", proxyEP, err)
 	}
 
+	// Proxy connetions are created asynchronously, so we wait for the
+	// expected number of endpoints to appear for the specified service name.
+	ch := make(chan struct{})
+	numNames := 1
+	if hasLocalListener {
+		numNames = 2
+	}
 	// Proxy connections are started asynchronously, so we need to wait..
-	waitForMountTable := func(ch chan int, expect int) {
+	go func() {
 		then := time.Now().Add(time.Minute)
 		for {
 			me, err := ns.Resolve(ctx, name)
@@ -247,64 +227,36 @@
 			for i, s := range me.Servers {
 				ctx.Infof("%d: %s", i, s)
 			}
-			if err == nil && len(me.Servers) == expect {
-				ch <- 1
+			if err == nil && len(me.Servers) == numNames {
+				close(ch)
 				return
 			}
 			if time.Now().After(then) {
-				t.Fatalf("timed out waiting for %d servers, found %d", expect, len(me.Servers))
+				t.Fatalf("timed out waiting for %d servers, found %d", numNames, len(me.Servers))
 			}
 			time.Sleep(100 * time.Millisecond)
 		}
-	}
-	waitForServerStatus := func(ch chan int, proxy string) {
-		then := time.Now().Add(time.Minute)
-		for {
-			status := server.Status()
-			if len(status.Proxies) == 1 && status.Proxies[0].Proxy == proxy {
-				ch <- 2
-				return
-			}
-			if time.Now().After(then) {
-				t.Fatalf("timed out")
-			}
-			time.Sleep(100 * time.Millisecond)
-		}
-	}
-	proxyEP, _ := naming.SplitAddressName(addrs[0])
-	proxiedEP, err := inaming.NewEndpoint(proxyEP)
-	if err != nil {
-		t.Fatalf("unexpected error for %q: %s", proxyEP, err)
-	}
-	proxiedEP.RID = naming.FixedRoutingID(0x555555555)
-	proxiedEP.Blessings = []string{"server"}
-	expectedNames := []string{naming.JoinAddressName(proxiedEP.String(), "suffix")}
-	if hasLocalListener {
-		expectedNames = append(expectedNames, naming.JoinAddressName(eps[0].String(), "suffix"))
-	}
+	}()
 
-	// Proxy connetions are created asynchronously, so we wait for the
-	// expected number of endpoints to appear for the specified service name.
-	ch := make(chan int, 2)
-	go waitForMountTable(ch, len(expectedNames))
-	go waitForServerStatus(ch, spec.Proxy)
 	select {
 	case <-time.After(time.Minute):
 		t.Fatalf("timedout waiting for two entries in the mount table and server status")
-	case i := <-ch:
-		select {
-		case <-time.After(time.Minute):
-			t.Fatalf("timedout waiting for two entries in the mount table or server status")
-		case j := <-ch:
-			if !((i == 1 && j == 2) || (i == 2 && j == 1)) {
-				t.Fatalf("unexpected return values from waiters")
-			}
-		}
+	case <-ch:
 	}
 
 	status := server.Status()
-	if got, want := status.Proxies[0].Endpoint, proxiedEP; !reflect.DeepEqual(got, want) {
-		t.Fatalf("got %q, want %q", got, want)
+	proxiedEP := status.Proxies[0].Endpoint
+	if proxiedEP.Network() != proxyEP.Network() ||
+		proxiedEP.Addr().String() != proxyEP.Addr().String() ||
+		proxiedEP.ServesMountTable() || proxiedEP.ServesLeaf() ||
+		proxiedEP.BlessingNames()[0] != "test-blessing/server" {
+		t.Fatalf("got %q, want (tcp, %s, s, test-blessing/server)",
+			proxiedEP, proxyEP.Addr().String())
+	}
+	expectedNames := []string{naming.JoinAddressName(proxiedEP.String(), "suffix")}
+	if hasLocalListener {
+		normalEP := status.Endpoints[0]
+		expectedNames = append(expectedNames, naming.JoinAddressName(normalEP.String(), "suffix"))
 	}
 
 	got := []string{}
@@ -322,7 +274,7 @@
 		// mount table, given that we're trying to test the proxy, we remove
 		// the local endpoint from the mount table entry!  We have to remove both
 		// the tcp and the websocket address.
-		sep := eps[0].String()
+		sep := status.Endpoints[0].String()
 		ns.Unmount(ctx, "mountpoint/server", sep)
 	}
 
diff --git a/runtime/internal/rpc/test/server_test.go b/runtime/internal/rpc/test/server_test.go
new file mode 100644
index 0000000..3c078af
--- /dev/null
+++ b/runtime/internal/rpc/test/server_test.go
@@ -0,0 +1,268 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package test
+
+import (
+	"reflect"
+	"sort"
+	"testing"
+	"time"
+
+	"v.io/v23"
+	"v.io/v23/context"
+	"v.io/v23/naming"
+	"v.io/v23/options"
+	"v.io/v23/rpc"
+	"v.io/v23/security"
+	"v.io/v23/verror"
+	inaming "v.io/x/ref/runtime/internal/naming"
+	"v.io/x/ref/test"
+)
+
+type noMethodsType struct{ Field string }
+
+type fieldType struct {
+	unexported string
+}
+type noExportedFieldsType struct{}
+
+func (noExportedFieldsType) F(_ *context.T, _ rpc.ServerCall, f fieldType) error { return nil }
+
+type badObjectDispatcher struct{}
+
+func (badObjectDispatcher) Lookup(_ *context.T, suffix string) (interface{}, security.Authorizer, error) {
+	return noMethodsType{}, nil, nil
+}
+
+// TestBadObject ensures that Serve handles bad receiver objects gracefully (in
+// particular, it doesn't panic).
+func TestBadObject(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	sctx := withPrincipal(t, ctx, "server")
+	cctx := withPrincipal(t, ctx, "client")
+
+	if _, _, err := v23.WithNewServer(sctx, "", nil, nil); err == nil {
+		t.Fatal("should have failed")
+	}
+	if _, _, err := v23.WithNewServer(sctx, "", new(noMethodsType), nil); err == nil {
+		t.Fatal("should have failed")
+	}
+	if _, _, err := v23.WithNewServer(sctx, "", new(noExportedFieldsType), nil); err == nil {
+		t.Fatal("should have failed")
+	}
+	if _, _, err := v23.WithNewDispatchingServer(sctx, "", badObjectDispatcher{}); err != nil {
+		t.Fatalf("ServeDispatcher failed: %v", err)
+	}
+	// TODO(mattr): It doesn't necessarily make sense to me that a bad object from
+	// the dispatcher results in a retry.
+	cctx, _ = context.WithTimeout(ctx, time.Second)
+	var result string
+	if err := v23.GetClient(cctx).Call(cctx, "servername", "SomeMethod", nil, []interface{}{&result}); err == nil {
+		// TODO(caprita): Check the error type rather than
+		// merely ensuring the test doesn't panic.
+		t.Fatalf("Call should have failed")
+	}
+}
+
+func TestServerArgs(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+	sctx := withPrincipal(t, ctx, "server")
+
+	esctx := v23.WithListenSpec(sctx, rpc.ListenSpec{})
+	_, _, err := v23.WithNewServer(esctx, "", &testServer{}, nil)
+	if verror.ErrorID(err) != verror.ErrBadArg.ID {
+		t.Fatalf("expected a BadArg error: got %v", err)
+	}
+
+	esctx = v23.WithListenSpec(sctx, rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{{"tcp", "*:0"}},
+	})
+	_, _, err = v23.WithNewServer(esctx, "", &testServer{}, nil)
+	if verror.ErrorID(err) != verror.ErrBadArg.ID {
+		t.Fatalf("expected a BadArg error: got %v", err)
+	}
+
+	esctx = v23.WithListenSpec(sctx, rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{
+			{"tcp", "*:0"},
+			{"tcp", "127.0.0.1:0"},
+		},
+	})
+	_, _, err = v23.WithNewServer(esctx, "", &testServer{}, nil)
+	if verror.ErrorID(err) == verror.ErrBadArg.ID {
+		t.Fatalf("expected a BadArg error: got %v", err)
+	}
+}
+
+type statusServer struct{ ch chan struct{} }
+
+func (s *statusServer) Hang(*context.T, rpc.ServerCall) error {
+	s.ch <- struct{}{} // Notify the server has received a call.
+	<-s.ch             // Wait for the server to be ready to go.
+	return nil
+}
+
+func TestServerStatus(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	serverChan := make(chan struct{})
+	_, server, err := v23.WithNewServer(ctx, "test", &statusServer{serverChan}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	status := server.Status()
+	if got, want := status.State, rpc.ServerActive; got != want {
+		t.Fatalf("got %s, want %s", got, want)
+	}
+
+	progress := make(chan error)
+	makeCall := func(ctx *context.T) {
+		call, err := v23.GetClient(ctx).StartCall(ctx, "test", "Hang", nil)
+		progress <- err
+		progress <- call.Finish()
+	}
+	go makeCall(ctx)
+
+	// Wait for RPC to start and the server has received the call.
+	if err := <-progress; err != nil {
+		t.Fatal(err)
+	}
+	<-serverChan
+
+	// Stop server asynchronously
+	go func() {
+		if err = server.Stop(); err != nil {
+			t.Fatal(err)
+		}
+	}()
+
+	waitForStatus := func(want rpc.ServerState) {
+		then := time.Now()
+		for {
+			status = server.Status()
+			if got := status.State; got != want {
+				if time.Now().Sub(then) > time.Minute {
+					t.Fatalf("got %s, want %s", got, want)
+				}
+			} else {
+				break
+			}
+			time.Sleep(100 * time.Millisecond)
+		}
+	}
+
+	// Server should enter 'ServerStopping' state.
+	waitForStatus(rpc.ServerStopping)
+	// Server won't stop until the statusServer's hung method completes.
+	close(serverChan)
+	// Wait for RPC to finish
+	if err := <-progress; err != nil {
+		t.Fatal(err)
+	}
+	// Now that the RPC is done, the server should be able to stop.
+	waitForStatus(rpc.ServerStopped)
+}
+
+func TestMountStatus(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	sctx := withPrincipal(t, ctx, "server")
+	sctx = v23.WithListenSpec(sctx, rpc.ListenSpec{
+		Addrs: rpc.ListenAddrs{
+			{"tcp", "127.0.0.1:0"},
+			{"tcp", "127.0.0.1:0"},
+		},
+	})
+	_, server, err := v23.WithNewServer(sctx, "foo", &testServer{}, nil)
+	if err != nil {
+		t.Fatal(err)
+	}
+	status := server.Status()
+	eps := server.Status().Endpoints
+	if got, want := len(eps), 2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+	setLeafEndpoints(eps)
+	if got, want := len(status.Mounts), 2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+	servers := status.Mounts.Servers()
+	if got, want := len(servers), 2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+	if got, want := servers, endpointToStrings(eps); !reflect.DeepEqual(got, want) {
+		t.Fatalf("got %v, want %v", got, want)
+	}
+
+	// Add a second name and we should now see 4 mounts, 2 for each name.
+	if err := server.AddName("bar"); err != nil {
+		t.Fatal(err)
+	}
+	status = server.Status()
+	if got, want := len(status.Mounts), 4; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+	servers = status.Mounts.Servers()
+	if got, want := len(servers), 2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+	if got, want := servers, endpointToStrings(eps); !reflect.DeepEqual(got, want) {
+		t.Fatalf("got %v, want %v", got, want)
+	}
+	names := status.Mounts.Names()
+	if got, want := len(names), 2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+	serversPerName := map[string][]string{}
+	for _, ms := range status.Mounts {
+		serversPerName[ms.Name] = append(serversPerName[ms.Name], ms.Server)
+	}
+	if got, want := len(serversPerName), 2; got != want {
+		t.Fatalf("got %d, want %d", got, want)
+	}
+	for _, name := range []string{"foo", "bar"} {
+		if got, want := len(serversPerName[name]), 2; got != want {
+			t.Fatalf("got %d, want %d", got, want)
+		}
+	}
+}
+
+func TestIsLeafServerOption(t *testing.T) {
+	ctx, shutdown := test.V23Init()
+	defer shutdown()
+
+	_, _, err := v23.WithNewDispatchingServer(ctx, "leafserver",
+		&testServerDisp{&testServer{}}, options.IsLeaf(true))
+	if err != nil {
+		t.Fatal(err)
+	}
+	// we have set IsLeaf to true, sending any suffix to leafserver should result
+	// in an suffix was not expected error.
+	var result string
+	callErr := v23.GetClient(ctx).Call(ctx, "leafserver/unwantedSuffix", "Echo", []interface{}{"Mirror on the wall"}, []interface{}{&result})
+	if callErr == nil {
+		t.Fatalf("Call should have failed with suffix was not expected error")
+	}
+}
+
+func endpointToStrings(eps []naming.Endpoint) []string {
+	r := []string{}
+	for _, ep := range eps {
+		r = append(r, ep.String())
+	}
+	sort.Strings(r)
+	return r
+}
+
+func setLeafEndpoints(eps []naming.Endpoint) {
+	for i := range eps {
+		eps[i].(*inaming.Endpoint).IsLeaf = true
+	}
+}
diff --git a/runtime/internal/rpc/test/testserver_test.go b/runtime/internal/rpc/test/testserver_test.go
new file mode 100644
index 0000000..6137cd5
--- /dev/null
+++ b/runtime/internal/rpc/test/testserver_test.go
@@ -0,0 +1,251 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package test
+
+import (
+	"fmt"
+	"io"
+	"sync"
+	"time"
+
+	"v.io/v23/context"
+	"v.io/v23/i18n"
+	"v.io/v23/rpc"
+	"v.io/v23/security"
+	"v.io/v23/security/access"
+	"v.io/v23/uniqueid"
+	"v.io/v23/vtrace"
+)
+
+// This file contains a test server and dispatcher which are used by other
+// tests, especially those in full_test.
+type userType string
+
+type testServer struct{}
+
+func (*testServer) Closure(*context.T, rpc.ServerCall) error {
+	return nil
+}
+
+func (*testServer) Error(*context.T, rpc.ServerCall) error {
+	return errMethod
+}
+
+func (*testServer) Echo(_ *context.T, call rpc.ServerCall, arg string) (string, error) {
+	return fmt.Sprintf("method:%q,suffix:%q,arg:%q", "Echo", call.Suffix(), arg), nil
+}
+
+func (*testServer) EchoUser(_ *context.T, call rpc.ServerCall, arg string, u userType) (string, userType, error) {
+	return fmt.Sprintf("method:%q,suffix:%q,arg:%q", "EchoUser", call.Suffix(), arg), u, nil
+}
+
+func (*testServer) EchoLang(ctx *context.T, call rpc.ServerCall) (string, error) {
+	return string(i18n.GetLangID(ctx)), nil
+}
+
+func (*testServer) EchoBlessings(ctx *context.T, call rpc.ServerCall) (server, client string, _ error) {
+	local := security.LocalBlessingNames(ctx, call.Security())
+	remote, _ := security.RemoteBlessingNames(ctx, call.Security())
+	return fmt.Sprintf("%v", local), fmt.Sprintf("%v", remote), nil
+}
+
+func (*testServer) EchoGrantedBlessings(_ *context.T, call rpc.ServerCall, arg string) (result, blessing string, _ error) {
+	return arg, fmt.Sprintf("%v", call.GrantedBlessings()), nil
+}
+
+func (*testServer) EchoAndError(_ *context.T, call rpc.ServerCall, arg string) (string, error) {
+	result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", "EchoAndError", call.Suffix(), arg)
+	if arg == "error" {
+		return result, errMethod
+	}
+	return result, nil
+}
+
+func (*testServer) Stream(_ *context.T, call rpc.StreamServerCall, arg string) (string, error) {
+	result := fmt.Sprintf("method:%q,suffix:%q,arg:%q", "Stream", call.Suffix(), arg)
+	var u userType
+	var err error
+	for err = call.Recv(&u); err == nil; err = call.Recv(&u) {
+		result += " " + string(u)
+		if err := call.Send(u); err != nil {
+			return "", err
+		}
+	}
+	if err == io.EOF {
+		err = nil
+	}
+	return result, err
+}
+
+func (*testServer) Unauthorized(*context.T, rpc.StreamServerCall) (string, error) {
+	return "UnauthorizedResult", nil
+}
+
+type testServerAuthorizer struct{}
+
+func (testServerAuthorizer) Authorize(ctx *context.T, call security.Call) error {
+	// Verify that the Call object seen by the authorizer
+	// has the necessary fields.
+	lb := call.LocalBlessings()
+	if lb.IsZero() {
+		return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalBlessings", call)
+	}
+	if tpcavs := lb.ThirdPartyCaveats(); len(tpcavs) > 0 && call.LocalDischarges() == nil {
+		return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalDischarges even when LocalBlessings have third-party caveats", call)
+
+	}
+	if call.LocalPrincipal() == nil {
+		return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalPrincipal", call)
+	}
+	if call.Method() == "" {
+		return fmt.Errorf("testServerAuthorzer: Call object %v has no Method", call)
+	}
+	if call.LocalEndpoint() == nil {
+		return fmt.Errorf("testServerAuthorzer: Call object %v has no LocalEndpoint", call)
+	}
+	if call.RemoteEndpoint() == nil {
+		return fmt.Errorf("testServerAuthorzer: Call object %v has no RemoteEndpoint", call)
+	}
+
+	// Do not authorize the method "Unauthorized".
+	if call.Method() == "Unauthorized" {
+		return fmt.Errorf("testServerAuthorizer denied access")
+	}
+	return nil
+}
+
+type testServerDisp struct{ server interface{} }
+
+func (t testServerDisp) Lookup(_ *context.T, suffix string) (interface{}, security.Authorizer, error) {
+	// If suffix is "nilAuth" we use default authorization, if it is "aclAuth" we
+	// use an AccessList-based authorizer, and otherwise we use the custom testServerAuthorizer.
+	var authorizer security.Authorizer
+	switch suffix {
+	case "discharger":
+		return &dischargeServer{}, testServerAuthorizer{}, nil
+	case "nilAuth":
+		authorizer = nil
+	case "aclAuth":
+		authorizer = &access.AccessList{
+			In: []security.BlessingPattern{"test-blessing/client", "test-blessing/server"},
+		}
+	default:
+		authorizer = testServerAuthorizer{}
+	}
+	return t.server, authorizer, nil
+}
+
+type dischargeServer struct {
+	mu     sync.Mutex
+	called bool
+}
+
+func (ds *dischargeServer) Discharge(ctx *context.T, call rpc.StreamServerCall, cav security.Caveat, _ security.DischargeImpetus) (security.Discharge, error) {
+	ds.mu.Lock()
+	ds.called = true
+	ds.mu.Unlock()
+	tp := cav.ThirdPartyDetails()
+	if tp == nil {
+		return security.Discharge{}, fmt.Errorf("discharger: %v does not represent a third-party caveat", cav)
+	}
+	if err := tp.Dischargeable(ctx, call.Security()); err != nil {
+		return security.Discharge{}, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", cav, err)
+	}
+	// Add a fakeTimeCaveat to be able to control discharge expiration via 'clock'.
+	expiry, err := security.NewCaveat(fakeTimeCaveat, clock.Now())
+	if err != nil {
+		return security.Discharge{}, fmt.Errorf("failed to create an expiration on the discharge: %v", err)
+	}
+	return call.Security().LocalPrincipal().MintDischarge(cav, expiry)
+}
+
+// granter implements rpc.Granter.
+//
+// It returns the specified (security.Blessings, error) pair if either the
+// blessing or the error is specified. Otherwise it returns a blessing
+// derived from the local blessings of the current call.
+type granter struct {
+	rpc.CallOpt
+	b   security.Blessings
+	err error
+}
+
+func (g granter) Grant(ctx *context.T, call security.Call) (security.Blessings, error) {
+	if !g.b.IsZero() || g.err != nil {
+		return g.b, g.err
+	}
+	return call.LocalPrincipal().Bless(
+		call.RemoteBlessings().PublicKey(),
+		call.LocalBlessings(),
+		"blessed",
+		security.UnconstrainedUse())
+}
+
+// dischargeTestServer implements the discharge service. Always fails to
+// issue a discharge, but records the impetus and traceid of the RPC call.
+type dischargeTestServer struct {
+	p       security.Principal
+	impetus []security.DischargeImpetus
+	traceid []uniqueid.Id
+}
+
+func (s *dischargeTestServer) Discharge(ctx *context.T, _ rpc.ServerCall, cav security.Caveat, impetus security.DischargeImpetus) (security.Discharge, error) {
+	s.impetus = append(s.impetus, impetus)
+	s.traceid = append(s.traceid, vtrace.GetSpan(ctx).Trace())
+	return security.Discharge{}, fmt.Errorf("discharges not issued")
+}
+
+func (s *dischargeTestServer) Release() ([]security.DischargeImpetus, []uniqueid.Id) {
+	impetus, traceid := s.impetus, s.traceid
+	s.impetus, s.traceid = nil, nil
+	return impetus, traceid
+}
+
+type streamRecvInGoroutineServer struct{ c chan error }
+
+func (s *streamRecvInGoroutineServer) RecvInGoroutine(_ *context.T, call rpc.StreamServerCall) error {
+	// Spawn a goroutine to read streaming data from the client.
+	go func() {
+		var i interface{}
+		for {
+			err := call.Recv(&i)
+			if err != nil {
+				s.c <- err
+				return
+			}
+		}
+	}()
+	// Imagine the server did some processing here and now that it is done,
+	// it does not care to see what else the client has to say.
+	return nil
+}
+
+type expiryDischarger struct {
+	called bool
+}
+
+func (ed *expiryDischarger) Discharge(ctx *context.T, call rpc.StreamServerCall, cav security.Caveat, _ security.DischargeImpetus) (security.Discharge, error) {
+	tp := cav.ThirdPartyDetails()
+	if tp == nil {
+		return security.Discharge{}, fmt.Errorf("discharger: %v does not represent a third-party caveat", cav)
+	}
+	if err := tp.Dischargeable(ctx, call.Security()); err != nil {
+		return security.Discharge{}, fmt.Errorf("third-party caveat %v cannot be discharged for this context: %v", cav, err)
+	}
+	expDur := 10 * time.Millisecond
+	if ed.called {
+		expDur = time.Second
+	}
+	expiry, err := security.NewExpiryCaveat(time.Now().Add(expDur))
+	if err != nil {
+		return security.Discharge{}, fmt.Errorf("failed to create an expiration on the discharge: %v", err)
+	}
+	d, err := call.Security().LocalPrincipal().MintDischarge(cav, expiry)
+	if err != nil {
+		return security.Discharge{}, err
+	}
+	ed.called = true
+	return d, nil
+}
diff --git a/runtime/internal/rpc/test/testutil_test.go b/runtime/internal/rpc/test/testutil_test.go
new file mode 100644
index 0000000..5b32e71
--- /dev/null
+++ b/runtime/internal/rpc/test/testutil_test.go
@@ -0,0 +1,208 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package test
+
+import (
+	"fmt"
+	"reflect"
+	"strings"
+	"sync"
+	"testing"
+	"time"
+
+	"v.io/v23"
+	"v.io/v23/context"
+	"v.io/v23/security"
+	"v.io/v23/uniqueid"
+	"v.io/v23/vdl"
+	"v.io/v23/verror"
+	"v.io/x/ref/test/testutil"
+)
+
+var errMethod = verror.New(verror.ErrAborted, nil)
+var fakeTimeCaveat = security.CaveatDescriptor{
+	Id:        uniqueid.Id{0x18, 0xba, 0x6f, 0x84, 0xd5, 0xec, 0xdb, 0x9b, 0xf2, 0x32, 0x19, 0x5b, 0x53, 0x92, 0x80, 0x0},
+	ParamType: vdl.TypeOf(int64(0)),
+}
+
+func init() {
+	security.RegisterCaveatValidator(fakeTimeCaveat, func(_ *context.T, _ security.Call, t int64) error {
+		if now := clock.Now(); now > t {
+			return fmt.Errorf("fakeTimeCaveat expired: now=%d > then=%d", now, t)
+		}
+		return nil
+	})
+}
+
+var clock = new(fakeClock)
+
+type fakeClock struct {
+	sync.Mutex
+	time int64
+}
+
+func (c *fakeClock) Now() int64 {
+	c.Lock()
+	defer c.Unlock()
+	return c.time
+}
+
+func (c *fakeClock) Advance(steps uint) {
+	c.Lock()
+	c.time += int64(steps)
+	c.Unlock()
+}
+
+// singleBlessingStore implements security.BlessingStore. It is a
+// BlessingStore that marks the last blessing that was set on it as
+// shareable with any peer. It does not care about the public key that
+// blessing being set is bound to.
+type singleBlessingStore struct {
+	b security.Blessings
+}
+
+func (s *singleBlessingStore) Set(b security.Blessings, _ security.BlessingPattern) (security.Blessings, error) {
+	s.b = b
+	return security.Blessings{}, nil
+}
+func (s *singleBlessingStore) ForPeer(...string) security.Blessings {
+	return s.b
+}
+func (*singleBlessingStore) SetDefault(b security.Blessings) error {
+	return nil
+}
+func (*singleBlessingStore) Default() security.Blessings {
+	return security.Blessings{}
+}
+func (*singleBlessingStore) PublicKey() security.PublicKey {
+	return nil
+}
+func (*singleBlessingStore) DebugString() string {
+	return ""
+}
+func (*singleBlessingStore) PeerBlessings() map[security.BlessingPattern]security.Blessings {
+	return nil
+}
+func (*singleBlessingStore) CacheDischarge(security.Discharge, security.Caveat, security.DischargeImpetus) {
+	return
+}
+func (*singleBlessingStore) ClearDischarges(...security.Discharge) {
+	return
+}
+func (*singleBlessingStore) Discharge(security.Caveat, security.DischargeImpetus) security.Discharge {
+	return security.Discharge{}
+}
+
+// singleBlessingPrincipal implements security.Principal. It is a wrapper over
+// a security.Principal that intercepts  all invocations on the
+// principal's BlessingStore and serves them via a singleBlessingStore.
+type singleBlessingPrincipal struct {
+	security.Principal
+	b singleBlessingStore
+}
+
+func (p *singleBlessingPrincipal) BlessingStore() security.BlessingStore {
+	return &p.b
+}
+
+func withPrincipal(t *testing.T, ctx *context.T, name string, caveats ...security.Caveat) *context.T {
+	idp := testutil.IDProviderFromPrincipal(v23.GetPrincipal(ctx))
+	p := testutil.NewPrincipal()
+	if err := idp.Bless(p, name, caveats...); err != nil {
+		t.Fatal(err)
+	}
+	ctx, err := v23.WithPrincipal(ctx, p)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return ctx
+}
+
+func bless(t *testing.T, pctx, whoctx *context.T, extension string, cavs ...security.Caveat) security.Blessings {
+	idp := testutil.IDProviderFromPrincipal(v23.GetPrincipal(pctx))
+	b, err := idp.NewBlessings(v23.GetPrincipal(whoctx), extension, cavs...)
+	if err != nil {
+		t.Fatal(err)
+	}
+	return b
+}
+
+func mkCaveat(cav security.Caveat, err error) security.Caveat {
+	if err != nil {
+		panic(err)
+	}
+	return cav
+}
+
+func mkThirdPartyCaveat(discharger security.PublicKey, location string, c security.Caveat) security.Caveat {
+	tpc, err := security.NewPublicKeyCaveat(discharger, location, security.ThirdPartyRequirements{}, c)
+	if err != nil {
+		panic(err)
+	}
+	return tpc
+}
+
+func matchesErrorPattern(err error, id verror.IDAction, pattern string) bool {
+	if len(pattern) > 0 && err != nil && strings.Index(err.Error(), pattern) < 0 {
+		return false
+	}
+	if err == nil && id.ID == "" {
+		return true
+	}
+	return verror.ErrorID(err) == id.ID
+}
+
+func waitForNames(t *testing.T, ctx *context.T, exist bool, names ...string) {
+	for _, n := range names {
+		for {
+			me, err := v23.GetNamespace(ctx).Resolve(ctx, n)
+			if err == nil && exist && len(me.Names()) > 0 {
+				break
+			}
+			if (err != nil && !exist) || (err == nil && len(me.Names()) == 0) {
+				break
+			}
+			ctx.Infof("Still waiting for %v, %v: %#v, %v", exist, n, me, err)
+			time.Sleep(10 * time.Millisecond)
+		}
+	}
+}
+
+func makeResultPtrs(ins []interface{}) []interface{} {
+	outs := make([]interface{}, len(ins))
+	for ix, in := range ins {
+		typ := reflect.TypeOf(in)
+		if typ == nil {
+			// Nil indicates interface{}.
+			var empty interface{}
+			typ = reflect.ValueOf(&empty).Elem().Type()
+		}
+		outs[ix] = reflect.New(typ).Interface()
+	}
+	return outs
+}
+
+func checkResultPtrs(t *testing.T, name string, gotptrs, want []interface{}) {
+	for ix, res := range gotptrs {
+		got := reflect.ValueOf(res).Elem().Interface()
+		want := want[ix]
+		switch g := got.(type) {
+		case verror.E:
+			w, ok := want.(verror.E)
+			// don't use reflect deep equal on verror's since they contain
+			// a list of stack PCs which will be different.
+			if !ok {
+				t.Errorf("%s result %d got type %T, want %T", name, ix, g, w)
+			}
+			if verror.ErrorID(g) != w.ID {
+				t.Errorf("%s result %d got %v, want %v", name, ix, g, w)
+			}
+		default:
+			if !reflect.DeepEqual(got, want) {
+				t.Errorf("%s result %d got %v, want %v", name, ix, got, want)
+			}
+		}
+	}
+}
diff --git a/runtime/internal/rpc/transition/transition_test.go b/runtime/internal/rpc/transition/transition_test.go
index d50c239..13ab953 100644
--- a/runtime/internal/rpc/transition/transition_test.go
+++ b/runtime/internal/rpc/transition/transition_test.go
@@ -38,7 +38,7 @@
 
 	sp := testutil.NewPrincipal()
 	testutil.IDProviderFromPrincipal(v23.GetPrincipal(ctx)).Bless(sp, "server")
-	server, err := irpc.InternalNewServer(ctx, sm, v23.GetNamespace(ctx),
+	server, err := irpc.DeprecatedNewServer(ctx, sm, v23.GetNamespace(ctx),
 		nil, "", v23.GetClient(ctx))
 	if err != nil {
 		t.Fatal(err)
diff --git a/runtime/internal/rpc/transitionclient.go b/runtime/internal/rpc/transitionclient.go
index 0c41746..ade2e3a 100644
--- a/runtime/internal/rpc/transitionclient.go
+++ b/runtime/internal/rpc/transitionclient.go
@@ -26,7 +26,7 @@
 	if ret.xc, err = NewXClient(ctx, flowMgr, ns, opts...); err != nil {
 		return nil, err
 	}
-	if ret.c, err = InternalNewClient(streamMgr, ns, opts...); err != nil {
+	if ret.c, err = DeprecatedNewClient(streamMgr, ns, opts...); err != nil {
 		ret.xc.Close()
 		return nil, err
 	}
diff --git a/runtime/internal/rt/runtime.go b/runtime/internal/rt/runtime.go
index 02e919a..77f07f9 100644
--- a/runtime/internal/rt/runtime.go
+++ b/runtime/internal/rt/runtime.go
@@ -27,6 +27,7 @@
 	"v.io/v23/verror"
 	"v.io/v23/vtrace"
 
+	"v.io/x/ref"
 	"v.io/x/ref/internal/logger"
 	"v.io/x/ref/lib/apilog"
 	"v.io/x/ref/lib/flags"
@@ -43,27 +44,6 @@
 	ivtrace "v.io/x/ref/runtime/internal/vtrace"
 )
 
-const (
-	None = iota
-	XClients
-	XServers
-)
-
-var TransitionState = None
-
-func init() {
-	switch ts := os.Getenv("V23_RPC_TRANSITION_STATE"); ts {
-	case "xclients":
-		TransitionState = XClients
-	case "xservers":
-		TransitionState = XServers
-	case "":
-		TransitionState = None
-	default:
-		panic("Unknown transition state: " + ts)
-	}
-}
-
 type contextKey int
 
 const (
@@ -288,7 +268,7 @@
 			Blessings: principal.BlessingStore().Default(),
 		})
 	}
-	server, err := irpc.InternalNewServer(ctx, sm, ns, id.settingsPublisher, id.settingsName, r.GetClient(ctx), otherOpts...)
+	server, err := irpc.DeprecatedNewServer(ctx, sm, ns, id.settingsPublisher, id.settingsName, r.GetClient(ctx), otherOpts...)
 	if err != nil {
 		return nil, err
 	}
@@ -442,11 +422,11 @@
 	var err error
 	deps := []interface{}{vtraceDependency{}}
 
-	if fm != nil && TransitionState >= XClients {
+	if fm != nil && ref.RPCTransitionState() >= ref.XClients {
 		client, err = irpc.NewTransitionClient(ctx, sm, fm, ns, otherOpts...)
 		deps = append(deps, fm, sm)
 	} else {
-		client, err = irpc.InternalNewClient(sm, ns, otherOpts...)
+		client, err = irpc.DeprecatedNewClient(sm, ns, otherOpts...)
 		deps = append(deps, sm)
 	}
 
@@ -601,7 +581,7 @@
 
 func (r *Runtime) WithNewServer(ctx *context.T, name string, object interface{}, auth security.Authorizer, opts ...rpc.ServerOpt) (*context.T, rpc.Server, error) {
 	defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
-	if TransitionState >= XServers {
+	if ref.RPCTransitionState() >= ref.XServers {
 		// TODO(mattr): Deal with shutdown deps.
 		newctx, spub, sname, opts, err := r.commonServerInit(ctx, opts...)
 		if err != nil {
@@ -631,7 +611,7 @@
 
 func (r *Runtime) WithNewDispatchingServer(ctx *context.T, name string, disp rpc.Dispatcher, opts ...rpc.ServerOpt) (*context.T, rpc.Server, error) {
 	defer apilog.LogCall(ctx)(ctx) // gologcop: DO NOT EDIT, MUST BE FIRST STATEMENT
-	if TransitionState >= XServers {
+	if ref.RPCTransitionState() >= ref.XServers {
 		// TODO(mattr): Deal with shutdown deps.
 		newctx, spub, sname, opts, err := r.commonServerInit(ctx, opts...)
 		if err != nil {
diff --git a/services/agent/internal/server/sock_len.go b/services/agent/internal/server/sock_len.go
index 7706d58..211bf7d 100644
--- a/services/agent/internal/server/sock_len.go
+++ b/services/agent/internal/server/sock_len.go
@@ -1,3 +1,7 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package server
 
 // #include <sys/un.h>
diff --git a/services/agent/internal/server/sock_len_darwin_test.go b/services/agent/internal/server/sock_len_darwin_test.go
index ca8fc74..87ddbb9 100644
--- a/services/agent/internal/server/sock_len_darwin_test.go
+++ b/services/agent/internal/server/sock_len_darwin_test.go
@@ -1,3 +1,7 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package server
 
 import (
diff --git a/services/agent/internal/server/sock_len_linux_test.go b/services/agent/internal/server/sock_len_linux_test.go
index e592f12..0ec18b1 100644
--- a/services/agent/internal/server/sock_len_linux_test.go
+++ b/services/agent/internal/server/sock_len_linux_test.go
@@ -1,3 +1,7 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
 package server
 
 import (