blob: a27c68e217fface59202ebca9a74dc8d35b92cac [file] [log] [blame]
Jiri Simsad7616c92015-03-24 23:44:30 -07001// Copyright 2015 The Vanadium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
Cosmos Nicolaou4e029972014-06-13 14:53:08 -07005package namespace_test
Jiri Simsa5293dcb2014-05-10 09:56:38 -07006
7import (
Asim Shankar263c73b2015-03-19 18:31:26 -07008 "fmt"
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -07009 "runtime"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070010 "runtime/debug"
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -070011 "sync"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070012 "testing"
13 "time"
14
Jiri Simsa6ac95222015-02-23 16:11:49 -080015 "v.io/v23"
16 "v.io/v23/context"
Todd Wang5082a552015-04-02 10:56:11 -070017 "v.io/v23/namespace"
Jiri Simsa6ac95222015-02-23 16:11:49 -080018 "v.io/v23/naming"
19 "v.io/v23/options"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070020 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080021 "v.io/v23/security"
22 "v.io/v23/verror"
Jiri Simsa337af232015-02-27 14:36:46 -080023 "v.io/x/lib/vlog"
Cosmos Nicolaouf889c732014-10-16 20:46:54 -070024
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -070025 "v.io/x/ref/lib/xrpc"
Suharsh Sivakumardcc11d72015-05-11 12:19:20 -070026 _ "v.io/x/ref/runtime/factories/generic"
27 inamespace "v.io/x/ref/runtime/internal/naming/namespace"
Todd Wang5987a942015-04-06 11:06:17 -070028 "v.io/x/ref/services/mounttable/mounttablelib"
Todd Wang5082a552015-04-02 10:56:11 -070029 "v.io/x/ref/test"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070030 "v.io/x/ref/test/testutil"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070031)
32
Suharsh Sivakumard19c95d2015-02-19 14:44:50 -080033//go:generate v23 test generate
Asim Shankarc920db32014-10-16 19:18:21 -070034
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -070035func resolveWithRetry(ctx *context.T, name string, opts ...naming.NamespaceOpt) *naming.MountEntry {
36 ns := v23.GetNamespace(ctx)
37 for {
38 mp, err := ns.Resolve(ctx, name, opts...)
39 if err == nil {
40 return mp
41 }
42 time.Sleep(100 * time.Millisecond)
43 }
44}
45
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -080046func createContexts(t *testing.T) (sc, c *context.T, cleanup func()) {
Todd Wang60052d82015-05-22 15:00:10 -070047 ctx, shutdown := test.V23Init()
Asim Shankarb547ea92015-02-17 18:49:45 -080048 var (
49 err error
Asim Shankar4a698282015-03-21 21:59:18 -070050 psc = testutil.NewPrincipal("sc")
51 pc = testutil.NewPrincipal("c")
Asim Shankarb547ea92015-02-17 18:49:45 -080052 )
53 // Setup the principals so that they recognize each other.
54 if err := psc.AddToRoots(pc.BlessingStore().Default()); err != nil {
Ankurfb9255a2015-01-21 15:29:38 -080055 t.Fatal(err)
56 }
Asim Shankarb547ea92015-02-17 18:49:45 -080057 if err := pc.AddToRoots(psc.BlessingStore().Default()); err != nil {
58 t.Fatal(err)
59 }
Todd Wangad492042015-04-17 15:58:40 -070060 if sc, err = v23.WithPrincipal(ctx, psc); err != nil {
Asim Shankarb547ea92015-02-17 18:49:45 -080061 t.Fatal(err)
62 }
Todd Wangad492042015-04-17 15:58:40 -070063 if c, err = v23.WithPrincipal(ctx, pc); err != nil {
Ankurfb9255a2015-01-21 15:29:38 -080064 t.Fatal(err)
65 }
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -080066 return sc, c, shutdown
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -080067}
68
Jiri Simsa5293dcb2014-05-10 09:56:38 -070069func boom(t *testing.T, f string, v ...interface{}) {
70 t.Logf(f, v...)
71 t.Fatal(string(debug.Stack()))
72}
73
David Why Use Two When One Will Do Presottocce8f4f2014-09-30 14:50:44 -070074// N squared but who cares, this is a little test.
75// Ignores dups.
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -070076func contains(container, contained []string) (string, bool) {
David Why Use Two When One Will Do Presottocce8f4f2014-09-30 14:50:44 -070077L:
78 for _, d := range contained {
79 for _, r := range container {
80 if r == d {
81 continue L
82 }
83 }
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -070084 return d, false
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -070085 }
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -070086 return "", true
David Why Use Two When One Will Do Presottocce8f4f2014-09-30 14:50:44 -070087}
88
89func compare(t *testing.T, caller, name string, got, want []string) {
90 // Compare ignoring dups.
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -070091 a, foundA := contains(got, want)
92 b, foundB := contains(want, got)
93 if !foundA {
94 vlog.Infof("%s: %q: failed to find %q: got %v, want %v", caller, name, a, got, want)
95 boom(t, "%s: %q: failed to find %q: got %v, want %v", caller, name, a, got, want)
96 }
97 if !foundB {
98 vlog.Infof("%s: %q: failed to find %q: got %v, want %v", caller, name, a, got, want)
99 boom(t, "%s: %q: failed to find %q: got %v, want %v", caller, name, b, got, want)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700100 }
101}
102
Todd Wang5082a552015-04-02 10:56:11 -0700103func doGlob(t *testing.T, ctx *context.T, ns namespace.T, pattern string, limit int) []string {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700104 var replies []string
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700105
106 sctx, done := context.WithTimeout(ctx, 2*time.Minute)
107 defer done()
108 rc, err := ns.Glob(sctx, pattern)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700109 if err != nil {
110 boom(t, "Glob(%s): %s", pattern, err)
111 }
112 for s := range rc {
David Why Use Two When One Will Do Presotto03c34d62015-02-10 01:38:58 -0800113 switch v := s.(type) {
James Ringc971dca2015-04-09 09:51:20 -0700114 case *naming.GlobReplyEntry:
115 replies = append(replies, v.Value.Name)
David Why Use Two When One Will Do Presotto03c34d62015-02-10 01:38:58 -0800116 if limit > 0 && len(replies) > limit {
117 boom(t, "Glob returns too many results, perhaps not limiting recursion")
118 }
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700119 case *naming.GlobReplyError:
120 boom(t, "Glob failed at %q: %v", v.Value.Name, v.Value.Error)
David Why Use Two When One Will Do Presotto2db32f92014-07-18 12:20:35 -0700121 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700122 }
123 return replies
124}
125
Robin Thellend434e39f2014-08-27 14:46:27 -0700126type testServer struct {
127 suffix string
128}
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700129
Todd Wang54feabe2015-04-15 23:38:26 -0700130func (testServer) KnockKnock(*context.T, rpc.ServerCall) (string, error) {
Todd Wange77f9952015-02-18 13:20:50 -0800131 return "Who's there?", nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700132}
133
Robin Thellend39ac3232014-12-02 09:50:41 -0800134// testServer has the following namespace:
Robin Thellend434e39f2014-08-27 14:46:27 -0700135// "" -> {level1} -> {level2}
Todd Wang54feabe2015-04-15 23:38:26 -0700136func (t *testServer) GlobChildren__(*context.T, rpc.ServerCall) (<-chan string, error) {
Robin Thellend39ac3232014-12-02 09:50:41 -0800137 ch := make(chan string, 1)
138 switch t.suffix {
139 case "":
140 ch <- "level1"
141 case "level1":
142 ch <- "level2"
143 default:
144 return nil, nil
Robin Thellend434e39f2014-08-27 14:46:27 -0700145 }
Robin Thellend39ac3232014-12-02 09:50:41 -0800146 close(ch)
147 return ch, nil
Robin Thellend434e39f2014-08-27 14:46:27 -0700148}
149
150type dispatcher struct{}
151
Robin Thellenda02fe8f2014-11-19 09:58:29 -0800152func (d *dispatcher) Lookup(suffix string) (interface{}, security.Authorizer, error) {
Asim Shankar149b4972015-04-23 13:29:58 -0700153 return &testServer{suffix}, security.AllowEveryone(), nil
Robin Thellend434e39f2014-08-27 14:46:27 -0700154}
155
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800156func knockKnock(t *testing.T, ctx *context.T, name string) {
Jiri Simsa6ac95222015-02-23 16:11:49 -0800157 client := v23.GetClient(ctx)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700158 var result string
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700159 if err := client.Call(ctx, name, "KnockKnock", nil, []interface{}{&result}); err != nil {
160 boom(t, "Call failed: %s", err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700161 }
162 if result != "Who's there?" {
163 boom(t, "Wrong result: %v", result)
164 }
165}
166
David Why Use Two When One Will Do Presotto38788d42015-03-31 17:13:54 -0700167func doResolveTest(t *testing.T, fname string, f func(*context.T, string, ...naming.NamespaceOpt) (*naming.MountEntry, error), ctx *context.T, name string, want []string, opts ...naming.NamespaceOpt) {
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700168 maxretries := 5
169 var lastErr error
170 for i := 0; i < maxretries; i++ {
171 me, err := f(ctx, name, opts...)
172 if err == nil {
173 if i > 0 {
174 t.Logf("doResolveTest: retried %d times", i)
175 }
176 compare(t, fname, name, me.Names(), want)
177 return
178 }
179 if err != nil && verror.Action(err).RetryAction() != 0 {
180 boom(t, "Failed to %s %s: %s, attempt %d", fname, name, err, i)
181 }
182 lastErr = err
Ryan Brownbc2c87c2014-11-17 18:55:25 +0000183 }
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700184 boom(t, "Failed to %s %s: %s after %d attempts", fname, name, lastErr, maxretries)
Ryan Brownfc290142014-11-24 15:47:24 -0800185}
186
Todd Wang5082a552015-04-02 10:56:11 -0700187func testResolveToMountTable(t *testing.T, ctx *context.T, ns namespace.T, name string, want ...string) {
David Why Use Two When One Will Do Presotto8de85852015-01-21 11:05:09 -0800188 doResolveTest(t, "ResolveToMountTable", ns.ResolveToMountTable, ctx, name, want)
Ryan Brownfc290142014-11-24 15:47:24 -0800189}
190
Todd Wang5082a552015-04-02 10:56:11 -0700191func testResolveToMountTableWithPattern(t *testing.T, ctx *context.T, ns namespace.T, name string, pattern naming.NamespaceOpt, want ...string) {
David Why Use Two When One Will Do Presotto8de85852015-01-21 11:05:09 -0800192 doResolveTest(t, "ResolveToMountTable", ns.ResolveToMountTable, ctx, name, want, pattern)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700193}
194
Todd Wang5082a552015-04-02 10:56:11 -0700195func testResolve(t *testing.T, ctx *context.T, ns namespace.T, name string, want ...string) {
David Why Use Two When One Will Do Presotto8de85852015-01-21 11:05:09 -0800196 doResolveTest(t, "Resolve", ns.Resolve, ctx, name, want)
Ryan Brownfc290142014-11-24 15:47:24 -0800197}
198
Todd Wang5082a552015-04-02 10:56:11 -0700199func testResolveWithPattern(t *testing.T, ctx *context.T, ns namespace.T, name string, pattern naming.NamespaceOpt, want ...string) {
David Why Use Two When One Will Do Presotto8de85852015-01-21 11:05:09 -0800200 doResolveTest(t, "Resolve", ns.Resolve, ctx, name, want, pattern)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700201}
202
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700203type serverEntry struct {
204 mountPoint string
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700205 stop func() error
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700206 endpoint naming.Endpoint
207 name string
208}
209
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700210func runServer(t *testing.T, ctx *context.T, disp rpc.Dispatcher, mountPoint string) *serverEntry {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800211 return run(t, ctx, disp, mountPoint, false)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700212}
213
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800214func runMT(t *testing.T, ctx *context.T, mountPoint string) *serverEntry {
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700215 mtd, err := mounttablelib.NewMountTableDispatcher(ctx, "", "", "mounttable")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700216 if err != nil {
Bogdan Capritae96cd042015-02-03 17:32:57 -0800217 boom(t, "NewMountTableDispatcher returned error: %v", err)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700218 }
Bogdan Capritae96cd042015-02-03 17:32:57 -0800219 return run(t, ctx, mtd, mountPoint, true)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700220}
221
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700222func run(t *testing.T, ctx *context.T, disp rpc.Dispatcher, mountPoint string, mt bool) *serverEntry {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700223 s, err := xrpc.NewDispatchingServer(ctx, mountPoint, disp, options.ServesMountTable(mt))
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700224 if err != nil {
225 boom(t, "r.NewServer: %s", err)
226 }
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700227 eps := s.Status().Endpoints
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700228 t.Logf("server %q -> %s", eps[0].Name(), mountPoint)
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700229 // Wait until the mount point appears in the mount table.
230 resolveWithRetry(ctx, mountPoint)
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700231 return &serverEntry{mountPoint: mountPoint, stop: s.Stop, endpoint: eps[0], name: eps[0].Name()}
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700232}
233
234const (
235 mt1MP = "mt1"
236 mt2MP = "mt2"
237 mt3MP = "mt3"
238 mt4MP = "mt4"
239 mt5MP = "mt5"
240 j1MP = "joke1"
241 j2MP = "joke2"
242 j3MP = "joke3"
243
David Why Use Two When One Will Do Presotto80a31832015-05-11 15:56:42 -0700244 ttl = 5 * time.Minute
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700245)
246
247// runMountTables creates a root mountable with some mount tables mounted
248// in it: mt{1,2,3,4,5}
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800249func runMountTables(t *testing.T, ctx *context.T) (*serverEntry, map[string]*serverEntry) {
250 root := runMT(t, ctx, "")
Jiri Simsa6ac95222015-02-23 16:11:49 -0800251 v23.GetNamespace(ctx).SetRoots(root.name)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700252 t.Logf("mountTable %q -> %s", root.mountPoint, root.endpoint)
253
254 mps := make(map[string]*serverEntry)
255 for _, mp := range []string{mt1MP, mt2MP, mt3MP, mt4MP, mt5MP} {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800256 m := runMT(t, ctx, mp)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700257 t.Logf("mountTable %q -> %s", mp, m.endpoint)
258 mps[mp] = m
259 }
260 return root, mps
261}
262
Robin Thellend434e39f2014-08-27 14:46:27 -0700263// createNamespace creates a hierarchy of mounttables and servers
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700264// as follows:
265// /mt1, /mt2, /mt3, /mt4, /mt5, /joke1, /joke2, /joke3.
266// That is, mt1 is a mount table mounted in the root mount table,
267// joke1 is a server mounted in the root mount table.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800268func createNamespace(t *testing.T, ctx *context.T) (*serverEntry, map[string]*serverEntry, map[string]*serverEntry, func()) {
269 root, mts := runMountTables(t, ctx)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700270 jokes := make(map[string]*serverEntry)
271 // Let's run some non-mount table services.
272 for _, j := range []string{j1MP, j2MP, j3MP} {
Robin Thellend434e39f2014-08-27 14:46:27 -0700273 disp := &dispatcher{}
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800274 jokes[j] = runServer(t, ctx, disp, j)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700275 }
276 return root, mts, jokes, func() {
277 for _, s := range jokes {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700278 s.stop()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700279 }
280 for _, s := range mts {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700281 s.stop()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700282 }
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700283 root.stop()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700284 }
285}
286
287// runNestedMountTables creates some nested mount tables in the hierarchy
288// created by createNamespace as follows:
289// /mt4/foo, /mt4/foo/bar and /mt4/baz where foo, bar and baz are mount tables.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800290func runNestedMountTables(t *testing.T, ctx *context.T, mts map[string]*serverEntry) {
Jiri Simsa6ac95222015-02-23 16:11:49 -0800291 ns := v23.GetNamespace(ctx)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700292 // Set up some nested mounts and verify resolution.
293 for _, m := range []string{"mt4/foo", "mt4/foo/bar"} {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800294 mts[m] = runMT(t, ctx, m)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700295 }
296
297 // Use a global name for a mount, rather than a relative one.
298 // We directly mount baz into the mt4/foo mount table.
299 globalMP := naming.JoinAddressName(mts["mt4/foo"].name, "baz")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800300 mts["baz"] = runMT(t, ctx, "baz")
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700301 sctx, done := context.WithTimeout(ctx, 2*time.Minute)
302 defer done()
303 if err := ns.Mount(sctx, globalMP, mts["baz"].name, ttl); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700304 boom(t, "Failed to Mount %s: %s", globalMP, err)
305 }
306}
307
308// TestNamespaceCommon tests common use of the Namespace library
309// against a root mount table and some mount tables mounted on it.
310func TestNamespaceCommon(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800311 _, c, cleanup := createContexts(t)
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800312 defer cleanup()
313
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800314 root, mts, jokes, stopper := createNamespace(t, c)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700315 defer stopper()
Jiri Simsa6ac95222015-02-23 16:11:49 -0800316 ns := v23.GetNamespace(c)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700317
318 // All of the initial mounts are served by the root mounttable
319 // and hence ResolveToMountTable should return the root mountable
320 // as the address portion of the terminal name for those mounttables.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800321 testResolveToMountTable(t, c, ns, "", root.name)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700322 for _, m := range []string{mt2MP, mt3MP, mt5MP} {
David Why Use Two When One Will Do Presotto8b4dbbf2014-11-06 10:50:14 -0800323 rootMT := naming.Join(root.name, m)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700324 // All of these mount tables are hosted by the root mount table
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800325 testResolveToMountTable(t, c, ns, m, rootMT)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700326
327 // The server registered for each mount point is a mount table
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800328 testResolve(t, c, ns, m, mts[m].name)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700329
330 // ResolveToMountTable will walk through to the sub MountTables
331 mtbar := naming.Join(m, "bar")
David Why Use Two When One Will Do Presotto8b4dbbf2014-11-06 10:50:14 -0800332 subMT := naming.Join(mts[m].name, "bar")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800333 testResolveToMountTable(t, c, ns, mtbar, subMT)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700334 }
335
336 for _, j := range []string{j1MP, j2MP, j3MP} {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800337 testResolve(t, c, ns, j, jokes[j].name)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700338 }
339}
340
Cosmos Nicolaou8bd8e102015-01-13 21:52:53 -0800341// TestNamespaceDetails tests more detailed use of the Namespace library.
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700342func TestNamespaceDetails(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800343 sc, c, cleanup := createContexts(t)
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800344 defer cleanup()
345
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800346 root, mts, _, stopper := createNamespace(t, sc)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700347 defer stopper()
348
Jiri Simsa6ac95222015-02-23 16:11:49 -0800349 ns := v23.GetNamespace(c)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700350 ns.SetRoots(root.name)
351
David Why Use Two When One Will Do Presottoadf0ca12014-11-13 10:49:01 -0800352 // /mt2 is not an endpoint. Thus, the example below will fail.
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700353 mt3Server := mts[mt3MP].name
David Why Use Two When One Will Do Presottoadf0ca12014-11-13 10:49:01 -0800354 mt2a := "/mt2/a"
Todd Wang8fa38762015-03-25 14:04:59 -0700355 if err := ns.Mount(c, mt2a, mt3Server, ttl); verror.ErrorID(err) == naming.ErrNoSuchName.ID {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700356 boom(t, "Successfully mounted %s - expected an err %v, not %v", mt2a, naming.ErrNoSuchName, err)
357 }
358
David Why Use Two When One Will Do Presottoadf0ca12014-11-13 10:49:01 -0800359 // Mount using the relative name.
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700360 // This means walk through mt2 if it already exists and mount within
361 // the lower level mount table, if the name doesn't exist we'll create
362 // a new name for it.
363 mt2a = "mt2/a"
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800364 if err := ns.Mount(c, mt2a, mt3Server, ttl); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700365 boom(t, "Failed to Mount %s: %s", mt2a, err)
366 }
367
David Why Use Two When One Will Do Presotto8b4dbbf2014-11-06 10:50:14 -0800368 mt2mt := naming.Join(mts[mt2MP].name, "a")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700369 // The mt2/a is served by the mt2 mount table
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800370 testResolveToMountTable(t, c, ns, mt2a, mt2mt)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700371 // The server for mt2a is mt3server from the second mount above.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800372 testResolve(t, c, ns, mt2a, mt3Server)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700373
David Why Use Two When One Will Do Presottoadf0ca12014-11-13 10:49:01 -0800374 // Add two more mounts. The // should be stripped off of the
375 // second.
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700376 for _, mp := range []struct{ name, server string }{
377 {"mt2", mts[mt4MP].name},
David Why Use Two When One Will Do Presottoadf0ca12014-11-13 10:49:01 -0800378 {"mt2//", mts[mt5MP].name},
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700379 } {
David Why Use Two When One Will Do Presotto38788d42015-03-31 17:13:54 -0700380 if err := ns.Mount(c, mp.name, mp.server, ttl, naming.ServesMountTable(true)); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700381 boom(t, "Failed to Mount %s: %s", mp.name, err)
382 }
383 }
384
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800385 names := []string{naming.JoinAddressName(mts[mt4MP].name, "a"),
386 naming.JoinAddressName(mts[mt5MP].name, "a")}
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800387 names = append(names, naming.JoinAddressName(mts[mt2MP].name, "a"))
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700388 // We now have 3 mount tables prepared to serve mt2/a
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800389 testResolveToMountTable(t, c, ns, "mt2/a", names...)
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800390 names = []string{mts[mt4MP].name, mts[mt5MP].name}
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800391 names = append(names, mts[mt2MP].name)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800392 testResolve(t, c, ns, "mt2", names...)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700393}
394
395// TestNestedMounts tests some more deeply nested mounts
396func TestNestedMounts(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800397 sc, c, cleanup := createContexts(t)
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800398 defer cleanup()
399
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800400 root, mts, _, stopper := createNamespace(t, sc)
401 runNestedMountTables(t, sc, mts)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700402 defer stopper()
403
Jiri Simsa6ac95222015-02-23 16:11:49 -0800404 ns := v23.GetNamespace(c)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700405 ns.SetRoots(root.name)
406
407 // Set up some nested mounts and verify resolution.
408 for _, m := range []string{"mt4/foo", "mt4/foo/bar"} {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800409 testResolve(t, c, ns, m, mts[m].name)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700410 }
411
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800412 testResolveToMountTable(t, c, ns, "mt4/foo",
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800413 naming.JoinAddressName(mts[mt4MP].name, "foo"))
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800414 testResolveToMountTable(t, c, ns, "mt4/foo/bar",
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800415 naming.JoinAddressName(mts["mt4/foo"].name, "bar"))
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800416 testResolveToMountTable(t, c, ns, "mt4/foo/baz",
Cosmos Nicolaouae8dd212014-12-13 23:43:08 -0800417 naming.JoinAddressName(mts["mt4/foo"].name, "baz"))
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700418}
419
420// TestServers tests invoking RPCs on simple servers
421func TestServers(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800422 sc, c, cleanup := createContexts(t)
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800423 defer cleanup()
424
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800425 root, mts, jokes, stopper := createNamespace(t, sc)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700426 defer stopper()
Jiri Simsa6ac95222015-02-23 16:11:49 -0800427 ns := v23.GetNamespace(c)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700428 ns.SetRoots(root.name)
429
Robin Thellend434e39f2014-08-27 14:46:27 -0700430 // Let's run some non-mount table services
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700431 for _, j := range []string{j1MP, j2MP, j3MP} {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800432 testResolve(t, c, ns, j, jokes[j].name)
433 knockKnock(t, c, j)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700434 globalName := naming.JoinAddressName(mts["mt4"].name, j)
Robin Thellend434e39f2014-08-27 14:46:27 -0700435 disp := &dispatcher{}
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700436 gj := "g_" + j
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800437 jokes[gj] = runServer(t, c, disp, globalName)
438 testResolve(t, c, ns, "mt4/"+j, jokes[gj].name)
439 knockKnock(t, c, "mt4/"+j)
440 testResolveToMountTable(t, c, ns, "mt4/"+j, globalName)
441 testResolveToMountTable(t, c, ns, "mt4/"+j+"/garbage", globalName+"/garbage")
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700442 }
443}
444
445// TestGlob tests some glob patterns.
446func TestGlob(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800447 sc, c, cleanup := createContexts(t)
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800448 defer cleanup()
449
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800450 root, mts, _, stopper := createNamespace(t, sc)
451 runNestedMountTables(t, sc, mts)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700452 defer stopper()
Jiri Simsa6ac95222015-02-23 16:11:49 -0800453 ns := v23.GetNamespace(c)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700454 ns.SetRoots(root.name)
455
456 tln := []string{"baz", "mt1", "mt2", "mt3", "mt4", "mt5", "joke1", "joke2", "joke3"}
457 barbaz := []string{"mt4/foo/bar", "mt4/foo/baz"}
Robin Thellend434e39f2014-08-27 14:46:27 -0700458 level12 := []string{"joke1/level1", "joke1/level1/level2", "joke2/level1", "joke2/level1/level2", "joke3/level1", "joke3/level1/level2"}
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700459 foo := append([]string{"mt4/foo"}, barbaz...)
Robin Thellend434e39f2014-08-27 14:46:27 -0700460 foo = append(foo, level12...)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700461 // Try various globs.
462 globTests := []struct {
463 pattern string
464 expected []string
465 }{
466 {"*", tln},
David Why Use Two When One Will Do Presottocce8f4f2014-09-30 14:50:44 -0700467 {"x", []string{}},
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700468 {"m*", []string{"mt1", "mt2", "mt3", "mt4", "mt5"}},
469 {"mt[2,3]", []string{"mt2", "mt3"}},
470 {"*z", []string{"baz"}},
Robin Thellend434e39f2014-08-27 14:46:27 -0700471 {"joke1/*", []string{"joke1/level1"}},
472 {"j?ke1/level1/*", []string{"joke1/level1/level2"}},
473 {"joke1/level1/*", []string{"joke1/level1/level2"}},
474 {"joke1/level1/level2/...", []string{"joke1/level1/level2"}},
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700475 {"...", append(append(tln, foo...), "")},
476 {"*/...", append(tln, foo...)},
477 {"*/foo/*", barbaz},
478 {"*/*/*z", []string{"mt4/foo/baz"}},
479 {"*/f??/*z", []string{"mt4/foo/baz"}},
Robin Thellend434e39f2014-08-27 14:46:27 -0700480 {"mt4/foo/baz", []string{"mt4/foo/baz"}},
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700481 }
482 for _, test := range globTests {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800483 out := doGlob(t, c, ns, test.pattern, 0)
Robin Thellend434e39f2014-08-27 14:46:27 -0700484 compare(t, "Glob", test.pattern, out, test.expected)
Robin Thellend5f838572014-07-10 13:28:56 -0700485 // Do the same with a full rooted name.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800486 out = doGlob(t, c, ns, naming.JoinAddressName(root.name, test.pattern), 0)
Robin Thellend5f838572014-07-10 13:28:56 -0700487 var expectedWithRoot []string
488 for _, s := range test.expected {
489 expectedWithRoot = append(expectedWithRoot, naming.JoinAddressName(root.name, s))
490 }
Robin Thellend434e39f2014-08-27 14:46:27 -0700491 compare(t, "Glob", test.pattern, out, expectedWithRoot)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700492 }
493}
494
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700495type GlobbableServer struct {
496 callCount int
497 mu sync.Mutex
498}
499
Todd Wang54feabe2015-04-15 23:38:26 -0700500func (g *GlobbableServer) Glob__(*context.T, rpc.ServerCall, string) (<-chan naming.GlobReply, error) {
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700501 g.mu.Lock()
502 defer g.mu.Unlock()
503 g.callCount++
Robin Thellend39ac3232014-12-02 09:50:41 -0800504 return nil, nil
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700505}
506
507func (g *GlobbableServer) GetAndResetCount() int {
508 g.mu.Lock()
509 defer g.mu.Unlock()
510 cnt := g.callCount
511 g.callCount = 0
512
513 return cnt
514}
515
516// TestGlobEarlyStop tests that Glob doesn't query terminal servers with finished patterns.
517func TestGlobEarlyStop(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800518 sc, c, cleanup := createContexts(t)
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800519 defer cleanup()
520
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800521 root, mts, _, stopper := createNamespace(t, sc)
522 runNestedMountTables(t, sc, mts)
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700523 defer stopper()
524
525 globServer := &GlobbableServer{}
526 name := naming.JoinAddressName(mts["mt4/foo/bar"].name, "glob")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800527 runningGlobServer := runServer(t, c, testutil.LeafDispatcher(globServer, nil), name)
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700528 defer runningGlobServer.stop()
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700529
Jiri Simsa6ac95222015-02-23 16:11:49 -0800530 ns := v23.GetNamespace(c)
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700531 ns.SetRoots(root.name)
532
533 tests := []struct {
534 pattern string
535 expectedCalls int
David Why Use Two When One Will Do Presottoc28686e2014-11-05 11:19:29 -0800536 expected []string
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700537 }{
David Why Use Two When One Will Do Presottoc28686e2014-11-05 11:19:29 -0800538 {"mt4/foo/bar/glob", 0, []string{"mt4/foo/bar/glob"}},
539 {"mt4/foo/bar/glob/...", 1, []string{"mt4/foo/bar/glob"}},
540 {"mt4/foo/bar/glob/*", 1, nil},
541 {"mt4/foo/bar/***", 0, []string{"mt4/foo/bar", "mt4/foo/bar/glob"}},
542 {"mt4/foo/bar/...", 1, []string{"mt4/foo/bar", "mt4/foo/bar/glob"}},
543 {"mt4/foo/bar/*", 0, []string{"mt4/foo/bar/glob"}},
544 {"mt4/***/bar/***", 0, []string{"mt4/foo/bar", "mt4/foo/bar/glob"}},
545 {"mt4/*/bar/***", 0, []string{"mt4/foo/bar", "mt4/foo/bar/glob"}},
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700546 }
David Why Use Two When One Will Do Presottoc28686e2014-11-05 11:19:29 -0800547 // Test allowing the tests to descend into leaves.
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700548 for _, test := range tests {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800549 out := doGlob(t, c, ns, test.pattern, 0)
David Why Use Two When One Will Do Presottoc28686e2014-11-05 11:19:29 -0800550 compare(t, "Glob", test.pattern, out, test.expected)
Matt Rosencrantz50c2bb82014-07-24 09:10:33 -0700551 if calls := globServer.GetAndResetCount(); calls != test.expectedCalls {
552 boom(t, "Wrong number of Glob calls to terminal server got: %d want: %d.", calls, test.expectedCalls)
553 }
554 }
555}
556
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700557func TestCycles(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800558 sc, c, cleanup := createContexts(t)
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800559 defer cleanup()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700560
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800561 root, _, _, stopper := createNamespace(t, sc)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700562 defer stopper()
Jiri Simsa6ac95222015-02-23 16:11:49 -0800563 ns := v23.GetNamespace(c)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700564 ns.SetRoots(root.name)
565
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800566 c1 := runMT(t, c, "c1")
567 c2 := runMT(t, c, "c2")
568 c3 := runMT(t, c, "c3")
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700569 defer c1.stop()
570 defer c2.stop()
571 defer c3.stop()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700572
573 m := "c1/c2"
David Why Use Two When One Will Do Presotto38788d42015-03-31 17:13:54 -0700574 if err := ns.Mount(c, m, c1.name, ttl, naming.ServesMountTable(true)); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700575 boom(t, "Failed to Mount %s: %s", "c1/c2", err)
576 }
577
578 m = "c1/c2/c3"
David Why Use Two When One Will Do Presotto38788d42015-03-31 17:13:54 -0700579 if err := ns.Mount(c, m, c3.name, ttl, naming.ServesMountTable(true)); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700580 boom(t, "Failed to Mount %s: %s", m, err)
581 }
582
583 m = "c1/c3/c4"
David Why Use Two When One Will Do Presotto38788d42015-03-31 17:13:54 -0700584 if err := ns.Mount(c, m, c1.name, ttl, naming.ServesMountTable(true)); err != nil {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700585 boom(t, "Failed to Mount %s: %s", m, err)
586 }
587
Shyam Jayaramandbae76b2014-11-17 12:51:29 -0800588 // Since c1 was mounted with the Serve call, it will have both the tcp and ws endpoints.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800589 testResolve(t, c, ns, "c1", c1.name)
590 testResolve(t, c, ns, "c1/c2", c1.name)
591 testResolve(t, c, ns, "c1/c3", c3.name)
592 testResolve(t, c, ns, "c1/c3/c4", c1.name)
593 testResolve(t, c, ns, "c1/c3/c4/c3/c4", c1.name)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700594 cycle := "c3/c4"
595 for i := 0; i < 40; i++ {
596 cycle += "/c3/c4"
597 }
Todd Wang8fa38762015-03-25 14:04:59 -0700598 if _, err := ns.Resolve(c, "c1/"+cycle); verror.ErrorID(err) != naming.ErrResolutionDepthExceeded.ID {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700599 boom(t, "Failed to detect cycle")
600 }
601
David Why Use Two When One Will Do Presotto3fc13f42015-03-30 09:56:26 -0700602 // Perform the glob with a response length limit and dup suppression. The dup supression
603 // should win.
604 r := doGlob(t, c, ns, "c1/...", 1000)
605 if len(r) != 6 {
Asim Shankara036a0f2015-05-08 11:22:54 -0700606 t.Fatalf("expected 6 replies, got %v", r)
David Why Use Two When One Will Do Presotto3fc13f42015-03-30 09:56:26 -0700607 }
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700608}
609
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700610// TestGoroutineLeaks tests for leaking goroutines - we have many:-(
611func TestGoroutineLeaks(t *testing.T) {
612 t.Skip()
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800613 sc, _, cleanup := createContexts(t)
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800614 defer cleanup()
615
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800616 _, _, _, stopper := createNamespace(t, sc)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700617 defer func() {
618 vlog.Infof("%d goroutines:", runtime.NumGoroutine())
619 }()
620 defer stopper()
621 defer func() {
622 vlog.Infof("%d goroutines:", runtime.NumGoroutine())
623 }()
624 //panic("this will show up lots of goroutine+channel leaks!!!!")
625}
626
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700627func TestBadRoots(t *testing.T) {
Todd Wang5082a552015-04-02 10:56:11 -0700628 if _, err := inamespace.New(); err != nil {
Cosmos Nicolaou4e029972014-06-13 14:53:08 -0700629 t.Errorf("namespace.New should not have failed with no roots")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700630 }
Todd Wang5082a552015-04-02 10:56:11 -0700631 if _, err := inamespace.New("not a rooted name"); err == nil {
Cosmos Nicolaou4e029972014-06-13 14:53:08 -0700632 t.Errorf("namespace.New should have failed with an unrooted name")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700633 }
634}
Ryan Brownfc290142014-11-24 15:47:24 -0800635
636func bless(blesser, delegate security.Principal, extension string) {
637 b, err := blesser.Bless(delegate.PublicKey(), blesser.BlessingStore().Default(), extension, security.UnconstrainedUse())
638 if err != nil {
639 panic(err)
640 }
641 delegate.BlessingStore().SetDefault(b)
642}
643
Asim Shankar263c73b2015-03-19 18:31:26 -0700644func TestAuthorizationDuringResolve(t *testing.T) {
Jiri Simsa6ac95222015-02-23 16:11:49 -0800645 ctx, shutdown := v23.Init()
Asim Shankarb547ea92015-02-17 18:49:45 -0800646 defer shutdown()
647
648 var (
Todd Wangad492042015-04-17 15:58:40 -0700649 rootMtCtx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal()) // root mounttable
650 mtCtx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal()) // intermediate mounttable
651 serverCtx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal()) // end server
652 clientCtx, _ = v23.WithPrincipal(ctx, testutil.NewPrincipal()) // client process (doing Resolves).
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700653 clientNs = v23.GetNamespace(clientCtx)
654 serverNs = v23.GetNamespace(serverCtx)
655 idp = testutil.NewIDProvider("idp") // identity provider
Asim Shankar263c73b2015-03-19 18:31:26 -0700656 serverEndpoint = naming.FormatEndpoint("tcp", "127.0.0.1:14141")
Asim Shankarb547ea92015-02-17 18:49:45 -0800657 )
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700658
Asim Shankarb547ea92015-02-17 18:49:45 -0800659 // Setup default blessings for the processes.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800660 idp.Bless(v23.GetPrincipal(rootMtCtx), "rootmt")
661 idp.Bless(v23.GetPrincipal(serverCtx), "server")
662 idp.Bless(v23.GetPrincipal(mtCtx), "childmt")
663 idp.Bless(v23.GetPrincipal(clientCtx), "client")
Asim Shankarb547ea92015-02-17 18:49:45 -0800664
665 // Setup the namespace root for all the "processes".
666 rootmt := runMT(t, rootMtCtx, "")
667 for _, ctx := range []*context.T{mtCtx, serverCtx, clientCtx} {
Jiri Simsa6ac95222015-02-23 16:11:49 -0800668 v23.GetNamespace(ctx).SetRoots(rootmt.name)
Asim Shankarb547ea92015-02-17 18:49:45 -0800669 }
670 // Disable caching in the client so that any Mount calls by the server
671 // are noticed immediately.
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700672 clientNs.CacheCtl(naming.DisableCache(true))
Asim Shankarb547ea92015-02-17 18:49:45 -0800673
Asim Shankarb547ea92015-02-17 18:49:45 -0800674 // Intermediate mounttables should be authenticated.
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800675 mt := runMT(t, mtCtx, "mt")
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700676 defer func() {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700677 mt.stop()
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700678 }()
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700679
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800680 // Mount a server on "mt".
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700681 if err := serverNs.Mount(serverCtx, "mt/server", serverEndpoint, time.Minute, naming.ReplaceMount(true)); err != nil {
Asim Shankarb547ea92015-02-17 18:49:45 -0800682 t.Error(err)
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800683 }
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700684
Asim Shankar263c73b2015-03-19 18:31:26 -0700685 // The namespace root should be authenticated too
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700686 resolveWithRetry(clientCtx, "mt/server")
687 // Host:Port and Endpoint versions of the other namespace root
688 // (which has different blessings)
689 hproot := fmt.Sprintf("(otherroot)@%v", rootmt.endpoint.Addr())
690 eproot := naming.FormatEndpoint(rootmt.endpoint.Addr().Network(), rootmt.endpoint.Addr().String(), rootmt.endpoint.RoutingID(), naming.BlessingOpt("otherroot"), naming.ServesMountTable(rootmt.endpoint.ServesMountTable()))
691 for _, root := range []string{hproot, eproot} {
692 name := naming.JoinAddressName(root, "mt")
693 // Rooted name resolutions should fail authorization because of the "otherrot"
694 if e, err := clientNs.Resolve(clientCtx, name); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
695 t.Errorf("resolve(%q) returned (%v, errorid=%v %v), wanted errorid=%v", name, e, verror.ErrorID(err), err, verror.ErrNotTrusted.ID)
696 }
697 // But not fail if the skip-authorization option is provided
698 if e, err := clientNs.Resolve(clientCtx, name, options.SkipServerEndpointAuthorization{}); err != nil {
699 t.Errorf("resolve(%q): Got (%v, %v), expected resolution to succeed", name, e, err)
700 }
701
702 // The namespace root from the context should be authorized as well.
703 ctx, ns, _ := v23.WithNewNamespace(clientCtx, naming.JoinAddressName(root, ""))
704 if e, err := ns.Resolve(ctx, "mt/server"); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
705 t.Errorf("resolve with root=%q returned (%v, errorid=%v %v), wanted errorid=%v: %s", root, e, verror.ErrorID(err), err, verror.ErrNotTrusted.ID, verror.DebugString(err))
706 }
707 if _, err := ns.Resolve(ctx, "mt/server", options.SkipServerEndpointAuthorization{}); err != nil {
708 t.Errorf("resolve with root=%q should have succeeded when authorization checks are skipped. Got %v: %s", root, err, verror.DebugString(err))
Asim Shankar263c73b2015-03-19 18:31:26 -0700709 }
710 }
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700711
Asim Shankar263c73b2015-03-19 18:31:26 -0700712 // Imagine that the network address of "mt" has been taken over by an
713 // attacker. However, this attacker cannot mess with the mount entry
714 // for "mt". This would result in "mt" and its mount entry (in the
715 // global mounttable) having inconsistent blessings. Simulate this by
716 // explicitly changing the mount entry for "mt".
717 goodChildMTEndpoint := naming.FormatEndpoint(mt.endpoint.Addr().Network(), mt.endpoint.Addr().String(), naming.BlessingOpt("idp/goodchildmt"), mt.endpoint.RoutingID())
David Why Use Two When One Will Do Presotto38788d42015-03-31 17:13:54 -0700718 if err := v23.GetNamespace(mtCtx).Mount(mtCtx, "mt", goodChildMTEndpoint, time.Minute, naming.ServesMountTable(true), naming.ReplaceMount(true)); err != nil {
Asim Shankarb547ea92015-02-17 18:49:45 -0800719 t.Error(err)
Suharsh Sivakumar77357d72015-02-21 22:14:20 -0800720 }
721
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700722 if e, err := clientNs.Resolve(serverCtx, "mt/server", options.SkipServerEndpointAuthorization{}); err != nil {
Matt Rosencrantz0e207172015-04-16 14:58:02 -0700723 t.Errorf("Resolve should succeed when skipping server authorization. Got (%v, %v) %s", e, err, verror.DebugString(err))
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700724 } else if e, err := clientNs.Resolve(serverCtx, "mt/server"); verror.ErrorID(err) != verror.ErrNotTrusted.ID {
Asim Shankarb547ea92015-02-17 18:49:45 -0800725 t.Errorf("Resolve should have failed with %q because an attacker has taken over the intermediate mounttable. Got (%+v, errorid=%q:%v)", verror.ErrNotTrusted.ID, e, verror.ErrorID(err), err)
726 }
727}
David Why Use Two When One Will Do Presotto18be8b02015-03-02 17:26:25 -0800728
729// TestDelete tests deleting some parts of the name space.
730func TestDelete(t *testing.T) {
731 _, c, cleanup := createContexts(t)
732 defer cleanup()
733 ns := v23.GetNamespace(c)
734
735 // Create a root mount table with mount tables mounted at mt1, mt1, ...
736 root, _, _, stopper := createNamespace(t, c)
737 defer stopper()
738 ns.SetRoots(root.name)
739
740 // We should be able to remove servers below the root.
741 if err := ns.Delete(c, "mt1", false); err != nil {
742 t.Errorf("Delete failed: %s", err)
743 }
744
745 // Create a server below one level down.
746 if err := ns.Mount(c, "mt2/b/c", "/madeup:1111/server", time.Minute); err != nil {
747 t.Errorf("Mount mt2/b/c failed: %s", err)
748 }
749
750 // We should not be able to delete mt2/b...
751 if err := ns.Delete(c, "mt2/b", false); err == nil {
752 t.Errorf("Delete mt2/b should have failed")
753 }
754
755 // ...unless we include its children.
756 if err := ns.Delete(c, "mt2/b", true); err != nil {
757 t.Errorf("Delete failed: %s", err)
758 }
759}
Robin Thellend89e95232015-03-24 13:48:48 -0700760
761type leafObject struct{}
762
Todd Wang54feabe2015-04-15 23:38:26 -0700763func (leafObject) Foo(*context.T, rpc.ServerCall) error {
Robin Thellend89e95232015-03-24 13:48:48 -0700764 return nil
765}
766
767func TestLeaf(t *testing.T) {
768 _, ctx, cleanup := createContexts(t)
769 defer cleanup()
770 root := runMT(t, ctx, "")
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700771 defer func() { root.stop() }()
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700772
Robin Thellend89e95232015-03-24 13:48:48 -0700773 ns := v23.GetNamespace(ctx)
774 ns.SetRoots(root.name)
775
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700776 server, err := xrpc.NewServer(ctx, "leaf", &leafObject{}, nil)
Robin Thellend89e95232015-03-24 13:48:48 -0700777 if err != nil {
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700778 boom(t, "xrpc.NewServer: %s", err)
Robin Thellend89e95232015-03-24 13:48:48 -0700779 }
Cosmos Nicolaou6bed4192015-05-07 21:31:15 -0700780 defer server.Stop()
Robin Thellend89e95232015-03-24 13:48:48 -0700781
Cosmos Nicolaou33cf8982015-05-26 10:39:49 -0700782 mountEntry := resolveWithRetry(ctx, "leaf")
Robin Thellend89e95232015-03-24 13:48:48 -0700783 if expected := true; mountEntry.IsLeaf != expected {
784 boom(t, "unexpected mountEntry.IsLeaf value. Got %v, expected %v", mountEntry.IsLeaf, expected)
785 }
Robin Thellend00643742015-04-01 10:36:50 -0700786
787 c, err := ns.Glob(ctx, "leaf")
788 if err != nil {
789 boom(t, "ns.Glob failed: %v", err)
790 }
791 count := 0
792 for result := range c {
James Ringc971dca2015-04-09 09:51:20 -0700793 if me, ok := result.(*naming.GlobReplyEntry); ok {
Robin Thellend00643742015-04-01 10:36:50 -0700794 count++
James Ringc971dca2015-04-09 09:51:20 -0700795 if expected := true; me.Value.IsLeaf != expected {
796 boom(t, "unexpected me.IsLeaf value. Got %v, expected %v", me.Value.IsLeaf, expected)
Robin Thellend00643742015-04-01 10:36:50 -0700797 }
798 }
799 }
800 if count == 0 {
801 boom(t, "Glob did not return any results. Expected 1")
802 }
Robin Thellend89e95232015-03-24 13:48:48 -0700803}