blob: 3cd964b9a50515f1b4b44d2d3e7bdc7e55cba3d3 [file] [log] [blame]
Jiri Simsa5293dcb2014-05-10 09:56:38 -07001package mounttable
2
3import (
4 "errors"
Asim Shankar88292912014-10-09 19:41:07 -07005 "fmt"
Jiri Simsa5293dcb2014-05-10 09:56:38 -07006 "reflect"
7 "runtime/debug"
8 "sort"
9 "strings"
10 "testing"
11 "time"
12
Jiri Simsa519c5072014-09-17 21:37:57 -070013 "veyron.io/veyron/veyron2"
14 "veyron.io/veyron/veyron2/context"
15 "veyron.io/veyron/veyron2/ipc"
16 "veyron.io/veyron/veyron2/naming"
Asim Shankarcc044212014-10-15 23:25:26 -070017 "veyron.io/veyron/veyron2/options"
Jiri Simsa519c5072014-09-17 21:37:57 -070018 "veyron.io/veyron/veyron2/rt"
19 "veyron.io/veyron/veyron2/security"
20 "veyron.io/veyron/veyron2/services/mounttable"
21 "veyron.io/veyron/veyron2/services/mounttable/types"
22 "veyron.io/veyron/veyron2/vlog"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070023
Asim Shankarc920db32014-10-16 19:18:21 -070024 "veyron.io/veyron/veyron/lib/testutil"
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -070025 "veyron.io/veyron/veyron/profiles"
Jiri Simsa5293dcb2014-05-10 09:56:38 -070026)
27
Cosmos Nicolaou4e029972014-06-13 14:53:08 -070028// stupidNS is a version of naming.Namespace that we can control. This exists so that we have some
Jiri Simsa5293dcb2014-05-10 09:56:38 -070029// firm ground to stand on vis a vis the stub interface.
Cosmos Nicolaou4e029972014-06-13 14:53:08 -070030type stupidNS struct {
Asim Shankar88292912014-10-09 19:41:07 -070031 r veyron2.Runtime
Ryan Brownac972652014-05-19 10:57:32 -070032}
Jiri Simsa5293dcb2014-05-10 09:56:38 -070033
Asim Shankar88292912014-10-09 19:41:07 -070034// Simulate different processes with different runtimes.
35// rootRT is the one running the mounttable service.
36var rootRT, aliceRT, bobRT veyron2.Runtime
Jiri Simsa5293dcb2014-05-10 09:56:38 -070037
38const ttlSecs = 60 * 60
39
40func boom(t *testing.T, f string, v ...interface{}) {
41 t.Logf(f, v...)
42 t.Fatal(string(debug.Stack()))
43}
44
Asim Shankar88292912014-10-09 19:41:07 -070045// quuxClient returns an ipc.Client that would be used by the provided runtime
46// and uses the simple namespace for name resolution.
47func quuxClient(r veyron2.Runtime) ipc.Client {
Asim Shankarcc044212014-10-15 23:25:26 -070048 c, err := r.NewClient(options.Namespace{stupidNS{r}})
Jiri Simsa5293dcb2014-05-10 09:56:38 -070049 if err != nil {
50 panic(err)
51 }
52 return c
53}
54
David Why Use Two When One Will Do Presotto3da1c792014-10-03 11:15:53 -070055func (stupidNS) Mount(context.T, string, string, time.Duration, ...naming.MountOpt) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070056 return errors.New("unimplemented")
57}
58
Cosmos Nicolaou4e029972014-06-13 14:53:08 -070059func (stupidNS) Unmount(context.T, string, string) error {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070060 return errors.New("unimplemented")
61}
62
63// Resolve will only go one level deep, i.e., it doesn't walk past the first mount point.
Cosmos Nicolaou4e029972014-06-13 14:53:08 -070064func (ns stupidNS) Resolve(ctx context.T, name string) ([]string, error) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070065 vlog.VI(1).Infof("MyResolve %q", name)
66 address, suffix := naming.SplitAddressName(name)
67 if len(address) == 0 {
68 return nil, naming.ErrNoSuchName
69 }
70 if strings.HasPrefix(suffix, "//") {
71 // We're done, the server at address will handle the name.
72 return []string{naming.JoinAddressName(address, suffix)}, nil
73 }
74
75 // Resolve via another
Asim Shankar88292912014-10-09 19:41:07 -070076 objectPtr, err := mounttable.BindMountTable("/"+address+"//"+suffix, quuxClient(ns.r))
Jiri Simsa5293dcb2014-05-10 09:56:38 -070077 if err != nil {
78 return nil, err
79 }
David Why Use Two When One Will Do Presotto6f9f5742014-10-20 16:27:05 -070080 entry, err := objectPtr.ResolveStepX(ns.r.NewContext())
Jiri Simsa5293dcb2014-05-10 09:56:38 -070081 if err != nil {
82 return nil, err
83 }
84 var servers []string
David Why Use Two When One Will Do Presotto6f9f5742014-10-20 16:27:05 -070085 for _, s := range entry.Servers {
86 servers = append(servers, naming.Join(s.Server, entry.Name))
Jiri Simsa5293dcb2014-05-10 09:56:38 -070087 }
88 vlog.VI(1).Infof("-> %v", servers)
89 return servers, nil
90}
91
Cosmos Nicolaou4e029972014-06-13 14:53:08 -070092func (s stupidNS) Unresolve(ctx context.T, name string) ([]string, error) {
Matt Rosencrantz29147f72014-06-06 12:46:01 -070093 return s.Resolve(ctx, name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -070094}
95
Cosmos Nicolaou4e029972014-06-13 14:53:08 -070096func (stupidNS) ResolveToMountTable(ctx context.T, name string) ([]string, error) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -070097 return nil, errors.New("ResolveToMountTable is not implemented in this MountTable")
98}
99
David Why Use Two When One Will Do Presotto39602db2014-08-18 14:28:27 -0700100func (stupidNS) FlushCacheEntry(name string) bool {
101 return false
102}
103
David Why Use Two When One Will Do Presotto7764f312014-08-20 16:24:05 -0700104func (stupidNS) CacheCtl(ctls ...naming.CacheCtl) []naming.CacheCtl {
105 return nil
106}
107
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700108// Glob implements naming.MountTable.Glob.
Cosmos Nicolaou4e029972014-06-13 14:53:08 -0700109func (stupidNS) Glob(ctx context.T, pattern string) (chan naming.MountEntry, error) {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700110 return nil, errors.New("Glob is not implemented in this MountTable")
111}
112
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700113func (s stupidNS) SetRoots(...string) error {
Cosmos Nicolaoue6e87f12014-06-03 14:29:10 -0700114 return nil
115}
116
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700117func (s stupidNS) Roots() []string {
118 return []string{}
119}
120
Asim Shankar88292912014-10-09 19:41:07 -0700121func doMount(t *testing.T, name, service string, shouldSucceed bool, as veyron2.Runtime) {
122 mtpt, err := mounttable.BindMountTable(name, quuxClient(as))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700123 if err != nil {
124 boom(t, "Failed to BindMountTable: %s", err)
125 }
Asim Shankarcc044212014-10-15 23:25:26 -0700126 if err := mtpt.Mount(as.NewContext(), service, uint32(ttlSecs), 0, options.RetryTimeout(0)); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700127 if shouldSucceed {
128 boom(t, "Failed to Mount %s onto %s: %s", service, name, err)
129 }
130 } else if !shouldSucceed {
131 boom(t, "doMount %s onto %s, expected failure but succeeded", service, name)
132 }
133}
134
Asim Shankar88292912014-10-09 19:41:07 -0700135func doUnmount(t *testing.T, name, service string, shouldSucceed bool, as veyron2.Runtime) {
136 mtpt, err := mounttable.BindMountTable(name, quuxClient(as))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700137 if err != nil {
138 boom(t, "Failed to BindMountTable: %s", err)
139 }
Asim Shankarcc044212014-10-15 23:25:26 -0700140 if err := mtpt.Unmount(as.NewContext(), service, options.RetryTimeout(0)); err != nil {
Ankur6387ef22014-05-23 17:24:27 -0700141 if shouldSucceed {
Ryan Brownac972652014-05-19 10:57:32 -0700142 boom(t, "Failed to Unmount %s onto %s: %s", service, name, err)
143 }
Ankur6387ef22014-05-23 17:24:27 -0700144 } else if !shouldSucceed {
Ryan Brownac972652014-05-19 10:57:32 -0700145 boom(t, "doUnmount %s onto %s, expected failure but succeeded", service, name)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700146 }
147}
148
Asim Shankar88292912014-10-09 19:41:07 -0700149func export(t *testing.T, name, contents string, as veyron2.Runtime) {
150 objectPtr, err := BindCollection(name, quuxClient(as))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700151 if err != nil {
152 boom(t, "Failed to BindCollection: %s", err)
153 }
Asim Shankar88292912014-10-09 19:41:07 -0700154 if err := objectPtr.Export(as.NewContext(), contents, true); err != nil {
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700155 boom(t, "Failed to Export %s to %s: %s", name, contents, err)
156 }
157}
158
Asim Shankar88292912014-10-09 19:41:07 -0700159func checkContents(t *testing.T, name, expected string, shouldSucceed bool, as veyron2.Runtime) {
160 objectPtr, err := BindCollection(name, quuxClient(as))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700161 if err != nil {
162 boom(t, "Failed to BindCollection: %s", err)
163 }
Asim Shankarcc044212014-10-15 23:25:26 -0700164 contents, err := objectPtr.Lookup(as.NewContext(), options.RetryTimeout(0))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700165 if err != nil {
166 if shouldSucceed {
167 boom(t, "Failed to Lookup %s: %s", name, err)
168 }
169 return
170 }
171 if string(contents) != expected {
172 boom(t, "Lookup %s, expected %q, got %q", name, expected, contents)
173 }
174 if !shouldSucceed {
175 boom(t, "Lookup %s, expected failure, got %q", name, contents)
176 }
177}
178
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700179func newMT(t *testing.T, acl string) (ipc.Server, string) {
Asim Shankarcc044212014-10-15 23:25:26 -0700180 server, err := rootRT.NewServer(options.ServesMountTable(true))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700181 if err != nil {
182 boom(t, "r.NewServer: %s", err)
183 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700184 // Add mount table service.
Ryan Brownac972652014-05-19 10:57:32 -0700185 mt, err := NewMountTable(acl)
186 if err != nil {
187 boom(t, "NewMountTable: %v", err)
188 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700189 // Start serving on a loopback address.
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -0700190 e, err := server.ListenX(profiles.LocalListenSpec)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700191 if err != nil {
192 boom(t, "Failed to Listen mount table: %s", err)
193 }
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700194 if err := server.Serve("", mt); err != nil {
195 boom(t, "Failed to register mock collection: %s", err)
196 }
197 estr := e.String()
198 t.Logf("endpoint %s", estr)
199 return server, estr
200}
201
202func newCollection(t *testing.T, acl string) (ipc.Server, string) {
Asim Shankar88292912014-10-09 19:41:07 -0700203 server, err := rootRT.NewServer()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700204 if err != nil {
205 boom(t, "r.NewServer: %s", err)
206 }
207 // Start serving on a loopback address.
Cosmos Nicolaoud6c3c9c2014-09-30 15:42:53 -0700208 e, err := server.ListenX(profiles.LocalListenSpec)
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700209 if err != nil {
210 boom(t, "Failed to Listen mount table: %s", err)
211 }
212 // Add a collection service. This is just a service we can mount
213 // and test against.
214 cPrefix := "collection"
215 if err := server.Serve(cPrefix, newCollectionServer()); err != nil {
216 boom(t, "Failed to register mock collection: %s", err)
217 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700218 estr := e.String()
219 t.Logf("endpoint %s", estr)
220 return server, estr
221}
222
223func TestMountTable(t *testing.T) {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700224 mt, mtAddr := newMT(t, "testdata/test.acl")
225 defer mt.Stop()
226 collection, collectionAddr := newCollection(t, "testdata/test.acl")
227 defer collection.Stop()
228
229 collectionName := naming.JoinAddressName(collectionAddr, "collection")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700230
231 // Mount the collection server into the mount table.
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700232 vlog.Infof("Mount the collection server into the mount table.")
Asim Shankar88292912014-10-09 19:41:07 -0700233 doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/stuff"), collectionName, true, rootRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700234
235 // Create a few objects and make sure we can read them.
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700236 vlog.Infof("Create a few objects.")
Asim Shankar88292912014-10-09 19:41:07 -0700237 export(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", rootRT)
238 export(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/in/spain"), "in spain", rootRT)
239 export(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", rootRT)
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700240 vlog.Infof("Make sure we can read them.")
Asim Shankar88292912014-10-09 19:41:07 -0700241 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", true, rootRT)
242 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/in/spain"), "in spain", true, rootRT)
243 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootRT)
244 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable//stuff/falls"), "falls mainly on the plain", false, rootRT)
245 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/nonexistant"), "falls mainly on the plain", false, rootRT)
246 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", true, bobRT)
247 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/the/rain"), "the rain", false, aliceRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700248
249 // Test multiple mounts.
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700250 vlog.Infof("Multiple mounts.")
Asim Shankar88292912014-10-09 19:41:07 -0700251 doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, true, rootRT)
252 doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/x/y"), collectionName, true, rootRT)
253 doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/alpha//beta"), collectionName, true, rootRT)
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700254 vlog.Infof("Make sure we can read them.")
Asim Shankar88292912014-10-09 19:41:07 -0700255 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuff/falls"), "falls mainly on the plain", true, rootRT)
256 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", true, rootRT)
257 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/x/y/falls"), "falls mainly on the plain", true, rootRT)
258 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/alpha/beta/falls"), "falls mainly on the plain", true, rootRT)
259 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", true, aliceRT)
260 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, bobRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700261
262 // Test generic unmount.
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700263 vlog.Info("Test generic unmount.")
Asim Shankar88292912014-10-09 19:41:07 -0700264 doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), "", true, rootRT)
265 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700266
267 // Test specific unmount.
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700268 vlog.Info("Test specific unmount.")
Asim Shankar88292912014-10-09 19:41:07 -0700269 doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), collectionName, true, rootRT)
270 doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/a/b"), collectionName, true, rootRT)
271 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/a/b/falls"), "falls mainly on the plain", false, rootRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700272
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700273 // Try timing out a mount.
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700274 vlog.Info("Try timing out a mount.")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700275 ft := NewFakeTimeClock()
276 setServerListClock(ft)
Asim Shankar88292912014-10-09 19:41:07 -0700277 doMount(t, naming.JoinAddressName(mtAddr, "//mounttable/stuffWithTTL"), collectionName, true, rootRT)
278 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuffWithTTL/the/rain"), "the rain", true, rootRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700279 ft.advance(time.Duration(ttlSecs+4) * time.Second)
Asim Shankar88292912014-10-09 19:41:07 -0700280 checkContents(t, naming.JoinAddressName(mtAddr, "mounttable/stuffWithTTL/the/rain"), "the rain", false, rootRT)
Ryan Brownac972652014-05-19 10:57:32 -0700281
David Why Use Two When One Will Do Presotto5add67e2014-07-31 11:14:30 -0700282 // Test unauthorized mount.
283 vlog.Info("Test unauthorized mount.")
Asim Shankar88292912014-10-09 19:41:07 -0700284 doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, false, bobRT)
285 doMount(t, naming.JoinAddressName(mtAddr, "//mounttable//a/b"), collectionName, false, aliceRT)
Ryan Brownac972652014-05-19 10:57:32 -0700286
Asim Shankar88292912014-10-09 19:41:07 -0700287 doUnmount(t, naming.JoinAddressName(mtAddr, "//mounttable/x/y"), collectionName, false, bobRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700288}
289
Asim Shankar88292912014-10-09 19:41:07 -0700290func doGlob(t *testing.T, name, pattern string, as veyron2.Runtime) []string {
291 mtpt, err := mounttable.BindMountTable(name, quuxClient(as))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700292 if err != nil {
293 boom(t, "Failed to BindMountTable: %s", err)
294 }
Asim Shankar88292912014-10-09 19:41:07 -0700295 stream, err := mtpt.Glob(as.NewContext(), pattern)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700296 if err != nil {
297 boom(t, "Failed call to %s.Glob(%s): %s", name, pattern, err)
298 }
299 var reply []string
Shyam Jayaraman97b9dca2014-07-31 13:30:46 -0700300 rStream := stream.RecvStream()
301 for rStream.Advance() {
302 e := rStream.Value()
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700303 reply = append(reply, e.Name)
304 }
Shyam Jayaramanc4aed6e2014-07-22 14:25:06 -0700305
Shyam Jayaraman97b9dca2014-07-31 13:30:46 -0700306 if err := rStream.Err(); err != nil {
Shyam Jayaramanc4aed6e2014-07-22 14:25:06 -0700307 boom(t, "Glob %s: %s", name, err)
308 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700309 return reply
310}
311
312// checkMatch verified that the two slices contain the same string items, albeit
313// not necessarily in the same order. Item repetitions are allowed, but their
314// numbers need to match as well.
315func checkMatch(t *testing.T, want []string, got []string) {
316 w := sort.StringSlice(want)
317 w.Sort()
318 g := sort.StringSlice(got)
319 g.Sort()
320 if !reflect.DeepEqual(w, g) {
321 boom(t, "Glob expected %v got %v", want, got)
322 }
323}
324
325func TestGlob(t *testing.T) {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700326 server, estr := newMT(t, "")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700327 defer server.Stop()
328
329 // set up a mount space
Robin Thellend434e39f2014-08-27 14:46:27 -0700330 fakeServer := naming.JoinAddressName(estr, "//quux")
Asim Shankar88292912014-10-09 19:41:07 -0700331 doMount(t, naming.JoinAddressName(estr, "//one/bright/day"), fakeServer, true, rootRT)
332 doMount(t, naming.JoinAddressName(estr, "//in/the/middle"), fakeServer, true, rootRT)
333 doMount(t, naming.JoinAddressName(estr, "//of/the/night"), fakeServer, true, rootRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700334
335 // Try various globs.
336 tests := []struct {
337 in string
338 expected []string
339 }{
340 {"*", []string{"one", "in", "of"}},
Bogdan Capritab6b195a2014-06-11 17:55:03 -0700341 {"...", []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 -0700342 {"*/...", []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 -0700343 {"one/...", []string{"one", "one/bright", "one/bright/day"}},
Robin Thellend434e39f2014-08-27 14:46:27 -0700344 {"of/the/night/two/dead/boys", []string{"of/the/night"}},
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700345 {"*/the", []string{"in/the", "of/the"}},
346 {"*/the/...", []string{"in/the", "of/the", "in/the/middle", "of/the/night"}},
347 {"o*", []string{"one", "of"}},
348 {"", []string{""}},
349 }
350 for _, test := range tests {
Asim Shankar88292912014-10-09 19:41:07 -0700351 out := doGlob(t, naming.JoinAddressName(estr, "//"), test.in, rootRT)
Ryan Brownac972652014-05-19 10:57:32 -0700352 checkMatch(t, test.expected, out)
353 }
Robin Thellend434e39f2014-08-27 14:46:27 -0700354
355 // Test Glob on a name that is under a mounted server. The result should the
356 // the address the mounted server with the extra suffix.
357 {
358 name := naming.JoinAddressName(estr, "//of/the/night/two/dead/boys/got/up/to/fight")
359 pattern := "*"
Asim Shankar88292912014-10-09 19:41:07 -0700360 m, err := mounttable.BindGlobbable(name, quuxClient(rootRT))
Robin Thellend434e39f2014-08-27 14:46:27 -0700361 if err != nil {
362 boom(t, "Failed to BindMountTable: %s", err)
363 }
Asim Shankar88292912014-10-09 19:41:07 -0700364 stream, err := m.Glob(rootRT.NewContext(), pattern)
Robin Thellend434e39f2014-08-27 14:46:27 -0700365 if err != nil {
366 boom(t, "Failed call to %s.Glob(%s): %s", name, pattern, err)
367 }
368 var results []types.MountEntry
369 iterator := stream.RecvStream()
370 for iterator.Advance() {
371 results = append(results, iterator.Value())
372 }
373 if err := iterator.Err(); err != nil {
374 boom(t, "Glob %s: %s", name, err)
375 }
376 if len(results) != 1 {
377 boom(t, "Unexpected number of results. Got %v, want 1", len(results))
378 }
379 if results[0].Name != "" {
380 boom(t, "Unexpected name. Got %v, want ''", results[0].Name)
381 }
382 _, suffix := naming.SplitAddressName(results[0].Servers[0].Server)
383 if expected := "//quux/two/dead/boys/got/up/to/fight"; suffix != expected {
384 boom(t, "Unexpected suffix. Got %v, want %v", suffix, expected)
385 }
386 }
Ryan Brownac972652014-05-19 10:57:32 -0700387}
388
389func TestGlobACLs(t *testing.T) {
Tilak Sharmada5165e2014-10-07 16:39:51 -0700390 t.Skip("Skipped until ACLs are correctly implemented for mounttable.Glob.")
391
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700392 server, estr := newMT(t, "testdata/test.acl")
Ryan Brownac972652014-05-19 10:57:32 -0700393 defer server.Stop()
394
395 // set up a mount space
396 fakeServer := naming.JoinAddressName(estr, "quux")
Asim Shankar88292912014-10-09 19:41:07 -0700397 doMount(t, naming.JoinAddressName(estr, "//one/bright/day"), fakeServer, true, rootRT)
398 doMount(t, naming.JoinAddressName(estr, "//a/b/c"), fakeServer, true, rootRT)
Ryan Brownac972652014-05-19 10:57:32 -0700399
400 // Try various globs.
401 tests := []struct {
Asim Shankar88292912014-10-09 19:41:07 -0700402 as veyron2.Runtime
Ryan Brownac972652014-05-19 10:57:32 -0700403 in string
404 expected []string
405 }{
Asim Shankar88292912014-10-09 19:41:07 -0700406 {rootRT, "*", []string{"one", "a"}},
407 {aliceRT, "*", []string{"one", "a"}},
408 {bobRT, "*", []string{"one"}},
409 {rootRT, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c"}},
410 {aliceRT, "*/...", []string{"one", "a", "one/bright", "a/b", "one/bright/day", "a/b/c"}},
411 {bobRT, "*/...", []string{"one", "one/bright", "one/bright/day"}},
Ryan Brownac972652014-05-19 10:57:32 -0700412 }
413 for _, test := range tests {
Asim Shankar88292912014-10-09 19:41:07 -0700414 out := doGlob(t, naming.JoinAddressName(estr, "//"), test.in, test.as)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700415 checkMatch(t, test.expected, out)
416 }
417}
418
419func TestServerFormat(t *testing.T) {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700420 server, estr := newMT(t, "")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700421 defer server.Stop()
422
Asim Shankar88292912014-10-09 19:41:07 -0700423 doMount(t, naming.JoinAddressName(estr, "//mounttable/endpoint"), naming.JoinAddressName(estr, "life/on/the/mississippi"), true, rootRT)
424 doMount(t, naming.JoinAddressName(estr, "//mounttable/hostport"), "/atrampabroad:8000", true, rootRT)
425 doMount(t, naming.JoinAddressName(estr, "//mounttable/hostport-endpoint-platypus"), "/@atrampabroad:8000@@", true, rootRT)
426 doMount(t, naming.JoinAddressName(estr, "//mounttable/invalid/not/rooted"), "atrampabroad:8000", false, rootRT)
427 doMount(t, naming.JoinAddressName(estr, "//mounttable/invalid/no/port"), "/atrampabroad", false, rootRT)
428 doMount(t, naming.JoinAddressName(estr, "//mounttable/invalid/endpoint"), "/@following the equator:8000@@@", false, rootRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700429}
430
431func TestExpiry(t *testing.T) {
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700432 server, estr := newMT(t, "")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700433 defer server.Stop()
Cosmos Nicolaoufdc838b2014-06-30 21:44:27 -0700434 collection, collectionAddr := newCollection(t, "testdata/test.acl")
435 defer collection.Stop()
436
437 collectionName := naming.JoinAddressName(collectionAddr, "collection")
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700438
439 ft := NewFakeTimeClock()
440 setServerListClock(ft)
Asim Shankar88292912014-10-09 19:41:07 -0700441 doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), collectionName, true, rootRT)
442 doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b2"), collectionName, true, rootRT)
443 doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b1"), collectionName, true, rootRT)
444 doMount(t, naming.JoinAddressName(estr, "//mounttable/a2/b2/c"), collectionName, true, rootRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700445
Asim Shankar88292912014-10-09 19:41:07 -0700446 checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootRT))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700447 ft.advance(time.Duration(ttlSecs/2) * time.Second)
Asim Shankar88292912014-10-09 19:41:07 -0700448 checkMatch(t, []string{"a1/b1", "a2/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootRT))
449 checkMatch(t, []string{"c"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable/a2/b2"), "*", rootRT))
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700450 // Refresh only a1/b1. All the other mounts will expire upon the next
451 // ft advance.
Asim Shankar88292912014-10-09 19:41:07 -0700452 doMount(t, naming.JoinAddressName(estr, "//mounttable/a1/b1"), collectionName, true, rootRT)
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700453 ft.advance(time.Duration(ttlSecs/2+4) * time.Second)
Asim Shankar88292912014-10-09 19:41:07 -0700454 checkMatch(t, []string{"a1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*", rootRT))
455 checkMatch(t, []string{"a1/b1"}, doGlob(t, naming.JoinAddressName(estr, "//mounttable"), "*/b1/...", rootRT))
Ryan Brownac972652014-05-19 10:57:32 -0700456}
457
458func TestBadACLs(t *testing.T) {
459 _, err := NewMountTable("testdata/invalid.acl")
460 if err == nil {
461 boom(t, "Expected json parse error in acl file")
462 }
463 _, err = NewMountTable("testdata/doesntexist.acl")
464 if err == nil {
465 boom(t, "Expected error from missing acl file")
466 }
467 _, err = NewMountTable("testdata/noroot.acl")
468 if err == nil {
469 boom(t, "Expected error for missing '/' acl")
470 }
Jiri Simsa5293dcb2014-05-10 09:56:38 -0700471}
Asim Shankar88292912014-10-09 19:41:07 -0700472
473func init() {
Asim Shankarc920db32014-10-16 19:18:21 -0700474 testutil.Init()
Asim Shankar88292912014-10-09 19:41:07 -0700475 // Create the runtime for each of the three "processes"
Asim Shankarcc044212014-10-15 23:25:26 -0700476 rootRT = rt.Init(options.ForceNewSecurityModel{})
Asim Shankar88292912014-10-09 19:41:07 -0700477 var err error
Asim Shankarcc044212014-10-15 23:25:26 -0700478 if aliceRT, err = rt.New(options.ForceNewSecurityModel{}); err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700479 panic(err)
480 }
Asim Shankarcc044212014-10-15 23:25:26 -0700481 if bobRT, err = rt.New(options.ForceNewSecurityModel{}); err != nil {
Asim Shankar88292912014-10-09 19:41:07 -0700482 panic(err)
483 }
484
485 // And setup their blessings so that they present "root", "alice" and "bob"
486 // and these blessings are recognized by the others.
487 principals := map[string]security.Principal{
488 "root": rootRT.Principal(),
489 "alice": aliceRT.Principal(),
490 "bob": bobRT.Principal(),
491 }
492 for name, p := range principals {
493 blessing, err := p.BlessSelf(name)
494 if err != nil {
495 panic(fmt.Sprintf("BlessSelf(%q) failed: %v", name, err))
496 }
497 // Share this blessing with all servers and use it when serving clients.
498 if err = p.BlessingStore().SetDefault(blessing); err != nil {
499 panic(fmt.Sprintf("%v: %v", blessing, err))
500 }
501 if _, err = p.BlessingStore().Set(blessing, security.AllPrincipals); err != nil {
502 panic(fmt.Sprintf("%v: %v", blessing, err))
503 }
504 // Have all principals trust the root of this blessing.
505 for _, other := range principals {
506 if err := other.AddToRoots(blessing); err != nil {
507 panic(err)
508 }
509 }
510 }
511}