mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Resolve merge conflicts on update from upstream
This commit is contained in:
@@ -1,669 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var injectNode = require("nr-test-utils").require("@node-red/nodes/core/common/20-inject.js");
|
||||
var Context = require("nr-test-utils").require("@node-red/runtime/lib/nodes/context");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('inject node', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
function initContext(done) {
|
||||
Context.init({
|
||||
contextStorage: {
|
||||
memory0: {
|
||||
module: "memory"
|
||||
},
|
||||
memory1: {
|
||||
module: "memory"
|
||||
}
|
||||
}
|
||||
});
|
||||
Context.load().then(function () {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload().then(function () {
|
||||
return Context.clean({allNodes: {}});
|
||||
}).then(function () {
|
||||
return Context.close();
|
||||
}).then(function () {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
});
|
||||
|
||||
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"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic", "t1");
|
||||
if (rval) {
|
||||
msg.should.have.property("payload");
|
||||
should.deepEqual(msg.payload, rval);
|
||||
}
|
||||
else {
|
||||
msg.should.have.property("payload", val);
|
||||
}
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
basicTest("num", 10);
|
||||
basicTest("str", "10");
|
||||
basicTest("bool", true);
|
||||
var val_json = '{ "x":"vx", "y":"vy", "z":"vz" }';
|
||||
basicTest("json", val_json, JSON.parse(val_json));
|
||||
var val_buf = "[1,2,3,4,5]";
|
||||
basicTest("bin", val_buf, Buffer.from(JSON.parse(val_buf)));
|
||||
|
||||
it('inject value of environment variable ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", topic: "t1", payload: "NR_TEST", payloadType: "env", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic", "t1");
|
||||
msg.should.have.property("payload", "foo");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
process.env.NR_TEST = 'foo';
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of flow context property', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", topic: "t1", payload: "flowValue", payloadType: "flow", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic", "t1");
|
||||
msg.should.have.property("payload", "changeMe");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.context().flow.set("flowValue", "changeMe");
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of persistable flow context property', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", topic: "t1", payload: "#:(memory0)::flowValue", payloadType: "flow", wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic", "t1");
|
||||
msg.should.have.property("payload", "changeMe");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.context().flow.set("flowValue", "changeMe", "memory0", function (err) {
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of two persistable flow context property', function (done) {
|
||||
var flow = [{id: "n0", z: "flow", type: "inject", topic: "t0", payload: "#:(memory0)::val", payloadType: "flow", wires: [["n2"]]},
|
||||
{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "flow", wires: [["n2"]]},
|
||||
{id: "n2", z: "flow", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n0 = helper.getNode("n0");
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic");
|
||||
if (msg.topic === "t0") {
|
||||
msg.should.have.property("payload", "foo");
|
||||
}
|
||||
else if (msg.topic === "t1") {
|
||||
msg.should.have.property("payload", "bar");
|
||||
}
|
||||
else {
|
||||
done(new Error("unexpected message"));
|
||||
}
|
||||
count++;
|
||||
if (count === 2) {
|
||||
done();
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var global = n0.context().flow;
|
||||
global.set("val", "foo", "memory0", function (err) {
|
||||
global.set("val", "bar", "memory1", function (err) {
|
||||
n0.receive({});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of global context property', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", topic: "t1", payload: "globalValue", payloadType: "global", wires: [["n2"]]},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic", "t1");
|
||||
msg.should.have.property("payload", "changeMe");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.context().global.set("globalValue", "changeMe");
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of persistable global context property', function (done) {
|
||||
var flow = [{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "global", wires: [["n2"]]},
|
||||
{id: "n2", z: "flow", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic", "t1");
|
||||
msg.should.have.property("payload", "foo");
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var global = n1.context().global;
|
||||
global.set("val", "foo", "memory1", function (err) {
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of two persistable global context property', function (done) {
|
||||
var flow = [{id: "n0", z: "flow", type: "inject", topic: "t0", payload: "#:(memory0)::val", payloadType: "global", wires: [["n2"]]},
|
||||
{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "global", wires: [["n2"]]},
|
||||
{id: "n2", z: "flow", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n0 = helper.getNode("n0");
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic");
|
||||
if (msg.topic === "t0") {
|
||||
msg.should.have.property("payload", "foo");
|
||||
}
|
||||
else if (msg.topic === "t1") {
|
||||
msg.should.have.property("payload", "bar");
|
||||
}
|
||||
else {
|
||||
done(new Error("unexpected message"));
|
||||
}
|
||||
count++;
|
||||
if (count === 2) {
|
||||
done();
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var global = n0.context().global;
|
||||
global.set("val", "foo", "memory0", function (err) {
|
||||
global.set("val", "bar", "memory1", function (err) {
|
||||
n0.receive({});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of persistable flow & global context property', function (done) {
|
||||
var flow = [{id: "n0", z: "flow", type: "inject", topic: "t0", payload: "#:(memory0)::val", payloadType: "flow", wires: [["n2"]]},
|
||||
{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "global", wires: [["n2"]]},
|
||||
{id: "n2", z: "flow", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n0 = helper.getNode("n0");
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic");
|
||||
if (msg.topic === "t0") {
|
||||
msg.should.have.property("payload", "foo");
|
||||
}
|
||||
else if (msg.topic === "t1") {
|
||||
msg.should.have.property("payload", "bar");
|
||||
}
|
||||
else {
|
||||
done(new Error("unexpected message"));
|
||||
}
|
||||
count++;
|
||||
if (count === 2) {
|
||||
done();
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var context = n0.context();
|
||||
var flow = context.flow;
|
||||
var global = context.global;
|
||||
flow.set("val", "foo", "memory0", function (err) {
|
||||
global.set("val", "bar", "memory1", function (err) {
|
||||
n0.receive({});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('sets the value of two persistable global context property', function (done) {
|
||||
var flow = [{id: "n0", z: "flow", type: "inject", topic: "t0", payload: "#:(memory0)::val", payloadType: "global", wires: [["n2"]]},
|
||||
{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "global", wires: [["n2"]]},
|
||||
{id: "n2", z: "flow", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
initContext(function () {
|
||||
var n0 = helper.getNode("n0");
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic");
|
||||
if (msg.topic === "t0") {
|
||||
msg.should.have.property("payload", "foo");
|
||||
}
|
||||
else if (msg.topic === "t1") {
|
||||
msg.should.have.property("payload", "bar");
|
||||
}
|
||||
else {
|
||||
done(new Error("unexpected message"));
|
||||
}
|
||||
count++;
|
||||
if (count === 2) {
|
||||
done();
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var global = n0.context().global;
|
||||
global.set("val", "foo", "memory0", function (err) {
|
||||
global.set("val", "bar", "memory1", function (err) {
|
||||
n0.receive({});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
it('should inject once with default delay property', function(done) {
|
||||
helper.load(injectNode, [{id:"n1", type:"inject", topic: "t1",
|
||||
payload:"",payloadType:"date",
|
||||
once: true, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}],
|
||||
function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('onceDelay', 100);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should inject once with default delay', function(done) {
|
||||
var timestamp = new Date();
|
||||
timestamp.setSeconds(timestamp.getSeconds() + 1);
|
||||
|
||||
helper.load(injectNode, [{id:"n1", type:"inject", topic: "t1",
|
||||
payload:"",payloadType:"date",
|
||||
once: true, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}],
|
||||
function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 't1');
|
||||
msg.should.have.property('payload');
|
||||
should(msg.payload).be.lessThan(timestamp.getTime());
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should inject once with 500 msec. delay', function(done) {
|
||||
helper.load(injectNode, [{id:"n1", type:"inject", topic: "t1",
|
||||
payload:"",payloadType:"date",
|
||||
once: true, onceDelay: 0.5, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}],
|
||||
function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('onceDelay', 500);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should inject once with delay of two seconds', function(done) {
|
||||
this.timeout(2700); // have to wait for the inject with delay of two seconds
|
||||
|
||||
var timestamp = new Date();
|
||||
timestamp.setSeconds(timestamp.getSeconds() + 1);
|
||||
|
||||
helper.load(injectNode, [{id:"n1", type:"inject", topic: "t1",
|
||||
payload:"",payloadType:"date",
|
||||
once: true, onceDelay: 2, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}],
|
||||
function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 't1');
|
||||
should(msg.payload).be.greaterThan(timestamp.getTime());
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should inject repeatedly', function(done) {
|
||||
|
||||
helper.load(injectNode, [{id:"n1", type:"inject",
|
||||
payload:"payload", topic: "t2",
|
||||
repeat: 0.2, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}],
|
||||
function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 't2');
|
||||
msg.should.have.property('payload', 'payload');
|
||||
count += 1;
|
||||
if (count > 2) {
|
||||
helper.clearFlows().then(function() {
|
||||
done();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should inject once with delay of two seconds and repeatedly', function(done) {
|
||||
var timestamp = new Date();
|
||||
timestamp.setSeconds(timestamp.getSeconds() + 1);
|
||||
|
||||
helper.load(injectNode, [{id:"n1", type:"inject", topic: "t1",
|
||||
payload:"",payloadType:"date", repeat: 0.2,
|
||||
once: true, onceDelay: 1.2, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}],
|
||||
function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 't1');
|
||||
should(msg.payload).be.greaterThan(timestamp.getTime());
|
||||
count += 1;
|
||||
if (count > 2) {
|
||||
helper.clearFlows().then(function() {
|
||||
done();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should inject with cron', function(done) {
|
||||
helper.load(injectNode, [{id:"n1", type:"inject",
|
||||
payloadType:"date", topic: "t3",
|
||||
crontab: "* * * * * *", wires:[["n3"]] },
|
||||
{id:"n3", type:"helper"}],
|
||||
function() {
|
||||
var n3 = helper.getNode("n3");
|
||||
n3.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 't3');
|
||||
msg.should.have.property('payload').be.a.Number();
|
||||
helper.clearFlows().then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should inject multiple properties ', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", props: [{p:"topic", v:"t1", vt:"str"}, {p:"payload", v:"foo", vt:"str"}, {p:"x", v: 10, "vt":"num"}, {p:"y", v: "x+2", "vt":"jsonata"}], wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic", "t1");
|
||||
msg.should.have.property("payload", "foo");
|
||||
msg.should.have.property("x", 10);
|
||||
msg.should.have.property("y", 12);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should inject custom properties in message', function (done) {
|
||||
//n1: inject node with { topic:"static", payload:"static", bool1:true, str1:"1" }
|
||||
var flow = [{id: "n1", type: "inject", props: [{p:"payload", v:"static", vt:"str"}, {p:"topic", v:"static", vt:"str"}, {p:"bool1", v:"true", vt:"bool"}, {p:"str1", v:"1", vt:"str"}], wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.not.have.property("payload"); //payload removed
|
||||
msg.should.have.property("topic", "t_override"); //changed value to t_override
|
||||
msg.should.have.property("str1", 1);//changed type from str to num
|
||||
msg.should.have.property("num1", 1);//new prop
|
||||
msg.should.have.property("bool1", false);//changed value to false
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({ __user_inject_props__: [
|
||||
{p:"topic", v:"t_override", vt:"str"}, //change value to t_override
|
||||
{p:"str1", v:"1", vt:"num"}, //change type
|
||||
{p:"num1", v:"1", vt:"num"}, //new prop
|
||||
{p:"bool1", v:"false", vt:"bool"}, //change value to false
|
||||
]});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should inject multiple properties using legacy props if needed', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", payload:"123", payloadType:"num", topic:"foo", props: [{p:"topic", vt:"str"}, {p:"payload"}], wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic", "foo");
|
||||
msg.should.have.property("payload", 123);
|
||||
done();
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should report invalid JSONata expression', function (done) {
|
||||
var flow = [{id: "n1", type: "inject", props: [{p:"topic", v:"t1", vt:"str"}, {p:"payload", v:"@", vt:"jsonata"}], wires: [["n2"]], z: "flow"},
|
||||
{id: "n2", type: "helper"}];
|
||||
helper.load(injectNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("topic", "t1");
|
||||
msg.should.not.have.property("payload");
|
||||
count++;
|
||||
if (count == 2) {
|
||||
done();
|
||||
}
|
||||
} catch (err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.on("call:error", function(err) {
|
||||
count++;
|
||||
if (count == 2) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
describe('post', function() {
|
||||
it('should inject message', function(done) {
|
||||
helper.load(injectNode,
|
||||
[{id:"n1", type:"inject",
|
||||
payloadType:"str", topic: "t4",payload:"hello",
|
||||
wires:[["n4"]] },
|
||||
{ id:"n4", type:"helper"}], function() {
|
||||
var n4 = helper.getNode("n4");
|
||||
n4.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 't4');
|
||||
msg.should.have.property('payload', 'hello');
|
||||
helper.clearFlows().then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
try {
|
||||
helper.request()
|
||||
.post('/inject/n1')
|
||||
.expect(200).end(function(err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return helper.clearFlows()
|
||||
.then(function () {
|
||||
done(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should inject custom properties in posted message', function(done) {
|
||||
var flow = [{id:"n1", type:"inject", payloadType:"str", topic: "t4",payload:"hello", wires:[["n4"]] },
|
||||
{ id:"n4", type:"helper"}];
|
||||
helper.load(injectNode, flow, function() {
|
||||
var n4 = helper.getNode("n4");
|
||||
n4.on("input", function(msg) {
|
||||
msg.should.not.have.property("payload"); //payload removed
|
||||
msg.should.have.property("topic", "t_override"); //changed value to t_override
|
||||
msg.should.have.property("str1", "1"); //injected prop
|
||||
msg.should.have.property("num1", 1); //injected prop
|
||||
msg.should.have.property("bool1", true); //injected prop
|
||||
|
||||
helper.clearFlows().then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
try {
|
||||
helper.request()
|
||||
.post('/inject/n1')
|
||||
.send({ __user_inject_props__: [
|
||||
{p:"topic", v:"t_override", vt:"str"}, //change value to t_override
|
||||
{p:"str1", v:"1", vt:"str"}, //new prop
|
||||
{p:"num1", v:"1", vt:"num"}, //new prop
|
||||
{p:"bool1", v:"true", vt:"bool"}, //new prop
|
||||
]})
|
||||
.expect(200).end(function(err) {
|
||||
if (err) {
|
||||
console.log(err);
|
||||
return helper.clearFlows()
|
||||
.then(function () {
|
||||
done(err);
|
||||
});
|
||||
}
|
||||
});
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail for invalid node', function(done) {
|
||||
helper.request().post('/inject/invalid').expect(404).end(done);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,659 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var debugNode = require("nr-test-utils").require("@node-red/nodes/core/common/21-debug.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var WebSocket = require('ws');
|
||||
|
||||
describe('debug node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
beforeEach(function (done) {
|
||||
setTimeout(function() {
|
||||
done();
|
||||
}, 55);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", name:"Debug", complete:"false" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('name', 'Debug');
|
||||
n1.should.have.property('complete', "payload");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish on input', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", name:"Debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:"test"});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",name:"Debug",msg:"test",path:"global",
|
||||
format:"string[4]",property:"payload"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish to console', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", console:"true"}];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var count = 0;
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:"test"});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:"test",property:"payload",format:"string[4]",path:"global"}
|
||||
}]);
|
||||
count++;
|
||||
}, function() {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "debug";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
var tstmp = logEvents[0][0].timestamp;
|
||||
logEvents[0][0].should.eql({level:helper.log().INFO, id:'n1',type:'debug',msg:'test', timestamp:tstmp,path:"global"});
|
||||
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish complete message', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", complete:"true" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:"test"});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",
|
||||
data:{id:"n1",msg:'{"payload":"test"}',format:"Object",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish complete message to console', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", complete:"true", console:"true" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:"test"});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",
|
||||
data:{id:"n1",msg:'{"payload":"test"}',format:"Object",path:"global"}
|
||||
}]);
|
||||
}, function() {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "debug";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
var tstmp = logEvents[0][0].timestamp;
|
||||
logEvents[0][0].should.eql({level:helper.log().INFO, id:"n1",type:"debug",msg:'\n{ payload: \'test\' }',timestamp:tstmp,path:"global"});
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish other property', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", complete:"foo" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:"test", foo:"bar"});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:"bar",property:"foo",format:"string[3]",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish multi-level properties', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", complete:"foo.bar" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:"test", foo: {bar:"bar"}});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:"bar",property:"foo.bar",format:"string[3]",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish an Error', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: new Error("oops")});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:'{"name":"Error","message":"oops"}',property:"payload",format:"error",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish a boolean', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: true});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg: 'true',property:"payload",format:"boolean",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish a number', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", console:"true" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: 7});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:"7",property:"payload",format:"number",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish a NaN', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", console:"true" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: Number.NaN});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:"NaN",property:"payload",format:"number",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish with no payload', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:'(undefined)',property:"payload",format:"undefined",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish a null', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:null});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:'(undefined)',property:"payload",format:"null",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish an object', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: {type:'foo'}});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",
|
||||
data:{id:"n1",msg:'{"type":"foo"}',property:"payload",format:"Object",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish an array', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: [0,1,2,3]});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",
|
||||
data:{id:"n1",msg: '[0,1,2,3]',format:"array[4]",
|
||||
property:"payload",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish an object with circular references', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
var o = { name: 'bar' };
|
||||
o.o = o;
|
||||
n1.emit("input", {payload: o});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",
|
||||
data:{
|
||||
id:"n1",
|
||||
msg:'{"name":"bar","o":"[Circular ~]"}',
|
||||
property:"payload",format:"Object",path:"global"
|
||||
}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish an object to console', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", console:"true"}];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: {type:'foo'}});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:'{"type":"foo"}',property:"payload",format:"Object",path:"global"}
|
||||
}]);
|
||||
}, function() {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "debug";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
var tstmp = logEvents[0][0].timestamp;
|
||||
logEvents[0][0].should.eql({level:helper.log().INFO,id:"n1",type:"debug",msg:'\n{ type: \'foo\' }',timestamp:tstmp,path:"global"});
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish a string after a newline to console if the string contains \\n', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", console:"true"}];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:"test\ntest"});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:"test\ntest",property:"payload",format:"string[9]",path:"global"}
|
||||
}]);
|
||||
}, function() {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "debug";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
var tstmp = logEvents[0][0].timestamp;
|
||||
logEvents[0][0].should.eql({level:helper.log().INFO,id:"n1",type:"debug",msg:"\ntest\ntest",timestamp:tstmp,path:"global"});
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish complete message with edit', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", name:"Debug", complete: "true",
|
||||
targetType: "jsonata", complete: '"<" & payload & ">"'}];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:"test"});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",name:"Debug",msg:"<test>",
|
||||
format:"string[6]",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should truncate a long message', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:Array(1002).join("X")});
|
||||
}, function(msg) {
|
||||
var a = JSON.parse(msg);
|
||||
a.should.eql([{
|
||||
topic:"debug",
|
||||
data:{
|
||||
id:"n1",
|
||||
msg: Array(1001).join("X")+'...',
|
||||
property:"payload",
|
||||
format:"string[1001]",
|
||||
path:"global"
|
||||
}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should truncate a long string in the object', function(done) {
|
||||
var flow = [{id:"n1", type:"debug"}];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: {foo: Array(1002).join("X")}});
|
||||
}, function(msg) {
|
||||
var a = JSON.parse(msg);
|
||||
a.should.eql([{
|
||||
topic:"debug",
|
||||
data:{
|
||||
id:"n1",
|
||||
msg:'{"foo":"'+Array(1001).join("X")+'..."}',
|
||||
property:"payload",
|
||||
format:"Object",
|
||||
path:"global"
|
||||
}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should truncate a large array', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: Array(1001).fill("X")});
|
||||
}, function(msg) {
|
||||
var a = JSON.parse(msg);
|
||||
a.should.eql([{
|
||||
topic:"debug",
|
||||
data:{
|
||||
id:"n1",
|
||||
msg:JSON.stringify({
|
||||
__enc__: true,
|
||||
type: "array",
|
||||
data: Array(1000).fill("X"),
|
||||
length: 1001
|
||||
}),
|
||||
property:"payload",
|
||||
format:"array[1001]",
|
||||
path:"global"
|
||||
}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should truncate a large array in the object', function(done) {
|
||||
var flow = [{id:"n1", type:"debug"}];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: {foo: Array(1001).fill("X")}});
|
||||
}, function(msg) {
|
||||
var a = JSON.parse(msg);
|
||||
a.should.eql([{
|
||||
topic:"debug",
|
||||
data:{
|
||||
id:"n1",
|
||||
msg:JSON.stringify({
|
||||
foo:{
|
||||
__enc__: true,
|
||||
type: "array",
|
||||
data: Array(1000).fill("X"),
|
||||
length: 1001
|
||||
}
|
||||
}),
|
||||
property:"payload",
|
||||
format:"Object",
|
||||
path:"global"
|
||||
}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should truncate a large buffer', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: Buffer.alloc(501,"\"")});
|
||||
}, function(msg) {
|
||||
var a = JSON.parse(msg);
|
||||
a[0].should.eql({
|
||||
topic:"debug",
|
||||
data:{
|
||||
id:"n1",
|
||||
msg: Array(1001).join("2"),
|
||||
property:"payload",
|
||||
format:"buffer[501]",
|
||||
path:"global"
|
||||
}
|
||||
});
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should truncate a large buffer in the object', function(done) {
|
||||
var flow = [{id:"n1", type:"debug"}];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: {foo: Buffer.alloc(1001,"X")}});
|
||||
}, function(msg) {
|
||||
var a = JSON.parse(msg);
|
||||
a[0].should.eql({
|
||||
topic:"debug",
|
||||
data:{
|
||||
id:"n1",
|
||||
msg:JSON.stringify({
|
||||
foo:{
|
||||
type: "Buffer",
|
||||
data: Array(1000).fill(88),
|
||||
__enc__: true,
|
||||
length: 1001
|
||||
}
|
||||
}),
|
||||
property:"payload",
|
||||
format:"Object",
|
||||
path:"global"
|
||||
}
|
||||
});
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert Buffer to hex', function(done) {
|
||||
var flow = [{id:"n1", type:"debug" }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload: Buffer.from('HELLO', 'utf8')});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",
|
||||
data:{
|
||||
id:"n1",
|
||||
msg:'48454c4c4f',
|
||||
property:"payload",
|
||||
format:"buffer[5]",
|
||||
path:"global"
|
||||
}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should publish when active', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", active: false }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function() {
|
||||
n1.emit("input", {payload:"message 1"});
|
||||
helper.request()
|
||||
.post('/debug/n1/enable')
|
||||
.expect(200).end(function(err) {
|
||||
if (err) { return done(err); }
|
||||
n1.emit("input", {payload:"message 2"});
|
||||
});
|
||||
}, function(msg) {
|
||||
JSON.parse(msg).should.eql([{
|
||||
topic:"debug",data:{id:"n1",msg:"message 2",property:"payload",format:"string[9]",path:"global"}
|
||||
}]);
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should not publish when inactive', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", active: true }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
websocket_test(function(close) {
|
||||
helper.request()
|
||||
.post('/debug/n1/disable')
|
||||
.expect(201).end(function(err) {
|
||||
if (err) {
|
||||
close();
|
||||
return done(err);
|
||||
}
|
||||
n1.emit("input", {payload:"message"});
|
||||
setTimeout(function() {
|
||||
close();
|
||||
done();
|
||||
}, 200);
|
||||
});
|
||||
}, function(msg) {
|
||||
should.fail(null,null,"unexpected message");
|
||||
}, function() {});
|
||||
});
|
||||
});
|
||||
|
||||
describe('post', function() {
|
||||
it('should return 404 on invalid state', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", active: true }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
helper.request()
|
||||
.post('/debug/n1/foobar')
|
||||
.expect(404).end(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should return 404 on invalid node', function(done) {
|
||||
helper.request()
|
||||
.post('/debug/n99/enable')
|
||||
.expect(404).end(done);
|
||||
});
|
||||
|
||||
it('should return 400 for invalid bulk disable', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", active: true }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
helper.request()
|
||||
.post('/debug/disable')
|
||||
.send({})
|
||||
.set('Content-type', 'application/json')
|
||||
.expect(400).end(done);
|
||||
});
|
||||
|
||||
})
|
||||
|
||||
it('should return success for bulk disable', function(done) {
|
||||
var flow = [{id:"n1", type:"debug", active: true }];
|
||||
helper.load(debugNode, flow, function() {
|
||||
helper.request()
|
||||
.post('/debug/disable')
|
||||
.send({nodes:['n1']})
|
||||
.set('Content-type', 'application/json')
|
||||
.expect(201).end(done);
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
|
||||
describe('get', function() {
|
||||
it('should return the view.html', function(done) {
|
||||
var flow = [{id:"n1", type:"debug"}];
|
||||
helper.load(debugNode, flow, function() {
|
||||
helper.request()
|
||||
.get('/debug/view/view.html')
|
||||
.expect(200)
|
||||
.end(done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
function websocket_test(open_callback, message_callback, done_callback) {
|
||||
var ws = new WebSocket(helper.url() + "/comms");
|
||||
var close_callback = function() { ws.close(); };
|
||||
ws.on('open', function() { open_callback(close_callback); });
|
||||
ws.on('message', function(msg) {
|
||||
try {
|
||||
message_callback(msg, close_callback);
|
||||
ws.close();
|
||||
done_callback();
|
||||
} catch(err) {
|
||||
done_callback(err);
|
||||
}
|
||||
});
|
||||
}
|
@@ -1,44 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var catchNode = require("nr-test-utils").require("@node-red/nodes/core/common/25-catch.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('catch Node', function() {
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should output a message when called', function(done) {
|
||||
var flow = [ { id:"n1", type:"catch", name:"catch", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(catchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.should.have.property('name', 'catch');
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.be.a.Error();
|
||||
msg.toString().should.equal("Error: big error");
|
||||
done();
|
||||
});
|
||||
var err = new Error("big error");
|
||||
n1.emit("input", err);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -1,54 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var catchNode = require("nr-test-utils").require("@node-red/nodes/core/common/25-status.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('status Node', function() {
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should output a message when called', function(done) {
|
||||
var flow = [ { id:"n1", type:"status", name:"status", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"} ];
|
||||
helper.load(catchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.should.have.property('name', 'status');
|
||||
n2.on("input", function(msg) {
|
||||
msg.text.should.equal("Oh dear");
|
||||
msg.should.have.property('source');
|
||||
msg.source.should.have.property('id',"12345");
|
||||
msg.source.should.have.property('type',"testnode");
|
||||
msg.source.should.have.property('name',"fred");
|
||||
done();
|
||||
});
|
||||
var mst = {
|
||||
text: "Oh dear",
|
||||
source: {
|
||||
id: "12345",
|
||||
type: "testnode",
|
||||
name: "fred"
|
||||
}
|
||||
}
|
||||
n1.emit("input", mst);
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -1,187 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var linkNode = require("nr-test-utils").require("@node-red/nodes/core/common/60-link.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('link Node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should be loaded (link in)', function(done) {
|
||||
var flow = [{id:"n1", type:"link in", name: "link-in" }];
|
||||
helper.load(linkNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('name', 'link-in');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be loaded (link out)', function(done) {
|
||||
var flow = [{id:"n1", type:"link out", name: "link-out" }];
|
||||
helper.load(linkNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('name', 'link-out');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be linked', function(done) {
|
||||
var flow = [{id:"n1", type:"link out", name: "link-out", links:["n2"]},
|
||||
{id:"n2", type:"link in", name: "link-in", wires:[["n3"]]},
|
||||
{id:"n3", type:"helper"}];
|
||||
helper.load(linkNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n3 = helper.getNode("n3");
|
||||
n3.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload', 'hello');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"hello"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be linked to multiple nodes', function(done) {
|
||||
var flow = [{id:"n1", type:"link out", name: "link-out", links:["n2", "n3"]},
|
||||
{id:"n2", type:"link in", name: "link-in0", wires:[["n4"]]},
|
||||
{id:"n3", type:"link in", name: "link-in1", wires:[["n4"]]},
|
||||
{id:"n4", type:"helper"} ];
|
||||
helper.load(linkNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n4 = helper.getNode("n4");
|
||||
var count = 0;
|
||||
n4.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property('payload', 'hello');
|
||||
count++;
|
||||
if(count == 2) {
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"hello"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be linked from multiple nodes', function(done) {
|
||||
var flow = [{id:"n1", type:"link out", name: "link-out0", links:["n3"]},
|
||||
{id:"n2", type:"link out", name: "link-out1", links:["n3"]},
|
||||
{id:"n3", type:"link in", name: "link-in", wires:[["n4"]]},
|
||||
{id:"n4", type:"helper"} ];
|
||||
helper.load(linkNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n4 = helper.getNode("n4");
|
||||
var count = 0;
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload', 'hello');
|
||||
count++;
|
||||
if(count == 2) {
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"hello"});
|
||||
n2.receive({payload:"hello"});
|
||||
});
|
||||
});
|
||||
|
||||
describe("link-call node", function() {
|
||||
it('should call link-in node and get response', function(done) {
|
||||
var flow = [{id:"link-in-1", type:"link in", wires: [[ "func"]]},
|
||||
{id:"func", type:"helper", wires: [["link-out-1"]]},
|
||||
{id:"link-out-1", type:"link out", mode: "return"},
|
||||
{id:"link-call", type:"link call", links:["link-in-1"], wires:[["n4"]]},
|
||||
{id:"n4", type:"helper"} ];
|
||||
helper.load(linkNode, flow, function() {
|
||||
var func = helper.getNode("func");
|
||||
func.on("input", function(msg, send, done) {
|
||||
msg.payload = "123";
|
||||
send(msg);
|
||||
done();
|
||||
})
|
||||
var n1 = helper.getNode("link-call");
|
||||
var n4 = helper.getNode("n4");
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload', '123');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"hello"});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
it('should allow nested link-call flows', function(done) {
|
||||
var flow = [/** Multiply by 2 link flow **/
|
||||
{id:"li1", type:"link in", wires: [[ "m2"]]},
|
||||
{id:"m2", type:"helper", wires: [["lo1"]]},
|
||||
{id:"lo1", type:"link out", mode: "return"},
|
||||
/** Multiply by 3 link flow **/
|
||||
{id:"li2", type:"link in", wires: [[ "m3"]]},
|
||||
{id:"m3", type:"helper", wires: [["lo2"]]},
|
||||
{id:"lo2", type:"link out", mode: "return"},
|
||||
/** Multiply by 6 link flow **/
|
||||
{id:"li3", type:"link in", wires: [[ "link-call-1"]]},
|
||||
{id:"link-call-1", type:"link call", links:["m2"], wires:[["link-call-2"]]},
|
||||
{id:"link-call-2", type:"link call", links:["m3"], wires:[["lo3"]]},
|
||||
{id:"lo3", type:"link out", mode: "return"},
|
||||
/** Test Flow Entry **/
|
||||
{id:"link-call", type:"link call", links:["li3"], wires:[["n4"]]},
|
||||
{id:"n4", type:"helper"} ];
|
||||
helper.load(linkNode, flow, function() {
|
||||
var m2 = helper.getNode("m2");
|
||||
m2.on("input", function(msg, send, done) { msg.payload *= 2 ; send(msg); done(); })
|
||||
var m3 = helper.getNode("m3");
|
||||
m3.on("input", function(msg, send, done) { msg.payload *= 3 ; send(msg); done(); })
|
||||
|
||||
var n1 = helper.getNode("link-call");
|
||||
var n4 = helper.getNode("n4");
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload', 24);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:4});
|
||||
});
|
||||
})
|
||||
});
|
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var commentNode = require("nr-test-utils").require("@node-red/nodes/core/common/90-comment.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('comment Node', function() {
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"n1", type:"comment", name: "comment" }];
|
||||
helper.load(commentNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('name', 'comment');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -1,36 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var unknown = require("nr-test-utils").require("@node-red/nodes/core/common/98-unknown.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('unknown Node', function() {
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"n1", type:"unknown", name: "unknown" }];
|
||||
helper.load(unknown, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('name', 'unknown');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,152 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
|
||||
var rangeNode = require("nr-test-utils").require("@node-red/nodes/core/function/16-range.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('range Node', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload();
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
it('should load some defaults', function(done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","name":"rangeNode"}];
|
||||
helper.load(rangeNode, flow, function() {
|
||||
var rangeNode1 = helper.getNode("rangeNode1");
|
||||
rangeNode1.should.have.property('name', 'rangeNode');
|
||||
rangeNode1.should.have.property('round', false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* Run a generic range test
|
||||
* @param action - scale/clamp (range limit)/roll (modulo): what action to choose
|
||||
* @param minin - map from minimum value
|
||||
* @param maxin - map from maximum value
|
||||
* @param minout - map to minimum value
|
||||
* @param maxout - map to maximum value
|
||||
* @param round - whether to round the result to the nearest integer
|
||||
* @param aPayload - what payload to send to the range node
|
||||
* @param expectedResult - what result we're expecting
|
||||
* @param done - the callback to call when test done
|
||||
*/
|
||||
function genericRangeTest(action, minin, maxin, minout, maxout, round, aPayload, expectedResult, done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","minin":minin,"maxin":maxin,"minout":minout,"maxout":maxout,"action":action,"round":round,"name":"rangeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(rangeNode, flow, function() {
|
||||
var rangeNode1 = helper.getNode("rangeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.payload.should.equal(expectedResult);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
rangeNode1.receive({payload:aPayload});
|
||||
});
|
||||
}
|
||||
|
||||
it('ranges numbers up tenfold', function(done) {
|
||||
genericRangeTest("scale", 0, 100, 0, 1000, false, 50, 500, done);
|
||||
});
|
||||
|
||||
it('ranges numbers down such as centimetres to metres', function(done) {
|
||||
genericRangeTest("scale", 0, 100, 0, 1, false, 55, 0.55, done);
|
||||
});
|
||||
|
||||
it('wraps numbers down say for degree/rotation reading 1/2', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, 15, 180, done); // 1/2 around wrap => "one and a half turns"
|
||||
});
|
||||
|
||||
it('wraps numbers around say for degree/rotation reading 1/3', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, 13.3333, 120, done); // 1/3 around wrap => "one and a third turns"
|
||||
});
|
||||
|
||||
it('wraps numbers around say for degree/rotation reading 1/4', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, 12.5, 90, done); // 1/4 around wrap => "one and a quarter turns"
|
||||
});
|
||||
|
||||
it('wraps numbers down say for degree/rotation reading 1/4', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, -12.5, 270, done); // 1/4 backwards wrap => "one and a quarter turns backwards"
|
||||
});
|
||||
|
||||
it('wraps numbers around say for degree/rotation reading 0', function(done) {
|
||||
genericRangeTest("roll", 0, 10, 0, 360, true, -10, 0, done);
|
||||
});
|
||||
|
||||
it('clamps numbers within a range - over max', function(done) {
|
||||
genericRangeTest("clamp", 0, 10, 0, 1000, false, 111, 1000, done);
|
||||
});
|
||||
|
||||
it('clamps numbers within a range - below min', function(done) {
|
||||
genericRangeTest("clamp", 0, 10, 0, 1000, false, -1, 0, done);
|
||||
});
|
||||
|
||||
it('just passes on msg if payload not present', function(done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","minin":0,"maxin":100,"minout":0,"maxout":100,"action":"scale","round":true,"name":"rangeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(rangeNode, flow, function() {
|
||||
var rangeNode1 = helper.getNode("rangeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
helperNode1.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.not.have.property('payload');
|
||||
msg.topic.should.equal("pass on");
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
rangeNode1.receive({topic:"pass on"});
|
||||
});
|
||||
});
|
||||
|
||||
it('reports if input is not a number', function(done) {
|
||||
var flow = [{"id":"rangeNode1","type":"range","minin":0,"maxin":0,"minout":0,"maxout":0,"action":"scale","round":true,"name":"rangeNode","wires":[["helperNode1"]]},
|
||||
{id:"helperNode1", type:"helper", wires:[]}];
|
||||
helper.load(rangeNode, flow, function() {
|
||||
var rangeNode1 = helper.getNode("rangeNode1");
|
||||
var helperNode1 = helper.getNode("helperNode1");
|
||||
rangeNode1.on("call:log",function(args) {
|
||||
var log = args.args[0];
|
||||
if (log.indexOf("notnumber") > -1) {
|
||||
rangeNode1.log.restore();
|
||||
done();
|
||||
} else {
|
||||
try {
|
||||
should.fail(null, null, "Non-number inputs should be reported!");
|
||||
} catch (err) {
|
||||
rangeNode1.log.restore();
|
||||
done(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
rangeNode1.receive({payload:"NOT A NUMBER"});
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,498 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var templateNode = require("nr-test-utils").require("@node-red/nodes/core/function/80-template.js");
|
||||
var Context = require("nr-test-utils").require("@node-red/runtime/lib/nodes/context");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('template node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
beforeEach(function(done) {
|
||||
done();
|
||||
});
|
||||
|
||||
function initContext(done) {
|
||||
Context.init({
|
||||
contextStorage: {
|
||||
memory0: { // do not use (for excluding effect fallback)
|
||||
module: "memory"
|
||||
},
|
||||
memory1: {
|
||||
module: "memory"
|
||||
},
|
||||
memory2: {
|
||||
module: "memory"
|
||||
}
|
||||
}
|
||||
});
|
||||
Context.load().then(function () {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload().then(function () {
|
||||
return Context.clean({allNodes:{}});
|
||||
}).then(function () {
|
||||
return Context.close();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should modify payload using node-configured template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
msg.should.have.property('template', 'this should be ignored as the node has its own template {{payload}}');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar", template: "this should be ignored as the node has its own template {{payload}}"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify the configured property using msg.template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"randomProperty", template:"",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
msg.should.have.property('template', 'payload={{payload}}');
|
||||
msg.should.have.property('randomProperty', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo", topic: "bar", template: "payload={{payload}}"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to overwrite msg.template using the template from msg.template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", template:"",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'topic=bar');
|
||||
msg.should.have.property('template', 'topic={{topic}}');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo", topic: "bar", template: "topic={{topic}}"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from msg.template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", template:"",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var received = [];
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
received.push(msg);
|
||||
if (received.length === 3) {
|
||||
received[0].should.have.property('topic', 'bar');
|
||||
received[0].should.have.property('payload', 'topic=bar');
|
||||
received[0].should.have.property('template', 'topic={{topic}}');
|
||||
|
||||
received[1].should.have.property('topic', 'another bar');
|
||||
received[1].should.have.property('payload', 'topic=another bar');
|
||||
received[1].should.have.property('template', 'topic={{topic}}');
|
||||
|
||||
received[2].should.have.property('topic', 'bar');
|
||||
received[2].should.have.property('payload', 'payload=foo');
|
||||
received[2].should.have.property('template', 'payload={{payload}}');
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo", topic: "bar", template: "topic={{topic}}"});
|
||||
n1.receive({payload:"foo", topic: "another bar", template: "topic={{topic}}"});
|
||||
n1.receive({payload:"foo", topic: "bar", template: "payload={{payload}}"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow.value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.context().flow.set("value","foo");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from persistable flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow[memory1].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.context().flow.set("value","foo","memory1",function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle nested context tags - property not set', function(done) {
|
||||
// This comes from the Coursera Node-RED course and is a good example of
|
||||
// multiple conditional tags
|
||||
var template = `{{#flow.time}}time={{flow.time}}{{/flow.time}}{{^flow.time}}!time{{/flow.time}}{{#flow.random}}random={{flow.random}}randomtime={{flow.randomtime}}{{/flow.random}}{{^flow.random}}!random{{/flow.random}}`;
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:template,wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', '!time!random');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
})
|
||||
it('should handle nested context tags - property set', function(done) {
|
||||
// This comes from the Coursera Node-RED course and is a good example of
|
||||
// multiple conditional tags
|
||||
var template = `{{#flow.time}}time={{flow.time}}{{/flow.time}}{{^flow.time}}!time{{/flow.time}}{{#flow.random}}random={{flow.random}}randomtime={{flow.randomtime}}{{/flow.random}}{{^flow.random}}!random{{/flow.random}}`;
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:template,wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'time=123random=456randomtime=789');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.context().flow.set(["time","random","randomtime"],["123","456","789"],function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
it('should modify payload from two persistable flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow[memory1].value}}/{{flow[memory2].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo/bar');
|
||||
done();
|
||||
});
|
||||
n1.context().flow.set("value","foo","memory1",function (err) {
|
||||
n1.context().flow.set("value","bar","memory2",function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global.value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.context().global.set("value","foo");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from persistable global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global[memory1].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.context().global.set("value","foo","memory1", function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from two persistable global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global[memory1].value}}/{{global[memory2].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo/bar');
|
||||
done();
|
||||
});
|
||||
n1.context().global.set("value","foo","memory1", function (err) {
|
||||
n1.context().global.set("value","bar","memory2", function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload from persistable flow & global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow[memory1].value}}/{{global[memory1].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo/bar');
|
||||
done();
|
||||
});
|
||||
n1.context().flow.set("value","foo","memory1", function (err) {
|
||||
n1.context().global.set("value","bar","memory1", function (err) {
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle missing node context', function(done) {
|
||||
// this is artificial test because in flow there is missing z property (probably never happen in real usage)
|
||||
var flow = [{id:"n1",type:"template", field:"payload", template:"payload={{flow.value}},{{global.value}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=,');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle escape characters in Mustache format and JSON output mode', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", syntax:"mustache", template:"{\"data\":\"{{payload}}\"}", output:"json", wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.payload.should.have.property('data', 'line\t1\nline\\2\r\nline\b3\f');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"line\t1\nline\\2\r\nline\b3\f"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify payload in plain text mode', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field:"payload", syntax:"plain", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload={{payload}}');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", fieldType:"flow", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
// mesage is intact
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
// result is in flow context
|
||||
n2.context().flow.get("payload").should.equal("payload=foo");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify persistable flow context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"#:(memory1)::payload", fieldType:"flow", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
// mesage is intact
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
// result is in flow context
|
||||
n2.context().flow.get("payload", "memory1", function (err, val) {
|
||||
val.should.equal("payload=foo");
|
||||
done();
|
||||
});
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", fieldType:"global", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
// mesage is intact
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
// result is in global context
|
||||
n2.context().global.get("payload").should.equal("payload=foo");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should modify persistable global context', function(done) {
|
||||
var flow = [{id:"n1",z:"t1", type:"template", field:"#:(memory1)::payload", fieldType:"global", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
initContext(function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
// mesage is intact
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'foo');
|
||||
// result is in global context
|
||||
n2.context().global.get("payload", "memory1", function (err, val) {
|
||||
val.should.equal("payload=foo");
|
||||
done();
|
||||
});
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle if the field isn\'t set', function(done) {
|
||||
var flow = [{id:"n1", type:"template", template: "payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo",topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle deeper objects', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field: "topic.foo.bar", template: "payload={{payload.doh.rei.me}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic');
|
||||
msg.topic.should.have.property('foo');
|
||||
msg.topic.foo.should.have.a.property('bar', 'payload=foo');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:{doh:{rei:{me:"foo"}}}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle block contexts objects', function(done) {
|
||||
var flow = [{id:"n1", type:"template", template: "A{{#payload.A}}{{payload.A}}{{.}}{{/payload.A}}B",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('payload','AabcabcB');
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:{A:"abc"}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should raise error if passed bad template', function(done) {
|
||||
var flow = [{id:"n1", type:"template", field: "payload", template: "payload={{payload",wires:[["n2"]]},{id:"n2",type:"helper"}];
|
||||
helper.load(templateNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
setTimeout(function() {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "template";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.toString().should.startWith("Unclosed tag at ");
|
||||
done();
|
||||
},25);
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,973 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var sinon = require("sinon");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var execNode = require("nr-test-utils").require("@node-red/nodes/core/function/90-exec.js");
|
||||
var osType = require("os").type();
|
||||
|
||||
var child_process = require('child_process');
|
||||
|
||||
describe('exec node', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload().then(function() {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be loaded with any defaults', function(done) {
|
||||
var flow = [{id:"n1", type:"exec", name: "exec1"}];
|
||||
helper.load(execNode, flow, function() {
|
||||
try {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property("name", "exec1");
|
||||
n1.should.have.property("cmd", "");
|
||||
n1.should.have.property("append", "");
|
||||
n1.should.have.property("addpay","payload");
|
||||
n1.should.have.property("timer",0);
|
||||
n1.should.have.property("oldrc","false");
|
||||
n1.should.have.property("execOpt");
|
||||
n1.execOpt.should.have.property("encoding", 'binary');
|
||||
n1.execOpt.should.have.property("maxBuffer", 10000000);
|
||||
n1.execOpt.should.have.property("windowsHide", false);
|
||||
n1.should.have.property("spawnOpt");
|
||||
n1.spawnOpt.should.have.property("windowsHide", false);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('calling exec', function() {
|
||||
|
||||
it('should exec a simple command', function(done) {
|
||||
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:false, append:"", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
var spy = sinon.stub(child_process, 'exec').callsFake(
|
||||
function(arg1, arg2, arg3, arg4) {
|
||||
// arg3(error,stdout,stderr);
|
||||
arg3(null,arg1,arg1.toUpperCase());
|
||||
});
|
||||
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
var received = 0;
|
||||
var messages = [null,null,null];
|
||||
var completeTest = function() {
|
||||
received = received + 1;
|
||||
if (received < 3) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var msg = messages[0];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("echo");
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",0);
|
||||
|
||||
msg = messages[1];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("ECHO");
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",0);
|
||||
|
||||
msg = messages[2];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("code",0);
|
||||
|
||||
child_process.exec.restore();
|
||||
done();
|
||||
}
|
||||
catch(err) {
|
||||
child_process.exec.restore();
|
||||
done(err);
|
||||
}
|
||||
};
|
||||
n2.on("input", function(msg) {
|
||||
messages[0] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n3.on("input", function(msg) {
|
||||
messages[1] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
messages[2] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n1.receive({payload:"and"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should exec a simple command with appended value from message', function (done) {
|
||||
var flow = [{id:"n1", type:"exec", wires:[["n2"]], command:"echo", addpay:"topic", append:"more", oldrc:"false"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(execNode, flow, function () {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function (msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("bar more\n");
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo", topic:"bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should exec a simple command with extra parameters', function(done) {
|
||||
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:"payload", append:"more", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
var spy = sinon.stub(child_process, 'exec').callsFake(
|
||||
function(arg1, arg2, arg3, arg4) {
|
||||
//console.log(arg1);
|
||||
// arg3(error,stdout,stderr);
|
||||
arg3(null,arg1,arg1.toUpperCase());
|
||||
});
|
||||
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
var received = 0;
|
||||
var messages = [null,null];
|
||||
var completeTest = function() {
|
||||
received++;
|
||||
if (received < 2) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var msg = messages[0];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("echo and more");
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",0);
|
||||
|
||||
msg = messages[1];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("ECHO AND MORE");
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",0);
|
||||
child_process.exec.restore();
|
||||
done();
|
||||
}
|
||||
catch(err) {
|
||||
child_process.exec.restore();
|
||||
done(err);
|
||||
}
|
||||
};
|
||||
n2.on("input", function(msg) {
|
||||
messages[0] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n3.on("input", function(msg) {
|
||||
messages[1] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n1.receive({payload:"and"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to return a binary buffer', function(done) {
|
||||
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
var spy = sinon.stub(child_process, 'exec').callsFake(
|
||||
function(arg1, arg2, arg3, arg4) {
|
||||
//console.log(arg1);
|
||||
// arg3(error,stdout,stderr);
|
||||
arg3("error",Buffer.from([0x01,0x02,0x03,0x88]),Buffer.from([0x01,0x02,0x03,0x88]));
|
||||
});
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n2.on("input", function(msg) {
|
||||
//console.log("n2",msg);
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
Buffer.isBuffer(msg.payload).should.be.true();
|
||||
msg.payload.length.should.equal(4);
|
||||
child_process.exec.restore();
|
||||
done();
|
||||
} catch(err) {
|
||||
child_process.exec.restore();
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to timeout a long running command', function(done) {
|
||||
var flow;
|
||||
if (osType === "Windows_NT") {
|
||||
// Although Windows timeout command is equivalent to sleep, this cannot be used because it promptly outputs a message.
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"0.3", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
}
|
||||
else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"0.3", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("signal","SIGTERM");
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to kill a long running command', function(done) {
|
||||
var flow;
|
||||
if (osType === "Windows_NT") {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
}
|
||||
else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",null);
|
||||
msg.rc.should.have.property("signal","SIGTERM");
|
||||
} catch(err) { done(err); }
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("signal","SIGTERM");
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
setTimeout(function() {
|
||||
n1.receive({kill:""});
|
||||
},150);
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to kill a long running command - SIGINT', function(done) {
|
||||
var flow;
|
||||
var sig = "SIGINT";
|
||||
if (osType === "Windows_NT") {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",null);
|
||||
msg.rc.should.have.property("signal","SIGINT");
|
||||
} catch(err) { done(err); }
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("signal",sig);
|
||||
done();
|
||||
} catch(err) { done(err); }
|
||||
});
|
||||
setTimeout(function() {
|
||||
n1.receive({kill:"SIGINT"});
|
||||
},150);
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('should return the rc for a failing command', function(done) {
|
||||
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"error", addpay:false, append:"", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
var spy = sinon.stub(child_process, 'exec').callsFake(
|
||||
function(arg1, arg2, arg3, arg4) {
|
||||
//console.log(arg1);
|
||||
// arg3(error,stdout,stderr);
|
||||
arg3({code: 1},arg1,arg1.toUpperCase());
|
||||
});
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
var received = 0;
|
||||
var messages = [null,null,null];
|
||||
var completeTest = function() {
|
||||
received++;
|
||||
if (received < 3) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var msg = messages[0];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("error");
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",1);
|
||||
msg.rc.should.have.property("message",undefined);
|
||||
|
||||
msg = messages[1];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("ERROR");
|
||||
|
||||
msg = messages[2];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("code",1);
|
||||
|
||||
child_process.exec.restore();
|
||||
done();
|
||||
}
|
||||
catch(err) {
|
||||
child_process.exec.restore();
|
||||
done(err);
|
||||
}
|
||||
};
|
||||
n2.on("input", function(msg) {
|
||||
messages[0] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n3.on("input", function(msg) {
|
||||
messages[1] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
messages[2] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n1.receive({payload:"and"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve existing properties on msg object', function(done) {
|
||||
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:false, append:"", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
var spy = sinon.stub(child_process, 'exec').callsFake(
|
||||
function(arg1, arg2, arg3, arg4) {
|
||||
// arg3(error,stdout,stderr);
|
||||
arg3(null,arg1,arg1.toUpperCase());
|
||||
});
|
||||
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
var received = 0;
|
||||
var messages = [null,null,null];
|
||||
var completeTest = function() {
|
||||
received = received + 1;
|
||||
if (received < 3) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var msg = messages[0];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("echo");
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",0);
|
||||
msg.should.have.property("foo","bar");
|
||||
|
||||
msg = messages[1];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("ECHO");
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",0);
|
||||
msg.should.have.property("foo","bar");
|
||||
|
||||
msg = messages[2];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("code",0);
|
||||
msg.should.have.property("foo","bar");
|
||||
|
||||
child_process.exec.restore();
|
||||
done();
|
||||
}
|
||||
catch(err) {
|
||||
child_process.exec.restore();
|
||||
done(err);
|
||||
}
|
||||
};
|
||||
n2.on("input", function(msg) {
|
||||
messages[0] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n3.on("input", function(msg) {
|
||||
messages[1] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
messages[2] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n1.receive({payload:"and", foo:"bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve existing properties on msg object for a failing command', function(done) {
|
||||
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"error", addpay:false, append:"", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
var spy = sinon.stub(child_process, 'exec').callsFake(
|
||||
function(arg1, arg2, arg3, arg4) {
|
||||
// arg3(error,stdout,stderr);
|
||||
arg3({code: 1},arg1,arg1.toUpperCase());
|
||||
});
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
var received = 0;
|
||||
var messages = [null,null,null];
|
||||
var completeTest = function() {
|
||||
received++;
|
||||
if (received < 3) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var msg = messages[0];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("error");
|
||||
msg.should.have.property("rc");
|
||||
msg.rc.should.have.property("code",1);
|
||||
msg.rc.should.have.property("message",undefined);
|
||||
msg.should.have.property("foo",null);
|
||||
|
||||
msg = messages[1];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal("ERROR");
|
||||
msg.should.have.property("foo",null);
|
||||
|
||||
msg = messages[2];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("code",1);
|
||||
msg.should.have.property("foo",null);
|
||||
|
||||
child_process.exec.restore();
|
||||
done();
|
||||
}
|
||||
catch(err) {
|
||||
child_process.exec.restore();
|
||||
done(err);
|
||||
}
|
||||
};
|
||||
n2.on("input", function(msg) {
|
||||
messages[0] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n3.on("input", function(msg) {
|
||||
messages[1] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
messages[2] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n1.receive({payload:"and", foo:null});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('calling spawn', function() {
|
||||
|
||||
it('should spawn a simple command', function(done) {
|
||||
var flow;
|
||||
var expected;
|
||||
if (osType === "Windows_NT") {
|
||||
// Need to use cmd to spawn a process because Windows echo command is a built-in command and cannot be spawned.
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo", addpay:true, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "hello world\r\n";
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "hello world\n";
|
||||
}
|
||||
var events = require('events');
|
||||
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
var payload = "";
|
||||
n2.on("input", function(msg) {
|
||||
//console.log(msg);
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
payload += msg.payload;
|
||||
if (payload.endsWith("\n")) {
|
||||
payload.should.equal(expected);
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.receive({payload:"hello world"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should spawn a simple command with a non string payload parameter', function(done) {
|
||||
var flow;
|
||||
var expected;
|
||||
if (osType === "Windows_NT") {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo", addpay:true, append:" deg C", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "12345 deg C\r\n";
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:" deg C", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "12345 deg C\n";
|
||||
}
|
||||
var payload = "";
|
||||
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n2.on("input", function(msg) {
|
||||
//console.log(msg);
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
payload += msg.payload;
|
||||
if (payload.endsWith("\n")) {
|
||||
payload.should.equal(expected);
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.receive({payload:12345});
|
||||
});
|
||||
});
|
||||
|
||||
it('should spawn a simple command and return binary buffer', function(done) {
|
||||
var flow;
|
||||
if (osType === "Windows_NT") {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo", addpay:true, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
}
|
||||
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
Buffer.isBuffer(msg.payload).should.be.true();
|
||||
if (osType === "Windows_NT") {
|
||||
msg.payload.length.should.equalOneOf(6,8);
|
||||
} else {
|
||||
msg.payload.length.should.equal(7);
|
||||
}
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.receive({payload:Buffer.from([0x01,0x02,0x03,0x88])});
|
||||
});
|
||||
});
|
||||
|
||||
it('should work if passed multiple words to spawn command', function(done) {
|
||||
var flow;
|
||||
var expected;
|
||||
if (osType === "Windows_NT") {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo this now works", addpay:false, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "this now works\r\n";
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo this now works", addpay:false, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "this now works\n";
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
var received = 0;
|
||||
var messages = [null,null];
|
||||
var completeTest = function() {
|
||||
received++;
|
||||
if (received < 2) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var msg = messages[0];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal(expected);
|
||||
|
||||
msg = messages[1];
|
||||
msg.should.have.property("payload");
|
||||
should.exist(msg.payload);
|
||||
msg.payload.should.have.property("code",0);
|
||||
done();
|
||||
}
|
||||
catch(err) {
|
||||
done(err);
|
||||
}
|
||||
};
|
||||
|
||||
n2.on("input", function(msg) {
|
||||
var payload = msg.payload;
|
||||
if (messages[0]) {
|
||||
messages[0].payload += payload;
|
||||
}
|
||||
else {
|
||||
messages[0] = msg;
|
||||
}
|
||||
if (payload.endsWith("\n")) {
|
||||
completeTest();
|
||||
}
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
messages[1] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n1.receive({payload:null,fred:123});
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an error for a bad command', function(done) {
|
||||
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"madeupcommandshouldfail", addpay:false, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("code");
|
||||
msg.payload.code.should.be.below(0);
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.receive({payload:null});
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an error for a failing command', function(done) {
|
||||
var flow;
|
||||
var expected;
|
||||
var expectedFound = false;
|
||||
if (osType === "Windows_NT") {
|
||||
// Cannot use mkdir because Windows mkdir command automatically creates non-existent directories.
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping /foo/bar/doo/dah", addpay:false, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "IP address must be specified.";
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"mkdir /foo/bar/doo/dah", addpay:false, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = ' directory';
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n3.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
if (msg.payload.indexOf(expected) >= 0) {
|
||||
// The error text on the stderr stream might get sent in more than one piece.
|
||||
// We only need to know that it occurred before the return code is sent,
|
||||
// as checked below in node n4.
|
||||
expectedFound = true;
|
||||
}
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
expectedFound.should.be.true;
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("code",1);
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.receive({payload:null});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to timeout a long running command', function(done) {
|
||||
var flow;
|
||||
if (osType === "Windows_NT") {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000", timer:"0.3", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"0.3", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("code",null);
|
||||
msg.payload.should.have.property("signal","SIGTERM");
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to kill a long running command', function(done) {
|
||||
var flow;
|
||||
if (osType === "Windows_NT") {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("signal","SIGTERM");
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
setTimeout(function() {
|
||||
n1.receive({kill:""});
|
||||
},150);
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('should be able to kill a long running command - SIGINT', function(done) {
|
||||
var flow;
|
||||
var sig = "SIGINT";
|
||||
if (osType === "Windows_NT") {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping", addpay:false, append:"192.0.2.0 -n 1 -w 1000 > NUL", timer:"2", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"sleep", addpay:false, append:"1", timer:"2", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
n4.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("signal",sig);
|
||||
done();
|
||||
}
|
||||
catch(err) { done(err); }
|
||||
});
|
||||
setTimeout(function() {
|
||||
n1.receive({kill:"SIGINT"});
|
||||
},150);
|
||||
n1.receive({});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve existing properties on msg object', function(done) {
|
||||
var flow;
|
||||
var expected;
|
||||
if (osType === "Windows_NT") {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"cmd /C echo this now works", addpay:false, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "this now works\r\n";
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo this now works", addpay:false, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "this now works\n";
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
var received = 0;
|
||||
var messages = [null,null];
|
||||
var completeTest = function() {
|
||||
received++;
|
||||
if (received < 2) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
var msg = messages[0];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.payload.should.equal(expected);
|
||||
msg.should.have.property("foo",123);
|
||||
|
||||
msg = messages[1];
|
||||
msg.should.have.property("payload");
|
||||
should.exist(msg.payload);
|
||||
msg.payload.should.have.property("code",0);
|
||||
msg.should.have.property("foo",123);
|
||||
|
||||
done();
|
||||
}
|
||||
catch(err) {
|
||||
done(err);
|
||||
}
|
||||
};
|
||||
|
||||
n2.on("input", function(msg) {
|
||||
var payload = msg.payload;
|
||||
if (messages[0]) {
|
||||
messages[0].payload += payload;
|
||||
}
|
||||
else {
|
||||
messages[0] = msg;
|
||||
}
|
||||
if (payload.endsWith("\n")) {
|
||||
completeTest();
|
||||
}
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
messages[1] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n1.receive({payload:null,foo:123});
|
||||
});
|
||||
});
|
||||
|
||||
it('should preserve existing properties on msg object for a failing command', function(done) {
|
||||
var flow;
|
||||
var expected;
|
||||
if (osType === "Windows_NT") {
|
||||
// Cannot use mkdir because Windows mkdir command automatically creates non-existent directories.
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"ping /foo/bar/doo/dah", addpay:false, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = "IP address must be specified.";
|
||||
} else {
|
||||
flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"mkdir /foo/bar/doo/dah", addpay:false, append:"", useSpawn:"true", oldrc:"false"},
|
||||
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
|
||||
expected = ' directory';
|
||||
}
|
||||
helper.load(execNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var n3 = helper.getNode("n3");
|
||||
var n4 = helper.getNode("n4");
|
||||
var received = 0;
|
||||
var messages = [null,null];
|
||||
var completeTest = function() {
|
||||
if (messages[0] === null || messages[1] === null) {
|
||||
// We have not yet had responses on both ports.
|
||||
return
|
||||
}
|
||||
try {
|
||||
var msg = messages[0];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.be.a.String();
|
||||
msg.should.have.property("foo","baz");
|
||||
|
||||
msg = messages[1];
|
||||
msg.should.have.property("payload");
|
||||
msg.payload.should.have.property("code",1);
|
||||
msg.should.have.property("foo","baz");
|
||||
|
||||
done();
|
||||
}
|
||||
catch(err) {
|
||||
done(err);
|
||||
}
|
||||
};
|
||||
|
||||
n3.on("input", function(msg) {
|
||||
messages[0] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n4.on("input", function(msg) {
|
||||
messages[1] = msg;
|
||||
completeTest();
|
||||
});
|
||||
n1.receive({payload:null,foo:"baz"});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
});
|
File diff suppressed because it is too large
Load Diff
@@ -1,568 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var ws = require("ws");
|
||||
var should = require("should");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var websocketNode = require("nr-test-utils").require("@node-red/nodes/core/network/22-websocket.js");
|
||||
|
||||
var sockets = [];
|
||||
|
||||
function getWsUrl(path) {
|
||||
return helper.url().replace(/http/, "ws") + path;
|
||||
}
|
||||
|
||||
function createClient(listenerid) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var node = helper.getNode(listenerid);
|
||||
var url = getWsUrl(node.path);
|
||||
var sock = new ws(url);
|
||||
sockets.push(sock);
|
||||
|
||||
sock.on("open", function() {
|
||||
resolve(sock);
|
||||
});
|
||||
|
||||
sock.on("error", function(err) {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function closeAll() {
|
||||
for (var i = 0; i < sockets.length; i++) {
|
||||
sockets[i].close();
|
||||
}
|
||||
sockets = [];
|
||||
}
|
||||
|
||||
function getSocket(listenerid) {
|
||||
var node = helper.getNode(listenerid);
|
||||
return node.server;
|
||||
}
|
||||
|
||||
describe('websocket Node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
closeAll();
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
describe('websocket-listener', function() {
|
||||
it('should load', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket-listener", path: "/ws" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property("path", "/ws");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should be server', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket-listener", path: "/ws" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property('isServer', true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle wholemsg property', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket-listener", path: "/ws2", wholemsg: "true" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property("wholemsg", false);
|
||||
helper.getNode("n2").should.have.property("wholemsg", true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should create socket', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket in", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
done();
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should close socket on delete', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket-listener", path: "/ws" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("close", function(code, msg) {
|
||||
done();
|
||||
});
|
||||
helper.clearFlows();
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive data', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", "hello");
|
||||
done();
|
||||
});
|
||||
sock.send("hello");
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.send('{"text":"hello"}');
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg when data not JSON', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.send('hello');
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", "hello");
|
||||
done();
|
||||
});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg when data not object', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", 123);
|
||||
done();
|
||||
});
|
||||
sock.send(123);
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "helper", wires: [["n3"]] },
|
||||
{ id: "n3", type: "websocket out", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("message", function(msg, flags) {
|
||||
msg.should.equal("hello");
|
||||
done();
|
||||
});
|
||||
helper.getNode("n2").send({
|
||||
payload: "hello"
|
||||
});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send wholemsg', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket out", server: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("message", function(msg, flags) {
|
||||
JSON.parse(msg).should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
helper.getNode("n3").send({
|
||||
text: "hello"
|
||||
});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should do nothing if no payload', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "helper", wires: [["n3"]] },
|
||||
{ id: "n3", type: "websocket out", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
setTimeout(function() {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "file";
|
||||
});
|
||||
logEvents.should.have.length(0);
|
||||
done();
|
||||
},100);
|
||||
helper.getNode("n2").send({topic: "hello"});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should echo', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "websocket out", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("message", function(msg, flags) {
|
||||
msg.should.equal("hello");
|
||||
done();
|
||||
});
|
||||
sock.send("hello");
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should echo wholemsg', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", server: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "websocket out", server: "n1" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
createClient("n1").then(function(sock) {
|
||||
sock.on("message", function(msg, flags) {
|
||||
JSON.parse(msg).should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
sock.send('{"text":"hello"}');
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should broadcast', function(done) {
|
||||
var flow = [
|
||||
{ id: "n1", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket out", server: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
Promise.all([createClient("n1"), createClient("n1")]).then(function(socks) {
|
||||
var promises = [
|
||||
new Promise((resolve,reject) => {
|
||||
socks[0].on("message", function(msg, flags) {
|
||||
try {
|
||||
msg.should.equal("hello");
|
||||
resolve();
|
||||
} catch(err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
}),
|
||||
new Promise((resolve,reject) => {
|
||||
socks[1].on("message", function(msg, flags) {
|
||||
try {
|
||||
msg.should.equal("hello");
|
||||
resolve();
|
||||
} catch(err) {
|
||||
reject(err);
|
||||
}
|
||||
});
|
||||
})
|
||||
];
|
||||
helper.getNode("n3").send({
|
||||
payload: "hello"
|
||||
});
|
||||
return Promise.all(promises).then(() => {done()});
|
||||
}).catch(function(err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('websocket-client', function() {
|
||||
it('should load', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property('path', getWsUrl("/ws"));
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not be server', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property('isServer', false);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle wholemsg property', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") },
|
||||
{ id: "n2", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
helper.getNode("n1").should.have.property("wholemsg", false);
|
||||
helper.getNode("n2").should.have.property("wholemsg", true);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should connect to server', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket-client", path: getWsUrl("/ws") }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
it('should close on delete', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n2", type: "websocket-client", path: getWsUrl("/ws") }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.on('close', function() {
|
||||
done();
|
||||
});
|
||||
helper.getNode("n2").close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive data', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") },
|
||||
{ id: "n2", type: "websocket in", client: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.send('hello');
|
||||
});
|
||||
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", "hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg data ', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", client: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.send('{"text":"hello"}');
|
||||
});
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should receive wholemsg when data not JSON', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket in", client: "n1", wires: [["n3"]] },
|
||||
{ id: "n3", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.send('hello');
|
||||
});
|
||||
helper.getNode("n3").on("input", function(msg) {
|
||||
msg.should.have.property("payload", "hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") },
|
||||
{ id: "n2", type: "websocket out", client: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.on('message', function(msg) {
|
||||
msg.should.equal("hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
getSocket("n1").on("open", function() {
|
||||
helper.getNode("n3").send({
|
||||
payload: "hello"
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send buffer', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws") },
|
||||
{ id: "n2", type: "websocket out", client: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.on('message', function(msg) {
|
||||
Buffer.isBuffer(msg).should.be.true();
|
||||
msg.should.have.length(5);
|
||||
done();
|
||||
});
|
||||
});
|
||||
getSocket("n1").on("open", function() {
|
||||
helper.getNode("n3").send({
|
||||
payload: Buffer.from("hello")
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should send wholemsg', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws" },
|
||||
{ id: "n1", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" },
|
||||
{ id: "n2", type: "websocket out", client: "n1" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('server').on('connection', function(sock) {
|
||||
sock.on('message', function(msg) {
|
||||
JSON.parse(msg).should.have.property("text", "hello");
|
||||
done();
|
||||
});
|
||||
});
|
||||
getSocket("n1").on('open', function(){
|
||||
helper.getNode("n3").send({
|
||||
text: "hello"
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should NOT feedback more than once', function(done) {
|
||||
var flow = [
|
||||
{ id: "server", type: "websocket-listener", path: "/ws", wholemsg: "true" },
|
||||
{ id: "client", type: "websocket-client", path: getWsUrl("/ws"), wholemsg: "true" },
|
||||
{ id: "n1", type: "websocket in", client: "client", wires: [["n2", "output"]] },
|
||||
{ id: "n2", type: "websocket out", server: "server" },
|
||||
{ id: "n3", type: "helper", wires: [["n2"]] },
|
||||
{ id: "output", type: "helper" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
getSocket('client').on('open', function() {
|
||||
helper.getNode("n3").send({
|
||||
payload: "ping"
|
||||
});
|
||||
});
|
||||
var acc = 0;
|
||||
helper.getNode("output").on("input", function(msg) {
|
||||
acc = acc + 1;
|
||||
});
|
||||
setTimeout( function() {
|
||||
acc.should.equal(1);
|
||||
helper.clearFlows();
|
||||
done();
|
||||
}, 250);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('websocket in node', function() {
|
||||
it('should report error if no server config', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket in", mode: "server" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "websocket in";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.toString().should.startWith("websocket.errors.missing-conf");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('websocket out node', function() {
|
||||
it('should report error if no server config', function(done) {
|
||||
var flow = [{ id: "n1", type: "websocket out", mode: "server" }];
|
||||
helper.load(websocketNode, flow, function() {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "websocket out";
|
||||
});
|
||||
//console.log(logEvents);
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.toString().should.startWith("websocket.errors.missing-conf");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,224 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var net = require("net");
|
||||
var should = require("should");
|
||||
var stoppable = require('stoppable');
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
var tcpinNode = require("nr-test-utils").require("@node-red/nodes/core/network/31-tcpin.js");
|
||||
|
||||
|
||||
describe('TCP in Node', function() {
|
||||
var port = 9200;
|
||||
var server = undefined;
|
||||
var server_port = 9300;
|
||||
var reply_data = undefined;
|
||||
|
||||
beforeEach(function(done) {
|
||||
startServer(done);
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload();
|
||||
stopServer(done);
|
||||
});
|
||||
|
||||
function sendArray(sock, array) {
|
||||
if(array.length > 0) {
|
||||
sock.write(array[0], function() {
|
||||
sendArray(sock, array.slice(1));
|
||||
});
|
||||
}
|
||||
else {
|
||||
sock.end();
|
||||
}
|
||||
}
|
||||
|
||||
function startServer(done) {
|
||||
server_port += 1;
|
||||
server = stoppable(net.createServer(function(c) {
|
||||
sendArray(c, reply_data);
|
||||
})).listen(server_port, "localhost", function(err) {
|
||||
done(err);
|
||||
});
|
||||
}
|
||||
|
||||
function stopServer(done) {
|
||||
server.stop(done);
|
||||
}
|
||||
|
||||
function send(wdata) {
|
||||
var opt = {port:port, host:"localhost"};
|
||||
var client = net.createConnection(opt, function() {
|
||||
client.write(wdata[0], function() {
|
||||
client.end();
|
||||
if(wdata.length > 1) {
|
||||
send(wdata.slice(1));
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function eql(v0, v1) {
|
||||
return((v0 === v1) || ((typeof v0) === 'object' && v0.equals(v1)));
|
||||
}
|
||||
|
||||
function testTCP(flow, wdata, rdata, is_server, done) {
|
||||
if(is_server) {
|
||||
reply_data = wdata;
|
||||
}
|
||||
helper.load(tcpinNode, flow, function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
var rcount = 0;
|
||||
n2.on("input", function(msg) {
|
||||
if(eql(msg.payload, rdata[rcount])) {
|
||||
rcount++;
|
||||
}
|
||||
else {
|
||||
should.fail();
|
||||
}
|
||||
if(rcount === rdata.length) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
if(!is_server) {
|
||||
send(wdata);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testTCP0(flow, wdata, rdata, done) {
|
||||
testTCP(flow, wdata, rdata, false, done);
|
||||
}
|
||||
|
||||
function testTCP1(flow, wdata, rdata, done) {
|
||||
testTCP(flow, wdata, rdata, true, done);
|
||||
}
|
||||
|
||||
it('should recv data (Stream/Buffer)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"stream", datatype:"buffer", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo"], [Buffer("foo")], done);
|
||||
});
|
||||
|
||||
it('should recv data (Stream/String/Delimiter:\\n)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"stream", datatype:"utf8", newline:"\n", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo\nbar"], ["foo", "bar"], done);
|
||||
});
|
||||
|
||||
it('should recv data (Stream/String/No delimiter)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"stream", datatype:"utf8", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo\nbar"], ["foo\nbar"], done);
|
||||
});
|
||||
|
||||
it('should recv data (Stream/Base64)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"stream", datatype:"base64", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo"], [Buffer("foo").toString('base64')], done);
|
||||
});
|
||||
|
||||
it('should recv data (Single/Buffer)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"single", datatype:"buffer", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo"], [Buffer("foo")], done);
|
||||
});
|
||||
|
||||
it('should recv data (Single/String)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"single", datatype:"utf8", newline:"\n", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo\nbar\nbaz"], ["foo\nbar\nbaz"], done);
|
||||
});
|
||||
|
||||
it('should recv data (Stream/Base64)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"single", datatype:"base64", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo"], [Buffer("foo").toString('base64')], done);
|
||||
});
|
||||
|
||||
it('should recv multiple data (Stream/Buffer)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"stream", datatype:"buffer", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo", "bar"], [Buffer("foo"), Buffer("bar")], done);
|
||||
});
|
||||
|
||||
it('should recv multiple data (Stream/String/Delimiter:\\n)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"stream", datatype:"utf8", newline:"\n", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo", "bar\nbaz"], ["foo", "bar", "baz"], done);
|
||||
});
|
||||
|
||||
it('should recv multiple data (Stream/String/No delimiter)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"stream", datatype:"utf8", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP0(flow, ["foo", "bar\nbaz"], ["foo", "bar\nbaz"], done);
|
||||
});
|
||||
|
||||
it('should recv multiple data (Stream/Base64)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"server", host:"localhost", port:port, datamode:"stream", datatype:"base64", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
var wdata = ["foo", "bar"];
|
||||
var rdata = wdata.map(function(x) {
|
||||
return Buffer(x).toString('base64');
|
||||
});
|
||||
testTCP0(flow, wdata, rdata, done);
|
||||
});
|
||||
|
||||
it('should connect & recv data (Stream/Buffer)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"client", host:"localhost", port:server_port, datamode:"stream", datatype:"buffer", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP1(flow, ["foo"], [Buffer("foo")], done);
|
||||
});
|
||||
|
||||
it('should connect & recv data (Stream/String/Delimiter:\\n)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"client", host:"localhost", port:server_port, datamode:"stream", datatype:"utf8", newline:"\n", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP1(flow, ["foo\nbar"], ["foo", "bar"], done);
|
||||
});
|
||||
|
||||
it('should connect & recv data (Stream/String/No delimiter)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"client", host:"localhost", port:server_port, datamode:"stream", datatype:"utf8", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP1(flow, ["foo\nbar"], ["foo\nbar"], done);
|
||||
});
|
||||
|
||||
it('should connect & recv data (Stream/Base64)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"client", host:"localhost", port:server_port, datamode:"stream", datatype:"base64", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP1(flow, ["foo"], [Buffer("foo").toString('base64')], done);
|
||||
});
|
||||
|
||||
it('should connect & recv data (Single/Buffer)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"client", host:"localhost", port:server_port, datamode:"single", datatype:"buffer", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP1(flow, ["foo"], [Buffer("foo")], done);
|
||||
});
|
||||
|
||||
it('should connect & recv data (Single/String)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"client", host:"localhost", port:server_port, datamode:"single", datatype:"utf8", newline:"\n", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP1(flow, ["foo\nbar\nbaz"], ["foo\nbar\nbaz"], done);
|
||||
});
|
||||
|
||||
it('should connect & recv data (Stream/Base64)', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp in", server:"client", host:"localhost", port:server_port, datamode:"single", datatype:"base64", newline:"", topic:"", base64:false, wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP1(flow, ["foo"], [Buffer("foo").toString('base64')], done);
|
||||
});
|
||||
|
||||
});
|
@@ -1,301 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var net = require("net");
|
||||
var should = require("should");
|
||||
var stoppable = require('stoppable');
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var tcpinNode = require("nr-test-utils").require("@node-red/nodes/core/network/31-tcpin.js");
|
||||
var RED = require("nr-test-utils").require("node-red/lib/red.js");
|
||||
|
||||
|
||||
describe('TCP Request Node', function() {
|
||||
var server = undefined;
|
||||
var port = 9000;
|
||||
|
||||
function startServer(done) {
|
||||
port += 1;
|
||||
server = stoppable(net.createServer(function(c) {
|
||||
c.on('data', function(data) {
|
||||
var rdata = "ACK:"+data.toString();
|
||||
c.write(rdata);
|
||||
});
|
||||
c.on('error', function(err) {
|
||||
startServer(done);
|
||||
});
|
||||
})).listen(port, "127.0.0.1", function(err) {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
before(function(done) {
|
||||
startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
server.stop(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
function testTCP(flow, val0, val1, done) {
|
||||
helper.load(tcpinNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
if (typeof val1 === 'object') {
|
||||
msg.should.have.properties(Object.assign({}, val1, {payload: Buffer.from(val1.payload)}));
|
||||
} else {
|
||||
msg.should.have.property('payload', Buffer.from(val1));
|
||||
}
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
if((typeof val0) === 'object') {
|
||||
n1.receive(val0);
|
||||
} else {
|
||||
n1.receive({payload:val0});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function testTCPMany(flow, values, result, done) {
|
||||
helper.load(tcpinNode, flow, () => {
|
||||
const n1 = helper.getNode("n1");
|
||||
const n2 = helper.getNode("n2");
|
||||
n2.on("input", msg => {
|
||||
try {
|
||||
if (typeof result === 'object') {
|
||||
msg.should.have.properties(Object.assign({}, result, {payload: Buffer.from(result.payload)}));
|
||||
} else {
|
||||
msg.should.have.property('payload', Buffer.from(result));
|
||||
}
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
values.forEach(value => {
|
||||
n1.receive(typeof value === 'object' ? value : {payload: value});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
describe('single message', function () {
|
||||
it('should send & recv data', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should retain complete message', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data when specified character received', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"char", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo0bar0',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo0',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data after fixed number of chars received', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"count", splitc: "7", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo bar',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & receive, then keep connection', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: 'foo',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data to/from server:port from msg', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCP(flow, {
|
||||
payload: "foo",
|
||||
host: "localhost",
|
||||
port: port
|
||||
}, {
|
||||
payload: "ACK:foo",
|
||||
host: 'localhost',
|
||||
port: port
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('many messages', function () {
|
||||
it('should send & recv data', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: 'f',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'o',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'o',
|
||||
topic: 'bar'
|
||||
}], {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data when specified character received', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"char", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "foo0",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "bar0",
|
||||
topic: 'bar'
|
||||
}], {
|
||||
payload: "ACK:foo0",
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data after fixed number of chars received', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"count", splitc: "7", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "fo",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "ob",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "ar",
|
||||
topic: 'bar'
|
||||
}], {
|
||||
payload: "ACK:foo",
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & receive, then keep connection', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "foo",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "bar",
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: "baz",
|
||||
topic: 'bar'
|
||||
}], {
|
||||
payload: "ACK:foobarbaz",
|
||||
topic: 'bar'
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should send & recv data to/from server:port from msg', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: "f",
|
||||
host: "localhost",
|
||||
port: port
|
||||
},
|
||||
{
|
||||
payload: "o",
|
||||
host: "localhost",
|
||||
port: port
|
||||
},
|
||||
{
|
||||
payload: "o",
|
||||
host: "localhost",
|
||||
port: port
|
||||
}
|
||||
], {
|
||||
payload: "ACK:foo",
|
||||
host: 'localhost',
|
||||
port: port
|
||||
}, done);
|
||||
});
|
||||
|
||||
it('should limit the queue size', function (done) {
|
||||
RED.settings.tcpMsgQueueSize = 10;
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
// create one more msg than is allowed
|
||||
const msgs = new Array(RED.settings.tcpMsgQueueSize + 1).fill('x');
|
||||
const expected = msgs.slice(0, -1);
|
||||
testTCPMany(flow, msgs, "ACK:" + expected.join(''), done);
|
||||
});
|
||||
|
||||
it('should only retain the latest message', function(done) {
|
||||
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
testTCPMany(flow, [{
|
||||
payload: 'f',
|
||||
topic: 'bar'
|
||||
}, {
|
||||
payload: 'o',
|
||||
topic: 'baz'
|
||||
}, {
|
||||
payload: 'o',
|
||||
topic: 'quux'
|
||||
}], {
|
||||
payload: 'ACK:foo',
|
||||
topic: 'quux'
|
||||
}, done);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,94 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var dgram = require("dgram");
|
||||
var should = require("should");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var udpNode = require("nr-test-utils").require("@node-red/nodes/core/network/32-udp.js");
|
||||
|
||||
|
||||
describe('UDP in Node', function() {
|
||||
var port = 9100;
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
function sendIPv4(msg) {
|
||||
var sock = dgram.createSocket('udp4');
|
||||
sock.send(msg, 0, msg.length, port, "127.0.0.1", function(msg) {
|
||||
sock.close();
|
||||
});
|
||||
}
|
||||
|
||||
function checkRecv(dt, proto, val0, val1, done) {
|
||||
var flow = [{id:"n1", type:"udp in",
|
||||
group: "", multicast:false,
|
||||
port:port, ipv:proto,
|
||||
datatype: dt, iface: "",
|
||||
wires:[["n2"]] },
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(udpNode, flow, function() {
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
var ip = ((proto === 'udp6') ? '::ffff:':'') +'127.0.0.1';
|
||||
msg.should.have.property('ip', ip);
|
||||
msg.should.have.property('port');
|
||||
msg.should.have.property('payload');
|
||||
msg.payload.should.deepEqual(val1);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
sendIPv4(val0);
|
||||
});
|
||||
}
|
||||
|
||||
it('should recv IPv4 data (Buffer)', function(done) {
|
||||
checkRecv('buffer', 'udp4', 'hello', Buffer('hello'), done);
|
||||
});
|
||||
|
||||
it('should recv IPv4 data (String)', function(done) {
|
||||
checkRecv('utf8', 'udp4', 'hello', 'hello', done);
|
||||
});
|
||||
|
||||
it('should recv IPv4 data (base64)', function(done) {
|
||||
checkRecv('base64', 'udp4', 'hello', Buffer('hello').toString('base64'), done);
|
||||
});
|
||||
|
||||
it('should recv IPv6 data (Buffer)', function(done) {
|
||||
checkRecv('buffer', 'udp6', 'hello', Buffer('hello'), done);
|
||||
});
|
||||
|
||||
it('should recv IPv6 data (String)', function(done) {
|
||||
checkRecv('utf8', 'udp6', 'hello', 'hello', done);
|
||||
});
|
||||
|
||||
it('should recv IPv6 data (base64)', function(done) {
|
||||
checkRecv('base64', 'udp6', 'hello', Buffer('hello').toString('base64'), done);
|
||||
});
|
||||
|
||||
});
|
@@ -1,88 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var dgram = require("dgram");
|
||||
var should = require("should");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var udpNode = require("nr-test-utils").require("@node-red/nodes/core/network/32-udp.js");
|
||||
|
||||
|
||||
describe('UDP out Node', function() {
|
||||
var port = 9200;
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
function recvData(data, done) {
|
||||
var sock = dgram.createSocket('udp4');
|
||||
sock.on('message', function(msg, rinfo) {
|
||||
sock.close(done);
|
||||
msg.should.deepEqual(data);
|
||||
});
|
||||
sock.bind(port, '127.0.0.1');
|
||||
port++;
|
||||
}
|
||||
|
||||
function checkSend(proto, val0, val1, decode, dest_in_msg, done) {
|
||||
var dst_ip = dest_in_msg ? undefined : "127.0.0.1";
|
||||
var dst_port = dest_in_msg ? undefined : port;
|
||||
var flow = [{id:"n1", type:"udp out",
|
||||
addr:dst_ip, port:dst_port, iface: "",
|
||||
ipv:proto, outport: "",
|
||||
base64:decode, multicast:false,
|
||||
wires:[] }];
|
||||
helper.load(udpNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var msg = {};
|
||||
if (decode) {
|
||||
msg.payload = Buffer.from("hello").toString('base64');
|
||||
}
|
||||
else {
|
||||
msg.payload = "hello";
|
||||
}
|
||||
if (dest_in_msg) {
|
||||
msg.ip = "127.0.0.1";
|
||||
msg.port = port;
|
||||
}
|
||||
recvData(val1, done);
|
||||
setTimeout(function() {
|
||||
n1.receive(msg);
|
||||
}, 200);
|
||||
});
|
||||
}
|
||||
|
||||
it('should send IPv4 data', function(done) {
|
||||
checkSend('udp4', 'hello', Buffer.from('hello'), false, false, done);
|
||||
});
|
||||
|
||||
it('should send IPv4 data (base64)', function(done) {
|
||||
checkSend('udp4', 'hello', Buffer.from('hello'), true, false, done);
|
||||
});
|
||||
|
||||
it('should send IPv4 data with dest from msg', function(done) {
|
||||
checkSend('udp4', 'hello', Buffer.from('hello'), false, true, done);
|
||||
});
|
||||
|
||||
});
|
File diff suppressed because it is too large
Load Diff
@@ -1,494 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var path = require("path");
|
||||
var fs = require('fs-extra');
|
||||
|
||||
var htmlNode = require("nr-test-utils").require("@node-red/nodes/core/parsers/70-HTML.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('HTML node', function() {
|
||||
|
||||
var resourcesDir = __dirname+ path.sep + ".." + path.sep + ".." + path.sep + ".." + path.sep + "resources" + path.sep;
|
||||
var file = path.join(resourcesDir, "70-HTML-test-file.html");
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
beforeEach(function() {
|
||||
fs.existsSync(file).should.be.true();
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"htmlNode1", type:"html", name: "htmlNode" }];
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var htmlNode1 = helper.getNode("htmlNode1");
|
||||
htmlNode1.should.have.property('name', 'htmlNode');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve header contents if asked to by msg.select', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
should.equal(msg.payload, 'This is a test page for node 70-HTML');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
// include 'body' in the select to verify we're in document mode
|
||||
// for the parser. See https://github.com/node-red/node-red/issues/3079
|
||||
n1.receive({payload:data,topic:"bar",select:"body h1"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve header contents if asked to by msg.select - alternative in property', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",property:"foo",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.foo[0].should.equal('This is a test page for node 70-HTML');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({foo:data,topic:"bar",select:"h1"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve header contents if asked to by msg.select - alternative in and out properties', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",property:"foo",outproperty:"bar",tag:"h1",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.bar[0].should.equal('This is a test page for node 70-HTML');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({foo:data,topic:"bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should emit an empty array if no matching elements', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('payload');
|
||||
msg.payload.should.be.empty;
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:data,topic:"bar",select:"h4"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve paragraph contents when specified', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],ret:"text",tag:"p"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
should.equal(msg.payload, 'There\'s nothing to read here.');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:data,topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve list contents as an array of html as default', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"ol"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload[0].indexOf("<li>Blue</li>").should.be.above(-1);
|
||||
msg.payload[0].indexOf("<li>Red</li>").should.be.above(-1);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:data,topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve list contents as an array of text', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"ol",ret:"text"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload[0].indexOf("Blue").should.be.above(-1);
|
||||
msg.payload[0].indexOf("Red").should.be.above(-1);
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:data,topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should fix up a unclosed tag', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"span"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
should.equal(msg.payload, '<img src="foo.png"/>');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:data,topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve an attribute from a tag', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],ret:"attr",tag:"span img"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload');
|
||||
msg.payload[0].should.have.property('src','foo.png');
|
||||
msg.should.have.property('topic', 'bar');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:data,topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should log on error', function(done) {
|
||||
fs.readFile(file,function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"p"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
try {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.receive({payload:null,topic: "bar"});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
helper.log().called.should.be.true();
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "html";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
// Each logEvent is the array of args passed to the function.
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass through if payload empty', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.not.have.property('payload');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('multiple messages', function(){
|
||||
var cnt = 0;
|
||||
var parts_id = undefined;
|
||||
|
||||
afterEach(function() {
|
||||
cnt.should.be.exactly(2);
|
||||
cnt = 0;
|
||||
parts_id = undefined;
|
||||
});
|
||||
|
||||
function check_parts(msg, index, count) {
|
||||
msg.should.have.property('parts');
|
||||
msg.parts.should.have.property('id');
|
||||
if(parts_id === undefined) {
|
||||
parts_id = msg.parts.id;
|
||||
}
|
||||
else {
|
||||
msg.parts.should.have.property('id', parts_id);
|
||||
}
|
||||
msg.parts.should.have.property('index', index);
|
||||
msg.parts.should.have.property('count', count);
|
||||
msg.parts.should.have.property('type', 'string');
|
||||
msg.parts.should.have.property('ch', '');
|
||||
}
|
||||
|
||||
it('should retrieve list contents as html as default with output as multiple msgs', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"ul",as:"multi"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
cnt++;
|
||||
msg.should.have.property('topic', 'bar');
|
||||
check_parts(msg, cnt -1, 2);
|
||||
if (cnt !== 1 && cnt !== 2) {
|
||||
return false;
|
||||
}
|
||||
if (cnt === 1) {
|
||||
msg.payload.indexOf("<li>Apple</li>").should.be.above(-1);
|
||||
msg.payload.indexOf("<li>Pear</li>").should.be.above(-1);
|
||||
} else if (cnt === 2) {
|
||||
msg.payload.indexOf("<li>Potato</li>").should.be.above(-1);
|
||||
msg.payload.indexOf("<li>Parsnip</li>").should.be.above(-1);
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
|
||||
});
|
||||
n1.receive({payload:data,topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it('should retrieve list contents as html as default with output as multiple msgs - alternative property', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",property:"foo",wires:[["n2"]],tag:"ul",as:"multi"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
cnt++;
|
||||
msg.should.have.property('topic', 'bar');
|
||||
check_parts(msg, cnt -1, 2);
|
||||
if (cnt !== 1 && cnt !== 2) {
|
||||
return false;
|
||||
}
|
||||
if (cnt === 1) {
|
||||
msg.foo.indexOf("<li>Apple</li>").should.be.above(-1);
|
||||
msg.foo.indexOf("<li>Pear</li>").should.be.above(-1);
|
||||
} else if (cnt === 2) {
|
||||
msg.foo.indexOf("<li>Potato</li>").should.be.above(-1);
|
||||
msg.foo.indexOf("<li>Parsnip</li>").should.be.above(-1);
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({foo:data, topic:"bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve list contents as text with output as multiple msgs ', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"ul",ret:"text",as:"multi"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
cnt++;
|
||||
msg.should.have.property('topic', 'bar');
|
||||
check_parts(msg, cnt -1, 2);
|
||||
if (cnt !== 1 && cnt !== 2) {
|
||||
return false;
|
||||
}
|
||||
if (cnt === 1) {
|
||||
msg.payload.indexOf("Apple").should.be.above(-1);
|
||||
msg.payload.indexOf("Pear").should.be.above(-1);
|
||||
} else if (cnt === 2) {
|
||||
msg.payload.indexOf("Potato").should.be.above(-1);
|
||||
msg.payload.indexOf("Parsnip").should.be.above(-1);
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:data,topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should retrieve an attribute from a tag', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],ret:"attr",tag:"span img",as:"multi"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('payload');
|
||||
msg.payload.should.have.property('src','foo.png');
|
||||
msg.should.have.property('topic', 'bar');
|
||||
check_parts(msg, 0, 1);
|
||||
cnt = 2; // frig the answer as only one img tag
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:data,topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should not reuse message', function(done) {
|
||||
fs.readFile(file, 'utf8', function(err, data) {
|
||||
var flow = [{id:"n1",type:"html",wires:[["n2"]],tag:"ul",ret:"text",as:"multi"},
|
||||
{id:"n2", type:"helper"}];
|
||||
|
||||
helper.load(htmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var prev_msg = undefined;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
cnt++;
|
||||
if (prev_msg == undefined) {
|
||||
prev_msg = msg;
|
||||
}
|
||||
else {
|
||||
msg.should.not.equal(prev_msg);
|
||||
}
|
||||
if (cnt == 2) {
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err)
|
||||
}
|
||||
});
|
||||
n1.receive({payload:data,topic: "bar"});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
@@ -1,546 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var jsonNode = require("nr-test-utils").require("@node-red/nodes/core/parsers/70-JSON.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('JSON node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should convert a valid json string to a javascript object', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload.should.have.property('employees');
|
||||
msg.payload.employees[0].should.have.property('firstName', 'John');
|
||||
msg.payload.employees[0].should.have.property('lastName', 'Smith');
|
||||
done();
|
||||
});
|
||||
var jsonString = '{"employees":[{"firstName":"John", "lastName":"Smith"}]}';
|
||||
jn1.receive({payload:jsonString,topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a javascript object to a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '{"employees":[{"firstName":"John","lastName":"Smith"}]}');
|
||||
done();
|
||||
});
|
||||
var obj = {employees:[{firstName:"John", lastName:"Smith"}]};
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a array to a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '[1,2,3]');
|
||||
done();
|
||||
});
|
||||
var obj = [1,2,3];
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a boolean to a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, 'true');
|
||||
done();
|
||||
});
|
||||
var obj = true;
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a json string to a boolean', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, true);
|
||||
done();
|
||||
});
|
||||
var obj = "true";
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a number to a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '2019');
|
||||
done();
|
||||
});
|
||||
var obj = 2019;
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a json string to a number', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, 1962);
|
||||
done();
|
||||
});
|
||||
var obj = '1962';
|
||||
jn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if asked to parse an invalid json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn1.receive({payload:'foo',topic: "bar"});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
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].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},20);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if asked to parse something thats not json or js', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.toString().should.eql('json.errors.dropped-object');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
},50);
|
||||
jn1.receive({payload:Buffer.from("a")});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass straight through if no payload set', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.not.have.property('payload');
|
||||
done();
|
||||
});
|
||||
jn1.receive({topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should ensure the result is a json string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var count = 0;
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
should.equal(msg.payload, '{"employees":[{"firstName":"John","lastName":"Smith"}]}');
|
||||
count++;
|
||||
if (count === 2) {
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var obj = {employees:[{firstName:"John", lastName:"Smith"}]};
|
||||
jn1.receive({payload:obj,topic: "bar"});
|
||||
jn1.receive({payload:JSON.stringify(obj),topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should ensure the result is a JS Object', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var count = 0;
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload.should.have.property('employees');
|
||||
msg.payload.employees[0].should.have.property('firstName', 'John');
|
||||
msg.payload.employees[0].should.have.property('lastName', 'Smith');
|
||||
count++;
|
||||
if (count === 2) {
|
||||
done();
|
||||
}
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var obj = {employees:[{firstName:"John", lastName:"Smith"}]};
|
||||
jn1.receive({payload:obj,topic: "bar"});
|
||||
jn1.receive({payload:JSON.stringify(obj),topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle any msg property - receive existing string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",property:"one.two",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.have.property('one');
|
||||
msg.one.should.have.property('two');
|
||||
msg.one.two.should.have.property('employees');
|
||||
msg.one.two.employees[0].should.have.property('firstName', 'John');
|
||||
msg.one.two.employees[0].should.have.property('lastName', 'Smith');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var jsonString = '{"employees":[{"firstName":"John", "lastName":"Smith"}]}';
|
||||
jn1.receive({payload:"",one:{two:jsonString},topic: "bar"});
|
||||
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle any msg property - receive existing obj', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",property:"one.two",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
try {
|
||||
should.equal(msg.one.two, '{"employees":[{"firstName":"John","lastName":"Smith"}]}');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
var jsonString = '{"employees":[{"firstName":"John", "lastName":"Smith"}]}';
|
||||
jn1.receive({payload:"",one:{two:JSON.parse(jsonString)},topic: "bar"});
|
||||
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass an object if provided a valid JSON string and schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload.number, 3);
|
||||
should.equal(msg.payload.string, "allo");
|
||||
done();
|
||||
});
|
||||
var jsonString = '{"number": 3, "string": "allo"}';
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass an object if provided a valid object and schema and action is object', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload.number, 3);
|
||||
should.equal(msg.payload.string, "allo");
|
||||
done();
|
||||
});
|
||||
var obj = {"number": 3, "string": "allo"};
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass a string if provided a valid object and schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '{"number":3,"string":"allo"}');
|
||||
done();
|
||||
});
|
||||
var obj = {"number": 3, "string": "allo"};
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass a string if provided a valid JSON string and schema and action is string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, '{"number":3,"string":"allo"}');
|
||||
done();
|
||||
});
|
||||
var jsonString = '{"number":3,"string":"allo"}';
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed an invalid object and valid schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
var obj = {"number": "foo", "string": 3};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("json.errors.schema-error");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed an invalid object and valid schema and action is object', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"obj",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
var obj = {"number": "foo", "string": 3};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("json.errors.schema-error");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed an invalid JSON string and valid schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
var jsonString = '{"number":"Hello","string":3}';
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("json.errors.schema-error");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed an invalid JSON string and valid schema and action is string', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
var jsonString = '{"number":"Hello","string":3}';
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("json.errors.schema-error");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if passed a valid object and invalid schema', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
try {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
var schema = "garbage";
|
||||
var obj = {"number": "foo", "string": 3};
|
||||
jn1.receive({payload:obj, schema:schema});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "json";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.equal("json.errors.schema-error-compile");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('msg.schema property should be deleted before sending to next node (string input)', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.schema, undefined);
|
||||
done();
|
||||
});
|
||||
var jsonString = '{"number":3,"string":"allo"}';
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:jsonString, schema:schema});
|
||||
});
|
||||
});
|
||||
|
||||
it('msg.schema property should be deleted before sending to next node (object input)', function(done) {
|
||||
var flow = [{id:"jn1",type:"json",action:"str",wires:[["jn2"]]},
|
||||
{id:"jn2", type:"helper"}];
|
||||
helper.load(jsonNode, flow, function() {
|
||||
var jn1 = helper.getNode("jn1");
|
||||
var jn2 = helper.getNode("jn2");
|
||||
jn2.on("input", function(msg) {
|
||||
should.equal(msg.schema, undefined);
|
||||
done();
|
||||
});
|
||||
var jsonObject = {"number":3,"string":"allo"};
|
||||
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
|
||||
jn1.receive({payload:jsonObject, schema:schema});
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,198 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var xmlNode = require("nr-test-utils").require("@node-red/nodes/core/parsers/70-XML.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('XML node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"xmlNode1", type:"xml", name: "xmlNode" }];
|
||||
helper.load(xmlNode, flow, function() {
|
||||
var xmlNode1 = helper.getNode("xmlNode1");
|
||||
xmlNode1.should.have.property('name', 'xmlNode');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a valid xml string to a javascript object', function(done) {
|
||||
var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(xmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload.should.have.property('employees');
|
||||
msg.payload.employees.should.have.property('firstName');
|
||||
should.equal(msg.payload.employees.firstName[0], 'John');
|
||||
msg.payload.employees.should.have.property('lastName');
|
||||
should.equal(msg.payload.employees.lastName[0], 'Smith');
|
||||
done();
|
||||
});
|
||||
var string = '<employees><firstName>John</firstName><lastName>Smith</lastName></employees>';
|
||||
n1.receive({payload:string,topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a valid xml string to a javascript object - alternative property', function(done) {
|
||||
var flow = [{id:"n1",type:"xml",property:"foo",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(xmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.foo.should.have.property('employees');
|
||||
msg.foo.employees.should.have.property('firstName');
|
||||
should.equal(msg.foo.employees.firstName[0], 'John');
|
||||
msg.foo.employees.should.have.property('lastName');
|
||||
should.equal(msg.foo.employees.lastName[0], 'Smith');
|
||||
done();
|
||||
});
|
||||
var string = '<employees><firstName>John</firstName><lastName>Smith</lastName></employees>';
|
||||
n1.receive({foo:string,topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a valid xml string to a javascript object with options', function(done) {
|
||||
var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(xmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload.should.have.property('employees');
|
||||
msg.payload.employees.should.have.property('firstName');
|
||||
should.equal(msg.payload.employees.firstName[0], 'John');
|
||||
msg.payload.employees.should.have.property('lastName');
|
||||
should.equal(msg.payload.employees.lastName[0], 'Smith');
|
||||
done();
|
||||
});
|
||||
var string = '<employees><firstName>John</firstName><lastName>Smith</lastName></employees>';
|
||||
n1.receive({payload:string, topic:"bar", options:{trim:true}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a javascript object to an xml string', function(done) {
|
||||
var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(xmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
var index = msg.payload.indexOf('<employees><firstName>John</firstName><lastName>Smith</lastName></employees>');
|
||||
index.should.be.above(-1);
|
||||
done();
|
||||
});
|
||||
var obj = {"employees":{"firstName":["John"],"lastName":["Smith"] }};
|
||||
n1.receive({payload:obj,topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a javascript object to an xml string with options - alternative property', function(done) {
|
||||
var flow = [{id:"n1",type:"xml",property:"foo",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(xmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
var index = msg.foo.indexOf('<employees>\n <firstName>John</firstName>\n <lastName>Smith</lastName>\n</employees>');
|
||||
index.should.be.above(-1);
|
||||
done();
|
||||
});
|
||||
var obj = {"employees":{"firstName":["John"],"lastName":["Smith"] }};
|
||||
n1.receive({foo:obj, topic:"bar", options:{headless:true}});
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if asked to parse an invalid xml string', function(done) {
|
||||
var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(xmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.receive({payload:'<not valid>',topic: "bar"});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "xml";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.toString().should.startWith("Error: Attribute without value");
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
},200);
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if asked to parse something thats not xml or js', function(done) {
|
||||
var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(xmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.receive({payload:1,topic: "bar"});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "xml";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg',"xml.errors.xml_js");
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
},200);
|
||||
});
|
||||
});
|
||||
|
||||
it('should just pass through if payload is missing', function(done) {
|
||||
var flow = [{id:"n1",type:"xml",wires:[["n2"]],func:"return msg;"},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(xmlNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.not.have.property('payload');
|
||||
done();
|
||||
});
|
||||
n1.receive({topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -1,195 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var yamlNode = require("nr-test-utils").require("@node-red/nodes/core/parsers/70-YAML.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
describe('YAML node', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"yamlNode1", type:"yaml", name: "yamlNode" }];
|
||||
helper.load(yamlNode, flow, function() {
|
||||
var yamlNode1 = helper.getNode("yamlNode1");
|
||||
yamlNode1.should.have.property('name', 'yamlNode');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a valid yaml string to a javascript object', function(done) {
|
||||
var flow = [{id:"yn1",type:"yaml",wires:[["yn2"]],func:"return msg;"},
|
||||
{id:"yn2", type:"helper"}];
|
||||
helper.load(yamlNode, flow, function() {
|
||||
var yn1 = helper.getNode("yn1");
|
||||
var yn2 = helper.getNode("yn2");
|
||||
yn2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.payload.should.have.property('employees');
|
||||
msg.payload.employees[0].should.have.property('firstName', 'John');
|
||||
msg.payload.employees[0].should.have.property('lastName', 'Smith');
|
||||
done();
|
||||
});
|
||||
var yamlString = "employees:\n - firstName: John\n lastName: Smith\n";
|
||||
yn1.receive({payload:yamlString,topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a valid yaml string to a javascript object - using another property', function(done) {
|
||||
var flow = [{id:"yn1",type:"yaml",property:"foo",wires:[["yn2"]],func:"return msg;"},
|
||||
{id:"yn2", type:"helper"}];
|
||||
helper.load(yamlNode, flow, function() {
|
||||
var yn1 = helper.getNode("yn1");
|
||||
var yn2 = helper.getNode("yn2");
|
||||
yn2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.foo.should.have.property('employees');
|
||||
msg.foo.employees[0].should.have.property('firstName', 'John');
|
||||
msg.foo.employees[0].should.have.property('lastName', 'Smith');
|
||||
done();
|
||||
});
|
||||
var yamlString = "employees:\n - firstName: John\n lastName: Smith\n";
|
||||
yn1.receive({foo:yamlString,topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a javascript object to a yaml string', function(done) {
|
||||
var flow = [{id:"yn1",type:"yaml",wires:[["yn2"]],func:"return msg;"},
|
||||
{id:"yn2", type:"helper"}];
|
||||
helper.load(yamlNode, flow, function() {
|
||||
var yn1 = helper.getNode("yn1");
|
||||
var yn2 = helper.getNode("yn2");
|
||||
yn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, "employees:\n - firstName: John\n lastName: Smith\n");
|
||||
done();
|
||||
});
|
||||
var obj = {employees:[{firstName:"John", lastName:"Smith"}]};
|
||||
yn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert a javascript object to a yaml string - using another property', function(done) {
|
||||
var flow = [{id:"yn1",type:"yaml",property:"foo",wires:[["yn2"]],func:"return msg;"},
|
||||
{id:"yn2", type:"helper"}];
|
||||
helper.load(yamlNode, flow, function() {
|
||||
var yn1 = helper.getNode("yn1");
|
||||
var yn2 = helper.getNode("yn2");
|
||||
yn2.on("input", function(msg) {
|
||||
should.equal(msg.foo, "employees:\n - firstName: John\n lastName: Smith\n");
|
||||
done();
|
||||
});
|
||||
var obj = {employees:[{firstName:"John", lastName:"Smith"}]};
|
||||
yn1.receive({foo:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should convert an array to a yaml string', function(done) {
|
||||
var flow = [{id:"yn1",type:"yaml",wires:[["yn2"]],func:"return msg;"},
|
||||
{id:"yn2", type:"helper"}];
|
||||
helper.load(yamlNode, flow, function() {
|
||||
var yn1 = helper.getNode("yn1");
|
||||
var yn2 = helper.getNode("yn2");
|
||||
yn2.on("input", function(msg) {
|
||||
should.equal(msg.payload, "- 1\n- 2\n- 3\n");
|
||||
done();
|
||||
});
|
||||
var obj = [1,2,3];
|
||||
yn1.receive({payload:obj});
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if asked to parse an invalid yaml string', function(done) {
|
||||
var flow = [{id:"yn1",type:"yaml",wires:[["yn2"]],func:"return msg;"},
|
||||
{id:"yn2", type:"helper"}];
|
||||
helper.load(yamlNode, flow, function() {
|
||||
try {
|
||||
var yn1 = helper.getNode("yn1");
|
||||
var yn2 = helper.getNode("yn2");
|
||||
yn1.receive({payload:'employees:\n-firstName: John\n- lastName: Smith\n',topic: "bar"});
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "yaml";
|
||||
});
|
||||
logEvents.should.have.length(1);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.should.startWith("end of the stream");
|
||||
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
|
||||
done();
|
||||
} catch(err) { done(err) }
|
||||
},50);
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should log an error if asked to parse something thats not yaml or js', function(done) {
|
||||
var flow = [{id:"yn1",type:"yaml",wires:[["yn2"]],func:"return msg;"},
|
||||
{id:"yn2", type:"helper"}];
|
||||
helper.load(yamlNode, flow, function() {
|
||||
var yn1 = helper.getNode("yn1");
|
||||
var yn2 = helper.getNode("yn2");
|
||||
setTimeout(function() {
|
||||
try {
|
||||
var logEvents = helper.log().args.filter(function(evt) {
|
||||
return evt[0].type == "yaml";
|
||||
});
|
||||
logEvents.should.have.length(3);
|
||||
logEvents[0][0].should.have.a.property('msg');
|
||||
logEvents[0][0].msg.toString().should.eql('yaml.errors.dropped');
|
||||
logEvents[1][0].should.have.a.property('msg');
|
||||
logEvents[1][0].msg.toString().should.eql('yaml.errors.dropped');
|
||||
logEvents[2][0].should.have.a.property('msg');
|
||||
logEvents[2][0].msg.toString().should.eql('yaml.errors.dropped-object');
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
},150);
|
||||
yn1.receive({payload:true});
|
||||
yn1.receive({payload:1});
|
||||
yn1.receive({payload:Buffer.from("a")});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass straight through if no payload set', function(done) {
|
||||
var flow = [{id:"yn1",type:"yaml",wires:[["yn2"]],func:"return msg;"},
|
||||
{id:"yn2", type:"helper"}];
|
||||
helper.load(yamlNode, flow, function() {
|
||||
var yn1 = helper.getNode("yn1");
|
||||
var yn2 = helper.getNode("yn2");
|
||||
yn2.on("input", function(msg) {
|
||||
msg.should.have.property('topic', 'bar');
|
||||
msg.should.not.have.property('payload');
|
||||
done();
|
||||
});
|
||||
yn1.receive({topic: "bar"});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
File diff suppressed because it is too large
Load Diff
@@ -1,554 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var sortNode = require("nr-test-utils").require("@node-red/nodes/core/sequence/18-sort.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var RED = require("nr-test-utils").require("node-red/lib/red.js");
|
||||
var Context = require("nr-test-utils").require("@node-red/runtime/lib/nodes/context");
|
||||
|
||||
describe('SORT node', function() {
|
||||
|
||||
beforeEach(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
function initContext(done) {
|
||||
Context.init({
|
||||
contextStorage: {
|
||||
memory: {
|
||||
module: "memory"
|
||||
}
|
||||
}
|
||||
});
|
||||
Context.load().then(function () {
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload().then(function(){
|
||||
RED.settings.nodeMessageBufferMaxLength = 0;
|
||||
helper.stopServer(done);
|
||||
});
|
||||
});
|
||||
|
||||
it('should be loaded', function(done) {
|
||||
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:false, name: "SortNode", wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(sortNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('name', 'SortNode');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
function check_sort0(flow, target, key, key_type, data_in, data_out, done) {
|
||||
var sort = flow[0];
|
||||
sort.target = target;
|
||||
sort.targetType = "msg";
|
||||
sort.msgKey = key;
|
||||
sort.msgKeyType = key_type;
|
||||
helper.load(sortNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property(target);
|
||||
var data = msg[target];
|
||||
data.length.should.equal(data_out.length);
|
||||
for(var i = 0; i < data_out.length; i++) {
|
||||
var data0 = data[i];
|
||||
var data1 = data_out[i];
|
||||
if (typeof data0 === "object") {
|
||||
data0.should.deepEqual(data1);
|
||||
}
|
||||
else {
|
||||
data0.should.equal(data1);
|
||||
}
|
||||
}
|
||||
done();
|
||||
}
|
||||
catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
});
|
||||
var msg = {};
|
||||
msg[target] = data_in;
|
||||
n1.receive(msg);
|
||||
});
|
||||
}
|
||||
|
||||
function check_sort0A(flow, data_in, data_out, done) {
|
||||
check_sort0(flow, "payload", "", "elem", data_in, data_out, done);
|
||||
}
|
||||
|
||||
function check_sort0B(flow, data_in, data_out, done) {
|
||||
check_sort0(flow, "data", "", "elem", data_in, data_out, done);
|
||||
}
|
||||
|
||||
function check_sort0C(flow, exp, data_in, data_out, done) {
|
||||
check_sort0(flow, "data", exp, "jsonata", data_in, data_out, done);
|
||||
}
|
||||
|
||||
function check_sort1(flow, key, key_type, data_in, data_out, done) {
|
||||
function equals(v0, v1) {
|
||||
var k0 = Object.keys(v0);
|
||||
var k1 = Object.keys(v1);
|
||||
|
||||
if (k0.length === k1.length) {
|
||||
for (var i = 0; i < k0.length; i++) {
|
||||
var k = k0[i];
|
||||
if (!v1.hasOwnProperty(k) ||
|
||||
(v0[k] !== v1[k])) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
function indexOf(a, v) {
|
||||
for(var i = 0; i < a.length; i++) {
|
||||
var av = a[i];
|
||||
if ((typeof v === 'object') && equals(v, av)) {
|
||||
return i;
|
||||
}
|
||||
else if (v === av) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
var sort = flow[0];
|
||||
var prop = (key_type === "msg") ? key : "payload";
|
||||
sort.targetType = "seq";
|
||||
sort.seqKey = key;
|
||||
sort.seqKeyType = key_type;
|
||||
helper.load(sortNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property(prop);
|
||||
msg.should.have.property("parts");
|
||||
msg.parts.should.have.property("count", data_out.length);
|
||||
var data = msg[prop];
|
||||
var index = indexOf(data_out, data);
|
||||
msg.parts.should.have.property("index", index);
|
||||
count++;
|
||||
if (count === data_out.length) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
var len = data_in.length;
|
||||
for(var i = 0; i < len; i++) {
|
||||
var parts = { id: "X", index: i, count: len };
|
||||
var msg = {parts: parts};
|
||||
msg[prop] = data_in[i];
|
||||
n1.receive(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function check_sort1A(flow, data_in, data_out, done) {
|
||||
check_sort1(flow, "payload", "msg", data_in, data_out, done);
|
||||
}
|
||||
|
||||
function check_sort1B(flow, data_in, data_out, done) {
|
||||
check_sort1(flow, "data", "msg", data_in, data_out, done);
|
||||
}
|
||||
|
||||
function check_sort1C(flow, exp, data_in, data_out, done) {
|
||||
check_sort1(flow, exp, "jsonata", data_in, data_out, done);
|
||||
}
|
||||
|
||||
(function() {
|
||||
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:false, wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var data_in = [ "200", "4", "30", "1000" ];
|
||||
var data_out = [ "1000", "200", "30", "4" ];
|
||||
it('should sort payload (elem, not number, ascending)', function(done) {
|
||||
check_sort0A(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort msg prop (elem, not number, ascending)', function(done) {
|
||||
check_sort0B(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort message group/payload (not number, ascending)', function(done) {
|
||||
check_sort1A(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort message group/prop (not number, ascending)', function(done) {
|
||||
check_sort1B(flow, data_in, data_out, done);
|
||||
});
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var flow = [{id:"n1", type:"sort", order:"descending", as_num:false, wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var data_in = [ "200", "4", "30", "1000" ];
|
||||
var data_out = [ "4", "30", "200", "1000" ];
|
||||
it('should sort payload (elem, not number, descending)', function(done) {
|
||||
check_sort0A(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort msg prop (elem, not number, descending)', function(done) {
|
||||
check_sort0B(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort message group/payload (not number, descending)', function(done) {
|
||||
check_sort1A(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort message group/prop (not number, descending)', function(done) {
|
||||
check_sort1B(flow, data_in, data_out, done);
|
||||
});
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:true, wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var data_in = [ "200", "4", "30", "1000" ];
|
||||
var data_out = [ "4", "30", "200", "1000" ];
|
||||
it('should sort payload (elem, number, ascending)', function(done) {
|
||||
check_sort0A(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort msg prop (elem, number, ascending)', function(done) {
|
||||
check_sort0B(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort message group/payload (number, ascending)', function(done) {
|
||||
check_sort1A(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort message group/prop (number, ascending)', function(done) {
|
||||
check_sort1B(flow, data_in, data_out, done);
|
||||
});
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var flow = [{id:"n1", type:"sort", order:"descending", as_num:true, wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var data_in = [ "200", "4", "30", "1000" ];
|
||||
var data_out = [ "1000", "200", "30", "4" ];
|
||||
it('should sort payload (elem, number, descending)', function(done) {
|
||||
check_sort0A(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort msg prop (elem, number, descending)', function(done) {
|
||||
check_sort0B(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort message group/payload (number, descending)', function(done) {
|
||||
check_sort1A(flow, data_in, data_out, done);
|
||||
});
|
||||
it('should sort message group/prop (number, descending)', function(done) {
|
||||
check_sort1B(flow, data_in, data_out, done);
|
||||
});
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:false, wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var data_in = [ "C200", "A4", "B30", "D1000" ];
|
||||
var data_out = [ "D1000", "C200", "B30", "A4" ];
|
||||
it('should sort payload (exp, not number, ascending)', function(done) {
|
||||
check_sort0C(flow, "$substring($,1)", data_in, data_out, done);
|
||||
});
|
||||
it('should sort message group (exp, not number, ascending)', function(done) {
|
||||
check_sort1C(flow, "$substring(payload,1)", data_in, data_out, done);
|
||||
});
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var flow = [{id:"n1", type:"sort", order:"descending", as_num:false, wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var data_in = [ "C200", "A4", "B30", "D1000" ];
|
||||
var data_out = [ "A4", "B30", "C200", "D1000" ];
|
||||
it('should sort message group (exp, not number, descending)', function(done) {
|
||||
check_sort0C(flow, "$substring($,1)", data_in, data_out, done);
|
||||
});
|
||||
it('should sort payload (exp, not number, descending)', function(done) {
|
||||
check_sort1C(flow, "$substring(payload,1)", data_in, data_out, done);
|
||||
});
|
||||
})();
|
||||
|
||||
(function() {
|
||||
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:true, wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var conv = function(x) {
|
||||
return x.map(function(v) { return { val:v }; });
|
||||
};
|
||||
var data_in = conv([ "200", "4", "30", "1000" ]);
|
||||
var data_out = conv([ "4", "30", "200", "1000" ]);
|
||||
it('should sort payload of objects', function(done) {
|
||||
check_sort0C(flow, "val", data_in, data_out, done);
|
||||
});
|
||||
})();
|
||||
|
||||
it('should sort payload by context (exp, not number, ascending)', function(done) {
|
||||
var flow = [{id:"n1", type:"sort", target:"data", targetType:"msg", msgKey:"$flowContext($)", msgKeyType:"jsonata", order:"ascending", as_num:false, wires:[["n2"]],z:"flow"},
|
||||
{id:"n2", type:"helper",z:"flow"},
|
||||
{id:"flow", type:"tab"}];
|
||||
var data_in = [ "first", "second", "third", "fourth" ];
|
||||
var data_out = [ "second", "third", "first", "fourth" ];
|
||||
helper.load(sortNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.context()["flow"].set("first","3");
|
||||
n1.context()["flow"].set("second","1");
|
||||
n1.context()["flow"].set("third","2");
|
||||
n1.context()["flow"].set("fourth","4");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("data");
|
||||
var data = msg["data"];
|
||||
data.length.should.equal(data_out.length);
|
||||
for(var i = 0; i < data_out.length; i++) {
|
||||
data[i].should.equal(data_out[i]);
|
||||
}
|
||||
done();
|
||||
});
|
||||
var msg = {};
|
||||
msg["data"] = data_in;
|
||||
n1.receive(msg);
|
||||
});
|
||||
});
|
||||
|
||||
it('should sort message group by context (exp, not number, ascending)', function(done) {
|
||||
var flow = [{id:"n1", type:"sort", target:"data", targetType:"seq", seqKey:"$globalContext(payload)", seqKeyType:"jsonata", order:"ascending", as_num:false, wires:[["n2"]],z:"flow"},
|
||||
{id:"n2", type:"helper",z:"flow"},
|
||||
{id:"flow", type:"tab"}];
|
||||
var data_in = [ "first", "second", "third", "fourth" ];
|
||||
var data_out = [ "second", "fourth", "third", "first" ];
|
||||
helper.load(sortNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n1.context()["global"].set("first","4");
|
||||
n1.context()["global"].set("second","1");
|
||||
n1.context()["global"].set("third","3");
|
||||
n1.context()["global"].set("fourth","2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("payload");
|
||||
msg.should.have.property("parts");
|
||||
msg.parts.should.have.property("count", data_out.length);
|
||||
var data = msg["payload"];
|
||||
var index = data_out.indexOf(data);
|
||||
msg.parts.should.have.property("index", index);
|
||||
count++;
|
||||
if (count === data_out.length) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
catch(e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
var len = data_in.length;
|
||||
for(var i = 0; i < len; i++) {
|
||||
var parts = { id: "X", index: i, count: len };
|
||||
var msg = {parts: parts};
|
||||
msg["payload"] = data_in[i];
|
||||
n1.receive(msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should sort payload by persistable context (exp, not number, descending)', function(done) {
|
||||
var flow = [{id:"n1", type:"sort", target:"data", targetType:"msg", msgKey:"$globalContext($,\"memory\")", msgKeyType:"jsonata", order:"descending", as_num:false, wires:[["n2"]],z:"flow"},
|
||||
{id:"n2", type:"helper",z:"flow"},
|
||||
{id:"flow", type:"tab"}];
|
||||
var data_in = [ "first", "second", "third", "fourth" ];
|
||||
var data_out = [ "fourth", "first", "third", "second" ];
|
||||
helper.load(sortNode, flow, function() {
|
||||
initContext(function(){
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n1.context()["global"].set(["first","second","third","fourth"],["3","1","2","4"],"memory",function(){
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("data");
|
||||
var data = msg["data"];
|
||||
data.length.should.equal(data_out.length);
|
||||
for(var i = 0; i < data_out.length; i++) {
|
||||
data[i].should.equal(data_out[i]);
|
||||
}
|
||||
done();
|
||||
});
|
||||
var msg = {};
|
||||
msg["data"] = data_in;
|
||||
n1.receive(msg);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should sort message group by persistable context (exp, not number, descending)', function(done) {
|
||||
var flow = [{id:"n1", type:"sort", target:"data", targetType:"seq", seqKey:"$flowContext(payload,\"memory\")", seqKeyType:"jsonata", order:"descending", as_num:false, wires:[["n2"]],z:"flow"},
|
||||
{id:"n2", type:"helper",z:"flow"},
|
||||
{id:"flow", type:"tab"}];
|
||||
var data_in = [ "first", "second", "third", "fourth" ];
|
||||
var data_out = [ "first", "third", "fourth", "second" ];
|
||||
helper.load(sortNode, flow, function() {
|
||||
initContext(function(){
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
n1.context()["flow"].set(["first","second","third","fourth"],["4","1","3","2"],"memory",function(){
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("payload");
|
||||
msg.should.have.property("parts");
|
||||
msg.parts.should.have.property("count", data_out.length);
|
||||
var data = msg["payload"];
|
||||
var index = data_out.indexOf(data);
|
||||
msg.parts.should.have.property("index", index);
|
||||
count++;
|
||||
if (count === data_out.length) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
var len = data_in.length;
|
||||
for(var i = 0; i < len; i++) {
|
||||
var parts = { id: "X", index: i, count: len };
|
||||
var msg = {parts: parts};
|
||||
msg["payload"] = data_in[i];
|
||||
n1.receive(msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle JSONata script error', function(done) {
|
||||
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:false, target:"payload", targetType:"seq", seqKey:"$unknown()", seqKeyType:"jsonata", wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(sortNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
setTimeout(function() {
|
||||
var logEvents = helper.log().args.filter(function (evt) {
|
||||
return evt[0].type == "sort";
|
||||
});
|
||||
var evt = logEvents[0][0];
|
||||
evt.should.have.property('id', "n1");
|
||||
evt.should.have.property('type', "sort");
|
||||
evt.should.have.property('msg', "sort.invalid-exp");
|
||||
done();
|
||||
}, 150);
|
||||
var msg0 = { payload: "A", parts: { id: "X", index: 0, count: 2} };
|
||||
var msg1 = { payload: "B", parts: { id: "X", index: 1, count: 2} };
|
||||
n1.receive(msg0);
|
||||
n1.receive(msg1);
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle too many pending messages', function(done) {
|
||||
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:false, target:"payload", targetType:"seq", seqKey:"payload", seqKeyType:"msg", wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(sortNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
RED.settings.nodeMessageBufferMaxLength = 2;
|
||||
setTimeout(function() {
|
||||
var logEvents = helper.log().args.filter(function (evt) {
|
||||
return evt[0].type == "sort";
|
||||
});
|
||||
var evt = logEvents[0][0];
|
||||
evt.should.have.property('id', "n1");
|
||||
evt.should.have.property('type', "sort");
|
||||
evt.should.have.property('msg', "sort.too-many");
|
||||
done();
|
||||
}, 150);
|
||||
for(var i = 0; i < 4; i++) {
|
||||
var msg = { payload: "V"+i,
|
||||
parts: { id: "X", index: i, count: 4} };
|
||||
n1.receive(msg);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should clear pending messages on close', function(done) {
|
||||
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:false, target:"payload", targetType:"seq", seqKey:"payload", seqKeyType:"msg", wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(sortNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var msg = { payload: 0,
|
||||
parts: { id: "X", index: 0, count: 2} };
|
||||
n1.receive(msg);
|
||||
setTimeout(function() {
|
||||
n1.close().then(function() {
|
||||
var logEvents = helper.log().args.filter(function (evt) {
|
||||
return evt[0].type == "sort";
|
||||
});
|
||||
var evt = logEvents[0][0];
|
||||
evt.should.have.property('id', "n1");
|
||||
evt.should.have.property('type', "sort");
|
||||
evt.should.have.property('msg', "sort.clear");
|
||||
done();
|
||||
});
|
||||
}, 150);
|
||||
});
|
||||
});
|
||||
|
||||
describe('messaging API', function() {
|
||||
function mapiDoneTestHelper(done, targetType, msgAndTimings) {
|
||||
const completeNode = require("nr-test-utils").require("@node-red/nodes/core/common/24-complete.js");
|
||||
const catchNode = require("nr-test-utils").require("@node-red/nodes/core/common/25-catch.js");
|
||||
const flow = [
|
||||
{id: "sortNode1", type: "sort", order: "ascending", as_num: false, target: "payload", targetType,
|
||||
seqKey: "payload", seqKeyType: "msg", wires: [[]]},
|
||||
{ id: "completeNode1", type: "complete", scope: ["sortNode1"], uncaught: false, wires: [["helperNode1"]] },
|
||||
{ id: "catchNode1", type: "catch", scope: ["sortNode1"], uncaught: false, wires: [["helperNode1"]] },
|
||||
{ id: "helperNode1", type: "helper", wires: [[]] }];
|
||||
const numMsgs = msgAndTimings.length;
|
||||
helper.load([sortNode, completeNode, catchNode], flow, function () {
|
||||
const sortNode1 = helper.getNode("sortNode1");
|
||||
const helperNode1 = helper.getNode("helperNode1");
|
||||
RED.settings.nodeMessageBufferMaxLength = 2;
|
||||
const t = Date.now();
|
||||
let c = 0;
|
||||
helperNode1.on("input", function (msg) {
|
||||
msg.should.have.a.property('payload');
|
||||
(Date.now() - t).should.be.approximately(msgAndTimings[msg.seq].avr, msgAndTimings[msg.seq].var);
|
||||
c += 1;
|
||||
if (c === numMsgs) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < numMsgs; i++) {
|
||||
setTimeout(function () { sortNode1.receive(msgAndTimings[i].msg); }, msgAndTimings[i].delay);
|
||||
}
|
||||
});
|
||||
}
|
||||
it('should call done() when message is sent (payload)', function (done) {
|
||||
mapiDoneTestHelper(done, "msg", [
|
||||
{ msg: { seq: 0, payload: [1, 3, 2] }, delay: 0, avr: 0, var: 100 },
|
||||
]);
|
||||
});
|
||||
it('should call done() when message is sent (sequence)', function (done) {
|
||||
mapiDoneTestHelper(done, "seq", [
|
||||
{ msg: { seq: 0, payload: 3, parts: {id:"A", index: 0, count: 2}}, delay: 0, avr: 500, var: 100 },
|
||||
{ msg: { seq: 1, payload: 2, parts: {id:"A", index: 1, count: 2}}, delay: 500, avr: 500, var: 100}
|
||||
]);
|
||||
});
|
||||
it('should call done() regardless of buffer overflow (same group)', function (done) {
|
||||
mapiDoneTestHelper(done, "seq", [
|
||||
{ msg: { seq: 0, payload: 1, parts: {id:"A", index: 0, count: 3}}, delay: 0, avr: 1000, var: 100 },
|
||||
{ msg: { seq: 1, payload: 3, parts: {id:"A", index: 1, count: 3}}, delay: 500, avr: 1000, var: 100 },
|
||||
{ msg: { seq: 2, payload: 2, parts: {id:"A", index: 2, count: 3}}, delay: 1000, avr: 1000, var: 100 },
|
||||
]);
|
||||
});
|
||||
it('should call done() regardless of buffer overflow (different group)', function (done) {
|
||||
mapiDoneTestHelper(done, "seq", [
|
||||
{ msg: { seq: 0, payload: 1, parts: {id:"A", index: 0, count: 2}}, delay: 0, avr: 1000, var: 100 },
|
||||
{ msg: { seq: 1, payload: 3, parts: {id:"B", index: 0, count: 2}}, delay: 500, avr: 1200, var: 100 },
|
||||
{ msg: { seq: 2, payload: 5, parts: {id:"C", index: 0, count: 2}}, delay: 1000, avr: 1500, var: 100 },
|
||||
{ msg: { seq: 3, payload: 2, parts: {id:"B", index: 1, count: 2}}, delay: 1200, avr: 1200, var: 100 },
|
||||
{ msg: { seq: 4, payload: 4, parts: {id:"C", index: 1, count: 2}}, delay: 1500, avr: 1500, var: 100 },
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
@@ -1,542 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var batchNode = require("nr-test-utils").require("@node-red/nodes/core/sequence/19-batch.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var RED = require("nr-test-utils").require("node-red/lib/red.js");
|
||||
|
||||
describe('BATCH node', function() {
|
||||
this.timeout(8000);
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
RED.settings.nodeMessageBufferMaxLength = 0;
|
||||
});
|
||||
|
||||
it('should be loaded with defaults', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
n1.should.have.property('name', 'BatchNode');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
function check_parts(msg, id, idx, count) {
|
||||
msg.should.have.property("parts");
|
||||
var parts = msg.parts;
|
||||
parts.should.have.property("id", id);
|
||||
parts.should.have.property("index", idx);
|
||||
parts.should.have.property("count", count);
|
||||
}
|
||||
|
||||
function check_data(n1, n2, results, done) {
|
||||
var id = undefined;
|
||||
var ix0 = 0; // seq no
|
||||
var ix1 = 0; // loc. in seq
|
||||
var seq = undefined;
|
||||
var msgs = [];
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
for (var i = 0; i < msgs.length; i++) {
|
||||
msg.should.not.equal(msgs[i]);
|
||||
}
|
||||
msgs.push(msg);
|
||||
if (seq === undefined) {
|
||||
seq = results[ix0];
|
||||
}
|
||||
var val = seq[ix1];
|
||||
msg.should.have.property("payload", val);
|
||||
if (id === undefined) {
|
||||
id = msg.parts.id;
|
||||
}
|
||||
check_parts(msg, id, ix1, seq.length);
|
||||
ix1++;
|
||||
if (ix1 === seq.length) {
|
||||
ix0++;
|
||||
ix1 = 0;
|
||||
seq = undefined;
|
||||
id = undefined;
|
||||
if (ix0 === results.length) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function check_count(flow, results, done) {
|
||||
try {
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
check_data(n1, n2, results, done);
|
||||
for(var i = 0; i < 6; i++) {
|
||||
n1.receive({payload: i});
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
}
|
||||
|
||||
function delayed_send(receiver, index, count, delay, done) {
|
||||
if (index < count) {
|
||||
setTimeout(function() {
|
||||
receiver.receive({payload: index});
|
||||
delayed_send(receiver, index+1, count, delay, done);
|
||||
}, delay);
|
||||
}
|
||||
else if(index === count) {
|
||||
if (done) {
|
||||
done();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function check_interval(flow, results, delay, done) {
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
check_data(n1, n2, results, done);
|
||||
delayed_send(n1, 0, 4, delay);
|
||||
});
|
||||
}
|
||||
|
||||
function check_concat(flow, results, inputs, done) {
|
||||
try {
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
check_data(n1, n2, results, done);
|
||||
for(var data of inputs) {
|
||||
var msg = {
|
||||
topic: data[0],
|
||||
payload: data[1],
|
||||
parts: {
|
||||
id: data[0],
|
||||
index: data[2],
|
||||
count: data[3]
|
||||
}
|
||||
};
|
||||
n1.receive(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
}
|
||||
|
||||
describe('mode: count', function() {
|
||||
|
||||
it('should create seq. with count', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 2, overlap: 0, interval: 10, allowEmptySequence: false, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
[0, 1],
|
||||
[2, 3],
|
||||
[4, 5]
|
||||
];
|
||||
check_count(flow, results, done);
|
||||
});
|
||||
|
||||
it('should create seq. with count and overlap', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 3, overlap: 2, interval: 10, allowEmptySequence: false, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
[0, 1, 2],
|
||||
[1, 2, 3],
|
||||
[2, 3, 4],
|
||||
[3, 4, 5]
|
||||
];
|
||||
check_count(flow, results, done);
|
||||
});
|
||||
|
||||
it('should handle too many pending messages', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 5, overlap: 0, interval: 10, allowEmptySequence: false, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
RED.settings.nodeMessageBufferMaxLength = 2;
|
||||
setTimeout(function() {
|
||||
var logEvents = helper.log().args.filter(function (evt) {
|
||||
return evt[0].type == "batch";
|
||||
});
|
||||
var evt = logEvents[0][0];
|
||||
evt.should.have.property('id', "n1");
|
||||
evt.should.have.property('type', "batch");
|
||||
evt.should.have.property('msg', "batch.too-many");
|
||||
done();
|
||||
}, 150);
|
||||
for(var i = 0; i < 3; i++) {
|
||||
n1.receive({payload: i});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle reset', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "count", count: 2, overlap: 0, interval: 0, allowEmptySequence: false, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var results = [
|
||||
[0, 1],
|
||||
[4, 5]
|
||||
];
|
||||
check_data(n1, n2, results, done);
|
||||
n1.receive({payload:0});
|
||||
n1.receive({payload:1});
|
||||
n1.receive({payload:2});
|
||||
n1.receive({payload:3, reset: true});
|
||||
n1.receive({payload:4});
|
||||
n1.receive({payload:5});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('mode: interval', function() {
|
||||
it('should create seq. with interval', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "interval", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
[0, 1],
|
||||
[2, 3]
|
||||
];
|
||||
check_interval(flow, results, 450, done);
|
||||
});
|
||||
|
||||
it('should create seq. with interval (in float)', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "interval", count: 0, overlap: 0, interval: 0.5, allowEmptySequence: false, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
[0, 1],
|
||||
[2, 3]
|
||||
];
|
||||
check_interval(flow, results, 225, done);
|
||||
});
|
||||
|
||||
it('should create seq. with interval & not send empty seq', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "interval", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
// 1300, 2600, 3900, 5200,
|
||||
[0], [1], [2], [3]
|
||||
];
|
||||
check_interval(flow, results, 1300, done);
|
||||
});
|
||||
|
||||
it('should create seq. with interval & send empty seq', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "interval", count: 0, overlap: 0, interval: 1, allowEmptySequence: true, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
// 1300, 2600, 3900, 5200,
|
||||
[null], [0], [1], [2], [null], [3]
|
||||
];
|
||||
check_interval(flow, results, 1300, done);
|
||||
});
|
||||
|
||||
it('should handle too many pending messages', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "interval", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
RED.settings.nodeMessageBufferMaxLength = 2;
|
||||
setTimeout(function() {
|
||||
var logEvents = helper.log().args.filter(function (evt) {
|
||||
return evt[0].type == "batch";
|
||||
});
|
||||
var evt = logEvents[0][0];
|
||||
evt.should.have.property('id', "n1");
|
||||
evt.should.have.property('type', "batch");
|
||||
evt.should.have.property('msg', "batch.too-many");
|
||||
done();
|
||||
}, 150);
|
||||
for(var i = 0; i < 3; i++) {
|
||||
n1.receive({payload: i});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle reset', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "interval", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var results = [
|
||||
[0, 1],
|
||||
[4, 5]
|
||||
];
|
||||
check_data(n1, n2, results, done);
|
||||
delayed_send(n1, 0, 3, 400, function () {
|
||||
setTimeout(function () {
|
||||
n1.receive({payload: "3", reset: true});
|
||||
delayed_send(n1, 4, 7, 400);
|
||||
}, 10);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('mode: concat', function() {
|
||||
it('should concat two seq. (series)', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "concat", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [{topic: "TA"}, {topic: "TB"}], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
[2, 3, 0, 1]
|
||||
];
|
||||
var inputs = [
|
||||
["TB", 0, 0, 2],
|
||||
["TB", 1, 1, 2],
|
||||
["TA", 2, 0, 2],
|
||||
["TA", 3, 1, 2]
|
||||
];
|
||||
check_concat(flow, results, inputs, done);
|
||||
});
|
||||
|
||||
it('should concat two seq. (mixed)', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "concat", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [{topic: "TA"}, {topic: "TB"}], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
[2, 3, 0, 1]
|
||||
];
|
||||
var inputs = [
|
||||
["TA", 2, 0, 2],
|
||||
["TB", 0, 0, 2],
|
||||
["TA", 3, 1, 2],
|
||||
["TB", 1, 1, 2]
|
||||
];
|
||||
check_concat(flow, results, inputs, done);
|
||||
});
|
||||
|
||||
it('should concat three seq.', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "concat", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [{topic: "TA"}, {topic: "TB"}, {topic: "TC"}], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
[2, 3, 0, 1, 4]
|
||||
];
|
||||
var inputs = [
|
||||
["TC", 4, 0, 1],
|
||||
["TB", 0, 0, 2],
|
||||
["TB", 1, 1, 2],
|
||||
["TA", 2, 0, 2],
|
||||
["TA", 3, 1, 2]
|
||||
];
|
||||
check_concat(flow, results, inputs, done);
|
||||
});
|
||||
|
||||
it('should concat same seq.', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "concat", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [{topic: "TA"}, {topic: "TA"}], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = [
|
||||
[9, 8, 9, 8]
|
||||
];
|
||||
var inputs = [
|
||||
["TA", 9, 0, 2],
|
||||
["TA", 8, 1, 2]
|
||||
];
|
||||
check_concat(flow, results, inputs, done);
|
||||
});
|
||||
|
||||
it('should handle too many pending messages', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "concat", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [{topic: "TA"}, {topic: "TB"}], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
RED.settings.nodeMessageBufferMaxLength = 2;
|
||||
setTimeout(function() {
|
||||
var logEvents = helper.log().args.filter(function (evt) {
|
||||
return evt[0].type == "batch";
|
||||
});
|
||||
var evt = logEvents[0][0];
|
||||
evt.should.have.property('id', "n1");
|
||||
evt.should.have.property('type', "batch");
|
||||
evt.should.have.property('msg', "batch.too-many");
|
||||
done();
|
||||
}, 150);
|
||||
var C = 3;
|
||||
for(var i = 0; i < C; i++) {
|
||||
var parts_a = {index:i, count:C, id:"A"};
|
||||
var parts_b = {index:i, count:C, id:"B"};
|
||||
n1.receive({payload: i, topic: "TA", parts:parts_a});
|
||||
n1.receive({payload: i, topic: "TB", parts:parts_b});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should handle reset', function(done) {
|
||||
var flow = [{id:"n1", type:"batch", name: "BatchNode", mode: "concat", count: 0, overlap: 0, interval: 1, allowEmptySequence: false, topics: [{topic: "TA"}, {topic: "TB"}], wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
try {
|
||||
helper.load(batchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var results = [
|
||||
[2, 3, 0, 1]
|
||||
];
|
||||
check_data(n1, n2, results, done);
|
||||
var inputs0 = [
|
||||
["TB", 0, 0, 2],
|
||||
["TA", 1, 0, 2],
|
||||
];
|
||||
for(var data of inputs0) {
|
||||
var msg = {
|
||||
topic: data[0],
|
||||
payload: data[1],
|
||||
parts: {
|
||||
id: data[0],
|
||||
index: data[2],
|
||||
count: data[3]
|
||||
}
|
||||
};
|
||||
n1.receive(msg);
|
||||
}
|
||||
n1.receive({payload: undefined, reset: true});
|
||||
var inputs1 = [
|
||||
["TB", 0, 0, 2],
|
||||
["TB", 1, 1, 2],
|
||||
["TA", 2, 0, 2],
|
||||
["TA", 3, 1, 2]
|
||||
];
|
||||
for(var data of inputs1) {
|
||||
var msg = {
|
||||
topic: data[0],
|
||||
payload: data[1],
|
||||
parts: {
|
||||
id: data[0],
|
||||
index: data[2],
|
||||
count: data[3]
|
||||
}
|
||||
};
|
||||
n1.receive(msg);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('messaging API', function() {
|
||||
function mapiDoneTestHelper(done, mode, count, overlap, interval, allowEmptySequence, msgAndTimings) {
|
||||
const completeNode = require("nr-test-utils").require("@node-red/nodes/core/common/24-complete.js");
|
||||
const catchNode = require("nr-test-utils").require("@node-red/nodes/core/common/25-catch.js");
|
||||
const flow = [{id:"batchNode1", type:"batch", name: "BatchNode", mode, count, overlap, interval,
|
||||
allowEmptySequence, topics: [{topic: "TA"}], wires:[[]]},
|
||||
{id:"completeNode1",type:"complete",scope: ["batchNode1"],uncaught:false,wires:[["helperNode1"]]},
|
||||
{id:"catchNode1", type:"catch",scope: ["batchNode1"],uncaught:false,wires:[["helperNode1"]]},
|
||||
{id:"helperNode1",type:"helper", wires:[[]]}];
|
||||
const numMsgs = msgAndTimings.length;
|
||||
helper.load([batchNode, completeNode, catchNode], flow, function () {
|
||||
const batchNode1 = helper.getNode("batchNode1");
|
||||
const helperNode1 = helper.getNode("helperNode1");
|
||||
RED.settings.nodeMessageBufferMaxLength = 2;
|
||||
const t = Date.now();
|
||||
let c = 0;
|
||||
helperNode1.on("input", function (msg) {
|
||||
msg.should.have.a.property('payload');
|
||||
(Date.now() - t).should.be.approximately(msgAndTimings[msg.payload].avr, msgAndTimings[msg.payload].var);
|
||||
c += 1;
|
||||
if ( c === numMsgs) {
|
||||
done();
|
||||
}
|
||||
});
|
||||
for (let i = 0; i < numMsgs; i++) {
|
||||
setTimeout( function() { batchNode1.receive(msgAndTimings[i].msg); }, msgAndTimings[i].delay);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
it('should call done() when message is sent (mode: count)', function(done) {
|
||||
mapiDoneTestHelper(done, "count", 2, 0, 2, false, [
|
||||
{ msg: {payload: 0}, delay: 0, avr: 0, var: 100},
|
||||
{ msg: {payload: 1}, delay: 0, avr: 0, var: 100}
|
||||
]);
|
||||
});
|
||||
it('should call done() when reset (mode: count)', function(done) {
|
||||
mapiDoneTestHelper(done, "count", 2, 0, 2, false, [
|
||||
{ msg: {payload: 0}, delay: 0, avr: 200, var: 100},
|
||||
{ msg: {payload: 1, reset:true}, delay: 200, avr: 200, var: 100}
|
||||
]);
|
||||
});
|
||||
it('should call done() regardless of buffer overflow (mode: count)', function(done) {
|
||||
mapiDoneTestHelper(done, "count", 10, 0, 2, false, [
|
||||
{ msg: {payload: 0}, delay: 0, avr: 500, var: 100},
|
||||
{ msg: {payload: 1}, delay: 100, avr: 500, var: 100},
|
||||
{ msg: {payload: 2}, delay: 500, avr: 500, var: 100}
|
||||
]);
|
||||
});
|
||||
it('should call done() when message is sent (mode: interval)', function(done) {
|
||||
mapiDoneTestHelper(done, "interval", 2, 0, 2, false, [
|
||||
{ msg: {payload: 0}, delay: 0, avr: 2000, var: 100},
|
||||
{ msg: {payload: 1}, delay: 500, avr: 2000, var: 100}
|
||||
]);
|
||||
});
|
||||
it('should call done() when reset (mode: interval)', function(done) {
|
||||
mapiDoneTestHelper(done, "interval", 2, 0, 2, false, [
|
||||
{ msg: {payload: 0}, delay: 0, avr: 200, var: 100},
|
||||
{ msg: {payload: 1, reset:true}, delay: 200, avr: 200, var: 100}
|
||||
]);
|
||||
});
|
||||
it('should call done() regardless of buffer overflow (mode: interval)', function(done) {
|
||||
mapiDoneTestHelper(done, "interval", 2, 0, 2, false, [
|
||||
{ msg: {payload: 0}, delay: 0, avr: 500, var: 100},
|
||||
{ msg: {payload: 1}, delay: 100, avr: 500, var: 100},
|
||||
{ msg: {payload: 2}, delay: 500, avr: 500, var: 100}
|
||||
]);
|
||||
});
|
||||
it('should call done() when message is sent (mode: concat)', function(done) {
|
||||
mapiDoneTestHelper(done, "concat", 2, 0, 2, false, [
|
||||
{ msg: {topic:"TA", payload: 0, parts: {id: "TA", index: 0, count: 2}}, delay: 0, avr: 1000, var: 100},
|
||||
{ msg: {topic:"TA", payload: 1, parts: {id: "TA", index: 1, count: 2}}, delay: 1000, avr: 1000, var: 100},
|
||||
]);
|
||||
});
|
||||
it('should call done() when reset (mode: concat)', function(done) {
|
||||
mapiDoneTestHelper(done, "concat", 2, 0, 2, false, [
|
||||
{ msg: {topic:"TA", payload: 0, parts: {id: "TA", index: 0, count: 2}}, delay: 0, avr: 1000, var: 100},
|
||||
{ msg: {payload: 1, reset:true}, delay: 1000, avr: 1000, var: 100},
|
||||
]);
|
||||
});
|
||||
it('should call done() regardless of buffer overflow (mode: concat)', function(done) {
|
||||
mapiDoneTestHelper(done, "concat", 2, 0, 2, false, [
|
||||
{ msg: {topic:"TA", payload: 0, parts: {id: "TA", index: 0, count: 3}}, delay: 0, avr: 1000, var: 100},
|
||||
{ msg: {topic:"TA", payload: 0, parts: {id: "TA", index: 1, count: 3}}, delay: 500, avr: 1000, var: 100},
|
||||
{ msg: {topic:"TA", payload: 0, parts: {id: "TA", index: 2, count: 3}}, delay: 1000, avr: 1000, var: 100}
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
File diff suppressed because it is too large
Load Diff
@@ -1,217 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var fs = require("fs-extra");
|
||||
var path = require("path");
|
||||
var should = require("should");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
var watchNode = require("nr-test-utils").require("@node-red/nodes/core/storage/23-watch.js");
|
||||
|
||||
|
||||
describe('watch Node', function() {
|
||||
this.timeout(5000);
|
||||
|
||||
var resourcesDir = path.join(__dirname,"..","..","..","resources");
|
||||
var baseDir = path.join(resourcesDir, "23-watch-test-dir");
|
||||
var count = 0;
|
||||
|
||||
function prepareDir() {
|
||||
var dirToWatch = path.join(baseDir, "base"+count);
|
||||
fs.mkdirSync(dirToWatch);
|
||||
count++;
|
||||
return {
|
||||
dirToWatch:dirToWatch,
|
||||
file0ToWatch:path.join(dirToWatch, "file0.txt"),
|
||||
file1ToWatch:path.join(dirToWatch, "file1.txt"),
|
||||
subDirToWatch:path.join(dirToWatch, "subdir"),
|
||||
file2ToWatch:path.join(dirToWatch, "subdir", "file2.txt")
|
||||
}
|
||||
}
|
||||
|
||||
function wait(msec, func) {
|
||||
setTimeout(func, msec);
|
||||
}
|
||||
|
||||
before(function(done) {
|
||||
fs.ensureDirSync(baseDir);
|
||||
done();
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
fs.removeSync(baseDir);
|
||||
done();
|
||||
});
|
||||
|
||||
afterEach(function(done) {
|
||||
helper.unload();
|
||||
done();
|
||||
});
|
||||
|
||||
function testWatch(flow, change_func, results, done) {
|
||||
var processed = {};
|
||||
helper.load(watchNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
var count = 0;
|
||||
var len = Object.keys(results).length;
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
// console.log(msg);
|
||||
msg.should.have.property('file');
|
||||
|
||||
var file = msg.file;
|
||||
if (file in processed) {
|
||||
// multiple messages come in rare case
|
||||
return;
|
||||
}
|
||||
processed[file] = true;
|
||||
if (file === 'subdir') {
|
||||
// On OSX, we get a change event on subdir when a file inside changes.
|
||||
// On Travis, we don't. *sigh*
|
||||
return;
|
||||
}
|
||||
(file in results).should.be.true();
|
||||
|
||||
var result = results[file];
|
||||
msg.should.have.property('payload', result.payload);
|
||||
msg.should.have.property('type', result.type);
|
||||
if('size' in result) {
|
||||
msg.should.have.property('size', result.size);
|
||||
}
|
||||
count++;
|
||||
if(count === len) {
|
||||
n1.close();
|
||||
// wait for close
|
||||
wait(100, done);
|
||||
}
|
||||
}catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
// wait for preparation
|
||||
wait(500, change_func);
|
||||
});
|
||||
}
|
||||
|
||||
it('should watch a file to be changed', function(done) {
|
||||
var files = prepareDir();
|
||||
fs.writeFileSync(files.file0ToWatch, '');
|
||||
var flow = [{id:"n1", type:"watch", name: "watch",
|
||||
files: files.file0ToWatch, recursive: false,
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = {
|
||||
'file0.txt' : {
|
||||
'payload' : files.file0ToWatch,
|
||||
'topic': files.file0ToWatch,
|
||||
'type': 'file',
|
||||
'size': 5
|
||||
}
|
||||
};
|
||||
testWatch(flow, function() {
|
||||
fs.appendFileSync(files.file0ToWatch, "ABCDE");
|
||||
}, results, done);
|
||||
});
|
||||
|
||||
it('should watch multiple files to be changed', function(done) {
|
||||
var files = prepareDir();
|
||||
fs.writeFileSync(files.file0ToWatch, '');
|
||||
fs.writeFileSync(files.file1ToWatch, '');
|
||||
var flow = [{id:"n1", type:"watch", name: "watch",
|
||||
files: files.file0ToWatch +","+files.file1ToWatch, recursive: false,
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = {
|
||||
'file0.txt' : {
|
||||
'payload' : files.file0ToWatch,
|
||||
'topic': files.file0ToWatch,
|
||||
'type': 'file'//,
|
||||
// 'size': 5
|
||||
},
|
||||
'file1.txt' : {
|
||||
'payload' : files.file1ToWatch,
|
||||
'topic': files.file1ToWatch,
|
||||
'type': 'file'//,
|
||||
// 'size': 3
|
||||
}
|
||||
};
|
||||
testWatch(flow, function() {
|
||||
fs.appendFileSync(files.file0ToWatch, "ABCDE");
|
||||
fs.appendFileSync(files.file1ToWatch, "123");
|
||||
}, results, done);
|
||||
});
|
||||
|
||||
it('should watch attribute of a file to be changed', function(done) {
|
||||
var files = prepareDir();
|
||||
fs.writeFileSync(files.file0ToWatch, '');
|
||||
fs.chmodSync(files.file0ToWatch, 0o444);
|
||||
var flow = [{id:"n1", type:"watch", name: "watch",
|
||||
files: files.file0ToWatch, recursive: false,
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = {
|
||||
'file0.txt' : {
|
||||
'payload' : files.file0ToWatch,
|
||||
'topic': files.file0ToWatch,
|
||||
'type': 'file'//,
|
||||
// 'size': 0
|
||||
}
|
||||
};
|
||||
testWatch(flow, function() {
|
||||
fs.chmodSync(files.file0ToWatch, 0o777);
|
||||
}, results, done);
|
||||
});
|
||||
|
||||
it('should watch a file in a directory to be changed', function(done) {
|
||||
var files = prepareDir();
|
||||
fs.writeFileSync(files.file0ToWatch, '');
|
||||
var flow = [{id:"n1", type:"watch", name: "watch",
|
||||
files: files.dirToWatch, recursive: true,
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = {
|
||||
'file0.txt' : {
|
||||
'payload' : files.file0ToWatch,
|
||||
'topic': files.file0ToWatch,
|
||||
'type': 'file'//,
|
||||
// 'size': 5
|
||||
}
|
||||
};
|
||||
testWatch(flow, function() {
|
||||
fs.appendFileSync(files.file0ToWatch, "ABCDE");
|
||||
}, results, done);
|
||||
});
|
||||
|
||||
it('should watch a sub directory in a directory to be changed', function(done) {
|
||||
var files = prepareDir();
|
||||
fs.mkdirSync(files.subDirToWatch);
|
||||
var flow = [{id:"n1", type:"watch", name: "watch",
|
||||
files: files.dirToWatch, recursive: true,
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", type:"helper"}];
|
||||
var results = {
|
||||
'file2.txt': {
|
||||
payload: files.file2ToWatch,
|
||||
type: 'file'//,
|
||||
// size: 5
|
||||
}
|
||||
};
|
||||
testWatch(flow, function() {
|
||||
fs.appendFileSync(files.file2ToWatch, "ABCDE");
|
||||
}, results, done);
|
||||
});
|
||||
|
||||
});
|
@@ -1,570 +0,0 @@
|
||||
/**
|
||||
* Copyright JS Foundation and other contributors, http://js.foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var functionNode = require("nr-test-utils").require("@node-red/nodes/core/function/10-function.js");
|
||||
var helper = require("node-red-node-test-helper");
|
||||
|
||||
// Notice:
|
||||
// - nodes should have x, y, z property when defining subflow.
|
||||
|
||||
describe('subflow', function() {
|
||||
|
||||
before(function(done) {
|
||||
helper.startServer(done);
|
||||
});
|
||||
|
||||
after(function(done) {
|
||||
helper.stopServer(done);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
helper.unload();
|
||||
});
|
||||
|
||||
it('should define subflow', function(done) {
|
||||
var flow = [
|
||||
{id:"t1", type:"tab"},
|
||||
{id:"n1", z:"t1", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", z:"t1", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
in:[{wires:[ {id:"s1-n1"} ]}],
|
||||
out:[{wires:[ {id:"s1-n1", port:0} ]}]},
|
||||
{id:"s1-n1", z:"s1", type:"function",
|
||||
func:"return msg;", wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass data to/from subflow', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", 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} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.payload = msg.payload+'bar'; return msg;", wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("payload", "foobar");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should pass data to/from nested subflow', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow1
|
||||
{id:"s1", type:"subflow", name:"Subflow1", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n2", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
|
||||
wires:[["s1-n2"]]},
|
||||
{id:"s1-n2", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.payload = msg.payload+'baz'; return msg;", wires:[]},
|
||||
// Subflow2
|
||||
{id:"s2", type:"subflow", name:"Subflow2", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s2-n1", x:10, y:10, z:"s2", type:"function",
|
||||
func:"msg.payload=msg.payload+'bar'; return msg;", wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("payload", "foobarbaz");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of subflow template', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "V"}
|
||||
],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of subflow instance', 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: "K", type: "str", value: "V"}
|
||||
],
|
||||
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} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access last env var with same name', 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: "K", type: "str", value: "V0"},
|
||||
{name: "X", type: "str", value: "VX"},
|
||||
{name: "K", type: "str", value: "V1"}
|
||||
],
|
||||
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} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V1");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
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:"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:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("VS", "STR");
|
||||
msg.should.have.property("VN", 100);
|
||||
msg.should.have.property("VB", true);
|
||||
msg.should.have.property("VJ", [1,2,3]);
|
||||
msg.should.have.property("Vb");
|
||||
should.ok(msg.Vb instanceof Buffer);
|
||||
msg.should.have.property("VE","STR");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should overwrite env var of subflow template by env var of subflow instance', 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: "K", type: "str", value: "V"}
|
||||
],
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "TV"}
|
||||
],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of parent subflow template', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow1
|
||||
{id:"s1", type:"subflow", name:"Subflow1", info:"",
|
||||
env: [
|
||||
{name: "K", type: "str", value: "V"},
|
||||
],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n2", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
|
||||
wires:[["s1-n2"]]},
|
||||
{id:"s1-n2", x:10, y:10, z:"s1", type:"function",
|
||||
func:"return msg;", wires:[]},
|
||||
// Subflow2
|
||||
{id:"s2", type:"subflow", name:"Subflow2", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s2-n1", x:10, y:10, z:"s2", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of parent subflow instance', 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: "K", type: "str", value: "V"}
|
||||
],
|
||||
wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow1
|
||||
{id:"s1", type:"subflow", name:"Subflow1", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n2", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
|
||||
wires:[["s1-n2"]]},
|
||||
{id:"s1-n2", x:10, y:10, z:"s1", type:"function",
|
||||
func:"return msg;", wires:[]},
|
||||
// Subflow2
|
||||
{id:"s2", type:"subflow", name:"Subflow2", info:"",
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s2-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s2-n1", x:10, y:10, z:"s2", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of tab', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:"", env: [
|
||||
{name: "K", type: "str", value: "V"}
|
||||
]},
|
||||
{id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"", env: [],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of group', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"g1", z:"t0", type:"group", env:[
|
||||
{name: "K", type: "str", value: "V"}
|
||||
]},
|
||||
{id:"n1", x:10, y:10, z:"t0", g:"g1", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"", env: [],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
it('should access env var of nested group', function(done) {
|
||||
var flow = [
|
||||
{id:"t0", type:"tab", label:"", disabled:false, info:""},
|
||||
{id:"g1", z:"t0", type:"group", env:[
|
||||
{name: "K", type: "str", value: "V"}
|
||||
]},
|
||||
{id:"g2", z:"t0", g:"g1", type:"group", env:[]},
|
||||
{id:"n1", x:10, y:10, z:"t0", g:"g2", type:"subflow:s1", wires:[["n2"]]},
|
||||
{id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
|
||||
// Subflow
|
||||
{id:"s1", type:"subflow", name:"Subflow", info:"", env: [],
|
||||
in:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1"} ]
|
||||
}],
|
||||
out:[{
|
||||
x:10, y:10,
|
||||
wires:[ {id:"s1-n1", port:0} ]
|
||||
}]
|
||||
},
|
||||
{id:"s1-n1", x:10, y:10, z:"s1", type:"function",
|
||||
func:"msg.V = env.get('K'); return msg;",
|
||||
wires:[]}
|
||||
];
|
||||
helper.load(functionNode, flow, function() {
|
||||
var n1 = helper.getNode("n1");
|
||||
var n2 = helper.getNode("n2");
|
||||
n2.on("input", function(msg) {
|
||||
try {
|
||||
msg.should.have.property("V", "V");
|
||||
done();
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
n1.receive({payload:"foo"});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
Reference in New Issue
Block a user