From a281b8c74e8e77a7d27bcf1c7d778c9b5d4997d1 Mon Sep 17 00:00:00 2001 From: Dave Conway-Jones Date: Thu, 13 Apr 2017 11:36:54 +0100 Subject: [PATCH] Make exec node spawn and exec outputs more consistent (with an option to revert if necessary) and new info docs --- nodes/core/core/75-exec.html | 35 ++++-- nodes/core/core/75-exec.js | 27 +++-- test/nodes/core/core/75-exec_spec.js | 175 ++++++++++++--------------- 3 files changed, 121 insertions(+), 116 deletions(-) diff --git a/nodes/core/core/75-exec.html b/nodes/core/core/75-exec.html index 2285689d5..985653d8b 100644 --- a/nodes/core/core/75-exec.html +++ b/nodes/core/core/75-exec.html @@ -21,17 +21,24 @@
- +  msg.payload
+
+ + +
- - + +
@@ -74,11 +81,10 @@
the standard error of the command.
-
  • Return code
    -
    payload number
    -
    the return code of the command.
    +
    payload object
    +
    an object containing the return code, and possibly message, signal properties.
  • @@ -86,8 +92,10 @@

    By default uses the exec system call which calls the command, waits for it to complete, and then returns the output. For example a successful command should have a return code of { code: 0 }.

    Optionally can use spawn instead, which returns the output from stdout and stderr - as the command runs, usually one line at a time. On completion it then returns a numeric return code - on the 3rd port. For example, a successful command should return 0.

    + as the command runs, usually one line at a time. On completion it then returns an object + on the 3rd port. For example, a successful command should return { code: 0 }.

    +

    Errors may return extra information on the 3rd port msg.payload, such as a message string, + signal string.

    The command that is run is defined within the node, with an option to append msg.payload and a further set of parameters.

    Commands or parameters with spaces should be enclosed in quotes - "This is a single parameter"

    The returned payload is usually a string, unless non-UTF8 characters are detected, in which @@ -95,7 +103,8 @@

    The node's status icon and PID will be visible while the node is active. Changes to this can be read by the Status node.

    Killing processes

    Sending msg.kill will kill a single active process. msg.kill should be a string containing - the type of signal to be sent, for example, SIGINT, SIGQUIT or SIGHUP. Defaults to SIGTERM if set to an empty string.

    + the type of signal to be sent, for example, SIGINT, SIGQUIT or SIGHUP. + Defaults to SIGTERM if set to an empty string.

    If the node has more than one process running then msg.pid must also be set with the value of the PID to be killed.

    Tip: if running a Python app you may need to use the -u parameter to stop the output being buffered.

    @@ -108,8 +117,9 @@ command: {value:""}, addpay: {value:true}, append: {value:""}, - useSpawn: {value:""}, + useSpawn: {value:"false"}, timer: {value:""}, + oldrc: {value:false}, name: {value:""} }, inputs:1, @@ -122,6 +132,11 @@ }, labelStyle: function() { return this.name?"node_label_italic":""; + }, + oneditprepare: function() { + if ($("#node-input-useSpawn").val() === null) { + $("#node-input-useSpawn").val(this.useSpawn.toString()); + } } }); diff --git a/nodes/core/core/75-exec.js b/nodes/core/core/75-exec.js index b97d2b3a9..757cb9b2d 100644 --- a/nodes/core/core/75-exec.js +++ b/nodes/core/core/75-exec.js @@ -26,15 +26,16 @@ module.exports = function(RED) { if (n.addpay === undefined) { n.addpay = true; } this.addpay = n.addpay; this.append = (n.append || "").trim(); - this.useSpawn = n.useSpawn; + this.useSpawn = (n.useSpawn == "true"); this.timer = Number(n.timer || 0)*1000; this.activeProcesses = {}; + this.oldrc = (n.oldrc || false).toString(); var node = this; var cleanup = function(p) { node.activeProcesses[p].kill(); - node.status({fill:"red",shape:"dot",text:"timeout"}); - node.error("Exec node timeout"); + //node.status({fill:"red",shape:"dot",text:"timeout"}); + //node.error("Exec node timeout"); } this.on("input", function(msg) { @@ -89,13 +90,17 @@ module.exports = function(RED) { node.send([null,RED.util.cloneMessage(msg),null]); } }); - child.on('close', function (code) { + child.on('close', function (code,signal) { if (unknownCommand || (node.activeProcesses.hasOwnProperty(child.pid) && node.activeProcesses[child.pid] !== null)) { delete node.activeProcesses[child.pid]; if (child.tout) { clearTimeout(child.tout); } msg.payload = code; + if (node.oldrc === "false") { + msg.payload = {code:code}; + if (signal) { msg.payload.signal = signal; } + } if (code === 0) { node.status({}); } - if (code === null) { node.status({fill:"red",shape:"dot",text:"timeout"}); } + if (code === null) { node.status({fill:"red",shape:"dot",text:"killed"}); } else if (code < 0) { node.status({fill:"red",shape:"dot",text:"rc:"+code}); } else { node.status({fill:"yellow",shape:"dot",text:"rc:"+code}); } node.send([null,null,RED.util.cloneMessage(msg)]); @@ -127,10 +132,12 @@ module.exports = function(RED) { //console.log('[exec] stdout: ' + stdout); //console.log('[exec] stderr: ' + stderr); if (error !== null) { - msg3 = {payload:error}; - node.status({fill:"red",shape:"dot",text:"error: "+error.code}); - //console.log('[exec] error: ' + error); - } else { + msg3 = {payload:{code:error.code, message:error.message}}; + if (error.signal) { msg3.payload.signal = error.signal; } + if (error.code === null) { node.status({fill:"red",shape:"dot",text:"killed"}); } + else { node.status({fill:"red",shape:"dot",text:"error:"+error.code}); } + node.log('error:' + error); + } else if (node.oldrc === "false") { msg3 = {payload:{code:0}}; } if (!msg3) { node.status({}); } @@ -147,7 +154,7 @@ module.exports = function(RED) { } } }); - + this.on('close',function() { for (var pid in node.activeProcesses) { /* istanbul ignore else */ diff --git a/test/nodes/core/core/75-exec_spec.js b/test/nodes/core/core/75-exec_spec.js index 94e32af5c..5e70219b3 100644 --- a/test/nodes/core/core/75-exec_spec.js +++ b/test/nodes/core/core/75-exec_spec.js @@ -43,6 +43,7 @@ describe('exec node', function() { n1.should.have.property("append", ""); n1.should.have.property("addpay",true); n1.should.have.property("timer",0); + n1.should.have.property("oldrc","false"); done(); }); }); @@ -50,11 +51,10 @@ describe('exec node', function() { describe('calling exec', function() { it('should exec a simple command', function(done) { - var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:false, append:""}, + var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:false, append:"", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; var spy = sinon.stub(child_process, 'exec', function(arg1, arg2, arg3, arg4) { - //console.log(arg1); // arg3(error,stdout,stderr); arg3(null,arg1,arg1.toUpperCase()); }); @@ -67,7 +67,7 @@ describe('exec node', function() { var received = 0; var messages = [null,null,null]; var completeTest = function() { - received++; + received = received + 1; if (received < 3) { return; } @@ -79,7 +79,7 @@ describe('exec node', function() { msg = messages[1]; msg.should.have.property("payload"); - msg.payload.should.be.a.String; + msg.payload.should.be.a.String(); msg.payload.should.equal("ECHO"); msg = messages[2]; @@ -110,7 +110,7 @@ describe('exec node', function() { }); it('should exec a simple command with extra parameters', function(done) { - var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more"}, + var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; var spy = sinon.stub(child_process, 'exec', function(arg1, arg2, arg3, arg4) { @@ -163,7 +163,7 @@ describe('exec node', function() { }); it('should be able to return a binary buffer', function(done) { - var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more"}, + var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; var spy = sinon.stub(child_process, 'exec', function(arg1, arg2, arg3, arg4) { @@ -197,10 +197,10 @@ describe('exec node', function() { var flow; if (osType === "Windows_NT") { // Although Windows timeout command is equivalent to sleep, this cannot be used because it promptly outputs a message. - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"0.3"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"0.3", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"0.3"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"0.3", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; } helper.load(execNode, flow, function() { @@ -210,17 +210,17 @@ describe('exec node', function() { var n4 = helper.getNode("n4"); n4.on("input", function(msg) { msg.should.have.property("payload"); - msg.payload.should.have.property("killed",true); + msg.payload.should.have.property("signal","SIGTERM"); //done(); }); setTimeout(function() { var logEvents = helper.log().args.filter(function(evt) { return evt[0].type == "exec"; }); - var i = logEvents.length - 1; + var i = logEvents.length - 2; //logEvents.should.have.length(1); - logEvents[i][0].should.have.a.property('msg'); - logEvents[i][0].msg.toString().should.startWith("Exec node timeout"); + logEvents[0][0].should.have.a.property('msg'); + logEvents[0][0].msg.toString().should.startWith("error:Error: Command"); done(); },400); n1.receive({}); @@ -230,10 +230,10 @@ describe('exec node', function() { it('should be able to kill a long running command', function(done) { var flow; if (osType === "Windows_NT") { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; } helper.load(execNode, flow, function() { @@ -244,7 +244,6 @@ describe('exec node', function() { n4.on("input", function(msg) { try { msg.should.have.property("payload"); - msg.payload.should.have.property("killed",true); msg.payload.should.have.property("signal","SIGTERM"); done(); } catch(err) { @@ -260,11 +259,12 @@ describe('exec node', function() { it('should be able to kill a long running command - SIGINT', function(done) { var flow; + var sig = "SIGINT"; if (osType === "Windows_NT") { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; } helper.load(execNode, flow, function() { @@ -275,8 +275,7 @@ describe('exec node', function() { n4.on("input", function(msg) { try { msg.should.have.property("payload"); - msg.payload.should.have.property("killed",true); - //msg.payload.should.have.property("signal","SIGINT"); + msg.payload.should.have.property("signal",sig); done(); } catch(err) { done(err); @@ -291,7 +290,7 @@ describe('exec node', function() { it('should return the rc for a failing command', function(done) { - var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"error", addpay:false, append:""}, + var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"error", addpay:false, append:"", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; var spy = sinon.stub(child_process, 'exec', function(arg1, arg2, arg3, arg4) { @@ -319,7 +318,7 @@ describe('exec node', function() { msg = messages[1]; msg.should.have.property("payload"); - msg.payload.should.be.a.String; + msg.payload.should.be.a.String(); msg.payload.should.equal("ERROR"); msg = messages[2]; @@ -358,11 +357,11 @@ describe('exec node', function() { var expected; if (osType === "Windows_NT") { // Need to use cmd to spawn a process because Windows echo command is a built-in command and cannot be spawned. - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo", addpay:true, append:"", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo", addpay:true, append:"", useSpawn:true, oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; expected = "hello world\r\n"; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"", useSpawn:true, oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; expected = "hello world\n"; } @@ -392,11 +391,11 @@ describe('exec node', function() { var flow; var expected; if (osType === "Windows_NT") { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo", addpay:true, append:" deg C", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo", addpay:true, append:" deg C", useSpawn:true, oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; expected = "12345 deg C\r\n"; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:" deg C", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:" deg C", useSpawn:true, oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; expected = "12345 deg C\n"; } @@ -421,11 +420,11 @@ describe('exec node', function() { var flow; var expected; if (osType === "Windows_NT") { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo", addpay:true, append:"", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo", addpay:true, append:"", useSpawn:true, oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; - expected = 8; + expected = 6; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"", useSpawn:true, oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; expected = 7; } @@ -453,11 +452,11 @@ describe('exec node', function() { var flow; var expected; if (osType === "Windows_NT") { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo this now works", addpay:false, append:"", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo this now works", addpay:false, append:"", useSpawn:true, oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; expected = "this now works\r\n"; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo this now works", addpay:false, append:"", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo this now works", addpay:false, append:"", useSpawn:true, oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; expected = "this now works\n"; } @@ -482,8 +481,7 @@ describe('exec node', function() { msg = messages[1]; msg.should.have.property("payload"); should.exist(msg.payload); - msg.payload.should.be.a.Number(); - msg.payload.should.equal(0); + msg.payload.should.have.property("code",0); done(); } catch(err) { done(err); @@ -503,42 +501,33 @@ describe('exec node', function() { }); }); - if (!/^v0.10/.test(process.version)) { - it('should return an error for a bad command', function(done) { - var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"madeupcommandshouldfail", addpay:false, append:"", useSpawn:true}, - {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; - helper.load(execNode, flow, function() { - var n1 = helper.getNode("n1"); - var n2 = helper.getNode("n2"); - var n3 = helper.getNode("n3"); - var n4 = helper.getNode("n4"); - n4.on("input", function(msg) { - if (/^v0.10/.test(process.version)) { - msg.should.have.property("payload"); - msg.payload.should.be.a.Number(); - msg.payload.should.be.below(0); - } else { - msg.should.have.property("payload"); - msg.payload.should.be.a.Number(); - msg.payload.should.be.below(0); - } - done(); - }); - n1.receive({payload:null}); + it('should return an error for a bad command', function(done) { + var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"madeupcommandshouldfail", addpay:false, append:"", useSpawn:"true", oldrc:"false"}, + {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; + helper.load(execNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + var n3 = helper.getNode("n3"); + var n4 = helper.getNode("n4"); + n4.on("input", function(msg) { + msg.should.have.property("payload"); + msg.payload.should.have.property("code",-2); + done(); }); + n1.receive({payload:null}); }); - } + }); it('should return an error for a failing command', function(done) { var flow; var expected; if (osType === "Windows_NT") { // Cannot use mkdir because Windows mkdir command automatically creates non-existent directories. - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping /foo/bar/doo/dah", addpay:false, append:"", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping /foo/bar/doo/dah", addpay:false, append:"", useSpawn:"true", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; expected = "IP address must be specified."; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"mkdir /foo/bar/doo/dah", addpay:false, append:"", useSpawn:true}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"mkdir /foo/bar/doo/dah", addpay:false, append:"", useSpawn:"true", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; expected = "mkdir: /foo/bar/doo: No such file or directory\n"; } @@ -553,7 +542,8 @@ describe('exec node', function() { msg.payload.should.equal(expected); }); n4.on("input", function(msg) { - msg.should.have.property("payload",1); + msg.should.have.property("payload"); + msg.payload.should.have.property("code",1); done(); }); n1.receive({payload:null}); @@ -563,41 +553,34 @@ describe('exec node', function() { it('should be able to timeout a long running command', function(done) { var flow; if (osType === "Windows_NT") { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"0.3"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"0.3", useSpawn:"true", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"0.3", useSpawn:true}, - {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; - } - helper.load(execNode, flow, function() { - var n1 = helper.getNode("n1"); - var n2 = helper.getNode("n2"); - var n3 = helper.getNode("n3"); - var n4 = helper.getNode("n4"); - n4.on("input", function(msg) { - msg.should.have.property("payload",null); - //done(); - }); - setTimeout(function() { - var logEvents = helper.log().args.filter(function(evt) { - return evt[0].type == "exec"; - }); - var i = logEvents.length - 1; - logEvents[i][0].should.have.a.property('msg'); - logEvents[i][0].msg.toString().should.startWith("Exec node timeout"); - done(); - },400); - n1.receive({}); - }); - }); - - it('should be able to kill a long running command', function(done) { - var flow; - if (osType === "Windows_NT") { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2"}, - {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; - } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"0.3", useSpawn:"true", oldrc:"false"}, + {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; + } + helper.load(execNode, flow, function() { + var n1 = helper.getNode("n1"); + var n2 = helper.getNode("n2"); + var n3 = helper.getNode("n3"); + var n4 = helper.getNode("n4"); + n4.on("input", function(msg) { + msg.should.have.property("payload"); + msg.payload.should.have.property("code",null); + msg.payload.should.have.property("signal","SIGTERM"); + done(); + }); + n1.receive({}); + }); + }); + + it('should be able to kill a long running command', function(done) { + var flow; + if (osType === "Windows_NT") { + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2", oldrc:"false"}, + {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; + } else { + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; } helper.load(execNode, flow, function() { @@ -607,7 +590,6 @@ describe('exec node', function() { var n4 = helper.getNode("n4"); n4.on("input", function(msg) { msg.should.have.property("payload"); - msg.payload.should.have.property("killed",true); msg.payload.should.have.property("signal","SIGTERM"); done(); }); @@ -620,11 +602,13 @@ describe('exec node', function() { it('should be able to kill a long running command - SIGINT', function(done) { var flow; + var sig = "SIGINT"; if (osType === "Windows_NT") { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; + sig = "SIGTERM"; } else { - flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2"}, + flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2", oldrc:"false"}, {id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}]; } helper.load(execNode, flow, function() { @@ -634,8 +618,7 @@ describe('exec node', function() { var n4 = helper.getNode("n4"); n4.on("input", function(msg) { msg.should.have.property("payload"); - msg.payload.should.have.property("killed",true); - //msg.payload.should.have.property("signal","SIGINT"); + msg.payload.should.have.property("signal",sig); done(); }); setTimeout(function() {