Merge "core.js: Adding support for RpcServerOptions such as IsLeaf and ServesMountTable to wspr and JS."
diff --git a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
index cc470f4..a1a4626 100644
--- a/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
+++ b/src/gen-vdl/v.io/x/ref/services/wspr/internal/app/index.js
@@ -28,12 +28,14 @@
var _type5 = new vdl.Type();
var _type6 = new vdl.Type();
var _type7 = new vdl.Type();
+var _type8 = new vdl.Type();
var _typeGranterHandle = new vdl.Type();
var _typeGranterRequest = new vdl.Type();
var _typeGranterResponse = new vdl.Type();
var _typeRpcCallOption = new vdl.Type();
var _typeRpcRequest = new vdl.Type();
var _typeRpcResponse = new vdl.Type();
+var _typeRpcServerOption = new vdl.Type();
_type1.kind = vdl.kind.LIST;
_type1.name = "";
_type1.elem = _typeRpcCallOption;
@@ -45,16 +47,19 @@
_type3.elem = vdl.types.ANY;
_type4.kind = vdl.kind.LIST;
_type4.name = "";
-_type4.elem = new security.Caveat()._type;
-_type5.kind = vdl.kind.OPTIONAL;
+_type4.elem = _typeRpcServerOption;
+_type5.kind = vdl.kind.LIST;
_type5.name = "";
-_type5.elem = new principal.JsBlessings()._type;
-_type6.kind = vdl.kind.LIST;
+_type5.elem = new security.Caveat()._type;
+_type6.kind = vdl.kind.OPTIONAL;
_type6.name = "";
-_type6.elem = vdl.types.STRING;
+_type6.elem = new principal.JsBlessings()._type;
_type7.kind = vdl.kind.LIST;
_type7.name = "";
-_type7.elem = new signature.Interface()._type;
+_type7.elem = vdl.types.STRING;
+_type8.kind = vdl.kind.LIST;
+_type8.name = "";
+_type8.elem = new signature.Interface()._type;
_typeGranterHandle.kind = vdl.kind.INT32;
_typeGranterHandle.name = "v.io/x/ref/services/wspr/internal/app.GranterHandle";
_typeGranterRequest.kind = vdl.kind.STRUCT;
@@ -72,6 +77,9 @@
_typeRpcResponse.kind = vdl.kind.STRUCT;
_typeRpcResponse.name = "v.io/x/ref/services/wspr/internal/app.RpcResponse";
_typeRpcResponse.fields = [{name: "OutArgs", type: _type3}, {name: "TraceResponse", type: new vtrace.Response()._type}];
+_typeRpcServerOption.kind = vdl.kind.UNION;
+_typeRpcServerOption.name = "v.io/x/ref/services/wspr/internal/app.RpcServerOption";
+_typeRpcServerOption.fields = [{name: "IsLeaf", type: vdl.types.BOOL}, {name: "ServesMountTable", type: vdl.types.BOOL}];
_type1.freeze();
_type2.freeze();
_type3.freeze();
@@ -79,18 +87,21 @@
_type5.freeze();
_type6.freeze();
_type7.freeze();
+_type8.freeze();
_typeGranterHandle.freeze();
_typeGranterRequest.freeze();
_typeGranterResponse.freeze();
_typeRpcCallOption.freeze();
_typeRpcRequest.freeze();
_typeRpcResponse.freeze();
+_typeRpcServerOption.freeze();
module.exports.GranterHandle = (vdl.registry.lookupOrCreateConstructor(_typeGranterHandle));
module.exports.GranterRequest = (vdl.registry.lookupOrCreateConstructor(_typeGranterRequest));
module.exports.GranterResponse = (vdl.registry.lookupOrCreateConstructor(_typeGranterResponse));
module.exports.RpcCallOption = (vdl.registry.lookupOrCreateConstructor(_typeRpcCallOption));
module.exports.RpcRequest = (vdl.registry.lookupOrCreateConstructor(_typeRpcRequest));
module.exports.RpcResponse = (vdl.registry.lookupOrCreateConstructor(_typeRpcResponse));
+module.exports.RpcServerOption = (vdl.registry.lookupOrCreateConstructor(_typeRpcServerOption));
@@ -114,7 +125,7 @@
-Controller.prototype.serve = function(ctx, serverCall, name, serverId) {
+Controller.prototype.serve = function(ctx, serverCall, name, serverId, serverOpts) {
throw new Error('Method Serve not implemented');
};
@@ -201,6 +212,11 @@
doc: "",
type: vdl.types.UINT32
},
+ {
+ name: 'serverOpts',
+ doc: "",
+ type: _type4
+ },
],
outArgs: [],
inStream: null,
@@ -325,7 +341,7 @@
{
name: 'caveat',
doc: "",
- type: _type4
+ type: _type5
},
],
outArgs: [{
@@ -356,7 +372,7 @@
{
name: 'caveats',
doc: "",
- type: _type4
+ type: _type5
},
],
outArgs: [{
@@ -393,7 +409,7 @@
outArgs: [{
name: '',
doc: "",
- type: _type5
+ type: _type6
},
],
inStream: null,
@@ -435,7 +451,7 @@
outArgs: [{
name: '',
doc: "",
- type: _type6
+ type: _type7
},
],
inStream: null,
@@ -456,7 +472,7 @@
outArgs: [{
name: '',
doc: "",
- type: _type7
+ type: _type8
},
],
inStream: null,
@@ -472,7 +488,7 @@
outArgs: [{
name: '',
doc: "",
- type: _type5
+ type: _type6
},
],
inStream: null,
diff --git a/src/rpc/client.js b/src/rpc/client.js
index 39629f6..ba291a9 100644
--- a/src/rpc/client.js
+++ b/src/rpc/client.js
@@ -689,6 +689,7 @@
* that the allowed server must match in order for the RPC to be initiated.</p>
* @param {module:vanadium.security~GranterFunction} opts.granter <p>A granter
* function.</p>
+ * @return {module:vanadium.rpc~Client~ClientCallOption}
*/
Client.prototype.callOption = function(opts) {
// TODO(nlacasse): Support other CallOption types.
@@ -706,10 +707,15 @@
};
/**
- * Constructor for ClientCallOption object.
+ * @summary ClientCallOption represents different configurations that can be
+ * specified when making an RPC call.
+ * @description
+ * Private constructor, use
+ * [client.callOption(opts)]{@link module:vanadium.rpc~Client#callOption}
+ * to construct an instance.
* @constructor
- * @private
- * @param {Object} opts call options.
+ * @inner
+ * @memberof module:vanadium.rpc~Client
*/
function ClientCallOption(opts) {
this.opts = opts;
diff --git a/src/rpc/index.js b/src/rpc/index.js
index 0f4a7ce..9ac099d 100644
--- a/src/rpc/index.js
+++ b/src/rpc/index.js
@@ -40,5 +40,6 @@
* @memberof module:vanadium.rpc
* @namespace reserved
*/
- reserved: require('../gen-vdl/v.io/v23/rpc/reserved')
+ reserved: require('../gen-vdl/v.io/v23/rpc/reserved'),
+ serverOption: require('./server-option')
};
\ No newline at end of file
diff --git a/src/rpc/leaf-dispatcher.js b/src/rpc/leaf-dispatcher.js
index 5ca47d8..700a539 100644
--- a/src/rpc/leaf-dispatcher.js
+++ b/src/rpc/leaf-dispatcher.js
@@ -9,20 +9,22 @@
/**
* Returns a dispatcher function that will reuse the same service object
- * for all suffixes
+ * for all suffixes.
* @private
* @param {Service} service Service object.
- * @param {Authorizer} authorizer, optional the authorizer to use.
- * @return {function} a dispatcher function that will reuse the same service
+ * @param {Authorizer} [authorizer] Optional authorizer to use.
+ * @return {function} A dispatcher function that will reuse the same service
* object.
*/
function createLeafDispatcher(service, authorizer) {
- return function() {
+ var dispacther = function() {
return {
service: service,
authorizer: authorizer,
};
};
+ dispacther._isLeaf = true;
+ return dispacther;
}
/**
diff --git a/src/rpc/server-option.js b/src/rpc/server-option.js
new file mode 100644
index 0000000..d8785ce
--- /dev/null
+++ b/src/rpc/server-option.js
@@ -0,0 +1,80 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var RpcServerOption =
+ require('../gen-vdl/v.io/x/ref/services/wspr/internal/app').RpcServerOption;
+var verror = require('../gen-vdl/v.io/v23/verror');
+
+module.exports = serverOption;
+
+/**
+ * Creates serverOption that can be passed to
+ * [runtime.newServer(serverOptions)]{@link module:vanadium~Runtime#newServer}
+ * to specify different server configurations.
+ * @param {object} opts Server options.
+ * @param {bool} opts.isLeaf Indicates server will be used to serve a leaf
+ * service. This option is automatically set to true if
+ * [server.serve()]{@link module:vanadium.rpc~Server#serve} is used.
+ * It defaults to false if
+ * [server.serveDispacther()]{@link module:vanadium.rpc~Server#serveDispatcher}
+ * is used instead.
+ * @param {bool} opts.servesMountTable Indicates server will be used to serve
+ * a MountTable. This server cannot be used for any other purpose.
+ * @return {module:vanadium.rpc~Server~ServerOption}
+ * @memberof module:vanadium.rpc
+ */
+function serverOption(opts) {
+ opts = opts || {};
+ var allowedOptions = ['isLeaf', 'servesMountTable'];
+ // Validate opts.
+ var keys = Object.keys(opts);
+ keys.forEach(function(key) {
+ if (allowedOptions.indexOf(key) < 0) {
+ throw new verror.BadArgError(null, 'Invalid server option ' + key);
+ }
+ });
+
+ return new ServerOption(opts);
+}
+
+/**
+ * @summary ServerOption represents different configurations that can be
+ * specified when creating a new server.
+ * @description
+ * Private constructor, use
+ * [vanadium.rpc.serverOption(opts)]{@link module:vanadium.rpc.serverOption}
+ * to construct an instance.
+ * @constructor
+ * @memberof module:vanadium.rpc~Server
+ * @inner
+ */
+function ServerOption(opts) {
+ opts = opts || {};
+ var allowedOptions = ['isLeaf', 'servesMountTable'];
+ // Validate opts.
+ var keys = Object.keys(opts);
+ keys.forEach(function(key) {
+ if (allowedOptions.indexOf(key) < 0) {
+ throw new verror.BadArgError(null, 'Invalid server option ' + key);
+ }
+ });
+
+ this._opts = opts;
+}
+
+/**
+ * Convert ServerOption object to array of RpcCallOption VDL values.
+ * @private
+ * @return {Array} Array of RpcServerOption VDL values.
+ */
+ServerOption.prototype._toRpcServerOption = function(ctx, proxy) {
+ var rpcCallOptions = [];
+ var keys = Object.keys(this._opts);
+ keys.forEach(function(key) {
+ var opt = {};
+ opt[key] = this._opts[key];
+ rpcCallOptions.push(new RpcServerOption(opt));
+ }, this);
+ return rpcCallOptions;
+};
\ No newline at end of file
diff --git a/src/rpc/server-router.js b/src/rpc/server-router.js
index fa11661..53520d8 100644
--- a/src/rpc/server-router.js
+++ b/src/rpc/server-router.js
@@ -653,7 +653,13 @@
Router.prototype.serve = function(name, server, cb) {
vlog.logger.info('Serving under the name: ', name);
this._servers[server.id] = server;
- return this._controller.serve(this._rootCtx, name, server.id, cb);
+ // If using a leaf dispatcher, set the IsLeaf ServerOption.
+ var isLeaf = server.dispatcher && server.dispatcher._isLeaf;
+ if (isLeaf) {
+ server.serverOption._opts.isLeaf = true;
+ }
+ var rpcOpts = server.serverOption._toRpcServerOption();
+ return this._controller.serve(this._rootCtx, name, server.id, rpcOpts, cb);
};
/**
diff --git a/src/rpc/server.js b/src/rpc/server.js
index 6f41879..9265898 100644
--- a/src/rpc/server.js
+++ b/src/rpc/server.js
@@ -29,6 +29,7 @@
var defaultAuthorizer = require('../security/default-authorizer');
var actions = require('./../verror/actions');
var makeError = require('../verror/make-errors');
+var ServerOption = require('./server-option');
var nextServerID = 1; // The ID for the next server.
@@ -42,7 +43,7 @@
* @constructor
* @memberof module:vanadium.rpc
*/
-function Server(router) {
+function Server(router, serverOption) {
if (!(this instanceof Server)) {
return new Server(router);
}
@@ -53,6 +54,7 @@
this.id = nextServerID++;
this.dispatcher = null;
this.serviceObjectHandles = {};
+ this.serverOption = serverOption || new ServerOption();
}
/**
diff --git a/src/runtime/index.js b/src/runtime/index.js
index 4c7ccf2..e019cbf 100644
--- a/src/runtime/index.js
+++ b/src/runtime/index.js
@@ -146,10 +146,15 @@
/**
* Creates a new [Server]{@link module:vanadium.rpc~Server} instance.<br>
* Server allows one to create, publish and stop Vanadium services.
+ * @param {module:vanadium.rpc~Server~ServerOption} [serverOption] Optional
+ * server option that can be specified when creating a new server. serverOption
+ * can be created with the
+ * [vanadium.rpc.serverOption(opts)]{@link module:vanadium.rpc#serverOption}
+ * method.
* @return {module:vanadium.rpc~Server} A server instance.
*/
-Runtime.prototype.newServer = function() {
- return new Server(this._getRouter());
+Runtime.prototype.newServer = function(serverOption) {
+ return new Server(this._getRouter(), serverOption);
};
/**
diff --git a/src/vanadium.js b/src/vanadium.js
index 63923b1..6154e3a 100644
--- a/src/vanadium.js
+++ b/src/vanadium.js
@@ -51,7 +51,7 @@
vom: require('./vom'),
uniqueId: require('./lib/uniqueid'),
vtrace: require('./vtrace'),
- runtimeForContext: require('./runtime/runtime-from-context'),
+ runtimeForContext: require('./runtime/runtime-from-context')
};
if (isBrowser) {
diff --git a/test/integration/serve.js b/test/integration/serve.js
index 5250edd..9d67350 100644
--- a/test/integration/serve.js
+++ b/test/integration/serve.js
@@ -47,13 +47,14 @@
//
function serve(name, dispatcher, callback) {
var options = defaults;
-
+ var serverOption;
// alternate: serve(options, callback)
if (typeof name === 'object') {
options = extend(defaults, name);
callback = dispatcher;
name = options.name;
dispatcher = options.dispatcher;
+ serverOption = options.serverOption;
}
vanadium.init(config, function(err, runtime) {
@@ -68,7 +69,7 @@
return callback(err, basicRes);
}
- var server = runtime.newServer();
+ var server = runtime.newServer(serverOption);
server.serveDispatcher(name, dispatcher, function(err) {
if (err) {
return callback(err, basicRes);
diff --git a/test/integration/test-namespace.js b/test/integration/test-namespace.js
index f5cfc88..c7ede04 100644
--- a/test/integration/test-namespace.js
+++ b/test/integration/test-namespace.js
@@ -27,10 +27,16 @@
var ctx = runtime.getContext();
var rpc = namespace.glob(ctx, PREFIX + '*');
rpc.catch(end);
- return readAllNames(rpc.stream);
+ return readAllMountPoints(rpc.stream);
}).then(function validate(actual) {
- var expected = [PREFIX + 'cottage', PREFIX + 'house'];
- assert.deepEqual(actual.sort(), expected.sort());
+ var expected = [{
+ name: PREFIX + 'cottage',
+ isLeaf: false
+ }, {
+ name: PREFIX + 'house',
+ isLeaf: false
+ }];
+ assertResults(actual, expected, assert);
end();
}).catch(end);
@@ -54,13 +60,16 @@
var ctx = runtime.getContext();
var rpc = namespace.glob(ctx, PREFIX + 'cottage/*/*/*');
rpc.catch(end);
- return readAllNames(rpc.stream);
+ return readAllMountPoints(rpc.stream);
}).then(function validate(actual) {
- var expected = [
- PREFIX + 'cottage/lawn/back/sprinkler',
- PREFIX + 'cottage/lawn/front/sprinkler'
- ];
- assert.deepEqual(actual.sort(), expected.sort());
+ var expected = [{
+ name: PREFIX + 'cottage/lawn/back/sprinkler',
+ isLeaf: true
+ }, {
+ name: PREFIX + 'cottage/lawn/front/sprinkler',
+ isLeaf: true
+ }];
+ assertResults(actual, expected, assert);
end();
}).catch(end);
@@ -84,7 +93,7 @@
var ctx = runtime.getContext();
var rpc = namespace.glob(ctx, PREFIX + 'does/not/exist');
rpc.catch(end);
- return readAllNames(rpc.stream);
+ return readAllMountPoints(rpc.stream);
}).then(function validate(actual) {
var expected = [];
assert.deepEqual(actual.sort(), expected.sort());
@@ -166,7 +175,7 @@
vanadium.init(config).then(function glob(rt) {
runtime = rt;
var namespace = rt.namespace();
- // Note: Glob will always timeout after 30s
+ // Note: Glob will always timeout after 30s
// see v.io/x/ref/profiles/internal/naming/namespace/parallelstartcall.go
// This means we'll get a timeout error on the glob stream before
// timeouts.long expires.
@@ -372,10 +381,16 @@
}).then(function glob() {
var rpc = namespace.glob(ctx, PREFIX + '*');
rpc.catch(end);
- return readAllNames(rpc.stream);
+ return readAllMountPoints(rpc.stream);
}).then(function validate(actual) {
- var expected = [PREFIX + 'cottage', PREFIX + 'house'];
- assert.deepEqual(actual.sort(), expected.sort());
+ var expected = [{
+ name: PREFIX + 'cottage',
+ isLeaf: false
+ }, {
+ name: PREFIX + 'house',
+ isLeaf: false
+ }];
+ assertResults(actual, expected, assert);
end();
}).catch(end);
@@ -710,15 +725,15 @@
* Given a glob stream, returns a promise that will resolve to an array
* of glob results after all the results have been collected from the stream.
*/
-function readAllNames(stream) {
- var names = [];
+function readAllMountPoints(stream) {
+ var mps = [];
return new Promise(function(resolve, reject) {
stream.on('data', function(mountPoint) {
- names.push(mountPoint.name);
+ mps.push(mountPoint);
});
stream.on('end', function(name) {
- resolve(names);
+ resolve(mps);
});
stream.on('error', function(errItem) {
@@ -730,6 +745,21 @@
});
}
+function assertResults(got, want, assert) {
+ var toEqual = [];
+ got.forEach(function(e) {
+ toEqual.push({
+ name: e.name,
+ isLeaf: e.isLeaf
+ });
+ });
+ assert.deepEqual(want.sort(mpSorter), toEqual.sort(mpSorter));
+
+ function mpSorter(a, b) {
+ return a.name.localeCompare(b.name);
+ }
+}
+
var SAMPLE_NAMESPACE = [
'house/alarm',
'house/living-room/lights',
@@ -810,4 +840,4 @@
});
}
});
-}
+}
\ No newline at end of file
diff --git a/test/integration/test-server-call.js b/test/integration/test-server-call.js
index b4eb53c..84abd12 100644
--- a/test/integration/test-server-call.js
+++ b/test/integration/test-server-call.js
@@ -4,10 +4,9 @@
var test = require('prova');
var serve = require('./serve');
-var leafDispatcher = require('../../src/rpc/leaf-dispatcher');
// Services that handles anything in a/b/* where b is the service name
-var dispatcher = leafDispatcher({
+var service = {
getSuffix: function(ctx, serverCall) {
return serverCall.securityCall.suffix;
},
@@ -24,7 +23,13 @@
cb(null, results);
}
-});
+};
+
+function dispatcher(suffix, cb) {
+ cb(null, {
+ service: service
+ });
+}
var expectedContext = {
suffix: 'suf',
diff --git a/test/integration/test-server-option.js b/test/integration/test-server-option.js
new file mode 100644
index 0000000..fc726de
--- /dev/null
+++ b/test/integration/test-server-option.js
@@ -0,0 +1,165 @@
+// Copyright 2015 The Vanadium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+var test = require('prova');
+var vanadium = require('../../');
+var serve = require('./serve');
+
+function dispatcher(suffix) {
+ return {
+ service: function(ctx, serverCall) {
+ throw new Error('NotImplemented');
+ },
+ authorizer: function(ctx, call) {
+ return null;
+ }
+ };
+}
+
+test('Test IsLeaf=True Server Option', function(t) {
+ var serverOption = vanadium.rpc.serverOption({
+ isLeaf: true
+ });
+ var name = 'testing/serverOption/isLeafTrue';
+
+ var servObj = {
+ name: name,
+ dispatcher: dispatcher,
+ serverOption: serverOption
+ };
+
+ serve(servObj, function(err, res) {
+ t.error(err);
+
+ var rt = res.runtime;
+ var ns = rt.namespace();
+ var stream = ns.glob(rt.getContext(), name).stream;
+ stream.on('data', function(mp) {
+ t.error(err);
+
+ t.equal(mp.isLeaf, true, 'Glob must indicate server is a leaf');
+ t.equal(mp.servesMountTable, false,
+ 'Glob must indicate server is not a mounttable');
+ res.end(t);
+ });
+ });
+});
+
+test('Test IsLeaf=False Server Option', function(t) {
+ var serverOption = vanadium.rpc.serverOption({
+ isLeaf: false
+ });
+ var name = 'testing/serverOption/isLeafFalse';
+
+ var servObj = {
+ name: name,
+ dispatcher: dispatcher,
+ serverOption: serverOption
+ };
+
+ serve(servObj, function(err, res) {
+ t.error(err);
+
+ var rt = res.runtime;
+ var ns = rt.namespace();
+ var stream = ns.glob(rt.getContext(), name).stream;
+ stream.on('data', function(mp) {
+ t.error(err);
+
+ t.equal(mp.isLeaf, false, 'Glob must indicate server is not a leaf');
+ t.equal(mp.servesMountTable, false,
+ 'Glob must indicate server is not a mounttable');
+ res.end(t);
+ });
+ });
+});
+
+test('Test ServesMountTable=True Server Option', function(t) {
+ var serverOption = vanadium.rpc.serverOption({
+ servesMountTable: true
+ });
+ var name = 'testing/serverOption/ServesMountTableTrue';
+
+ var servObj = {
+ name: name,
+ dispatcher: dispatcher,
+ serverOption: serverOption
+ };
+
+ serve(servObj, function(err, res) {
+ t.error(err);
+
+ var rt = res.runtime;
+ var ns = rt.namespace();
+ var stream = ns.glob(rt.getContext(), name).stream;
+ stream.on('data', function(mp) {
+ t.error(err);
+
+ t.equal(mp.isLeaf, false, 'Glob must indicate server is not a leaf');
+ t.equal(mp.servesMountTable, true,
+ 'Glob must indicate server is a mounttable');
+ res.end(t);
+ });
+ });
+});
+
+test('Test ServesMountTable=false server option', function(t) {
+ var serverOption = vanadium.rpc.serverOption({
+ servesMountTable: false
+ });
+ var name = 'testing/serverOption/ServesMountTableFalse';
+
+ var servObj = {
+ name: name,
+ dispatcher: dispatcher,
+ serverOption: serverOption
+ };
+
+ serve(servObj, function(err, res) {
+ t.error(err);
+
+ var rt = res.runtime;
+ var ns = rt.namespace();
+ var stream = ns.glob(rt.getContext(), name).stream;
+ stream.on('data', function(mp) {
+ t.error(err);
+
+ t.equal(mp.isLeaf, false, 'Glob must indicate server is not a leaf');
+ t.equal(mp.servesMountTable, false,
+ 'Glob must indicate server is not a mounttable');
+ res.end(t);
+ });
+ });
+});
+
+test('Test ServesMountTable=ture and IsLeaf=true server option',
+ function(t) {
+ var serverOption = vanadium.rpc.serverOption({
+ servesMountTable: true,
+ isLeaf: true
+ });
+ var name = 'testing/serverOption/Both';
+
+ var servObj = {
+ name: name,
+ dispatcher: dispatcher,
+ serverOption: serverOption
+ };
+
+ serve(servObj, function(err, res) {
+ t.error(err);
+
+ var rt = res.runtime;
+ var ns = rt.namespace();
+ var stream = ns.glob(rt.getContext(), name).stream;
+ stream.on('data', function(mp) {
+ t.error(err);
+
+ t.equal(mp.isLeaf, true, 'Glob must indicate server is a leaf');
+ t.equal(mp.servesMountTable, true,
+ 'Glob must indicate server is a mounttable');
+ res.end(t);
+ });
+ });
+ });
\ No newline at end of file