Merge pull request #4320 from node-red/dev

Sync `dev` to `master` for 3.1.0 release
This commit is contained in:
Nick O'Leary
2023-09-06 14:04:36 +01:00
committed by GitHub
347 changed files with 56100 additions and 15528 deletions

View File

@@ -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");

View 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({});
});
});
});

View File

@@ -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() {

View File

@@ -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");

View File

@@ -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:[]}];

View File

@@ -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"]]},

View File

@@ -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() {

View File

@@ -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');

View File

@@ -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) }

View File

@@ -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"]]},

View File

@@ -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) {