blob: 981bc7ac98beb6b4fcd4ad873e9bd8f699f9dd8c [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"
Jiri Simsa6ac95222015-02-23 16:11:49 -080021 "v.io/v23/naming"
22 "v.io/v23/options"
Matt Rosencrantz94502cf2015-03-18 09:43:44 -070023 "v.io/v23/rpc"
Jiri Simsa6ac95222015-02-23 16:11:49 -080024 "v.io/v23/security"
Todd Wang387d8a42015-03-30 17:09:05 -070025 "v.io/v23/security/access"
Asim Shankarb425c552015-07-10 02:18:59 -070026 "v.io/v23/services/mounttable"
Robin Thellendfd82dcc2015-04-14 21:16:59 -070027 "v.io/v23/services/stats"
28 "v.io/v23/vdl"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070029
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -070030 libstats "v.io/x/ref/lib/stats"
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -070031 "v.io/x/ref/lib/xrpc"
Robin Thellendfd82dcc2015-04-14 21:16:59 -070032 "v.io/x/ref/services/debug/debuglib"
Matt Rosencrantz165e8902015-06-12 15:27:27 -070033 "v.io/x/ref/services/mounttable/mounttablelib"
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -070034 "v.io/x/ref/test"
Asim Shankar4a698282015-03-21 21:59:18 -070035 "v.io/x/ref/test/testutil"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070036)
37
Matt Rosencrantz165e8902015-06-12 15:27:27 -070038func init() {
39 test.Init()
40}
41
Asim Shankar88292912014-10-09 19:41:07 -070042// Simulate different processes with different runtimes.
Matt Rosencrantz6edab562015-01-12 11:07:55 -080043// rootCtx is the one running the mounttable service.
Jiri Simsa5293dcb2014-05-10 09:56:38 -070044const ttlSecs = 60 * 60
45
46func boom(t *testing.T, f string, v ...interface{}) {
47 t.Logf(f, v...)
48 t.Fatal(string(debug.Stack()))
49}
50
Asim Shankar43d1f932015-03-24 20:57:56 -070051func 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 -070052 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080053 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -070054 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 -070055 if !shouldSucceed {
56 return
57 }
58 boom(t, "Failed to Mount %s onto %s: %s", service, name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070059 }
60}
61
Matt Rosencrantz6edab562015-01-12 11:07:55 -080062func 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 -070063 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080064 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -070065 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 -070066 if !shouldSucceed {
67 return
68 }
Alex Fandriantoa2e7c372015-04-20 10:46:10 -070069 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 -070070 }
71}
72
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070073func 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 -080074 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080075 client := v23.GetClient(ctx)
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070076 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 -080077 if !shouldSucceed {
78 return
79 }
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -070080 boom(t, "Failed to GetPermissions %s: %s", name, err)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080081 }
82 return
83}
84
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070085func 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 -080086 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080087 client := v23.GetClient(ctx)
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -070088 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 -080089 if !shouldSucceed {
90 return
91 }
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -070092 boom(t, "Failed to SetPermissions %s: %s", name, err)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080093 }
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -080094}
95
Matt Rosencrantz6edab562015-01-12 11:07:55 -080096func 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 -080097 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -080098 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -070099 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 -0800100 if !shouldSucceed {
101 return
102 }
103 boom(t, "Failed to Delete node %s: %s", name, err)
104 }
105}
106
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800107func 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 -0800108 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -0800109 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700110 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 -0800111 if !shouldSucceed {
112 return
113 }
114 boom(t, "Failed to Delete subtree %s: %s", name, err)
115 }
116}
117
Todd Wang2331dd02015-03-17 15:38:39 -0700118func mountentry2names(e *naming.MountEntry) []string {
Asim Shankar8bc78d62015-02-03 16:53:27 -0800119 names := make([]string, len(e.Servers))
120 for idx, s := range e.Servers {
121 names[idx] = naming.JoinAddressName(s.Server, e.Name)
122 }
123 return names
124}
125
126func strslice(strs ...string) []string {
127 return strs
128}
129
Todd Wang2331dd02015-03-17 15:38:39 -0700130func resolve(ctx *context.T, name string) (*naming.MountEntry, error) {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700131 // Resolve the name one level.
Todd Wang2331dd02015-03-17 15:38:39 -0700132 var entry naming.MountEntry
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700133 client := v23.GetClient(ctx)
134 if err := client.Call(ctx, name, "ResolveStep", nil, []interface{}{&entry}, options.NoResolve{}); err != nil {
Todd Wange77f9952015-02-18 13:20:50 -0800135 return nil, err
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700136 }
137 if len(entry.Servers) < 1 {
Asim Shankar8bc78d62015-02-03 16:53:27 -0800138 return nil, errors.New("resolve returned no servers")
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700139 }
Asim Shankar8bc78d62015-02-03 16:53:27 -0800140 return &entry, nil
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700141}
142
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800143func export(t *testing.T, ctx *context.T, name, contents string) {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700144 // Resolve the name.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800145 resolved, err := resolve(ctx, name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700146 if err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700147 boom(t, "Failed to Export.Resolve %s: %s", name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700148 }
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700149 // Export the value.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800150 client := v23.GetClient(ctx)
Suharsh Sivakumar1abd5a82015-04-10 00:24:14 -0700151 if err := client.Call(ctx, mountentry2names(resolved)[0], "Export", []interface{}{contents, true}, nil, options.NoResolve{}); err != nil {
152 boom(t, "Failed to Export.Call %s to %s: %s", name, contents, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700153 }
154}
155
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800156func 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 -0700157 // Resolve the name.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800158 resolved, err := resolve(ctx, name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700159 if err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700160 if !shouldSucceed {
161 return
162 }
163 boom(t, "Failed to Resolve %s: %s", name, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700164 }
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700165 // Look up the value.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800166 client := v23.GetClient(ctx)
Asim Shankar8bc78d62015-02-03 16:53:27 -0800167 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 -0700168 if err != nil {
169 if shouldSucceed {
170 boom(t, "Failed Lookup.StartCall %s: %s", name, err)
171 }
172 return
173 }
174 var contents []byte
Todd Wange77f9952015-02-18 13:20:50 -0800175 if err := call.Finish(&contents); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700176 if shouldSucceed {
177 boom(t, "Failed to Lookup %s: %s", name, err)
178 }
179 return
180 }
181 if string(contents) != expected {
182 boom(t, "Lookup %s, expected %q, got %q", name, expected, contents)
183 }
184 if !shouldSucceed {
185 boom(t, "Lookup %s, expected failure, got %q", name, contents)
186 }
187}
188
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700189func newMT(t *testing.T, permsFile, persistDir, statsDir string, rootCtx *context.T) (func() error, string) {
Cosmos Nicolaou64d573d2015-07-13 16:22:18 -0700190 reservedDisp := debuglib.NewDispatcher(nil)
Todd Wangad492042015-04-17 15:58:40 -0700191 ctx := v23.WithReservedNameDispatcher(rootCtx, reservedDisp)
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700192
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700193 // Add mount table service.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700194 mt, err := mounttablelib.NewMountTableDispatcher(ctx, permsFile, persistDir, statsDir)
Ryan Brownac972652014-05-19 10:57:32 -0700195 if err != nil {
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700196 boom(t, "mounttablelib.NewMountTableDispatcher: %v", err)
Ryan Brownac972652014-05-19 10:57:32 -0700197 }
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700198
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700199 // Start serving on a loopback address.
200 server, err := xrpc.NewDispatchingServer(ctx, "", mt, options.ServesMountTable(true))
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700201 if err != nil {
202 boom(t, "r.NewServer: %s", err)
203 }
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700204
205 estr := server.Status().Endpoints[0].String()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700206 t.Logf("endpoint %s", estr)
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700207 return server.Stop, estr
208}
209
210func newCollection(t *testing.T, rootCtx *context.T) (func() error, string) {
211 // Start serving a collection service on a loopback address. This
212 // is just a service we can mount and test against.
213 server, err := xrpc.NewDispatchingServer(rootCtx, "collection", newCollectionServer())
214 if err != nil {
215 boom(t, "r.NewServer: %s", err)
216 }
217 estr := server.Status().Endpoints[0].String()
218 t.Logf("endpoint %s", estr)
219 return server.Stop, estr
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700220}
221
222func TestMountTable(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800223 rootCtx, aliceCtx, bobCtx, shutdown := initTest()
224 defer shutdown()
225
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700226 stop, mtAddr := newMT(t, "testdata/test.perms", "", "testMountTable", rootCtx)
227 defer stop()
228 stop, collectionAddr := newCollection(t, rootCtx)
229 defer stop()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700230
231 collectionName := naming.JoinAddressName(collectionAddr, "collection")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700232
233 // Mount the collection server into the mount table.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700234 rootCtx.Infof("Mount the collection server into the mount table.")
Asim Shankar43d1f932015-03-24 20:57:56 -0700235 doMount(t, rootCtx, mtAddr, "stuff", collectionName, true)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700236
237 // Create a few objects and make sure we can read them.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700238 rootCtx.Infof("Create a few objects.")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800239 export(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/the/rain"), "the rain")
240 export(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/in/spain"), "in spain")
241 export(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/falls"), "falls mainly on the plain")
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700242 rootCtx.Infof("Make sure we can read them.")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800243 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/the/rain"), "the rain", true)
244 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/in/spain"), "in spain", true)
245 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/falls"), "falls mainly on the plain", true)
246 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "/stuff/falls"), "falls mainly on the plain", true)
247 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/nonexistant"), "falls mainly on the plain", false)
248 checkContents(t, bobCtx, naming.JoinAddressName(mtAddr, "stuff/the/rain"), "the rain", true)
249 checkContents(t, aliceCtx, naming.JoinAddressName(mtAddr, "stuff/the/rain"), "the rain", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700250
251 // Test multiple mounts.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700252 rootCtx.Infof("Multiple mounts.")
Asim Shankar43d1f932015-03-24 20:57:56 -0700253 doMount(t, rootCtx, mtAddr, "a/b", collectionName, true)
254 doMount(t, rootCtx, mtAddr, "x/y", collectionName, true)
255 doMount(t, rootCtx, mtAddr, "alpha//beta", collectionName, true)
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700256 rootCtx.Infof("Make sure we can read them.")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800257 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuff/falls"), "falls mainly on the plain", true)
258 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "a/b/falls"), "falls mainly on the plain", true)
259 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "x/y/falls"), "falls mainly on the plain", true)
260 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "alpha/beta/falls"), "falls mainly on the plain", true)
261 checkContents(t, aliceCtx, naming.JoinAddressName(mtAddr, "a/b/falls"), "falls mainly on the plain", true)
262 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 -0800263
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700264 // Test getting/setting AccessLists.
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700265 perms, version := doGetPermissions(t, rootCtx, mtAddr, "stuff", true)
266 doSetPermissions(t, rootCtx, mtAddr, "stuff", perms, "xyzzy", false) // bad version
267 doSetPermissions(t, rootCtx, mtAddr, "stuff", perms, version, true) // correct version
Adam Sadovskyb1f9e3c2015-04-08 11:03:49 -0700268 _, nversion := doGetPermissions(t, rootCtx, mtAddr, "stuff", true)
269 if nversion == version {
270 boom(t, "version didn't change after SetPermissions: %s", nversion)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800271 }
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700272 doSetPermissions(t, rootCtx, mtAddr, "stuff", perms, "", true) // no version
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800273
274 // 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 -0700275 doSetPermissions(t, aliceCtx, mtAddr, "onlybob", perms, "", false)
276 doSetPermissions(t, bobCtx, mtAddr, "onlybob", perms, "", true)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700277
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700278 // Test that setting Permissions to permissions that don't include the the setter's
Suharsh Sivakumar7120abd2015-04-15 13:54:23 -0700279 // blessings in Admin, automatically add their Blessings to Admin to prevent
280 // locking everyone out.
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700281 perms, _ = doGetPermissions(t, bobCtx, mtAddr, "onlybob", true)
282 noRootPerms := perms.Copy()
283 noRootPerms.Clear("bob", "Admin")
284 doSetPermissions(t, bobCtx, mtAddr, "onlybob", noRootPerms, "", true)
Suharsh Sivakumar7120abd2015-04-15 13:54:23 -0700285 // This should succeed, because "bob" should automatically be added to "Admin"
286 // even though he cleared himself from "Admin".
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700287 doSetPermissions(t, bobCtx, mtAddr, "onlybob", perms, "", true)
288 // Test that adding a non-standard perms is normalized when retrieved.
289 admin := perms["Admin"]
Suharsh Sivakumar7120abd2015-04-15 13:54:23 -0700290 admin.In = []security.BlessingPattern{"bob", "bob"}
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700291 perms["Admin"] = admin
292 doSetPermissions(t, bobCtx, mtAddr, "onlybob", perms, "", true)
293 perms, _ = doGetPermissions(t, bobCtx, mtAddr, "onlybob", true)
294 if got, want := perms["Admin"].In, []security.BlessingPattern{"bob"}; !reflect.DeepEqual(got, want) {
Suharsh Sivakumar7120abd2015-04-15 13:54:23 -0700295 boom(t, "got %v, want %v", got, want)
296 }
297
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700298 // Test generic unmount.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700299 rootCtx.Info("Test generic unmount.")
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800300 doUnmount(t, rootCtx, mtAddr, "a/b", "", true)
301 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "a/b/falls"), "falls mainly on the plain", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700302
303 // Test specific unmount.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700304 rootCtx.Info("Test specific unmount.")
Asim Shankar43d1f932015-03-24 20:57:56 -0700305 doMount(t, rootCtx, mtAddr, "a/b", collectionName, true)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800306 doUnmount(t, rootCtx, mtAddr, "a/b", collectionName, true)
307 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "a/b/falls"), "falls mainly on the plain", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700308
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700309 // Try timing out a mount.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700310 rootCtx.Info("Try timing out a mount.")
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700311 ft := mounttablelib.NewFakeTimeClock()
312 mounttablelib.SetServerListClock(ft)
Asim Shankar43d1f932015-03-24 20:57:56 -0700313 doMount(t, rootCtx, mtAddr, "stuffWithTTL", collectionName, true)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800314 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuffWithTTL/the/rain"), "the rain", true)
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700315 ft.Advance(time.Duration(ttlSecs+4) * time.Second)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800316 checkContents(t, rootCtx, naming.JoinAddressName(mtAddr, "stuffWithTTL/the/rain"), "the rain", false)
Ryan Brownac972652014-05-19 10:57:32 -0700317
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700318 // Test unauthorized mount.
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700319 rootCtx.Info("Test unauthorized mount.")
Asim Shankar43d1f932015-03-24 20:57:56 -0700320 doMount(t, bobCtx, mtAddr, "/a/b", collectionName, false)
321 doMount(t, aliceCtx, mtAddr, "/a/b", collectionName, false)
Ryan Brownac972652014-05-19 10:57:32 -0700322
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800323 doUnmount(t, bobCtx, mtAddr, "x/y", collectionName, false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700324}
325
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800326func 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 -0700327 name := naming.JoinAddressName(ep, suffix)
Jiri Simsa6ac95222015-02-23 16:11:49 -0800328 client := v23.GetClient(ctx)
Matt Rosencrantz94502cf2015-03-18 09:43:44 -0700329 call, err := client.StartCall(ctx, name, rpc.GlobMethod, []interface{}{pattern}, options.NoResolve{})
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700330 if err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700331 boom(t, "Glob.StartCall %s %s: %s", name, pattern, err)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700332 }
333 var reply []string
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700334 for {
Todd Wang2331dd02015-03-17 15:38:39 -0700335 var gr naming.GlobReply
David Why Use Two When One Will Do Presottoe5e62d02015-02-19 14:35:20 -0800336 err := call.Recv(&gr)
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700337 if err == io.EOF {
338 break
339 }
340 if err != nil {
341 boom(t, "Glob.StartCall %s: %s", name, pattern, err)
342 }
David Why Use Two When One Will Do Presottoe5e62d02015-02-19 14:35:20 -0800343 switch v := gr.(type) {
Todd Wang2331dd02015-03-17 15:38:39 -0700344 case naming.GlobReplyEntry:
David Why Use Two When One Will Do Presottoe5e62d02015-02-19 14:35:20 -0800345 if joinServer && len(v.Value.Servers) > 0 {
346 reply = append(reply, naming.JoinAddressName(v.Value.Servers[0].Server, v.Value.Name))
347 } else {
348 reply = append(reply, v.Value.Name)
349 }
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700350 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700351 }
Todd Wange77f9952015-02-18 13:20:50 -0800352 if err := call.Finish(); err != nil {
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700353 boom(t, "Glob.Finish %s: %s", name, pattern, err)
Shyam Jayaramanc4aed6e2014-07-22 14:25:06 -0700354 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700355 return reply
356}
357
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800358func doGlob(t *testing.T, ctx *context.T, ep, suffix, pattern string) []string {
359 return doGlobX(t, ctx, ep, suffix, pattern, false)
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700360}
361
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700362// checkMatch verified that the two slices contain the same string items, albeit
363// not necessarily in the same order. Item repetitions are allowed, but their
364// numbers need to match as well.
365func checkMatch(t *testing.T, want []string, got []string) {
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800366 if len(want) == 0 && len(got) == 0 {
367 return
368 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700369 w := sort.StringSlice(want)
370 w.Sort()
371 g := sort.StringSlice(got)
372 g.Sort()
373 if !reflect.DeepEqual(w, g) {
374 boom(t, "Glob expected %v got %v", want, got)
375 }
376}
377
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800378// checkExists makes sure a name exists (or not).
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800379func checkExists(t *testing.T, ctx *context.T, ep, suffix string, shouldSucceed bool) {
380 x := doGlobX(t, ctx, ep, "", suffix, false)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800381 if len(x) != 1 || x[0] != suffix {
382 if shouldSucceed {
383 boom(t, "Failed to find %s", suffix)
384 }
385 return
386 }
387 if !shouldSucceed {
388 boom(t, "%s exists but shouldn't", suffix)
389 }
390}
391
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700392func TestGlob(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700393 rootCtx, shutdown := test.V23Init()
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800394 defer shutdown()
395
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700396 stop, estr := newMT(t, "", "", "testGlob", rootCtx)
397 defer stop()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700398
399 // set up a mount space
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700400 fakeServer := naming.JoinAddressName(estr, "quux")
Asim Shankar43d1f932015-03-24 20:57:56 -0700401 doMount(t, rootCtx, estr, "one/bright/day", fakeServer, true)
402 doMount(t, rootCtx, estr, "in/the/middle", fakeServer, true)
403 doMount(t, rootCtx, estr, "of/the/night", fakeServer, true)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700404
405 // Try various globs.
406 tests := []struct {
407 in string
408 expected []string
409 }{
410 {"*", []string{"one", "in", "of"}},
Bogdan Capritab6b195a2014-06-11 17:55:03 -0700411 {"...", []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 -0700412 {"*/...", []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 -0700413 {"one/...", []string{"one", "one/bright", "one/bright/day"}},
Robin Thellend434e39f2014-08-27 14:46:27 -0700414 {"of/the/night/two/dead/boys", []string{"of/the/night"}},
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700415 {"*/the", []string{"in/the", "of/the"}},
416 {"*/the/...", []string{"in/the", "of/the", "in/the/middle", "of/the/night"}},
417 {"o*", []string{"one", "of"}},
418 {"", []string{""}},
419 }
420 for _, test := range tests {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800421 out := doGlob(t, rootCtx, estr, "", test.in)
Ryan Brownac972652014-05-19 10:57:32 -0700422 checkMatch(t, test.expected, out)
423 }
Robin Thellend434e39f2014-08-27 14:46:27 -0700424
425 // Test Glob on a name that is under a mounted server. The result should the
426 // the address the mounted server with the extra suffix.
427 {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800428 results := doGlobX(t, rootCtx, estr, "of/the/night/two/dead/boys/got/up/to/fight", "*", true)
Robin Thellend434e39f2014-08-27 14:46:27 -0700429 if len(results) != 1 {
430 boom(t, "Unexpected number of results. Got %v, want 1", len(results))
431 }
David Why Use Two When One Will Do Presotto9c374c22014-10-21 16:16:30 -0700432 _, suffix := naming.SplitAddressName(results[0])
433 if expected := "quux/two/dead/boys/got/up/to/fight"; suffix != expected {
Robin Thellend434e39f2014-08-27 14:46:27 -0700434 boom(t, "Unexpected suffix. Got %v, want %v", suffix, expected)
435 }
436 }
Ryan Brownac972652014-05-19 10:57:32 -0700437}
438
Asim Shankarb425c552015-07-10 02:18:59 -0700439type fakeServerCall struct{}
440
441func (fakeServerCall) Security() security.Call { return security.NewCall(&security.CallParams{}) }
442func (fakeServerCall) Suffix() string { return "" }
443func (fakeServerCall) LocalEndpoint() naming.Endpoint { return nil }
444func (fakeServerCall) RemoteEndpoint() naming.Endpoint { return nil }
445func (fakeServerCall) GrantedBlessings() security.Blessings { return security.Blessings{} }
446func (fakeServerCall) Server() rpc.Server { return nil }
447
448func TestGlobAborts(t *testing.T) {
449 ctx, shutdown := test.V23Init()
450 defer shutdown()
451
452 mt, err := mounttablelib.NewMountTableDispatcher(ctx, "", "", "")
453 if err != nil {
454 t.Fatal(err)
455 }
456
457 mount := func(name string) error {
Asim Shankar56db0852015-07-16 14:25:31 -0700458 invoker, _, _ := mt.Lookup(ctx, name)
Asim Shankarb425c552015-07-10 02:18:59 -0700459 server := naming.FormatEndpoint("tcp", name)
460 return invoker.(mounttable.MountTableServerStub).Mount(ctx, fakeServerCall{}, server, 0, 0)
461 }
462 // Mount 125 entries: 5 "directories" with 25 entries each.
463 for i := 0; i < 5; i++ {
464 for j := 0; j < 25; j++ {
465 if err := mount(fmt.Sprintf("%d/%d", i, j)); err != nil {
466 t.Fatalf("%v (%d, %d)", err, i, j)
467 }
468 }
469 }
470
471 glob := func(ctx *context.T) (int, error) {
Asim Shankar56db0852015-07-16 14:25:31 -0700472 root, _, _ := mt.Lookup(ctx, "")
Asim Shankarb425c552015-07-10 02:18:59 -0700473 ch, err := root.(rpc.Globber).Globber().AllGlobber.Glob__(ctx, fakeServerCall{}, "...")
474 if err != nil {
475 return 0, err
476 }
477 num := 0
478 for range ch {
479 num++
480 }
481 return num, nil
482 }
483
484 got, err := glob(ctx)
485 if err != nil {
486 t.Fatal(err)
487 }
488 if want := 5 + 125 + 1; got != want { // 5 "directories", 125 entries, 1 root entry
489 t.Errorf("Got %d want %d", got, want)
490 }
491 canceled, cancel := context.WithCancel(ctx)
492 cancel()
493 if got, err = glob(canceled); err != nil {
494 t.Fatal(err)
495 }
496 if got != 0 {
497 t.Errorf("Glob returned entries even though the context was cancelled first (returned %d)", got)
498 }
499}
500
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700501func TestAccessListTemplate(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800502 rootCtx, aliceCtx, bobCtx, shutdown := initTest()
503 defer shutdown()
504
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700505 stop, estr := newMT(t, "testdata/test.perms", "", "testAccessListTemplate", rootCtx)
506 defer stop()
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800507 fakeServer := naming.JoinAddressName(estr, "quux")
Tilak Sharmada5165e2014-10-07 16:39:51 -0700508
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800509 // Noone should be able to mount on someone else's names.
Asim Shankar43d1f932015-03-24 20:57:56 -0700510 doMount(t, aliceCtx, estr, "users/ted", fakeServer, false)
511 doMount(t, bobCtx, estr, "users/carol", fakeServer, false)
512 doMount(t, rootCtx, estr, "users/george", fakeServer, false)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800513
514 // Anyone should be able to mount on their own names.
Asim Shankar43d1f932015-03-24 20:57:56 -0700515 doMount(t, aliceCtx, estr, "users/alice", fakeServer, true)
516 doMount(t, bobCtx, estr, "users/bob", fakeServer, true)
517 doMount(t, rootCtx, estr, "users/root", fakeServer, true)
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700518
519 // Make sure the counter works.
520 doUnmount(t, aliceCtx, estr, "users/alice", "", true)
521 doUnmount(t, bobCtx, estr, "users/bob", "", true)
522 doUnmount(t, rootCtx, estr, "users/root", "", true)
523 perms := access.Permissions{"Admin": access.AccessList{In: []security.BlessingPattern{security.AllPrincipals}}}
524 doSetPermissions(t, aliceCtx, estr, "users/alice/a/b/c/d", perms, "", true)
525 doSetPermissions(t, aliceCtx, estr, "users/alice/a/b/c/d", perms, "", true)
526
527 // Do we obey limits?
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700528 for i := 0; i < mounttablelib.DefaultMaxNodesPerUser()-5; i++ {
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700529 node := fmt.Sprintf("users/alice/a/b/c/d/%d", i)
530 doSetPermissions(t, aliceCtx, estr, node, perms, "", true)
531 }
532 doSetPermissions(t, aliceCtx, estr, "users/alice/a/b/c/d/straw", perms, "", false)
533
534 // See if the stats numbers are correct.
535 testcases := []struct {
536 key string
537 expected interface{}
538 }{
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700539 {"alice", int64(mounttablelib.DefaultMaxNodesPerUser())},
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700540 {"bob", int64(0)},
541 {"root", int64(0)},
David Why Use Two When One Will Do Presotto67b70712015-06-02 13:13:58 -0700542 {conventions.ServerUser, int64(3)},
David Why Use Two When One Will Do Presottoc74ac702015-05-07 15:33:52 -0700543 }
544 for _, tc := range testcases {
545 name := "testAccessListTemplate/num-nodes-per-user/" + tc.key
546 got, err := libstats.Value(name)
547 if err != nil {
548 t.Errorf("unexpected error getting map entry for %s: %s", name, err)
549 }
550 if got != tc.expected {
551 t.Errorf("unexpected getting map entry for %s. Got %v, want %v", name, got, tc.expected)
552 }
553 }
554}
555
556func getUserNodeCounts(t *testing.T) (counts map[string]int32) {
557 s, err := libstats.Value("mounttable/num-nodes-per-user")
558 if err != nil {
559 boom(t, "Can't get mounttable statistics")
560 }
561 // This string is a json encoded map. Decode.
562 switch v := s.(type) {
563 default:
564 boom(t, "Wrong type for mounttable statistics")
565 case string:
566 err = json.Unmarshal([]byte(v), &counts)
567 if err != nil {
568 boom(t, "Can't unmarshal mounttable statistics")
569 }
570 }
571 return
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800572}
573
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700574func TestGlobAccessLists(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800575 rootCtx, aliceCtx, bobCtx, shutdown := initTest()
576 defer shutdown()
577
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700578 stop, estr := newMT(t, "testdata/test.perms", "", "testGlobAccessLists", rootCtx)
579 defer stop()
Ryan Brownac972652014-05-19 10:57:32 -0700580
581 // set up a mount space
582 fakeServer := naming.JoinAddressName(estr, "quux")
Asim Shankar43d1f932015-03-24 20:57:56 -0700583 doMount(t, aliceCtx, estr, "one/bright/day", fakeServer, false) // Fails because alice can't mount there.
584 doMount(t, bobCtx, estr, "one/bright/day", fakeServer, true)
585 doMount(t, rootCtx, estr, "a/b/c", fakeServer, true)
Ryan Brownac972652014-05-19 10:57:32 -0700586
587 // Try various globs.
588 tests := []struct {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800589 ctx *context.T
Ryan Brownac972652014-05-19 10:57:32 -0700590 in string
591 expected []string
592 }{
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800593 {rootCtx, "*", []string{"one", "a", "stuff", "users"}},
594 {aliceCtx, "*", []string{"one", "a", "users"}},
595 {bobCtx, "*", []string{"one", "stuff", "users"}},
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800596 // bob, alice, and root have different visibility to the space.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800597 {rootCtx, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c", "stuff", "users"}},
598 {aliceCtx, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c", "users"}},
599 {bobCtx, "*/...", []string{"one", "one/bright", "one/bright/day", "stuff", "users"}},
Ryan Brownac972652014-05-19 10:57:32 -0700600 }
601 for _, test := range tests {
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800602 out := doGlob(t, test.ctx, estr, "", test.in)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700603 checkMatch(t, test.expected, out)
604 }
605}
606
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800607func TestCleanup(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700608 rootCtx, shutdown := test.V23Init()
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800609 defer shutdown()
610
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700611 stop, estr := newMT(t, "", "", "testCleanup", rootCtx)
612 defer stop()
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800613
614 // Set up one mount.
615 fakeServer := naming.JoinAddressName(estr, "quux")
Asim Shankar43d1f932015-03-24 20:57:56 -0700616 doMount(t, rootCtx, estr, "one/bright/day", fakeServer, true)
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800617 checkMatch(t, []string{"one", "one/bright", "one/bright/day"}, doGlob(t, rootCtx, estr, "", "*/..."))
618
619 // After the unmount nothing should be left
620 doUnmount(t, rootCtx, estr, "one/bright/day", "", true)
David Why Use Two When One Will Do Presotto4d26a992015-05-06 10:17:09 -0700621 checkMatch(t, nil, doGlob(t, rootCtx, estr, "", "one"))
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800622 checkMatch(t, nil, doGlob(t, rootCtx, estr, "", "*/..."))
623
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700624 // Set up a mount, then set the AccessList.
Asim Shankar43d1f932015-03-24 20:57:56 -0700625 doMount(t, rootCtx, estr, "one/bright/day", fakeServer, true)
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800626 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 -0700627 perms := access.Permissions{"Read": access.AccessList{In: []security.BlessingPattern{security.AllPrincipals}}}
628 doSetPermissions(t, rootCtx, estr, "one/bright", perms, "", true)
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800629
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700630 // 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 -0800631 doUnmount(t, rootCtx, estr, "one/bright/day", "", true)
632 checkMatch(t, []string{"one", "one/bright"}, doGlob(t, rootCtx, estr, "", "*/..."))
633}
634
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800635func TestDelete(t *testing.T) {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800636 rootCtx, aliceCtx, bobCtx, shutdown := initTest()
637 defer shutdown()
638
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700639 stop, estr := newMT(t, "testdata/test.perms", "", "testDelete", rootCtx)
640 defer stop()
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800641
642 // set up a mount space
643 fakeServer := naming.JoinAddressName(estr, "quux")
Asim Shankar43d1f932015-03-24 20:57:56 -0700644 doMount(t, bobCtx, estr, "one/bright/day", fakeServer, true)
645 doMount(t, rootCtx, estr, "a/b/c", fakeServer, true)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800646
647 // It shouldn't be possible to delete anything with children unless explicitly requested.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800648 doDeleteNode(t, rootCtx, estr, "a/b", false)
649 checkExists(t, rootCtx, estr, "a/b", true)
650 doDeleteSubtree(t, rootCtx, estr, "a/b", true)
651 checkExists(t, rootCtx, estr, "a/b", false)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800652
653 // Alice shouldn't be able to delete what bob created but bob and root should.
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800654 doDeleteNode(t, aliceCtx, estr, "one/bright/day", false)
655 checkExists(t, rootCtx, estr, "one/bright/day", true)
656 doDeleteNode(t, rootCtx, estr, "one/bright/day", true)
657 checkExists(t, rootCtx, estr, "one/bright/day", false)
658 doDeleteNode(t, bobCtx, estr, "one/bright", true)
659 checkExists(t, rootCtx, estr, "one/bright", false)
David Why Use Two When One Will Do Presottoe43213b2015-06-02 10:33:10 -0700660
661 // Make sure directory admin can delete directory children.
662 perms := access.Permissions{"Admin": access.AccessList{In: []security.BlessingPattern{"bob"}}}
663 doSetPermissions(t, bobCtx, estr, "hoohaa", perms, "", false)
664 doDeleteNode(t, rootCtx, estr, "hoohaa", true)
665 checkExists(t, rootCtx, estr, "hoohaa", false)
David Why Use Two When One Will Do Presottoab2bcf22015-01-05 13:14:01 -0800666}
667
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700668func TestServerFormat(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700669 rootCtx, shutdown := test.V23Init()
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800670 defer shutdown()
671
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700672 stop, estr := newMT(t, "", "", "testerverFormat", rootCtx)
673 defer stop()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700674
Asim Shankar43d1f932015-03-24 20:57:56 -0700675 doMount(t, rootCtx, estr, "endpoint", naming.JoinAddressName(estr, "life/on/the/mississippi"), true)
676 doMount(t, rootCtx, estr, "hostport", "/atrampabroad:8000", true)
677 doMount(t, rootCtx, estr, "invalid/not/rooted", "atrampabroad:8000", false)
678 doMount(t, rootCtx, estr, "invalid/no/port", "/atrampabroad", false)
679 doMount(t, rootCtx, estr, "invalid/endpoint", "/@following the equator:8000@@@", false)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700680}
681
682func TestExpiry(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700683 rootCtx, shutdown := test.V23Init()
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800684 defer shutdown()
685
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700686 stop, estr := newMT(t, "", "", "testExpiry", rootCtx)
687 defer stop()
688 stop, collectionAddr := newCollection(t, rootCtx)
689 defer stop()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700690
691 collectionName := naming.JoinAddressName(collectionAddr, "collection")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700692
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700693 ft := mounttablelib.NewFakeTimeClock()
694 mounttablelib.SetServerListClock(ft)
Asim Shankar43d1f932015-03-24 20:57:56 -0700695 doMount(t, rootCtx, estr, "a1/b1", collectionName, true)
696 doMount(t, rootCtx, estr, "a1/b2", collectionName, true)
697 doMount(t, rootCtx, estr, "a2/b1", collectionName, true)
698 doMount(t, rootCtx, estr, "a2/b2/c", collectionName, true)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700699
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800700 checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, rootCtx, estr, "", "*/b1/..."))
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700701 ft.Advance(time.Duration(ttlSecs/2) * time.Second)
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800702 checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, rootCtx, estr, "", "*/b1/..."))
703 checkMatch(t, []string{"c"}, doGlob(t, rootCtx, estr, "a2/b2", "*"))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700704 // Refresh only a1/b1. All the other mounts will expire upon the next
705 // ft advance.
Asim Shankar43d1f932015-03-24 20:57:56 -0700706 doMount(t, rootCtx, estr, "a1/b1", collectionName, true)
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700707 ft.Advance(time.Duration(ttlSecs/2+4) * time.Second)
David Why Use Two When One Will Do Presottoa4100172015-01-14 09:25:45 -0800708 checkMatch(t, []string{"a1", "a1/b1"}, doGlob(t, rootCtx, estr, "", "*/..."))
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800709 checkMatch(t, []string{"a1/b1"}, doGlob(t, rootCtx, estr, "", "*/b1/..."))
Ryan Brownac972652014-05-19 10:57:32 -0700710}
711
Benjamin Prosnitzb60efb92015-03-11 17:47:43 -0700712func TestBadAccessLists(t *testing.T) {
Cosmos Nicolaou27dc65b2015-07-10 16:23:19 -0700713 ctx, shutdown := test.TestContext()
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700714 defer shutdown()
715 _, err := mounttablelib.NewMountTableDispatcher(ctx, "testdata/invalid.perms", "", "mounttable")
Ryan Brownac972652014-05-19 10:57:32 -0700716 if err == nil {
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700717 boom(t, "Expected json parse error in permissions file")
Ryan Brownac972652014-05-19 10:57:32 -0700718 }
Cosmos Nicolaou19a50f62015-06-20 09:15:40 -0700719 _, err = mounttablelib.NewMountTableDispatcher(ctx, "testdata/doesntexist.perms", "", "mounttable")
Robin Thellendc4b51692015-02-05 17:11:16 -0800720 if err != nil {
David Why Use Two When One Will Do Presottoba9593f2015-04-22 12:29:26 -0700721 boom(t, "Missing permissions file should not cause an error")
Ryan Brownac972652014-05-19 10:57:32 -0700722 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700723}
Asim Shankar88292912014-10-09 19:41:07 -0700724
Robin Thellend0aed6da2015-04-17 14:39:35 -0700725func getCounter(t *testing.T, ctx *context.T, name string) int64 {
726 st := stats.StatsClient(name)
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700727 v, err := st.Value(ctx)
728 if err != nil {
Robin Thellend0aed6da2015-04-17 14:39:35 -0700729 t.Fatalf("Failed to get %q: %v", name, err)
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700730 return -1
731 }
732 var value int64
733 if err := vdl.Convert(&value, v); err != nil {
Robin Thellend0aed6da2015-04-17 14:39:35 -0700734 t.Fatalf("Unexpected value type for %q: %v", name, err)
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700735 }
736 return value
737}
738
Robin Thellend0aed6da2015-04-17 14:39:35 -0700739func nodeCount(t *testing.T, ctx *context.T, addr string) int64 {
740 name := naming.JoinAddressName(addr, "__debug/stats/mounttable/num-nodes")
741 return getCounter(t, ctx, name)
742}
743
744func serverCount(t *testing.T, ctx *context.T, addr string) int64 {
745 name := naming.JoinAddressName(addr, "__debug/stats/mounttable/num-mounted-servers")
746 return getCounter(t, ctx, name)
747}
748
749func TestStatsCounters(t *testing.T) {
Todd Wang60052d82015-05-22 15:00:10 -0700750 rootCtx, shutdown := test.V23Init()
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700751 defer shutdown()
752
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700753 ft := mounttablelib.NewFakeTimeClock()
754 mounttablelib.SetServerListClock(ft)
Robin Thellend62909b22015-04-23 13:54:55 -0700755
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700756 stop, estr := newMT(t, "", "", "mounttable", rootCtx)
757 defer stop()
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700758
759 // Test flat tree
760 for i := 1; i <= 10; i++ {
761 name := fmt.Sprintf("node%d", i)
762 addr := naming.JoinAddressName(estr, name)
763 doMount(t, rootCtx, estr, name, addr, true)
764 if expected, got := int64(i+1), nodeCount(t, rootCtx, estr); got != expected {
765 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
766 }
Robin Thellend0aed6da2015-04-17 14:39:35 -0700767 if expected, got := int64(i), serverCount(t, rootCtx, estr); got != expected {
768 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
769 }
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700770 }
771 for i := 1; i <= 10; i++ {
772 name := fmt.Sprintf("node%d", i)
773 if i%2 == 0 {
774 doUnmount(t, rootCtx, estr, name, "", true)
775 } else {
776 doDeleteSubtree(t, rootCtx, estr, name, true)
777 }
778 if expected, got := int64(11-i), nodeCount(t, rootCtx, estr); got != expected {
779 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
780 }
Robin Thellend0aed6da2015-04-17 14:39:35 -0700781 if expected, got := int64(10-i), serverCount(t, rootCtx, estr); got != expected {
782 t.Errorf("Unexpected number of server. Got %d, expected %d", got, expected)
783 }
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700784 }
785
786 // Test deep tree
787 doMount(t, rootCtx, estr, "1/2/3/4/5/6/7/8/9a/10", naming.JoinAddressName(estr, ""), true)
788 doMount(t, rootCtx, estr, "1/2/3/4/5/6/7/8/9b/11", naming.JoinAddressName(estr, ""), true)
789 if expected, got := int64(13), nodeCount(t, rootCtx, estr); got != expected {
790 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
791 }
Robin Thellend0aed6da2015-04-17 14:39:35 -0700792 if expected, got := int64(2), serverCount(t, rootCtx, estr); got != expected {
793 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
794 }
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700795 doDeleteSubtree(t, rootCtx, estr, "1/2/3/4/5", true)
796 if expected, got := int64(5), 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(0), 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", true)
803 if expected, got := int64(1), 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
807 // Test multiple servers per node
808 for i := 1; i <= 5; i++ {
809 server := naming.JoinAddressName(estr, fmt.Sprintf("addr%d", i))
810 doMount(t, rootCtx, estr, "node1", server, true)
811 doMount(t, rootCtx, estr, "node2", server, true)
812 if expected, got := int64(3), nodeCount(t, rootCtx, estr); got != expected {
813 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
814 }
815 if expected, got := int64(2*i), serverCount(t, rootCtx, estr); got != expected {
816 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
817 }
818 }
819 doUnmount(t, rootCtx, estr, "node1", "", true)
820 if expected, got := int64(2), nodeCount(t, rootCtx, estr); got != expected {
821 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
822 }
823 if expected, got := int64(5), serverCount(t, rootCtx, estr); got != expected {
824 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
825 }
826 for i := 1; i <= 5; i++ {
827 server := naming.JoinAddressName(estr, fmt.Sprintf("addr%d", i))
828 doUnmount(t, rootCtx, estr, "node2", server, true)
829 expectedNodes := int64(2)
830 if i == 5 {
831 expectedNodes = 1
832 }
833 if expected, got := expectedNodes, nodeCount(t, rootCtx, estr); got != expected {
834 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
835 }
836 if expected, got := int64(5-i), serverCount(t, rootCtx, estr); got != expected {
837 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
838 }
839 }
Robin Thellend93b1f6d2015-04-22 12:31:34 -0700840
841 // Mount on an existing intermediate node.
842 doMount(t, rootCtx, estr, "1/2/3/4/5/6/7/8/9a/10", naming.JoinAddressName(estr, ""), true)
843 doMount(t, rootCtx, estr, "1/2/3/4/5", naming.JoinAddressName(estr, ""), true)
844 if expected, got := int64(6), nodeCount(t, rootCtx, estr); got != expected {
845 t.Errorf("Unexpected number of nodes. Got %d, expected %d", got, expected)
846 }
847 if expected, got := int64(1), serverCount(t, rootCtx, estr); got != expected {
848 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
849 }
Robin Thellend62909b22015-04-23 13:54:55 -0700850
851 // Test expired mounts
852 // "1/2/3/4/5" is still mounted from earlier.
Matt Rosencrantz165e8902015-06-12 15:27:27 -0700853 ft.Advance(time.Duration(ttlSecs+4) * time.Second)
Robin Thellend62909b22015-04-23 13:54:55 -0700854 if _, err := resolve(rootCtx, naming.JoinAddressName(estr, "1/2/3/4/5")); err == nil {
855 t.Errorf("Expected failure. Got success")
856 }
857 if expected, got := int64(0), serverCount(t, rootCtx, estr); got != expected {
858 t.Errorf("Unexpected number of servers. Got %d, expected %d", got, expected)
859 }
Robin Thellendfd82dcc2015-04-14 21:16:59 -0700860}
861
David Why Use Two When One Will Do Presottoe3e932c2015-05-15 14:59:46 -0700862func TestIntermediateNodesCreatedFromConfig(t *testing.T) {
863 rootCtx, _, _, shutdown := initTest()
864 defer shutdown()
865
Matt Rosencrantzbb6295d2015-06-19 15:13:58 -0700866 stop, estr := newMT(t, "testdata/intermediate.perms", "", "TestIntermediateNodesCreatedFromConfig", rootCtx)
867 defer stop()
David Why Use Two When One Will Do Presottoe3e932c2015-05-15 14:59:46 -0700868
869 // x and x/y should have the same permissions at the root.
870 rootPerms, _ := doGetPermissions(t, rootCtx, estr, "", true)
871 if perms, _ := doGetPermissions(t, rootCtx, estr, "x", true); !reflect.DeepEqual(rootPerms, perms) {
872 boom(t, "for x got %v, want %v", perms, rootPerms)
873 }
874 if perms, _ := doGetPermissions(t, rootCtx, estr, "x/y", true); !reflect.DeepEqual(rootPerms, perms) {
875 boom(t, "for x/y got %v, want %v", perms, rootPerms)
876 }
877 if perms, _ := doGetPermissions(t, rootCtx, estr, "x/y/z", true); reflect.DeepEqual(rootPerms, perms) {
878 boom(t, "for x/y/z got %v, don't want %v", perms, rootPerms)
879 }
880}
881
Jiri Simsa6ac95222015-02-23 16:11:49 -0800882func initTest() (rootCtx *context.T, aliceCtx *context.T, bobCtx *context.T, shutdown v23.Shutdown) {
Cosmos Nicolaou1381f8a2015-03-13 09:40:34 -0700883 test.Init()
Todd Wang60052d82015-05-22 15:00:10 -0700884 ctx, shutdown := test.V23Init()
Asim Shankar88292912014-10-09 19:41:07 -0700885 var err error
Todd Wangad492042015-04-17 15:58:40 -0700886 if rootCtx, err = v23.WithPrincipal(ctx, testutil.NewPrincipal("root")); err != nil {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800887 panic("failed to set root principal")
Matt Rosencrantzac32b6c2014-12-01 15:49:18 -0800888 }
Todd Wangad492042015-04-17 15:58:40 -0700889 if aliceCtx, err = v23.WithPrincipal(ctx, testutil.NewPrincipal("alice")); err != nil {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800890 panic("failed to set alice principal")
Asim Shankar88292912014-10-09 19:41:07 -0700891 }
Todd Wangad492042015-04-17 15:58:40 -0700892 if bobCtx, err = v23.WithPrincipal(ctx, testutil.NewPrincipal("bob")); err != nil {
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800893 panic("failed to set bob principal")
Asim Shankar88292912014-10-09 19:41:07 -0700894 }
Matt Rosencrantz6edab562015-01-12 11:07:55 -0800895 for _, r := range []*context.T{rootCtx, aliceCtx, bobCtx} {
Asim Shankar8bc78d62015-02-03 16:53:27 -0800896 // A hack to set the namespace roots to a value that won't work.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800897 v23.GetNamespace(r).SetRoots()
Asim Shankar8bc78d62015-02-03 16:53:27 -0800898 // And have all principals recognize each others blessings.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800899 p1 := v23.GetPrincipal(r)
Asim Shankar8bc78d62015-02-03 16:53:27 -0800900 for _, other := range []*context.T{rootCtx, aliceCtx, bobCtx} {
Asim Shankar4a698282015-03-21 21:59:18 -0700901 // testutil.NewPrincipal has already setup each
Asim Shankar8bc78d62015-02-03 16:53:27 -0800902 // principal to use the same blessing for both server
903 // and client activities.
Jiri Simsa6ac95222015-02-23 16:11:49 -0800904 if err := p1.AddToRoots(v23.GetPrincipal(other).BlessingStore().Default()); err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700905 panic(err)
906 }
907 }
908 }
Suharsh Sivakumar19fbf992015-01-23 11:02:27 -0800909 return rootCtx, aliceCtx, bobCtx, shutdown
Asim Shankar88292912014-10-09 19:41:07 -0700910}