UNPKG

mountebank-test

Version:

Over the wire test doubles

153 lines (135 loc) 5.59 kB
'use strict'; var net = require('net'), Q = require('q'), baseLogger = require('winston'), ScopedLogger = require('../../util/scopedLogger'), ResponseResolver = require('../responseResolver'), StubRepository = require('../stubRepository'), util = require('util'), helpers = require('../../util/helpers'), TcpProxy = require('../tcp/tcpProxy'), DryRunValidator = require('../dryRunValidator'); /** * Used to fill in defaults for the response. A user may set up a stub * with not all fields filled in, and we use this function to fill in the rest */ function postProcess (stub) { return { data: stub.data || 'foo' }; } /** * Used to get consistent logging look & feel */ function scopeFor (port, name) { var scope = util.format('foo:%s', port); if (name) { scope += ' ' + name; } return scope; } /** * Spins up a server listening on a socket * @param options - the JSON request body for the imposter create request * @param recordRequests - the --mock command line parameter */ function createServer (options, recordRequests, debug) { // This is an async operation, so we use a deferred var deferred = Q.defer(), // and an array to record all requests for mock verification requests = [], // set up a logger with the correct log prefix logger = ScopedLogger.create(baseLogger, scopeFor(options.port)), // create the protocol-specific proxy (here we're reusing tcp's proxy) proxy = TcpProxy.create(logger, 'utf8'), // create the response resolver, which contains the strategies for resolving is, proxy, and inject stubs // the postProcess parameter is used to fill in defaults for the response that were not passed by the user resolver = ResponseResolver.create(proxy, postProcess), // create the repository which matches the appropriate stub to respond with stubs = StubRepository.create(resolver, debug, 'utf8'), // and create the actual server using node.js's net module server = net.createServer(); // we need to respond to new connections server.on('connection', function (socket) { socket.on('data', function (data) { // This will be the request API interface used by stubs, etc. var request = { requestFrom: helpers.socketName(socket), data: data.toString('utf8') }; // remember the request for mock verification, unless told not to if (recordRequests) { var recordedRequest = helpers.clone(request); recordedRequest.timestamp = new Date().toJSON(); requests.push(recordedRequest); } // let's resolve any stubs (don't worry - there are defaults if no stubs are defined) return stubs.resolve(request, logger).then(function (stubResponse) { var buffer = new Buffer(stubResponse.data, 'utf8'); // This writes the response socket.write(buffer); }); }); }); // Bind the socket to a port (the || 0 bit auto-selects a port if one isn't provided) server.listen(options.port || 0, function () { // Some basic bookkeeping... var actualPort = server.address().port, metadata = {}; if (options.name) { metadata.name = options.name; } if (options.port !== actualPort) { logger.changeScope(scopeFor(actualPort)); } logger.info('Open for business...'); // This resolves the promise, allowing execution to continue after we're listening on a socket // The object we resolve with defines the core imposter API expected in imposter.js deferred.resolve({ requests: requests, addStub: stubs.addStub, stubs: stubs.stubs, metadata: metadata, port: actualPort, close: function () { server.close(); logger.info ('Ciao for now'); } }); }); return deferred.promise; } /** * Creates the core protocol interface - all protocols must implement * @param allowInjection - represents the command line --allowInjection parameter * @param recordRequests - represents the command line --mock parameter */ function initialize (allowInjection, recordRequests, debug) { return { // The name of the protocol, used in JSON representation of imposters name: 'foo', // The creation method, called in imposter.js. The request JSON object gets passed in create: function (request) { return createServer(request, recordRequests, debug); }, // The validator used when creating imposters // If you don't have any protocol-specific validation, the DryRunValidator will suffice Validator: { create: function () { return DryRunValidator.create({ StubRepository: StubRepository, // This is the request that will be 'dry run' through the validator testRequest: { requestFrom: '', data: '' }, allowInjection: allowInjection }); } } }; } module.exports = { // This will be called in mountebank.js when you register the protocol there initialize: initialize };