1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Merge pull request #1580 from node-red-hitachi/0.18-parts-ext-switch-fix

fix bugs in SWITCH updates
This commit is contained in:
Nick O'Leary 2018-01-26 08:18:10 +00:00 committed by GitHub
commit d355de509b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 185 additions and 106 deletions

View File

@ -83,8 +83,8 @@ module.exports = function(RED) {
this.previousValue = null; this.previousValue = null;
var node = this; var node = this;
var valid = true; var valid = true;
var needs_count = false;
var repair = n.repair; var repair = n.repair;
var needs_count = repair;
for (var i=0; i<this.rules.length; i+=1) { for (var i=0; i<this.rules.length; i+=1) {
var rule = this.rules[i]; var rule = this.rules[i];
needs_count = needs_count || ((rule.t === "tail") || (rule.t === "jsonata_exp")); needs_count = needs_count || ((rule.t === "tail") || (rule.t === "jsonata_exp"));
@ -187,16 +187,18 @@ module.exports = function(RED) {
function send_group(onwards, port_count) { function send_group(onwards, port_count) {
var counts = new Array(port_count).fill(0); var counts = new Array(port_count).fill(0);
var ids = new Array(port_count); for (var i = 0; i < onwards.length; i++) {
for(var i = 0; i < onwards.length; i++) {
var onward = onwards[i]; var onward = onwards[i];
for(var j = 0; j < port_count; j++) { for (var j = 0; j < port_count; j++) {
counts[j] += (onward[j] !== null) ? 1 : 0 counts[j] += (onward[j] !== null) ? 1 : 0
} }
ids[i] = RED.util.generateId();
} }
var indexes = new Array(port_count).fill(0); var ids = new Array(port_count);
for (var j = 0; j < port_count; j++) {
ids[j] = RED.util.generateId();
}
var ports = new Array(port_count); var ports = new Array(port_count);
var indexes = new Array(port_count).fill(0);
for (var i = 0; i < onwards.length; i++) { for (var i = 0; i < onwards.length; i++) {
var onward = onwards[i]; var onward = onwards[i];
for (var j = 0; j < port_count; j++) { for (var j = 0; j < port_count; j++) {
@ -250,8 +252,7 @@ module.exports = function(RED) {
if (msg.hasOwnProperty("parts")) { if (msg.hasOwnProperty("parts")) {
var parts = msg.parts; var parts = msg.parts;
return (parts.hasOwnProperty("id") && return (parts.hasOwnProperty("id") &&
parts.hasOwnProperty("index") && parts.hasOwnProperty("index"));
parts.hasOwnProperty("count"));
} }
return false; return false;
} }
@ -325,7 +326,7 @@ module.exports = function(RED) {
} }
} }
node.previousValue = prop; node.previousValue = prop;
if (repair || !has_parts) { if (!repair || !has_parts) {
node.send(onward); node.send(onward);
} }
else { else {

View File

@ -121,12 +121,15 @@ describe('switch Node', function() {
}); });
} }
function customFlowSequenceSwitchTest(flow, seq_in, seq_out, done) { function customFlowSequenceSwitchTest(flow, seq_in, seq_out, repair, modifier, done) {
helper.load(switchNode, flow, function() { helper.load(switchNode, flow, function() {
var switchNode1 = helper.getNode("switchNode1"); var switchNode1 = helper.getNode("switchNode1");
var helperNode1 = helper.getNode("helperNode1"); var helperNode1 = helper.getNode("helperNode1");
var sid = undefined; var sid = undefined;
var count = 0; var count = 0;
if (modifier !== undefined) {
modifier(switchNode1);
}
helperNode1.on("input", function(msg) { helperNode1.on("input", function(msg) {
try { try {
msg.should.have.property("payload", seq_out[count]); msg.should.have.property("payload", seq_out[count]);
@ -140,8 +143,14 @@ describe('switch Node', function() {
else { else {
id.should.equal(sid); id.should.equal(sid);
} }
parts.should.have.property("index", count); if (repair) {
parts.should.have.property("count", seq_out.length); parts.should.have.property("index", count);
parts.should.have.property("count", seq_out.length);
}
else {
parts.should.have.property("index", msg.xindex);
parts.should.have.property("count", seq_in.length);
}
count++; count++;
if (count === seq_out.length) { if (count === seq_out.length) {
done(); done();
@ -153,11 +162,13 @@ describe('switch Node', function() {
var len = seq_in.length; var len = seq_in.length;
for (var i = 0; i < len; i++) { for (var i = 0; i < len; i++) {
var parts = {index:i, count:len, id:222}; var parts = {index:i, count:len, id:222};
var msg = {payload:seq_in[i], parts:parts}; var msg = {payload:seq_in[i], xindex:i, parts:parts};
switchNode1.receive(msg); switchNode1.receive(msg);
} }
}); });
} }
it('should check if payload equals given value', function(done) { it('should check if payload equals given value', function(done) {
genericSwitchTest("eq", "Hello", true, true, "Hello", done); genericSwitchTest("eq", "Hello", true, true, "Hello", done);
@ -539,22 +550,55 @@ describe('switch Node', function() {
customFlowSwitchTest(flow, true, -5, done); customFlowSwitchTest(flow, true, -5, done);
}); });
it('should take head of message sequence', function(done) { it('should take head of message sequence (no repair)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"head","v":3}],checkall:true,outputs:1,wires:[["helperNode1"]]}, var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"head","v":3}],checkall:false,repair:false,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}]; {id:"helperNode1", type:"helper", wires:[]}];
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [0, 1, 2], done); customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [0, 1, 2], false, undefined, done);
}); });
it('should take tail of message sequence', function(done) { it('should take head of message sequence (repair)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"tail","v":3}],checkall:true,outputs:1,wires:[["helperNode1"]]}, var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"head","v":3}],checkall:false,repair:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}]; {id:"helperNode1", type:"helper", wires:[]}];
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [2, 3, 4], done); customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [0, 1, 2], true, undefined, done);
}); });
it('should take slice of message sequence', function(done) { it('should take head of message sequence (w. context)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"index","v":1,"v2":3}],checkall:true,outputs:1,wires:[["helperNode1"]]}, var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"head","v":"count",vt:"global"}],checkall:false,repair:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}]; {id:"helperNode1", type:"helper", wires:[]}];
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [1,2, 3], done); customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [0, 1, 2], true,
function(node) {
node.context().global.set("count", 3);
}, done);
});
it('should take head of message sequence (w. JSONata)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"head","v":"1+4/2",vt:"jsonata"}],checkall:false,repair:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [0, 1, 2], true, undefined, done);
});
it('should take tail of message sequence (no repair)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"tail","v":3}],checkall:true,repair:false,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [2, 3, 4], false, undefined, done);
});
it('should take tail of message sequence (repair)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"tail","v":3}],checkall:true,repair:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [2, 3, 4], true, undefined, done);
});
it('should take slice of message sequence (no repair)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"index","v":1,"v2":3}],checkall:true,repair:false,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [1, 2, 3], false, undefined, done);
});
it('should take slice of message sequence (repair)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"index","v":1,"v2":3}],checkall:true,repair:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [1, 2, 3], true, undefined, done);
}); });
it('should check JSONata expression is true', function(done) { it('should check JSONata expression is true', function(done) {
@ -564,77 +608,34 @@ describe('switch Node', function() {
{id:"helperNode1", type:"helper", wires:[]}]; {id:"helperNode1", type:"helper", wires:[]}];
customFlowSwitchTest(flow, true, 9, done); customFlowSwitchTest(flow, true, 9, done);
}); });
it('should repair message sequence', function(done) { it('should be able to use $I in JSONata expression', function(done) {
var flow = [{id:"n1",type:"switch",name:"switchNode",property:"payload", var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"jsonata_exp","v":"$I % 2 = 1",vt:"jsonata"}],checkall:true,repair:true,outputs:1,wires:[["helperNode1"]]},
rules:[{"t":"gt","v":0},{"t":"lt","v":0},{"t":"else"}], {id:"helperNode1", type:"helper", wires:[]}];
checkall:true,repair:true, customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [1, 3], true, undefined, done);
outputs:3,wires:[["n2"],["n3"],["n4"]]},
{id:"n2", type:"helper", wires:[]},
{id:"n3", type:"helper", wires:[]},
{id:"n4", type:"helper", wires:[]}
];
helper.load(switchNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var n3 = helper.getNode("n3");
var n4 = helper.getNode("n4");
var data = { "0":1, "1":-2, "2":2, "3":0, "4":-1 };
var count = 0;
function check_msg(msg, vf) {
try {
msg.should.have.property("payload");
var payload = msg.payload;
msg.should.have.property("parts");
vf(payload).should.be.ok;
var parts = msg.parts;
parts.should.have.property("id", 222);
parts.should.have.property("count", 5);
parts.should.have.property("index");
var index = parts.index;
payload.should.equal(data[index]);
count++;
if (count == 5) {
done();
}
}
catch (e) {
done(e);
}
}
n2.on("input", function(msg) {
check_msg(msg, function(x) { return(x < 0); });
});
n3.on("input", function(msg) {
check_msg(msg, function(x) { return(x === 0); });
});
n4.on("input", function(msg) {
check_msg(msg, function(x) { return(x > 0); });
});
for(var i in data) {
n1.receive({payload: data[i], parts:{index:i,count:5,id:222}});
}
});
}); });
it('should create message sequence for each port', function(done) { it('should be able to use $N in JSONata expression', function(done) {
var flow = [{id:"n1",type:"switch",name:"switchNode",property:"payload", var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"jsonata_exp","v":"payload >= $N-2",vt:"jsonata"}],checkall:true,repair:true,outputs:1,wires:[["helperNode1"]]},
rules:[{"t":"gt","v":0},{"t":"lt","v":0},{"t":"else"}], {id:"helperNode1", type:"helper", wires:[]}];
checkall:true,repair:false, customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [3, 4], true, undefined, done);
outputs:3,wires:[["n2"],["n3"],["n4"]]}, });
{id:"n2", type:"helper", wires:[]}, // >0
{id:"n3", type:"helper", wires:[]}, // <0
{id:"n4", type:"helper", wires:[]} // ==0 function customFlowSequenceMultiSwitchTest(flow, seq_in, outs, repair, done) {
];
helper.load(switchNode, flow, function() { helper.load(switchNode, flow, function() {
var n1 = helper.getNode("n1"); var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2"); var port_count = Object.keys(outs).length;
var n3 = helper.getNode("n3"); var sid;
var n4 = helper.getNode("n4"); var ids = new Array(port_count).fill(undefined);
var data = [ 1, -2, 2, 0, -1 ]; var counts = new Array(port_count).fill(0);
var vals = [[1, 2], [-2, -1], [0]]; var vals = new Array(port_count);
var ids = [undefined, undefined, undefined]; var recv_count = 0;
var counts = [0, 0, 0]; for (var id in outs) {
var out = outs[id];
vals[out.port] = out.vals;
recv_count += out.vals.length;
}
var count = 0; var count = 0;
function check_msg(msg, ix, vf) { function check_msg(msg, ix, vf) {
try { try {
@ -644,23 +645,35 @@ describe('switch Node', function() {
vf(payload).should.be.ok; vf(payload).should.be.ok;
var parts = msg.parts; var parts = msg.parts;
var evals = vals[ix]; var evals = vals[ix];
parts.should.have.property("count", evals.length);
parts.should.have.property("id"); parts.should.have.property("id");
var id = parts.id; var id = parts.id;
if (ids[ix] === undefined) { if (repair) {
ids[ix] = id; if (ids[ix] === undefined) {
ids[ix] = id;
}
else {
ids[ix].should.equal(id);
}
parts.should.have.property("count", evals.length);
parts.should.have.property("index", counts[ix]);
} }
else { else {
ids[ix].should.equal(id); if (sid === undefined) {
sid = id;
}
else {
sid.should.equal(id);
}
parts.should.have.property("count", seq_in.length);
parts.should.have.property("index", msg.xindex);
} }
parts.should.have.property("index");
var index = parts.index; var index = parts.index;
var eindex = counts[ix]; var eindex = counts[ix];
var eval = evals[eindex]; var eval = evals[eindex];
payload.should.equal(eval); payload.should.equal(eval);
counts[ix]++; counts[ix]++;
count++; count++;
if (count == 5) { if (count === recv_count) {
done(); done();
} }
} }
@ -668,19 +681,84 @@ describe('switch Node', function() {
done(e); done(e);
} }
} }
n2.on("input", function(msg) { for (var id in outs) {
check_msg(msg, 0, function(x) { return(x > 0); }); (function() {
}); var node = helper.getNode(id);
n3.on("input", function(msg) { var port = outs[id].port;
check_msg(msg, 1, function(x) { return(x < 0); }); var vf = outs[id].vf;
}); node.on("input", function(msg) {
n4.on("input", function(msg) { check_msg(msg, port, vf);
check_msg(msg, 2, function(x) { return(x === 0); }); });
}); })();
for(var i in data) { }
n1.receive({payload: data[i], parts:{index:i,count:5,id:222}}); for(var i in seq_in) {
n1.receive({payload:seq_in[i], xindex:i,
parts:{index:i, count:seq_in.length, id:222}});
} }
}); });
}
it('should not repair message sequence for each port', function(done) {
var flow = [{id:"n1",type:"switch",name:"switchNode",property:"payload",
rules:[{"t":"gt","v":0},{"t":"lt","v":0},{"t":"else"}],
checkall:true,repair:false,
outputs:3,wires:[["n2"],["n3"],["n4"]]},
{id:"n2", type:"helper", wires:[]},
{id:"n3", type:"helper", wires:[]},
{id:"n4", type:"helper", wires:[]}
];
var data = [ 1, -2, 2, 0, -1 ];
var outs = {
"n2" : { port:0, vals:[1, 2],
vf:function(x) { return(x > 0); } },
"n3" : { port:1, vals:[-2, -1],
vf:function(x) { return(x < 0); } },
"n4" : { port:2, vals:[0],
vf:function(x) { return(x == 0); } },
};
customFlowSequenceMultiSwitchTest(flow, data, outs, false, done);
});
it('should repair message sequence for each port', function(done) {
var flow = [{id:"n1",type:"switch",name:"switchNode",property:"payload",
rules:[{"t":"gt","v":0},{"t":"lt","v":0},{"t":"else"}],
checkall:true,repair:true,
outputs:3,wires:[["n2"],["n3"],["n4"]]},
{id:"n2", type:"helper", wires:[]}, // >0
{id:"n3", type:"helper", wires:[]}, // <0
{id:"n4", type:"helper", wires:[]} // ==0
];
var data = [ 1, -2, 2, 0, -1 ];
var outs = {
"n2" : { port:0, vals:[1, 2],
vf:function(x) { return(x > 0); } },
"n3" : { port:1, vals:[-2, -1],
vf:function(x) { return(x < 0); } },
"n4" : { port:2, vals:[0],
vf:function(x) { return(x == 0); } },
};
customFlowSequenceMultiSwitchTest(flow, data, outs, true, done);
});
it('should repair message sequence for each port (overlap)', function(done) {
var flow = [{id:"n1",type:"switch",name:"switchNode",property:"payload",
rules:[{"t":"gte","v":0},{"t":"lte","v":0},{"t":"else"}],
checkall:true,repair:true,
outputs:3,wires:[["n2"],["n3"],["n4"]]},
{id:"n2", type:"helper", wires:[]}, // >=0
{id:"n3", type:"helper", wires:[]}, // <=0
{id:"n4", type:"helper", wires:[]} // none
];
var data = [ 1, -2, 2, 0, -1 ];
var outs = {
"n2" : { port:0, vals:[1, 2, 0],
vf:function(x) { return(x > 0); } },
"n3" : { port:1, vals:[-2, 0, -1],
vf:function(x) { return(x < 0); } },
"n4" : { port:2, vals:[],
vf:function(x) { return(false); } },
};
customFlowSequenceMultiSwitchTest(flow, data, outs, true, done);
}); });
it('should handle too many pending messages', function(done) { it('should handle too many pending messages', function(done) {