mirror of
https://github.com/node-red/node-red.git
synced 2023-10-10 13:36:53 +02:00
b2f5a259ab
The node adds `shell` to `execOpts` if `/bin/bash` exists. Clearly it has not existed in Travis or running locally - but it does exist on gh-action runner, so the test was failing.
974 lines
43 KiB
JavaScript
974 lines
43 KiB
JavaScript
/**
|
|
* Copyright JS Foundation and other contributors, http://js.foundation
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
**/
|
|
|
|
var should = require("should");
|
|
var sinon = require("sinon");
|
|
var helper = require("node-red-node-test-helper");
|
|
var execNode = require("nr-test-utils").require("@node-red/nodes/core/function/90-exec.js");
|
|
var osType = require("os").type();
|
|
|
|
var child_process = require('child_process');
|
|
|
|
describe('exec node', function() {
|
|
|
|
beforeEach(function(done) {
|
|
helper.startServer(done);
|
|
});
|
|
|
|
afterEach(function(done) {
|
|
helper.unload().then(function() {
|
|
helper.stopServer(done);
|
|
});
|
|
});
|
|
|
|
it('should be loaded with any defaults', function(done) {
|
|
var flow = [{id:"n1", type:"exec", name: "exec1"}];
|
|
helper.load(execNode, flow, function() {
|
|
try {
|
|
var n1 = helper.getNode("n1");
|
|
n1.should.have.property("name", "exec1");
|
|
n1.should.have.property("cmd", "");
|
|
n1.should.have.property("append", "");
|
|
n1.should.have.property("addpay","payload");
|
|
n1.should.have.property("timer",0);
|
|
n1.should.have.property("oldrc","false");
|
|
n1.should.have.property("execOpt");
|
|
n1.execOpt.should.have.property("encoding", 'binary');
|
|
n1.execOpt.should.have.property("maxBuffer", 10000000);
|
|
n1.execOpt.should.have.property("windowsHide", false);
|
|
n1.should.have.property("spawnOpt");
|
|
n1.spawnOpt.should.have.property("windowsHide", false);
|
|
done();
|
|
} catch(err) {
|
|
done(err);
|
|
}
|
|
});
|
|
});
|
|
|
|
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:"", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
var spy = sinon.stub(child_process, 'exec').callsFake(
|
|
function(arg1, arg2, arg3, arg4) {
|
|
// arg3(error,stdout,stderr);
|
|
arg3(null,arg1,arg1.toUpperCase());
|
|
});
|
|
|
|
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");
|
|
var received = 0;
|
|
var messages = [null,null,null];
|
|
var completeTest = function() {
|
|
received = received + 1;
|
|
if (received < 3) {
|
|
return;
|
|
}
|
|
try {
|
|
var msg = messages[0];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("echo");
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",0);
|
|
|
|
msg = messages[1];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("ECHO");
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",0);
|
|
|
|
msg = messages[2];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("code",0);
|
|
|
|
child_process.exec.restore();
|
|
done();
|
|
}
|
|
catch(err) {
|
|
child_process.exec.restore();
|
|
done(err);
|
|
}
|
|
};
|
|
n2.on("input", function(msg) {
|
|
messages[0] = msg;
|
|
completeTest();
|
|
});
|
|
n3.on("input", function(msg) {
|
|
messages[1] = msg;
|
|
completeTest();
|
|
});
|
|
n4.on("input", function(msg) {
|
|
messages[2] = msg;
|
|
completeTest();
|
|
});
|
|
n1.receive({payload:"and"});
|
|
});
|
|
});
|
|
|
|
it('should exec a simple command with appended value from message', function (done) {
|
|
var flow = [{id:"n1", type:"exec", wires:[["n2"]], command:"echo", addpay:"topic", append:"more", oldrc:"false"},
|
|
{id:"n2", type:"helper"}];
|
|
helper.load(execNode, flow, function () {
|
|
var n1 = helper.getNode("n1");
|
|
var n2 = helper.getNode("n2");
|
|
n2.on("input", function (msg) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("bar more\n");
|
|
done();
|
|
} catch(err) {
|
|
done(err)
|
|
}
|
|
});
|
|
n1.receive({payload:"foo", topic:"bar"});
|
|
});
|
|
});
|
|
|
|
it('should exec a simple command with extra parameters', function(done) {
|
|
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:"payload", append:"more", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
var spy = sinon.stub(child_process, 'exec').callsFake(
|
|
function(arg1, arg2, arg3, arg4) {
|
|
//console.log(arg1);
|
|
// arg3(error,stdout,stderr);
|
|
arg3(null,arg1,arg1.toUpperCase());
|
|
});
|
|
|
|
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");
|
|
var received = 0;
|
|
var messages = [null,null];
|
|
var completeTest = function() {
|
|
received++;
|
|
if (received < 2) {
|
|
return;
|
|
}
|
|
try {
|
|
var msg = messages[0];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("echo and more");
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",0);
|
|
|
|
msg = messages[1];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("ECHO AND MORE");
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",0);
|
|
child_process.exec.restore();
|
|
done();
|
|
}
|
|
catch(err) {
|
|
child_process.exec.restore();
|
|
done(err);
|
|
}
|
|
};
|
|
n2.on("input", function(msg) {
|
|
messages[0] = msg;
|
|
completeTest();
|
|
});
|
|
n3.on("input", function(msg) {
|
|
messages[1] = msg;
|
|
completeTest();
|
|
});
|
|
n1.receive({payload:"and"});
|
|
});
|
|
});
|
|
|
|
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", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
var spy = sinon.stub(child_process, 'exec').callsFake(
|
|
function(arg1, arg2, arg3, arg4) {
|
|
//console.log(arg1);
|
|
// arg3(error,stdout,stderr);
|
|
arg3("error",Buffer.from([0x01,0x02,0x03,0x88]),Buffer.from([0x01,0x02,0x03,0x88]));
|
|
});
|
|
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");
|
|
n2.on("input", function(msg) {
|
|
//console.log("n2",msg);
|
|
try {
|
|
msg.should.have.property("payload");
|
|
Buffer.isBuffer(msg.payload).should.be.true();
|
|
msg.payload.length.should.equal(4);
|
|
child_process.exec.restore();
|
|
done();
|
|
} catch(err) {
|
|
child_process.exec.restore();
|
|
done(err);
|
|
}
|
|
});
|
|
n1.receive({});
|
|
});
|
|
});
|
|
|
|
it('should be able to timeout a long running command', function(done) {
|
|
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", 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", 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) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("signal","SIGTERM");
|
|
done();
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
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() {
|
|
var n1 = helper.getNode("n1");
|
|
var n2 = helper.getNode("n2");
|
|
var n3 = helper.getNode("n3");
|
|
var n4 = helper.getNode("n4");
|
|
n2.on("input", function(msg) {
|
|
try {
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",null);
|
|
msg.rc.should.have.property("signal","SIGTERM");
|
|
} catch(err) { done(err); }
|
|
});
|
|
n4.on("input", function(msg) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("signal","SIGTERM");
|
|
done();
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
setTimeout(function() {
|
|
n1.receive({kill:""});
|
|
},150);
|
|
n1.receive({});
|
|
});
|
|
});
|
|
|
|
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", 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() {
|
|
var n1 = helper.getNode("n1");
|
|
var n2 = helper.getNode("n2");
|
|
var n3 = helper.getNode("n3");
|
|
var n4 = helper.getNode("n4");
|
|
n2.on("input", function(msg) {
|
|
try {
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",null);
|
|
msg.rc.should.have.property("signal","SIGINT");
|
|
} catch(err) { done(err); }
|
|
});
|
|
n4.on("input", function(msg) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("signal",sig);
|
|
done();
|
|
} catch(err) { done(err); }
|
|
});
|
|
setTimeout(function() {
|
|
n1.receive({kill:"SIGINT"});
|
|
},150);
|
|
n1.receive({});
|
|
});
|
|
});
|
|
|
|
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:"", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
var spy = sinon.stub(child_process, 'exec').callsFake(
|
|
function(arg1, arg2, arg3, arg4) {
|
|
//console.log(arg1);
|
|
// arg3(error,stdout,stderr);
|
|
arg3({code: 1},arg1,arg1.toUpperCase());
|
|
});
|
|
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");
|
|
var received = 0;
|
|
var messages = [null,null,null];
|
|
var completeTest = function() {
|
|
received++;
|
|
if (received < 3) {
|
|
return;
|
|
}
|
|
try {
|
|
var msg = messages[0];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("error");
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",1);
|
|
msg.rc.should.have.property("message",undefined);
|
|
|
|
msg = messages[1];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("ERROR");
|
|
|
|
msg = messages[2];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("code",1);
|
|
|
|
child_process.exec.restore();
|
|
done();
|
|
}
|
|
catch(err) {
|
|
child_process.exec.restore();
|
|
done(err);
|
|
}
|
|
};
|
|
n2.on("input", function(msg) {
|
|
messages[0] = msg;
|
|
completeTest();
|
|
});
|
|
n3.on("input", function(msg) {
|
|
messages[1] = msg;
|
|
completeTest();
|
|
});
|
|
n4.on("input", function(msg) {
|
|
messages[2] = msg;
|
|
completeTest();
|
|
});
|
|
n1.receive({payload:"and"});
|
|
});
|
|
});
|
|
|
|
it('should preserve existing properties on msg object', function(done) {
|
|
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').callsFake(
|
|
function(arg1, arg2, arg3, arg4) {
|
|
// arg3(error,stdout,stderr);
|
|
arg3(null,arg1,arg1.toUpperCase());
|
|
});
|
|
|
|
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");
|
|
var received = 0;
|
|
var messages = [null,null,null];
|
|
var completeTest = function() {
|
|
received = received + 1;
|
|
if (received < 3) {
|
|
return;
|
|
}
|
|
try {
|
|
var msg = messages[0];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("echo");
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",0);
|
|
msg.should.have.property("foo","bar");
|
|
|
|
msg = messages[1];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("ECHO");
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",0);
|
|
msg.should.have.property("foo","bar");
|
|
|
|
msg = messages[2];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("code",0);
|
|
msg.should.have.property("foo","bar");
|
|
|
|
child_process.exec.restore();
|
|
done();
|
|
}
|
|
catch(err) {
|
|
child_process.exec.restore();
|
|
done(err);
|
|
}
|
|
};
|
|
n2.on("input", function(msg) {
|
|
messages[0] = msg;
|
|
completeTest();
|
|
});
|
|
n3.on("input", function(msg) {
|
|
messages[1] = msg;
|
|
completeTest();
|
|
});
|
|
n4.on("input", function(msg) {
|
|
messages[2] = msg;
|
|
completeTest();
|
|
});
|
|
n1.receive({payload:"and", foo:"bar"});
|
|
});
|
|
});
|
|
|
|
it('should preserve existing properties on msg object for a failing command', function(done) {
|
|
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').callsFake(
|
|
function(arg1, arg2, arg3, arg4) {
|
|
// arg3(error,stdout,stderr);
|
|
arg3({code: 1},arg1,arg1.toUpperCase());
|
|
});
|
|
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");
|
|
var received = 0;
|
|
var messages = [null,null,null];
|
|
var completeTest = function() {
|
|
received++;
|
|
if (received < 3) {
|
|
return;
|
|
}
|
|
try {
|
|
var msg = messages[0];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("error");
|
|
msg.should.have.property("rc");
|
|
msg.rc.should.have.property("code",1);
|
|
msg.rc.should.have.property("message",undefined);
|
|
msg.should.have.property("foo",null);
|
|
|
|
msg = messages[1];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal("ERROR");
|
|
msg.should.have.property("foo",null);
|
|
|
|
msg = messages[2];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("code",1);
|
|
msg.should.have.property("foo",null);
|
|
|
|
child_process.exec.restore();
|
|
done();
|
|
}
|
|
catch(err) {
|
|
child_process.exec.restore();
|
|
done(err);
|
|
}
|
|
};
|
|
n2.on("input", function(msg) {
|
|
messages[0] = msg;
|
|
completeTest();
|
|
});
|
|
n3.on("input", function(msg) {
|
|
messages[1] = msg;
|
|
completeTest();
|
|
});
|
|
n4.on("input", function(msg) {
|
|
messages[2] = msg;
|
|
completeTest();
|
|
});
|
|
n1.receive({payload:"and", foo:null});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
describe('calling spawn', function() {
|
|
|
|
it('should spawn a simple command', function(done) {
|
|
var flow;
|
|
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", 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", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
expected = "hello world\n";
|
|
}
|
|
var events = require('events');
|
|
|
|
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");
|
|
var payload = "";
|
|
n2.on("input", function(msg) {
|
|
//console.log(msg);
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
payload += msg.payload;
|
|
if (payload.endsWith("\n")) {
|
|
payload.should.equal(expected);
|
|
done();
|
|
}
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
n1.receive({payload:"hello world"});
|
|
});
|
|
});
|
|
|
|
it('should spawn a simple command with a non string payload parameter', function(done) {
|
|
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", 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", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
expected = "12345 deg C\n";
|
|
}
|
|
var payload = "";
|
|
|
|
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");
|
|
n2.on("input", function(msg) {
|
|
//console.log(msg);
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
payload += msg.payload;
|
|
if (payload.endsWith("\n")) {
|
|
payload.should.equal(expected);
|
|
done();
|
|
}
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
n1.receive({payload:12345});
|
|
});
|
|
});
|
|
|
|
it('should spawn a simple command and return binary buffer', function(done) {
|
|
var flow;
|
|
if (osType === "Windows_NT") {
|
|
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"}];
|
|
} else {
|
|
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"}];
|
|
}
|
|
|
|
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");
|
|
n2.on("input", function(msg) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
Buffer.isBuffer(msg.payload).should.be.true();
|
|
if (osType === "Windows_NT") {
|
|
msg.payload.length.should.equalOneOf(6,8);
|
|
} else {
|
|
msg.payload.length.should.equal(7);
|
|
}
|
|
done();
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
n1.receive({payload:Buffer.from([0x01,0x02,0x03,0x88])});
|
|
});
|
|
});
|
|
|
|
it('should work if passed multiple words to spawn command', function(done) {
|
|
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", 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", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
expected = "this now works\n";
|
|
}
|
|
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");
|
|
var received = 0;
|
|
var messages = [null,null];
|
|
var completeTest = function() {
|
|
received++;
|
|
if (received < 2) {
|
|
return;
|
|
}
|
|
try {
|
|
var msg = messages[0];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal(expected);
|
|
|
|
msg = messages[1];
|
|
msg.should.have.property("payload");
|
|
should.exist(msg.payload);
|
|
msg.payload.should.have.property("code",0);
|
|
done();
|
|
}
|
|
catch(err) {
|
|
done(err);
|
|
}
|
|
};
|
|
|
|
n2.on("input", function(msg) {
|
|
var payload = msg.payload;
|
|
if (messages[0]) {
|
|
messages[0].payload += payload;
|
|
}
|
|
else {
|
|
messages[0] = msg;
|
|
}
|
|
if (payload.endsWith("\n")) {
|
|
completeTest();
|
|
}
|
|
});
|
|
n4.on("input", function(msg) {
|
|
messages[1] = msg;
|
|
completeTest();
|
|
});
|
|
n1.receive({payload:null,fred:123});
|
|
});
|
|
});
|
|
|
|
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) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("code");
|
|
msg.payload.code.should.be.below(0);
|
|
done();
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
n1.receive({payload:null});
|
|
});
|
|
});
|
|
|
|
it('should return an error for a failing command', function(done) {
|
|
var flow;
|
|
var expected;
|
|
var expectedFound = false;
|
|
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", 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", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
expected = ' directory';
|
|
}
|
|
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");
|
|
n3.on("input", function(msg) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
if (msg.payload.indexOf(expected) >= 0) {
|
|
// The error text on the stderr stream might get sent in more than one piece.
|
|
// We only need to know that it occurred before the return code is sent,
|
|
// as checked below in node n4.
|
|
expectedFound = true;
|
|
}
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
n4.on("input", function(msg) {
|
|
try {
|
|
expectedFound.should.be.true;
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("code",1);
|
|
done();
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
n1.receive({payload:null});
|
|
});
|
|
});
|
|
|
|
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", 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", 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) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("code",null);
|
|
msg.payload.should.have.property("signal","SIGTERM");
|
|
done();
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
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() {
|
|
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) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("signal","SIGTERM");
|
|
done();
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
setTimeout(function() {
|
|
n1.receive({kill:""});
|
|
},150);
|
|
n1.receive({});
|
|
});
|
|
});
|
|
|
|
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", 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() {
|
|
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) {
|
|
try {
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("signal",sig);
|
|
done();
|
|
}
|
|
catch(err) { done(err); }
|
|
});
|
|
setTimeout(function() {
|
|
n1.receive({kill:"SIGINT"});
|
|
},150);
|
|
n1.receive({});
|
|
});
|
|
});
|
|
|
|
it('should preserve existing properties on msg object', function(done) {
|
|
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", 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", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
expected = "this now works\n";
|
|
}
|
|
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");
|
|
var received = 0;
|
|
var messages = [null,null];
|
|
var completeTest = function() {
|
|
received++;
|
|
if (received < 2) {
|
|
return;
|
|
}
|
|
try {
|
|
var msg = messages[0];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.payload.should.equal(expected);
|
|
msg.should.have.property("foo",123);
|
|
|
|
msg = messages[1];
|
|
msg.should.have.property("payload");
|
|
should.exist(msg.payload);
|
|
msg.payload.should.have.property("code",0);
|
|
msg.should.have.property("foo",123);
|
|
|
|
done();
|
|
}
|
|
catch(err) {
|
|
done(err);
|
|
}
|
|
};
|
|
|
|
n2.on("input", function(msg) {
|
|
var payload = msg.payload;
|
|
if (messages[0]) {
|
|
messages[0].payload += payload;
|
|
}
|
|
else {
|
|
messages[0] = msg;
|
|
}
|
|
if (payload.endsWith("\n")) {
|
|
completeTest();
|
|
}
|
|
});
|
|
n4.on("input", function(msg) {
|
|
messages[1] = msg;
|
|
completeTest();
|
|
});
|
|
n1.receive({payload:null,foo:123});
|
|
});
|
|
});
|
|
|
|
it('should preserve existing properties on msg object 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", 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", oldrc:"false"},
|
|
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
|
expected = ' directory';
|
|
}
|
|
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");
|
|
var received = 0;
|
|
var messages = [null,null];
|
|
var completeTest = function() {
|
|
if (messages[0] === null || messages[1] === null) {
|
|
// We have not yet had responses on both ports.
|
|
return
|
|
}
|
|
try {
|
|
var msg = messages[0];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.be.a.String();
|
|
msg.should.have.property("foo","baz");
|
|
|
|
msg = messages[1];
|
|
msg.should.have.property("payload");
|
|
msg.payload.should.have.property("code",1);
|
|
msg.should.have.property("foo","baz");
|
|
|
|
done();
|
|
}
|
|
catch(err) {
|
|
done(err);
|
|
}
|
|
};
|
|
|
|
n3.on("input", function(msg) {
|
|
messages[0] = msg;
|
|
completeTest();
|
|
});
|
|
n4.on("input", function(msg) {
|
|
messages[1] = msg;
|
|
completeTest();
|
|
});
|
|
n1.receive({payload:null,foo:"baz"});
|
|
});
|
|
});
|
|
|
|
});
|
|
});
|