From 7b1787fdbb01c44c940423981e11deb0aff523e5 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Sat, 13 Jan 2018 16:14:03 +0000 Subject: [PATCH] Debug to status option (#1499) * Let debug optionally target the status line (32 chars only) * Add batching of messages to debug ws comms * let Debug handle simple case of NaN would also close #1530 * Fixup debug tests for batch comms (no new tests yet) * mixup comms/api test to match new batch mode (no new tests) * Add test for NaN being sent OK. * redo original fix to padding / labels for new debug options * fix debug test (re-add fix from #1444) * Fix up merge issues in debug tests --- editor/js/comms.js | 44 ++++--- nodes/core/core/58-debug.html | 51 ++++++-- nodes/core/core/58-debug.js | 62 +++++++-- nodes/core/core/lib/debug/debug-utils.js | 4 +- nodes/core/locales/en-US/messages.json | 6 +- red/api/comms.js | 28 ++-- test/nodes/core/core/20-inject_spec.js | 12 +- test/nodes/core/core/58-debug_spec.js | 158 +++++++++++++---------- test/red/api/comms_spec.js | 29 +++-- 9 files changed, 260 insertions(+), 134 deletions(-) diff --git a/editor/js/comms.js b/editor/js/comms.js index 1e5328862..6340deb50 100644 --- a/editor/js/comms.js +++ b/editor/js/comms.js @@ -64,27 +64,31 @@ RED.comms = (function() { } } ws.onmessage = function(event) { - var msg = JSON.parse(event.data); - if (pendingAuth && msg.auth) { - if (msg.auth === "ok") { - pendingAuth = false; - completeConnection(); - } else if (msg.auth === "fail") { - // anything else is an error... - active = false; - RED.user.login({updateMenu:true},function() { - connectWS(); - }) + var message = JSON.parse(event.data); + for (var m = 0; m < message.length; m++) { + var msg = message[m]; + if (pendingAuth && msg.auth) { + if (msg.auth === "ok") { + pendingAuth = false; + completeConnection(); + } else if (msg.auth === "fail") { + // anything else is an error... + active = false; + RED.user.login({updateMenu:true},function() { + connectWS(); + }) + } } - } else if (msg.topic) { - for (var t in subscriptions) { - if (subscriptions.hasOwnProperty(t)) { - var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$"); - if (re.test(msg.topic)) { - var subscribers = subscriptions[t]; - if (subscribers) { - for (var i=0;i
- - + + +
+
+ + +
+
+ +
@@ -26,7 +37,7 @@

Alongside each message, the debug sidebar includes information about the time the message was received, the node that sent it and the type of the message. Clicking on the source node id will reveal that node within the workspace.

The button on the node can be used to enable or disable its output. It is recommended to disable or remove any Debug nodes that are not being used.

-

The node can also be configured to send all messages to the runtime log.

+

The node can also be configured to send all messages to the runtime log, or to send short (32 characters) to the status text under the debug node.

@@ -38,7 +49,9 @@ defaults: { name: {value:""}, active: {value:true}, - console: {value:"false"}, + tosidebar: {value:true}, + console: {value:false}, + tostatus: {value:false}, complete: {value:"false", required:true} }, label: function() { @@ -100,7 +113,6 @@ } }, onpaletteadd: function() { - var options = { messageMouseEnter: function(sourceId) { if (sourceId) { @@ -148,7 +160,7 @@ var that = this; RED._debug = function(msg) { - that.handleDebugMessage("",{ + that.handleDebugMessage("", { name:"debug", msg:msg }); @@ -170,7 +182,6 @@ var sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z); if (sourceNode) { o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name}; - } RED.debug.handleDebugMessage(o); if (subWindow) { @@ -225,6 +236,15 @@ delete RED._debug; }, oneditprepare: function() { + if (this.tosidebar === undefined) { + this.tosidebar = true; + $("#node-input-tosidebar").prop('checked', true); + } + if (typeof this.console === "string") { + this.console = (this.console == 'true'); + $("#node-input-console").prop('checked', this.console); + $("#node-input-tosidebar").prop('checked', true); + } $("#node-input-typed-complete").typedInput({types:['msg', {value:"full",label:RED._("node-red:debug.msgobj"),hasValue:false}]}); if (this.complete === "true" || this.complete === true) { // show complete message object @@ -240,6 +260,16 @@ ) { $("#node-input-typed-complete").typedInput('value','payload'); } + if ($("#node-input-typed-complete").typedInput('type') === 'msg') { + $("#node-tostatus-line").show(); + } + else { $("#node-tostatus-line").hide(); } + }); + $("#node-input-complete").on('change',function() { + if ($("#node-input-typed-complete").typedInput('type') === 'msg') { + $("#node-tostatus-line").show(); + } + else { $("#node-tostatus-line").hide(); } }); }, oneditsave: function() { @@ -250,7 +280,6 @@ $("#node-input-complete").val($("#node-input-typed-complete").typedInput('value')); } } - }); })(); diff --git a/nodes/core/core/58-debug.js b/nodes/core/core/58-debug.js index 083fcb78b..3e4290554 100644 --- a/nodes/core/core/58-debug.js +++ b/nodes/core/core/58-debug.js @@ -5,7 +5,7 @@ module.exports = function(RED) { var events = require("events"); var path = require("path"); var safeJSONStringify = require("json-stringify-safe"); - var debuglength = RED.settings.debugMaxLength||1000; + var debuglength = RED.settings.debugMaxLength || 1000; var useColors = RED.settings.debugUseColors || false; util.inspect.styles.boolean = "red"; @@ -13,26 +13,49 @@ module.exports = function(RED) { RED.nodes.createNode(this,n); this.name = n.name; this.complete = (n.complete||"payload").toString(); - - if (this.complete === "false") { - this.complete = "payload"; - } - - this.console = n.console; + if (this.complete === "false") { this.complete = "payload"; } + this.console = ""+(n.console || false); + this.tostatus = n.tostatus || false; + this.tosidebar = n.tosidebar; + if (this.tosidebar === undefined) { this.tosidebar = true; } + this.severity = n.severity || 40; this.active = (n.active === null || typeof n.active === "undefined") || n.active; + this.status({}); + var node = this; + var levels = { + off: 1, + fatal: 10, + error: 20, + warn: 30, + info: 40, + debug: 50, + trace: 60, + audit: 98, + metric: 99 + }; + var colors = { + "0": "grey", + "10": "grey", + "20": "red", + "30": "yellow", + "40": "grey", + "50": "green", + "60": "blue" + }; this.on("input",function(msg) { if (this.complete === "true") { - // debug complete msg object + // debug complete msg object if (this.console === "true") { node.log("\n"+util.inspect(msg, {colors:useColors, depth:10})); } - if (this.active) { - sendDebug({id:node.id,name:node.name,topic:msg.topic,msg:msg,_path:msg._path}); + if (this.active && this.tosidebar) { + sendDebug({id:node.id, name:node.name, topic:msg.topic, msg:msg, _path:msg._path}); } - } else { - // debug user defined msg property + } + else { + // debug user defined msg property var property = "payload"; var output = msg[property]; if (this.complete !== "false" && typeof this.complete !== "undefined") { @@ -53,7 +76,15 @@ module.exports = function(RED) { } } if (this.active) { - sendDebug({id:node.id,z:node.z,name:node.name,topic:msg.topic,property:property,msg:output,_path:msg._path}); + if (this.tosidebar == true) { + sendDebug({id:node.id, z:node.z, name:node.name, topic:msg.topic, property:property, msg:output, _path:msg._path}); + } + if (this.tostatus === true) { + var st = util.inspect(output); + if (st.length > 32) { st = st.substr(0,32) + "..."; } + node.oldStatus = {fill:colors[node.severity], shape:"dot", text:st}; + node.status(node.oldStatus); + } } } }); @@ -196,9 +227,14 @@ module.exports = function(RED) { if (state === "enable") { node.active = true; res.sendStatus(200); + if (node.tostatus) { node.status({}); } } else if (state === "disable") { node.active = false; res.sendStatus(201); + if (node.tostatus && node.hasOwnProperty("oldStatus")) { + node.oldStatus.shape = "ring"; + node.status(node.oldStatus); + } } else { res.sendStatus(404); } diff --git a/nodes/core/core/lib/debug/debug-utils.js b/nodes/core/core/lib/debug/debug-utils.js index 63958b363..52e5a7ce1 100644 --- a/nodes/core/core/lib/debug/debug-utils.js +++ b/nodes/core/core/lib/debug/debug-utils.js @@ -439,7 +439,9 @@ RED.debug = (function() { $(''+name+'').appendTo(metaRow); } - if (format === 'Object' || /^array/.test(format) || format === 'boolean' || format === 'number' ) { + if ((format === 'number') && (payload === "NaN")) { + payload = Number.NaN; + } else if (format === 'Object' || /^array/.test(format) || format === 'boolean' || format === 'number' ) { payload = JSON.parse(payload); } else if (/error/i.test(format)) { payload = JSON.parse(payload); diff --git a/nodes/core/locales/en-US/messages.json b/nodes/core/locales/en-US/messages.json index c2665538d..07bbe174b 100644 --- a/nodes/core/locales/en-US/messages.json +++ b/nodes/core/locales/en-US/messages.json @@ -103,9 +103,13 @@ "output": "Output", "msgprop": "message property", "msgobj": "complete msg object", - "to": "to", + "to": "To", "debtab": "debug tab", "tabcon": "debug tab and console", + "toSidebar": "debug window", + "toConsole": "system console", + "toStatus": "node status (32 characters)", + "severity": "Level", "notification": { "activated": "Successfully activated: __label__", "deactivated": "Successfully deactivated: __label__" diff --git a/red/api/comms.js b/red/api/comms.js index 030b46e24..323ed4673 100644 --- a/red/api/comms.js +++ b/red/api/comms.js @@ -63,7 +63,7 @@ function start() { // https://github.com/websockets/ws/pull/632 // that is fixed in the 1.x release of the ws module // that we cannot currently pickup as it drops node 0.10 support - perMessageDeflate: false + //perMessageDeflate: false }); wsServer.on('connection',function(ws) { @@ -189,15 +189,27 @@ function publish(topic,data,retain) { } } +var stack = []; +var ok2tx = true; function publishTo(ws,topic,data) { - var msg = JSON.stringify({topic:topic,data:data}); - try { - ws.send(msg); - } catch(err) { - removeActiveConnection(ws); - removePendingConnection(ws); - log.warn(log._("comms.error-send",{message:err.toString()})); + if (topic && data) { stack.push({topic:topic,data:data}); } + + if (ok2tx && (stack.length > 0)) { + ok2tx = false; + try { + ws.send(JSON.stringify(stack)); + } catch(err) { + removeActiveConnection(ws); + removePendingConnection(ws); + log.warn(log._("comms.error-send",{message:err.toString()})); + } + stack = []; + var txtout = setTimeout(function() { + ok2tx = true; + publishTo(ws); + }, 50); // TODO: OK so a 50mS update rate should prob not be hard-coded } + } function handleRemoteSubscription(ws,topic) { diff --git a/test/nodes/core/core/20-inject_spec.js b/test/nodes/core/core/20-inject_spec.js index 2137f2967..a42520a68 100644 --- a/test/nodes/core/core/20-inject_spec.js +++ b/test/nodes/core/core/20-inject_spec.js @@ -51,10 +51,14 @@ describe('inject node', function() { function() { var n2 = helper.getNode("n2"); n2.on("input", function(msg) { - msg.should.have.property('topic', 't1'); - msg.should.have.property('payload'); - should(msg.payload).be.lessThan(timestamp.getTime()); - done(); + try { + msg.should.have.property('topic', 't1'); + msg.should.have.property('payload'); + should(msg.payload).be.lessThan(timestamp.getTime()); + done(); + } catch(err) { + done(err); + } }); }); }); diff --git a/test/nodes/core/core/58-debug_spec.js b/test/nodes/core/core/58-debug_spec.js index a136736c3..e1d6cd3a9 100644 --- a/test/nodes/core/core/58-debug_spec.js +++ b/test/nodes/core/core/58-debug_spec.js @@ -25,13 +25,19 @@ describe('debug node', function() { helper.startServer(done); }); + beforeEach(function (done) { + setTimeout(function() { + done(); + }, 55); + }); + afterEach(function() { helper.unload(); }); it('should be loaded', function(done) { - var flow = [{id:"n1", type:"debug", name: "Debug", complete:"false" }]; + var flow = [{id:"n1", type:"debug", name:"Debug", complete:"false" }]; helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); n1.should.have.property('name', 'Debug'); @@ -41,31 +47,31 @@ describe('debug node', function() { }); it('should publish on input', function(done) { - var flow = [{id:"n1", type:"debug", name: "Debug" }]; + var flow = [{id:"n1", type:"debug", name:"Debug" }]; helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { n1.emit("input", {payload:"test"}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",name:"Debug",msg:"test", format:"string[4]",property:"payload"} - }); + }]); }, done); }); }); it('should publish to console', function(done) { - var flow = [{id:"n1", type:"debug", console: "true"}]; + var flow = [{id:"n1", type:"debug", console:"true"}]; helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); var count = 0; websocket_test(function() { n1.emit("input", {payload:"test"}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg:"test",property:"payload",format:"string[4]"} - }); + }]); count++; }, function() { try { @@ -86,31 +92,31 @@ describe('debug node', function() { }); it('should publish complete message', function(done) { - var flow = [{id:"n1", type:"debug", complete: "true" }]; + var flow = [{id:"n1", type:"debug", complete:"true" }]; helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { n1.emit("input", {payload:"test"}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug", data:{id:"n1",msg:'{\n "payload": "test"\n}',format:"Object"} - }); + }]); }, done); }); }); it('should publish complete message to console', function(done) { - var flow = [{id:"n1", type:"debug", complete: "true", console: "true" }]; + var flow = [{id:"n1", type:"debug", complete:"true", console:"true" }]; helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { n1.emit("input", {payload:"test"}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug", data:{id:"n1",msg:'{\n "payload": "test"\n}',format:"Object"} - }); + }]); }, function() { try { helper.log().called.should.be.true(); @@ -129,29 +135,29 @@ describe('debug node', function() { }); it('should publish other property', function(done) { - var flow = [{id:"n1", type:"debug", complete: "foo" }]; + var flow = [{id:"n1", type:"debug", complete:"foo" }]; helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { n1.emit("input", {payload:"test", foo:"bar"}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg:"bar",property:"foo",format:"string[3]"} - }); + }]); }, done); }); }); it('should publish multi-level properties', function(done) { - var flow = [{id:"n1", type:"debug", complete: "foo.bar" }]; + var flow = [{id:"n1", type:"debug", complete:"foo.bar" }]; helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { - n1.emit("input", {payload:"test", foo: {bar: "bar"}}); + n1.emit("input", {payload:"test", foo: {bar:"bar"}}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg:"bar",property:"foo.bar",format:"string[3]"} - }); + }]); }, done); }); }); @@ -163,9 +169,9 @@ describe('debug node', function() { websocket_test(function() { n1.emit("input", {payload: new Error("oops")}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg:'{"name":"Error","message":"oops"}',property:"payload",format:"error"} - }); + }]); }, done); }); }); @@ -177,9 +183,9 @@ describe('debug node', function() { websocket_test(function() { n1.emit("input", {payload: true}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg: 'true',property:"payload",format:"boolean"} - }); + }]); }, done); }); }); @@ -191,9 +197,23 @@ describe('debug node', function() { websocket_test(function() { n1.emit("input", {payload: 7}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg:"7",property:"payload",format:"number"} - }); + }]); + }, done); + }); + }); + + it('should publish a NaN', function(done) { + var flow = [{id:"n1", type:"debug", console:"true" }]; + helper.load(debugNode, flow, function() { + var n1 = helper.getNode("n1"); + websocket_test(function() { + n1.emit("input", {payload: Number.NaN}); + }, function(msg) { + JSON.parse(msg).should.eql([{ + topic:"debug",data:{id:"n1",msg:"NaN",property:"payload",format:"number"} + }]); }, done); }); }); @@ -205,9 +225,9 @@ describe('debug node', function() { websocket_test(function() { n1.emit("input", {}); }, function(msg) { - JSON.parse(msg).should.eql({ - topic:"debug",data:{id:"n1",msg: '(undefined)',property:"payload",format:"undefined"} - }); + JSON.parse(msg).should.eql([{ + topic:"debug",data:{id:"n1",msg:'(undefined)',property:"payload",format:"undefined"} + }]); }, done); }); }); @@ -217,11 +237,11 @@ describe('debug node', function() { helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { - n1.emit("input", {payload: null}); + n1.emit("input", {payload:null}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg:'(undefined)',property:"payload",format:"null"} - }); + }]); }, done); }); }); @@ -233,10 +253,10 @@ describe('debug node', function() { websocket_test(function() { n1.emit("input", {payload: {type:'foo'}}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug", data:{id:"n1",msg:'{\n "type": "foo"\n}',property:"payload",format:"Object"} - }); + }]); }, done); }); }); @@ -248,11 +268,11 @@ describe('debug node', function() { websocket_test(function() { n1.emit("input", {payload: [0,1,2,3]}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug", data:{id:"n1",msg: '[\n 0,\n 1,\n 2,\n 3\n]',format:"array[4]", property:"payload"} - }); + }]); }, done); }); }); @@ -266,28 +286,28 @@ describe('debug node', function() { o.o = o; n1.emit("input", {payload: o}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug", data:{ id:"n1", msg:'{\n "name": "bar",\n "o": "[Circular ~]"\n}', property:"payload",format:"Object" } - }); + }]); }, done); }); }); it('should publish an object to console', function(done) { - var flow = [{id:"n1", type:"debug", console: "true"}]; + var flow = [{id:"n1", type:"debug", console:"true"}]; helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { n1.emit("input", {payload: {type:'foo'}}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg:'{\n "type": "foo"\n}',property:"payload",format:"Object"} - }); + }]); }, function() { try { helper.log().called.should.be.true(); @@ -306,15 +326,15 @@ describe('debug node', function() { }); it('should publish a string after a newline to console if the string contains \\n', function(done) { - var flow = [{id:"n1", type:"debug", console: "true"}]; + var flow = [{id:"n1", type:"debug", console:"true"}]; helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { - n1.emit("input", {payload: "test\ntest"}); + n1.emit("input", {payload:"test\ntest"}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg:"test\ntest",property:"payload",format:"string[9]"} - }); + }]); }, function() { try { helper.log().called.should.be.true(); @@ -337,10 +357,10 @@ describe('debug node', function() { helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { - n1.emit("input", {payload: Array(1002).join("X")}); + n1.emit("input", {payload:Array(1002).join("X")}); }, function(msg) { var a = JSON.parse(msg); - a.should.eql({ + a.should.eql([{ topic:"debug", data:{ id:"n1", @@ -348,7 +368,7 @@ describe('debug node', function() { property:"payload", format:"string[1001]" } - }); + }]); }, done); }); }); @@ -361,7 +381,7 @@ describe('debug node', function() { n1.emit("input", {payload: {foo: Array(1002).join("X")}}); }, function(msg) { var a = JSON.parse(msg); - a.should.eql({ + a.should.eql([{ topic:"debug", data:{ id:"n1", @@ -369,7 +389,7 @@ describe('debug node', function() { property:"payload", format:"Object" } - }); + }]); }, done); }); }); @@ -382,7 +402,7 @@ describe('debug node', function() { n1.emit("input", {payload: Array(1001).fill("X")}); }, function(msg) { var a = JSON.parse(msg); - a.should.eql({ + a.should.eql([{ topic:"debug", data:{ id:"n1", @@ -391,11 +411,11 @@ describe('debug node', function() { type: "array", data: Array(1000).fill("X"), length: 1001 - },null," "), + },null," "), property:"payload", format:"array[1001]" } - }); + }]); }, done); }); }); @@ -408,7 +428,7 @@ describe('debug node', function() { n1.emit("input", {payload: {foo: Array(1001).fill("X")}}); }, function(msg) { var a = JSON.parse(msg); - a.should.eql({ + a.should.eql([{ topic:"debug", data:{ id:"n1", @@ -423,7 +443,7 @@ describe('debug node', function() { property:"payload", format:"Object" } - }); + }]); }, done); }); }); @@ -436,7 +456,7 @@ describe('debug node', function() { n1.emit("input", {payload: Buffer(501).fill("\"")}); }, function(msg) { var a = JSON.parse(msg); - a.should.eql({ + a[0].should.eql({ topic:"debug", data:{ id:"n1", @@ -457,7 +477,7 @@ describe('debug node', function() { n1.emit("input", {payload: {foo: Buffer(1001).fill("X")}}); }, function(msg) { var a = JSON.parse(msg); - a.should.eql({ + a[0].should.eql({ topic:"debug", data:{ id:"n1", @@ -482,17 +502,17 @@ describe('debug node', function() { helper.load(debugNode, flow, function() { var n1 = helper.getNode("n1"); websocket_test(function() { - n1.emit("input", {payload: new Buffer('HELLO', 'utf8')}); + n1.emit("input", {payload: new Buffer.from('HELLO', 'utf8')}); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug", data:{ id:"n1", - msg: '48454c4c4f', + msg:'48454c4c4f', property:"payload", - format: "buffer[5]" + format:"buffer[5]" } - }); + }]); }, done); }); }); @@ -510,9 +530,9 @@ describe('debug node', function() { n1.emit("input", {payload:"message 2"}); }); }, function(msg) { - JSON.parse(msg).should.eql({ + JSON.parse(msg).should.eql([{ topic:"debug",data:{id:"n1",msg:"message 2",property:"payload",format:"string[9]"} - }); + }]); }, done); }); }); @@ -577,8 +597,12 @@ function websocket_test(open_callback, message_callback, done_callback) { var close_callback = function() { ws.close(); }; ws.on('open', function() { open_callback(close_callback); }); ws.on('message', function(msg) { - message_callback(msg, close_callback); - ws.close(); - done_callback(); + try { + message_callback(msg, close_callback); + ws.close(); + done_callback(); + } catch(err) { + done_callback(err); + } }); } diff --git a/test/red/api/comms_spec.js b/test/red/api/comms_spec.js index 458b92fbf..d86bd39d5 100644 --- a/test/red/api/comms_spec.js +++ b/test/red/api/comms_spec.js @@ -31,6 +31,13 @@ var address = '127.0.0.1'; var listenPort = 0; // use ephemeral port describe("api/comms", function() { + + beforeEach(function (done) { + setTimeout(function() { + done(); + }, 55); + }); + describe("with default keepalive", function() { var server; var url; @@ -72,7 +79,7 @@ describe("api/comms", function() { comms.publish('topic1', 'foo'); }); ws.on('message', function(msg) { - msg.should.equal('{"topic":"topic1","data":"foo"}'); + msg.should.equal('[{"topic":"topic1","data":"foo"}]'); ws.close(); done(); }); @@ -85,7 +92,8 @@ describe("api/comms", function() { ws.send('{"subscribe":"topic2"}'); }); ws.on('message', function(msg) { - msg.should.equal('{"topic":"topic2","data":"bar"}'); + console.log(msg); + msg.should.equal('[{"topic":"topic2","data":"bar"}]'); ws.close(); done(); }); @@ -100,7 +108,8 @@ describe("api/comms", function() { comms.publish('topic3', 'new'); }); ws.on('message', function(msg) { - msg.should.equal('{"topic":"topic3","data":"new"}'); + console.log(msg); + msg.should.equal('[{"topic":"topic3","data":"new"}]'); ws.close(); done(); }); @@ -115,7 +124,8 @@ describe("api/comms", function() { comms.publish('topic3', 'correct'); }); ws.on('message', function(msg) { - msg.should.equal('{"topic":"topic3","data":"correct"}'); + console.log(msg); + msg.should.equal('[{"topic":"topic3","data":"correct"}]'); ws.close(); done(); }); @@ -133,7 +143,8 @@ describe("api/comms", function() { comms.publish('topic4', 'bar'); }); ws.on('message', function(msg) { - msg.should.equal('{"topic":"topic4","data":"bar"}'); + console.log(msg); + msg.should.equal('[{"topic":"topic4","data":"bar"}]'); ws.close(); done(); }); @@ -325,7 +336,7 @@ describe("api/comms", function() { var ws = new WebSocket(url); var count = 0; ws.on('message', function(data) { - var msg = JSON.parse(data); + var msg = JSON.parse(data)[0]; msg.should.have.property('topic','hb'); msg.should.have.property('data').be.a.Number; count++; @@ -346,7 +357,7 @@ describe("api/comms", function() { }, 50); }); ws.on('message', function(data) { - var msg = JSON.parse(data); + var msg = JSON.parse(data)[0]; // It is possible a heartbeat message may arrive - so ignore them if (msg.topic != "hb") { msg.should.have.property('topic', 'foo'); @@ -435,7 +446,7 @@ describe("api/comms", function() { ws.send('{"subscribe":"foo"}'); comms.publish('foo', 'correct'); } else { - msg.should.equal('{"topic":"foo","data":"correct"}'); + msg.should.equal('[{"topic":"foo","data":"correct"}]'); ws.close(); } }); @@ -509,7 +520,7 @@ describe("api/comms", function() { },200); }); ws.on('message', function(msg) { - msg.should.equal('{"topic":"foo","data":"correct"}'); + msg.should.equal('[{"topic":"foo","data":"correct"}]'); count++; ws.close(); });