mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Merge pull request #4320 from node-red/dev
Sync `dev` to `master` for 3.1.0 release
This commit is contained in:
6
test/node_modules/nr-test-utils/index.js
generated
vendored
6
test/node_modules/nr-test-utils/index.js
generated
vendored
@@ -16,7 +16,6 @@
|
||||
|
||||
|
||||
const path = require("path");
|
||||
const fs = require("fs");
|
||||
|
||||
const PACKAGE_ROOT = "../../../packages/node_modules";
|
||||
|
||||
@@ -27,5 +26,10 @@ module.exports = {
|
||||
},
|
||||
resolve: function(file) {
|
||||
return path.resolve(path.join(__dirname,PACKAGE_ROOT,file));
|
||||
},
|
||||
sleep: async (time) => {
|
||||
return new Promise(resolve => {
|
||||
setTimeout(resolve, time)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@@ -22,7 +22,9 @@ var helper = require("node-red-node-test-helper");
|
||||
describe('inject node', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helper.startServer(done);
|
||||
helper.startServer(() => {
|
||||
done()
|
||||
});
|
||||
});
|
||||
|
||||
function initContext(done) {
|
||||
@@ -41,7 +43,7 @@ describe('inject node', function() {
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(function(done) {
|
||||
afterEach(async function() {
|
||||
helper.unload().then(function () {
|
||||
return Context.clean({allNodes: {}});
|
||||
}).then(function () {
|
||||
@@ -53,8 +55,11 @@ describe('inject node', function() {
|
||||
|
||||
function basicTest(type, val, rval) {
|
||||
it('inject value ('+type+')', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", topic: "t1", payload: val, payloadType: type, wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
var flow = [
|
||||
{id:'flow', type:'tab'},
|
||||
{id: "n1", type: "inject", topic: "t1", payload: val, payloadType: type, wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper", z:'flow'}
|
||||
];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
@@ -93,6 +98,7 @@ describe('inject node', function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
delete process.env.NR_TEST
|
||||
try {
|
||||
msg.should.have.property("topic", "t1");
|
||||
msg.should.have.property("payload", "foo");
|
||||
@@ -101,13 +107,13 @@ describe('inject node', function() {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
process.env.NR_TEST = 'foo';
|
||||
process.env.NR_TEST = 'foo';
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('inject name of node as environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "NR_NODE_NAME", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "NR_NODE_NAME", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -125,7 +131,7 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject id of node as environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "NR_NODE_ID", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "NR_NODE_ID", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -143,7 +149,7 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject path of node as environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "NR_NODE_PATH", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "NR_NODE_PATH", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -162,7 +168,7 @@ describe('inject node', function() {
|
||||
|
||||
|
||||
it('inject name of flow as environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "NR_FLOW_NAME", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "NR_FLOW_NAME", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "flow", type: "tab", label: "FLOW" },
|
||||
];
|
||||
@@ -182,7 +188,7 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject id of flow as environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "NR_FLOW_ID", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "NR_FLOW_ID", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "flow", type: "tab", name: "FLOW" },
|
||||
];
|
||||
@@ -202,9 +208,10 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject name of group as environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "NR_GROUP_NAME", payloadType: "env", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "g0", type: "group", name: "GROUP" },
|
||||
var flow = [{id: "flow", type: "tab" },
|
||||
{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "NR_GROUP_NAME", payloadType: "env", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper", z: "flow"},
|
||||
{id: "g0", type: "group", name: "GROUP", z: "flow" },
|
||||
];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -222,9 +229,10 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject id of group as environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "NR_GROUP_ID", payloadType: "env", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "g0", type: "group", name: "GROUP" },
|
||||
var flow = [{id: "flow", type: "tab" },
|
||||
{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "NR_GROUP_ID", payloadType: "env", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper", z: "flow"},
|
||||
{id: "g0", type: "group", name: "GROUP", z: "flow" },
|
||||
];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -243,8 +251,9 @@ describe('inject node', function() {
|
||||
|
||||
|
||||
it('inject name of node as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_NODE_NAME}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
var flow = [{id: "flow", type: "tab" },
|
||||
{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "${NR_NODE_NAME}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper", z: "flow"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
@@ -261,7 +270,7 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject id of node as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_NODE_ID}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "${NR_NODE_ID}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -279,7 +288,7 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject path of node as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_NODE_PATH}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "${NR_NODE_PATH}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -298,7 +307,7 @@ describe('inject node', function() {
|
||||
|
||||
|
||||
it('inject name of flow as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_FLOW_NAME}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "${NR_FLOW_NAME}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "flow", type: "tab", label: "FLOW" },
|
||||
];
|
||||
@@ -318,7 +327,7 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject id of flow as environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_FLOW_ID}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "${NR_FLOW_ID}", payloadType: "str", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "flow", type: "tab", name: "FLOW" },
|
||||
];
|
||||
@@ -338,9 +347,10 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject name of group as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_GROUP_NAME}", payloadType: "str", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "g0", type: "group", name: "GROUP" },
|
||||
var flow = [{id: "flow", type: "tab" },
|
||||
{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "${NR_GROUP_NAME}", payloadType: "str", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper", z: "flow"},
|
||||
{id: "g0", type: "group", name: "GROUP", z: "flow" },
|
||||
];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -358,9 +368,10 @@ describe('inject node', function() {
|
||||
});
|
||||
|
||||
it('inject id of group as environment variable by substitution ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", name: "NAME", topnic: "t1", payload: "${NR_GROUP_ID}", payloadType: "str", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper"},
|
||||
{id: "g0", type: "group", name: "GROUP" },
|
||||
var flow = [{id: "flow", type: "tab" },
|
||||
{id: "n1", type: "inject", name: "NAME", topic: "t1", payload: "${NR_GROUP_ID}", payloadType: "str", wires: [["n2"]], z: "flow", g: "g0"},
|
||||
{id: "n2", type: "helper", z: "flow"},
|
||||
{id: "g0", type: "group", name: "GROUP", z: "flow" },
|
||||
];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
|
73
test/nodes/core/common/91-global-config_spec.js
Normal file
73
test/nodes/core/common/91-global-config_spec.js
Normal file
@@ -0,0 +1,73 @@
|
||||
var should = require("should");
|
||||
var config = require("nr-test-utils").require("@node-red/nodes/core/common/91-global-config.js");
|
||||
var inject = require("nr-test-utils").require("@node-red/nodes/core/common/20-inject.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('Global Config Node', function() {
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"n1", type:"global-config", name: "XYZ" }];
|
||||
helper.load(config, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property("name", "XYZ");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should access global environment variable', function(done) {
|
||||
var flow = [{id:"n1", type:"global-config", name: "XYZ",
|
||||
env: [ {
|
||||
name: "X",
|
||||
type: "string",
|
||||
value: "foo"
|
||||
}]
|
||||
},
|
||||
{id: "n2", type: "inject", topic: "t1", payload: "X", payloadType: "env", wires: [["n3"]], z: "flow"},
|
||||
{id: "n3", type: "helper"}
|
||||
];
|
||||
helper.load([config, inject], flow, function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
n3.on("input", (msg) => {
|
||||
try {
|
||||
msg.should.have.property("payload", "foo");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n2.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('should evaluate a global environment variable that is a JSONata value', function (done) {
|
||||
const flow = [{
|
||||
id: "n1", type: "global-config", name: "XYZ",
|
||||
env: [
|
||||
{ name: "now-var", type: "jsonata", value: "$millis()" }
|
||||
]
|
||||
},
|
||||
{ id: "n2", type: "inject", topic: "t1", payload: "now-var", payloadType: "env", wires: [["n3"]], z: "flow" },
|
||||
{ id: "n3", type: "helper" }
|
||||
];
|
||||
helper.load([config, inject], flow, function () {
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
n3.on("input", (msg) => {
|
||||
try {
|
||||
const now = Date.now();
|
||||
msg.should.have.property("payload").and.be.approximately(now, 1000);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n2.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -1424,7 +1424,58 @@ describe('function node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should timeout if timeout is set', function(done) {
|
||||
var flow = [{id:"n1",type:"function",wires:[["n2"]],timeout:"0.010",func:"while(1==1){};\nreturn msg;"}];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "function";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
var msg = logEvents[0][0];
|
||||
msg.should.have.property('level', helper.log().ERROR);
|
||||
msg.should.have.property('id', 'n1');
|
||||
msg.should.have.property('type', 'function');
|
||||
should.equal(msg.msg.message, 'Script execution timed out after 10ms');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
},50);
|
||||
});
|
||||
});
|
||||
|
||||
it('check if default function timeout settings are recognized', function (done) {
|
||||
RED.settings.functionTimeout = 0.01;
|
||||
var flow = [{id: "n1",type: "function",timeout: RED.settings.functionTimeout,wires: [["n2"]],func: "while(1==1){};\nreturn msg;"}];
|
||||
helper.load(functionNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.receive({ payload: "foo", topic: "bar" });
|
||||
setTimeout(function () {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function (evt) {
|
||||
return evt[0].type == "function";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
var msg = logEvents[0][0];
|
||||
msg.should.have.property('level', helper.log().ERROR);
|
||||
msg.should.have.property('id', 'n1');
|
||||
msg.should.have.property('type', 'function');
|
||||
should.equal(RED.settings.functionTimeout, 0.01);
|
||||
should.equal(msg.msg.message, 'Script execution timed out after 10ms');
|
||||
delete RED.settings.functionTimeout;
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
}, 500);
|
||||
});
|
||||
});
|
||||
|
||||
describe("finalize function", function() {
|
||||
|
||||
|
@@ -568,11 +568,12 @@ describe('change Node', function() {
|
||||
|
||||
it('sets the value using env property from group', function(done) {
|
||||
var flow = [
|
||||
{"id": "flow", type:"tab"},
|
||||
{"id":"group1","type":"group","env":[
|
||||
{"name":"NR_TEST_A", "value":"bar", "type": "str"}
|
||||
]},
|
||||
{"id":"changeNode1","type":"change","g":"group1",rules:[{"t":"set","p":"payload","pt":"msg","to":"NR_TEST_A","tot":"env"}],"name":"changeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}
|
||||
], z: "flow"},
|
||||
{"id":"changeNode1","type":"change","g":"group1",rules:[{"t":"set","p":"payload","pt":"msg","to":"NR_TEST_A","tot":"env"}],"name":"changeNode","wires":[["helperNode1"]], z: "flow"},
|
||||
{id:"helperNode1", type:"helper", wires:[], z: "flow"}
|
||||
];
|
||||
helper.load(changeNode, flow, function() {
|
||||
var changeNode1 = helper.getNode("changeNode1");
|
||||
@@ -591,12 +592,13 @@ describe('change Node', function() {
|
||||
|
||||
it('sets the value using env property from nested group', function(done) {
|
||||
var flow = [
|
||||
{"id": "flow", type:"tab"},
|
||||
{"id":"group1","type":"group","env":[
|
||||
{"name":"NR_TEST_A", "value":"bar", "type": "str"}
|
||||
]},
|
||||
{"id":"group2","type":"group","g":"group1","env":[]},
|
||||
{"id":"changeNode1","type":"change","g":"group2",rules:[{"t":"set","p":"payload","pt":"msg","to":"NR_TEST_A","tot":"env"}],"name":"changeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}
|
||||
], z: "flow"},
|
||||
{"id":"group2","type":"group","g":"group1","env":[], z: "flow"},
|
||||
{"id":"changeNode1","type":"change","g":"group2",rules:[{"t":"set","p":"payload","pt":"msg","to":"NR_TEST_A","tot":"env"}],"name":"changeNode","wires":[["helperNode1"]], z: "flow"},
|
||||
{id:"helperNode1", type:"helper", wires:[], z: "flow"}
|
||||
];
|
||||
helper.load(changeNode, flow, function() {
|
||||
var changeNode1 = helper.getNode("changeNode1");
|
||||
|
@@ -106,6 +106,27 @@ describe('range Node', function() {
|
||||
genericRangeTest("clamp", 0, 10, 0, 1000, false, -1, 0, done);
|
||||
});
|
||||
|
||||
it('drops msg if in drop mode and input outside range', function(done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","minin":2,"maxin":8,"minout":20,"maxout":80,"action":"drop","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.have.property('payload');
|
||||
msg.payload.should.equal(50);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
rangeNode1.receive({payload:1});
|
||||
rangeNode1.receive({payload:9});
|
||||
rangeNode1.receive({payload:5});
|
||||
});
|
||||
});
|
||||
|
||||
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:[]}];
|
||||
|
@@ -817,6 +817,105 @@ describe('delay Node', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('can part flush and reset rate limit queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":1,"timeoutUnits":"seconds","rate":1,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"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) {
|
||||
// console.log("GOT",Date.now() - t,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,50);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "bar") {
|
||||
msg.payload.should.equal(2);
|
||||
(Date.now() - t).should.be.approximately(200,100);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "fob") {
|
||||
msg.payload.should.equal(5);
|
||||
(Date.now() - t).should.be.approximately(400,100);
|
||||
c = 5;
|
||||
}
|
||||
if (c === 5) { done(); }
|
||||
} catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
// send test messages
|
||||
// delayNode1.receive({payload:1,topic:"foo"});
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"foo"}); } );
|
||||
setTimeout( function() { delayNode1.receive({payload:2,topic:"far"}); }, 10 );
|
||||
setTimeout( function() { delayNode1.receive({payload:3,topic:"boo"}); }, 20 );
|
||||
setTimeout( function() { delayNode1.receive({payload:4,topic:"bar"}); }, 30 );
|
||||
setTimeout( function() { delayNode1.receive({flush:2,reset:true}); }, 200);
|
||||
setTimeout( function() { delayNode1.receive({payload:5,topic:"fob"}); }, 300 );
|
||||
setTimeout( function() { delayNode1.receive({flush:1,reset:true}); }, 400);
|
||||
});
|
||||
});
|
||||
|
||||
it('can full flush and reset rate limit queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":1,"timeoutUnits":"seconds","rate":1,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"allowrate":false,"outputs":1,"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) {
|
||||
// console.log("GOT",Date.now() - t,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,50);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "bar") {
|
||||
msg.payload.should.equal(4);
|
||||
(Date.now() - t).should.be.approximately(200,100);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "all") {
|
||||
msg.payload.should.equal(5);
|
||||
(Date.now() - t).should.be.approximately(200,100);
|
||||
c = c + 1;
|
||||
}
|
||||
else if (msg.topic === "fob") {
|
||||
msg.payload.should.equal(6);
|
||||
(Date.now() - t).should.be.approximately(400,100);
|
||||
c = 5;
|
||||
}
|
||||
if (c === 5) { done(); }
|
||||
} catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
// send test messages
|
||||
// delayNode1.receive({payload:1,topic:"foo"});
|
||||
setImmediate( function() { delayNode1.receive({payload:1,topic:"foo"}); } );
|
||||
setTimeout( function() { delayNode1.receive({payload:2,topic:"far"}); }, 10 );
|
||||
setTimeout( function() { delayNode1.receive({payload:3,topic:"boo"}); }, 20 );
|
||||
setTimeout( function() { delayNode1.receive({payload:4,topic:"bar"}); }, 30 );
|
||||
setTimeout( function() { delayNode1.receive({payload:5,topic:"last",flush:true,reset:true}); }, 200);
|
||||
setTimeout( function() { delayNode1.receive({payload:6,topic:"fob"}); }, 300 );
|
||||
setTimeout( function() { delayNode1.receive({flush:1,reset:true}); }, 400);
|
||||
});
|
||||
});
|
||||
|
||||
it('can part push to front of rate limit queue', function(done) {
|
||||
this.timeout(2000);
|
||||
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":1,"timeoutUnits":"seconds","rate":1,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
|
||||
|
@@ -31,6 +31,7 @@ var multer = require("multer");
|
||||
var RED = require("nr-test-utils").require("node-red/lib/red");
|
||||
var fs = require('fs-extra');
|
||||
var auth = require('basic-auth');
|
||||
var crypto = require("crypto");
|
||||
const { version } = require("os");
|
||||
const net = require('net')
|
||||
|
||||
@@ -163,6 +164,100 @@ describe('HTTP Request Node', function() {
|
||||
delete process.env.NO_PROXY;
|
||||
}
|
||||
|
||||
function getDigestPassword() {
|
||||
return 'digest-test-password';
|
||||
}
|
||||
|
||||
function getDigest(algorithm, value) {
|
||||
var hash;
|
||||
if (algorithm === 'SHA-256') {
|
||||
hash = crypto.createHash('sha256');
|
||||
} else if (algorithm === 'SHA-512-256') {
|
||||
hash = crypto.createHash('sha512');
|
||||
} else {
|
||||
hash = crypto.createHash('md5');
|
||||
}
|
||||
|
||||
var hex = hash.update(value).digest('hex');
|
||||
if (algorithm === 'SHA-512-256') {
|
||||
hex = hex.slice(0, 64);
|
||||
}
|
||||
return hex;
|
||||
}
|
||||
|
||||
function getDigestResponse(req, algorithm, sess, realm, username, nonce, nc, cnonce, qop) {
|
||||
var ha1 = getDigest(algorithm, username + ':' + realm + ':' + getDigestPassword());
|
||||
if (sess) {
|
||||
ha1 = getDigest(algorithm, ha1 + ':' + nonce + ':' + cnonce)
|
||||
}
|
||||
let ha2 = getDigest(algorithm, req.method + ':' + req.path);
|
||||
return qop
|
||||
? getDigest(algorithm, ha1 + ':' + nonce + ':' + nc + ':' + cnonce + ':' + qop + ':' + ha2)
|
||||
: getDigest(algorithm, ha1 + ':' + nonce + ':' + ha2);
|
||||
}
|
||||
|
||||
function handleDigestResponse(req, res, algorithm, sess, qop) {
|
||||
let realm = "node-red";
|
||||
let nonce = "123456";
|
||||
let nc = '00000001';
|
||||
let algorithmValue = sess ? `${algorithm}-sess` : algorithm;
|
||||
|
||||
let authHeader = req.headers['authorization'];
|
||||
if (!authHeader) {
|
||||
let qopField = qop ? `qop="${qop}", ` : '';
|
||||
|
||||
res.setHeader(
|
||||
'WWW-Authenticate',
|
||||
`Digest ${qopField}realm="${realm}", nonce="${nonce}", algorithm="${algorithmValue}"`
|
||||
);
|
||||
res.status(401).end();
|
||||
return;
|
||||
}
|
||||
|
||||
var authFields = {};
|
||||
let re = /([a-z0-9_-]+)=(?:"([^"]+)"|([a-z0-9_-]+))/gi;
|
||||
for (;;) {
|
||||
var match = re.exec(authHeader);
|
||||
if (!match) {
|
||||
break;
|
||||
}
|
||||
authFields[match[1]] = match[2] || match[3];
|
||||
}
|
||||
// console.log(JSON.stringify(authFields));
|
||||
|
||||
if (qop && authFields['qop'] != qop) {
|
||||
console.log('test1');
|
||||
res.status(401).end();
|
||||
return;
|
||||
}
|
||||
|
||||
if (
|
||||
!authFields['username'] ||
|
||||
!authFields['response'] ||
|
||||
authFields['realm'] != realm ||
|
||||
authFields['nonce'] != nonce ||
|
||||
authFields['algorithm'] != algorithmValue
|
||||
) {
|
||||
console.log('test2');
|
||||
res.status(401).end();
|
||||
return;
|
||||
}
|
||||
|
||||
let username = authFields['username'];
|
||||
let response = authFields['response'];
|
||||
let cnonce = authFields['cnonce'] || '';
|
||||
let expectedResponse = getDigestResponse(
|
||||
req, algorithm, sess, realm, username, nonce, nc, cnonce, qop
|
||||
);
|
||||
if (!response || expectedResponse.toLowerCase() !== response.toLowerCase()) {
|
||||
console.log('test3', response, expectedResponse);
|
||||
res.status(401).end();
|
||||
return;
|
||||
}
|
||||
|
||||
res.status(201).end();
|
||||
}
|
||||
|
||||
before(function(done) {
|
||||
|
||||
testApp = express();
|
||||
@@ -222,6 +317,21 @@ describe('HTTP Request Node', function() {
|
||||
}
|
||||
res.json(result);
|
||||
});
|
||||
testApp.get('/authenticate-digest-md5', function(req, res){
|
||||
handleDigestResponse(req, res, "MD5", false, false);
|
||||
});
|
||||
testApp.get('/authenticate-digest-md5-sess', function(req, res){
|
||||
handleDigestResponse(req, res, "MD5", true, 'auth');
|
||||
});
|
||||
testApp.get('/authenticate-digest-md5-qop', function(req, res){
|
||||
handleDigestResponse(req, res, "MD5", false, 'auth');
|
||||
});
|
||||
testApp.get('/authenticate-digest-sha-256', function(req, res){
|
||||
handleDigestResponse(req, res, "SHA-256", false, 'auth');
|
||||
});
|
||||
testApp.get('/authenticate-digest-sha-512-256', function(req, res){
|
||||
handleDigestResponse(req, res, "SHA-512-256", false, 'auth');
|
||||
});
|
||||
testApp.get('/proxyAuthenticate', function(req, res){
|
||||
// var user = auth.parse(req.headers['proxy-authorization']);
|
||||
var result = {
|
||||
@@ -557,7 +667,7 @@ describe('HTTP Request Node', function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload','');
|
||||
msg.should.have.property('payload',{});
|
||||
msg.should.have.property('statusCode',204);
|
||||
done();
|
||||
} catch(err) {
|
||||
@@ -2018,6 +2128,100 @@ describe('HTTP Request Node', function() {
|
||||
});
|
||||
*/
|
||||
|
||||
it('should authenticate on server - digest MD5', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",authType:"digest", url:getTestURL('/authenticate-digest-md5')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.credentials = {user:'xxxuser', password:getDigestPassword()};
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('statusCode',201);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should authenticate on server - digest MD5 sess', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",authType:"digest", url:getTestURL('/authenticate-digest-md5-sess')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.credentials = {user:'xxxuser', password:getDigestPassword()};
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('statusCode',201);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should authenticate on server - digest MD5 qop', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",authType:"digest", url:getTestURL('/authenticate-digest-md5-qop')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.credentials = {user:'xxxuser', password:getDigestPassword()};
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('statusCode',201);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should authenticate on server - digest SHA-256', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",authType:"digest", url:getTestURL('/authenticate-digest-sha-256')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.credentials = {user:'xxxuser', password:getDigestPassword()};
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('statusCode',201);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should authenticate on server - digest SHA-512-256', function(done) {
|
||||
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"GET",ret:"obj",authType:"digest", url:getTestURL('/authenticate-digest-sha-512-256')},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(httpRequestNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.credentials = {user:'xxxuser', password:getDigestPassword()};
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('statusCode',201);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('file-upload', function() {
|
||||
|
@@ -53,7 +53,7 @@ describe('MQTT Nodes', function () {
|
||||
mqttBroker.should.have.property('broker', BROKER_HOST);
|
||||
mqttBroker.should.have.property('port', BROKER_PORT);
|
||||
mqttBroker.should.have.property('brokerurl');
|
||||
// mqttBroker.should.have.property('autoUnsubscribe', true);//default: true
|
||||
mqttBroker.should.have.property('autoUnsubscribe', true); //default: true
|
||||
mqttBroker.should.have.property('autoConnect', false);//Set "autoConnect:false" in brokerOptions
|
||||
mqttBroker.should.have.property('options');
|
||||
mqttBroker.options.should.have.property('clean', true);
|
||||
@@ -96,8 +96,8 @@ describe('MQTT Nodes', function () {
|
||||
mqttBroker.should.have.property('broker', BROKER_HOST);
|
||||
mqttBroker.should.have.property('port', BROKER_PORT);
|
||||
mqttBroker.should.have.property('brokerurl');
|
||||
// mqttBroker.should.have.property('autoUnsubscribe', true);//default: true
|
||||
mqttBroker.should.have.property('autoConnect', false);//Set "autoConnect:false" in brokerOptions
|
||||
mqttBroker.should.have.property('autoUnsubscribe', true);
|
||||
mqttBroker.should.have.property('autoConnect', false); //Set "autoConnect:false" in brokerOptions
|
||||
mqttBroker.should.have.property('options');
|
||||
mqttBroker.options.should.have.property('clean', false);
|
||||
mqttBroker.options.should.have.property('clientId', 'clientid');
|
||||
|
@@ -173,7 +173,7 @@ describe('JSON node', function() {
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("Unexpected token o");
|
||||
logEvents[0][0].msg.should.match(/^Unexpected token (o|'o')/);
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
@@ -199,7 +199,7 @@ describe('JSON node', function() {
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("Unexpected token o");
|
||||
logEvents[0][0].msg.should.match(/^Unexpected token (o|'o')/);
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
|
@@ -98,6 +98,29 @@ describe('file Nodes', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should write to a file using JSONata', function(done) {
|
||||
var fileToTest4jsonata = "'" + resourcesDir + "/'&(20+30)&'-file-test-file.txt'";
|
||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename": fileToTest4jsonata, "filenameType": "jsonata", "appendNewline":false, "overwriteFile":true, wires: [["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper"}];
|
||||
helper.load(fileNode, flow, function() {
|
||||
var n1 = helper.getNode("fileNode1");
|
||||
var n2 = helper.getNode("helperNode1");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
var f = fs.readFileSync(fileToTest);
|
||||
f.should.have.length(4);
|
||||
fs.unlinkSync(fileToTest);
|
||||
msg.should.have.property("payload", "test");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"test"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should write to a file using RED.settings.fileWorkingDirectory', function(done) {
|
||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":relativePathToFile, "appendNewline":false, "overwriteFile":true, wires: [["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper"}];
|
||||
@@ -121,7 +144,6 @@ describe('file Nodes', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should write multi-byte string to a file', function(done) {
|
||||
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":true, wires: [["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper"}];
|
||||
@@ -423,6 +445,31 @@ describe('file Nodes', function() {
|
||||
n1.receive({payload:"typedInput", _user_specified_filename:fileToTest});
|
||||
});
|
||||
});
|
||||
|
||||
it('should support number in msg._user_specified_filename', function (done) {
|
||||
var flow = [{id:"fileNode1", type:"file", filename:"_user_specified_filename", filenameType:"msg", name:"fileNode", "appendNewline":false, "overwriteFile":true, wires:[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper"}];
|
||||
helper.load(fileNode, flow, function () {
|
||||
RED.settings.fileWorkingDirectory = resourcesDir;
|
||||
var n1 = helper.getNode("fileNode1");
|
||||
var n2 = helper.getNode("helperNode1");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
var fileToTest = path.join(resourcesDir, "123");
|
||||
var f = fs.readFileSync(fileToTest);
|
||||
f.should.have.length(4);
|
||||
fs.unlinkSync(fileToTest);
|
||||
msg.should.have.property("payload", "test");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload: "test", _user_specified_filename: 123});
|
||||
});
|
||||
});
|
||||
|
||||
it('should use env.TEST_FILE set in nodes typedInput', function(done) {
|
||||
var flow = [{id:"fileNode1", type:"file", filename:"TEST_FILE", filenameType: "env", name: "fileNode", "appendNewline":true, "overwriteFile":true, wires: [["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper"}];
|
||||
@@ -1237,6 +1284,27 @@ describe('file Nodes', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it('should read in a file using JSONata and output a utf8 string', function(done) {
|
||||
var fileToTest4jsonata = "'" + resourcesDir + "/'&(20+30)&'-file-test-file.txt'";
|
||||
var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "filename":fileToTest4jsonata, "filenameType": "jsonata", "format":"utf8", wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(fileNode, flow, function() {
|
||||
var n1 = helper.getNode("fileInNode1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload');
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.have.length(40)
|
||||
msg.payload.should.equal("File message line 1\nFile message line 2\n");
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:""});
|
||||
});
|
||||
});
|
||||
|
||||
it('should read in a file using fileWorkingDirectory to set cwd', function(done) {
|
||||
var flow = [{id:"fileInNode1", type:"file in", name: "fileInNode", "filename":relativePathToFile, "format":"utf8", wires:[["n2"]]},
|
||||
|
@@ -253,34 +253,32 @@ describe('subflow', function() {
|
||||
|
||||
it('should access typed value of env var', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
|
||||
env: [
|
||||
{name: "KN", type: "num", value: "100"},
|
||||
{name: "KB", type: "bool", value: "true"},
|
||||
{name: "KJ", type: "json", value: "[1,2,3]"},
|
||||
{name: "Kb", type: "bin", value: "[65,65]"},
|
||||
{name: "Ke", type: "env", value: "KS"}
|
||||
],
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}],
|
||||
env: [
|
||||
{name: "KS", type: "str", value: "STR"}
|
||||
]
|
||||
{ id: "t0", type: "tab", label: "", disabled: false, info: "" },
|
||||
{
|
||||
id: "n1", x: 10, y: 10, z: "t0", type: "subflow:s1",
|
||||
env: [
|
||||
{ name: "KN", type: "num", value: "100" },
|
||||
{ name: "KB", type: "bool", value: "true" },
|
||||
{ name: "KJ", type: "json", value: "[1,2,3]" },
|
||||
{ name: "Kb", type: "bin", value: "[65,65]" },
|
||||
{ name: "Ke", type: "env", value: "KS" },
|
||||
{ name: "Kj", type: "jsonata", value: "1+2" },
|
||||
],
|
||||
wires: [["n2"]]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.VE = env.get('Ke'); msg.VS = env.get('KS'); msg.VN = env.get('KN'); msg.VB = env.get('KB'); msg.VJ = env.get('KJ'); msg.Vb = env.get('Kb'); return msg;",
|
||||
wires:[]}
|
||||
{ id: "n2", x: 10, y: 10, z: "t0", type: "helper", wires: [] },
|
||||
// Subflow
|
||||
{
|
||||
id: "s1", type: "subflow", name: "Subflow", info: "",
|
||||
in: [{ x: 10, y: 10, wires: [{ id: "s1-n1" }] }],
|
||||
out: [{ x: 10, y: 10, wires: [{ id: "s1-n1", port: 0 }] }],
|
||||
env: [{ name: "KS", type: "str", value: "STR" }]
|
||||
},
|
||||
{
|
||||
id: "s1-n1", x: 10, y: 10, z: "s1", type: "function",
|
||||
func: "msg.VE = env.get('Ke'); msg.VS = env.get('KS'); msg.VN = env.get('KN'); msg.VB = env.get('KB'); msg.VJ = env.get('KJ'); msg.Vb = env.get('Kb'); msg.Vj = env.get('Kj'); return msg;",
|
||||
wires: []
|
||||
}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
@@ -294,6 +292,7 @@ describe('subflow', function() {
|
||||
msg.should.have.property("Vb");
|
||||
should.ok(msg.Vb instanceof Buffer);
|
||||
msg.should.have.property("VE","STR");
|
||||
msg.should.have.property("Vj",3);
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
|
@@ -126,6 +126,26 @@ describe("api/admin/context", function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should call context.getValue to get a node context value - url unsafe keyname', function (done) {
|
||||
stub.returns(Promise.resolve(nContext));
|
||||
request(app)
|
||||
.get('/context/node/5678/foo%23123?store=file')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.end(function (err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
stub.args[0][0].should.have.property('user', undefined);
|
||||
stub.args[0][0].should.have.property('scope', 'node');
|
||||
stub.args[0][0].should.have.property('id', '5678');
|
||||
stub.args[0][0].should.have.property('key', 'foo#123');
|
||||
stub.args[0][0].should.have.property('store', 'file');
|
||||
var body = res.body;
|
||||
body.should.eql(nContext);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('should handle error which context.getValue causes', function (done) {
|
||||
var stubbedResult = Promise.reject('error');
|
||||
stubbedResult.catch(function() {});
|
||||
@@ -214,6 +234,24 @@ describe("api/admin/context", function () {
|
||||
});
|
||||
});
|
||||
|
||||
it('should call context.delete to delete a node context - url unsafe keyname', function (done) {
|
||||
stub.returns(Promise.resolve());
|
||||
request(app)
|
||||
.delete('/context/node/5678/foo%23123?store=file')
|
||||
.expect(204)
|
||||
.end(function (err, res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
stub.args[0][0].should.have.property('user', undefined);
|
||||
stub.args[0][0].should.have.property('scope', 'node');
|
||||
stub.args[0][0].should.have.property('id', '5678');
|
||||
stub.args[0][0].should.have.property('key', 'foo#123');
|
||||
stub.args[0][0].should.have.property('store', 'file');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle error which context.delete causes', function (done) {
|
||||
var stubbedResult = Promise.reject('error');
|
||||
stubbedResult.catch(function() {});
|
||||
|
@@ -61,12 +61,14 @@ describe("api/editor/index", function() {
|
||||
sinon.stub(NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/"+m),"init").callsFake(function(){});
|
||||
});
|
||||
sinon.stub(NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/theme"),"app").callsFake(function(){ return express()});
|
||||
sinon.stub(NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/settings"),"sshkeys").callsFake(function(){ return express()});
|
||||
});
|
||||
after(function() {
|
||||
mockList.forEach(function(m) {
|
||||
NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/"+m).init.restore();
|
||||
})
|
||||
NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/theme").app.restore();
|
||||
NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/settings").sshkeys.restore();
|
||||
auth.needsPermission.restore();
|
||||
log.error.restore();
|
||||
});
|
||||
|
@@ -41,7 +41,7 @@ describe("api/editor/settings", function() {
|
||||
});
|
||||
|
||||
it('returns the user settings', function(done) {
|
||||
info.init({
|
||||
info.init({}, {
|
||||
settings: {
|
||||
getUserSettings: function(opts) {
|
||||
if (opts.user !== "fred") {
|
||||
@@ -67,7 +67,7 @@ describe("api/editor/settings", function() {
|
||||
});
|
||||
it('updates the user settings', function(done) {
|
||||
var update;
|
||||
info.init({
|
||||
info.init({}, {
|
||||
settings: {
|
||||
updateUserSettings: function(opts) {
|
||||
if (opts.user !== "fred") {
|
||||
|
@@ -34,7 +34,7 @@ describe("api/editor/sshkeys", function() {
|
||||
}
|
||||
}
|
||||
before(function() {
|
||||
sshkeys.init(mockRuntime);
|
||||
sshkeys.init({}, mockRuntime);
|
||||
app = express();
|
||||
app.use(bodyParser.json());
|
||||
app.use("/settings/user/keys", sshkeys.app());
|
||||
|
@@ -98,7 +98,7 @@ describe("api/editor/theme", function () {
|
||||
},
|
||||
header: {
|
||||
title: "Test Header Title",
|
||||
url: "http://nodered.org",
|
||||
url: "https://nodered.org",
|
||||
image: "/absolute/path/to/header/image" // or null to remove image
|
||||
},
|
||||
|
||||
@@ -147,7 +147,7 @@ describe("api/editor/theme", function () {
|
||||
context.page.tabicon.should.have.a.property("colour", "#8f008f")
|
||||
context.should.have.a.property("header");
|
||||
context.header.should.have.a.property("title", "Test Header Title");
|
||||
context.header.should.have.a.property("url", "http://nodered.org");
|
||||
context.header.should.have.a.property("url", "https://nodered.org");
|
||||
context.header.should.have.a.property("image", "theme/header/image");
|
||||
context.page.should.have.a.property("css");
|
||||
context.page.css.should.have.lengthOf(1);
|
||||
|
File diff suppressed because it is too large
Load Diff
48
test/unit/@node-red/runtime/lib/flows/Group_spec.js
Normal file
48
test/unit/@node-red/runtime/lib/flows/Group_spec.js
Normal file
@@ -0,0 +1,48 @@
|
||||
const should = require("should");
|
||||
const NR_TEST_UTILS = require("nr-test-utils");
|
||||
const { Group } = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Group");
|
||||
|
||||
describe('Group', function () {
|
||||
describe('getSetting', function () {
|
||||
it("returns group name/id", async function () {
|
||||
const group = new Group({
|
||||
getSetting: v => v+v
|
||||
}, {
|
||||
name: "g1",
|
||||
id: "group1"
|
||||
})
|
||||
await group.start()
|
||||
|
||||
group.getSetting("NR_GROUP_NAME").should.equal("g1")
|
||||
group.getSetting("NR_GROUP_ID").should.equal("group1")
|
||||
})
|
||||
it("delegates to parent if not found", async function () {
|
||||
const group = new Group({
|
||||
getSetting: v => v+v
|
||||
}, {
|
||||
name: "g1",
|
||||
id: "group1"
|
||||
})
|
||||
await group.start()
|
||||
|
||||
group.getSetting("123").should.equal("123123")
|
||||
})
|
||||
it("delegates to parent if explicit requested", async function () {
|
||||
const parentGroup = new Group({
|
||||
getSetting: v => v+v
|
||||
}, {
|
||||
name: "g0",
|
||||
id: "group0"
|
||||
})
|
||||
const group = new Group(parentGroup, {
|
||||
name: "g1",
|
||||
id: "group1"
|
||||
})
|
||||
await parentGroup.start()
|
||||
await group.start()
|
||||
|
||||
group.getSetting("$parent.NR_GROUP_NAME").should.equal("g0")
|
||||
group.getSetting("$parent.NR_GROUP_ID").should.equal("group0")
|
||||
})
|
||||
})
|
||||
})
|
@@ -68,11 +68,13 @@ describe('Subflow', function() {
|
||||
this.handled = 0;
|
||||
this.stopped = false;
|
||||
this.received = null;
|
||||
this.receivedEnv = null;
|
||||
currentNodes[node.id] = node;
|
||||
this.on('input',function(msg) {
|
||||
// console.log(this.id,msg.payload);
|
||||
node.handled++;
|
||||
node.received = msg.payload;
|
||||
node.receivedEnv = msg.receivedEnv;
|
||||
node.send(msg);
|
||||
});
|
||||
this.on('close',function() {
|
||||
@@ -185,7 +187,15 @@ describe('Subflow', function() {
|
||||
var flow = node._flow;
|
||||
var val = flow.getSetting("__KEY__");
|
||||
node.received = val;
|
||||
node.send({payload: val});
|
||||
const receivedEnv = {}
|
||||
try {
|
||||
['__KEY__','__KEY1__','__KEY2__','__KEY3__','__KEY4__'].forEach(k => {
|
||||
receivedEnv[k] = flow.getSetting(k)
|
||||
})
|
||||
} catch (err) {
|
||||
console.log(err)
|
||||
}
|
||||
node.send({payload: val, receivedEnv});
|
||||
});
|
||||
this.on('close',function() {
|
||||
node.stopped = true;
|
||||
@@ -282,7 +292,7 @@ describe('Subflow', function() {
|
||||
getType.restore();
|
||||
});
|
||||
describe('#start',function() {
|
||||
it("instantiates a subflow and stops it",function(done) {
|
||||
it("instantiates a subflow and stops it", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
@@ -297,7 +307,7 @@ describe('Subflow', function() {
|
||||
]);
|
||||
var flow = Flow.create({handleError: (a,b,c) => { console.log(a,b,c); }},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
Object.keys(activeNodes).should.have.length(4);
|
||||
@@ -332,37 +342,21 @@ describe('Subflow', function() {
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes["1"].receive({payload:"test"});
|
||||
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
|
||||
setTimeout(function() {
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",1);
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",1);
|
||||
|
||||
|
||||
|
||||
flow.stop().then(function() {
|
||||
Object.keys(currentNodes).should.have.length(0);
|
||||
Object.keys(stoppedNodes).should.have.length(6);
|
||||
|
||||
// currentNodes.should.not.have.a.property("1");
|
||||
// currentNodes.should.not.have.a.property("3");
|
||||
// currentNodes.should.not.have.a.property("4");
|
||||
// // currentNodes.should.not.have.a.property(sfInstanceId);
|
||||
// // currentNodes.should.not.have.a.property(sfInstanceId2);
|
||||
// // currentNodes.should.not.have.a.property(sfConfigId);
|
||||
// stoppedNodes.should.have.a.property("1");
|
||||
// stoppedNodes.should.have.a.property("3");
|
||||
// stoppedNodes.should.have.a.property("4");
|
||||
// // stoppedNodes.should.have.a.property(sfInstanceId);
|
||||
// // stoppedNodes.should.have.a.property(sfInstanceId2);
|
||||
// // stoppedNodes.should.have.a.property(sfConfigId);
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
await flow.stop()
|
||||
Object.keys(currentNodes).should.have.length(0);
|
||||
Object.keys(stoppedNodes).should.have.length(6);
|
||||
});
|
||||
it("instantiates a subflow inside a subflow and stops it",function(done) {
|
||||
|
||||
it("instantiates a subflow inside a subflow and stops it", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
@@ -379,24 +373,20 @@ describe('Subflow', function() {
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",0);
|
||||
currentNodes["3"].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes["1"].receive({payload:"test"});
|
||||
|
||||
setTimeout(function() {
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
flow.stop().then(function() {
|
||||
Object.keys(currentNodes).should.have.length(0);
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
await flow.stop()
|
||||
Object.keys(currentNodes).should.have.length(0);
|
||||
});
|
||||
it("rewires a subflow node on update/start",function(done){
|
||||
|
||||
it("rewires a subflow node on update/start", async function(){
|
||||
var rawConfig = [
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
@@ -417,7 +407,7 @@ describe('Subflow', function() {
|
||||
var diff = flowUtils.diffConfigs(config,newConfig);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
Object.keys(activeNodes).should.have.length(4);
|
||||
@@ -429,36 +419,28 @@ describe('Subflow', function() {
|
||||
currentNodes["4"].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes["1"].receive({payload:"test"});
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",0);
|
||||
|
||||
setTimeout(function() {
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",0);
|
||||
flow.update(newConfig,newConfig.flows["t1"]);
|
||||
await flow.start(diff)
|
||||
currentNodes["1"].receive({payload:"test2"});
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
currentNodes["1"].should.have.a.property("handled",2);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",2);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",2);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",1);
|
||||
|
||||
flow.update(newConfig,newConfig.flows["t1"]);
|
||||
flow.start(diff)
|
||||
|
||||
currentNodes["1"].receive({payload:"test2"});
|
||||
setTimeout(function() {
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",2);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",2);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",2);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",1);
|
||||
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
},150);
|
||||
await flow.stop()
|
||||
});
|
||||
});
|
||||
describe('#stop', function() {
|
||||
it("stops subflow instance nodes",function(done) {
|
||||
it("stops subflow instance nodes", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
@@ -470,20 +452,18 @@ describe('Subflow', function() {
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
Object.keys(activeNodes).should.have.length(3);
|
||||
Object.keys(stoppedNodes).should.have.length(0);
|
||||
flow.stop(["2"]).then(function() {
|
||||
Object.keys(currentNodes).should.have.length(2);
|
||||
Object.keys(stoppedNodes).should.have.length(1);
|
||||
done();
|
||||
}).catch(done);
|
||||
await flow.stop(["2"])
|
||||
Object.keys(currentNodes).should.have.length(2);
|
||||
Object.keys(stoppedNodes).should.have.length(1);
|
||||
});
|
||||
});
|
||||
describe("#handleStatus",function() {
|
||||
it("passes a status event to the subflow's parent tab status node - all scope",function(done) {
|
||||
it("passes a status event to the subflow's parent tab status node - all scope", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
@@ -496,27 +476,24 @@ describe('Subflow', function() {
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].receive({payload:"test"});
|
||||
setTimeout(function() {
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","test status");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("type","testStatus");
|
||||
statusMessage.status.source.should.have.a.property("name","test-status-node");
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","test status");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("type","testStatus");
|
||||
statusMessage.status.source.should.have.a.property("name","test-status-node");
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
await flow.stop()
|
||||
});
|
||||
it("passes a status event to the subflow's parent tab status node - targetted scope",function(done) {
|
||||
it("passes a status event to the subflow's parent tab status node - targetted scope", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
@@ -531,34 +508,30 @@ describe('Subflow', function() {
|
||||
|
||||
var flow = Flow.create({handleStatus:() => { parentFlowStatusCalled = true} },config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].receive({payload:"test"});
|
||||
|
||||
setTimeout(function() {
|
||||
parentFlowStatusCalled.should.be.false();
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
parentFlowStatusCalled.should.be.false();
|
||||
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","test status");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("type","testStatus");
|
||||
statusMessage.status.source.should.have.a.property("name","test-status-node");
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","test status");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("type","testStatus");
|
||||
statusMessage.status.source.should.have.a.property("name","test-status-node");
|
||||
|
||||
flow.stop().then(function() {
|
||||
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
await flow.stop()
|
||||
});
|
||||
});
|
||||
|
||||
describe("status node", function() {
|
||||
it("emits a status event when a message is passed to a subflow-status node - msg.payload as string", function(done) {
|
||||
it("emits a status event when a message is passed to a subflow-status node - msg.payload as string", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
@@ -578,29 +551,24 @@ describe('Subflow', function() {
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].receive({payload:"test-payload"});
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
|
||||
setTimeout(function() {
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","test-payload");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id","2");
|
||||
statusMessage.status.source.should.have.a.property("type","subflow:sf1");
|
||||
|
||||
flow.stop().then(function() {
|
||||
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","test-payload");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id","2");
|
||||
statusMessage.status.source.should.have.a.property("type","subflow:sf1");
|
||||
await flow.stop()
|
||||
});
|
||||
it("emits a status event when a message is passed to a subflow-status node - msg.payload as status obj", function(done) {
|
||||
it("emits a status event when a message is passed to a subflow-status node - msg.payload as status obj", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
@@ -620,29 +588,26 @@ describe('Subflow', function() {
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].receive({payload:{text:"payload-obj"}});
|
||||
|
||||
setTimeout(function() {
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","payload-obj");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id","2");
|
||||
statusMessage.status.source.should.have.a.property("type","subflow:sf1");
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
flow.stop().then(function() {
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","payload-obj");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id","2");
|
||||
statusMessage.status.source.should.have.a.property("type","subflow:sf1");
|
||||
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
await flow.stop()
|
||||
});
|
||||
it("emits a status event when a message is passed to a subflow-status node - msg.status", function(done) {
|
||||
it("emits a status event when a message is passed to a subflow-status node - msg.status", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
@@ -662,29 +627,26 @@ describe('Subflow', function() {
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].receive({status:{text:"status-obj"}});
|
||||
|
||||
setTimeout(function() {
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","status-obj");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id","2");
|
||||
statusMessage.status.source.should.have.a.property("type","subflow:sf1");
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
flow.stop().then(function() {
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","status-obj");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id","2");
|
||||
statusMessage.status.source.should.have.a.property("type","subflow:sf1");
|
||||
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
flow.stop()
|
||||
});
|
||||
it("does not emit a regular status event if it contains a subflow-status node", function(done) {
|
||||
it("does not emit a regular status event if it contains a subflow-status node", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
@@ -704,7 +666,7 @@ describe('Subflow', function() {
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
@@ -712,15 +674,12 @@ describe('Subflow', function() {
|
||||
|
||||
currentNodes["sn"].should.have.a.property("handled",0);
|
||||
|
||||
flow.stop().then(function() {
|
||||
|
||||
done();
|
||||
});
|
||||
await flow.stop()
|
||||
});
|
||||
})
|
||||
|
||||
describe("#handleError",function() {
|
||||
it("passes an error event to the subflow's parent tab catch node - all scope",function(done) {
|
||||
it("passes an error event to the subflow's parent tab catch node - all scope",async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
@@ -733,28 +692,26 @@ describe('Subflow', function() {
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].receive({payload:"test"});
|
||||
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
|
||||
setTimeout(function() {
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("error");
|
||||
statusMessage.error.should.have.a.property("message","test error");
|
||||
statusMessage.error.should.have.a.property("source");
|
||||
statusMessage.error.source.should.have.a.property("type","testError");
|
||||
statusMessage.error.source.should.have.a.property("name","test-error-node");
|
||||
statusMessage.should.have.a.property("error");
|
||||
statusMessage.error.should.have.a.property("message","test error");
|
||||
statusMessage.error.should.have.a.property("source");
|
||||
statusMessage.error.source.should.have.a.property("type","testError");
|
||||
statusMessage.error.source.should.have.a.property("name","test-error-node");
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
await flow.stop()
|
||||
});
|
||||
it("passes an error event to the subflow's parent tab catch node - targetted scope",function(done) {
|
||||
it("passes an error event to the subflow's parent tab catch node - targetted scope", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
@@ -768,50 +725,31 @@ describe('Subflow', function() {
|
||||
var parentFlowErrorCalled = false;
|
||||
var flow = Flow.create({handleError:() => { parentFlowErrorCalled = true} },config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].receive({payload:"test"});
|
||||
|
||||
setTimeout(function() {
|
||||
parentFlowErrorCalled.should.be.false();
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
|
||||
parentFlowErrorCalled.should.be.false();
|
||||
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("error");
|
||||
statusMessage.error.should.have.a.property("message","test error");
|
||||
statusMessage.error.should.have.a.property("source");
|
||||
statusMessage.error.source.should.have.a.property("type","testError");
|
||||
statusMessage.error.source.should.have.a.property("name","test-error-node");
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
statusMessage.should.have.a.property("error");
|
||||
statusMessage.error.should.have.a.property("message","test error");
|
||||
statusMessage.error.should.have.a.property("source");
|
||||
statusMessage.error.source.should.have.a.property("type","testError");
|
||||
statusMessage.error.source.should.have.a.property("name","test-error-node");
|
||||
|
||||
await flow.stop()
|
||||
});
|
||||
});
|
||||
|
||||
describe("#env var", function() {
|
||||
// should be changed according to internal env var representation
|
||||
function setEnv(node, key, val) {
|
||||
var flow = node._flow;
|
||||
if (flow) {
|
||||
var env = flow.env;
|
||||
if (!env) {
|
||||
env = flow.env = {};
|
||||
}
|
||||
env[key] = {
|
||||
name: key,
|
||||
type: "str",
|
||||
value: val
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
it("can access process env var", function(done) {
|
||||
it("can access process env var", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
|
||||
@@ -828,29 +766,25 @@ describe('Subflow', function() {
|
||||
handleError: (a,b,c) => { console.log(a,b,c); }
|
||||
},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
process.env["__KEY__"] = "__VAL__";
|
||||
|
||||
currentNodes["1"].receive({payload: "test"});
|
||||
setTimeout(function() {
|
||||
currentNodes["3"].should.have.a.property("received", "__VAL__");
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
currentNodes["3"].should.have.a.property("received", "__VAL__");
|
||||
await flow.stop()
|
||||
});
|
||||
|
||||
it("can access subflow env var", function(done) {
|
||||
it("can access subflow env var", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"t1.3",wires:[]},
|
||||
{id:"sf1",type:"subflow",name:"Subflow 2",info:"",
|
||||
"in":[ {wires:[{id:"sf1-1"}]} ],
|
||||
"out":[ {wires:[{id:"sf1-2",port:0}]} ]},
|
||||
{id:"sf1",type:"subflow",name:"Subflow 2",info:"",env: [{name: '__KEY__', value: '__VAL1__', type: 'str'}],
|
||||
"in":[ {wires:[{id:"sf1-1"}]} ],
|
||||
"out":[ {wires:[{id:"sf1-2",port:0}]} ]},
|
||||
{id:"sf1-1",type:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
|
||||
{id:"sf1-2",type:"testEnv",z:"sf1",foo:"sf1.2",x:166,y:99,wires:[[]]}
|
||||
]);
|
||||
@@ -859,7 +793,7 @@ describe('Subflow', function() {
|
||||
handleError: (a,b,c) => { console.log(a,b,c); }
|
||||
},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
var testenv_node = null;
|
||||
for (var n in currentNodes) {
|
||||
@@ -870,32 +804,30 @@ describe('Subflow', function() {
|
||||
}
|
||||
}
|
||||
process.env["__KEY__"] = "__VAL0__";
|
||||
setEnv(testenv_node, "__KEY__", "__VAL1__");
|
||||
|
||||
currentNodes["1"].receive({payload: "test"});
|
||||
setTimeout(function() {
|
||||
currentNodes["3"].should.have.a.property("received", "__VAL1__");
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
currentNodes["3"].should.have.a.property("received", "__VAL1__");
|
||||
await flow.stop()
|
||||
});
|
||||
|
||||
it("can access nested subflow env var", function(done) {
|
||||
it("can access nested subflow env var", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"t1",type:"tab", env: [{name: '__KEY1__', value: 't1', type: 'str'}]},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"t1.3",wires:[]},
|
||||
{id:"sf1",type:"subflow",name:"Subflow 1",info:"",
|
||||
in:[{wires:[{id:"sf1-1"}]}],
|
||||
out:[{wires:[{id:"sf1-2",port:0}]}]},
|
||||
env: [{name: '__KEY2__', value: 'sf1', type: 'str'}],
|
||||
in:[{wires:[{id:"sf1-1"}]}],
|
||||
out:[{wires:[{id:"sf1-2",port:0}]}]},
|
||||
{id:"sf2",type:"subflow",name:"Subflow 2",info:"",
|
||||
in:[{wires:[{id:"sf2-1"}]}],
|
||||
out:[{wires:[{id:"sf2-2",port:0}]}]},
|
||||
env: [{name: '__KEY3__', value: 'sf2', type: 'str'}],
|
||||
in:[{wires:[{id:"sf2-1"}]}],
|
||||
out:[{wires:[{id:"sf2-2",port:0}]}]},
|
||||
{id:"sf1-1",type:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
|
||||
{id:"sf1-2",type:"subflow:sf2",z:"sf1",x:166,y:99,wires:[[]]},
|
||||
{id:"sf1-2",type:"subflow:sf2",z:"sf1",x:166,y:99,wires:[[]], env: [{name: '__KEY4__', value: 'sf1-2', type: 'str'}] },
|
||||
{id:"sf2-1",type:"test",z:"sf2",foo:"sf2.1",x:166,y:99,wires:[["sf2-2"]]},
|
||||
{id:"sf2-2",type:"testEnv",z:"sf2",foo:"sf2.2",x:166,y:99,wires:[[]]},
|
||||
]);
|
||||
@@ -904,45 +836,22 @@ describe('Subflow', function() {
|
||||
handleError: (a,b,c) => { console.log(a,b,c); }
|
||||
},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
var node_sf1_1 = null;
|
||||
var node_sf2_1 = null;
|
||||
var testenv_node = null;
|
||||
for (var n in currentNodes) {
|
||||
var node = currentNodes[n];
|
||||
if (node.foo === "sf1.1") {
|
||||
node_sf1_1 = node;
|
||||
}
|
||||
if (node.foo === "sf2.1") {
|
||||
node_sf2_1 = node;
|
||||
}
|
||||
}
|
||||
await flow.start();
|
||||
|
||||
process.env["__KEY__"] = "__VAL0__";
|
||||
currentNodes["1"].receive({payload: "test"});
|
||||
setTimeout(function() {
|
||||
currentNodes["3"].should.have.a.property("received", "__VAL0__");
|
||||
|
||||
setEnv(node_sf1_1, "__KEY__", "__VAL1__");
|
||||
currentNodes["1"].receive({payload: "test"});
|
||||
setTimeout(function() {
|
||||
currentNodes["3"].should.have.a.property("received", "__VAL1__");
|
||||
|
||||
setEnv(node_sf2_1, "__KEY__", "__VAL2__");
|
||||
currentNodes["1"].receive({payload: "test"});
|
||||
setTimeout(function() {
|
||||
currentNodes["3"].should.have.a.property("received", "__VAL2__");
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
},150);
|
||||
},150);
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
currentNodes["3"].should.have.a.property("receivedEnv");
|
||||
currentNodes["3"].receivedEnv.should.have.a.property('__KEY__', '__VAL0__')
|
||||
currentNodes["3"].receivedEnv.should.have.a.property('__KEY1__', 't1')
|
||||
currentNodes["3"].receivedEnv.should.have.a.property('__KEY2__', 'sf1')
|
||||
currentNodes["3"].receivedEnv.should.have.a.property('__KEY3__', 'sf2')
|
||||
currentNodes["3"].receivedEnv.should.have.a.property('__KEY4__', 'sf1-2')
|
||||
|
||||
await flow.stop()
|
||||
});
|
||||
|
||||
it("can access name of subflow as env var", function(done) {
|
||||
it("can access name of subflow as env var", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
|
||||
@@ -959,19 +868,15 @@ describe('Subflow', function() {
|
||||
handleError: (a,b,c) => { console.log(a,b,c); }
|
||||
},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
currentNodes["1"].receive({payload: "test"});
|
||||
setTimeout(function() {
|
||||
currentNodes["3"].should.have.a.property("received", "SFN");
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
currentNodes["3"].should.have.a.property("received", "SFN");
|
||||
await flow.stop()
|
||||
});
|
||||
|
||||
it("can access id of subflow as env var", function(done) {
|
||||
it("can access id of subflow as env var", async function() {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
|
||||
@@ -988,19 +893,13 @@ describe('Subflow', function() {
|
||||
handleError: (a,b,c) => { console.log(a,b,c); }
|
||||
},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
await flow.start();
|
||||
|
||||
currentNodes["1"].receive({payload: "test"});
|
||||
setTimeout(function() {
|
||||
currentNodes["3"].should.have.a.property("received", "2");
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
},150);
|
||||
await NR_TEST_UTILS.sleep(150)
|
||||
currentNodes["3"].should.have.a.property("received", "2");
|
||||
await flow.stop()
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
@@ -93,7 +93,7 @@ describe('flows/index', function() {
|
||||
flowCreate.flows[id] = {
|
||||
flow: flow,
|
||||
global: global,
|
||||
start: sinon.spy(),
|
||||
start: sinon.spy(async() => {}),
|
||||
update: sinon.spy(),
|
||||
stop: sinon.spy(),
|
||||
getActiveNodes: function() {
|
||||
@@ -221,13 +221,18 @@ describe('flows/index', function() {
|
||||
return Promise.resolve({flows:originalConfig});
|
||||
}
|
||||
events.once('flows:started',function() {
|
||||
flows.setFlows(newConfig,"nodes").then(function() {
|
||||
flows.getFlows().flows.should.eql(newConfig);
|
||||
flowCreate.flows['t1'].update.called.should.be.true();
|
||||
flowCreate.flows['t2'].start.called.should.be.true();
|
||||
flowCreate.flows['_GLOBAL_'].update.called.should.be.true();
|
||||
done();
|
||||
events.once('flows:started', function() {
|
||||
try {
|
||||
flows.getFlows().flows.should.eql(newConfig);
|
||||
flowCreate.flows['t1'].update.called.should.be.true();
|
||||
flowCreate.flows['t2'].start.called.should.be.true();
|
||||
flowCreate.flows['_GLOBAL_'].update.called.should.be.true();
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
})
|
||||
flows.setFlows(newConfig,"nodes")
|
||||
});
|
||||
|
||||
flows.init({log:mockLog, settings:{},storage:storage});
|
||||
@@ -250,13 +255,14 @@ describe('flows/index', function() {
|
||||
}
|
||||
|
||||
events.once('flows:started',function() {
|
||||
flows.setFlows(newConfig,"nodes").then(function() {
|
||||
events.once('flows:started',function() {
|
||||
flows.getFlows().flows.should.eql(newConfig);
|
||||
flowCreate.flows['t1'].update.called.should.be.true();
|
||||
flowCreate.flows['t2'].start.called.should.be.true();
|
||||
flowCreate.flows['_GLOBAL_'].update.called.should.be.true();
|
||||
flows.stopFlows().then(done);
|
||||
})
|
||||
flows.setFlows(newConfig,"nodes")
|
||||
});
|
||||
|
||||
flows.init({log:mockLog, settings:{},storage:storage});
|
||||
|
@@ -149,7 +149,7 @@ describe('flows/util', function() {
|
||||
{id:"t1",type:"tab"}
|
||||
];
|
||||
var parsedConfig = flowUtil.parseConfig(originalConfig);
|
||||
var expectedConfig = {"allNodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]},"t1":{"id":"t1","type":"tab"}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]}}}},"groups":{},"missingTypes":[]};
|
||||
var expectedConfig = {"allNodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]},"t1":{"id":"t1","type":"tab"}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"groups":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]}}}},"missingTypes":[]};
|
||||
parsedConfig.should.eql(expectedConfig);
|
||||
});
|
||||
|
||||
@@ -160,7 +160,7 @@ describe('flows/util', function() {
|
||||
{id:"t1",type:"tab"}
|
||||
];
|
||||
var parsedConfig = flowUtil.parseConfig(originalConfig);
|
||||
var expectedConfig = {"allNodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]},"cn":{"id":"cn","type":"test"},"t1":{"id":"t1","type":"tab"}},"subflows":{},"configs":{"cn":{"id":"cn","type":"test","_users":["t1-1"]}},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]}}}},"groups":{},"missingTypes":[]};
|
||||
var expectedConfig = {"allNodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]},"cn":{"id":"cn","type":"test"},"t1":{"id":"t1","type":"tab"}},"subflows":{},"configs":{"cn":{"id":"cn","type":"test","_users":["t1-1"]}},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"groups":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]}}}},"missingTypes":[]};
|
||||
parsedConfig.should.eql(expectedConfig);
|
||||
});
|
||||
|
||||
@@ -172,7 +172,7 @@ describe('flows/util', function() {
|
||||
{id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]}
|
||||
];
|
||||
var parsedConfig = flowUtil.parseConfig(originalConfig);
|
||||
var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]},"t2":{"id":"t2","type":"tab"},"t2-1":{"id":"t2-1","x":10,"y":10,"z":"t2","type":"test","wires":[]}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]}}},"t2":{"id":"t2","type":"tab","subflows":{},"configs":{},"nodes":{"t2-1":{"id":"t2-1","x":10,"y":10,"z":"t2","type":"test","wires":[]}}}},"groups":{},"missingTypes":[]};
|
||||
var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]},"t2":{"id":"t2","type":"tab"},"t2-1":{"id":"t2-1","x":10,"y":10,"z":"t2","type":"test","wires":[]}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"groups":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]}}},"t2":{"id":"t2","type":"tab","subflows":{},"configs":{},"groups":{},"nodes":{"t2-1":{"id":"t2-1","x":10,"y":10,"z":"t2","type":"test","wires":[]}}}},"missingTypes":[]};
|
||||
parsedConfig.should.eql(expectedConfig);
|
||||
});
|
||||
|
||||
@@ -184,7 +184,7 @@ describe('flows/util', function() {
|
||||
{id:"sf1-1",x:10,y:10,z:"sf1",type:"test",wires:[]}
|
||||
];
|
||||
var parsedConfig = flowUtil.parseConfig(originalConfig);
|
||||
var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"subflow:sf1","wires":[]},"sf1":{"id":"sf1","type":"subflow"},"sf1-1":{"id":"sf1-1","x":10,"y":10,"z":"sf1","type":"test","wires":[]}},"subflows":{"sf1":{"id":"sf1","type":"subflow","configs":{},"nodes":{"sf1-1":{"id":"sf1-1","x":10,"y":10,"z":"sf1","type":"test","wires":[]}},"instances":[{"id":"t1-1","x":10,"y":10,"z":"t1","type":"subflow:sf1","wires":[],"subflow":"sf1"}]}},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"subflow:sf1","wires":[],"subflow":"sf1"}}}},"groups":{},"missingTypes":[]};
|
||||
var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"subflow:sf1","wires":[]},"sf1":{"id":"sf1","type":"subflow"},"sf1-1":{"id":"sf1-1","x":10,"y":10,"z":"sf1","type":"test","wires":[]}},"subflows":{"sf1":{"id":"sf1","type":"subflow","configs":{},"groups":{},"nodes":{"sf1-1":{"id":"sf1-1","x":10,"y":10,"z":"sf1","type":"test","wires":[]}},"instances":[{"id":"t1-1","x":10,"y":10,"z":"t1","type":"subflow:sf1","wires":[],"subflow":"sf1"}]}},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"groups":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"subflow:sf1","wires":[],"subflow":"sf1"}}}},"missingTypes":[]};
|
||||
parsedConfig.should.eql(expectedConfig);
|
||||
});
|
||||
|
||||
@@ -196,7 +196,7 @@ describe('flows/util', function() {
|
||||
];
|
||||
var parsedConfig = flowUtil.parseConfig(originalConfig);
|
||||
parsedConfig.missingTypes.should.eql(['missing']);
|
||||
var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"sf1","wires":[]},"t1-2":{"id":"t1-2","x":10,"y":10,"z":"t1","type":"missing","wires":[]}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"sf1","wires":[]},'t1-2': { id: 't1-2', x: 10, y: 10, z: 't1', type: 'missing', wires: [] }}}},"groups":{},"missingTypes":["missing"]};
|
||||
var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"sf1","wires":[]},"t1-2":{"id":"t1-2","x":10,"y":10,"z":"t1","type":"missing","wires":[]}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"groups":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"sf1","wires":[]},'t1-2': { id: 't1-2', x: 10, y: 10, z: 't1', type: 'missing', wires: [] }}}},"missingTypes":["missing"]};
|
||||
redUtil.compareObjects(parsedConfig,expectedConfig).should.be.true();
|
||||
});
|
||||
|
||||
@@ -206,7 +206,7 @@ describe('flows/util', function() {
|
||||
{id:"cn",type:"test"},
|
||||
];
|
||||
var parsedConfig = flowUtil.parseConfig(originalConfig);
|
||||
var expectedConfig = {"allNodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]},"cn":{"id":"cn","type":"test"}},"subflows":{},"configs":{"cn":{"id":"cn","type":"test","_users":["t1-1"]}},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]}}}},"groups":{},"missingTypes":[]};
|
||||
var expectedConfig = {"allNodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]},"cn":{"id":"cn","type":"test"}},"subflows":{},"configs":{"cn":{"id":"cn","type":"test","_users":["t1-1"]}},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]}}}},"missingTypes":[]};
|
||||
parsedConfig.should.eql(expectedConfig);
|
||||
});
|
||||
|
||||
@@ -217,7 +217,7 @@ describe('flows/util', function() {
|
||||
{id:"g1",type:"group",z:"t1"}
|
||||
];
|
||||
var parsedConfig = flowUtil.parseConfig(originalConfig);
|
||||
var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]},"g1":{"id":"g1","type":"group","z":"t1"}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]}}}},"groups":{"g1":{"id":"g1","type":"group","z":"t1"}},"missingTypes":[]}
|
||||
var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]},"g1":{"id":"g1","type":"group","z":"t1"}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"groups":{"g1":{"id":"g1","type":"group","z":"t1"}},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]}}}},"missingTypes":[]}
|
||||
parsedConfig.should.eql(expectedConfig);
|
||||
});
|
||||
|
||||
|
@@ -489,7 +489,7 @@ describe('storage/localfilesystem', function() {
|
||||
var rootdir = path.win32.resolve(userDir+'/some');
|
||||
// make it into a local UNC path
|
||||
flowFile = flowFile.replace('C:\\', '\\\\localhost\\c$\\');
|
||||
localfilesystem.init({userDir:userDir, flowFile:flowFile}, mockRuntime).then(function() {
|
||||
localfilesystem.init({userDir:userDir, flowFile:flowFile, getUserSettings: () => {{}}}, mockRuntime).then(function() {
|
||||
fs.existsSync(flowFile).should.be.false();
|
||||
localfilesystem.saveFlows(testFlow).then(function() {
|
||||
fs.existsSync(flowFile).should.be.true();
|
||||
|
@@ -14,11 +14,33 @@
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var NR_TEST_UTILS = require("nr-test-utils");
|
||||
var util = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/util");
|
||||
const should = require("should");
|
||||
const NR_TEST_UTILS = require("nr-test-utils");
|
||||
const util = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/util");
|
||||
const { mkdtemp, readFile } = require('fs/promises');
|
||||
const { join } = require('path');
|
||||
const { tmpdir } = require('os');
|
||||
|
||||
describe('storage/localfilesystem/util', function() {
|
||||
describe('writeFile', function () {
|
||||
it('manages concurrent calls to modify the same file', async function () {
|
||||
const testDirectory = await mkdtemp(join(tmpdir(), 'nr-test-'));
|
||||
const testFile = join(testDirectory, 'foo.txt')
|
||||
const testBackupFile = testFile + '.$$$'
|
||||
|
||||
let counter = 0
|
||||
const promises = [
|
||||
util.writeFile(testFile, `update-${counter++}`, testBackupFile ),
|
||||
util.writeFile(testFile, `update-${counter++}`, testBackupFile ),
|
||||
util.writeFile(testFile, `update-${counter++}`, testBackupFile )
|
||||
]
|
||||
|
||||
await Promise.all(promises)
|
||||
|
||||
const result = await readFile(testFile, { encoding: 'utf-8' })
|
||||
result.should.equal('update-2')
|
||||
})
|
||||
})
|
||||
describe('parseJSON', function() {
|
||||
it('returns parsed JSON', function() {
|
||||
var result = util.parseJSON('{"a":123}');
|
||||
|
Reference in New Issue
Block a user