blob: 4043d3af38debc856a74f45b114f0fb605bdfb6d [file] [log] [blame]
package namespace_test
import (
"runtime"
"runtime/debug"
"strings"
"sync"
"testing"
"time"
"veyron.io/veyron/veyron2"
"veyron.io/veyron/veyron2/context"
"veyron.io/veyron/veyron2/ipc"
"veyron.io/veyron/veyron2/ipc/stream"
"veyron.io/veyron/veyron2/naming"
"veyron.io/veyron/veyron2/options"
"veyron.io/veyron/veyron2/rt"
"veyron.io/veyron/veyron2/security"
"veyron.io/veyron/veyron2/services/mounttable"
verror "veyron.io/veyron/veyron2/verror2"
"veyron.io/veyron/veyron2/vlog"
"veyron.io/veyron/veyron/lib/glob"
"veyron.io/veyron/veyron/lib/testutil"
"veyron.io/veyron/veyron/lib/websocket"
_ "veyron.io/veyron/veyron/profiles"
"veyron.io/veyron/veyron/runtimes/google/naming/namespace"
vsecurity "veyron.io/veyron/veyron/security"
service "veyron.io/veyron/veyron/services/mounttable/lib"
)
func init() {
testutil.Init()
stream.RegisterProtocol("ws", websocket.Dial, nil)
}
func createRuntimes(t *testing.T) (sr, r veyron2.Runtime, cleanup func()) {
var err error
// Create a runtime for the server.
sr, err = rt.New()
if err != nil {
t.Fatalf("Could not initialize runtime: %v", err)
}
// We use a different runtime for the client side.
r, err = rt.New()
if err != nil {
t.Fatalf("Could not initialize runtime: %v", err)
}
return sr, r, func() {
sr.Cleanup()
r.Cleanup()
}
}
func boom(t *testing.T, f string, v ...interface{}) {
t.Logf(f, v...)
t.Fatal(string(debug.Stack()))
}
func addWSName(name string) []string {
return []string{name, strings.Replace(name, "@tcp@", "@ws@", 1)}
}
// N squared but who cares, this is a little test.
// Ignores dups.
func contains(container, contained []string) bool {
L:
for _, d := range contained {
for _, r := range container {
if r == d {
continue L
}
}
return false
}
return true
}
func compare(t *testing.T, caller, name string, got, want []string) {
// Compare ignoring dups.
if !contains(got, want) || !contains(want, got) {
boom(t, "%s: %q: got %v, want %v", caller, name, got, want)
}
}
func doGlob(t *testing.T, r veyron2.Runtime, ns naming.Namespace, pattern string, limit int) []string {
var replies []string
rc, err := ns.Glob(r.NewContext(), pattern)
if err != nil {
boom(t, "Glob(%s): %s", pattern, err)
}
for s := range rc {
replies = append(replies, s.Name)
if limit > 0 && len(replies) > limit {
boom(t, "Glob returns too many results, perhaps not limiting recursion")
}
}
return replies
}
type testServer struct {
suffix string
}
func (testServer) KnockKnock(ctx ipc.ServerContext) string {
return "Who's there?"
}
// Glob applies pattern to the following tree:
// "" -> {level1} -> {level2}
// "".Glob("*") returns "level1"
// "".Glob("...") returns "level1" and "level1/level2"
// "level1".Glob("*") returns "level2"
func (t *testServer) Glob(ctx *ipc.GlobContextStub, pattern string) error {
g, err := glob.Parse(pattern)
if err != nil {
return err
}
tree := []string{"", "level1", "level2"}
for i, leaf := range tree {
if leaf == t.suffix {
return t.globLoop(ctx, "", g, tree[i+1:])
}
}
return nil
}
func (t *testServer) globLoop(ctx *ipc.GlobContextStub, prefix string, g *glob.Glob, tree []string) error {
if g.Len() == 0 {
if err := ctx.SendStream().Send(naming.VDLMountEntry{Name: prefix}); err != nil {
return err
}
}
if g.Finished() || len(tree) == 0 {
return nil
}
if ok, _, left := g.MatchInitialSegment(tree[0]); ok {
if err := t.globLoop(ctx, naming.Join(prefix, tree[0]), left, tree[1:]); err != nil {
return err
}
}
return nil
}
type allowEveryoneAuthorizer struct{}
func (allowEveryoneAuthorizer) Authorize(security.Context) error { return nil }
type dispatcher struct{}
func (d *dispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
return &testServer{suffix}, allowEveryoneAuthorizer{}, nil
}
func knockKnock(t *testing.T, runtime veyron2.Runtime, name string) {
client := runtime.Client()
ctx := runtime.NewContext()
call, err := client.StartCall(ctx, name, "KnockKnock", nil)
if err != nil {
boom(t, "StartCall failed: %s", err)
}
var result string
if err := call.Finish(&result); err != nil {
boom(t, "Finish returned an error: %s", err)
}
if result != "Who's there?" {
boom(t, "Wrong result: %v", result)
}
}
func doResolveTest(t *testing.T, fname string, f func(context.T, string, ...naming.ResolveOpt) ([]string, error), ctx context.T, name string, want []string, opts ...naming.ResolveOpt) {
servers, err := f(ctx, name, opts...)
if err != nil {
boom(t, "Failed to %s %s: %s", fname, name, err)
}
compare(t, fname, name, servers, want)
}
func testResolveToMountTable(t *testing.T, r veyron2.Runtime, ns naming.Namespace, name string, want ...string) {
doResolveTest(t, "ResolveToMountTable", ns.ResolveToMountTable, r.NewContext(), name, want)
}
func testResolveToMountTableWithPattern(t *testing.T, r veyron2.Runtime, ns naming.Namespace, name string, pattern naming.ResolveOpt, want ...string) {
doResolveTest(t, "ResolveToMountTable", ns.ResolveToMountTable, r.NewContext(), name, want, pattern)
}
func testResolve(t *testing.T, r veyron2.Runtime, ns naming.Namespace, name string, want ...string) {
doResolveTest(t, "Resolve", ns.Resolve, r.NewContext(), name, want)
}
func testResolveWithPattern(t *testing.T, r veyron2.Runtime, ns naming.Namespace, name string, pattern naming.ResolveOpt, want ...string) {
doResolveTest(t, "Resolve", ns.Resolve, r.NewContext(), name, want, pattern)
}
func testUnresolve(t *testing.T, r veyron2.Runtime, ns naming.Namespace, name string, want ...string) {
servers, err := ns.Unresolve(r.NewContext(), name)
if err != nil {
boom(t, "Failed to Resolve %q: %s", name, err)
}
compare(t, "Unresolve", name, servers, want)
}
type serverEntry struct {
mountPoint string
server ipc.Server
endpoint naming.Endpoint
name string
}
func runServer(t *testing.T, sr veyron2.Runtime, disp ipc.Dispatcher, mountPoint string) *serverEntry {
return run(t, sr, disp, mountPoint, false)
}
func runMT(t *testing.T, sr veyron2.Runtime, mountPoint string) *serverEntry {
mt, err := service.NewMountTable("")
if err != nil {
boom(t, "NewMountTable returned error: %v", err)
}
return run(t, sr, mt, mountPoint, true)
}
func run(t *testing.T, sr veyron2.Runtime, disp ipc.Dispatcher, mountPoint string, mt bool) *serverEntry {
s, err := sr.NewServer(options.ServesMountTable(mt))
if err != nil {
boom(t, "r.NewServer: %s", err)
}
// Add a mount table server.
// Start serving on a loopback address.
ep, err := s.Listen(ipc.ListenSpec{Protocol: "tcp", Address: "127.0.0.1:0"})
if err != nil {
boom(t, "Failed to Listen: %s", err)
}
if err := s.ServeDispatcher(mountPoint, disp); err != nil {
boom(t, "Failed to serve mount table at %s: %s", mountPoint, err)
}
name := naming.JoinAddressName(ep.String(), "")
return &serverEntry{mountPoint: mountPoint, server: s, endpoint: ep, name: name}
}
const (
mt1MP = "mt1"
mt2MP = "mt2"
mt3MP = "mt3"
mt4MP = "mt4"
mt5MP = "mt5"
j1MP = "joke1"
j2MP = "joke2"
j3MP = "joke3"
ttl = 100 * time.Second
)
// runMountTables creates a root mountable with some mount tables mounted
// in it: mt{1,2,3,4,5}
func runMountTables(t *testing.T, r veyron2.Runtime) (*serverEntry, map[string]*serverEntry) {
root := runMT(t, r, "")
r.Namespace().SetRoots(root.name)
t.Logf("mountTable %q -> %s", root.mountPoint, root.endpoint)
mps := make(map[string]*serverEntry)
for _, mp := range []string{mt1MP, mt2MP, mt3MP, mt4MP, mt5MP} {
m := runMT(t, r, mp)
t.Logf("mountTable %q -> %s", mp, m.endpoint)
mps[mp] = m
}
return root, mps
}
// createNamespace creates a hierarchy of mounttables and servers
// as follows:
// /mt1, /mt2, /mt3, /mt4, /mt5, /joke1, /joke2, /joke3.
// That is, mt1 is a mount table mounted in the root mount table,
// joke1 is a server mounted in the root mount table.
func createNamespace(t *testing.T, r veyron2.Runtime) (*serverEntry, map[string]*serverEntry, map[string]*serverEntry, func()) {
root, mts := runMountTables(t, r)
jokes := make(map[string]*serverEntry)
// Let's run some non-mount table services.
for _, j := range []string{j1MP, j2MP, j3MP} {
disp := &dispatcher{}
jokes[j] = runServer(t, r, disp, j)
}
return root, mts, jokes, func() {
for _, s := range jokes {
s.server.Stop()
}
for _, s := range mts {
s.server.Stop()
}
root.server.Stop()
}
}
// runNestedMountTables creates some nested mount tables in the hierarchy
// created by createNamespace as follows:
// /mt4/foo, /mt4/foo/bar and /mt4/baz where foo, bar and baz are mount tables.
func runNestedMountTables(t *testing.T, r veyron2.Runtime, mts map[string]*serverEntry) {
ns, ctx := r.Namespace(), r.NewContext()
// Set up some nested mounts and verify resolution.
for _, m := range []string{"mt4/foo", "mt4/foo/bar"} {
mts[m] = runMT(t, r, m)
}
// Use a global name for a mount, rather than a relative one.
// We directly mount baz into the mt4/foo mount table.
globalMP := naming.JoinAddressName(mts["mt4/foo"].name, "baz")
mts["baz"] = runMT(t, r, "baz")
if err := ns.Mount(ctx, globalMP, mts["baz"].name, ttl); err != nil {
boom(t, "Failed to Mount %s: %s", globalMP, err)
}
}
// TestNamespaceCommon tests common use of the Namespace library
// against a root mount table and some mount tables mounted on it.
func TestNamespaceCommon(t *testing.T) {
_, r, cleanup := createRuntimes(t)
defer cleanup()
root, mts, jokes, stopper := createNamespace(t, r)
defer stopper()
ns := r.Namespace()
// All of the initial mounts are served by the root mounttable
// and hence ResolveToMountTable should return the root mountable
// as the address portion of the terminal name for those mounttables.
testResolveToMountTable(t, r, ns, "", root.name)
for _, m := range []string{mt2MP, mt3MP, mt5MP} {
rootMT := naming.Join(root.name, m)
// All of these mount tables are hosted by the root mount table
testResolveToMountTable(t, r, ns, m, rootMT)
// The server registered for each mount point is a mount table
testResolve(t, r, ns, m, addWSName(mts[m].name)...)
// ResolveToMountTable will walk through to the sub MountTables
mtbar := naming.Join(m, "bar")
subMT := naming.Join(mts[m].name, "bar")
testResolveToMountTable(t, r, ns, mtbar, addWSName(subMT)...)
}
for _, j := range []string{j1MP, j2MP, j3MP} {
testResolve(t, r, ns, j, addWSName(jokes[j].name)...)
}
}
// TestNamespaceDetails tests more detailed use of the Namespace library,
// including the intricacies of // meaning and placement.
func TestNamespaceDetails(t *testing.T) {
sr, r, cleanup := createRuntimes(t)
defer cleanup()
root, mts, _, stopper := createNamespace(t, sr)
defer stopper()
ns := r.Namespace()
ns.SetRoots(root.name)
// /mt2 is not an endpoint. Thus, the example below will fail.
mt3Server := mts[mt3MP].name
mt2a := "/mt2/a"
if err := ns.Mount(r.NewContext(), mt2a, mt3Server, ttl); verror.Is(err, naming.ErrNoSuchName.ID) {
boom(t, "Successfully mounted %s - expected an err %v, not %v", mt2a, naming.ErrNoSuchName, err)
}
// Mount using the relative name.
// This means walk through mt2 if it already exists and mount within
// the lower level mount table, if the name doesn't exist we'll create
// a new name for it.
mt2a = "mt2/a"
if err := ns.Mount(r.NewContext(), mt2a, mt3Server, ttl); err != nil {
boom(t, "Failed to Mount %s: %s", mt2a, err)
}
mt2mt := naming.Join(mts[mt2MP].name, "a")
// The mt2/a is served by the mt2 mount table
testResolveToMountTable(t, r, ns, mt2a, addWSName(mt2mt)...)
// The server for mt2a is mt3server from the second mount above.
testResolve(t, r, ns, mt2a, mt3Server)
// Add two more mounts. The // should be stripped off of the
// second.
for _, mp := range []struct{ name, server string }{
{"mt2", mts[mt4MP].name},
{"mt2//", mts[mt5MP].name},
} {
if err := ns.Mount(r.NewContext(), mp.name, mp.server, ttl, naming.ServesMountTableOpt(true)); err != nil {
boom(t, "Failed to Mount %s: %s", mp.name, err)
}
}
names := []string{naming.JoinAddressName(mts[mt4MP].name, "a"),
naming.JoinAddressName(mts[mt5MP].name, "a")}
names = append(names, addWSName(naming.JoinAddressName(mts[mt2MP].name, "a"))...)
// We now have 3 mount tables prepared to serve mt2/a
testResolveToMountTable(t, r, ns, "mt2/a", names...)
names = []string{mts[mt4MP].name, mts[mt5MP].name}
names = append(names, addWSName(mts[mt2MP].name)...)
testResolve(t, r, ns, "mt2", names...)
}
// TestNestedMounts tests some more deeply nested mounts
func TestNestedMounts(t *testing.T) {
sr, r, cleanup := createRuntimes(t)
defer cleanup()
root, mts, _, stopper := createNamespace(t, sr)
runNestedMountTables(t, sr, mts)
defer stopper()
ns := r.Namespace()
ns.SetRoots(root.name)
// Set up some nested mounts and verify resolution.
for _, m := range []string{"mt4/foo", "mt4/foo/bar"} {
testResolve(t, r, ns, m, addWSName(mts[m].name)...)
}
testResolveToMountTable(t, r, ns, "mt4/foo",
addWSName(naming.JoinAddressName(mts[mt4MP].name, "foo"))...)
testResolveToMountTable(t, r, ns, "mt4/foo/bar",
addWSName(naming.JoinAddressName(mts["mt4/foo"].name, "bar"))...)
testResolveToMountTable(t, r, ns, "mt4/foo/baz",
addWSName(naming.JoinAddressName(mts["mt4/foo"].name, "baz"))...)
}
// TestServers tests invoking RPCs on simple servers
func TestServers(t *testing.T) {
sr, r, cleanup := createRuntimes(t)
defer cleanup()
root, mts, jokes, stopper := createNamespace(t, sr)
defer stopper()
ns := r.Namespace()
ns.SetRoots(root.name)
// Let's run some non-mount table services
for _, j := range []string{j1MP, j2MP, j3MP} {
testResolve(t, r, ns, j, addWSName(jokes[j].name)...)
knockKnock(t, r, j)
globalName := naming.JoinAddressName(mts["mt4"].name, j)
disp := &dispatcher{}
gj := "g_" + j
jokes[gj] = runServer(t, r, disp, globalName)
testResolve(t, r, ns, "mt4/"+j, addWSName(jokes[gj].name)...)
knockKnock(t, r, "mt4/"+j)
testResolveToMountTable(t, r, ns, "mt4/"+j, addWSName(globalName)...)
testResolveToMountTable(t, r, ns, "mt4/"+j+"/garbage", addWSName(globalName+"/garbage")...)
}
}
// TestGlob tests some glob patterns.
func TestGlob(t *testing.T) {
sr, r, cleanup := createRuntimes(t)
defer cleanup()
root, mts, _, stopper := createNamespace(t, sr)
runNestedMountTables(t, sr, mts)
defer stopper()
ns := r.Namespace()
ns.SetRoots(root.name)
tln := []string{"baz", "mt1", "mt2", "mt3", "mt4", "mt5", "joke1", "joke2", "joke3"}
barbaz := []string{"mt4/foo/bar", "mt4/foo/baz"}
level12 := []string{"joke1/level1", "joke1/level1/level2", "joke2/level1", "joke2/level1/level2", "joke3/level1", "joke3/level1/level2"}
foo := append([]string{"mt4/foo"}, barbaz...)
foo = append(foo, level12...)
// Try various globs.
globTests := []struct {
pattern string
expected []string
}{
{"*", tln},
{"x", []string{}},
{"m*", []string{"mt1", "mt2", "mt3", "mt4", "mt5"}},
{"mt[2,3]", []string{"mt2", "mt3"}},
{"*z", []string{"baz"}},
{"joke1/*", []string{"joke1/level1"}},
{"j?ke1/level1/*", []string{"joke1/level1/level2"}},
{"joke1/level1/*", []string{"joke1/level1/level2"}},
{"joke1/level1/level2/...", []string{"joke1/level1/level2"}},
{"...", append(append(tln, foo...), "")},
{"*/...", append(tln, foo...)},
{"*/foo/*", barbaz},
{"*/*/*z", []string{"mt4/foo/baz"}},
{"*/f??/*z", []string{"mt4/foo/baz"}},
{"mt4/foo/baz", []string{"mt4/foo/baz"}},
}
for _, test := range globTests {
out := doGlob(t, r, ns, test.pattern, 0)
compare(t, "Glob", test.pattern, out, test.expected)
// Do the same with a full rooted name.
out = doGlob(t, r, ns, naming.JoinAddressName(root.name, test.pattern), 0)
var expectedWithRoot []string
for _, s := range test.expected {
expectedWithRoot = append(expectedWithRoot, naming.JoinAddressName(root.name, s))
}
compare(t, "Glob", test.pattern, out, expectedWithRoot)
}
}
type GlobbableServer struct {
callCount int
mu sync.Mutex
}
func (g *GlobbableServer) Glob(ipc.GlobContext, string) error {
g.mu.Lock()
defer g.mu.Unlock()
g.callCount++
return nil
}
func (g *GlobbableServer) GetAndResetCount() int {
g.mu.Lock()
defer g.mu.Unlock()
cnt := g.callCount
g.callCount = 0
return cnt
}
// TestGlobEarlyStop tests that Glob doesn't query terminal servers with finished patterns.
func TestGlobEarlyStop(t *testing.T) {
sr, r, cleanup := createRuntimes(t)
defer cleanup()
root, mts, _, stopper := createNamespace(t, sr)
runNestedMountTables(t, sr, mts)
defer stopper()
globServer := &GlobbableServer{}
name := naming.JoinAddressName(mts["mt4/foo/bar"].name, "glob")
runningGlobServer := runServer(t, r, ipc.LeafDispatcher(mounttable.GlobbableServer(globServer), nil), name)
defer runningGlobServer.server.Stop()
ns := r.Namespace()
ns.SetRoots(root.name)
tests := []struct {
pattern string
expectedCalls int
expected []string
}{
{"mt4/foo/bar/glob", 0, []string{"mt4/foo/bar/glob"}},
{"mt4/foo/bar/glob/...", 1, []string{"mt4/foo/bar/glob"}},
{"mt4/foo/bar/glob/*", 1, nil},
{"mt4/foo/bar/***", 0, []string{"mt4/foo/bar", "mt4/foo/bar/glob"}},
{"mt4/foo/bar/...", 1, []string{"mt4/foo/bar", "mt4/foo/bar/glob"}},
{"mt4/foo/bar/*", 0, []string{"mt4/foo/bar/glob"}},
{"mt4/***/bar/***", 0, []string{"mt4/foo/bar", "mt4/foo/bar/glob"}},
{"mt4/*/bar/***", 0, []string{"mt4/foo/bar", "mt4/foo/bar/glob"}},
}
// Test allowing the tests to descend into leaves.
for _, test := range tests {
out := doGlob(t, r, ns, test.pattern, 0)
compare(t, "Glob", test.pattern, out, test.expected)
if calls := globServer.GetAndResetCount(); calls != test.expectedCalls {
boom(t, "Wrong number of Glob calls to terminal server got: %d want: %d.", calls, test.expectedCalls)
}
}
}
func TestCycles(t *testing.T) {
sr, r, cleanup := createRuntimes(t)
defer cleanup()
root, _, _, stopper := createNamespace(t, sr)
defer stopper()
ns := r.Namespace()
ns.SetRoots(root.name)
c1 := runMT(t, r, "c1")
c2 := runMT(t, r, "c2")
c3 := runMT(t, r, "c3")
defer c1.server.Stop()
defer c2.server.Stop()
defer c3.server.Stop()
m := "c1/c2"
if err := ns.Mount(r.NewContext(), m, c1.name, ttl, naming.ServesMountTableOpt(true)); err != nil {
boom(t, "Failed to Mount %s: %s", "c1/c2", err)
}
m = "c1/c2/c3"
if err := ns.Mount(r.NewContext(), m, c3.name, ttl, naming.ServesMountTableOpt(true)); err != nil {
boom(t, "Failed to Mount %s: %s", m, err)
}
m = "c1/c3/c4"
if err := ns.Mount(r.NewContext(), m, c1.name, ttl, naming.ServesMountTableOpt(true)); err != nil {
boom(t, "Failed to Mount %s: %s", m, err)
}
// Since c1 was mounted with the Serve call, it will have both the tcp and ws endpoints.
testResolve(t, r, ns, "c1", addWSName(c1.name)...)
testResolve(t, r, ns, "c1/c2", c1.name)
testResolve(t, r, ns, "c1/c3", c3.name)
testResolve(t, r, ns, "c1/c3/c4", c1.name)
testResolve(t, r, ns, "c1/c3/c4/c3/c4", c1.name)
cycle := "c3/c4"
for i := 0; i < 40; i++ {
cycle += "/c3/c4"
}
if _, err := ns.Resolve(r.NewContext(), "c1/"+cycle); !verror.Is(err, naming.ErrResolutionDepthExceeded.ID) {
boom(t, "Failed to detect cycle")
}
// Perform the glob with a response length limit.
doGlob(t, r, ns, "c1/...", 1000)
}
func TestUnresolve(t *testing.T) {
// TODO(cnicolaou): move unresolve tests into this test, right now,
// that's annoying because the stub compiler has some blocking bugs and the
// Unresolve functionality is partially implemented in the stubs.
t.Skip()
sr, r, cleanup := createRuntimes(t)
defer cleanup()
root, mts, jokes, stopper := createNamespace(t, sr)
runNestedMountTables(t, sr, mts)
defer stopper()
ns := r.Namespace()
ns.SetRoots(root.name)
vlog.Infof("Glob: %v", doGlob(t, r, ns, "*", 0))
testResolve(t, r, ns, "joke1", jokes["joke1"].name)
testUnresolve(t, r, ns, "joke1", "")
}
// TestGoroutineLeaks tests for leaking goroutines - we have many:-(
func TestGoroutineLeaks(t *testing.T) {
t.Skip()
sr, _, cleanup := createRuntimes(t)
defer cleanup()
_, _, _, stopper := createNamespace(t, sr)
defer func() {
vlog.Infof("%d goroutines:", runtime.NumGoroutine())
}()
defer stopper()
defer func() {
vlog.Infof("%d goroutines:", runtime.NumGoroutine())
}()
//panic("this will show up lots of goroutine+channel leaks!!!!")
}
func TestBadRoots(t *testing.T) {
_, r, cleanup := createRuntimes(t)
defer cleanup()
if _, err := namespace.New(r); err != nil {
t.Errorf("namespace.New should not have failed with no roots")
}
if _, err := namespace.New(r, "not a rooted name"); err == nil {
t.Errorf("namespace.New should have failed with an unrooted name")
}
}
func bless(blesser, delegate security.Principal, extension string) {
b, err := blesser.Bless(delegate.PublicKey(), blesser.BlessingStore().Default(), extension, security.UnconstrainedUse())
if err != nil {
panic(err)
}
delegate.BlessingStore().SetDefault(b)
}
func TestRootBlessing(t *testing.T) {
r, cr, cleanup := createRuntimes(t)
defer cleanup()
proot, err := vsecurity.NewPrincipal()
if err != nil {
panic(err)
}
b, err := proot.BlessSelf("root")
if err != nil {
panic(err)
}
proot.BlessingStore().SetDefault(b)
bless(proot, r.Principal(), "server")
bless(proot, cr.Principal(), "client")
cr.Principal().AddToRoots(proot.BlessingStore().Default())
r.Principal().AddToRoots(proot.BlessingStore().Default())
root, mts, _, stopper := createNamespace(t, r)
defer stopper()
ns := r.Namespace()
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)
}
_, err = ns.ResolveToMountTable(r.NewContext(), name, naming.RootBlessingPatternOpt("root/foobar"))
if !verror.Is(err, verror.NotTrusted.ID) {
t.Errorf("ResolveToMountTable expected NotTrusted error, got %v", err)
}
// Now check a matching pattern.
testResolveWithPattern(t, r, ns, name, naming.RootBlessingPatternOpt("root/server"), addWSName(mts[mt2MP].name)...)
testResolveToMountTableWithPattern(t, r, ns, name, naming.RootBlessingPatternOpt("root/server"), name)
// 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)
}