From eccc4046bbb5cce174d4b49407c0f6a953d5ad7a Mon Sep 17 00:00:00 2001 From: Nam Giang Date: Mon, 13 Feb 2017 01:55:22 -0800 Subject: [PATCH 1/5] mqtt over websocket on different path --- lib/server.js | 11 +++++++++-- test/abstract_server.js | 6 +++--- test/server.js | 2 +- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/lib/server.js b/lib/server.js index b8d9f1d..d4183cc 100755 --- a/lib/server.js +++ b/lib/server.js @@ -609,10 +609,17 @@ Server.prototype.close = function(callback) { * * @api public * @param {HttpServer} server + * @param {String} path */ -Server.prototype.attachHttpServer = function(server) { +Server.prototype.attachHttpServer = function(server, path) { var that = this; - ws.createServer({ server: server }, function(stream) { + + var opt = { server: server }; + if (path) { + opt.path = path; + } + + ws.createServer(opt, function(stream) { var conn = new Connection(stream); new Client(conn, that); }); diff --git a/test/abstract_server.js b/test/abstract_server.js index 2be95b5..8ac41d8 100644 --- a/test/abstract_server.js +++ b/test/abstract_server.js @@ -41,9 +41,9 @@ module.exports = function(moscaSettings, createConnection) { }); function finish () { - client.removeListener('error', finish) - client.stream.removeListener('close', finish) - done() + client.removeListener('error', finish); + client.stream.removeListener('close', finish); + done(); } } diff --git a/test/server.js b/test/server.js index 6e772a1..2ac1a83 100644 --- a/test/server.js +++ b/test/server.js @@ -174,7 +174,7 @@ describe("mosca.Server", function() { // Simulate a situation that it takes same time to do authorizeSubscribe. this.instance.authorizeSubscribe = function(client, topic, callback) { setTimeout(function(){ - callback(null, true) + callback(null, true); }, 300); }; From 2ca6787b4fa8079a946fb5181bcc386ffc5c4055 Mon Sep 17 00:00:00 2001 From: Nam Giang Date: Wed, 15 Feb 2017 19:46:37 -0800 Subject: [PATCH 2/5] adding unit test for websocket attach --- test/server_websocket_attach.js | 214 ++++++++++++++++++++++++++++++++ 1 file changed, 214 insertions(+) create mode 100644 test/server_websocket_attach.js diff --git a/test/server_websocket_attach.js b/test/server_websocket_attach.js new file mode 100644 index 0000000..623c0dd --- /dev/null +++ b/test/server_websocket_attach.js @@ -0,0 +1,214 @@ +var mqtt = require('mqtt') +var websocket = require('ws'); +var http = require('http'); + +var port = nextPort(); +var path = '/test'; +var mqttPath = '/mqttws'; +var mqttTopic = 'atopic'; +var ping = 'ping'; +var pong = 'pong'; + +describe("mosca.Server - Mqtt-over-WS attached to existing http server", function() { + + var mqttServ + var server + + afterEach(function(done){ + server.close(); + mqttServ.close(done); + }) + + it("should be able to do mqtt over WebSocket", function(done) { + server = http.createServer(); + mqttServ = new mosca.Server({}); + mqttServ.attachHttpServer(server); + + server.listen(port, function(){ + var client = mqtt.connect('ws://localhost:' + port); + client.subscribe(mqttTopic); + client.on("message", function(topic, payload) { + expect(topic).to.equal(mqttTopic); + expect(payload.toString()).to.equal(ping); + server.close(); + mqttServ.close(done); + }); + client.publish(mqttTopic, ping); + }); + }); + + it("should be able to do mqtt over WebSocket on specific path", function(done) { + server = http.createServer(); + mqttServ = new mosca.Server({}); + mqttServ.attachHttpServer(server, mqttPath); + + server.listen(port, function(){ + var client = mqtt.connect('ws://localhost:' + port + mqttPath); + client.subscribe(mqttTopic); + client.on("message", function(topic, payload) { + expect(topic).to.equal(mqttTopic); + expect(payload.toString()).to.equal(ping); + server.close(); + mqttServ.close(done); + }); + client.publish(mqttTopic, ping); + }); + }); + + it("should not be able to do mqtt over WebSocket on different path", function(done) { + server = http.createServer(); + mqttServ = new mosca.Server({port:3333});// async test, preventing intefere with other tests that spawn on 1883 port + mqttServ.attachHttpServer(server, mqttPath); + + server.listen(port, function(){ + var client = mqtt.connect('ws://localhost:' + port + '/junk'); + client.subscribe(mqttTopic); + var failed = false; + client.on("message", function(topic, payload) { + failed = true; + done(failed) + }); + client.publish(mqttTopic, ping); + setTimeout(function(){ + if (!failed){ + done() + } + }, 2000); + }); + }); + + it("should not be able to do mqtt over WebSocket on root path", function(done) { + var server = http.createServer(); + var mqttServ = new mosca.Server({port:3333}); + mqttServ.attachHttpServer(server, mqttPath); + + server.listen(port, function(){ + var client = mqtt.connect('ws://localhost:' + port); + client.subscribe(mqttTopic); + var failed = false; + client.on("message", function(topic, payload) { + failed = true; + mqttServ.close(function(){ + done(failed); + }); + }); + client.publish(mqttTopic, ping); + setTimeout(function(){ + if (!failed){ + server.close(); + mqttServ.close(done); + } + }, 2000); + }); + }); + + //TODO: this test failed, what does the spec say? + xit("should not be able to do mqtt over WebSocket on a specific path without attaching to any path", function(done) { + var server = http.createServer(); + var mqttServ = new mosca.Server({port:3333}); + mqttServ.attachHttpServer(server); + + server.listen(port, function(){ + var client = mqtt.connect('ws://localhost:' + port + mqttPath); + client.subscribe(mqttTopic); + var failed = false; + client.on("message", function(topic, payload) { + failed = true; + mqttServ.close(function(){ + done(failed); + }); + }); + client.publish(mqttTopic, ping); + setTimeout(function(){ + if (!failed){ + server.close(); + mqttServ.close(done); + } + }, 2000); + }); + }); +}); + +describe("mosca.Server - Websocket and Mqtt-over-WS attached to the same http server", function() { + it("ws client should not connect when mqtt is attached to http server without path", function(done) { + var server = http.createServer(); + var wss = new websocket.Server({ + server: server, + path: path, + perMessageDeflate: false + }); + var mqttServ = new mosca.Server({}); + mqttServ.attachHttpServer(server); + + server.listen(port, function(){ + var ws = new websocket('ws://localhost:' + port + path, { + perMessageDeflate: false + }); + + ws.on('error', function(e) { + expect(e).to.not.be.undefined; + server.close(); + mqttServ.close(done); + }); + }); + }); + + it("ws client should be able to connect when specific path is used", function(done) { + var server = http.createServer(); + var wss = new websocket.Server({ + server: server, + path: path, + perMessageDeflate: false + }); + wss.on('connection', function(conn){ + conn.on('message', function(msg){ + expect(msg).to.equal(ping); + conn.send(pong); + }); + }); + + var mqttServ = new mosca.Server({}); + mqttServ.attachHttpServer(server, mqttPath); + + server.listen(port, function(){ + var ws = new websocket('ws://localhost:' + port + path, { + perMessageDeflate: false + }); + + ws.on('open', function(){ + ws.send(ping); + }); + + ws.on('message', function(msg){ + expect(msg).to.equal(pong); + server.close(); + mqttServ.close(done); + }); + }); + }); + + + it("mqtt client should be able to connect as well", function(done) { + var server = http.createServer(); + var wss = new websocket.Server({ + server: server, + path: path, + perMessageDeflate: false + }); + + var mqttServ = new mosca.Server({}); + mqttServ.attachHttpServer(server, mqttPath); + + server.listen(port, function(){ + var client = mqtt.connect('ws://localhost:' + port + mqttPath); + client.subscribe(mqttTopic); + client.on("message", function(topic, payload) { + expect(topic).to.equal(mqttTopic); + expect(payload.toString()).to.equal(ping); + server.close(); + mqttServ.close(done); + }); + client.publish(mqttTopic, ping); + }); + }); +}); From 1c0c6d35518df0b1ca2fc18adb35ce019488eb66 Mon Sep 17 00:00:00 2001 From: Nam Giang Date: Wed, 15 Feb 2017 20:36:40 -0800 Subject: [PATCH 3/5] added ws to dev dependencies --- package.json | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index 7783fc9..e496049 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "author": "Matteo Collina ", "license": "MIT", "devDependencies": { + "browserify": "~13.0.0", "chai": "^3.5.0", "coveralls": "~2.11.1", "dox-foundation": "~0.5.4", @@ -62,9 +63,9 @@ "sinon-chai": "~2.8.0", "supertest": "~1.2.0", "tmp": "0.0.24", - "browserify": "~13.0.0", "uglify-js": "^2.4.16", - "underscore": "^1.7.0" + "underscore": "^1.7.0", + "ws": "^1.0.1" }, "dependencies": { "array-from": "^2.1.1", From dfdf509c8bc7722257ee6d71053fc2bf216f3eee Mon Sep 17 00:00:00 2001 From: Nam Giang Date: Sun, 26 Feb 2017 11:21:06 -0800 Subject: [PATCH 4/5] empty interfaces should not be invalid --- lib/options.js | 10 +- lib/server.js | 2 +- test/server_websocket_attach.js | 161 +++++++++++++++----------------- 3 files changed, 80 insertions(+), 93 deletions(-) diff --git a/lib/options.js b/lib/options.js index ca6009b..fe5ba31 100755 --- a/lib/options.js +++ b/lib/options.js @@ -259,11 +259,11 @@ function validate(opts, validationOptions) { var result = validator.validate(opts, '/Options', validationOptions); // check empty interfaces - if (opts.hasOwnProperty('interfaces')) { - if (opts.interfaces.length === 0) { - result.addError('no interfaces were defined'); - } - } + // if (opts.hasOwnProperty('interfaces')) { + // if (opts.interfaces.length === 0) { + // result.addError('no interfaces were defined'); + // } + // } // check required credentials if (opts.hasOwnProperty('interfaces')) { diff --git a/lib/server.js b/lib/server.js index d4183cc..711d31b 100755 --- a/lib/server.js +++ b/lib/server.js @@ -162,6 +162,7 @@ function Server(opts, callback) { // initialize servers list this.servers = []; + steed.series([ // steed.series: wait for ascoltatore @@ -236,7 +237,6 @@ function Server(opts, callback) { } }); - that.on("clientConnected", function(client) { if(that.modernOpts.publishNewClient) { that.publish({ diff --git a/test/server_websocket_attach.js b/test/server_websocket_attach.js index 623c0dd..3eed9bc 100644 --- a/test/server_websocket_attach.js +++ b/test/server_websocket_attach.js @@ -1,4 +1,4 @@ -var mqtt = require('mqtt') +var mqtt = require('mqtt'); var websocket = require('ws'); var http = require('http'); @@ -10,119 +10,83 @@ var ping = 'ping'; var pong = 'pong'; describe("mosca.Server - Mqtt-over-WS attached to existing http server", function() { - - var mqttServ - var server + var server, mqttServ; - afterEach(function(done){ + beforeEach(function(){ + server = http.createServer(); + mqttServ = new mosca.Server({interfaces:[]}); + }); + + afterEach(function(){ server.close(); - mqttServ.close(done); - }) + }); - it("should be able to do mqtt over WebSocket", function(done) { - server = http.createServer(); - mqttServ = new mosca.Server({}); + it("should not occupy 1883 port while attached to http server", function(done) { mqttServ.attachHttpServer(server); + server.listen(1883, done); + }); + it("should be able to do mqtt over WebSocket", function(done) { + mqttServ.attachHttpServer(server); server.listen(port, function(){ var client = mqtt.connect('ws://localhost:' + port); client.subscribe(mqttTopic); client.on("message", function(topic, payload) { expect(topic).to.equal(mqttTopic); expect(payload.toString()).to.equal(ping); - server.close(); - mqttServ.close(done); + done(); }); client.publish(mqttTopic, ping); }); }); it("should be able to do mqtt over WebSocket on specific path", function(done) { - server = http.createServer(); - mqttServ = new mosca.Server({}); mqttServ.attachHttpServer(server, mqttPath); - server.listen(port, function(){ var client = mqtt.connect('ws://localhost:' + port + mqttPath); client.subscribe(mqttTopic); client.on("message", function(topic, payload) { expect(topic).to.equal(mqttTopic); expect(payload.toString()).to.equal(ping); - server.close(); - mqttServ.close(done); + done(); }); client.publish(mqttTopic, ping); }); }); it("should not be able to do mqtt over WebSocket on different path", function(done) { - server = http.createServer(); - mqttServ = new mosca.Server({port:3333});// async test, preventing intefere with other tests that spawn on 1883 port mqttServ.attachHttpServer(server, mqttPath); - server.listen(port, function(){ var client = mqtt.connect('ws://localhost:' + port + '/junk'); client.subscribe(mqttTopic); - var failed = false; + var failed = false;// ensuring done is called once client.on("message", function(topic, payload) { failed = true; - done(failed) + done(failed); }); client.publish(mqttTopic, ping); setTimeout(function(){ if (!failed){ - done() + done(); } - }, 2000); + }, 3000); }); }); it("should not be able to do mqtt over WebSocket on root path", function(done) { - var server = http.createServer(); - var mqttServ = new mosca.Server({port:3333}); mqttServ.attachHttpServer(server, mqttPath); - server.listen(port, function(){ var client = mqtt.connect('ws://localhost:' + port); client.subscribe(mqttTopic); var failed = false; client.on("message", function(topic, payload) { failed = true; - mqttServ.close(function(){ - done(failed); - }); - }); - client.publish(mqttTopic, ping); - setTimeout(function(){ - if (!failed){ - server.close(); - mqttServ.close(done); - } - }, 2000); - }); - }); - - //TODO: this test failed, what does the spec say? - xit("should not be able to do mqtt over WebSocket on a specific path without attaching to any path", function(done) { - var server = http.createServer(); - var mqttServ = new mosca.Server({port:3333}); - mqttServ.attachHttpServer(server); - - server.listen(port, function(){ - var client = mqtt.connect('ws://localhost:' + port + mqttPath); - client.subscribe(mqttTopic); - var failed = false; - client.on("message", function(topic, payload) { - failed = true; - mqttServ.close(function(){ - done(failed); - }); + done(failed); }); client.publish(mqttTopic, ping); setTimeout(function(){ if (!failed){ - server.close(); - mqttServ.close(done); + done(); } }, 2000); }); @@ -130,16 +94,25 @@ describe("mosca.Server - Mqtt-over-WS attached to existing http server", functio }); describe("mosca.Server - Websocket and Mqtt-over-WS attached to the same http server", function() { - it("ws client should not connect when mqtt is attached to http server without path", function(done) { - var server = http.createServer(); - var wss = new websocket.Server({ + var server, mqttServ, wss; + + beforeEach(function(){ + server = http.createServer(); + mqttServ = new mosca.Server({interfaces:[]}); + + wss = new websocket.Server({ server: server, path: path, perMessageDeflate: false }); - var mqttServ = new mosca.Server({}); - mqttServ.attachHttpServer(server); + }); + + afterEach(function(){ + server.close(); + }); + it("ws client should not connect when mqtt is attached to http server without path", function(done) { + mqttServ.attachHttpServer(server); server.listen(port, function(){ var ws = new websocket('ws://localhost:' + port + path, { perMessageDeflate: false @@ -147,19 +120,13 @@ describe("mosca.Server - Websocket and Mqtt-over-WS attached to the same http se ws.on('error', function(e) { expect(e).to.not.be.undefined; - server.close(); - mqttServ.close(done); + done(); }); }); }); it("ws client should be able to connect when specific path is used", function(done) { - var server = http.createServer(); - var wss = new websocket.Server({ - server: server, - path: path, - perMessageDeflate: false - }); + mqttServ.attachHttpServer(server, mqttPath); wss.on('connection', function(conn){ conn.on('message', function(msg){ expect(msg).to.equal(ping); @@ -167,9 +134,6 @@ describe("mosca.Server - Websocket and Mqtt-over-WS attached to the same http se }); }); - var mqttServ = new mosca.Server({}); - mqttServ.attachHttpServer(server, mqttPath); - server.listen(port, function(){ var ws = new websocket('ws://localhost:' + port + path, { perMessageDeflate: false @@ -181,34 +145,57 @@ describe("mosca.Server - Websocket and Mqtt-over-WS attached to the same http se ws.on('message', function(msg){ expect(msg).to.equal(pong); - server.close(); - mqttServ.close(done); + done(); }); }); }); - it("mqtt client should be able to connect as well", function(done) { - var server = http.createServer(); - var wss = new websocket.Server({ - server: server, - path: path, - perMessageDeflate: false + mqttServ.attachHttpServer(server, mqttPath); + server.listen(port, function(){ + var client = mqtt.connect('ws://localhost:' + port + mqttPath); + client.subscribe(mqttTopic); + client.on("message", function(topic, payload) { + expect(topic).to.equal(mqttTopic); + expect(payload.toString()).to.equal(ping); + done(); + }); + client.publish(mqttTopic, ping); }); + }); - var mqttServ = new mosca.Server({}); + it("both ws and mqtt client should be able to connect at the same time", function(done) { mqttServ.attachHttpServer(server, mqttPath); + wss.on('connection', function(conn){ + conn.on('message', function(msg){ + expect(msg).to.equal(ping); + conn.send(pong); + }); + }); server.listen(port, function(){ var client = mqtt.connect('ws://localhost:' + port + mqttPath); - client.subscribe(mqttTopic); + var ws = new websocket('ws://localhost:' + port + path, { + perMessageDeflate: false + }); + + client.on('connect', function () { + client.subscribe(mqttTopic); + setTimeout(function(){// wait for ws to connect + ws.send(ping); + }, 2000); + }); + + ws.on('message', function(msg){ + expect(msg).to.equal(pong); + client.publish(mqttTopic, ping); + }); + client.on("message", function(topic, payload) { expect(topic).to.equal(mqttTopic); expect(payload.toString()).to.equal(ping); - server.close(); - mqttServ.close(done); + done(); }); - client.publish(mqttTopic, ping); }); }); }); From 5d2780259c3db00c9136466e49084ff71cd1d5d8 Mon Sep 17 00:00:00 2001 From: Nam Giang Date: Mon, 13 Mar 2017 15:01:55 -0700 Subject: [PATCH 5/5] comments clean up --- lib/options.js | 7 ------- 1 file changed, 7 deletions(-) diff --git a/lib/options.js b/lib/options.js index fe5ba31..1737484 100755 --- a/lib/options.js +++ b/lib/options.js @@ -258,13 +258,6 @@ function validate(opts, validationOptions) { var result = validator.validate(opts, '/Options', validationOptions); - // check empty interfaces - // if (opts.hasOwnProperty('interfaces')) { - // if (opts.interfaces.length === 0) { - // result.addError('no interfaces were defined'); - // } - // } - // check required credentials if (opts.hasOwnProperty('interfaces')) { var hasCredentials = opts.hasOwnProperty('credentials');