From c38b2ce30b8077665ca08ae3ab8aed1d1896a78c Mon Sep 17 00:00:00 2001 From: Liusongsen Yang Date: Wed, 17 May 2017 11:26:13 -0400 Subject: [PATCH 1/3] updated author info and version of MSL --- msl-server-node/package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/msl-server-node/package.json b/msl-server-node/package.json index 8654185..cc121f0 100644 --- a/msl-server-node/package.json +++ b/msl-server-node/package.json @@ -19,13 +19,14 @@ "Daniel Koo ", "Bryan Robbins ", "Chien-Hung Kuo ", - "Jake Sheppard " + "Jake Sheppard ", + "Liusongsen Yang " ], "bin": {"msl" : "./bin/msl"}, "engines": { "node": "~0.10" }, - "version": "1.0.11", + "version": "1.0.2", "readmeFilename": "README.md", "license": "Apache 2.0" } From 438a750615062a5f4acb36eaae38c4e70d58c47d Mon Sep 17 00:00:00 2001 From: Liusongsen Yang Date: Wed, 17 May 2017 11:35:26 -0400 Subject: [PATCH 2/3] Added a mock method for POST request, added a middleware file for user who wants to use MSL as a module in their express server. --- msl-client-node/mockapi.js | 23 ++ msl-client-node/package.json | 7 +- msl-server-node/bin/msl | 2 +- msl-server-node/mslMiddleware.js | 480 ++++++++++++++++++++++++++++ msl-server-node/web-server.js | 521 ++++--------------------------- 5 files changed, 575 insertions(+), 458 deletions(-) create mode 100644 msl-server-node/mslMiddleware.js diff --git a/msl-client-node/mockapi.js b/msl-client-node/mockapi.js index dc1a3ec..64e72e6 100644 --- a/msl-client-node/mockapi.js +++ b/msl-client-node/mockapi.js @@ -48,6 +48,29 @@ exports.setMockRespond = function(server, port, configurations) } +/** + * Method to register mock POST response. Once you register, whenever server receives a request matching + * the registered requestPath, it will respond with a fake response + * + * @param server => url of web-server.js running on node + * @param port => port number of web-server.js running on node + * @param configurations => Json object that contains the requestPath, requestJSONBody, contentType, responseText, delayTime, headers, function. + **/ +exports.setMockPOSTRespond = function(server, port, configurations) +{ + var xmlHttp = null; + xmlHttp = new XMLHttpRequest(); + if(configurations['eval'] !== undefined && typeof configurations['eval'] === 'function') + { + configurations['eval'] = configurations['eval'].toString(); + } + + xmlHttp.open( 'POST', 'http://' + server + ':' + port + '/mock/fakePOSTrespond', true ); + xmlHttp.setRequestHeader('Content-Type', 'application/json'); + xmlHttp.send(JSON.stringify(configurations)); +}; + + /** * Method to register a template to be used when mocking responses. Once registered, pass the same id * used to register the template along with a map containing the key-value pairs that are to be replaced. diff --git a/msl-client-node/package.json b/msl-client-node/package.json index c0c5b86..c225b0d 100644 --- a/msl-client-node/package.json +++ b/msl-client-node/package.json @@ -10,20 +10,21 @@ "xhr2":"0.0.7" }, "devDependencies": { - "msl-server": "~1.0.11" + "msl-server": "~1.0.2" }, "author": [ "Daniel Koo ", "Bryan Robbins ", "Chien-Hung Kuo ", - "Jake Sheppard " + "Jake Sheppard ", + "Liusongsen Yang " ], "main": "mockapi.js", "bin": {}, "engines": { "node": "~0.10" }, - "version": "1.0.5", + "version": "1.0.6", "readmeFilename": "README.md", "license": "Apache 2.0" } diff --git a/msl-server-node/bin/msl b/msl-server-node/bin/msl index 8dc5823..b33f6a4 100644 --- a/msl-server-node/bin/msl +++ b/msl-server-node/bin/msl @@ -1,3 +1,3 @@ #!/usr/bin/env node -require('../web-server'); \ No newline at end of file +require('../web-server')(); \ No newline at end of file diff --git a/msl-server-node/mslMiddleware.js b/msl-server-node/mslMiddleware.js new file mode 100644 index 0000000..2777b5d --- /dev/null +++ b/msl-server-node/mslMiddleware.js @@ -0,0 +1,480 @@ +/** + * Created by k25450 on 1/17/2017. + */ +var md5 = require('md5'); +var path = require('path'); +var util = require('util'); +var mustache = require('mustache'); +var minimist = require('minimist'); +var bodyParser = require('body-parser'); +var multer = require('multer'); +var fs = require('fs'); + + +module.exports = function (argv, callback) { + var filePath = 'test/mock/'; + var ignoredParams = ''; + var debug = argv.debug || true; + var localAppDir = argv.localAppDir || __dirname; + var extensions = argv.extensions || null; + var record = function (message, severity) { + if (debug) { + util.puts(message); + } else if (severity > 0 && !debug) { + util.puts(message); + } + }; + + if ((extensions != '' || extensions != null) && ( localAppDir != '' && localAppDir != null)) extensions = require(path.join(localAppDir, extensions)); + + var localAppMockAPI = function (req, res, next) { + debugger; + if (req.path == '/mock/fakerespond') { + + if (req.body.id == undefined || req.body.responseText == undefined) { + registerMock(req.body); + record("Mock body registered for: " + req.body.requestPath, 0); + res.writeHead(200, { + 'Content-Type': 'application/json' + }); + res.write('{"status":"success","message":"mock body registered"}'); + return res.end(); + } else { + record("Provided both template ID and response text", 1); + res.writeHead(500, { + 'Content-Type': 'application/json' + }); + res.write('{"status":"failed","message":"Provided both template ID and response text"}'); + return res.end(); + } + + } else if (req.path == '/mock/fakePOSTrespond') { + if (req.body.id == undefined || req.body.responseText == undefined) { + registerMock(req.body); + record("Mock body and Unique ID for POST request registered for: " + req.body.requestPath, 0); + res.writeHead(200, { + 'Content-Type': 'application/json' + }); + res.write('{"status":"success","message":"mock body registered"}'); + return res.end(); + } else { + record("Provided both template ID and response text", 1); + res.writeHead(500, { + 'Content-Type': 'application/json' + }); + res.write('{"status":"failed","message":"Provided both template ID and response text"}'); + return res.end(); + } + + + } else if (req.path == '/mock/interceptxhr') { + + registerInterceptXHR(req.body); + record("Intercept registered for: " + req.body.requestPath, 0); + res.writeHead(200, { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*' + }); + res.write('{"status":"success","message":"intercept XHR registered"}'); + + return res.end(); + + } else if (req.path == '/mock/getinterceptedxhr') { + + res.writeHead(200, { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*' + }); + + res.write(JSON.stringify(getInterceptedXHR(req.body))); + delete interceptXHRMap[req.body.requestPath]; + + record("Sent intercepted XHR for: " + req.body.requestPath, 0); + return res.end(); + + } else if (req.path == '/setIgnoreFlag') { + + setIgnore(req.body.requestPath) + record("Set ignored flag for: " + req.body.requestPath, 0); + + return res.end(); + } else if (req.path == '/unregisterMock') { + + unregisterMock(req.body.requestPath); + record("Unregisters path for: " + req.body.requestPath, 0); + + return res.end(); + } else if (req.path == '/mock/template') { + + record("Registered template for: " + req.body.id, 0); + + registerTemplate(req.body); + res.writeHead(200, { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*' + }); + res.write('{"status":"success","message":"template registered"}'); + + return res.end(); + + } else if (isFakeRespond(req)) { + var post; + if (req.method === 'POST') { + var body = {}; + req.on('data', function (data) { + body += data; + }); + req.on('end', function () { + post = body; + }); + } + if (req.method === 'POST') { + var mockReqRespMapKey = req._parsedUrl.pathname + md5(JSON.stringify(req.body)); + var responseObj = mockReqRespMap[mockReqRespMapKey]; + if (responseObj == undefined) { + mockReqRespMapKey = req.url + md5(JSON.stringify(req.body)); + if (mockReqRespMapKey.indexOf("?") >= 0) + mockReqRespMapKey = reparsePath(mockReqRespMapKey); + responseObj = mockReqRespMap[req.url + md5(JSON.stringify(req.body))]; + } + } else { + mockReqRespMapKey = req._parsedUrl.pathname; + responseObj = mockReqRespMap[mockReqRespMapKey]; + if (responseObj == undefined) { + mockReqRespMapKey = req.url; + if (mockReqRespMapKey.indexOf("?") >= 0) + mockReqRespMapKey = reparsePath(mockReqRespMapKey); + responseObj = mockReqRespMap[req.url]; + } + } + + if (responseObj["id"] !== undefined) { + var template = templateMap[responseObj["id"]]; + if (template == undefined) { + res.writeHead(500, { + 'Content-Type': 'application/json' + }); + res.write('{"status":"failed","message":"There is no template for the provided ID"}'); + return res.end(); + } + var pairs = responseObj["keyValues"]; + if (typeof pairs === 'string') { + pairs = JSON.parse(pairs); + } + var output = mustache.render(template, pairs); + res.writeHead(responseObj["statusCode"], { + 'Content-Type': responseObj["contentType"], + 'Access-Control-Allow-Origin': '*' + }); + + if (responseObj["eval"] !== undefined) { + var f = eval("(" + responseObj["eval"] + ")"); + res.write(f(req, output), post); + } else { + res.write(output); + } + + record("Responded with mock for: " + mockReqRespMapKey, 0); + + } else { + res.writeHead(responseObj["statusCode"], responseObj["header"]); + var responseText = ""; + if (responseObj["responseFile"] !== undefined) { + responseText = fs.readFileSync(responseObj["responseFile"]); + + } else { + responseText = responseObj["responseText"]; + } + + if (responseObj["delayTime"] > 0) + sleep(responseObj["delayTime"]); + if (responseObj["eval"] !== undefined) { + var f = eval("(" + responseObj["eval"] + ")"); + res.write(f(req, responseText), post); + } else { + res.write(responseText); + } + + record("Responded with mock for: " + mockReqRespMapKey, 0); + } + return res.end(); + } else if (isInterceptXHR(req)) { + if (req.method === 'POST') { + addInterceptedXHR(req, req.body); + } else { + addInterceptedXHR(req, null); + } + + res.writeHead(200, { + 'Content-Type': 'application/json', + 'Access-Control-Allow-Origin': '*' + }); + res.write('{"status":"success","message":"XHR intercepted"}'); + + record("Intercepted XHR for: " + req.url, 0); + return res.end(); + } else { + if (extensions) { + var options = { + req: req, + res: res, + fs: fs, + localAppDir: localAppDir, + filePath: filePath + }; + extensions.customUrlParsing(options); + + } else { + //looks like it is not needed anymore + //localApp.use(express.static(localAppDir + filePath)); + return next(); + + } + } + }; + + /** + * Used to register mocks for mock API calls + */ + var mockReqRespMap = {}; + + /** + * Used to for XHR interceptions + */ + var interceptXHRMap = {}; + + + /** + * Used for responding with a completed template + */ + var templateMap = {}; + + + /** + * Un-register the mock in the mockReqRespMap + * + * @param mapKey => URL that will be deleted from the memory, if empty will wipe out all the registered mock response. + */ + function unregisterMock(mapKey) { + if (mapKey !== "") { + delete mockReqRespMap[mapKey]; + } + else { + mockReqRespMap = {}; + } + + } + + /** + * Registers the mock into mockReqRespMap + * + * @param post => contains the fake response body + */ + function registerMock(post) { + + var responseObj = {}; + responseObj["statusCode"] = parseInt(post.statusCode) || 200; + responseObj["header"] = post.header || { + 'Content-Type': post.contentType || 'application/json', + 'Access-Control-Allow-Origin': '*' + }; + responseObj["contentType"] = post.contentType || "application/json"; + if (typeof post.responseText == 'object') { + + responseObj["responseText"] = JSON.stringify(post.responseText); + + } else { + responseObj["responseText"] = post.responseText || "This is a fake response"; + } + + + responseObj["responseFile"] = post.responseFile; + + responseObj["id"] = post.id; + responseObj["keyValues"] = post.keyValues || {}; + responseObj["eval"] = post.eval; + responseObj["delayTime"] = parseInt(post.delayTime) || 0; + + var requestPath = post.requestPath; + if (post.requestJSONBody == '' || post.requestJSONBody == null) { + + mockReqRespMap[requestPath] = responseObj; + } else { + responseObj["requestJSONBody"] = post.requestJSONBody; + var uniqueID = md5(JSON.stringify(post.requestJSONBody)); + mockReqRespMap[requestPath + uniqueID] = responseObj; + } + } + + + /** + * Registers the mock into mockReqRespMap + * + * @param req => + * contains the mock api call (request query string contains request + * path, fake status code, fake content type) + * @param post => + * contains the fake response + */ + function registerTemplate(post) { + templateMap[post.id] = post.template; + record("Registered template: " + post.template, 0); + + } + + + /** + * Registers the interception XHRs into interceptXHRMap + * + * @param req => contains the mock api call (request query string contains request path) + */ + function registerInterceptXHR(body) { + var interceptedXHRs = []; + var requestPath = body.requestPath; + interceptXHRMap[requestPath] = interceptedXHRs; + } + + + /** + * Saves intercepted XHR (url, method, body only) into interceptXHRMap + * + * @param req => XHR + * @param post => post body of the request (if any) + */ + function addInterceptedXHR(req, post) { + var xhrObj = {}; + var lightXHR = {}; + lightXHR["url"] = req.url; + lightXHR["method"] = req.method; + xhrObj["xhr"] = lightXHR; + xhrObj["post"] = post; + + if (interceptXHRMap[req.url] != undefined) { + interceptXHRMap[req.url].push(xhrObj); + } else { + interceptXHRMap[req._parsedUrl.pathname].push(xhrObj); + } + } + + /** + * Returns the intercepted XHRs + * + * @param req => XHR containing request path to look up (request query string contains request path) + * @return returns object containing list of XHRs with key xhr_# + */ + function getInterceptedXHR(req) { + var requestPath = req.requestPath; + var interceptedXHRs = interceptXHRMap[requestPath]; + + var interceptedXHRsObj = {}; + var counter = 1; + if (interceptedXHRs != undefined) { + for (var i = 0; i < interceptedXHRs.length; i++) { + interceptedXHRsObj["xhr_" + counter] = interceptedXHRs[i]; + counter++; + } + } + + return interceptedXHRsObj; + } + + /** + * Determines whether the request made by the path requires mock response by + * checking mockReqRespMap. + * + * @param req => XHR + * @return true/false + */ + function isFakeRespond(req) { + var temp = req.url.toString(); + var uniqueID = md5(JSON.stringify(req.body)); + if (temp.indexOf("?") >= 0) + req.url = reparsePath(temp); + if (((req.url in mockReqRespMap) && (mockReqRespMap[req.url] !== undefined)) || + ((req._parsedUrl.pathname in mockReqRespMap) && (mockReqRespMap[req._parsedUrl.pathname] !== undefined)) || + (((req.url + uniqueID) in mockReqRespMap) && (mockReqRespMap[req.url + uniqueID] !== undefined))) { + return true; + } else { + return false; + } + } + + /** + * Determines whether the request made by the path requires interception. + * + * @param req => XHR + * @return true/false + */ + function isInterceptXHR(req) { + if (((req.url in interceptXHRMap) && (interceptXHRMap[req.url] !== undefined)) || + ((req._parsedUrl.pathname in interceptXHRMap) && (interceptXHRMap[req._parsedUrl.pathname] !== undefined))) { + return true; + } else { + return false; + } + } + + /** + * set up the root for the mock response using file system. + * comment out by KCH due to not fully functional, will be implemented for next release. + * @param mockPath => root of the mock files. + * + */ +// function setMockFilePathFunc(mockPath) { +// filePath = mockPath; +// } + + /** + * set up the parameter that should be ignored when retrieving mock responses, for example, a random generated cache buster. + * @param params => parameters in the url that needs to be ignored. + * + */ + function setIgnore(params) { + ignoredParams += params; + } + + /** + * set up delay time of a certain response. Not exposed to the client. + * @param time => time to be delayed, represented in millisecond. + * + */ + function sleep(time) { + var stop = new Date().getTime(); + while (new Date().getTime() < stop + parseInt(time)) { + + } + } + + /** + * Supporting function to parse the the URL to ignore the parameters that user don't need. Not exposed to the client. + * + */ + function reparsePath(oldpath) { + if (oldpath.indexOf("?") >= 0) { + var vars = oldpath.split("?")[1].split("&"); + var result = oldpath.split("?")[0] + '?'; + var firstFlag = 0; + for (var i = 0; i < vars.length; i++) { + var pair = vars[i].split("="); + if (ignoredParams.search(pair[0]) < 0) { + if (firstFlag === 0) { + result = result + pair[0] + '=' + pair[1]; + firstFlag = 1; + } + else { + result = result + '&' + pair[0] + '=' + pair[1]; + } + } + } + return result; + } + else { + return oldpath; + } + } + record(["MSL launched from here: ", localAppDir].join(" "), 1); + record(["Process ID: ", process.pid].join(" "), 1); + record(["Debug Mode: ", debug].join(" "), 1); + + return localAppMockAPI; +}; \ No newline at end of file diff --git a/msl-server-node/web-server.js b/msl-server-node/web-server.js index 4b8eff7..ed58104 100644 --- a/msl-server-node/web-server.js +++ b/msl-server-node/web-server.js @@ -25,462 +25,75 @@ var multer = require('multer'); var fs = require('fs'); var path = require('path'); var util = require('util'); -console.log(process.argv.toString()); -var conf = {}; -if (process.argv.slice(2).toString().search('conf.js')>0) - conf = require(path.join(process.cwd(),process.argv.slice(2)[0].toString())); - -var localApp = express(); -var DEFAULT_PORT = 8000; -var filePath = 'test/mock/'; -var ignoredParams = ''; -var debug= false; -var argv1 = minimist(process.argv.slice(2)); -var localAppDir = conf.basedir||argv1.basedir||process.cwd(); -var getextensions = conf.extensions||argv1.extensions||''; -var extensions = {}; -if (getextensions != '') - extensions = require(path.join(localAppDir,getextensions)); -else - extensions = null; - -var main = function(argv) { - var port = conf.port||Number(argv1.port) || DEFAULT_PORT; - debug = (conf.debug||argv1.debug === 'true'); - localApp.listen(port); - record(["MSL launched from here: ", localAppDir]. - join(" "),1); - record(["MSL start on port:", port].join(" "),1); - record(["Process ID: ", process.pid].join(" "),1); - record(["Debug Mode: ", debug].join(" "),1); -}; - - -var record=function(message, severity){ - if(debug){ - util.puts(message); - }else if(severity>0 && !debug){ - util.puts(message); - } -}; - - -var localAppMockAPI = function(req, res, next) { - - if (req.path == '/mock/fakerespond') { - - if (req.body.id == undefined || req.body.responseText == undefined) { - registerMock(req.body); - record("Mock body registered for: " + req.body.requestPath, 0); - res.writeHead(200, { - 'Content-Type' : 'application/json' - }); - res.write('{"status":"success","message":"mock body registered"}'); - return res.end(); - } else { - record("Provided both template ID and response text", 1); - res.writeHead(500, { - 'Content-Type' : 'application/json' - }); - res.write('{"status":"failed","message":"Provided both template ID and response text"}'); - return res.end(); - } - - } else if (req.path == '/mock/interceptxhr') { - - registerInterceptXHR(req.body); - record("Intercept registered for: " + req.body.requestPath, 0); - res.writeHead(200, { - 'Content-Type' : 'application/json', - 'Access-Control-Allow-Origin' : '*' - }); - res.write('{"status":"success","message":"intercept XHR registered"}'); - - return res.end(); - - } else if (req.path == '/mock/getinterceptedxhr') { - - res.writeHead(200, { - 'Content-Type' : 'application/json', - 'Access-Control-Allow-Origin' : '*' - }); - - res.write(JSON.stringify(getInterceptedXHR(req.body))); - delete interceptXHRMap[req.body.requestPath]; - - record("Sent intercepted XHR for: " + req.body.requestPath, 0); - return res.end(); - - } else if (req.path == '/setIgnoreFlag') { - - setIgnore(req.body.requestPath) - record("Set ignored flag for: " + req.body.requestPath, 0); - - return res.end(); - } else if (req.path == '/unregisterMock') { - - unregisterMock(req.body.requestPath); - record("Unregisters path for: " + req.body.requestPath, 0); - - return res.end(); - } else if (req.path == '/mock/template') { - - record("Registered template for: " + req.body.id, 0); - - registerTemplate(req.body); - res.writeHead(200, { - 'Content-Type' : 'application/json', - 'Access-Control-Allow-Origin' : '*' - }); - res.write('{"status":"success","message":"template registered"}'); - - return res.end(); - - } else if (isFakeRespond(req)) { - var post; - if (req.method === 'POST') { - var body = {}; - req.on('data', function (data) { - body += data; - }); - req.on('end', function () { - post = body; - }); - } - - var mockReqRespMapKey = req._parsedUrl.pathname - var responseObj = mockReqRespMap[mockReqRespMapKey]; - if (responseObj == undefined) { - mockReqRespMapKey = req.url; - if (mockReqRespMapKey.indexOf("?") >= 0) - mockReqRespMapKey = reparsePath(mockReqRespMapKey); - responseObj = mockReqRespMap[req.url]; - } - - if (responseObj["id"] !== undefined) { - var template = templateMap[responseObj["id"]]; - if (template == undefined) { - res.writeHead(500, { - 'Content-Type' : 'application/json' - }); - res.write('{"status":"failed","message":"There is no template for the provided ID"}'); - return res.end(); - } - var pairs = responseObj["keyValues"]; - if (typeof pairs === 'string') { - pairs = JSON.parse(pairs); - } - var output = mustache.render(template, pairs); - res.writeHead(responseObj["statusCode"], { - 'Content-Type' : responseObj["contentType"], - 'Access-Control-Allow-Origin' : '*' - }); - - if (responseObj["eval"] !== undefined) { - var f = eval("(" + responseObj["eval"] + ")"); - res.write(f(req, output), post); - } else { - res.write(output); - } - - record("Responded with mock for: " + mockReqRespMapKey, 0); - - } else { - res.writeHead(responseObj["statusCode"], responseObj["header"]); - var responseText=""; - if(responseObj["responseFile"] !== undefined){ - responseText = fs.readFileSync(responseObj["responseFile"]); - - }else - { - responseText= responseObj["responseText"]; - } - - if (responseObj["delayTime"] > 0) - sleep(responseObj["delayTime"]); - if (responseObj["eval"] !== undefined) { - var f = eval("(" + responseObj["eval"] + ")"); - res.write(f(req, responseText), post); - } else { - res.write(responseText); - } - - record("Responded with mock for: " + mockReqRespMapKey, 0); - } - return res.end(); - } else if (isInterceptXHR(req)) { - if (req.method === 'POST') { - addInterceptedXHR(req, req.body); - } else { - addInterceptedXHR(req, null); - } - - res.writeHead(200, { - 'Content-Type' : 'application/json', - 'Access-Control-Allow-Origin' : '*' - }); - res.write('{"status":"success","message":"XHR intercepted"}'); - - record("Intercepted XHR for: " + req.url, 0); - return res.end(); - } else { - if(extensions){ - var options = { - req: req, - res: res, - fs: fs, - localAppDir: localAppDir, - filePath: filePath - }; - extensions.customUrlParsing(options); - - } else { - localApp.use(express.static(localAppDir+filePath)); - return next(); - - } - } -}; - -/** - * Used to register mocks for mock API calls - */ -var mockReqRespMap = {}; - -/** - * Used to for XHR interceptions - */ -var interceptXHRMap = {}; - - -/** - * Used for responding with a completed template - */ -var templateMap = {}; - - - -/** - * Un-register the mock in the mockReqRespMap - * - * @param mapKey => URL that will be deleted from the memory, if empty will wipe out all the registered mock response. - */ -function unregisterMock(mapKey) { - if (mapKey !== "") { - delete mockReqRespMap[mapKey]; - } - else { - mockReqRespMap = {}; - } - -} - -/** - * Registers the mock into mockReqRespMap - * - * @param post => contains the fake response body - */ -function registerMock(post) { - - var responseObj = {}; - responseObj["statusCode"] = parseInt(post.statusCode) || 200; - responseObj["header"] = post.header || { - 'Content-Type' : post.contentType || 'application/json', - 'Access-Control-Allow-Origin' : '*' - }; - responseObj["contentType"] = post.contentType || "application/json"; - if (typeof post.responseText == 'object') { - - responseObj["responseText"] = JSON.stringify(post.responseText); - - } else { - responseObj["responseText"] = post.responseText || "This is a fake response"; - } - - - responseObj["responseFile"] = post.responseFile; - - responseObj["id"] = post.id; - responseObj["keyValues"] = post.keyValues || {}; - responseObj["eval"] = post.eval; - responseObj["delayTime"] = parseInt(post.delayTime) || 0; - - var requestPath = post.requestPath; - mockReqRespMap[requestPath] = responseObj; -} - - - -/** - * Registers the mock into mockReqRespMap - * - * @param req => - * contains the mock api call (request query string contains request - * path, fake status code, fake content type) - * @param post => - * contains the fake response - */ -function registerTemplate(post) { - templateMap[post.id] = post.template; - record("Registered template: " + post.template,0); - -} - - - -/** - * Registers the interception XHRs into interceptXHRMap - * - * @param req => contains the mock api call (request query string contains request path) - */ -function registerInterceptXHR(body) { - var interceptedXHRs = []; - var requestPath = body.requestPath; - interceptXHRMap[requestPath] = interceptedXHRs; -} - - -/** - * Saves intercepted XHR (url, method, body only) into interceptXHRMap - * - * @param req => XHR - * @param post => post body of the request (if any) - */ -function addInterceptedXHR(req, post) { - var xhrObj = {}; - var lightXHR = {}; - lightXHR["url"] = req.url; - lightXHR["method"] = req.method; - xhrObj["xhr"] = lightXHR; - xhrObj["post"] = post; - - if(interceptXHRMap[req.url] != undefined) { - interceptXHRMap[req.url].push(xhrObj); - }else { - interceptXHRMap[req._parsedUrl.pathname].push(xhrObj); - } -} - -/** - * Returns the intercepted XHRs - * - * @param req => XHR containing request path to look up (request query string contains request path) - * @return returns object containing list of XHRs with key xhr_# - */ -function getInterceptedXHR(req) { - var requestPath = req.requestPath; - var interceptedXHRs = interceptXHRMap[requestPath]; - - var interceptedXHRsObj = {}; - var counter = 1; - if(interceptedXHRs != undefined) { - for (var i = 0; i < interceptedXHRs.length; i++) { - interceptedXHRsObj["xhr_" + counter] = interceptedXHRs[i]; - counter++; +var md5 = require('md5'); +var mslMiddleware = require('./mslMiddleware.js'); +var mslRouter = express.Router(); + +exports = module.exports = function (argv, callback) { + var localApp; + var DEFAULT_PORT; + var filePath = 'test/mock/'; + var ignoredParams = ''; + var debug = true; + var argv1; + var localAppDir; + var getextensions; + var port; + + var record = function (message, severity) { + if (debug) { + util.puts(message); + } else if (severity > 0 && !debug) { + util.puts(message); } + }; + console.log('the process argv are' + process.argv[0] + '\n' + process.argv[1] + '\n' + process.argv[2]); + var conf = {}; + + if (process.argv.slice(2).toString().search('conf.js') > 0) + conf = require(path.join(process.cwd(), process.argv.slice(2)[0].toString())); + + localApp = express(); + DEFAULT_PORT = 8000; + argv1 = minimist(process.argv.slice(2)) || ''; + if (argv != null) { + argv1 = argv; } + localAppDir = conf.basedir || argv1.basedir || process.cwd() || ''; + + //get extension files + getextensions = conf.extensions || argv1.extensions || ''; + + console.log(getextensions); + port = conf.port || Number(argv1.port) || DEFAULT_PORT; + debug = (conf.debug || argv1.debug === 'true'); + + var options = { + localApp: localApp, + DEFAULT_PORT: DEFAULT_PORT, + filePath: filePath, + ignoredParams: ignoredParams, + debug: debug, + argv1: argv1, + localAppDir: localAppDir, + extensions: getextensions, + port: port + }; + + var localAppMockAPI = mslMiddleware(options); + mslRouter.use(localAppMockAPI); + + console.log('MSL is launched as an independent server'); + localApp.use(express.static(localAppDir)); + localApp.use(bodyParser.json()); // for parsing application/json + localApp.use(bodyParser.urlencoded({extended: true})); // for parsing application/x-www-form-urlencoded + localApp.use(multer()); // for parsing multipart/form-data + localApp.use(mslRouter); + localApp.listen(port); - return interceptedXHRsObj; -} - -/** - * Determines whether the request made by the path requires mock response by - * checking mockReqRespMap. - * - * @param req => XHR - * @return true/false - */ -function isFakeRespond(req) { - var temp = req.url.toString(); - if (temp.indexOf("?")>=0) - req.url = reparsePath(temp); - if( ((req.url in mockReqRespMap) && (mockReqRespMap[req.url] !== undefined)) || - ((req._parsedUrl.pathname in mockReqRespMap) && (mockReqRespMap[req._parsedUrl.pathname] !== undefined)) ) { - return true; - }else { - return false; - } -} - -/** - * Determines whether the request made by the path requires interception. - * - * @param req => XHR - * @return true/false - */ -function isInterceptXHR(req) { - if( ((req.url in interceptXHRMap) && (interceptXHRMap[req.url] !== undefined)) || - ((req._parsedUrl.pathname in interceptXHRMap) && (interceptXHRMap[req._parsedUrl.pathname] !== undefined)) ) { - return true; - }else { - return false; - } -} - -/** - * set up the root for the mock response using file system. - * comment out by KCH due to not fully functional, will be implemented for next release. - * @param mockPath => root of the mock files. - * - */ -// function setMockFilePathFunc(mockPath) { -// filePath = mockPath; -// } - -/** - * set up the parameter that should be ignored when retrieving mock responses, for example, a random generated cache buster. - * @param params => parameters in the url that needs to be ignored. - * - */ -function setIgnore(params) { - ignoredParams += params; -} - -/** - * set up delay time of a certain response. Not exposed to the client. - * @param time => time to be delayed, represented in millisecond. - * - */ -function sleep(time) { - var stop = new Date().getTime(); - while(new Date().getTime() < stop + parseInt(time)) { - ; - } -} - -/** - * Supporting function to parse the the URL to ignore the parameters that user don't need. Not exposed to the client. - * - */ -function reparsePath(oldpath) { - if (oldpath.indexOf("?")>=0) { - var vars = oldpath.split("?")[1].split("&"); - var result = oldpath.split("?")[0]+'?'; - var firstFlag = 0; - for (var i=0;i