Skip to content

Commit

Permalink
Handle body request
Browse files Browse the repository at this point in the history
  • Loading branch information
Nicolas COUET committed Apr 12, 2018
1 parent 8611696 commit 0cb2a95
Show file tree
Hide file tree
Showing 2 changed files with 190 additions and 133 deletions.
317 changes: 187 additions & 130 deletions app/http-mock-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,183 +6,240 @@ const sleep = require('sleep');
const pathToRegexp = require('path-to-regexp');
const path = require('path');
const mime = require('mime');
const {parse} = require('querystring');

class HttpMockServer {
constructor(app) {
this.app = app;
http.createServer((req, res) => {
let foundEndpoint = this.findEndpoint(req);

if (foundEndpoint !== null) {
if (Array.isArray(foundEndpoint.response)) {
let weightResponseIndexes = [];
foundEndpoint.response.forEach((responseItem, index) => {
weightResponseIndexes = weightResponseIndexes.concat((new Array(responseItem.weight || 1)).fill(index));
});
const randIndex = weightResponseIndexes[Math.floor(Math.random() * weightResponseIndexes.length)];
if (randIndex !== undefined) {
HttpMockServer.writeResponse(req, res, foundEndpoint, foundEndpoint.response[randIndex]);
}
} else {
HttpMockServer.writeResponse(req, res, foundEndpoint, foundEndpoint.response);
}
constructor(app) {
this.app = app;
http.createServer((req, res) => {
let body = null;
req.on('data', (chunk) => {
if (!body) {
body = '';
}
body += chunk;
});
req.on('end', () => {

// build body
if (body) {
if (req.headers['content-type']) {
if (req.headers['content-type'] ===
'application/x-www-form-urlencoded') {
req.body = parse(body);
} else if (req.headers['content-type'] ===
'application/json') {
req.body = JSON.parse(body);
} else {
res.writeHead(404, {});
try {
req.body = JSON.parse(body);
}
catch (error) {
try {
req.body = parse(body);
}
catch (error) {
req.body = body;
}
}
}
} else {
req.body = body;
}
}

res.end();
}).listen(80);
}
let foundEndpoint = this.findEndpoint(req);

static writeResponse(request, response, endpoint, endpointResponse) {
if (endpointResponse.delay) {
if (Array.isArray(endpointResponse.delay)) {
if (endpointResponse.delay.length === 2) {
sleep.msleep(Math.floor(Math.random() * (endpointResponse.delay[1] - endpointResponse.delay[0])) + endpointResponse.delay[0]);
}
} else {
sleep.msleep(endpointResponse.delay);
if (foundEndpoint !== null) {
if (Array.isArray(foundEndpoint.response)) {
let weightResponseIndexes = [];
foundEndpoint.response.forEach((responseItem, index) => {
weightResponseIndexes = weightResponseIndexes.concat((new Array(responseItem.weight || 1)).fill(index));
});
const randIndex = weightResponseIndexes[Math.floor(Math.random() * weightResponseIndexes.length)];
if (randIndex !== undefined) {
HttpMockServer.writeResponse(req, res, foundEndpoint, foundEndpoint.response[randIndex]);
}
} else {
HttpMockServer.writeResponse(req, res, foundEndpoint, foundEndpoint.response);
}
} else {
res.writeHead(404, {});
}

response.writeHead(endpointResponse.status || 200, endpointResponse.headers);
res.end();
});
}).listen(80);
}

if (endpointResponse.velocity && endpointResponse.velocity.enabled) {
response.write(Velocity.render(HttpMockServer.getEndpointBody(endpoint, endpointResponse), {
math: Math,
req: request,
endpoint: endpoint,
context: endpointResponse.velocity.context,
params: endpoint.params
}));
} else {
response.write(HttpMockServer.getEndpointBody(endpoint, endpointResponse));
static writeResponse(request, response, endpoint, endpointResponse) {
if (endpointResponse.delay) {
if (Array.isArray(endpointResponse.delay)) {
if (endpointResponse.delay.length === 2) {
sleep.msleep(Math.floor(Math.random() * (endpointResponse.delay[1] - endpointResponse.delay[0])) + endpointResponse.delay[0]);
}
} else {
sleep.msleep(endpointResponse.delay);
}
}

static getEndpointPath(endpoint, endpointRequest) {
let basePath = endpoint.basePath || '';
response.writeHead(endpointResponse.status || 200, endpointResponse.headers);

if (endpointResponse.velocity && endpointResponse.velocity.enabled) {
response.write(Velocity.render(HttpMockServer.getEndpointBody(endpoint, endpointResponse), {
math: Math,
req: request,
endpoint: endpoint,
context: endpointResponse.velocity.context,
params: endpoint.params
}));
} else {
response.write(HttpMockServer.getEndpointBody(endpoint, endpointResponse));
}
}

if (basePath !== '') {
basePath = '/' + basePath.replace(/^\//, "");
}
static getEndpointPath(endpoint, endpointRequest) {
let basePath = endpoint.basePath || '';

return basePath.replace(/\/$/, "") + '/' + endpointRequest.path.replace(/^\//, "");
if (basePath !== '') {
basePath = '/' + basePath.replace(/^\//, "");
}

isRequestMatch(endpoint, endpointRequest, request, endpointParams) {
endpoint.callCount = endpoint.callCount || 0;
return basePath.replace(/\/$/, "") + '/' + endpointRequest.path.replace(/^\//, "");
}

if (endpoint.maxCalls && endpoint.callCount >= endpoint.maxCalls) {
return false;
}
isRequestMatch(endpoint, endpointRequest, request, endpointParams) {
endpoint.callCount = endpoint.callCount || 0;

if (endpointRequest.method && request.method !== endpointRequest.method) {
return false;
}
if (endpoint.maxCalls && endpoint.callCount >= endpoint.maxCalls) {
return false;
}

let keys = [];
const re = pathToRegexp(HttpMockServer.getEndpointPath(endpoint, endpointRequest), keys);
const params = re.exec(request.path);
if (endpointRequest.method && request.method !== endpointRequest.method) {
return false;
}

if (params === null) {
return false;
}
let keys = [];
const re = pathToRegexp(HttpMockServer.getEndpointPath(endpoint, endpointRequest), keys);
const params = re.exec(request.path);

let matchQuery = true;
if (params === null) {
return false;
}

if (endpointRequest.query) {
Object.keys(endpointRequest.query).forEach((key) => {
if (!request.query[key]) {
matchQuery = false;
return;
}
let matchQuery = true;

if (!(new RegExp(endpointRequest.query[key])).test(request.query[key])) {
matchQuery = false;
}
});
if (endpointRequest.query) {
Object.keys(endpointRequest.query).forEach((key) => {
if (!request.query[key]) {
matchQuery = false;
return;
}

if (!matchQuery) {
return false;
if (!(new RegExp(endpointRequest.query[key])).test(request.query[key])) {
matchQuery = false;
}
});
}

let matchHeader = true;
if (!matchQuery) {
return false;
}

if (endpointRequest.headers) {
Object.keys(endpointRequest.headers).forEach((key) => {
if (!request.headers[key]) {
matchHeader = false;
return;
}
let matchHeader = true;

if (!(new RegExp(endpointRequest.headers[key])).test(request.headers[key])) {
matchHeader = false;
}
});
if (endpointRequest.headers) {
Object.keys(endpointRequest.headers).forEach((key) => {
if (!request.headers[key]) {
matchHeader = false;
return;
}

if (!matchHeader) {
return false;
if (!(new RegExp(endpointRequest.headers[key])).test(request.headers[key])) {
matchHeader = false;
}
});
}

keys.forEach((key, index) => {
endpointParams[key.name] = params[index + 1];
});

return true;
if (!matchHeader) {
return false;
}

findEndpoint(request) {
let params = {};
const urlParse = url.parse(request.url, true);
request.path = urlParse.pathname;
request.query = urlParse.query;

let foundEndpoint = this.app.endpoints.find((endpoint) => {
if (Array.isArray(endpoint.request)) {
if (endpoint.request.find((endpointRequest) => {
return this.isRequestMatch(endpoint, endpointRequest, request, params);
})) {
return true;
}
} else {
if (this.isRequestMatch(endpoint, endpoint.request, request, params)) {
return true;
}
}
});
let matchBody = true;

if (!foundEndpoint) {
return null;
if (endpointRequest.body) {
Object.keys(endpointRequest.body).forEach((key) => {
if (!request.body[key]) {
matchBody = false;
return;
}

foundEndpoint.callCount++;
foundEndpoint = JSON.parse(JSON.stringify(foundEndpoint));
foundEndpoint.params = params;
if (!(new RegExp(endpointRequest.body[key])).test(request.body[key])) {
matchBody = false;
}
});
}

return foundEndpoint;
if (!matchBody) {
return false;
}

static getEndpointBody(endpoint, endpointResponse) {
if (endpointResponse.body !== undefined) {
return endpointResponse.body;
keys.forEach((key, index) => {
endpointParams[key.name] = params[index + 1];
});

return true;
}

findEndpoint(request) {
let params = {};
const urlParse = url.parse(request.url, true);
request.path = urlParse.pathname;
request.query = urlParse.query;

let foundEndpoint = this.app.endpoints.find((endpoint) => {
if (Array.isArray(endpoint.request)) {
if (endpoint.request.find((endpointRequest) => {
return this.isRequestMatch(endpoint, endpointRequest, request, params);
})) {
return true;
}
} else {
if (this.isRequestMatch(endpoint, endpoint.request, request, params)) {
return true;
}
}
});

const imageMimeTypes = [
'image/gif',
'image/jpeg',
'image/pjpeg',
'image/x-png',
'image/png',
'image/svg+xml'
];
if (!foundEndpoint) {
return null;
}

foundEndpoint.callCount++;
foundEndpoint = JSON.parse(JSON.stringify(foundEndpoint));
foundEndpoint.params = params;

const bodyFilePath = path.resolve(endpoint.currentDirectory, endpointResponse.bodyFile);
return foundEndpoint;
}

return fs.readFileSync(bodyFilePath, imageMimeTypes.indexOf(mime.getType(bodyFilePath)) === -1 ? 'utf8' : null);
static getEndpointBody(endpoint, endpointResponse) {
if (endpointResponse.body !== undefined) {
return endpointResponse.body;
}

const imageMimeTypes = [
'image/gif',
'image/jpeg',
'image/pjpeg',
'image/x-png',
'image/png',
'image/svg+xml'
];

const bodyFilePath = path.resolve(endpoint.currentDirectory, endpointResponse.bodyFile);

return fs.readFileSync(bodyFilePath, imageMimeTypes.indexOf(mime.getType(bodyFilePath)) === -1 ? 'utf8' : null);
}
}

module.exports = HttpMockServer;
6 changes: 3 additions & 3 deletions app/package-lock.json

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

0 comments on commit 0cb2a95

Please sign in to comment.