From 3652c5cebf444404f94c086d10a3525199aa98b8 Mon Sep 17 00:00:00 2001 From: Matt Broadstone Date: Fri, 24 Jul 2015 13:53:18 -0400 Subject: [PATCH] feat(MockServer): add refactored MockServer Currently only supports response sequences, and is otherwise a general refactoring of the existing mock_amqp.js MockServer with the addition of promisifying the setup/teardown methods --- test/unit/client.test.js | 59 +++++++++++++++++++ test/unit/mocks/index.js | 1 + test/unit/mocks/server.js | 119 ++++++++++++++++++++++++++++++++++++++ test/unit/test-fixture.js | 12 ++++ 4 files changed, 191 insertions(+) create mode 100644 test/unit/client.test.js create mode 100644 test/unit/mocks/server.js create mode 100644 test/unit/test-fixture.js diff --git a/test/unit/client.test.js b/test/unit/client.test.js new file mode 100644 index 0000000..8adc12f --- /dev/null +++ b/test/unit/client.test.js @@ -0,0 +1,59 @@ +'use strict'; + +var AMQPClient = require('../../lib').Client, + MockServer = require('./mocks').Server, + + constants = require('../../lib/constants'), + + SaslFrames = require('../../lib/frames/sasl_frame'), + OpenFrame = require('../../lib/frames/open_frame'), + CloseFrame = require('../../lib/frames/close_frame'), + + DefaultPolicy = require('../../lib/policies/default_policy'), + AMQPError = require('../../lib/types/amqp_error'), + + expect = require('chai').expect, + test = require('./test-fixture'); + +DefaultPolicy.connect.options.containerId = 'test'; + + +describe('Client', function() { + describe('#connect()', function() { + + beforeEach(function() { + if (!!test.server) test.server = undefined; + if (!!test.client) test.client = undefined; + test.client = new AMQPClient(); + test.server = new MockServer(); + return test.server.setup(); + }); + + afterEach(function() { + if (!test.server) return; + return test.server.teardown() + .then(function() { + test.server = undefined; + }); + }); + + it('should connect then disconnect', function() { + test.server.setResponseSequence([ + constants.saslVersion, + [ + new SaslFrames.SaslMechanisms(['PLAIN']), + new SaslFrames.SaslOutcome({code: constants.saslOutcomes.ok}) + ], + constants.amqpVersion, + new OpenFrame(DefaultPolicy.connect.options), + new CloseFrame(new AMQPError(AMQPError.ConnectionForced, 'test')) + ]); + + return test.client.connect(test.config.address) + .then(function() { + return test.client.disconnect(); + }); + }); + + }); +}); diff --git a/test/unit/mocks/index.js b/test/unit/mocks/index.js index 63e076d..31cccd9 100644 --- a/test/unit/mocks/index.js +++ b/test/unit/mocks/index.js @@ -2,6 +2,7 @@ module.exports = { Client: require('./client'), + Server: require('./server'), Connection: require('./connection'), Session: require('./session'), SenderLink: require('./sender_link'), diff --git a/test/unit/mocks/server.js b/test/unit/mocks/server.js new file mode 100644 index 0000000..a8b5aef --- /dev/null +++ b/test/unit/mocks/server.js @@ -0,0 +1,119 @@ +'use strict'; +var _ = require('lodash'), + Promise = require('bluebird'), + BufferList = require('bl'), + net = require('net'), + + debug = require('debug')('amqp10:mock:server'), + + FrameBase = require('../../../lib/frames/frame'), + SaslFrame = require('../../../lib/frames/sasl_frame').SaslFrame, + + tu = require('../testing_utils'); + + +function MockServer(options) { + this._server = null; + this._client = null; + this._responses = []; + + _.defaults(this, options, { + port: 4321, + serverGoesFirst: false + }); +} + +MockServer.prototype.setup = function() { + var self = this; + return new Promise(function(resolve, reject) { + self.server = net.createServer(function(c) { + debug('connection established'); + self._client = c; + + if (self.serverGoesFirst) { + self._sendNextResponse(); + } + + c.on('end', function() { + debug('connection terminated'); + self._client = undefined; + }); + + c.on('data', function(d) { + self._sendNextResponse(); + }); + }); + + self.server.on('error', function(err) { + reject(err); + }); + + self.server.listen(self.port, function() { + debug('server listening on ' + self.port); + resolve(); + }); + }); +}; + +MockServer.prototype.teardown = function() { + var self = this; + return new Promise(function(resolve, reject) { + if (!self._server) resolve(); + + self.server.close(function(err) { + if (!!err) return reject(err); + + debug('server shutting down'); + self.server = undefined; + resolve(); + }); + }); +}; + +function convertSequenceFramesToBuffers(frame) { + if (frame instanceof FrameBase.AMQPFrame || + frame instanceof SaslFrame) { + return tu.convertFrameToBuffer(frame); + } else if (Array.isArray(frame)) { + return [frame[0], convertSequenceFramesToBuffers(frame[1])]; + } + + return frame; +} + +MockServer.prototype.setResponseSequence = function(responses) { + this._responses = responses.map(convertSequenceFramesToBuffers); +}; + +MockServer.prototype._sendNextResponse = function() { + var self = this, + response = this._responses.unshift(); + + if (Array.isArray(response)) { + response.forEach(function(r) { self._sendResponse(r); }); + } else { + self._sendResponse(response); + } +}; + +MockServer.prototype._sendResponse = function(response) { + if (!response) { + debug('no data to send'); + return; + } + + if (typeof response !== 'string') { + this._client.write(response); + return; + } + + switch(response) { + case 'disconnect': this._client.end(); break; + default: + this._client.write(response, 'utf8', function() { + debug('wrote: ' + response); + }); + } +}; + +module.exports = MockServer; diff --git a/test/unit/test-fixture.js b/test/unit/test-fixture.js new file mode 100644 index 0000000..308b7ea --- /dev/null +++ b/test/unit/test-fixture.js @@ -0,0 +1,12 @@ +'use strict'; +var chai = require('chai'); +chai.config.includeStack = true; // turn on stack traces + +var config = { + address: (process.env.SERVER ? 'amqp://'+process.env.SERVER : 'amqp://localhost'), + defaultLink: 'amq.topic' +}; + +module.exports = { + config: config +};