blob: 879943bd8ac4a19fb11fd0fb6002f9314b611c14 [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
Matt Rosencrantz165e8902015-06-12 15:27:27 -07005package mounttablelib_test
Jiri Simsa5293dcb2014-05-10 09:56:38 -07006
7import (
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -07008 "encoding/json"
Jiri Simsa5293dcb2014-05-10 09:56:38 -07009 "errors"
Robin Thellendfd82dcc2015-04-14 21:16:59 -070010 "fmt"
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -070011 "io"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070012 "reflect"
13 "runtime/debug"
14 "sort"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070015 "testing"
16 "time"
17
Jiri Simsa6ac95222015-02-23 16:11:49 -080018 "v.io/v23"
19 "v.io/v23/context"
David Why Use Two When One Will Do Presotto67b70712015-06-02 13:13:58 -070020 "v.io/v23/conventions"
Robin Thellendf15f2952015-07-17 21:49:58 -070021 "v.io/v23/glob"
Jiri Simsa6ac95222015-02-23 16:11:49 -080022 "v.io/v23/naming"
23 "v.io/v23/options"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070024 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080025 "v.io/v23/security"
Todd Wang387d8a42015-03-30 17:09:05 -070026 "v.io/v23/security/access"
Asim Shankarb425c552015-07-10 02:18:59 -070027 "v.io/v23/services/mounttable"
Robin Thellendfd82dcc2015-04-14 21:16:59 -070028 "v.io/v23/services/stats"
29 "v.io/v23/vdl"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070030
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -070031 libstats "v.io/x/ref/lib/stats"
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -070032 "v.io/x/ref/lib/xrpc"
Robin Thellendfd82dcc2015-04-14 21:16:59 -070033 "v.io/x/ref/services/debug/debuglib"
Matt Rosencrantz165e8902015-06-12 15:27:27 -070034 "v.io/x/ref/services/mounttable/mounttablelib"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070035 "v.io/x/ref/test"
Asim Shankar4a698282015-03-21 21:59:18 -070036 "v.io/x/ref/test/testutil"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070037)
38
Matt Rosencrantz165e8902015-06-12 15:27:27 -070039func init() {
40 test.Init()
41}
42
Asim Shankar88292912014-10-09 19:41:07 -070043// Simulate different processes with different runtimes.
Matt Rosencrantz6edab562015-01-12 11:07:55 -080044// rootCtx is the one running the mounttable service.
Jiri Simsa5293dcb2014-05-10 09:56:38 -070045const ttlSecs = 60 * 60
46
47func boom(t *testing.T, f string, v ...interface{}) {
48 t.Logf(f, v...)
49 t.Fatal(string(debug.Stack()))
50}
51
Asim Shankar43d1f932015-03-24 20:57:56 -070052func doMount(t *testing.T, ctx *context.T, ep, suffix, service string, shouldSucceed bool) {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -070053 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080054 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -070055 if err := client.Call(ctx, name, "Mount", []interface{}{service, uint32(ttlSecs), 0}, nil, options.NoResolve{}); err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -070056 if !shouldSucceed {
57 return
58 }
59 boom(t, "Failed to Mount %s onto %s: %s", service, name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070060 }
61}
62
Matt Rosencrantz6edab562015-01-12 11:07:55 -080063func doUnmount(t *testing.T, ctx *context.T, ep, suffix, service string, shouldSucceed bool) {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -070064 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080065 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -070066 if err := client.Call(ctx, name, "Unmount", []interface{}{service}, nil, options.NoResolve{}); err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -070067 if !shouldSucceed {
68 return
69 }
Alex Fandriantoa2e7c372015-04-20 10:46:10 -070070 boom(t, "Failed to Unmount %s off of %s: %s", service, name, err)
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -070071 }
72}
73
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070074func doGetPermissions(t *testing.T, ctx *context.T, ep, suffix string, shouldSucceed bool) (perms access.Permissions, version string) {
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080075 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080076 client := v23.GetClient(ctx)
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070077 if err := client.Call(ctx, name, "GetPermissions", nil, []interface{}{&perms, &version}, options.NoResolve{}); err != nil {
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080078 if !shouldSucceed {
79 return
80 }
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -070081 boom(t, "Failed to GetPermissions %s: %s", name, err)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080082 }
83 return
84}
85
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070086func doSetPermissions(t *testing.T, ctx *context.T, ep, suffix string, perms access.Permissions, version string, shouldSucceed bool) {
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080087 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080088 client := v23.GetClient(ctx)
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070089 if err := client.Call(ctx, name, "SetPermissions", []interface{}{perms, version}, nil, options.NoResolve{}); err != nil {
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080090 if !shouldSucceed {
91 return
92 }
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -070093 boom(t, "Failed to SetPermissions %s: %s", name, err)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080094 }
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080095}
96
Matt Rosencrantz6edab562015-01-12 11:07:55 -080097func doDeleteNode(t *testing.T, ctx *context.T, ep, suffix string, shouldSucceed bool) {
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080098 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080099 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700100 if err := client.Call(ctx, name, "Delete", []interface{}{false}, nil, options.NoResolve{}); err != nil {
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800101 if !shouldSucceed {
102 return
103 }
104 boom(t, "Failed to Delete node %s: %s", name, err)
105 }
106}
107
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800108func doDeleteSubtree(t *testing.T, ctx *context.T, ep, suffix string, shouldSucceed bool) {
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800109 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -0800110 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700111 if err := client.Call(ctx, name, "Delete", []interface{}{true}, nil, options.NoResolve{}); err != nil {
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800112 if !shouldSucceed {
113 return
114 }
115 boom(t, "Failed to Delete subtree %s: %s", name, err)
116 }
117}
118
Todd Wang2331dd02015-03-17 15:38:39 -0700119func mountentry2names(e *naming.MountEntry) []string {
Asim Shankar8bc78d62015-02-03 16:53:27 -0800120 names := make([]string, len(e.Servers))
121 for idx, s := range e.Servers {
122 names[idx] = naming.JoinAddressName(s.Server, e.Name)
123 }
124 return names
125}
126
127func strslice(strs ...string) []string {
128 return strs
129}
130
Todd Wang2331dd02015-03-17 15:38:39 -0700131func resolve(ctx *context.T, name string) (*naming.MountEntry, error) {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700132 // Resolve the name one level.
Todd Wang2331dd02015-03-17 15:38:39 -0700133 var entry naming.MountEntry
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700134 client := v23.GetClient(ctx)
135 if err := client.Call(ctx, name, "ResolveStep", nil, []interface{}{&entry}, options.NoResolve{}); err != nil {
Todd Wange77f9952015-02-18 13:20:50 -0800136 return nil, err
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700137 }
138 if len(entry.Servers) < 1 {
Asim Shankar8bc78d62015-02-03 16:53:27 -0800139 return nil, errors.New("resolve returned no servers")
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700140 }
Asim Shankar8bc78d62015-02-03 16:53:27 -0800141 return &entry, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700142}
143
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800144func export(t *testing.T, ctx *context.T, name, contents string) {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700145 // Resolve the name.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800146 resolved, err := resolve(ctx, name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700147 if err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700148 boom(t, "Failed to Export.Resolve %s: %s", name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700149 }
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700150 // Export the value.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800151 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700152 if err := client.Call(ctx, mountentry2names(resolved)[0], "Export", []interface{}{contents, true}, nil, options.NoResolve{}); err != nil {
153 boom(t, "Failed to Export.Call %s to %s: %s", name, contents, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700154 }
155}
156
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800157func checkContents(t *testing.T, ctx *context.T, name, expected string, shouldSucceed bool) {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700158 // Resolve the name.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800159 resolved, err := resolve(ctx, name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700160 if err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700161 if !shouldSucceed {
162 return
163 }
164 boom(t, "Failed to Resolve %s: %s", name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700165 }
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700166 // Look up the value.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800167 client := v23.GetClient(ctx)
Asim Shankar8bc78d62015-02-03 16:53:27 -0800168 call, err := client.StartCall(ctx, mountentry2names(resolved)[0], "Lookup", nil, options.NoResolve{})
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700169 if err != nil {
170 if shouldSucceed {
171 boom(t, "Failed Lookup.StartCall %s: %s", name, err)
172 }
173 return
174 }
175 var contents []byte
Todd Wange77f9952015-02-18 13:20:50 -0800176 if err := call.Finish(&contents); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700177 if shouldSucceed {
178 boom(t, "Failed to Lookup %s: %s", name, err)
179 }
180 return
181 }
182 if string(contents) != expected {
183 boom(t, "Lookup %s, expected %q, got %q", name, expected, contents)
184 }
185 if !shouldSucceed {
186 boom(t, "Lookup %s, expected failure, got %q", name, contents)
187 }
188}
189
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700190func newMT(t *testing.T, permsFile, persistDir, statsDir string, rootCtx *context.T) (func() error, string) {
Cosmos Nicolaou64d573d2015-07-13 16:22:18 -0700191 reservedDisp := debuglib.NewDispatcher(nil)
Todd Wangad492042015-04-17 15:58:40 -0700192 ctx := v23.WithReservedNameDispatcher(rootCtx, reservedDisp)
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700193
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700194 // Add mount table service.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700195 mt, err := mounttablelib.NewMountTableDispatcher(ctx, permsFile, persistDir, statsDir)
Ryan Brownac972652014-05-19 10:57:32 -0700196 if err != nil {
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700197 boom(t, "mounttablelib.NewMountTableDispatcher: %v", err)
Ryan Brownac972652014-05-19 10:57:32 -0700198 }
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700199
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700200 // Start serving on a loopback address.
201 server, err := xrpc.NewDispatchingServer(ctx, "", mt, options.ServesMountTable(true))
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700202 if err != nil {
203 boom(t, "r.NewServer: %s", err)
204 }
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700205
206 estr := server.Status().Endpoints[0].String()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700207 t.Logf("endpoint %s", estr)
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700208 return server.Stop, estr
209}
210
211func newCollection(t *testing.T, rootCtx *context.T) (func() error, string) {
212 // Start serving a collection service on a loopback address. This
213 // is just a service we can mount and test against.
214 server, err := xrpc.NewDispatchingServer(rootCtx, "collection", newCollectionServer())
215 if err != nil {
216 boom(t, "r.NewServer: %s", err)
217 }
218 estr := server.Status().Endpoints[0].String()
219 t.Logf("endpoint %s", estr)
220 return server.Stop, estr
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700221}
222
223func TestMountTable(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800224 rootCtx, aliceCtx, bobCtx, shutdown := initTest()
225 defer shutdown()
226
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700227 stop, mtAddr := newMT(t, "testdata/test.perms", "", "testMountTable", rootCtx)
228 defer stop()
229 stop, collectionAddr := newCollection(t, rootCtx)
230 defer stop()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700231
232 collectionName := naming.JoinAddressName(collectionAddr, "collection")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700233
234 // Mount the collection server into the mount table.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700235 rootCtx.Infof("Mount the collection server into the mount table.")
Asim Shankar43d1f932015-03-24 20:57:56 -0700236 doMount(t, rootCtx, mtAddr, "stuff", collectionName, true)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700237
238 // Create a few objects and make sure we can read them.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700239 rootCtx.Infof("Create a few objects.")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800240 export(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/the/rain"), "the rain")
241 export(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/in/spain"), "in spain")
242 export(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/falls"), "falls mainly on the plain")
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700243 rootCtx.Infof("Make sure we can read them.")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800244 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/the/rain"), "the rain", true)
245 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/in/spain"), "in spain", true)
246 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/falls"), "falls mainly on the plain", true)
247 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "/stuff/falls"), "falls mainly on the plain", true)
248 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/nonexistant"), "falls mainly on the plain", false)
249 checkContents(t, bobCtx, naming.JoinAddressName(mtAddr, "stuff/the/rain"), "the rain", true)
250 checkContents(t, aliceCtx, naming.JoinAddressName(mtAddr, "stuff/the/rain"), "the rain", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700251
252 // Test multiple mounts.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700253 rootCtx.Infof("Multiple mounts.")
Asim Shankar43d1f932015-03-24 20:57:56 -0700254 doMount(t, rootCtx, mtAddr, "a/b", collectionName, true)
255 doMount(t, rootCtx, mtAddr, "x/y", collectionName, true)
256 doMount(t, rootCtx, mtAddr, "alpha//beta", collectionName, true)
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700257 rootCtx.Infof("Make sure we can read them.")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800258 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/falls"), "falls mainly on the plain", true)
259 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "a/b/falls"), "falls mainly on the plain", true)
260 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "x/y/falls"), "falls mainly on the plain", true)
261 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "alpha/beta/falls"), "falls mainly on the plain", true)
262 checkContents(t, aliceCtx, naming.JoinAddressName(mtAddr, "a/b/falls"), "falls mainly on the plain", true)
263 checkContents(t, bobCtx, naming.JoinAddressName(mtAddr, "a/b/falls"), "falls mainly on the plain", false)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800264
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700265 // Test getting/setting AccessLists.
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700266 perms, version := doGetPermissions(t, rootCtx, mtAddr, "stuff", true)
267 doSetPermissions(t, rootCtx, mtAddr, "stuff", perms, "xyzzy", false) // bad version
268 doSetPermissions(t, rootCtx, mtAddr, "stuff", perms, version, true) // correct version
Adam Sadovskyb1f9e3c2015-04-08 11:03:49 -0700269 _, nversion := doGetPermissions(t, rootCtx, mtAddr, "stuff", true)
270 if nversion == version {
271 boom(t, "version didn't change after SetPermissions: %s", nversion)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800272 }
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700273 doSetPermissions(t, rootCtx, mtAddr, "stuff", perms, "", true) // no version
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800274
275 // Bob should be able to create nodes under the mounttable root but not alice.
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700276 doSetPermissions(t, aliceCtx, mtAddr, "onlybob", perms, "", false)
277 doSetPermissions(t, bobCtx, mtAddr, "onlybob", perms, "", true)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700278
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700279 // Test that setting Permissions to permissions that don't include the the setter's
Suharsh Sivakumar7120abd2015-04-15 13:54:23 -0700280 // blessings in Admin, automatically add their Blessings to Admin to prevent
281 // locking everyone out.
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700282 perms, _ = doGetPermissions(t, bobCtx, mtAddr, "onlybob", true)
283 noRootPerms := perms.Copy()
284 noRootPerms.Clear("bob", "Admin")
285 doSetPermissions(t, bobCtx, mtAddr, "onlybob", noRootPerms, "", true)
Suharsh Sivakumar7120abd2015-04-15 13:54:23 -0700286 // This should succeed, because "bob" should automatically be added to "Admin"
287 // even though he cleared himself from "Admin".
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700288 doSetPermissions(t, bobCtx, mtAddr, "onlybob", perms, "", true)
289 // Test that adding a non-standard perms is normalized when retrieved.
290 admin := perms["Admin"]
Suharsh Sivakumar7120abd2015-04-15 13:54:23 -0700291 admin.In = []security.BlessingPattern{"bob", "bob"}
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700292 perms["Admin"] = admin
293 doSetPermissions(t, bobCtx, mtAddr, "onlybob", perms, "", true)
294 perms, _ = doGetPermissions(t, bobCtx, mtAddr, "onlybob", true)
295 if got, want := perms["Admin"].In, []security.BlessingPattern{"bob"}; !reflect.DeepEqual(got, want) {
Suharsh Sivakumar7120abd2015-04-15 13:54:23 -0700296 boom(t, "got %v, want %v", got, want)
297 }
298
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700299 // Test generic unmount.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700300 rootCtx.Info("Test generic unmount.")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800301 doUnmount(t, rootCtx, mtAddr, "a/b", "", true)
302 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "a/b/falls"), "falls mainly on the plain", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700303
304 // Test specific unmount.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700305 rootCtx.Info("Test specific unmount.")
Asim Shankar43d1f932015-03-24 20:57:56 -0700306 doMount(t, rootCtx, mtAddr, "a/b", collectionName, true)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800307 doUnmount(t, rootCtx, mtAddr, "a/b", collectionName, true)
308 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "a/b/falls"), "falls mainly on the plain", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700309
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700310 // Try timing out a mount.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700311 rootCtx.Info("Try timing out a mount.")
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700312 ft := mounttablelib.NewFakeTimeClock()
313 mounttablelib.SetServerListClock(ft)
Asim Shankar43d1f932015-03-24 20:57:56 -0700314 doMount(t, rootCtx, mtAddr, "stuffWithTTL", collectionName, true)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800315 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuffWithTTL/the/rain"), "the rain", true)
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700316 ft.Advance(time.Duration(ttlSecs+4) * time.Second)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800317 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuffWithTTL/the/rain"), "the rain", false)
Ryan Brownac972652014-05-19 10:57:32 -0700318
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700319 // Test unauthorized mount.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700320 rootCtx.Info("Test unauthorized mount.")
Asim Shankar43d1f932015-03-24 20:57:56 -0700321 doMount(t, bobCtx, mtAddr, "/a/b", collectionName, false)
322 doMount(t, aliceCtx, mtAddr, "/a/b", collectionName, false)
Ryan Brownac972652014-05-19 10:57:32 -0700323
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800324 doUnmount(t, bobCtx, mtAddr, "x/y", collectionName, false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700325}
326
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800327func doGlobX(t *testing.T, ctx *context.T, ep, suffix, pattern string, joinServer bool) []string {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700328 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -0800329 client := v23.GetClient(ctx)
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700330 call, err := client.StartCall(ctx, name, rpc.GlobMethod, []interface{}{pattern}, options.NoResolve{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700331 if err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700332 boom(t, "Glob.StartCall %s %s: %s", name, pattern, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700333 }
334 var reply []string
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700335 for {
Todd Wang2331dd02015-03-17 15:38:39 -0700336 var gr naming.GlobReply
David Why Use Two When One Will Do Presottoe5e62d02015-02-19 14:35:20 -0800337 err := call.Recv(&gr)
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700338 if err == io.EOF {
339 break
340 }
341 if err != nil {
342 boom(t, "Glob.StartCall %s: %s", name, pattern, err)
343 }
David Why Use Two When One Will Do Presottoe5e62d02015-02-19 14:35:20 -0800344 switch v := gr.(type) {
Todd Wang2331dd02015-03-17 15:38:39 -0700345 case naming.GlobReplyEntry:
David Why Use Two When One Will Do Presottoe5e62d02015-02-19 14:35:20 -0800346 if joinServer && len(v.Value.Servers) > 0 {
347 reply = append(reply, naming.JoinAddressName(v.Value.Servers[0].Server, v.Value.Name))
348 } else {
349 reply = append(reply, v.Value.Name)
350 }
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700351 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700352 }
Todd Wange77f9952015-02-18 13:20:50 -0800353 if err := call.Finish(); err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700354 boom(t, "Glob.Finish %s: %s", name, pattern, err)
Shyam Jayaramanc4aed6e2014-07-22 14:25:06 -0700355 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700356 return reply
357}
358
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800359func doGlob(t *testing.T, ctx *context.T, ep, suffix, pattern string) []string {
360 return doGlobX(t, ctx, ep, suffix, pattern, false)
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700361}
362
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700363// checkMatch verified that the two slices contain the same string items, albeit
364// not necessarily in the same order. Item repetitions are allowed, but their
365// numbers need to match as well.
366func checkMatch(t *testing.T, want []string, got []string) {
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800367 if len(want) == 0 && len(got) == 0 {
368 return
369 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700370 w := sort.StringSlice(want)
371 w.Sort()
372 g := sort.StringSlice(got)
373 g.Sort()
374 if !reflect.DeepEqual(w, g) {
375 boom(t, "Glob expected %v got %v", want, got)
376 }
377}
378
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800379// checkExists makes sure a name exists (or not).
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800380func checkExists(t *testing.T, ctx *context.T, ep, suffix string, shouldSucceed bool) {
381 x := doGlobX(t, ctx, ep, "", suffix, false)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800382 if len(x) != 1 || x[0] != suffix {
383 if shouldSucceed {
384 boom(t, "Failed to find %s", suffix)
385 }
386 return
387 }
388 if !shouldSucceed {
389 boom(t, "%s exists but shouldn't", suffix)
390 }
391}
392
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700393func TestGlob(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700394 rootCtx, shutdown := test.V23Init()
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800395 defer shutdown()
396
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700397 stop, estr := newMT(t, "", "", "testGlob", rootCtx)
398 defer stop()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700399
400 // set up a mount space
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700401 fakeServer := naming.JoinAddressName(estr, "quux")
Asim Shankar43d1f932015-03-24 20:57:56 -0700402 doMount(t, rootCtx, estr, "one/bright/day", fakeServer, true)
403 doMount(t, rootCtx, estr, "in/the/middle", fakeServer, true)
404 doMount(t, rootCtx, estr, "of/the/night", fakeServer, true)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700405
406 // Try various globs.
407 tests := []struct {
408 in string
409 expected []string
410 }{
411 {"*", []string{"one", "in", "of"}},
Bogdan Capritab6b195a2014-06-11 17:55:03 -0700412 {"...", []string{"", "one", "in", "of", "one/bright", "in/the", "of/the", "one/bright/day", "in/the/middle", "of/the/night"}},
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700413 {"*/...", []string{"one", "in", "of", "one/bright", "in/the", "of/the", "one/bright/day", "in/the/middle", "of/the/night"}},
Bogdan Capritab6b195a2014-06-11 17:55:03 -0700414 {"one/...", []string{"one", "one/bright", "one/bright/day"}},
Robin Thellend434e39f2014-08-27 14:46:27 -0700415 {"of/the/night/two/dead/boys", []string{"of/the/night"}},
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700416 {"*/the", []string{"in/the", "of/the"}},
417 {"*/the/...", []string{"in/the", "of/the", "in/the/middle", "of/the/night"}},
418 {"o*", []string{"one", "of"}},
419 {"", []string{""}},
420 }
421 for _, test := range tests {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800422 out := doGlob(t, rootCtx, estr, "", test.in)
Ryan Brownac972652014-05-19 10:57:32 -0700423 checkMatch(t, test.expected, out)
424 }
Robin Thellend434e39f2014-08-27 14:46:27 -0700425
426 // Test Glob on a name that is under a mounted server. The result should the
427 // the address the mounted server with the extra suffix.
428 {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800429 results := doGlobX(t, rootCtx, estr, "of/the/night/two/dead/boys/got/up/to/fight", "*", true)
Robin Thellend434e39f2014-08-27 14:46:27 -0700430 if len(results) != 1 {
431 boom(t, "Unexpected number of results. Got %v, want 1", len(results))
432 }
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700433 _, suffix := naming.SplitAddressName(results[0])
434 if expected := "quux/two/dead/boys/got/up/to/fight"; suffix != expected {
Robin Thellend434e39f2014-08-27 14:46:27 -0700435 boom(t, "Unexpected suffix. Got %v, want %v", suffix, expected)
436 }
437 }
Ryan Brownac972652014-05-19 10:57:32 -0700438}
439
Robin Thellendf15f2952015-07-17 21:49:58 -0700440type fakeServerCall struct {
441 sendCount int
442}
Asim Shankarb425c552015-07-10 02:18:59 -0700443
444func (fakeServerCall) Security() security.Call { return security.NewCall(&security.CallParams{}) }
445func (fakeServerCall) Suffix() string { return "" }
446func (fakeServerCall) LocalEndpoint() naming.Endpoint { return nil }
447func (fakeServerCall) RemoteEndpoint() naming.Endpoint { return nil }
448func (fakeServerCall) GrantedBlessings() security.Blessings { return security.Blessings{} }
449func (fakeServerCall) Server() rpc.Server { return nil }
Robin Thellendf15f2952015-07-17 21:49:58 -0700450func (c *fakeServerCall) SendStream() interface {
451 Send(naming.GlobReply) error
452} {
453 return c
454}
455func (c *fakeServerCall) Send(reply naming.GlobReply) error {
456 c.sendCount++
457 return nil
458}
Asim Shankarb425c552015-07-10 02:18:59 -0700459
460func TestGlobAborts(t *testing.T) {
461 ctx, shutdown := test.V23Init()
462 defer shutdown()
463
464 mt, err := mounttablelib.NewMountTableDispatcher(ctx, "", "", "")
465 if err != nil {
466 t.Fatal(err)
467 }
468
469 mount := func(name string) error {
Asim Shankar56db0852015-07-16 14:25:31 -0700470 invoker, _, _ := mt.Lookup(ctx, name)
Asim Shankarb425c552015-07-10 02:18:59 -0700471 server := naming.FormatEndpoint("tcp", name)
472 return invoker.(mounttable.MountTableServerStub).Mount(ctx, fakeServerCall{}, server, 0, 0)
473 }
474 // Mount 125 entries: 5 "directories" with 25 entries each.
475 for i := 0; i < 5; i++ {
476 for j := 0; j < 25; j++ {
477 if err := mount(fmt.Sprintf("%d/%d", i, j)); err != nil {
478 t.Fatalf("%v (%d, %d)", err, i, j)
479 }
480 }
481 }
482
483 glob := func(ctx *context.T) (int, error) {
Asim Shankar56db0852015-07-16 14:25:31 -0700484 root, _, _ := mt.Lookup(ctx, "")
Robin Thellendf15f2952015-07-17 21:49:58 -0700485 g, _ := glob.Parse("...")
486 fCall := &fakeServerCall{}
487 root.(rpc.Globber).Globber().AllGlobberX.Glob__(ctx, fCall, g)
488 return fCall.sendCount, nil
Asim Shankarb425c552015-07-10 02:18:59 -0700489 }
490
491 got, err := glob(ctx)
492 if err != nil {
493 t.Fatal(err)
494 }
495 if want := 5 + 125 + 1; got != want { // 5 "directories", 125 entries, 1 root entry
496 t.Errorf("Got %d want %d", got, want)
497 }
498 canceled, cancel := context.WithCancel(ctx)
499 cancel()
500 if got, err = glob(canceled); err != nil {
501 t.Fatal(err)
502 }
503 if got != 0 {
504 t.Errorf("Glob returned entries even though the context was cancelled first (returned %d)", got)
505 }
506}
507
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700508func TestAccessListTemplate(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800509 rootCtx, aliceCtx, bobCtx, shutdown := initTest()
510 defer shutdown()
511
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700512 stop, estr := newMT(t, "testdata/test.perms", "", "testAccessListTemplate", rootCtx)
513 defer stop()
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800514 fakeServer := naming.JoinAddressName(estr, "quux")
Tilak Sharmada5165e2014-10-07 16:39:51 -0700515
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800516 // Noone should be able to mount on someone else's names.
Asim Shankar43d1f932015-03-24 20:57:56 -0700517 doMount(t, aliceCtx, estr, "users/ted", fakeServer, false)
518 doMount(t, bobCtx, estr, "users/carol", fakeServer, false)
519 doMount(t, rootCtx, estr, "users/george", fakeServer, false)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800520
521 // Anyone should be able to mount on their own names.
Asim Shankar43d1f932015-03-24 20:57:56 -0700522 doMount(t, aliceCtx, estr, "users/alice", fakeServer, true)
523 doMount(t, bobCtx, estr, "users/bob", fakeServer, true)
524 doMount(t, rootCtx, estr, "users/root", fakeServer, true)
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700525
526 // Make sure the counter works.
527 doUnmount(t, aliceCtx, estr, "users/alice", "", true)
528 doUnmount(t, bobCtx, estr, "users/bob", "", true)
529 doUnmount(t, rootCtx, estr, "users/root", "", true)
530 perms := access.Permissions{"Admin": access.AccessList{In: []security.BlessingPattern{security.AllPrincipals}}}
531 doSetPermissions(t, aliceCtx, estr, "users/alice/a/b/c/d", perms, "", true)
532 doSetPermissions(t, aliceCtx, estr, "users/alice/a/b/c/d", perms, "", true)
533
534 // Do we obey limits?
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700535 for i := 0; i < mounttablelib.DefaultMaxNodesPerUser()-5; i++ {
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700536 node := fmt.Sprintf("users/alice/a/b/c/d/%d", i)
537 doSetPermissions(t, aliceCtx, estr, node, perms, "", true)
538 }
539 doSetPermissions(t, aliceCtx, estr, "users/alice/a/b/c/d/straw", perms, "", false)
540
541 // See if the stats numbers are correct.
542 testcases := []struct {
543 key string
544 expected interface{}
545 }{
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700546 {"alice", int64(mounttablelib.DefaultMaxNodesPerUser())},
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700547 {"bob", int64(0)},
548 {"root", int64(0)},
David Why Use Two When One Will Do Presotto67b70712015-06-02 13:13:58 -0700549 {conventions.ServerUser, int64(3)},
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700550 }
551 for _, tc := range testcases {
552 name := "testAccessListTemplate/num-nodes-per-user/" + tc.key
553 got, err := libstats.Value(name)
554 if err != nil {
555 t.Errorf("unexpected error getting map entry for %s: %s", name, err)
556 }
557 if got != tc.expected {
558 t.Errorf("unexpected getting map entry for %s. Got %v, want %v", name, got, tc.expected)
559 }
560 }
561}
562
563func getUserNodeCounts(t *testing.T) (counts map[string]int32) {
564 s, err := libstats.Value("mounttable/num-nodes-per-user")
565 if err != nil {
566 boom(t, "Can't get mounttable statistics")
567 }
568 // This string is a json encoded map. Decode.
569 switch v := s.(type) {
570 default:
571 boom(t, "Wrong type for mounttable statistics")
572 case string:
573 err = json.Unmarshal([]byte(v), &counts)
574 if err != nil {
575 boom(t, "Can't unmarshal mounttable statistics")
576 }
577 }
578 return
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800579}
580
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700581func TestGlobAccessLists(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800582 rootCtx, aliceCtx, bobCtx, shutdown := initTest()
583 defer shutdown()
584
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700585 stop, estr := newMT(t, "testdata/test.perms", "", "testGlobAccessLists", rootCtx)
586 defer stop()
Ryan Brownac972652014-05-19 10:57:32 -0700587
588 // set up a mount space
589 fakeServer := naming.JoinAddressName(estr, "quux")
Asim Shankar43d1f932015-03-24 20:57:56 -0700590 doMount(t, aliceCtx, estr, "one/bright/day", fakeServer, false) // Fails because alice can't mount there.
591 doMount(t, bobCtx, estr, "one/bright/day", fakeServer, true)
592 doMount(t, rootCtx, estr, "a/b/c", fakeServer, true)
Ryan Brownac972652014-05-19 10:57:32 -0700593
594 // Try various globs.
595 tests := []struct {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800596 ctx *context.T
Ryan Brownac972652014-05-19 10:57:32 -0700597 in string
598 expected []string
599 }{
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800600 {rootCtx, "*", []string{"one", "a", "stuff", "users"}},
601 {aliceCtx, "*", []string{"one", "a", "users"}},
602 {bobCtx, "*", []string{"one", "stuff", "users"}},
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800603 // bob, alice, and root have different visibility to the space.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800604 {rootCtx, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c", "stuff", "users"}},
605 {aliceCtx, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c", "users"}},
606 {bobCtx, "*/...", []string{"one", "one/bright", "one/bright/day", "stuff", "users"}},
Ryan Brownac972652014-05-19 10:57:32 -0700607 }
608 for _, test := range tests {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800609 out := doGlob(t, test.ctx, estr, "", test.in)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700610 checkMatch(t, test.expected, out)
611 }
612}
613
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800614func TestCleanup(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700615 rootCtx, shutdown := test.V23Init()
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800616 defer shutdown()
617
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700618 stop, estr := newMT(t, "", "", "testCleanup", rootCtx)
619 defer stop()
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800620
621 // Set up one mount.
622 fakeServer := naming.JoinAddressName(estr, "quux")
Asim Shankar43d1f932015-03-24 20:57:56 -0700623 doMount(t, rootCtx, estr, "one/bright/day", fakeServer, true)
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800624 checkMatch(t, []string{"one", "one/bright", "one/bright/day"}, doGlob(t, rootCtx, estr, "", "*/..."))
625
626 // After the unmount nothing should be left
627 doUnmount(t, rootCtx, estr, "one/bright/day", "", true)
David Why Use Two When One Will Do Presotto4d26a992015-05-06 10:17:09 -0700628 checkMatch(t, nil, doGlob(t, rootCtx, estr, "", "one"))
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800629 checkMatch(t, nil, doGlob(t, rootCtx, estr, "", "*/..."))
630
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700631 // Set up a mount, then set the AccessList.
Asim Shankar43d1f932015-03-24 20:57:56 -0700632 doMount(t, rootCtx, estr, "one/bright/day", fakeServer, true)
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800633 checkMatch(t, []string{"one", "one/bright", "one/bright/day"}, doGlob(t, rootCtx, estr, "", "*/..."))
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700634 perms := access.Permissions{"Read": access.AccessList{In: []security.BlessingPattern{security.AllPrincipals}}}
635 doSetPermissions(t, rootCtx, estr, "one/bright", perms, "", true)
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800636
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700637 // After the unmount we should still have everything above the AccessList.
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800638 doUnmount(t, rootCtx, estr, "one/bright/day", "", true)
639 checkMatch(t, []string{"one", "one/bright"}, doGlob(t, rootCtx, estr, "", "*/..."))
640}
641
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800642func TestDelete(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800643 rootCtx, aliceCtx, bobCtx, shutdown := initTest()
644 defer shutdown()
645
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700646 stop, estr := newMT(t, "testdata/test.perms", "", "testDelete", rootCtx)
647 defer stop()
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800648
649 // set up a mount space
650 fakeServer := naming.JoinAddressName(estr, "quux")
Asim Shankar43d1f932015-03-24 20:57:56 -0700651 doMount(t, bobCtx, estr, "one/bright/day", fakeServer, true)
652 doMount(t, rootCtx, estr, "a/b/c", fakeServer, true)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800653
654 // It shouldn't be possible to delete anything with children unless explicitly requested.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800655 doDeleteNode(t, rootCtx, estr, "a/b", false)
656 checkExists(t, rootCtx, estr, "a/b", true)
657 doDeleteSubtree(t, rootCtx, estr, "a/b", true)
658 checkExists(t, rootCtx, estr, "a/b", false)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800659
660 // Alice shouldn't be able to delete what bob created but bob and root should.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800661 doDeleteNode(t, aliceCtx, estr, "one/bright/day", false)
662 checkExists(t, rootCtx, estr, "one/bright/day", true)
663 doDeleteNode(t, rootCtx, estr, "one/bright/day", true)
664 checkExists(t, rootCtx, estr, "one/bright/day", false)
665 doDeleteNode(t, bobCtx, estr, "one/bright", true)
666 checkExists(t, rootCtx, estr, "one/bright", false)
David Why Use Two When One Will Do Presottoe43213b2015-06-02 10:33:10 -0700667
668 // Make sure directory admin can delete directory children.
669 perms := access.Permissions{"Admin": access.AccessList{In: []security.BlessingPattern{"bob"}}}
670 doSetPermissions(t, bobCtx, estr, "hoohaa", perms, "", false)
671 doDeleteNode(t, rootCtx, estr, "hoohaa", true)
672 checkExists(t, rootCtx, estr, "hoohaa", false)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800673}
674
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700675func TestServerFormat(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700676 rootCtx, shutdown := test.V23Init()
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800677 defer shutdown()
678
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700679 stop, estr := newMT(t, "", "", "testerverFormat", rootCtx)
680 defer stop()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700681
Asim Shankar43d1f932015-03-24 20:57:56 -0700682 doMount(t, rootCtx, estr, "endpoint", naming.JoinAddressName(estr, "life/on/the/mississippi"), true)
683 doMount(t, rootCtx, estr, "hostport", "/atrampabroad:8000", true)
684 doMount(t, rootCtx, estr, "invalid/not/rooted", "atrampabroad:8000", false)
685 doMount(t, rootCtx, estr, "invalid/no/port", "/atrampabroad", false)
686 doMount(t, rootCtx, estr, "invalid/endpoint", "/@following the equator:8000@@@", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700687}
688
689func TestExpiry(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700690 rootCtx, shutdown := test.V23Init()
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800691 defer shutdown()
692
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700693 stop, estr := newMT(t, "", "", "testExpiry", rootCtx)
694 defer stop()
695 stop, collectionAddr := newCollection(t, rootCtx)
696 defer stop()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700697
698 collectionName := naming.JoinAddressName(collectionAddr, "collection")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700699
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700700 ft := mounttablelib.NewFakeTimeClock()
701 mounttablelib.SetServerListClock(ft)
Asim Shankar43d1f932015-03-24 20:57:56 -0700702 doMount(t, rootCtx, estr, "a1/b1", collectionName, true)
703 doMount(t, rootCtx, estr, "a1/b2", collectionName, true)
704 doMount(t, rootCtx, estr, "a2/b1", collectionName, true)
705 doMount(t, rootCtx, estr, "a2/b2/c", collectionName, true)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700706
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800707 checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, rootCtx, estr, "", "*/b1/..."))
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700708 ft.Advance(time.Duration(ttlSecs/2) * time.Second)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800709 checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, rootCtx, estr, "", "*/b1/..."))
710 checkMatch(t, []string{"c"}, doGlob(t, rootCtx, estr, "a2/b2", "*"))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700711 // Refresh only a1/b1. All the other mounts will expire upon the next
712 // ft advance.
Asim Shankar43d1f932015-03-24 20:57:56 -0700713 doMount(t, rootCtx, estr, "a1/b1", collectionName, true)
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700714 ft.Advance(time.Duration(ttlSecs/2+4) * time.Second)
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800715 checkMatch(t, []string{"a1", "a1/b1"}, doGlob(t, rootCtx, estr, "", "*/..."))
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800716 checkMatch(t, []string{"a1/b1"}, doGlob(t, rootCtx, estr, "", "*/b1/..."))
Ryan Brownac972652014-05-19 10:57:32 -0700717}
718
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700719func TestBadAccessLists(t *testing.T) {
Cosmos Nicolaou27dc65b2015-07-10 16:23:19 -0700720 ctx, shutdown := test.TestContext()
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700721 defer shutdown()
722 _, err := mounttablelib.NewMountTableDispatcher(ctx, "testdata/invalid.perms", "", "mounttable")
Ryan Brownac972652014-05-19 10:57:32 -0700723 if err == nil {
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700724 boom(t, "Expected json parse error in permissions file")
Ryan Brownac972652014-05-19 10:57:32 -0700725 }
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700726 _, err = mounttablelib.NewMountTableDispatcher(ctx, "testdata/doesntexist.perms", "", "mounttable")
Robin Thellendc4b51692015-02-05 17:11:16 -0800727 if err != nil {
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700728 boom(t, "Missing permissions file should not cause an error")
Ryan Brownac972652014-05-19 10:57:32 -0700729 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700730}
Asim Shankar88292912014-10-09 19:41:07 -0700731
Robin Thellend0aed6da2015-04-17 14:39:35 -0700732func getCounter(t *testing.T, ctx *context.T, name string) int64 {
733 st := stats.StatsClient(name)
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700734 v, err := st.Value(ctx)
735 if err != nil {
Robin Thellend0aed6da2015-04-17 14:39:35 -0700736 t.Fatalf("Failed to get %q: %v", name, err)
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700737 return -1
738 }
739 var value int64
740 if err := vdl.Convert(&value, v); err != nil {
Robin Thellend0aed6da2015-04-17 14:39:35 -0700741 t.Fatalf("Unexpected value type for %q: %v", name, err)
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700742 }
743 return value
744}
745
Robin Thellend0aed6da2015-04-17 14:39:35 -0700746func nodeCount(t *testing.T, ctx *context.T, addr string) int64 {
747 name := naming.JoinAddressName(addr, "__debug/stats/mounttable/num-nodes")
748 return getCounter(t, ctx, name)
749}
750
751func serverCount(t *testing.T, ctx *context.T, addr string) int64 {
752 name := naming.JoinAddressName(addr, "__debug/stats/mounttable/num-mounted-servers")
753 return getCounter(t, ctx, name)
754}
755
756func TestStatsCounters(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700757 rootCtx, shutdown := test.V23Init()
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700758 defer shutdown()
759
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700760 ft := mounttablelib.NewFakeTimeClock()
761 mounttablelib.SetServerListClock(ft)
Robin Thellend62909b22015-04-23 13:54:55 -0700762
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700763 stop, estr := newMT(t, "", "", "mounttable", rootCtx)
764 defer stop()
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700765
766 // Test flat tree
767 for i := 1; i <= 10; i++ {
768 name := fmt.Sprintf("node%d", i)
769 addr := naming.JoinAddressName(estr, name)
770 doMount(t, rootCtx, estr, name, addr, true)
771 if expected, got := int64(i+1), nodeCount(t, rootCtx, estr); got != expected {
772 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
773 }
Robin Thellend0aed6da2015-04-17 14:39:35 -0700774 if expected, got := int64(i), serverCount(t, rootCtx, estr); got != expected {
775 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
776 }
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700777 }
778 for i := 1; i <= 10; i++ {
779 name := fmt.Sprintf("node%d", i)
780 if i%2 == 0 {
781 doUnmount(t, rootCtx, estr, name, "", true)
782 } else {
783 doDeleteSubtree(t, rootCtx, estr, name, true)
784 }
785 if expected, got := int64(11-i), nodeCount(t, rootCtx, estr); got != expected {
786 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
787 }
Robin Thellend0aed6da2015-04-17 14:39:35 -0700788 if expected, got := int64(10-i), serverCount(t, rootCtx, estr); got != expected {
789 t.Errorf("Unexpected number of server. Got %d, expected %d", got, expected)
790 }
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700791 }
792
793 // Test deep tree
794 doMount(t, rootCtx, estr, "1/2/3/4/5/6/7/8/9a/10", naming.JoinAddressName(estr, ""), true)
795 doMount(t, rootCtx, estr, "1/2/3/4/5/6/7/8/9b/11", naming.JoinAddressName(estr, ""), true)
796 if expected, got := int64(13), nodeCount(t, rootCtx, estr); got != expected {
797 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
798 }
Robin Thellend0aed6da2015-04-17 14:39:35 -0700799 if expected, got := int64(2), serverCount(t, rootCtx, estr); got != expected {
800 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
801 }
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700802 doDeleteSubtree(t, rootCtx, estr, "1/2/3/4/5", true)
803 if expected, got := int64(5), nodeCount(t, rootCtx, estr); got != expected {
804 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
805 }
Robin Thellend0aed6da2015-04-17 14:39:35 -0700806 if expected, got := int64(0), serverCount(t, rootCtx, estr); got != expected {
807 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
808 }
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700809 doDeleteSubtree(t, rootCtx, estr, "1", true)
810 if expected, got := int64(1), nodeCount(t, rootCtx, estr); got != expected {
811 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
812 }
Robin Thellend0aed6da2015-04-17 14:39:35 -0700813
814 // Test multiple servers per node
815 for i := 1; i <= 5; i++ {
816 server := naming.JoinAddressName(estr, fmt.Sprintf("addr%d", i))
817 doMount(t, rootCtx, estr, "node1", server, true)
818 doMount(t, rootCtx, estr, "node2", server, true)
819 if expected, got := int64(3), nodeCount(t, rootCtx, estr); got != expected {
820 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
821 }
822 if expected, got := int64(2*i), serverCount(t, rootCtx, estr); got != expected {
823 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
824 }
825 }
826 doUnmount(t, rootCtx, estr, "node1", "", true)
827 if expected, got := int64(2), nodeCount(t, rootCtx, estr); got != expected {
828 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
829 }
830 if expected, got := int64(5), serverCount(t, rootCtx, estr); got != expected {
831 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
832 }
833 for i := 1; i <= 5; i++ {
834 server := naming.JoinAddressName(estr, fmt.Sprintf("addr%d", i))
835 doUnmount(t, rootCtx, estr, "node2", server, true)
836 expectedNodes := int64(2)
837 if i == 5 {
838 expectedNodes = 1
839 }
840 if expected, got := expectedNodes, nodeCount(t, rootCtx, estr); got != expected {
841 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
842 }
843 if expected, got := int64(5-i), serverCount(t, rootCtx, estr); got != expected {
844 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
845 }
846 }
Robin Thellend93b1f6d2015-04-22 12:31:34 -0700847
848 // Mount on an existing intermediate node.
849 doMount(t, rootCtx, estr, "1/2/3/4/5/6/7/8/9a/10", naming.JoinAddressName(estr, ""), true)
850 doMount(t, rootCtx, estr, "1/2/3/4/5", naming.JoinAddressName(estr, ""), true)
851 if expected, got := int64(6), nodeCount(t, rootCtx, estr); got != expected {
852 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
853 }
854 if expected, got := int64(1), serverCount(t, rootCtx, estr); got != expected {
855 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
856 }
Robin Thellend62909b22015-04-23 13:54:55 -0700857
858 // Test expired mounts
859 // "1/2/3/4/5" is still mounted from earlier.
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700860 ft.Advance(time.Duration(ttlSecs+4) * time.Second)
Robin Thellend62909b22015-04-23 13:54:55 -0700861 if _, err := resolve(rootCtx, naming.JoinAddressName(estr, "1/2/3/4/5")); err == nil {
862 t.Errorf("Expected failure. Got success")
863 }
864 if expected, got := int64(0), serverCount(t, rootCtx, estr); got != expected {
865 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
866 }
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700867}
868
David Why Use Two When One Will Do Presottoe3e932c2015-05-15 14:59:46 -0700869func TestIntermediateNodesCreatedFromConfig(t *testing.T) {
870 rootCtx, _, _, shutdown := initTest()
871 defer shutdown()
872
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700873 stop, estr := newMT(t, "testdata/intermediate.perms", "", "TestIntermediateNodesCreatedFromConfig", rootCtx)
874 defer stop()
David Why Use Two When One Will Do Presottoe3e932c2015-05-15 14:59:46 -0700875
876 // x and x/y should have the same permissions at the root.
877 rootPerms, _ := doGetPermissions(t, rootCtx, estr, "", true)
878 if perms, _ := doGetPermissions(t, rootCtx, estr, "x", true); !reflect.DeepEqual(rootPerms, perms) {
879 boom(t, "for x got %v, want %v", perms, rootPerms)
880 }
881 if perms, _ := doGetPermissions(t, rootCtx, estr, "x/y", true); !reflect.DeepEqual(rootPerms, perms) {
882 boom(t, "for x/y got %v, want %v", perms, rootPerms)
883 }
884 if perms, _ := doGetPermissions(t, rootCtx, estr, "x/y/z", true); reflect.DeepEqual(rootPerms, perms) {
885 boom(t, "for x/y/z got %v, don't want %v", perms, rootPerms)
886 }
887}
888
Jiri Simsa6ac95222015-02-23 16:11:49 -0800889func initTest() (rootCtx *context.T, aliceCtx *context.T, bobCtx *context.T, shutdown v23.Shutdown) {
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -0700890 test.Init()
Todd Wang60052d82015-05-22 15:00:10 -0700891 ctx, shutdown := test.V23Init()
Asim Shankar88292912014-10-09 19:41:07 -0700892 var err error
Todd Wangad492042015-04-17 15:58:40 -0700893 if rootCtx, err = v23.WithPrincipal(ctx, testutil.NewPrincipal("root")); err != nil {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800894 panic("failed to set root principal")
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800895 }
Todd Wangad492042015-04-17 15:58:40 -0700896 if aliceCtx, err = v23.WithPrincipal(ctx, testutil.NewPrincipal("alice")); err != nil {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800897 panic("failed to set alice principal")
Asim Shankar88292912014-10-09 19:41:07 -0700898 }
Todd Wangad492042015-04-17 15:58:40 -0700899 if bobCtx, err = v23.WithPrincipal(ctx, testutil.NewPrincipal("bob")); err != nil {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800900 panic("failed to set bob principal")
Asim Shankar88292912014-10-09 19:41:07 -0700901 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800902 for _, r := range []*context.T{rootCtx, aliceCtx, bobCtx} {
Asim Shankar8bc78d62015-02-03 16:53:27 -0800903 // A hack to set the namespace roots to a value that won't work.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800904 v23.GetNamespace(r).SetRoots()
Asim Shankar8bc78d62015-02-03 16:53:27 -0800905 // And have all principals recognize each others blessings.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800906 p1 := v23.GetPrincipal(r)
Asim Shankar8bc78d62015-02-03 16:53:27 -0800907 for _, other := range []*context.T{rootCtx, aliceCtx, bobCtx} {
Asim Shankar4a698282015-03-21 21:59:18 -0700908 // testutil.NewPrincipal has already setup each
Asim Shankar8bc78d62015-02-03 16:53:27 -0800909 // principal to use the same blessing for both server
910 // and client activities.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800911 if err := p1.AddToRoots(v23.GetPrincipal(other).BlessingStore().Default()); err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700912 panic(err)
913 }
914 }
915 }
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800916 return rootCtx, aliceCtx, bobCtx, shutdown
Asim Shankar88292912014-10-09 19:41:07 -0700917}