blob: 44c4b853f3a39e56b29af4998bd9d90f11388b6e [file] [log] [blame]
// 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 vanadium = require('../../');
var config = require('./default-config');
var extend = require('xtend');
var defaults = {
autoBind: true
};
module.exports = serve;
// # serve(name, dispatcher, callback)
//
// DRYs up test code by wrapping the default success case for:
//
// vanadium.init() ->
// runtime.server(name, dispatcher, ...) ->
// runtime.bindTo(ctx, name, ...) -> r
// assertions ->
// runtime.close()
//
// To make a connection to the default integration test wspr instance and
// bind to a service use:
//
// serve('test/service', dispatcher, function(err, res) {
// res.service.returnBuiltInError(function(err) {
// assert.error(err)
//
// // your assertions here...
//
// // `res` has several attributes to make your life easier:
// //
// // * runtime: vanadium runtime object
// // * config: config passed into vanadium.init()
// // * server: returned from runtime._getServer()
// // * service: returned from runtime.bindTo(name, ...)
// // * end: the end function to shut down the connection
//
//
// // use the `res.end` function to close the underlying runtime/wspr
// // connection and end your test run.
// res.end(assert);
// })
// })
//
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) {
// basic response used for failures where we want .close and .end to
// still work:
var basicRes = {
end: end,
close: close
};
if (err) {
return callback(err, basicRes);
}
runtime.newDispatchingServer(name, dispatcher, serverOption,
function(err, server) {
if (err) {
return callback(err, basicRes);
}
var ctx = runtime.getContext();
waitUntilResolve();
// The server is not gauranteed to be mounted by the time the
// serve call finishes. We should wait until the name
// resolves before calling the callback. As a side a benefit,
// this also speeds up the browser tests, because browspr is
// quicker than wspr and so it is more likely to return before
// the server is mounted. The normal backoff for bindTo
// starts at 100ms, but this code only waits a few
// milliseconds. TODO(mattr): I have temporarily set this to
// retry at longer intervals. In practice this previous code
// (which checked every 10ms) allowed the server up to 0.5s or
// so to mount through the proxy. In the new RPC system it
// can take a bit longer. I upped the number of attempts and
// retry time to compensate. We will eventually optimize this
// time back down.
function waitUntilResolve() {
var ns = runtime.getNamespace();
var count = 0;
runResolve();
function runResolve() {
ns.resolve(ctx, name, function(err, s) {
if (err || s.length === 0) {
count++;
if (count === 20) {
return callback(
new Error(
'Timed out waiting for resolve in serve.js: ' + err),
basicRes);
}
return setTimeout(runResolve, 100);
}
completeServe();
});
}
}
function completeServe() {
var res = {
runtime: runtime,
config: config,
close: close,
end: end,
server: server
};
if (options.autoBind === false) {
return callback(err, res, end);
}
function onBind(err, service) {
if (err) {
return callback(err, basicRes);
}
res.service = service;
callback(err, res, end);
}
var client = runtime.getClient();
client.bindTo(ctx, name, onBind);
}
});
function close(callback) {
return runtime.close(callback);
}
// hoisted and passed as the last argument to the callback argument.
function end(assert, errorMsg) {
if (!!assert.end && typeof assert.end === 'function') {
return close(function(err) {
assert.error(err, 'should not error on runtime.close(...)');
assert.end(errorMsg);
});
} else {
var message = 'end(callback) requires an assert object';
throw new Error(message);
}
}
});
}