1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

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
This commit is contained in:
Dave Conway-Jones 2018-01-13 16:14:03 +00:00 committed by Nick O'Leary
parent 7bd8d8c3ae
commit 7b1787fdbb
9 changed files with 260 additions and 134 deletions

View File

@ -64,27 +64,31 @@ RED.comms = (function() {
} }
} }
ws.onmessage = function(event) { ws.onmessage = function(event) {
var msg = JSON.parse(event.data); var message = JSON.parse(event.data);
if (pendingAuth && msg.auth) { for (var m = 0; m < message.length; m++) {
if (msg.auth === "ok") { var msg = message[m];
pendingAuth = false; if (pendingAuth && msg.auth) {
completeConnection(); if (msg.auth === "ok") {
} else if (msg.auth === "fail") { pendingAuth = false;
// anything else is an error... completeConnection();
active = false; } else if (msg.auth === "fail") {
RED.user.login({updateMenu:true},function() { // anything else is an error...
connectWS(); active = false;
}) RED.user.login({updateMenu:true},function() {
connectWS();
})
}
} }
} else if (msg.topic) { else if (msg.topic) {
for (var t in subscriptions) { for (var t in subscriptions) {
if (subscriptions.hasOwnProperty(t)) { if (subscriptions.hasOwnProperty(t)) {
var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$"); var re = new RegExp("^"+t.replace(/([\[\]\?\(\)\\\\$\^\*\.|])/g,"\\$1").replace(/\+/g,"[^/]+").replace(/\/#$/,"(\/.*)?")+"$");
if (re.test(msg.topic)) { if (re.test(msg.topic)) {
var subscribers = subscriptions[t]; var subscribers = subscriptions[t];
if (subscribers) { if (subscribers) {
for (var i=0;i<subscribers.length;i++) { for (var i=0;i<subscribers.length;i++) {
subscribers[i](msg.topic,msg.data); subscribers[i](msg.topic,msg.data);
}
} }
} }
} }

View File

@ -6,11 +6,22 @@
<input id="node-input-complete" type="hidden"> <input id="node-input-complete" type="hidden">
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-console"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label> <label for="node-input-tosidebar"><i class="fa fa-random"></i> <span data-i18n="debug.to"></span></label>
<select type="text" id="node-input-console" style="display: inline-block; width: 250px; vertical-align: top;"> <label for="node-input-tosidebar" style="width:70%">
<option value="false" data-i18n="debug.debtab"></option> <input type="checkbox" id="node-input-tosidebar" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toSidebar"></span>
<option value="true" data-i18n="debug.tabcon"></option> </label>
</select> </div>
<div class="form-row">
<label for="node-input-console"> </label>
<label for="node-input-console" style="width:70%">
<input type="checkbox" id="node-input-console" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toConsole"></span>
</label>
</div>
<div class="form-row" id="node-tostatus-line">
<label for="node-input-tostatus"> </label>
<label for="node-input-tostatus" style="width:70%">
<input type="checkbox" id="node-input-tostatus" style="display:inline-block; width:22px; vertical-align:baseline;"><span data-i18n="debug.toStatus"></span>
</label>
</div> </div>
<div class="form-row"> <div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label> <label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="common.label.name"></span></label>
@ -26,7 +37,7 @@
<p>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. <p>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.</p> Clicking on the source node id will reveal that node within the workspace.</p>
<p>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.</p> <p>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.</p>
<p>The node can also be configured to send all messages to the runtime log.</p> <p>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.</p>
</script> </script>
<script src="debug/view/debug-utils.js"></script> <script src="debug/view/debug-utils.js"></script>
@ -38,7 +49,9 @@
defaults: { defaults: {
name: {value:""}, name: {value:""},
active: {value:true}, active: {value:true},
console: {value:"false"}, tosidebar: {value:true},
console: {value:false},
tostatus: {value:false},
complete: {value:"false", required:true} complete: {value:"false", required:true}
}, },
label: function() { label: function() {
@ -100,7 +113,6 @@
} }
}, },
onpaletteadd: function() { onpaletteadd: function() {
var options = { var options = {
messageMouseEnter: function(sourceId) { messageMouseEnter: function(sourceId) {
if (sourceId) { if (sourceId) {
@ -148,7 +160,7 @@
var that = this; var that = this;
RED._debug = function(msg) { RED._debug = function(msg) {
that.handleDebugMessage("",{ that.handleDebugMessage("", {
name:"debug", name:"debug",
msg:msg msg:msg
}); });
@ -170,7 +182,6 @@
var sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z); var sourceNode = RED.nodes.node(o.id) || RED.nodes.node(o.z);
if (sourceNode) { if (sourceNode) {
o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name}; o._source = {id:sourceNode.id,z:sourceNode.z,name:sourceNode.name};
} }
RED.debug.handleDebugMessage(o); RED.debug.handleDebugMessage(o);
if (subWindow) { if (subWindow) {
@ -225,6 +236,15 @@
delete RED._debug; delete RED._debug;
}, },
oneditprepare: function() { 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}]}); $("#node-input-typed-complete").typedInput({types:['msg', {value:"full",label:RED._("node-red:debug.msgobj"),hasValue:false}]});
if (this.complete === "true" || this.complete === true) { if (this.complete === "true" || this.complete === true) {
// show complete message object // show complete message object
@ -240,6 +260,16 @@
) { ) {
$("#node-input-typed-complete").typedInput('value','payload'); $("#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() { oneditsave: function() {
@ -250,7 +280,6 @@
$("#node-input-complete").val($("#node-input-typed-complete").typedInput('value')); $("#node-input-complete").val($("#node-input-typed-complete").typedInput('value'));
} }
} }
}); });
})(); })();
</script> </script>

View File

@ -5,7 +5,7 @@ module.exports = function(RED) {
var events = require("events"); var events = require("events");
var path = require("path"); var path = require("path");
var safeJSONStringify = require("json-stringify-safe"); var safeJSONStringify = require("json-stringify-safe");
var debuglength = RED.settings.debugMaxLength||1000; var debuglength = RED.settings.debugMaxLength || 1000;
var useColors = RED.settings.debugUseColors || false; var useColors = RED.settings.debugUseColors || false;
util.inspect.styles.boolean = "red"; util.inspect.styles.boolean = "red";
@ -13,26 +13,49 @@ module.exports = function(RED) {
RED.nodes.createNode(this,n); RED.nodes.createNode(this,n);
this.name = n.name; this.name = n.name;
this.complete = (n.complete||"payload").toString(); this.complete = (n.complete||"payload").toString();
if (this.complete === "false") { this.complete = "payload"; }
if (this.complete === "false") { this.console = ""+(n.console || false);
this.complete = "payload"; this.tostatus = n.tostatus || false;
} this.tosidebar = n.tosidebar;
if (this.tosidebar === undefined) { this.tosidebar = true; }
this.console = n.console; this.severity = n.severity || 40;
this.active = (n.active === null || typeof n.active === "undefined") || n.active; this.active = (n.active === null || typeof n.active === "undefined") || n.active;
this.status({});
var node = this; 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) { this.on("input",function(msg) {
if (this.complete === "true") { if (this.complete === "true") {
// debug complete msg object // debug complete msg object
if (this.console === "true") { if (this.console === "true") {
node.log("\n"+util.inspect(msg, {colors:useColors, depth:10})); node.log("\n"+util.inspect(msg, {colors:useColors, depth:10}));
} }
if (this.active) { if (this.active && this.tosidebar) {
sendDebug({id:node.id,name:node.name,topic:msg.topic,msg:msg,_path:msg._path}); 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 property = "payload";
var output = msg[property]; var output = msg[property];
if (this.complete !== "false" && typeof this.complete !== "undefined") { if (this.complete !== "false" && typeof this.complete !== "undefined") {
@ -53,7 +76,15 @@ module.exports = function(RED) {
} }
} }
if (this.active) { 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") { if (state === "enable") {
node.active = true; node.active = true;
res.sendStatus(200); res.sendStatus(200);
if (node.tostatus) { node.status({}); }
} else if (state === "disable") { } else if (state === "disable") {
node.active = false; node.active = false;
res.sendStatus(201); res.sendStatus(201);
if (node.tostatus && node.hasOwnProperty("oldStatus")) {
node.oldStatus.shape = "ring";
node.status(node.oldStatus);
}
} else { } else {
res.sendStatus(404); res.sendStatus(404);
} }

View File

@ -439,7 +439,9 @@ RED.debug = (function() {
$('<span class="debug-message-name">'+name+'</span>').appendTo(metaRow); $('<span class="debug-message-name">'+name+'</span>').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); payload = JSON.parse(payload);
} else if (/error/i.test(format)) { } else if (/error/i.test(format)) {
payload = JSON.parse(payload); payload = JSON.parse(payload);

View File

@ -103,9 +103,13 @@
"output": "Output", "output": "Output",
"msgprop": "message property", "msgprop": "message property",
"msgobj": "complete msg object", "msgobj": "complete msg object",
"to": "to", "to": "To",
"debtab": "debug tab", "debtab": "debug tab",
"tabcon": "debug tab and console", "tabcon": "debug tab and console",
"toSidebar": "debug window",
"toConsole": "system console",
"toStatus": "node status (32 characters)",
"severity": "Level",
"notification": { "notification": {
"activated": "Successfully activated: __label__", "activated": "Successfully activated: __label__",
"deactivated": "Successfully deactivated: __label__" "deactivated": "Successfully deactivated: __label__"

View File

@ -63,7 +63,7 @@ function start() {
// https://github.com/websockets/ws/pull/632 // https://github.com/websockets/ws/pull/632
// that is fixed in the 1.x release of the ws module // that is fixed in the 1.x release of the ws module
// that we cannot currently pickup as it drops node 0.10 support // that we cannot currently pickup as it drops node 0.10 support
perMessageDeflate: false //perMessageDeflate: false
}); });
wsServer.on('connection',function(ws) { wsServer.on('connection',function(ws) {
@ -189,15 +189,27 @@ function publish(topic,data,retain) {
} }
} }
var stack = [];
var ok2tx = true;
function publishTo(ws,topic,data) { function publishTo(ws,topic,data) {
var msg = JSON.stringify({topic:topic,data:data}); if (topic && data) { stack.push({topic:topic,data:data}); }
try {
ws.send(msg); if (ok2tx && (stack.length > 0)) {
} catch(err) { ok2tx = false;
removeActiveConnection(ws); try {
removePendingConnection(ws); ws.send(JSON.stringify(stack));
log.warn(log._("comms.error-send",{message:err.toString()})); } 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) { function handleRemoteSubscription(ws,topic) {

View File

@ -51,10 +51,14 @@ describe('inject node', function() {
function() { function() {
var n2 = helper.getNode("n2"); var n2 = helper.getNode("n2");
n2.on("input", function(msg) { n2.on("input", function(msg) {
msg.should.have.property('topic', 't1'); try {
msg.should.have.property('payload'); msg.should.have.property('topic', 't1');
should(msg.payload).be.lessThan(timestamp.getTime()); msg.should.have.property('payload');
done(); should(msg.payload).be.lessThan(timestamp.getTime());
done();
} catch(err) {
done(err);
}
}); });
}); });
}); });

View File

@ -25,13 +25,19 @@ describe('debug node', function() {
helper.startServer(done); helper.startServer(done);
}); });
beforeEach(function (done) {
setTimeout(function() {
done();
}, 55);
});
afterEach(function() { afterEach(function() {
helper.unload(); helper.unload();
}); });
it('should be loaded', function(done) { 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() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
n1.should.have.property('name', 'Debug'); n1.should.have.property('name', 'Debug');
@ -41,31 +47,31 @@ describe('debug node', function() {
}); });
it('should publish on input', function(done) { 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() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload:"test"}); n1.emit("input", {payload:"test"});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug",data:{id:"n1",name:"Debug",msg:"test", topic:"debug",data:{id:"n1",name:"Debug",msg:"test",
format:"string[4]",property:"payload"} format:"string[4]",property:"payload"}
}); }]);
}, done); }, done);
}); });
}); });
it('should publish to console', function(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() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
var count = 0; var count = 0;
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload:"test"}); n1.emit("input", {payload:"test"});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug",data:{id:"n1",msg:"test",property:"payload",format:"string[4]"} topic:"debug",data:{id:"n1",msg:"test",property:"payload",format:"string[4]"}
}); }]);
count++; count++;
}, function() { }, function() {
try { try {
@ -86,31 +92,31 @@ describe('debug node', function() {
}); });
it('should publish complete message', function(done) { 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() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload:"test"}); n1.emit("input", {payload:"test"});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug", topic:"debug",
data:{id:"n1",msg:'{\n "payload": "test"\n}',format:"Object"} data:{id:"n1",msg:'{\n "payload": "test"\n}',format:"Object"}
}); }]);
}, done); }, done);
}); });
}); });
it('should publish complete message to console', function(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() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload:"test"}); n1.emit("input", {payload:"test"});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug", topic:"debug",
data:{id:"n1",msg:'{\n "payload": "test"\n}',format:"Object"} data:{id:"n1",msg:'{\n "payload": "test"\n}',format:"Object"}
}); }]);
}, function() { }, function() {
try { try {
helper.log().called.should.be.true(); helper.log().called.should.be.true();
@ -129,29 +135,29 @@ describe('debug node', function() {
}); });
it('should publish other property', function(done) { 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() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload:"test", foo:"bar"}); n1.emit("input", {payload:"test", foo:"bar"});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug",data:{id:"n1",msg:"bar",property:"foo",format:"string[3]"} topic:"debug",data:{id:"n1",msg:"bar",property:"foo",format:"string[3]"}
}); }]);
}, done); }, done);
}); });
}); });
it('should publish multi-level properties', function(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() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload:"test", foo: {bar: "bar"}}); n1.emit("input", {payload:"test", foo: {bar:"bar"}});
}, function(msg) { }, 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]"} topic:"debug",data:{id:"n1",msg:"bar",property:"foo.bar",format:"string[3]"}
}); }]);
}, done); }, done);
}); });
}); });
@ -163,9 +169,9 @@ describe('debug node', function() {
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: new Error("oops")}); n1.emit("input", {payload: new Error("oops")});
}, function(msg) { }, 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"} topic:"debug",data:{id:"n1",msg:'{"name":"Error","message":"oops"}',property:"payload",format:"error"}
}); }]);
}, done); }, done);
}); });
}); });
@ -177,9 +183,9 @@ describe('debug node', function() {
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: true}); n1.emit("input", {payload: true});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug",data:{id:"n1",msg: 'true',property:"payload",format:"boolean"} topic:"debug",data:{id:"n1",msg: 'true',property:"payload",format:"boolean"}
}); }]);
}, done); }, done);
}); });
}); });
@ -191,9 +197,23 @@ describe('debug node', function() {
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: 7}); n1.emit("input", {payload: 7});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug",data:{id:"n1",msg:"7",property:"payload",format:"number"} 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); }, done);
}); });
}); });
@ -205,9 +225,9 @@ describe('debug node', function() {
websocket_test(function() { websocket_test(function() {
n1.emit("input", {}); n1.emit("input", {});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug",data:{id:"n1",msg: '(undefined)',property:"payload",format:"undefined"} topic:"debug",data:{id:"n1",msg:'(undefined)',property:"payload",format:"undefined"}
}); }]);
}, done); }, done);
}); });
}); });
@ -217,11 +237,11 @@ describe('debug node', function() {
helper.load(debugNode, flow, function() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: null}); n1.emit("input", {payload:null});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug",data:{id:"n1",msg:'(undefined)',property:"payload",format:"null"} topic:"debug",data:{id:"n1",msg:'(undefined)',property:"payload",format:"null"}
}); }]);
}, done); }, done);
}); });
}); });
@ -233,10 +253,10 @@ describe('debug node', function() {
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: {type:'foo'}}); n1.emit("input", {payload: {type:'foo'}});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug", topic:"debug",
data:{id:"n1",msg:'{\n "type": "foo"\n}',property:"payload",format:"Object"} data:{id:"n1",msg:'{\n "type": "foo"\n}',property:"payload",format:"Object"}
}); }]);
}, done); }, done);
}); });
}); });
@ -248,11 +268,11 @@ describe('debug node', function() {
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: [0,1,2,3]}); n1.emit("input", {payload: [0,1,2,3]});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug", topic:"debug",
data:{id:"n1",msg: '[\n 0,\n 1,\n 2,\n 3\n]',format:"array[4]", data:{id:"n1",msg: '[\n 0,\n 1,\n 2,\n 3\n]',format:"array[4]",
property:"payload"} property:"payload"}
}); }]);
}, done); }, done);
}); });
}); });
@ -266,28 +286,28 @@ describe('debug node', function() {
o.o = o; o.o = o;
n1.emit("input", {payload: o}); n1.emit("input", {payload: o});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug", topic:"debug",
data:{ data:{
id:"n1", id:"n1",
msg:'{\n "name": "bar",\n "o": "[Circular ~]"\n}', msg:'{\n "name": "bar",\n "o": "[Circular ~]"\n}',
property:"payload",format:"Object" property:"payload",format:"Object"
} }
}); }]);
}, done); }, done);
}); });
}); });
it('should publish an object to console', function(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() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: {type:'foo'}}); n1.emit("input", {payload: {type:'foo'}});
}, function(msg) { }, 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"} topic:"debug",data:{id:"n1",msg:'{\n "type": "foo"\n}',property:"payload",format:"Object"}
}); }]);
}, function() { }, function() {
try { try {
helper.log().called.should.be.true(); 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) { 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() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: "test\ntest"}); n1.emit("input", {payload:"test\ntest"});
}, function(msg) { }, 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]"} topic:"debug",data:{id:"n1",msg:"test\ntest",property:"payload",format:"string[9]"}
}); }]);
}, function() { }, function() {
try { try {
helper.log().called.should.be.true(); helper.log().called.should.be.true();
@ -337,10 +357,10 @@ describe('debug node', function() {
helper.load(debugNode, flow, function() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: Array(1002).join("X")}); n1.emit("input", {payload:Array(1002).join("X")});
}, function(msg) { }, function(msg) {
var a = JSON.parse(msg); var a = JSON.parse(msg);
a.should.eql({ a.should.eql([{
topic:"debug", topic:"debug",
data:{ data:{
id:"n1", id:"n1",
@ -348,7 +368,7 @@ describe('debug node', function() {
property:"payload", property:"payload",
format:"string[1001]" format:"string[1001]"
} }
}); }]);
}, done); }, done);
}); });
}); });
@ -361,7 +381,7 @@ describe('debug node', function() {
n1.emit("input", {payload: {foo: Array(1002).join("X")}}); n1.emit("input", {payload: {foo: Array(1002).join("X")}});
}, function(msg) { }, function(msg) {
var a = JSON.parse(msg); var a = JSON.parse(msg);
a.should.eql({ a.should.eql([{
topic:"debug", topic:"debug",
data:{ data:{
id:"n1", id:"n1",
@ -369,7 +389,7 @@ describe('debug node', function() {
property:"payload", property:"payload",
format:"Object" format:"Object"
} }
}); }]);
}, done); }, done);
}); });
}); });
@ -382,7 +402,7 @@ describe('debug node', function() {
n1.emit("input", {payload: Array(1001).fill("X")}); n1.emit("input", {payload: Array(1001).fill("X")});
}, function(msg) { }, function(msg) {
var a = JSON.parse(msg); var a = JSON.parse(msg);
a.should.eql({ a.should.eql([{
topic:"debug", topic:"debug",
data:{ data:{
id:"n1", id:"n1",
@ -391,11 +411,11 @@ describe('debug node', function() {
type: "array", type: "array",
data: Array(1000).fill("X"), data: Array(1000).fill("X"),
length: 1001 length: 1001
},null," "), },null," "),
property:"payload", property:"payload",
format:"array[1001]" format:"array[1001]"
} }
}); }]);
}, done); }, done);
}); });
}); });
@ -408,7 +428,7 @@ describe('debug node', function() {
n1.emit("input", {payload: {foo: Array(1001).fill("X")}}); n1.emit("input", {payload: {foo: Array(1001).fill("X")}});
}, function(msg) { }, function(msg) {
var a = JSON.parse(msg); var a = JSON.parse(msg);
a.should.eql({ a.should.eql([{
topic:"debug", topic:"debug",
data:{ data:{
id:"n1", id:"n1",
@ -423,7 +443,7 @@ describe('debug node', function() {
property:"payload", property:"payload",
format:"Object" format:"Object"
} }
}); }]);
}, done); }, done);
}); });
}); });
@ -436,7 +456,7 @@ describe('debug node', function() {
n1.emit("input", {payload: Buffer(501).fill("\"")}); n1.emit("input", {payload: Buffer(501).fill("\"")});
}, function(msg) { }, function(msg) {
var a = JSON.parse(msg); var a = JSON.parse(msg);
a.should.eql({ a[0].should.eql({
topic:"debug", topic:"debug",
data:{ data:{
id:"n1", id:"n1",
@ -457,7 +477,7 @@ describe('debug node', function() {
n1.emit("input", {payload: {foo: Buffer(1001).fill("X")}}); n1.emit("input", {payload: {foo: Buffer(1001).fill("X")}});
}, function(msg) { }, function(msg) {
var a = JSON.parse(msg); var a = JSON.parse(msg);
a.should.eql({ a[0].should.eql({
topic:"debug", topic:"debug",
data:{ data:{
id:"n1", id:"n1",
@ -482,17 +502,17 @@ describe('debug node', function() {
helper.load(debugNode, flow, function() { helper.load(debugNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
websocket_test(function() { websocket_test(function() {
n1.emit("input", {payload: new Buffer('HELLO', 'utf8')}); n1.emit("input", {payload: new Buffer.from('HELLO', 'utf8')});
}, function(msg) { }, function(msg) {
JSON.parse(msg).should.eql({ JSON.parse(msg).should.eql([{
topic:"debug", topic:"debug",
data:{ data:{
id:"n1", id:"n1",
msg: '48454c4c4f', msg:'48454c4c4f',
property:"payload", property:"payload",
format: "buffer[5]" format:"buffer[5]"
} }
}); }]);
}, done); }, done);
}); });
}); });
@ -510,9 +530,9 @@ describe('debug node', function() {
n1.emit("input", {payload:"message 2"}); n1.emit("input", {payload:"message 2"});
}); });
}, function(msg) { }, 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]"} topic:"debug",data:{id:"n1",msg:"message 2",property:"payload",format:"string[9]"}
}); }]);
}, done); }, done);
}); });
}); });
@ -577,8 +597,12 @@ function websocket_test(open_callback, message_callback, done_callback) {
var close_callback = function() { ws.close(); }; var close_callback = function() { ws.close(); };
ws.on('open', function() { open_callback(close_callback); }); ws.on('open', function() { open_callback(close_callback); });
ws.on('message', function(msg) { ws.on('message', function(msg) {
message_callback(msg, close_callback); try {
ws.close(); message_callback(msg, close_callback);
done_callback(); ws.close();
done_callback();
} catch(err) {
done_callback(err);
}
}); });
} }

View File

@ -31,6 +31,13 @@ var address = '127.0.0.1';
var listenPort = 0; // use ephemeral port var listenPort = 0; // use ephemeral port
describe("api/comms", function() { describe("api/comms", function() {
beforeEach(function (done) {
setTimeout(function() {
done();
}, 55);
});
describe("with default keepalive", function() { describe("with default keepalive", function() {
var server; var server;
var url; var url;
@ -72,7 +79,7 @@ describe("api/comms", function() {
comms.publish('topic1', 'foo'); comms.publish('topic1', 'foo');
}); });
ws.on('message', function(msg) { ws.on('message', function(msg) {
msg.should.equal('{"topic":"topic1","data":"foo"}'); msg.should.equal('[{"topic":"topic1","data":"foo"}]');
ws.close(); ws.close();
done(); done();
}); });
@ -85,7 +92,8 @@ describe("api/comms", function() {
ws.send('{"subscribe":"topic2"}'); ws.send('{"subscribe":"topic2"}');
}); });
ws.on('message', function(msg) { ws.on('message', function(msg) {
msg.should.equal('{"topic":"topic2","data":"bar"}'); console.log(msg);
msg.should.equal('[{"topic":"topic2","data":"bar"}]');
ws.close(); ws.close();
done(); done();
}); });
@ -100,7 +108,8 @@ describe("api/comms", function() {
comms.publish('topic3', 'new'); comms.publish('topic3', 'new');
}); });
ws.on('message', function(msg) { ws.on('message', function(msg) {
msg.should.equal('{"topic":"topic3","data":"new"}'); console.log(msg);
msg.should.equal('[{"topic":"topic3","data":"new"}]');
ws.close(); ws.close();
done(); done();
}); });
@ -115,7 +124,8 @@ describe("api/comms", function() {
comms.publish('topic3', 'correct'); comms.publish('topic3', 'correct');
}); });
ws.on('message', function(msg) { ws.on('message', function(msg) {
msg.should.equal('{"topic":"topic3","data":"correct"}'); console.log(msg);
msg.should.equal('[{"topic":"topic3","data":"correct"}]');
ws.close(); ws.close();
done(); done();
}); });
@ -133,7 +143,8 @@ describe("api/comms", function() {
comms.publish('topic4', 'bar'); comms.publish('topic4', 'bar');
}); });
ws.on('message', function(msg) { ws.on('message', function(msg) {
msg.should.equal('{"topic":"topic4","data":"bar"}'); console.log(msg);
msg.should.equal('[{"topic":"topic4","data":"bar"}]');
ws.close(); ws.close();
done(); done();
}); });
@ -325,7 +336,7 @@ describe("api/comms", function() {
var ws = new WebSocket(url); var ws = new WebSocket(url);
var count = 0; var count = 0;
ws.on('message', function(data) { 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('topic','hb');
msg.should.have.property('data').be.a.Number; msg.should.have.property('data').be.a.Number;
count++; count++;
@ -346,7 +357,7 @@ describe("api/comms", function() {
}, 50); }, 50);
}); });
ws.on('message', function(data) { 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 // It is possible a heartbeat message may arrive - so ignore them
if (msg.topic != "hb") { if (msg.topic != "hb") {
msg.should.have.property('topic', 'foo'); msg.should.have.property('topic', 'foo');
@ -435,7 +446,7 @@ describe("api/comms", function() {
ws.send('{"subscribe":"foo"}'); ws.send('{"subscribe":"foo"}');
comms.publish('foo', 'correct'); comms.publish('foo', 'correct');
} else { } else {
msg.should.equal('{"topic":"foo","data":"correct"}'); msg.should.equal('[{"topic":"foo","data":"correct"}]');
ws.close(); ws.close();
} }
}); });
@ -509,7 +520,7 @@ describe("api/comms", function() {
},200); },200);
}); });
ws.on('message', function(msg) { ws.on('message', function(msg) {
msg.should.equal('{"topic":"foo","data":"correct"}'); msg.should.equal('[{"topic":"foo","data":"correct"}]');
count++; count++;
ws.close(); ws.close();
}); });