mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Reorganise nodes into new categories
This commit is contained in:
1484
test/nodes/core/function/10-function_spec.js
Normal file
1484
test/nodes/core/function/10-function_spec.js
Normal file
File diff suppressed because it is too large
Load Diff
1101
test/nodes/core/function/10-switch_spec.js
Normal file
1101
test/nodes/core/function/10-switch_spec.js
Normal file
File diff suppressed because it is too large
Load Diff
1707
test/nodes/core/function/15-change_spec.js
Normal file
1707
test/nodes/core/function/15-change_spec.js
Normal file
File diff suppressed because it is too large
Load Diff
152
test/nodes/core/function/16-range_spec.js
Normal file
152
test/nodes/core/function/16-range_spec.js
Normal file
@@ -0,0 +1,152 @@
|
||||
/**
|
||||
* 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 rangeNode = require("nr-test-utils").require("@node-red/nodes/core/function/16-range.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('range Node', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload();
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
it('should load some defaults', function(done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","name":"rangeNode"}];
|
||||
helper.load(rangeNode, flow, function() {
|
||||
var rangeNode1 = helper.getNode("rangeNode1");
|
||||
rangeNode1.should.have.property('name', 'rangeNode');
|
||||
rangeNode1.should.have.property('round', false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Run a generic range test
|
||||
* @param action - scale/clamp (range limit)/roll (modulo): what action to choose
|
||||
* @param minin - map from minimum value
|
||||
* @param maxin - map from maximum value
|
||||
* @param minout - map to minimum value
|
||||
* @param maxout - map to maximum value
|
||||
* @param round - whether to round the result to the nearest integer
|
||||
* @param aPayload - what payload to send to the range node
|
||||
* @param expectedResult - what result we're expecting
|
||||
* @param done - the callback to call when test done
|
||||
*/
|
||||
function genericRangeTest(action, minin, maxin, minout, maxout, round, aPayload, expectedResult, done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","minin":minin,"maxin":maxin,"minout":minout,"maxout":maxout,"action":action,"round":round,"name":"rangeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(rangeNode, flow, function() {
|
||||
var rangeNode1 = helper.getNode("rangeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.equal(expectedResult);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
rangeNode1.receive({payload:aPayload});
|
||||
});
|
||||
}
|
||||
|
||||
it('ranges numbers up tenfold', function(done) {
|
||||
genericRangeTest("scale", 0, 100, 0, 1000, false, 50, 500, done);
|
||||
});
|
||||
|
||||
it('ranges numbers down such as centimetres to metres', function(done) {
|
||||
genericRangeTest("scale", 0, 100, 0, 1, false, 55, 0.55, done);
|
||||
});
|
||||
|
||||
it('wraps numbers down say for degree/rotation reading 1/2', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, 15, 180, done); // 1/2 around wrap => "one and a half turns"
|
||||
});
|
||||
|
||||
it('wraps numbers around say for degree/rotation reading 1/3', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, 13.3333, 120, done); // 1/3 around wrap => "one and a third turns"
|
||||
});
|
||||
|
||||
it('wraps numbers around say for degree/rotation reading 1/4', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, 12.5, 90, done); // 1/4 around wrap => "one and a quarter turns"
|
||||
});
|
||||
|
||||
it('wraps numbers down say for degree/rotation reading 1/4', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, -12.5, 270, done); // 1/4 backwards wrap => "one and a quarter turns backwards"
|
||||
});
|
||||
|
||||
it('wraps numbers around say for degree/rotation reading 0', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, -10, 0, done);
|
||||
});
|
||||
|
||||
it('clamps numbers within a range - over max', function(done) {
|
||||
genericRangeTest("clamp", 0, 10, 0, 1000, false, 111, 1000, done);
|
||||
});
|
||||
|
||||
it('clamps numbers within a range - below min', function(done) {
|
||||
genericRangeTest("clamp", 0, 10, 0, 1000, false, -1, 0, done);
|
||||
});
|
||||
|
||||
it('just passes on msg if payload not present', function(done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","minin":0,"maxin":100,"minout":0,"maxout":100,"action":"scale","round":true,"name":"rangeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(rangeNode, flow, function() {
|
||||
var rangeNode1 = helper.getNode("rangeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.not.have.property('payload');
|
||||
msg.topic.should.equal("pass on");
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
rangeNode1.receive({topic:"pass on"});
|
||||
});
|
||||
});
|
||||
|
||||
it('reports if input is not a number', function(done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","minin":0,"maxin":0,"minout":0,"maxout":0,"action":"scale","round":true,"name":"rangeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(rangeNode, flow, function() {
|
||||
var rangeNode1 = helper.getNode("rangeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
rangeNode1.on("call:log",function(args) {
|
||||
var log = args.args[0];
|
||||
if (log.indexOf("notnumber") > -1) {
|
||||
rangeNode1.log.restore();
|
||||
done();
|
||||
} else {
|
||||
try {
|
||||
should.fail(null, null, "Non-number inputs should be reported!");
|
||||
} catch (err) {
|
||||
rangeNode1.log.restore();
|
||||
done(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rangeNode1.receive({payload:"NOT A NUMBER"});
|
||||
});
|
||||
});
|
||||
});
|
498
test/nodes/core/function/80-template_spec.js
Normal file
498
test/nodes/core/function/80-template_spec.js
Normal file
@@ -0,0 +1,498 @@
|
||||
/**
|
||||
* 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 templateNode = require("nr-test-utils").require("@node-red/nodes/core/function/80-template.js");
|
||||
var Context = require("nr-test-utils").require("@node-red/runtime/lib/nodes/context");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('template node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
beforeEach(function(done) {
|
||||
done();
|
||||
});
|
||||
|
||||
function initContext(done) {
|
||||
Context.init({
|
||||
contextStorage: {
|
||||
memory0: { // do not use (for excluding effect fallback)
|
||||
module: "memory"
|
||||
},
|
||||
memory1: {
|
||||
module: "memory"
|
||||
},
|
||||
memory2: {
|
||||
module: "memory"
|
||||
}
|
||||
}
|
||||
});
|
||||
Context.load().then(function () {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload().then(function () {
|
||||
return Context.clean({allNodes:{}});
|
||||
}).then(function () {
|
||||
return Context.close();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should modify payload using node-configured template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
msg.should.have.property('template', 'this should be ignored as the node has its own template {{payload}}');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar", template: "this should be ignored as the node has its own template {{payload}}"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify the configured property using msg.template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"randomProperty", template:"",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
msg.should.have.property('template', 'payload={{payload}}');
|
||||
msg.should.have.property('randomProperty', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo", topic: "bar", template: "payload={{payload}}"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to overwrite msg.template using the template from msg.template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", template:"",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'topic=bar');
|
||||
msg.should.have.property('template', 'topic={{topic}}');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo", topic: "bar", template: "topic={{topic}}"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from msg.template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", template:"",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var received = [];
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
received.push(msg);
|
||||
if (received.length === 3) {
|
||||
received[0].should.have.property('topic', 'bar');
|
||||
received[0].should.have.property('payload', 'topic=bar');
|
||||
received[0].should.have.property('template', 'topic={{topic}}');
|
||||
|
||||
received[1].should.have.property('topic', 'another bar');
|
||||
received[1].should.have.property('payload', 'topic=another bar');
|
||||
received[1].should.have.property('template', 'topic={{topic}}');
|
||||
|
||||
received[2].should.have.property('topic', 'bar');
|
||||
received[2].should.have.property('payload', 'payload=foo');
|
||||
received[2].should.have.property('template', 'payload={{payload}}');
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo", topic: "bar", template: "topic={{topic}}"});
|
||||
n1.receive({payload:"foo", topic: "another bar", template: "topic={{topic}}"});
|
||||
n1.receive({payload:"foo", topic: "bar", template: "payload={{payload}}"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow.value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.context().flow.set("value","foo");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from persistable flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow[memory1].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.context().flow.set("value","foo","memory1",function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle nested context tags - property not set', function(done) {
|
||||
// This comes from the Coursera Node-RED course and is a good example of
|
||||
// multiple conditional tags
|
||||
var template = `{{#flow.time}}time={{flow.time}}{{/flow.time}}{{^flow.time}}!time{{/flow.time}}{{#flow.random}}random={{flow.random}}randomtime={{flow.randomtime}}{{/flow.random}}{{^flow.random}}!random{{/flow.random}}`;
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:template,wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', '!time!random');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
})
|
||||
it('should handle nested context tags - property set', function(done) {
|
||||
// This comes from the Coursera Node-RED course and is a good example of
|
||||
// multiple conditional tags
|
||||
var template = `{{#flow.time}}time={{flow.time}}{{/flow.time}}{{^flow.time}}!time{{/flow.time}}{{#flow.random}}random={{flow.random}}randomtime={{flow.randomtime}}{{/flow.random}}{{^flow.random}}!random{{/flow.random}}`;
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:template,wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'time=123random=456randomtime=789');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.context().flow.set(["time","random","randomtime"],["123","456","789"],function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
it('should modify payload from two persistable flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow[memory1].value}}/{{flow[memory2].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo/bar');
|
||||
done();
|
||||
});
|
||||
n1.context().flow.set("value","foo","memory1",function (err) {
|
||||
n1.context().flow.set("value","bar","memory2",function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global.value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.context().global.set("value","foo");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from persistable global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global[memory1].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.context().global.set("value","foo","memory1", function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from two persistable global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global[memory1].value}}/{{global[memory2].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo/bar');
|
||||
done();
|
||||
});
|
||||
n1.context().global.set("value","foo","memory1", function (err) {
|
||||
n1.context().global.set("value","bar","memory2", function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from persistable flow & global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow[memory1].value}}/{{global[memory1].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo/bar');
|
||||
done();
|
||||
});
|
||||
n1.context().flow.set("value","foo","memory1", function (err) {
|
||||
n1.context().global.set("value","bar","memory1", function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle missing node context', function(done) {
|
||||
// this is artificial test because in flow there is missing z property (probably never happen in real usage)
|
||||
var flow = [{id:"n1",type:"template", field:"payload", template:"payload={{flow.value}},{{global.value}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=,');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle escape characters in Mustache format and JSON output mode', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", syntax:"mustache", template:"{\"data\":\"{{payload}}\"}", output:"json", wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.payload.should.have.property('data', 'line\t1\nline\\2\r\nline\b3\f');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"line\t1\nline\\2\r\nline\b3\f"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload in plain text mode', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", syntax:"plain", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload={{payload}}');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", fieldType:"flow", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
// mesage is intact
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
// result is in flow context
|
||||
n2.context().flow.get("payload").should.equal("payload=foo");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify persistable flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"#:(memory1)::payload", fieldType:"flow", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
// mesage is intact
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
// result is in flow context
|
||||
n2.context().flow.get("payload", "memory1", function (err, val) {
|
||||
val.should.equal("payload=foo");
|
||||
done();
|
||||
});
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", fieldType:"global", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
// mesage is intact
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
// result is in global context
|
||||
n2.context().global.get("payload").should.equal("payload=foo");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify persistable global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"#:(memory1)::payload", fieldType:"global", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
// mesage is intact
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
// result is in global context
|
||||
n2.context().global.get("payload", "memory1", function (err, val) {
|
||||
val.should.equal("payload=foo");
|
||||
done();
|
||||
});
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle if the field isn\'t set', function(done) {
|
||||
var flow = [{id:"n1", type:"template", template: "payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle deeper objects', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field: "topic.foo.bar", template: "payload={{payload.doh.rei.me}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic');
|
||||
msg.topic.should.have.property('foo');
|
||||
msg.topic.foo.should.have.a.property('bar', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:{doh:{rei:{me:"foo"}}}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle block contexts objects', function(done) {
|
||||
var flow = [{id:"n1", type:"template", template: "A{{#payload.A}}{{payload.A}}{{.}}{{/payload.A}}B",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('payload','AabcabcB');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:{A:"abc"}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should raise error if passed bad template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field: "payload", template: "payload={{payload",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
setTimeout(function() {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "template";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.toString().should.startWith("Unclosed tag at ");
|
||||
done();
|
||||
},25);
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
721
test/nodes/core/function/89-delay_spec.js
Normal file
721
test/nodes/core/function/89-delay_spec.js
Normal file
@@ -0,0 +1,721 @@
|
||||
/**
|
||||
* 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 delayNode = require("nr-test-utils").require("@node-red/nodes/core/function/89-delay.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
var GRACE_PERCENTAGE=10;
|
||||
|
||||
var nanosToSeconds = 1000000000;
|
||||
var millisToSeconds = 1000;
|
||||
|
||||
var secondsToMinutes = 60;
|
||||
var secondsToHours = 3600;
|
||||
var secondsToDays = 86400;
|
||||
|
||||
describe('delay Node', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload();
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{"id":"delayNode1","type":"delay", "nbRateUnits":"1", "name":"delayNode","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"day","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[[]]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
delayNode1.should.have.property('name', 'delayNode');
|
||||
delayNode1.should.have.property('rate', 86400000);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to set rate to hour', function(done) {
|
||||
var flow = [{"id":"delayNode1","type":"delay", "nbRateUnits":"1", "name":"delayNode","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"hour","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[[]]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
delayNode1.should.have.property('name', 'delayNode');
|
||||
delayNode1.should.have.property('rate', 3600000);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to set rate to minute', function(done) {
|
||||
var flow = [{"id":"delayNode1","type":"delay", "nbRateUnits":"1", "name":"delayNode","pauseType":"delay","timeout":"5","timeoutUnits":"seconds","rate":"1","rateUnits":"minute","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[[]]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
delayNode1.should.have.property('name', 'delayNode');
|
||||
delayNode1.should.have.property('rate', 60000);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
var TimeUnitEnum = {
|
||||
MILLIS : "milliseconds",
|
||||
SECONDS : "seconds",
|
||||
MINUTES : "minutes",
|
||||
HOURS : "hours",
|
||||
DAYS : "days"
|
||||
}
|
||||
|
||||
/**
|
||||
* Tells whether two numeric values are close enough to each other
|
||||
* @param actualValue - the value we're testing
|
||||
* @param expectedValue - the value we're matching the test value against
|
||||
* @param tolerancePercent - the percentage of tolerated deviation (0 means equals)
|
||||
*/
|
||||
function closeEnough(actualValue, expectedValue, tolerancePercent) {
|
||||
var toReturn;
|
||||
var toleranceFraction = expectedValue * (tolerancePercent/100);
|
||||
var minExpected = expectedValue - toleranceFraction;
|
||||
var maxExpected = expectedValue + toleranceFraction;
|
||||
|
||||
if (actualValue >= minExpected && actualValue <= maxExpected) {
|
||||
toReturn = true;
|
||||
} else {
|
||||
toReturn = false;
|
||||
}
|
||||
return toReturn;
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a delay test
|
||||
* @param aTimeout - the timeout quantity
|
||||
* @param aTimeoutUnit - the unit of the timeout: milliseconds, seconds, minutes, hours, days
|
||||
*/
|
||||
function genericDelayTest(aTimeout, aTimeoutUnit, done) {
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"delay","timeout":aTimeout,"timeoutUnits":aTimeoutUnit,"rate":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
var endTime = process.hrtime(startTime);
|
||||
var runtimeNanos = ( (endTime[0] * nanosToSeconds) + endTime[1] );
|
||||
var runtimeSeconds = runtimeNanos / nanosToSeconds;
|
||||
var aTimeoutUnifiedToSeconds;
|
||||
|
||||
// calculating the timeout in seconds
|
||||
if (aTimeoutUnit == TimeUnitEnum.MILLIS) {
|
||||
aTimeoutUnifiedToSeconds = aTimeout / millisToSeconds;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.SECONDS) {
|
||||
aTimeoutUnifiedToSeconds = aTimeout;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.MINUTES) {
|
||||
aTimeoutUnifiedToSeconds = aTimeout * secondsToMinutes;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.HOURS) {
|
||||
aTimeoutUnifiedToSeconds = aTimeout * secondsToHours;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.DAYS) {
|
||||
aTimeoutUnifiedToSeconds = aTimeout * secondsToDays;
|
||||
}
|
||||
|
||||
if (closeEnough(runtimeSeconds, aTimeoutUnifiedToSeconds, GRACE_PERCENTAGE)) {
|
||||
done();
|
||||
} else {
|
||||
try {
|
||||
should.fail(null, null, "Delayed runtime seconds " + runtimeSeconds + " was not close enough to exlected timeout seconds: " + aTimeoutUnifiedToSeconds);
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var startTime = process.hrtime();
|
||||
delayNode1.receive({payload:"delayMe"});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* We send a message, take a timestamp then when the message is received by the helper node, we take another timestamp.
|
||||
* Then check if the message has been delayed by the expected amount.
|
||||
*/
|
||||
it('delays the message in seconds', function(done) {
|
||||
genericDelayTest(0.5, "seconds", done);
|
||||
});
|
||||
|
||||
it('delays the message in milliseconds', function(done) {
|
||||
genericDelayTest(500, "milliseconds", done);
|
||||
});
|
||||
|
||||
it('delays the message in minutes', function(done) { // this is also 0.5 seconds
|
||||
genericDelayTest(0.00833, "minutes", done);
|
||||
});
|
||||
|
||||
it('delays the message in hours', function(done) { // this is also 0.5 seconds
|
||||
genericDelayTest(0.0001388, "hours", done);
|
||||
});
|
||||
|
||||
it('delays the message in days', function(done) { // this is also 0.5 seconds
|
||||
genericDelayTest(0.000005787, "days", done);
|
||||
});
|
||||
|
||||
/**
|
||||
* Runs a rate limit test - only testing seconds!
|
||||
* @param aLimit - the message limit count
|
||||
* @param nbUnit - the multiple of the unit, aLimit Message for nbUnit Seconds
|
||||
* @param runtimeInMillis - when to terminate run and count messages received
|
||||
*/
|
||||
function genericRateLimitSECONDSTest(aLimit, nbUnit, runtimeInMillis, done) {
|
||||
var flow = [{"id":"delayNode1","type":"delay","nbRateUnits":nbUnit,"name":"delayNode","pauseType":"rate","timeout":5,"timeoutUnits":"seconds","rate":aLimit,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var receivedMessagesStack = [];
|
||||
var rate = 1000/aLimit;
|
||||
|
||||
var receiveTimestamp;
|
||||
|
||||
helperNode1.on("input", function(msg) {
|
||||
if (receiveTimestamp) {
|
||||
var elapse = process.hrtime(receiveTimestamp);
|
||||
var receiveInterval = (elapse[0] * 1000) + ((elapse[1] / nanosToSeconds) * 1000);
|
||||
receiveInterval.should.be.above(rate * 0.9);
|
||||
}
|
||||
receiveTimestamp = process.hrtime();
|
||||
receivedMessagesStack.push(msg);
|
||||
});
|
||||
|
||||
var possibleMaxMessageCount = Math.ceil(aLimit * (runtimeInMillis / 1000) + aLimit); // +aLimit as at the start of the 2nd period, we're allowing the 3rd burst
|
||||
|
||||
var i = 0;
|
||||
for (; i < possibleMaxMessageCount + 1; i++) {
|
||||
delayNode1.receive({payload:i});
|
||||
}
|
||||
|
||||
setTimeout(function() {
|
||||
try {
|
||||
receivedMessagesStack.length.should.be.lessThan(possibleMaxMessageCount);
|
||||
for (var j = 0; j < receivedMessagesStack.length; j++) {
|
||||
if (receivedMessagesStack[j].payload === j) {
|
||||
if (j === (receivedMessagesStack.length -1)) { // last message, all matched so far
|
||||
done();
|
||||
}
|
||||
} else {
|
||||
should.fail(null, null, "Received messages were not received in order. Message was " + receivedMessagesStack[i].payload + " on count " + i);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, runtimeInMillis);
|
||||
});
|
||||
}
|
||||
|
||||
it('limits the message rate to 1 per second', function(done) {
|
||||
genericRateLimitSECONDSTest(1, 1, 1500, done);
|
||||
});
|
||||
|
||||
it('limits the message rate to 1 per 2 seconds', function(done) {
|
||||
this.timeout(6000);
|
||||
genericRateLimitSECONDSTest(1, 2, 3000, done);
|
||||
});
|
||||
|
||||
it('limits the message rate to 2 per seconds, 2 seconds', function(done) {
|
||||
this.timeout(6000);
|
||||
genericRateLimitSECONDSTest(2, 1, 2100, done);
|
||||
});
|
||||
|
||||
/**
|
||||
* Runs a rate limit test with drop support - only testing seconds!
|
||||
* @param aLimit - the message limit count
|
||||
* @param nbUnit - the multiple of the unit, aLimit Message for nbUnit Seconds
|
||||
* @param runtimeInMillis - when to terminate run and count messages received
|
||||
*/
|
||||
function dropRateLimitSECONDSTest(aLimit, nbUnit, runtimeInMillis, done) {
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":5,"nbRateUnits":nbUnit,"timeoutUnits":"seconds","rate":aLimit,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var receivedMessagesStack = [];
|
||||
|
||||
var rate = 1000/aLimit;
|
||||
|
||||
var receiveTimestamp;
|
||||
|
||||
helperNode1.on("input", function(msg) {
|
||||
if (receiveTimestamp) {
|
||||
var elapse = process.hrtime(receiveTimestamp);
|
||||
var receiveInterval = (elapse[0] * 1000) + ((elapse[1] / nanosToSeconds) * 1000);
|
||||
receiveInterval.should.be.above(rate * 0.9);
|
||||
}
|
||||
receiveTimestamp = process.hrtime();
|
||||
receivedMessagesStack.push(msg);
|
||||
});
|
||||
|
||||
var possibleMaxMessageCount = Math.ceil(aLimit * (runtimeInMillis / 1000) + aLimit); // +aLimit as at the start of the 2nd period, we're allowing the 3rd burst
|
||||
|
||||
var i = 0;
|
||||
delayNode1.receive({payload:i});
|
||||
i++;
|
||||
for (; i < possibleMaxMessageCount + 1; i++) {
|
||||
setTimeout(function() {
|
||||
delayNode1.receive({payload:i});
|
||||
}, 2 * ((rate * i) / possibleMaxMessageCount) );
|
||||
}
|
||||
|
||||
//we need to send a message delayed so that it doesn't get dropped
|
||||
setTimeout(function() {
|
||||
delayNode1.receive({payload:++i});
|
||||
}, runtimeInMillis - 300); // should give enough time to squeeze another message in
|
||||
|
||||
setTimeout(function() {
|
||||
try {
|
||||
receivedMessagesStack.length.should.be.lessThan(possibleMaxMessageCount + 1);
|
||||
receivedMessagesStack.length.should.be.greaterThan(2); // ensure that we receive more than 1st and last message
|
||||
receivedMessagesStack[0].payload.should.be.exactly(0); // means we received the last message injected just before test termination
|
||||
var foundAtLeastOneDrop = false;
|
||||
for (var i = 0; i < receivedMessagesStack.length; i++) {
|
||||
if (i > 0) {
|
||||
if (receivedMessagesStack[i].payload - receivedMessagesStack[i - 1].payload > 1) {
|
||||
foundAtLeastOneDrop = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
foundAtLeastOneDrop.should.be.true();
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, runtimeInMillis);
|
||||
});
|
||||
}
|
||||
|
||||
it('limits the message rate to 1 per second, 4 seconds, with drop', function(done) {
|
||||
this.timeout(6000);
|
||||
dropRateLimitSECONDSTest(1, 1, 4000, done);
|
||||
});
|
||||
|
||||
it('limits the message rate to 1 per 2 seconds, 4 seconds, with drop', function(done) {
|
||||
this.timeout(6000);
|
||||
dropRateLimitSECONDSTest(1, 2, 4500, done);
|
||||
});
|
||||
|
||||
it('limits the message rate to 2 per second, 5 seconds, with drop', function(done) {
|
||||
this.timeout(6000);
|
||||
dropRateLimitSECONDSTest(2, 1, 5000, done);
|
||||
});
|
||||
|
||||
/**
|
||||
* Returns true if the actualTimeout is gracefully in between the timeoutFrom and timeoutTo
|
||||
* values. Gracefully means that inBetween could actually mean smaller/greater values
|
||||
* than the timeout range so long as it's within an actual grace percentage.
|
||||
* @param timeoutFrom - The expected timeout range (low number)
|
||||
* @param timeoutTo - The expected timeout range (high number)
|
||||
* @param actualTimeout - The actual measured timeout value of test
|
||||
* @param allowedGracePercent - The percentage of grace allowed
|
||||
*/
|
||||
function inBetweenDelays(timeoutFrom, timeoutTo, actualTimeout, allowedGracePercent) {
|
||||
if (closeEnough(actualTimeout, timeoutFrom, allowedGracePercent)) {
|
||||
return true;
|
||||
} else if (closeEnough(actualTimeout, timeoutTo, allowedGracePercent)) {
|
||||
return true;
|
||||
} else if (timeoutFrom < actualTimeout && timeoutTo > actualTimeout) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs a VARIABLE DELAY test, checks if the delay is in between the given timeout values
|
||||
* @param aTimeoutFrom - the timeout quantity which is the minimal acceptable wait period
|
||||
* @param aTimeoutTo - the timeout quantity which is the maximum acceptable wait period
|
||||
* @param aTimeoutUnit - the unit of the timeout: milliseconds, seconds, minutes, hours, days
|
||||
* @param delay - the variable delay: milliseconds
|
||||
*/
|
||||
function variableDelayTest(aTimeoutFrom, aTimeoutTo, aTimeoutUnit, delay, done) {
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"delayv","timeout":0.5,"timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":aTimeoutFrom,"randomLast":aTimeoutTo,"randomUnits":aTimeoutUnit,"drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
var endTime = process.hrtime(startTime);
|
||||
var runtimeNanos = ( (endTime[0] * nanosToSeconds) + endTime[1] );
|
||||
var runtimeSeconds = runtimeNanos / nanosToSeconds;
|
||||
var aTimeoutFromUnifiedToSeconds;
|
||||
var aTimeoutToUnifiedToSeconds;
|
||||
|
||||
// calculating the timeout in seconds
|
||||
if (aTimeoutUnit == TimeUnitEnum.MILLIS) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom / millisToSeconds;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo / millisToSeconds;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.SECONDS) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.MINUTES) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom * secondsToMinutes;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo * secondsToMinutes;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.HOURS) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom * secondsToHours;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo * secondsToHours;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.DAYS) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom * secondsToDays;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo * secondsToDays;
|
||||
}
|
||||
|
||||
if (inBetweenDelays(aTimeoutFromUnifiedToSeconds, aTimeoutToUnifiedToSeconds, runtimeSeconds, GRACE_PERCENTAGE)) {
|
||||
done();
|
||||
} else {
|
||||
try {
|
||||
should.fail(null, null, "Delayed runtime seconds " + runtimeSeconds + " was not \"in between enough\" enough to expected values of: " + aTimeoutFromUnifiedToSeconds + " and " + aTimeoutToUnifiedToSeconds);
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var startTime = process.hrtime();
|
||||
delayNode1.receive({payload:"delayMe", delay:delay});
|
||||
});
|
||||
}
|
||||
|
||||
it('variable delay set by msg.delay the message in milliseconds', function(done) {
|
||||
variableDelayTest("200", "300", "milliseconds", 250, done);
|
||||
});
|
||||
|
||||
it('variable delay is the default if msg.delay not specified', function(done) {
|
||||
variableDelayTest("450", "550", "milliseconds", null, done);
|
||||
});
|
||||
|
||||
it('variable delay is zero if msg.delay is zero', function(done) {
|
||||
variableDelayTest("0", "20", "milliseconds", 0, done);
|
||||
});
|
||||
|
||||
it('variable delay is zero if msg.delay is negative', function(done) {
|
||||
variableDelayTest("0", "20", "milliseconds", -250, done);
|
||||
});
|
||||
|
||||
/**
|
||||
* Runs a RANDOM DELAY test, checks if the delay is in between the given timeout values
|
||||
* @param aTimeoutFrom - the timeout quantity which is the minimal acceptable wait period
|
||||
* @param aTimeoutTo - the timeout quantity which is the maximum acceptable wait period
|
||||
* @param aTimeoutUnit - the unit of the timeout: milliseconds, seconds, minutes, hours, days
|
||||
*/
|
||||
function randomDelayTest(aTimeoutFrom, aTimeoutTo, aTimeoutUnit, done) {
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"random","timeout":5,"timeoutUnits":"seconds","rate":"1","rateUnits":"second","randomFirst":aTimeoutFrom,"randomLast":aTimeoutTo,"randomUnits":aTimeoutUnit,"drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
var endTime = process.hrtime(startTime);
|
||||
var runtimeNanos = ( (endTime[0] * nanosToSeconds) + endTime[1] );
|
||||
var runtimeSeconds = runtimeNanos / nanosToSeconds;
|
||||
var aTimeoutFromUnifiedToSeconds;
|
||||
var aTimeoutToUnifiedToSeconds;
|
||||
|
||||
// calculating the timeout in seconds
|
||||
if (aTimeoutUnit == TimeUnitEnum.MILLIS) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom / millisToSeconds;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo / millisToSeconds;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.SECONDS) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.MINUTES) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom * secondsToMinutes;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo * secondsToMinutes;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.HOURS) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom * secondsToHours;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo * secondsToHours;
|
||||
} else if (aTimeoutUnit == TimeUnitEnum.DAYS) {
|
||||
aTimeoutFromUnifiedToSeconds = aTimeoutFrom * secondsToDays;
|
||||
aTimeoutToUnifiedToSeconds = aTimeoutTo * secondsToDays;
|
||||
}
|
||||
|
||||
if (inBetweenDelays(aTimeoutFromUnifiedToSeconds, aTimeoutToUnifiedToSeconds, runtimeSeconds, GRACE_PERCENTAGE)) {
|
||||
done();
|
||||
} else {
|
||||
try {
|
||||
should.fail(null, null, "Delayed runtime seconds " + runtimeSeconds + " was not \"in between enough\" enough to expected values of: " + aTimeoutFromUnifiedToSeconds + " and " + aTimeoutToUnifiedToSeconds);
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var startTime = process.hrtime();
|
||||
delayNode1.receive({payload:"delayMe"});
|
||||
});
|
||||
}
|
||||
|
||||
it('randomly delays the message in seconds', function(done) {
|
||||
randomDelayTest(0.4, 0.8, "seconds", done);
|
||||
});
|
||||
|
||||
it('randomly delays the message in milliseconds', function(done) {
|
||||
randomDelayTest("400", "800", "milliseconds", done);
|
||||
});
|
||||
|
||||
it('randomly delays the message in minutes', function(done) {
|
||||
randomDelayTest(0.0066, 0.0133, "minutes", done);
|
||||
});
|
||||
|
||||
it('delays the message in hours', function(done) {
|
||||
randomDelayTest(0.000111111, 0.000222222, "hours", done);
|
||||
});
|
||||
|
||||
it('delays the message in days', function(done) {
|
||||
randomDelayTest(0.0000046296, 0.0000092593, "days", done);
|
||||
});
|
||||
|
||||
it('handles delay queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{id:"delayNode1", type :"delay","name":"delayNode","nbRateUnits":"1","pauseType":"queue","timeout":1,"timeoutUnits":"seconds","rate":4,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var t = Date.now();
|
||||
helperNode1.on("input", function(msg) {
|
||||
msg.should.have.a.property('payload');
|
||||
msg.should.have.a.property('topic');
|
||||
try {
|
||||
if (msg.topic === "_none_") {
|
||||
msg.payload.should.equal(2);
|
||||
(Date.now() - t).should.be.approximately(500,200);
|
||||
}
|
||||
else if (msg.topic === "A") {
|
||||
msg.payload.should.equal(4);
|
||||
(Date.now() - t).should.be.approximately(750,200);
|
||||
}
|
||||
else {
|
||||
msg.topic.should.equal("B");
|
||||
msg.payload.should.equal(1);
|
||||
(Date.now() - t).should.be.approximately(1000,200);
|
||||
done();
|
||||
}
|
||||
} catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
setTimeout(function() {
|
||||
// send test messages
|
||||
delayNode1.receive({payload:1}); // send something with blank topic
|
||||
delayNode1.receive({payload:1,topic:"A"}); // and something with a fixed topic
|
||||
delayNode1.receive({payload:1,topic:"B"}); // and something else with a fixed topic (3rd tick)
|
||||
delayNode1.receive({payload:2,topic:"A"}); // these should replace them in queue
|
||||
delayNode1.receive({payload:3,topic:"A"}); // ditto
|
||||
delayNode1.receive({payload:2}); // so only this should get out on first tick
|
||||
delayNode1.receive({payload:4,topic:"A"}); // and this one on second tick
|
||||
}, 275); // wait one tick beofre starting.. (to test no messages in queue path.)
|
||||
});
|
||||
});
|
||||
|
||||
it('handles timed queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"timed","timeout":1,"timeoutUnits":"seconds","rate":2,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var t = Date.now();
|
||||
helperNode1.on("input", function(msg) {
|
||||
msg.should.have.a.property('payload');
|
||||
msg.should.have.a.property('topic');
|
||||
try {
|
||||
if (msg.topic === "_none_") {
|
||||
msg.payload.should.equal(2);
|
||||
(Date.now() - t).should.be.approximately(500,200);
|
||||
}
|
||||
else if (msg.topic === "A") {
|
||||
msg.payload.should.equal(4);
|
||||
(Date.now() - t).should.be.approximately(500,200);
|
||||
}
|
||||
else {
|
||||
msg.topic.should.equal("B");
|
||||
msg.payload.should.equal(1);
|
||||
(Date.now() - t).should.be.approximately(500,200);
|
||||
done();
|
||||
}
|
||||
} catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
// send test messages
|
||||
delayNode1.receive({payload:1}); // send something with blank topic
|
||||
delayNode1.receive({payload:1,topic:"A"}); // and something with a fixed topic
|
||||
delayNode1.receive({payload:1,topic:"B"}); // and something else with a fixed topic
|
||||
delayNode1.receive({payload:2,topic:"A"}); // these should replace them in queue
|
||||
delayNode1.receive({payload:3,topic:"A"}); // ditto
|
||||
delayNode1.receive({payload:2}); // so all should go on first tick
|
||||
delayNode1.receive({payload:4,topic:"A"}); // and nothing on second
|
||||
});
|
||||
});
|
||||
|
||||
it('can flush delay queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"delay","timeout":1,"timeoutUnits":"seconds","rate":2,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var t = Date.now();
|
||||
var c = 0;
|
||||
helperNode1.on("input", function(msg) {
|
||||
msg.should.have.a.property('payload');
|
||||
msg.should.have.a.property('topic');
|
||||
try {
|
||||
if (msg.topic === "foo") {
|
||||
msg.payload.should.equal(1);
|
||||
(Date.now() - t).should.be.approximately(0,100);
|
||||
c = c + 1;
|
||||
}
|
||||
else {
|
||||
if (msg.topic === "bar") {
|
||||
msg.payload.should.equal(1);
|
||||
(Date.now() - t).should.be.approximately(0,100);
|
||||
c = c + 1;
|
||||
}
|
||||
}
|
||||
if (c === 5) { done(); }
|
||||
} catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
// send test messages
|
||||
delayNode1.receive({payload:1,topic:"foo"}); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({flush:true}); }); // reset the queue
|
||||
});
|
||||
});
|
||||
|
||||
it('can reset delay queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"delay","timeout":1,"timeoutUnits":"seconds","rate":2,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var t = Date.now();
|
||||
var c = 0;
|
||||
helperNode1.on("input", function(msg) {
|
||||
c = c + 1;
|
||||
});
|
||||
|
||||
setTimeout( function() {
|
||||
if (c === 0) { done(); }
|
||||
}, 700);
|
||||
|
||||
// send test messages
|
||||
delayNode1.receive({payload:1,topic:"foo"}); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({reset:true}); }); // reset the queue
|
||||
});
|
||||
});
|
||||
|
||||
it('can flush rate limit queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":1,"timeoutUnits":"seconds","rate":2,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var t = Date.now();
|
||||
var c = 0;
|
||||
helperNode1.on("input", function(msg) {
|
||||
msg.should.have.a.property('payload');
|
||||
msg.should.have.a.property('topic');
|
||||
try {
|
||||
if (msg.topic === "foo") {
|
||||
msg.payload.should.equal(1);
|
||||
(Date.now() - t).should.be.approximately(0,100);
|
||||
c = c + 1;
|
||||
}
|
||||
else {
|
||||
if (msg.topic === "bar") {
|
||||
msg.payload.should.equal(1);
|
||||
(Date.now() - t).should.be.approximately(0,100);
|
||||
c = c + 1;
|
||||
}
|
||||
}
|
||||
if (c === 5) { done(); }
|
||||
} catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
// send test messages
|
||||
delayNode1.receive({payload:1,topic:"foo"}); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({flush:true}); }); // reset the queue
|
||||
});
|
||||
});
|
||||
|
||||
it('can reset rate limit queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":1,"timeoutUnits":"seconds","rate":2,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(delayNode, flow, function() {
|
||||
var delayNode1 = helper.getNode("delayNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
var t = Date.now();
|
||||
var c = 0;
|
||||
helperNode1.on("input", function(msg) {
|
||||
msg.should.have.a.property('payload');
|
||||
msg.should.have.a.property('topic');
|
||||
try {
|
||||
if (msg.topic === "foo") {
|
||||
msg.payload.should.equal(1);
|
||||
(Date.now() - t).should.be.approximately(0,100);
|
||||
c = c + 1;
|
||||
}
|
||||
} catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
setTimeout( function() {
|
||||
if (c === 1) { done(); }
|
||||
}, 700);
|
||||
|
||||
// send test messages
|
||||
delayNode1.receive({payload:1,topic:"foo"}); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"bar"}); } ); // send something with blank topic
|
||||
setImmediate( function() { delayNode1.receive({reset:true}); }); // reset the queue
|
||||
});
|
||||
});
|
||||
});
|
974
test/nodes/core/function/89-trigger_spec.js
Normal file
974
test/nodes/core/function/89-trigger_spec.js
Normal file
@@ -0,0 +1,974 @@
|
||||
/**
|
||||
* 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 triggerNode = require("nr-test-utils").require("@node-red/nodes/core/function/89-trigger.js");
|
||||
var Context = require("nr-test-utils").require("@node-red/runtime/lib/nodes/context");
|
||||
var RED = require("nr-test-utils").require("node-red/lib/red");
|
||||
|
||||
describe('trigger node', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
function initContext(done) {
|
||||
Context.init({
|
||||
contextStorage: {
|
||||
memory0: {
|
||||
module: "memory"
|
||||
},
|
||||
memory1: {
|
||||
module: "memory"
|
||||
},
|
||||
memory2: {
|
||||
module: "memory"
|
||||
}
|
||||
}
|
||||
});
|
||||
Context.load().then(function () {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload().then(function () {
|
||||
return Context.clean({allNodes: {}});
|
||||
}).then(function () {
|
||||
return Context.close();
|
||||
}).then(function () {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
});
|
||||
|
||||
it("should be loaded with correct defaults", function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", "wires":[[]]}];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('name', 'triggerNode');
|
||||
n1.should.have.property('op1', '1');
|
||||
n1.should.have.property('op2', '0');
|
||||
n1.should.have.property('op1type', 'str');
|
||||
n1.should.have.property('op2type', 'str');
|
||||
n1.should.have.property('extend', "false");
|
||||
n1.should.have.property('units', 'ms');
|
||||
n1.should.have.property('duration', 250);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should be able to set delay in seconds", function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", units:"s", duration:"1", "wires":[[]]}];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('duration', 1000);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should be able to set delay in minutes", function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", units:"min", duration:"1", "wires":[[]]}];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('duration', 60000);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("should be able to set delay in hours", function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", units:"hr", duration:"1", "wires":[[]]}];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('duration', 3600000);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
function basicTest(type, val, rval) {
|
||||
it('should output 1st value when triggered ('+type+')', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:val, op1type:type, op2:"", op2type:"null", duration:"20", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
process.env[val] = rval;
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (rval) {
|
||||
msg.should.have.property("payload");
|
||||
should.deepEqual(msg.payload, rval);
|
||||
}
|
||||
else {
|
||||
msg.should.have.property("payload", val);
|
||||
}
|
||||
delete process.env[val];
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.emit("input", {payload:null});
|
||||
});
|
||||
});
|
||||
|
||||
it('should output 2st value when triggered ('+type+')', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"foo", op1type:"str", op2:val, op2type:type, duration:"20", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
process.env[val] = rval;
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.property("payload", "foo");
|
||||
c++;
|
||||
}
|
||||
else {
|
||||
if (rval) {
|
||||
msg.should.have.property("payload");
|
||||
should.deepEqual(msg.payload, rval);
|
||||
}
|
||||
else {
|
||||
msg.should.have.property("payload", val);
|
||||
}
|
||||
delete process.env[val];
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.emit("input", {payload:null});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
basicTest("num", 10);
|
||||
basicTest("str", "10");
|
||||
basicTest("bool", true);
|
||||
var val_json = '{ "x":"vx", "y":"vy", "z":"vz" }';
|
||||
basicTest("json", val_json, JSON.parse(val_json));
|
||||
var val_buf = "[1,2,3,4,5]";
|
||||
basicTest("bin", val_buf, Buffer.from(JSON.parse(val_buf)));
|
||||
basicTest("env", "NR-TEST", "env-val");
|
||||
|
||||
it('should output 1 then 0 when triggered (default)', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"20", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", '1');
|
||||
c+=1;
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", '0');
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.emit("input", {payload:null});
|
||||
});
|
||||
});
|
||||
|
||||
it('should ignore any other inputs while triggered if extend is false', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"50",wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
var errored = false;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", '1');
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", '0');
|
||||
}
|
||||
c+=1;
|
||||
}catch(err) {
|
||||
errored = true;
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
setTimeout( function() {
|
||||
if (!errored) {
|
||||
try {
|
||||
c.should.equal(2);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
}
|
||||
},100);
|
||||
n1.emit("input", {payload:null});
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:null});
|
||||
},10);
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:null});
|
||||
},30);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle true and false as strings and delay of 0', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"true",op1type:"val",op2:"false",op2type:"val",duration:"30", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", true);
|
||||
c+=1;
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", false);
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.emit("input", {payload:null});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple topics as one if not asked to handle', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", bytopic:"all", op1:"1", op2:"0", op1type:"num", op2type:"num", duration:"30", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
c += 1;
|
||||
if (c === 1) {
|
||||
msg.should.have.a.property("payload", 1);
|
||||
msg.should.have.a.property("topic", "A");
|
||||
}
|
||||
else if (c === 2) {
|
||||
msg.should.have.a.property("payload", 0);
|
||||
msg.should.have.a.property("topic", "A");
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.emit("input", {payload:1,topic:"A"});
|
||||
n1.emit("input", {payload:2,topic:"B"});
|
||||
n1.emit("input", {payload:3,topic:"C"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple topics individually if asked to do so', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", bytopic:"topic", op1:"1", op2:"0", op1type:"num", op2type:"num", duration:"30", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
c += 1;
|
||||
if (c === 1) {
|
||||
msg.should.have.a.property("payload", 1);
|
||||
msg.should.have.a.property("topic", "A");
|
||||
}
|
||||
else if (c === 2) {
|
||||
msg.should.have.a.property("payload", 1);
|
||||
msg.should.have.a.property("topic", "B");
|
||||
}
|
||||
else if (c === 3) {
|
||||
msg.should.have.a.property("payload", 1);
|
||||
msg.should.have.a.property("topic", "C");
|
||||
}
|
||||
else if (c === 4) {
|
||||
msg.should.have.a.property("payload", 0);
|
||||
msg.should.have.a.property("topic", "A");
|
||||
}
|
||||
else if (c === 5) {
|
||||
msg.should.have.a.property("payload", 0);
|
||||
msg.should.have.a.property("topic", "B");
|
||||
}
|
||||
else if (c === 6) {
|
||||
msg.should.have.a.property("payload", 0);
|
||||
msg.should.have.a.property("topic", "C");
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.emit("input", {payload:1,topic:"A"});
|
||||
n1.emit("input", {payload:2,topic:"B"});
|
||||
n1.emit("input", {payload:3,topic:"C"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle multiple topics individually, and extend one, if asked to do so', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", bytopic:"topic", extend:"true", op1:"1", op2:"0", op1type:"num", op2type:"num", duration:"30", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
c += 1;
|
||||
if (c === 1) {
|
||||
msg.should.have.a.property("payload", 1);
|
||||
msg.should.have.a.property("topic", "A");
|
||||
}
|
||||
else if (c === 2) {
|
||||
msg.should.have.a.property("payload", 1);
|
||||
msg.should.have.a.property("topic", "B");
|
||||
}
|
||||
else if (c === 3) {
|
||||
msg.should.have.a.property("payload", 1);
|
||||
msg.should.have.a.property("topic", "C");
|
||||
}
|
||||
else if (c === 4) {
|
||||
msg.should.have.a.property("payload", 0);
|
||||
msg.should.have.a.property("topic", "A");
|
||||
}
|
||||
else if (c === 5) {
|
||||
msg.should.have.a.property("payload", 0);
|
||||
msg.should.have.a.property("topic", "C");
|
||||
}
|
||||
else if (c === 6) {
|
||||
msg.should.have.a.property("payload", 0);
|
||||
msg.should.have.a.property("topic", "B");
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.emit("input", {payload:1,topic:"A"});
|
||||
n1.emit("input", {payload:2,topic:"B"});
|
||||
n1.emit("input", {payload:3,topic:"C"});
|
||||
setTimeout( function() { n1.emit("input", {payload:2,topic:"B"})}, 20 );
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to return things from flow and global context variables', function(done) {
|
||||
var spy = sinon.stub(RED.util, 'evaluateNodeProperty',
|
||||
function(arg1, arg2, arg3, arg4, arg5) { if (arg5) { arg5(null, arg1) } else { return arg1; } }
|
||||
);
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"foo", op1type:"flow", op2:"bar", op2type:"global", duration:"20", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", "foo");
|
||||
c+=1;
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "bar");
|
||||
RED.util.evaluateNodeProperty.restore();
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { RED.util.evaluateNodeProperty.restore(); done(err); }
|
||||
});
|
||||
n1.emit("input", {payload:null});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to return things from persistable flow and global context variables', function (done) {
|
||||
var flow = [{"id": "n1", "type": "trigger", "name": "triggerNode", "op1": "#:(memory1)::foo", "op1type": "flow",
|
||||
"op2": "#:(memory1)::bar", "op2type": "global", "duration": "20", "wires": [["n2"]], "z": "flow" },
|
||||
{"id": "n2", "type": "helper"}];
|
||||
helper.load(triggerNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", "foo");
|
||||
c += 1;
|
||||
} else {
|
||||
msg.should.have.a.property("payload", "bar");
|
||||
done();
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var context = n1.context();
|
||||
var flow = context.flow;
|
||||
var global = context.global;
|
||||
flow.set("foo", "foo", "memory1", function (err) {
|
||||
global.set("bar", "bar", "memory1", function (err) {
|
||||
n1.emit("input", { payload: null });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to return things from multiple persistable global context variables', function (done) {
|
||||
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
|
||||
"duration": "20", "wires": [["n2"]],
|
||||
"op1": "#:(memory1)::val", "op1type": "global",
|
||||
"op2": "#:(memory2)::val", "op2type": "global"
|
||||
},
|
||||
{"id": "n2", "type": "helper"}];
|
||||
helper.load(triggerNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
if (count === 0) {
|
||||
msg.should.have.a.property("payload", "foo");
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "bar");
|
||||
}
|
||||
count++;
|
||||
if (count === 1) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var global = n1.context().global;
|
||||
global.set("val", "foo", "memory1", function (err) {
|
||||
global.set("val", "bar", "memory2", function (err) {
|
||||
n1.emit("input", { payload: null });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to return things from multiple persistable flow context variables', function (done) {
|
||||
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
|
||||
"duration": "20", "wires": [["n2"]],
|
||||
"op1": "#:(memory1)::val", "op1type": "flow",
|
||||
"op2": "#:(memory2)::val", "op2type": "flow"
|
||||
},
|
||||
{"id": "n2", "type": "helper"}];
|
||||
helper.load(triggerNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
if (count === 0) {
|
||||
msg.should.have.a.property("payload", "foo");
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "bar");
|
||||
}
|
||||
count++;
|
||||
if (count === 1) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var flow = n1.context().flow;
|
||||
flow.set("val", "foo", "memory1", function (err) {
|
||||
flow.set("val", "bar", "memory2", function (err) {
|
||||
n1.emit("input", { payload: null });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to return things from multiple persistable flow & global context variables', function (done) {
|
||||
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
|
||||
"duration": "20", "wires": [["n2"]],
|
||||
"op1": "#:(memory1)::val", "op1type": "flow",
|
||||
"op2": "#:(memory2)::val", "op2type": "global"
|
||||
},
|
||||
{"id": "n2", "type": "helper"}];
|
||||
helper.load(triggerNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
if (count === 0) {
|
||||
msg.should.have.a.property("payload", "foo");
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "bar");
|
||||
}
|
||||
count++;
|
||||
if (count === 1) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var context = n1.context();
|
||||
var flow = context.flow;
|
||||
var global = context.flow;
|
||||
flow.set("val", "foo", "memory1", function (err) {
|
||||
global.set("val", "bar", "memory2", function (err) {
|
||||
n1.emit("input", { payload: null });
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to not output anything on first trigger', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"nul", op1:"true",op2:"false",op2type:"val",duration:"30", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.a.property("payload", false);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.emit("input", {payload:null});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to not output anything on second edge', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op2type:"nul", op1:"true",op1type:"val", op2:"false", duration:"30", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.a.property("payload", true);
|
||||
c += 1;
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
setTimeout( function() {
|
||||
c.should.equal(1); // should only have had one output.
|
||||
done();
|
||||
},90);
|
||||
n1.emit("input", {payload:null});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to reset correctly having not output anything on second edge', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op2type:"nul", op1:"true",op1type:"val", op2:"false", duration:"35", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.a.property("payload", true);
|
||||
c += 1;
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
setTimeout( function() {
|
||||
c.should.equal(3); // should only have had one output.
|
||||
done();
|
||||
},300);
|
||||
n1.emit("input", {payload:1});
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:2});
|
||||
},100);
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:3});
|
||||
},200);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to extend the delay', function(done) {
|
||||
this.timeout(5000); // add extra time for flake
|
||||
var spy = sinon.stub(RED.util, 'evaluateNodeProperty',
|
||||
function(arg1, arg2, arg3, arg4, arg5) { if (arg5) { arg5(null, arg1) } else { return arg1; } }
|
||||
);
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"flow", op1:"foo", op2:"bar", op2type:"global", duration:"100", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", "foo");
|
||||
c += 1;
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "bar");
|
||||
//console.log(Date.now() - ss);
|
||||
(Date.now() - ss).should.be.greaterThan(149);
|
||||
spy.restore();
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { spy.restore(); done(err); }
|
||||
});
|
||||
var ss = Date.now();
|
||||
n1.emit("input", {payload:"Hello"});
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:null});
|
||||
},50);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to extend the delay (but with no 2nd output)', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"pay", op2type:"nul", op1:"false", op2:"true", duration:"200", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", "Hello");
|
||||
c += 1;
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "World");
|
||||
(Date.now() - ss).should.be.greaterThan(300);
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var ss = Date.now();
|
||||
n1.emit("input", {payload:"Hello"});
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"Error"});
|
||||
},50);
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"Error"});
|
||||
},100);
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"World"});
|
||||
},330);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to extend the delay and output the most recent payload', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"nul", op2type:"payl", op1:"false", op2:"true", duration:"60", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.a.property("payload", "World");
|
||||
(Date.now() - ss).should.be.greaterThan(120);
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
var ss = Date.now();
|
||||
n1.emit("input", {payload:"Hello"});
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"Goodbye"});
|
||||
},40);
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"World"});
|
||||
},80);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able output the 2nd payload', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"false", op1type:"nul", op2type:"payl", op1:"false", op2:"true", duration:"50", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", "Goodbye");
|
||||
c += 1;
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "World");
|
||||
(Date.now() - ss).should.be.greaterThan(70);
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
var ss = Date.now();
|
||||
n1.emit("input", {payload:"Hello"});
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"Goodbye"});
|
||||
},20);
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {payload:"World"});
|
||||
},80);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to apply mustache templates to payloads', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"val", op1:"{{payload}}", op2:"{{topic}}", duration:"50", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", "Hello");
|
||||
c+=1;
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "World");
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.emit("input", {payload:"Hello",topic:"World"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle string null as null', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"pay", op1:"null", op2:"null", duration:"40", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", null);
|
||||
c+=1;
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", "World");
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.emit("input", {payload:"World"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle string null as null on op2', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1type:"val", op2type:"val", op1:"null", op2:"null", duration:"40", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (c === 0) {
|
||||
msg.should.have.a.property("payload", null);
|
||||
c+=1;
|
||||
}
|
||||
else {
|
||||
msg.should.have.a.property("payload", null);
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.emit("input", {payload:"null"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to set infinite timeout, and clear timeout', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"0", extend: false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
c += 1;
|
||||
msg.should.have.a.property("payload", "1");
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
setTimeout( function() {
|
||||
if (c === 2) { done(); }
|
||||
else {
|
||||
done(new Error("Too many messages received"));
|
||||
}
|
||||
},20);
|
||||
n1.emit("input", {payload:null}); // trigger
|
||||
n1.emit("input", {payload:null}); // blocked
|
||||
n1.emit("input", {payload:null}); // blocked
|
||||
n1.emit("input", {reset:true}); // clear the blockage
|
||||
n1.emit("input", {payload:null}); // trigger
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to set infinite timeout, and clear timeout by message', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", reset:"boo", duration:"0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
c += 1;
|
||||
msg.should.have.a.property("payload", "1");
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
setTimeout( function() {
|
||||
if (c === 2) { done(); }
|
||||
else {
|
||||
done(new Error("Too many messages received"));
|
||||
}
|
||||
},20);
|
||||
n1.emit("input", {payload:null}); // trigger
|
||||
n1.emit("input", {payload:null}); // blocked
|
||||
n1.emit("input", {payload:null}); // blocked
|
||||
n1.emit("input", {payload:"foo"}); // don't clear the blockage
|
||||
n1.emit("input", {payload:"boo"}); // clear the blockage
|
||||
n1.emit("input", {payload:null}); // trigger
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to set infinite timeout, and clear timeout by boolean true', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", reset:"true", duration:"0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
c += 1;
|
||||
msg.should.have.a.property("payload", "1");
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
setTimeout( function() {
|
||||
if (c === 2) { done(); }
|
||||
else {
|
||||
done(new Error("Too many messages received"));
|
||||
}
|
||||
},20);
|
||||
n1.emit("input", {payload:null}); // trigger
|
||||
n1.emit("input", {payload:null}); // blocked
|
||||
n1.emit("input", {payload:null}); // blocked
|
||||
n1.emit("input", {payload:false}); // don't clear the blockage
|
||||
n1.emit("input", {payload:true}); // clear the blockage
|
||||
n1.emit("input", {payload:null}); // trigger
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to set infinite timeout, and clear timeout by boolean false', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", reset:"false", duration:"0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
c += 1;
|
||||
msg.should.have.a.property("payload", "1");
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
setTimeout( function() {
|
||||
if (c === 2) { done(); }
|
||||
else {
|
||||
done(new Error("Too many messages received"));
|
||||
}
|
||||
},20);
|
||||
n1.emit("input", {payload:null}); // trigger
|
||||
n1.emit("input", {payload:null}); // blocked
|
||||
n1.emit("input", {payload:null}); // blocked
|
||||
n1.emit("input", {payload:"foo"}); // don't clear the blockage
|
||||
n1.emit("input", {payload:false}); // clear the blockage
|
||||
n1.emit("input", {payload:null}); // trigger
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to set a repeat, and clear loop by reset', function(done) {
|
||||
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", reset:"boo", op1:"", op1type:"pay", duration:-25, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(triggerNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var c = 0;
|
||||
n2.on("input", function(msg) {
|
||||
c += 1;
|
||||
try {
|
||||
msg.should.have.property('payload','foo');
|
||||
msg.payload = "bar"; // try to provoke pass by reference error
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.emit("input", {payload:"foo"}); // trigger
|
||||
n1.emit("input", {payload:"foo"}); // trigger
|
||||
setTimeout( function() {
|
||||
n1.emit("input", {reset:true}); // reset
|
||||
},90);
|
||||
setTimeout( function() {
|
||||
c.should.within(2,5); // should send foo between 2 and 5 times.
|
||||
done();
|
||||
},180);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
919
test/nodes/core/function/90-exec_spec.js
Normal file
919
test/nodes/core/function/90-exec_spec.js
Normal file
@@ -0,0 +1,919 @@
|
||||
/**
|
||||
* 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() {
|
||||
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",true);
|
||||
n1.should.have.property("timer",0);
|
||||
n1.should.have.property("oldrc","false");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
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',
|
||||
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 extra parameters', 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',
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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',
|
||||
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");
|
||||
n2.on("input", function(msg) {
|
||||
//console.log(msg);
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.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";
|
||||
}
|
||||
|
||||
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();
|
||||
msg.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) {
|
||||
messages[0] = msg;
|
||||
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) {
|
||||
messages[0] = msg;
|
||||
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"});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user