Skip to content

Commit

Permalink
feat(availity-mock-server): integrate mock server. Closes #127
Browse files Browse the repository at this point in the history
  • Loading branch information
Rob McGuinness committed Jan 2, 2018
1 parent 0683816 commit 79b156c
Show file tree
Hide file tree
Showing 36 changed files with 1,873 additions and 0 deletions.
5 changes: 5 additions & 0 deletions packages/availity-mock-server/.eslintrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
extends: availity
rules:
import/no-dynamic-require: 0
global-require: 0
62 changes: 62 additions & 0 deletions packages/availity-mock-server/config/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
const _ = require('lodash');
const chalk = require('chalk');
const logger = require('../logger').getInstance();

class Configuration {
constructor() {
this.server = null;
this.app = null;
this.router = null;
this.routes = [];
this.events = null;
this.path = null;
this.addressInUse = null;

this.constants = {
EVENTS: {
START: 'av:started',
STOPPED: 'av:stopped',
REQUEST: 'av:request',
RESPONSE: 'av:response',
REDIRECT: 'av:redirect',
FILE_NOT_FOUND: 'av:fileNotFound'
}
};
}

/**
* Set the path of the configuration object
*
* @param {Sring} path full path to configuration. Ex: path.join(__dirname, 'config.js')
*/

defaultConfig(path) {
return this.path ? require(path) : require('../config');
}

/**
* Sets the configuration object from the configuration file and command line overrides.
*
* @param {Object} options configuration object with production|development|testing settings.
*/
set(_options) {
const options = _options || {};

logger.setProvider(options.logProvider);

// Get the config object by path or from root
if (this.path) {
logger.info(`Using ${chalk.blue(this.path)}`);
}
let config = this.path ? require(this.path) : this.defaultConfig();

// Allow programmatic overrides for environment
config = _.merge(config, options);

// Save to `this.options`
this.options = config;
}
}

module.exports = new Configuration();
94 changes: 94 additions & 0 deletions packages/availity-mock-server/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/* eslint-disable promise/avoid-new */
const express = require('express');
const events = require('events');
const http = require('http');
const chalk = require('chalk');
const logger = require('./logger');
const config = require('./config');
const middleware = require('./middleware');

class Ekko {
constructor(ekkoConfig) {
if (ekkoConfig) {
const isString = typeof ekkoConfig === 'string';

if (isString) {
this.configPath = ekkoConfig;
} else {
this.middleware(ekkoConfig);
}
}

config.events = new events.EventEmitter();
}

middleware(options) {
config.path = this.configPath;
config.set(options);

config.app = express();
config.router = new express.Router();

middleware.headers();
middleware.config();

return config.router;
}

async start(options) {
this.middleware(options);

const port = config.options.port || 0;
config.app.set('port', port);
config.server = http.createServer(config.app);

return new Promise((resolve, reject) => {
config.server.listen(config.options.port, () => {
const url = `http://localhost:${config.server.address().port}`;
logger.getInstance().info(`Ekko server started at ${chalk.green(url)}`);

config.events.emit(config.constants.EVENTS.START, {
options: config.options
});

resolve(true);
});

config.server.on('error', e => {
if (e.errno === 'EADDRINUSE') {
logger
.getInstance()
.error(`Cannot start Ekko server on PORT ${config.options.port}. Check if port is already in use.`);
} else {
logger.getInstance().error(`Failed to start Ekko server on PORT ${config.options.port}`);
}

reject(new Error(e));
});
});
}

stop() {
return new Promise(resolve => {
if (config.server && config.server.close) {
config.server.close(() => {
config.events.emit(config.constants.EVENTS.STOPPED);
resolve(true);
});
} else {
config.events.emit(config.constants.EVENTS.STOPPED);
resolve(true);
}
});
}

on(event, callback) {
return config.events.on(event, callback);
}

config() {
return config;
}
}

module.exports = Ekko;
97 changes: 97 additions & 0 deletions packages/availity-mock-server/logger/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/* eslint no-console:0 */
const chalk = require('chalk');

let loggerInstance;

class DefaultLogger {
constructor(options) {
this.options = options;
}

warn(entry) {
this.record(entry, 'yellow');
}

error(entry) {
this.record(entry, 'red');
}

info(entry) {
this.record(entry);
}

debug(entry) {
this.record(entry);
}

log(entry) {
this.record(entry);
}

// › Starting server
record(entry, color) {
const defaultColor = entry instanceof Error ? 'red' : 'gray';
const crayoloa = color || defaultColor;

console.log(`${chalk[crayoloa](entry)}`);
}
}

class Logger {
constructor() {
this.provider = null;
this.setProvider(() => new DefaultLogger());
}

canLog() {
return process.env.NODE_ENV !== 'testing';
}

setProvider(fn) {
if (fn) {
this.provider = fn();
}
}

warn(entry) {
if (this.canLog()) {
this.provider.warn(entry);
}
}

error(entry) {
if (this.canLog()) {
this.provider.error(entry);
}
}

info(entry) {
if (this.canLog()) {
this.provider.info(entry);
}
}

debug(entry) {
if (this.canLog()) {
this.provider.debug(entry);
}
}

log(entry) {
if (this.canLog()) {
this.provider.log(entry);
}
}
}

module.exports = {
// singleton
getInstance() {
if (!loggerInstance) {
loggerInstance = new Logger();
}

return loggerInstance;
},

};
69 changes: 69 additions & 0 deletions packages/availity-mock-server/middleware/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
const errorhandler = require('errorhandler');
const compression = require('compression');
const methodOverride = require('method-override');
const cors = require('cors');
const path = require('path');
const bodyParser = require('body-parser');
const busboy = require('connect-busboy');
const _ = require('lodash');
const onFinished = require('on-finished');
const chalk = require('chalk');

const config = require('../config');
const routes = require('../routes');
const logger = require('../logger').getInstance();

const requestHandler = require('./request');
const notFoundHandler = require('./not.found');

// Custom request logger
module.exports = function development() {
if (logger.canLog()) {
config.router.use((req, res, next) => {
function logRequest() {
const method = `${chalk.white(req.method)}`;
const url = `${chalk.dim(req.originalUrl || req.url)}`;
// eslint-disable-next-line no-underscore-dangle
const code = res._header ? String(res.statusCode) : '';
const file = chalk.dim(res.avFile || '');

logger.log(`${method} ${url} ${chalk.white(code)} ${chalk.blue(path.basename(file))}`);
}

// Callback is called at the end of request cycle after headers are set
onFinished(res, logRequest);

next();
});
}

config.router.use(requestHandler());
config.router.use(errorhandler());
config.router.use(compression());
config.router.use(cors());

// pretty print json
config.app.set('json spaces', 2);

config.router.use(methodOverride('X-HTTP-Method-Override'));

config.router.use(
bodyParser.json({
limit: _.get(config, 'options.limit', '50mb')
})
); // parse application/json

config.router.use(
bodyParser.urlencoded({
extended: true,
limit: config.options.limit
})
); // // parse application/x-www-form-urlencoded

config.router.use(busboy({ immediate: false }));

config.app.use('/', config.router);
routes.init();

config.app.use(notFoundHandler());
};
9 changes: 9 additions & 0 deletions packages/availity-mock-server/middleware/headers.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const config = require('../config');

module.exports = function headers() {
config.app.disable('x-powered-by');
config.app.use((req, res, next) => {
res.setHeader('X-Powered-By', 'Ekko');
next();
});
};
7 changes: 7 additions & 0 deletions packages/availity-mock-server/middleware/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const headers = require('./headers');
const config = require('./config');

module.exports = {
headers,
config
};
38 changes: 38 additions & 0 deletions packages/availity-mock-server/middleware/not.found.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
const config = require('../config');

module.exports = function notfound() {
return (req, res) => {
res.status(404);

config.events.emit(config.constants.EVENTS.FILE_NOT_FOUND, {
req
});

const message = 'Not Found';

if (req.accepts('html')) {
res
.type('html')
.status(404)
.end(
'<!DOCTYPE html> <html> <head> <title>Dummy Mock Server Response</title> </head> <body> <h1>Not Found<h1> </body> </html>'
);
return;
}

// respond with json
if (req.accepts('json')) {
res.type('json').send({ error: message });
return;
}

// respond with json
if (req.accepts('xml')) {
res.type('xml').send(`<error><message>${message}</message></error>`);
return;
}

// default to plain-text. send()
res.type('txt').send({ error: message });
};
};
Loading

0 comments on commit 79b156c

Please sign in to comment.