runtimes/google/naming/namespace: Move parsing server blessing patterns from StartCall into ResolveX.
Also stop parsing the root mounttable blessing pattern, which we're getting rid.

Change-Id: Ic0ade79c5f62977a3016292d62b7d26bc480db16
diff --git a/runtimes/google/ipc/client.go b/runtimes/google/ipc/client.go
index 064f282..544ed1c 100644
--- a/runtimes/google/ipc/client.go
+++ b/runtimes/google/ipc/client.go
@@ -6,7 +6,6 @@
 	"math"
 	"math/rand"
 	"net"
-	"regexp"
 	"strings"
 	"sync"
 	"time"
@@ -86,8 +85,6 @@
 	errBlessingAdd = verror.Register(pkgPath+".blessingAddFailed", verror.NoRetry, "failed to add blessing granted to server {3}{:4}")
 )
 
-var serverPatternRegexp = regexp.MustCompile("^\\[([^\\]]+)\\](.*)")
-
 // TODO(ribrdb): Flip this to true once everything is updated.
 const enableSecureServerAuth = false
 
@@ -366,41 +363,42 @@
 
 // tryCall makes a single attempt at a call, against possibly multiple servers.
 func (c *client) tryCall(ctx context.T, name, method string, args []interface{}, skipResolve bool, opts []ipc.CallOpt) (ipc.Call, verror.ActionCode, verror.E) {
-	mtPattern, serverPattern, name := splitObjectName(name)
 	noDischarges := shouldNotFetchDischarges(opts)
 	// Resolve name unless told not to.
 	var servers []string
+	var pattern security.BlessingPattern
+	var resolveOpts []naming.ResolveOpt
 	if skipResolve {
-		servers = []string{name}
+		resolveOpts = append(resolveOpts, naming.SkipResolveOpt{})
+	} else if noDischarges {
+		resolveOpts = append(resolveOpts, vc.NoDischarges{})
+	}
+
+	if resolved, err := c.ns.ResolveX(ctx, name, resolveOpts...); err != nil {
+		vlog.Errorf("ResolveX: %v", err)
+		if verror.Is(err, naming.ErrNoSuchName.ID) {
+			return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
+		}
+		return nil, verror.NoRetry, verror.Make(verror.NoExist, ctx, name, err)
 	} else {
-		resolveOpts := []naming.ResolveOpt{naming.RootBlessingPatternOpt(mtPattern)}
-		if noDischarges {
-			resolveOpts = append(resolveOpts, vc.NoDischarges{})
+		pattern = security.BlessingPattern(resolved.Pattern)
+		if len(resolved.Servers) == 0 {
+			return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
 		}
-		if resolved, err := c.ns.Resolve(ctx, name, resolveOpts...); err != nil {
-			if verror.Is(err, naming.ErrNoSuchName.ID) {
-				return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
+		// An empty set of protocols means all protocols...
+		ordered, err := filterAndOrderServers(naming.ToStringSlice(resolved), c.preferredProtocols)
+		if err != nil {
+			return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name, err)
+		} else if len(ordered) == 0 {
+			// sooo annoying....
+			r := []interface{}{err}
+			r = append(r, name)
+			for _, s := range resolved.Servers {
+				r = append(r, s)
 			}
-			return nil, verror.NoRetry, verror.Make(verror.NoExist, ctx, name, err)
-		} else {
-			if len(resolved) == 0 {
-				return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name)
-			}
-			// An empty set of protocols means all protocols...
-			ordered, err := filterAndOrderServers(resolved, c.preferredProtocols)
-			if err != nil {
-				return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, name, err)
-			} else if len(ordered) == 0 {
-				// sooo annoying....
-				r := []interface{}{err}
-				r = append(r, name)
-				for _, s := range resolved {
-					r = append(r, s)
-				}
-				return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, r)
-			}
-			servers = ordered
+			return nil, verror.RetryRefetch, verror.Make(verror.NoServers, ctx, r)
 		}
+		servers = ordered
 	}
 
 	// servers is now orderd by the priority heurestic implemented in
@@ -469,7 +467,7 @@
 			if r.flow.LocalPrincipal() != nil {
 				// Validate caveats on the server's identity for the context associated with this call.
 				var err error
-				if serverB, grantedB, err = c.authorizeServer(ctx, r.flow, name, method, serverPattern, opts); err != nil {
+				if serverB, grantedB, err = c.authorizeServer(ctx, r.flow, name, method, pattern, opts); err != nil {
 					r.err = verror.Make(errNotTrusted, ctx,
 						name, r.flow.RemoteBlessings(), err)
 					vlog.VI(2).Infof("ipc: err: %s", r.err)
@@ -915,28 +913,3 @@
 func (fc *flowClient) RemoteBlessings() ([]string, security.Blessings) {
 	return fc.server, fc.flow.RemoteBlessings()
 }
-
-func splitObjectName(name string) (mtPattern, serverPattern security.BlessingPattern, objectName string) {
-	objectName = name
-	match := serverPatternRegexp.FindSubmatch([]byte(name))
-	if match != nil {
-		objectName = string(match[2])
-		if naming.Rooted(objectName) {
-			mtPattern = security.BlessingPattern(match[1])
-		} else {
-			serverPattern = security.BlessingPattern(match[1])
-			return
-		}
-	}
-	if !naming.Rooted(objectName) {
-		return
-	}
-
-	address, relative := naming.SplitAddressName(objectName)
-	match = serverPatternRegexp.FindSubmatch([]byte(relative))
-	if match != nil {
-		serverPattern = security.BlessingPattern(match[1])
-		objectName = naming.JoinAddressName(address, string(match[2]))
-	}
-	return
-}
diff --git a/runtimes/google/ipc/full_test.go b/runtimes/google/ipc/full_test.go
index c796e26..e7a680c 100644
--- a/runtimes/google/ipc/full_test.go
+++ b/runtimes/google/ipc/full_test.go
@@ -1322,44 +1322,6 @@
 	}
 }
 
-func TestSplitObjectName(t *testing.T) {
-	cases := []struct {
-		input, mt, server, name string
-	}{
-		{"[foo/bar]", "", "foo/bar", ""},
-		{"[x/y/...]/", "x/y/...", "", "/"},
-		{"[foo]a", "", "foo", "a"},
-		{"[foo]/a", "foo", "", "/a"},
-		{"[foo]/a/[bar]", "foo", "bar", "/a"},
-		{"a/b", "", "", "a/b"},
-		{"[foo]a/b", "", "foo", "a/b"},
-		{"/a/b", "", "", "/a/b"},
-		{"[foo]/a/b", "foo", "", "/a/b"},
-		{"/a/[bar]b", "", "bar", "/a/b"},
-		{"[foo]/a/[bar]b", "foo", "bar", "/a/b"},
-		{"/a/b[foo]", "", "", "/a/b[foo]"},
-		{"/a/b/[foo]c", "", "", "/a/b/[foo]c"},
-		{"/[01:02::]:444", "", "", "/[01:02::]:444"},
-		{"[foo]/[01:02::]:444", "foo", "", "/[01:02::]:444"},
-		{"/[01:02::]:444/foo", "", "", "/[01:02::]:444/foo"},
-		{"[a]/[01:02::]:444/foo", "a", "", "/[01:02::]:444/foo"},
-		{"/[01:02::]:444/[b]foo", "", "b", "/[01:02::]:444/foo"},
-		{"[c]/[01:02::]:444/[d]foo", "c", "d", "/[01:02::]:444/foo"},
-	}
-	for _, c := range cases {
-		mt, server, name := splitObjectName(c.input)
-		if string(mt) != c.mt {
-			t.Errorf("%q: unexpected mt pattern: %q not %q", c.input, mt, c.mt)
-		}
-		if string(server) != c.server {
-			t.Errorf("%q: unexpected server pattern: %q not %q", c.input, server, c.server)
-		}
-		if name != c.name {
-			t.Errorf("%q: unexpected name: %q not %q", c.input, name, c.name)
-		}
-	}
-}
-
 func TestServerBlessingsOpt(t *testing.T) {
 	var (
 		pserver   = tsecurity.NewPrincipal("server")
diff --git a/runtimes/google/ipc/server.go b/runtimes/google/ipc/server.go
index 1b6a66d..9a44ec4 100644
--- a/runtimes/google/ipc/server.go
+++ b/runtimes/google/ipc/server.go
@@ -145,10 +145,12 @@
 	}
 	var names []string
 	if s.ns != nil {
+		var entry *naming.MountEntry
 		var err error
-		if names, err = s.ns.Resolve(s.ctx, address); err != nil {
+		if entry, err = s.ns.ResolveX(s.ctx, address); err != nil {
 			return "", err
 		}
+		names = naming.ToStringSlice(entry)
 	} else {
 		names = append(names, address)
 	}
diff --git a/runtimes/google/naming/namespace/all_test.go b/runtimes/google/naming/namespace/all_test.go
index 2bb395c..8c1bd07 100644
--- a/runtimes/google/naming/namespace/all_test.go
+++ b/runtimes/google/naming/namespace/all_test.go
@@ -665,7 +665,6 @@
 
 	name := naming.Join(root.name, mt2MP)
 	// First check with a non-matching blessing pattern.
-	println("********")
 	_, err = ns.Resolve(r.NewContext(), name, naming.RootBlessingPatternOpt("root/foobar"))
 	if !verror.Is(err, verror.NotTrusted.ID) {
 		t.Errorf("Resolve expected NotTrusted error, got %v", err)
@@ -681,13 +680,4 @@
 
 	// After successful lookup it should be cached, so the pattern doesn't matter.
 	testResolveWithPattern(t, r, ns, name, naming.RootBlessingPatternOpt("root/foobar"), addWSName(mts[mt2MP].name)...)
-
-	// Test calling a method.
-	jokeName := naming.Join(root.name, mt4MP, j1MP)
-	runServer(t, r, &dispatcher{}, naming.Join(mts["mt4"].name, j1MP))
-	_, err = r.Client().StartCall(r.NewContext(), "[root/foobar]"+jokeName, "KnockKnock", nil)
-	if err == nil {
-		t.Errorf("StartCall expected NoAccess error, got %v", err)
-	}
-	knockKnock(t, r, "[root/server]"+jokeName)
 }
diff --git a/runtimes/google/naming/namespace/glob_test.go b/runtimes/google/naming/namespace/glob_test.go
index 790b459..b85188e 100644
--- a/runtimes/google/naming/namespace/glob_test.go
+++ b/runtimes/google/naming/namespace/glob_test.go
@@ -25,3 +25,41 @@
 		}
 	}
 }
+
+func TestSplitObjectName(t *testing.T) {
+	cases := []struct {
+		input, mt, server, name string
+	}{
+		{"[foo/bar]", "", "foo/bar", ""},
+		{"[x/y/...]/", "x/y/...", "", "/"},
+		{"[foo]a", "", "foo", "a"},
+		{"[foo]/a", "foo", "", "/a"},
+		{"[foo]/a/[bar]", "foo", "bar", "/a"},
+		{"a/b", "", "", "a/b"},
+		{"[foo]a/b", "", "foo", "a/b"},
+		{"/a/b", "", "", "/a/b"},
+		{"[foo]/a/b", "foo", "", "/a/b"},
+		{"/a/[bar]b", "", "bar", "/a/b"},
+		{"[foo]/a/[bar]b", "foo", "bar", "/a/b"},
+		{"/a/b[foo]", "", "", "/a/b[foo]"},
+		{"/a/b/[foo]c", "", "", "/a/b/[foo]c"},
+		{"/[01:02::]:444", "", "", "/[01:02::]:444"},
+		{"[foo]/[01:02::]:444", "foo", "", "/[01:02::]:444"},
+		{"/[01:02::]:444/foo", "", "", "/[01:02::]:444/foo"},
+		{"[a]/[01:02::]:444/foo", "a", "", "/[01:02::]:444/foo"},
+		{"/[01:02::]:444/[b]foo", "", "b", "/[01:02::]:444/foo"},
+		{"[c]/[01:02::]:444/[d]foo", "c", "d", "/[01:02::]:444/foo"},
+	}
+	for _, c := range cases {
+		mt, server, name := splitObjectName(c.input)
+		if string(mt) != c.mt {
+			t.Errorf("%q: unexpected mt pattern: %q not %q", c.input, mt, c.mt)
+		}
+		if string(server) != c.server {
+			t.Errorf("%q: unexpected server pattern: %q not %q", c.input, server, c.server)
+		}
+		if name != c.name {
+			t.Errorf("%q: unexpected name: %q not %q", c.input, name, c.name)
+		}
+	}
+}
diff --git a/runtimes/google/naming/namespace/namespace.go b/runtimes/google/naming/namespace/namespace.go
index 16ec70e..9ddc49d 100644
--- a/runtimes/google/naming/namespace/namespace.go
+++ b/runtimes/google/naming/namespace/namespace.go
@@ -1,12 +1,14 @@
 package namespace
 
 import (
+	"regexp"
 	"sync"
 	"time"
 
 	inaming "veyron.io/veyron/veyron/runtimes/google/naming"
 
 	"veyron.io/veyron/veyron2/naming"
+	"veyron.io/veyron/veyron2/security"
 	"veyron.io/veyron/veyron2/verror"
 	"veyron.io/veyron/veyron2/vlog"
 )
@@ -14,6 +16,8 @@
 const defaultMaxResolveDepth = 32
 const defaultMaxRecursiveGlobDepth = 10
 
+var serverPatternRegexp = regexp.MustCompile("^\\[([^\\]]+)\\](.*)")
+
 // namespace is an implementation of naming.Namespace.
 type namespace struct {
 	sync.RWMutex
@@ -111,7 +115,9 @@
 // rootMountEntry 'roots' a name creating a mount entry for the name.
 func (ns *namespace) rootMountEntry(name string) (*naming.MountEntry, bool) {
 	name = naming.Clean(name)
+	_, objPattern, name := splitObjectName(name)
 	e := new(naming.MountEntry)
+	e.Pattern = string(objPattern)
 	expiration := time.Now().Add(time.Hour) // plenty of time for a call
 	address, suffix := naming.SplitAddressName(name)
 	if len(address) == 0 {
@@ -181,3 +187,28 @@
 	}
 	return nil
 }
+
+func splitObjectName(name string) (mtPattern, serverPattern security.BlessingPattern, objectName string) {
+	objectName = name
+	match := serverPatternRegexp.FindSubmatch([]byte(name))
+	if match != nil {
+		objectName = string(match[2])
+		if naming.Rooted(objectName) {
+			mtPattern = security.BlessingPattern(match[1])
+		} else {
+			serverPattern = security.BlessingPattern(match[1])
+			return
+		}
+	}
+	if !naming.Rooted(objectName) {
+		return
+	}
+
+	address, relative := naming.SplitAddressName(objectName)
+	match = serverPatternRegexp.FindSubmatch([]byte(relative))
+	if match != nil {
+		serverPattern = security.BlessingPattern(match[1])
+		objectName = naming.JoinAddressName(address, string(match[2]))
+	}
+	return
+}
diff --git a/runtimes/google/naming/namespace/resolve.go b/runtimes/google/naming/namespace/resolve.go
index e1c4109..aca359e 100644
--- a/runtimes/google/naming/namespace/resolve.go
+++ b/runtimes/google/naming/namespace/resolve.go
@@ -77,6 +77,9 @@
 		vlog.Infof("ResolveX(%s) called from %s:%d", name, file, line)
 		vlog.Infof("ResolveX(%s) -> rootMountEntry %v", name, *e)
 	}
+	if skipResolve(opts) {
+		return e, nil
+	}
 	if len(e.Servers) == 0 {
 		return nil, verror.Make(naming.ErrNoSuchName, ctx, name)
 	}
@@ -271,6 +274,15 @@
 	return flushed
 }
 
+func skipResolve(opts []naming.ResolveOpt) bool {
+	for _, opt := range opts {
+		if _, ok := opt.(naming.SkipResolveOpt); ok {
+			return true
+		}
+	}
+	return false
+}
+
 func getRootPattern(opts []naming.ResolveOpt) string {
 	for _, opt := range opts {
 		if pattern, ok := opt.(naming.RootBlessingPatternOpt); ok {
diff --git a/runtimes/google/testing/mocks/naming/namespace.go b/runtimes/google/testing/mocks/naming/namespace.go
index e3403e5..d6cdb35 100644
--- a/runtimes/google/testing/mocks/naming/namespace.go
+++ b/runtimes/google/testing/mocks/naming/namespace.go
@@ -10,19 +10,26 @@
 	"veyron.io/veyron/veyron2/naming"
 	verror "veyron.io/veyron/veyron2/verror2"
 	"veyron.io/veyron/veyron2/vlog"
+
+	vnamespace "veyron.io/veyron/veyron/runtimes/google/naming/namespace"
 )
 
 // NewSimpleNamespace returns a simple implementation of a Namespace
 // server for use in tests.  In particular, it ignores TTLs and not
 // allow fully overlapping mount names.
 func NewSimpleNamespace() naming.Namespace {
-	return &namespace{mounts: make(map[string][]string)}
+	ns, err := vnamespace.New()
+	if err != nil {
+		panic(err)
+	}
+	return &namespace{mounts: make(map[string][]string), ns: ns}
 }
 
 // namespace is a simple partial implementation of naming.Namespace.
 type namespace struct {
 	sync.Mutex
 	mounts map[string][]string
+	ns     naming.Namespace
 }
 
 func (ns *namespace) Mount(ctx context.T, name, server string, _ time.Duration, _ ...naming.MountOpt) error {
@@ -79,13 +86,18 @@
 
 func (ns *namespace) ResolveX(ctx context.T, name string, opts ...naming.ResolveOpt) (*naming.MountEntry, error) {
 	defer vlog.LogCall()()
-	e := new(naming.MountEntry)
-	if address, _ := naming.SplitAddressName(name); len(address) > 0 {
-		e.Servers = []naming.MountedServer{naming.MountedServer{Server: name, Expires: time.Now().Add(1000 * time.Hour)}}
+	e, err := ns.ns.ResolveX(ctx, name, naming.SkipResolveOpt{})
+	if err != nil {
+		return e, err
+	}
+	if len(e.Servers) > 0 {
+		e.Servers[0].Server = naming.JoinAddressName(e.Servers[0].Server, e.Name)
+		e.Name = ""
 		return e, nil
 	}
 	ns.Lock()
 	defer ns.Unlock()
+	name = e.Name
 	for prefix, servers := range ns.mounts {
 		if strings.HasPrefix(name, prefix) {
 			e.Name = strings.TrimLeft(strings.TrimPrefix(name, prefix), "/")