Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for mocking services #90

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
6 changes: 5 additions & 1 deletion bin/blueoak-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ cli = parseOptions();

server.init({
appDir: process.cwd(),
mockServices: cli.mockServices
mocks: {
services: cli.mockServices,
middleware: cli.mockMiddleware
}
}, function(err) {
if (err) {
console.warn('Startup failed', err);
Expand All @@ -25,6 +28,7 @@ function parseOptions() {
// parse cli options
cli.version(pkg.version)
.option('--mock-services <services>', 'comma separated list of service names to mock', toList)
.option('--mock-middleware <middleware>', 'comma separated list of middleware to mock', toList)
.parse(process.argv);

return cli;
Expand Down
4 changes: 2 additions & 2 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ module.exports.init = function (opts, callback) {
global.__appDir = opts.appDir;
}

if (opts.mockServices) {
global.__mockServices = opts.mockServices;
if (opts.mocks) {
global.__mocks = opts.mocks;
}

//Load the bootstrap services first (config and logging) since they're only needed for the master
Expand Down
4 changes: 2 additions & 2 deletions lib/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ function createLoader() {
//if parent id is a consumer, i.e. was registered with a prefix,
//strip the prefix off since that's not part of the module name
parentId = parentId.indexOf('.') > -1 ? parentId.substring(parentId.indexOf('.') + 1) : parentId;

var mod = subRequire(id, parentId);
moduleMap[id] = mod;
dependencyMap[id] = normalizeServiceNames(di.getParamNames(mod.init));
Expand Down Expand Up @@ -180,7 +180,7 @@ function createLoader() {
var modPath = path.resolve(dir, file);
var mod;
try {
mod = require(modPath);
mod = subRequire(modPath);
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Middleware mocks were not loading because middleware was not loaded with subRequire. I did this to make it work, but admittedly do not understand all of the potential ramifications of this change.

} catch (e) {
throw new Error('Could not load ' + modPath + ': ' + e.message);
}
Expand Down
53 changes: 44 additions & 9 deletions lib/subRequire.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
* In this case we could call subRequire(Y, X), and it would require Y from the context of X.
*/
var path = require('path'),
util = require('util'),
fs = require('fs'),
_ = require('lodash');

var modulePath = {}; //maintain a list of the paths where we resolved files - needed for unloading the modules
Expand All @@ -25,15 +27,7 @@ var modulePath = {}; //maintain a list of the paths where we resolved files - ne
* but also provides a way to load submodules by passing the optional parentId argument.
*/
module.exports = function (id, parentId) {
// load mock if appropriate
if (global.__mockServices &&
_.includes(global.__mockServices, path.basename(id, path.extname(id)))
) {
var mockPath = path.resolve(global.__appDir, 'test', 'bos-mocks', 'services', path.basename(id));
if (mockPath) {
id = mockPath;
}
}
id = resolveMock(id);

if (id.indexOf('.js') > -1) {
return loadJsFile(id);
Expand All @@ -54,6 +48,47 @@ module.exports.unload = function (id) {
}
};

//Attempts to resolve mock modules
function resolveMock(id, type) {
// short circuit if no mocks are declared
if (!global.__mocks) {
return id;
}

// recurse to resolve different mock types
if (arguments.length < 2) {
id = resolveMock(id, 'services');
id = resolveMock(id, 'middleware');
return id;
}

// if the mock type declares our mock, attempt to resolve it
if (global.__mocks[type] &&
_.includes(global.__mocks[type], path.basename(id, path.extname(id)))
) {
var mockId = path.basename(id);
var mockPath = path.resolve(global.__appDir, 'test', 'bos-mocks', type, mockId);
var mockExists = fs.existsSync(mockPath) || fs.existsSync(mockPath + '.js');

// if we have a mock path and the mock exists, load it
// otherwise, warn the user
if (mockPath && mockExists) {
id = mockPath;
} else if (!mockExists) {
var logger = this.services.get('logger');
if (logger) {
this.services.get('logger').warn(
util.format('The requested mock %s "%s" were not found in the mock %s directory (%s)',
type,
mockId,
type,
path.dirname(mockPath)
));
}
}
}
return id;
}

//Performs a require directly on a file
//A module id is calculated based on the name of the file, e.g.
Expand Down
3 changes: 2 additions & 1 deletion test/integration/fixtures/server12/config/default.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"express": {
"port": "5000"
"port": "5000",
"middleware": ["pet-middleware1", "pet-middleware2"]
},

"cluster": {
Expand Down
12 changes: 8 additions & 4 deletions test/integration/fixtures/server12/handlers/petstore.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,23 +2,27 @@
* Copyright (c) 2015-2016 PointSource, LLC.
* MIT Licensed
*/
var service1;
var service2;
var serviceModule;
exports.init = function (logger, petService1, petService2, petServiceModule) {
var service1,
service2,
serviceModule;

exports.init = function (petService1, petService2, petServiceModule) {
service1 = petService1;
service2 = petService2;
serviceModule = petServiceModule;
};

exports.getPets1 = function (req, res, next) {
res.send(service1.getPets());
next();
};

exports.getPets2 = function (req, res, next) {
res.send(service2.getPets());
next();
};

exports.getPets3 = function (req, res, next) {
res.send(serviceModule.getPets());
next();
};
10 changes: 10 additions & 0 deletions test/integration/fixtures/server12/middleware/pet-middleware1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
exports.init = function (app, config, logger, callback) {
app.use(middleware);
logger.info('Pet Middleware1 initialized');
callback();
};

function middleware(req, res, next) {
res.header('x-pet-middleware1', 'pet-middleware1');
next();
}
10 changes: 10 additions & 0 deletions test/integration/fixtures/server12/middleware/pet-middleware2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
exports.init = function (app, config, logger, callback) {
app.use(middleware);
logger.info('Pet Middleware2 initialized');
callback();
};

function middleware(req, res, next) {
res.header('x-pet-middleware2', 'pet-middleware2');
next();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
exports.init = function (app, config, logger, callback) {
app.use(middleware);
logger.info('Pet Middleware1 Mock initialized');
callback();
};

function middleware(req, res, next) {
res.header('x-pet-middleware1', 'pet-middleware1-mock');
next();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
exports.init = function (app, config, logger, callback) {
app.use(middleware);
logger.info('Pet Middleware2 Mock initialized');
callback();
};

function middleware(req, res, next) {
res.header('x-pet-middleware2', 'pet-middleware2-mock');
next();
}
10 changes: 10 additions & 0 deletions test/integration/fixtures/server13/config/default.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"express": {
"port": "5000",
"middleware": ["pet-middleware"]
},

"cluster": {
"maxWorkers": 1
}
}
24 changes: 24 additions & 0 deletions test/integration/fixtures/server13/handlers/petstore.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright (c) 2015-2016 PointSource, LLC.
* MIT Licensed
*/
var service1;
var service2;
var serviceModule;
exports.init = function (logger, petService1, petService2, petServiceModule) {
service1 = petService1;
service2 = petService2;
serviceModule = petServiceModule;
};

exports.getPets1 = function (req, res, next) {
res.send(service1.getPets());
};

exports.getPets2 = function (req, res, next) {
res.send(service2.getPets());
};

exports.getPets3 = function (req, res, next) {
res.send(serviceModule.getPets());
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exports.init = function () {

};

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 14 additions & 0 deletions test/integration/fixtures/server13/services/pet-service1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2015-2016 PointSource, LLC.
* MIT Licensed
*/
exports.init = function(logger) {
logger.info('Pet Service1 initialized');
};

exports.getPets = function() {
return {
id: 1,
name: 'service1 pet'
};
};
14 changes: 14 additions & 0 deletions test/integration/fixtures/server13/services/pet-service2.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/*
* Copyright (c) 2015-2016 PointSource, LLC.
* MIT Licensed
*/
exports.init = function(logger) {
logger.info('Pet Service2 initialized');
};

exports.getPets = function() {
return {
id: 2,
name: 'service2 pet'
};
};
Loading