From ba9de995fe8d16f642d7c8f064533ae4f094d4a7 Mon Sep 17 00:00:00 2001 From: yuye Date: Thu, 9 Jun 2016 18:07:16 +0800 Subject: [PATCH 1/4] add test suite and fixes #3 --- .travis.yml | 23 +++ README.md | 2 + gulpfile.js | 66 +++++++ karma.conf.js | 113 +++++++++++ package.json | 20 +- test/client-test.js | 376 ++++++++++++++++++++++++++++++++++++ test/frame-test.js | 70 +++++++ test/support/server-mock.js | 209 ++++++++++++++++++++ test/utils-test.js | 43 +++++ test/webstomp-test.js | 22 +++ webpack.config.js | 30 +-- 11 files changed, 960 insertions(+), 14 deletions(-) create mode 100644 .travis.yml create mode 100644 gulpfile.js create mode 100644 karma.conf.js create mode 100644 test/client-test.js create mode 100644 test/frame-test.js create mode 100644 test/support/server-mock.js create mode 100644 test/utils-test.js create mode 100644 test/webstomp-test.js diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..10e5545 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,23 @@ +language: node_js +node_js: + - "6" + - "5" +branches: + only: + - master +env : + - BROWSSER=chromium_browser +addons: + firefox: 'latest' +cache: + directories: + - node_modules +before_script: + - npm install -g gulp + - export CHROME_BIN=chromium-browser + - export DISPLAY=:99.0 + - sh -e /etc/init.d/xvfb start + - sleep 3 # give xvfb some time to start +script: gulp test +after_success: + - gulp coverage \ No newline at end of file diff --git a/README.md b/README.md index 7d402d7..e0daa3a 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,6 @@ # webstomp-client +[![Build Status](https://travis-ci.org/yeyu456/webstomp-client.svg?branch=master)](https://travis-ci.org/yeyu456/webstomp-client) +[![Coverage Status](https://coveralls.io/repos/github/yeyu456/webstomp-client/badge.svg?branch=master)](https://coveralls.io/github/yeyu456/webstomp-client?branch=master) This library provides a [stomp](https://stomp.github.io/) client for Web browsers and nodejs through Web Sockets. diff --git a/gulpfile.js b/gulpfile.js new file mode 100644 index 0000000..9083591 --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,66 @@ +'use strict'; + +var gulp = require('gulp'); +var webpack = require('webpack'); +var del = require('del'); +var karma = require('karma').Server; +var spawn = require('child_process').spawn; +var coveralls = require('gulp-coveralls'); +var node; + +gulp.task('clean', function(cb) { + del.sync(['./dist/*']); + cb(); +}); + +gulp.task('testServer', ['clean'], function _testServer(cb) { + if (node) { + node.kill(); + } + webpack({ + entry: './test/support/server-mock.js', + output: { + path: __dirname + '/dist/support', + filename: 'server-mock.js' + }, + module: { + loaders: [ + { + test: /\.js$/, + loader: 'babel-loader', + exclude: /node_modules/ + } + ] + }, + target: 'node', + resolve: { + extensions: ['', '.js'] + } + }, function(err) { + if (err) { + cb(err); + + } else { + node = spawn('node', ['./dist/support/server-mock.js'], {stdio: 'inherit'}); + cb(); + } + }); +}); + +gulp.task('test', ['testServer'], function _test(cb) { + // jscs:disable requireCapitalizedConstructors + return new karma({ + configFile: __dirname + '/karma.conf.js', + singleRun: true + }, function _testCB(code) { + if (node) { + node.kill(); + } + cb(code); + }).start(); +}); + +gulp.task('coverage', function _coverage(cb) { + return gulp.src('dist/coverage/*/coverage.info') + .pipe(coveralls()); +}); diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..8c2014a --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,113 @@ +// Karma configuration +// Generated on Sat Jun 04 2016 17:41:44 GMT+0800 (中国标准时间) +var webpack = require('karma-webpack'); + +module.exports = function(config) { + config.set({ + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['mocha'], + // list of files / patterns to load in the browser + files: [ + 'node_modules/core-js/client/core.js', + 'test/utils-test.js', + 'test/frame-test.js', + 'test/webstomp-test.js', + 'test/client-test.js' + ], + plugins: [ + webpack, + 'karma-mocha', + 'karma-firefox-launcher', + 'karma-chrome-launcher', + 'karma-ie-launcher', + 'karma-coverage' + ], + // list of files to exclude + exclude: [], + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + 'test/*.js': ['webpack'], + 'src/**/*.js': ['webpack'] + }, + webpack: { + module: { + preLoaders: [ + { + test: /\.js$/, + loader: 'isparta', + exclude: /(node_modules|test)/ + } + ], + loaders: [ + { + test: /\.js$/, + loader: 'babel-loader', + exclude: /node_modules/ + } + ] + }, + resolve: { + extensions: ['', '.js'] + }, + externals: { + ws:'WebSocket' + }, + debug: true + }, + webpackMiddleware: { + noInfo: true + }, + reporters: ['progress', 'coverage'], + coverageReporter: { + dir: 'dist/coverage/', + subdir: function(browser) { + return browser.toLowerCase().split(/[ /-]/)[0]; + }, + reporters: [{ + type: 'html', + file: 'coverage.html' + }, { + type: 'lcovonly', + file: 'coverage.info' + }], + watermarks: { + statements: [60, 90], + functions: [60, 90], + branches: [60, 90], + lines: [60, 90] + } + }, + // web server port + port: 1110, + // enable / disable colors in the output (reporters and logs) + colors: true, + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['IE', 'Chrome'], + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: false, + + // Concurrency level + // how many browser should be started simultaneous + concurrency: Infinity + }); + if (process.env.TRAVIS) { + config.customLaunchers = { + Chrome: { + base: 'Chrome', + flags: ['--no-sandbox'] + } + }; + config.browsers = ['Firefox', 'Chrome']; + } +}; diff --git a/package.json b/package.json index 6f9088e..e196790 100644 --- a/package.json +++ b/package.json @@ -36,10 +36,26 @@ "jshint": "^2.9.1", "opn-cli": "^3.1.0", "webpack": "^1.12.14", - "ws": "^1.0.1" + "isparta-loader": "^2.0.0", + "ws": "^1.0.1", + "sockjs": "^0.3.17", + "sockjs-client": "^1.1.1", + "gulp": "^3.9.1", + "gulp-coveralls": "^0.1.4", + "del": "^2.2.0", + "mocha": "^2.5.3", + "chai": "^3.5.0", + "karma": "^0.13.22", + "karma-mocha": "^1.0.1", + "karma-webpack": "^1.7.0", + "karma-chrome-launcher": "^1.0.1", + "karma-ie-launcher": "^1.0.0", + "karma-firefox-launcher": "^1.0.0", + "karma-coverage": "^1.0.0", + "core-js": "^2.4.0" }, "scripts": { - "test": "echo \"TODO: add tests\"", + "test": "gulp test", "build": "webpack && webpack -p --config webpack.min.config.js", "dev": "webpack --watch", "example": "webpack && opn http://localhost:8080/example & http-server", diff --git a/test/client-test.js b/test/client-test.js new file mode 100644 index 0000000..9d6ac5e --- /dev/null +++ b/test/client-test.js @@ -0,0 +1,376 @@ +import {assert} from 'chai'; +import webstomp from './../src/webstomp'; +import SockJS from 'sockjs-client'; + +describe('[client]', () => { + + let url = 'http://127.0.0.1:1111/stomp'; + + describe('[connect]', () => { + + it('[connect fail]', (done) => { + let sockjs = new SockJS(url + '/fail'); + let client = webstomp.over(sockjs); + client.connect({}, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + + }, (evt) => { + if (evt && evt.type && evt.type === 'close') { + assert.isFalse(client.connected); + done(); + + } else { + + throw { + name: 'connectException', + message: 'connected with error frame.' + }; + } + }); + }); + + it('[connect success]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({}, (frame) => { + assert.isDefined(frame, 'command'); + assert.strictEqual(frame.command, 'CONNECTED'); + assert.isTrue(client.connected); + done(); + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + }); + + it('[disconnect]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({}, (frame) => { + assert.isTrue(client.connected); + client.disconnect(() => { + assert.isFalse(client.connected); + done(); + }); + done(); + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + }); + + it('[login]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect('username', 'password', (frame) => { + assert.isDefined(frame, 'body'); + assert.strictEqual(frame.body, 'login success'); + client.disconnect(); + done(); + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + }); + }); + + describe('[send]', () => { + it('[send and message]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({}, () => { + client.send('/send', 'test', {test: 'test'}); + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + client.onreceive = (frame) => { + assert.isDefined(frame, 'body'); + assert.strictEqual(frame.body, '0'); + done(); + }; + }); + }); + + describe('[error]', () => { + it('[error]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({'error-enable': '1'}, () => {}, (frame) => { + if (frame && frame.command === 'ERROR') { + client.disconnect(); + done(); + + } else { + throw { + name: 'connectException', + message: 'connected failed.' + }; + } + }); + }); + }); + + describe('[receipt]', () => { + it('[receipt]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({'receipt-enable': '1'}, () => {}, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + client.onreceipt = (frame) => { + done(); + } + }); + }); + + describe('[subscribe]', () => { + + let sockjs; + let client; + let sub; + + before((done)=> { + sockjs = new SockJS(url); + client = webstomp.over(sockjs); + sub = {}; + client.connect({}, () => { + done(); + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + }); + + it('[subscribe and message]', (done) => { + sub = client.subscribe('/channel', (frame) => { + assert.isDefined(sub, 'id'); + assert.isDefined(client.subscriptions[sub.id]); + assert.strictEqual(client.counter, 1); + + assert.isDefined(frame, 'body'); + assert.strictEqual(frame.body, '0'); + + done(); + }); + }); + + it('[subscribe and unsubscribe', (done) => { + assert.isDefined(sub, 'unsubscribe'); + sub.unsubscribe(); + client.onreceive = (frame) => { + assert.isDefined(frame.headers, 'id'); + assert.strictEqual(frame.headers.id, sub.id); + done(); + }; + }); + }); + + describe('[transaction]', () => { + + it('[ack]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({}, () => { + let sub = client.subscribe('/ack', (frame) => { + assert.isDefined(frame, 'ack'); + frame.ack(); + }); + client.onreceive = (frame) => { + assert.strictEqual(frame.body, 'ack success'); + sub.unsubscribe(); + client.disconnect(); + done(); + }; + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + }); + + it('[nack]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({}, () => { + let sub = client.subscribe('/nack', (frame) => { + assert.isDefined(frame, 'nack'); + frame.nack(); + }); + client.onreceive = (frame) => { + assert.strictEqual(frame.body, 'nack success'); + sub.unsubscribe(); + client.disconnect(); + done(); + }; + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + }); + + it('[begin and commit]', (done) => { + + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({}, () => { + let tran; + client.onreceive = (frame) => { + assert.strictEqual(frame.body, 'begin success'); + assert.isDefined(tran, 'id'); + assert.isDefined(tran, 'commit'); + assert.isDefined(tran, 'abort'); + tran.commit(); + + client.onreceive = (frame) => { + assert.strictEqual(frame.body, 'commit success'); + client.disconnect(); + done(); + }; + }; + tran = client.begin(); + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + }); + + it('[begin and abort]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({}, () => { + let tran; + client.onreceive = (frame) => { + assert.strictEqual(frame.body, 'begin success'); + + assert.isDefined(tran, 'id'); + assert.isDefined(tran, 'commit'); + assert.isDefined(tran, 'abort'); + tran.abort(); + + client.onreceive = (frame) => { + assert.strictEqual(frame.body, 'abort success'); + client.disconnect(); + done(); + }; + }; + tran = client.begin(); + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + + }); + + it('[begin commit and abort]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + client.connect({}, () => { + let tran; + client.onreceive = (frame) => { + assert.strictEqual(frame.body, 'begin success'); + assert.isDefined(tran, 'id'); + assert.isDefined(tran, 'commit'); + assert.isDefined(tran, 'abort'); + tran.commit(); + + client.onreceive = (frame) => { + assert.strictEqual(frame.body, 'commit success'); + tran.abort(); + + client.onreceive = (frame) => { + assert.strictEqual(frame.body, 'abort failed'); + client.disconnect(); + done(); + }; + }; + }; + tran = client.begin(); + + }, () => { + throw { + name: 'connectException', + message: 'connected failed.' + }; + }); + }); + }); + + describe('[heartbeat]', () => { + + it('[heartbeat disconnect]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs, {heartbeat: {outgoing: 10, incoming: 10}}); + client.connect({'heartbeat-enable': '1'}, (frame) => { + assert.isDefined(frame.headers, 'heart-beat'); + + }, (evt) => { + if (evt && evt.type && evt.type === 'close') { + assert.isFalse(client.connected); + done(); + + } else { + throw { + name: 'connectException', + message: 'connected with error frame.' + }; + } + }); + }); + }); + + describe('[largeFrame]', () => { + + it('[largeFrame]', (done) => { + let sockjs = new SockJS(url); + let client = webstomp.over(sockjs); + let content = '1234567890'; + client.connect({}, () => { + client.maxWebSocketFrameSize = 50; + client.send('/largeFrame', content, {}); + + }, () => { + throw { + name: 'connectException', + message: 'connected with error frame.' + }; + }); + client.onreceive = (frame) => { + assert.notStrictEqual(frame.body, content); + done(); + } + }); + }); +}); diff --git a/test/frame-test.js b/test/frame-test.js new file mode 100644 index 0000000..cf68e51 --- /dev/null +++ b/test/frame-test.js @@ -0,0 +1,70 @@ +import {assert} from 'chai'; +import {VERSIONS, BYTES} from './../src/utils'; +import Frame from './../src/frame'; + +describe('Frame', () => { + + it('toString', () => { + let frameStr = [ + 'CONNECT', + 'accept-version:' + VERSIONS.supportedVersions(), + 'heart-beat:0,0', + BYTES.LF + ].join(BYTES.LF); + let frame = new Frame( + 'CONNECT', { + 'accept-version': VERSIONS.supportedVersions(), + 'heart-beat': '0,0' + } + ); + assert.strictEqual(frame.toString(), frameStr); + }); + + it('toStringWithBody', () => { + let frameStr = [ + 'MESSAGE', + 'content-length:4', + BYTES.LF + 'test' + ].join(BYTES.LF); + let frame = new Frame('MESSAGE', {}, 'test'); + assert.strictEqual(frame.toString(), frameStr); + }); + + it('toStringIgnoreLength', () => { + let frameStr = [ + 'MESSAGE', + BYTES.LF + 'test' + ].join(BYTES.LF); + let frame = new Frame('MESSAGE', {'content-length': false}, 'test'); + assert.strictEqual(frame.toString(), frameStr); + }); + + it('marshall and unmarshallSingle', () => { + let frame = new Frame('MESSAGE', {'content-length': '4'}, 'test'); + let data = Frame.marshall('MESSAGE', {}, 'test'); + assert.deepEqual(Frame.unmarshallSingle(data), frame); + + data = Frame.marshall('MESSAGE', {'content-length': false}, 'test'); + assert.deepEqual(Frame.unmarshallSingle(data), new Frame('MESSAGE', {}, 'test')); + }); + + it('unmarshall', () => { + let frame = new Frame('MESSAGE', {'content-length': '4'}, 'test'); + let data = Frame.marshall('MESSAGE', {}, 'test'); + let r = Frame.unmarshall(data + 'test'); + + assert.deepEqual(r.frames[0], frame); + assert.strictEqual(r.partial, 'test'); + }); + + it('unmarshall multiple', () => { + let frame = new Frame('MESSAGE', {'content-length': '4'}, 'test'); + let data = Frame.marshall('MESSAGE', {}, 'test'); + let r = Frame.unmarshall(data + data); + + assert.strictEqual(r.frames.length, 2); + assert.deepEqual(r.frames[0], frame); + assert.deepEqual(r.frames[1], frame); + assert.strictEqual(r.partial, ''); + }); +}); diff --git a/test/support/server-mock.js b/test/support/server-mock.js new file mode 100644 index 0000000..450fc14 --- /dev/null +++ b/test/support/server-mock.js @@ -0,0 +1,209 @@ +const http = require('http'); +import sockjs from 'sockjs'; +import Frame from './../../src/frame'; +import {VERSIONS} from './../../src/utils'; + +class MockServer { + + constructor(ip, port, prefix) { + this.ip = ip; + this.port = port; + this.prefix = prefix; + this.subscribes = []; + this.lastMessageId = 0; + this.lastTransactionId = ''; + } + + start() { + let srv = http.createServer((req, res) => { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('okay'); + }); + srv.on('upgrade', (req, socket, head) => { + socket.write('HTTP/1.1 101 Web Socket Protocol Handshake\r\n' + + 'Upgrade: WebSocket\r\n' + + 'Connection: Upgrade\r\n' + + '\r\n'); + socket.pipe(socket); + }); + + this.sock = sockjs.createServer(); + this.sock.installHandlers(srv, {prefix: this.prefix}); + this.sock.on('connection', (conn) => { + conn.on('data', (message) => { + let frame = Frame.unmarshallSingle(message); + if (frame) { + switch (frame.command) { + case 'CONNECT': + MockServer._onConnect(conn, frame); + break; + + case 'DISCONNECT': + console.log('disconnected'); + break; + + case 'SEND': + MockServer._onSend(conn, frame); + break; + + case 'SUBSCRIBE': + this._onSubscribe(conn, frame); + break; + + case 'UNSUBSCRIBE': + this._onUnSubscribe(conn, frame); + break; + + case 'ACK': + this._onAck(conn, frame); + break; + + case 'NACK': + this._onNack(conn, frame); + break; + + case 'BEGIN': + this._onBegin(conn, frame); + break; + + case 'COMMIT': + this._onCommit(conn, frame); + break; + + case 'ABORT': + this._onAbort(conn, frame); + break; + + default: + break; + } + } + }); + conn.on('close', () => { + console.log('closed'); + }); + }); + srv.listen(this.port, this.ip); + } + + static _onConnect(conn, frame) { + if (frame.headers.login === 'username' && frame.headers.passcode === 'password') { + conn.write(Frame.marshall('CONNECTED', {version: VERSIONS.V1_2}, 'login success')); + + } else if (frame.headers['heartbeat-enable']) { + conn.write(Frame.marshall('CONNECTED', { + version: VERSIONS.V1_2, + 'heart-beat': '10, 10' + }, '')); + + } else if (frame.headers['error-enable']) { + conn.write(Frame.marshall('CONNECTED', {version: VERSIONS.V1_2}, '')); + conn.write(Frame.marshall('ERROR', {}, '')); + + } else if (frame.headers['receipt-enable']) { + conn.write(Frame.marshall('CONNECTED', {version: VERSIONS.V1_2}, '')); + conn.write(Frame.marshall('RECEIPT', {}, '')); + + } else { + conn.write(Frame.marshall('CONNECTED', {version: VERSIONS.V1_2}, '')); + } + } + + static _onSend(conn, frame) { + if (frame.headers.destination === '/send') { + if (frame.body === 'test' && + frame.headers.test && + frame.headers.test === 'test') { + conn.write(Frame.marshall('MESSAGE', {}, '0')); + return; + } + } else if (frame.headers.destination === '/largeFrame') { + if (parseInt(frame.headers['content-length']) !== frame.body.length) { + conn.write(Frame.marshall('MESSAGE', {}, frame.body)); + return; + } + } + conn.write(Frame.marshall('MESSAGE', {}, '1')); + } + + _onSubscribe(conn, frame) { + if (frame.headers.destination === '/channel' && frame.headers.id) { + this.subscribes.push(frame.headers.id); + conn.write(Frame.marshall('MESSAGE', {subscription: frame.headers.id}, '0')); + + } else if ((frame.headers.destination === '/ack' || frame.headers.destination === '/nack') && + frame.headers.id) { + this.subscribes.push(frame.headers.id); + conn.write(Frame.marshall('MESSAGE', { + subscription: frame.headers.id, + 'message-id': this.lastMessageId + }, '1')); + } + } + + _onUnSubscribe(conn, frame) { + if (frame.headers.id) { + let index = this.subscribes.indexOf(frame.headers.id); + if (index > -1) { + this.subscribes.splice(index, 1); + conn.write(Frame.marshall('MESSAGE', {id: frame.headers.id}, '0')); + return; + } + } + conn.write(Frame.marshall('MESSAGE', {id: frame.headers.id}, '1')); + } + + _onAck(conn, frame) { + let index = this.subscribes.indexOf(frame.headers.subscription); + if (index > -1 && String(this.lastMessageId) === frame.headers.id) { + this.lastMessageId++; + conn.write(Frame.marshall('MESSAGE', {}, 'ack success')); + } else { + conn.write(Frame.marshall('MESSAGE', {}, 'ack failed')); + } + } + + _onNack(conn, frame) { + let index = this.subscribes.indexOf(frame.headers.subscription); + if (index > -1 && String(this.lastMessageId) === frame.headers.id) { + this.lastMessageId++; + conn.write(Frame.marshall('MESSAGE', {}, 'nack success')); + } else { + conn.write(Frame.marshall('MESSAGE', {}, 'nack failed')); + } + } + + _onBegin(conn, frame) { + if (frame.headers.transaction) { + this.lastTransactionId = frame.headers.transaction; + conn.write(Frame.marshall('MESSAGE', {}, 'begin success')); + } else { + conn.write(Frame.marshall('MESSAGE', {}, 'begin failed')); + } + } + + _onCommit(conn, frame) { + if (frame.headers.transaction && frame.headers.transaction === this.lastTransactionId) { + conn.write(Frame.marshall('MESSAGE', {}, 'commit success')); + } else { + conn.write(Frame.marshall('MESSAGE', {}, 'commit failed')); + } + this.lastTransactionId = ''; + } + + _onAbort(conn, frame) { + if (frame.headers.transaction && frame.headers.transaction === this.lastTransactionId) { + conn.write(Frame.marshall('MESSAGE', {}, 'abort success')); + } else { + conn.write(Frame.marshall('MESSAGE', {}, 'abort failed')); + } + this.lastTransactionId = ''; + } +} + +if (require.main === module) { + let server = new MockServer('127.0.0.1', 1111, '/stomp'); + server.start(); +} + +export default MockServer; diff --git a/test/utils-test.js b/test/utils-test.js new file mode 100644 index 0000000..49c8c03 --- /dev/null +++ b/test/utils-test.js @@ -0,0 +1,43 @@ +import {assert} from 'chai'; +import * as utils from './../src/utils'; + +describe('utils', () => { + + it('trim', () => { + assert.strictEqual(utils.trim('test'), 'test'); + assert.strictEqual(utils.trim(' test'), 'test'); + assert.strictEqual(utils.trim('test '), 'test'); + assert.strictEqual(utils.trim('\f\n\r\t\v\u00a0\u1680\u2028\u2029\u202f\u205f\u3000\ufeff'), ''); + + assert.throws(() => { + utils.trim(1) + }, TypeError); + assert.throws(() => { + utils.trim(Object()) + }, TypeError); + }); + + it('unicodeStringToTypedArray', () => { + assert.deepEqual(utils.unicodeStringToTypedArray(' test '), new Uint8Array([32, 116, 101, 115, 116, 32])); + assert.deepEqual(utils.unicodeStringToTypedArray(''), new Uint8Array([])); + assert.deepEqual(utils.unicodeStringToTypedArray(JSON.stringify({test: 'test'})), + new Uint8Array([123, 34, 116, 101, 115, 116, 34, 58, 34, 116, 101, 115, 116, 34, 125])); + }); + + it('typedArrayToUnicodeString', () => { + assert.strictEqual(utils.typedArrayToUnicodeString([32, 116, 101, 115, 116, 32]), ' test '); + assert.strictEqual(utils.typedArrayToUnicodeString([49]), '1'); + assert.strictEqual(utils.typedArrayToUnicodeString([]), ''); + assert.strictEqual(utils.typedArrayToUnicodeString([123, 34, 116, 101, 115, 116, 34, 58, 34, 116, 101, 115, 116, 34, 125]), + JSON.stringify({test: 'test'})); + }); + + it('sizeOfUTF8', () => { + assert.strictEqual(utils.sizeOfUTF8(undefined), 0); + assert.strictEqual(utils.sizeOfUTF8(null), 0); + assert.strictEqual(utils.sizeOfUTF8(''), 0); + assert.strictEqual(utils.sizeOfUTF8('test'), 4); + assert.strictEqual(utils.sizeOfUTF8(' test '), 8); + assert.strictEqual(utils.sizeOfUTF8(JSON.stringify({test: 'test'})), 15); + }); +}); diff --git a/test/webstomp-test.js b/test/webstomp-test.js new file mode 100644 index 0000000..a891b55 --- /dev/null +++ b/test/webstomp-test.js @@ -0,0 +1,22 @@ +import {assert} from 'chai'; +import {VERSIONS} from './../src/utils'; +import webstomp from './../src/webstomp'; +import Client from './../src/client'; +import SockJS from 'sockjs-client'; + +describe('webstomp', () => { + + it('client', () => { + assert.instanceOf(webstomp.client('ws://127.0.0.1:1111/stomp'), Client); + }); + + it('over', () => { + let ws = new WebSocket('ws://127.0.0.1:1111/stomp', VERSIONS.supportedProtocols()); + assert.instanceOf(webstomp.over(ws), Client); + }); + + it('overWithSockJS', () => { + let sockjs = new SockJS('http://127.0.0.1:1111/stomp'); + assert.instanceOf(webstomp.over(sockjs), Client); + }); +}); diff --git a/webpack.config.js b/webpack.config.js index b1688a2..a373d5c 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,14 +1,20 @@ module.exports = { - entry: './src/webstomp.js', - output: { - path: __dirname + '/dist', - filename: 'webstomp.js', - library: 'webstomp', - libraryTarget: 'umd' - }, - module: { - loaders: [ - {test: /\.js$/, loader: 'babel'} - ] - } + entry: ['./src/webstomp.js'], + output: { + path: __dirname + '/dist', + filename: 'webstomp.js', + library: 'webstomp', + libraryTarget: 'umd' + }, + module: { + loaders: [ + { + test: /\.js$/, + loader: 'babel-loader' + } + ] + }, + resolve: { + extensions: ['', '.js'] + } }; From acf680844f64b91c4853aa63ee6ea8ee27549170 Mon Sep 17 00:00:00 2001 From: yuye Date: Wed, 15 Jun 2016 00:51:32 +0800 Subject: [PATCH 2/4] abandon gulp --- .travis.yml | 6 ++--- gulpfile.js | 66 --------------------------------------------------- karma.conf.js | 12 ++++------ package.json | 6 ++--- test/test.js | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 79 deletions(-) delete mode 100644 gulpfile.js create mode 100644 test/test.js diff --git a/.travis.yml b/.travis.yml index 10e5545..86e1ae7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ node_js: branches: only: - master + - test env : - BROWSSER=chromium_browser addons: @@ -13,11 +14,10 @@ cache: directories: - node_modules before_script: - - npm install -g gulp - export CHROME_BIN=chromium-browser - export DISPLAY=:99.0 - sh -e /etc/init.d/xvfb start - sleep 3 # give xvfb some time to start -script: gulp test +script: npm run test after_success: - - gulp coverage \ No newline at end of file + - npm run coverage diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 9083591..0000000 --- a/gulpfile.js +++ /dev/null @@ -1,66 +0,0 @@ -'use strict'; - -var gulp = require('gulp'); -var webpack = require('webpack'); -var del = require('del'); -var karma = require('karma').Server; -var spawn = require('child_process').spawn; -var coveralls = require('gulp-coveralls'); -var node; - -gulp.task('clean', function(cb) { - del.sync(['./dist/*']); - cb(); -}); - -gulp.task('testServer', ['clean'], function _testServer(cb) { - if (node) { - node.kill(); - } - webpack({ - entry: './test/support/server-mock.js', - output: { - path: __dirname + '/dist/support', - filename: 'server-mock.js' - }, - module: { - loaders: [ - { - test: /\.js$/, - loader: 'babel-loader', - exclude: /node_modules/ - } - ] - }, - target: 'node', - resolve: { - extensions: ['', '.js'] - } - }, function(err) { - if (err) { - cb(err); - - } else { - node = spawn('node', ['./dist/support/server-mock.js'], {stdio: 'inherit'}); - cb(); - } - }); -}); - -gulp.task('test', ['testServer'], function _test(cb) { - // jscs:disable requireCapitalizedConstructors - return new karma({ - configFile: __dirname + '/karma.conf.js', - singleRun: true - }, function _testCB(code) { - if (node) { - node.kill(); - } - cb(code); - }).start(); -}); - -gulp.task('coverage', function _coverage(cb) { - return gulp.src('dist/coverage/*/coverage.info') - .pipe(coveralls()); -}); diff --git a/karma.conf.js b/karma.conf.js index 8c2014a..a5494a1 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -1,5 +1,4 @@ // Karma configuration -// Generated on Sat Jun 04 2016 17:41:44 GMT+0800 (中国标准时间) var webpack = require('karma-webpack'); module.exports = function(config) { @@ -30,7 +29,7 @@ module.exports = function(config) { // preprocess matching files before serving them to the browser // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor preprocessors: { - 'test/*.js': ['webpack'], + 'test/!(test).js': ['webpack'], 'src/**/*.js': ['webpack'] }, webpack: { @@ -55,15 +54,14 @@ module.exports = function(config) { }, externals: { ws:'WebSocket' - }, - debug: true + } }, webpackMiddleware: { - noInfo: true + noInfo:true }, reporters: ['progress', 'coverage'], coverageReporter: { - dir: 'dist/coverage/', + dir: 'test/tmp/coverage/', subdir: function(browser) { return browser.toLowerCase().split(/[ /-]/)[0]; }, @@ -87,7 +85,7 @@ module.exports = function(config) { colors: true, // level of logging // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG - logLevel: config.LOG_INFO, + logLevel: config.LOG_DISABLE, // enable / disable watching file and executing tests whenever any file changes autoWatch: true, // start these browsers diff --git a/package.json b/package.json index e196790..8270a74 100644 --- a/package.json +++ b/package.json @@ -40,8 +40,6 @@ "ws": "^1.0.1", "sockjs": "^0.3.17", "sockjs-client": "^1.1.1", - "gulp": "^3.9.1", - "gulp-coveralls": "^0.1.4", "del": "^2.2.0", "mocha": "^2.5.3", "chai": "^3.5.0", @@ -52,10 +50,12 @@ "karma-ie-launcher": "^1.0.0", "karma-firefox-launcher": "^1.0.0", "karma-coverage": "^1.0.0", + "coveralls": "^2.11.10", "core-js": "^2.4.0" }, "scripts": { - "test": "gulp test", + "test": "node ./test/test.js", + "coverage": "cat ./test/tmp/coverage/chrome/coverage.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", "build": "webpack && webpack -p --config webpack.min.config.js", "dev": "webpack --watch", "example": "webpack && opn http://localhost:8080/example & http-server", diff --git a/test/test.js b/test/test.js new file mode 100644 index 0000000..f1dc4c4 --- /dev/null +++ b/test/test.js @@ -0,0 +1,65 @@ +var webpack = require('webpack'); +var karma = require('karma').Server; +var spawn = require('child_process').spawn; +var coveralls = require('coveralls'); +var path = require('path'); +var node = null; + + +function main() { + if (node) { + node.kill(); + } + var srcPath = path.join(__dirname, 'support', 'server-mock.js'); + var destDirPath = path.join(__dirname, 'tmp', 'support'); + var destPath = path.join(destDirPath, 'server-mock.js'); + webpack({ + entry: srcPath, + output: { + path: destDirPath, + filename: 'server-mock.js' + }, + module: { + loaders: [ + { + test: /\.js$/, + loader: 'babel-loader', + exclude: /node_modules/ + } + ] + }, + target: 'node', + resolve: { + extensions: ['', '.js'] + } + }, (err) => { + if (err) { + console.log(err); + process.exit(1); + + } else { + node = spawn('node', [destPath], {stdio: 'inherit'}); + test(); + } + }); +} + +function test() { + var testConfig = path.join(__dirname, '..', 'karma.conf.js'); + new karma({ + configFile: testConfig, + singleRun: true + }, (code) => { + if (node) { + node.kill(); + } + if (code !== 0) { + console.log('test failed'); + process.exit(code); + } + }).start(); +} + +if (require.main === module) { + main(); +} From e4d048b3293d7138fc3e8b9fa110da0a7e0c4532 Mon Sep 17 00:00:00 2001 From: yuye Date: Wed, 15 Jun 2016 00:58:42 +0800 Subject: [PATCH 3/4] use old coveralls since 2.11.10 is not present in npm --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 8270a74..786942c 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "karma-ie-launcher": "^1.0.0", "karma-firefox-launcher": "^1.0.0", "karma-coverage": "^1.0.0", - "coveralls": "^2.11.10", + "coveralls": "^2.11.9", "core-js": "^2.4.0" }, "scripts": { From b02d1d4a205809fb38513680708aba813b7313cb Mon Sep 17 00:00:00 2001 From: yuye Date: Wed, 15 Jun 2016 01:08:08 +0800 Subject: [PATCH 4/4] fix coverage script --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 786942c..7955af2 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,7 @@ }, "scripts": { "test": "node ./test/test.js", - "coverage": "cat ./test/tmp/coverage/chrome/coverage.info | ./node_modules/coveralls/bin/coveralls.js && rm -rf ./coverage", + "coverage": "cat ./test/tmp/coverage/chrome/coverage.info | ./node_modules/coveralls/bin/coveralls.js", "build": "webpack && webpack -p --config webpack.min.config.js", "dev": "webpack --watch", "example": "webpack && opn http://localhost:8080/example & http-server",