mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00: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:
		| @@ -83,8 +83,8 @@ module.exports = function(RED) { | ||||
|         this.previousValue = null; | ||||
|         var node = this; | ||||
|         var valid = true; | ||||
|         var needs_count = false; | ||||
|         var repair = n.repair; | ||||
|         var needs_count = repair; | ||||
|         for (var i=0; i<this.rules.length; i+=1) { | ||||
|             var rule = this.rules[i]; | ||||
|             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) { | ||||
|             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]; | ||||
|                 for(var j = 0; j < port_count; j++) { | ||||
|                 for (var j = 0; j < port_count; j++) { | ||||
|                     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 indexes = new Array(port_count).fill(0); | ||||
|             for (var i = 0; i < onwards.length; i++) { | ||||
|                 var onward = onwards[i]; | ||||
|                 for (var j = 0; j < port_count; j++) { | ||||
| @@ -250,8 +252,7 @@ module.exports = function(RED) { | ||||
|             if (msg.hasOwnProperty("parts")) { | ||||
|                 var parts = msg.parts; | ||||
|                 return (parts.hasOwnProperty("id") && | ||||
|                         parts.hasOwnProperty("index") && | ||||
|                         parts.hasOwnProperty("count")); | ||||
|                         parts.hasOwnProperty("index")); | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
| @@ -325,7 +326,7 @@ module.exports = function(RED) { | ||||
|                     } | ||||
|                 } | ||||
|                 node.previousValue = prop; | ||||
|                 if (repair || !has_parts) { | ||||
|                 if (!repair || !has_parts) { | ||||
|                     node.send(onward); | ||||
|                 } | ||||
|                 else { | ||||
|   | ||||
| @@ -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() { | ||||
|             var switchNode1 = helper.getNode("switchNode1"); | ||||
|             var helperNode1 = helper.getNode("helperNode1"); | ||||
|             var sid = undefined; | ||||
|             var count = 0; | ||||
|             if (modifier !== undefined) { | ||||
|                 modifier(switchNode1); | ||||
|             } | ||||
|             helperNode1.on("input", function(msg) { | ||||
|                 try { | ||||
|                     msg.should.have.property("payload", seq_out[count]); | ||||
| @@ -140,8 +143,14 @@ describe('switch Node', function() { | ||||
|                     else { | ||||
|                         id.should.equal(sid); | ||||
|                     } | ||||
|                     parts.should.have.property("index", count); | ||||
|                     parts.should.have.property("count", seq_out.length); | ||||
|                     if (repair) { | ||||
|                         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++; | ||||
|                     if (count === seq_out.length) { | ||||
|                         done(); | ||||
| @@ -153,11 +162,13 @@ describe('switch Node', function() { | ||||
|             var len = seq_in.length; | ||||
|             for (var i = 0; i < len; i++) { | ||||
|                 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); | ||||
|             } | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|      | ||||
|      | ||||
|     it('should check if payload equals given value', function(done) { | ||||
|         genericSwitchTest("eq", "Hello", true, true, "Hello", done); | ||||
| @@ -539,22 +550,55 @@ describe('switch Node', function() { | ||||
|         customFlowSwitchTest(flow, true, -5, done); | ||||
|     }); | ||||
|  | ||||
|     it('should take head of message sequence', function(done) { | ||||
|         var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"head","v":3}],checkall:true,outputs:1,wires:[["helperNode1"]]}, | ||||
|     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:false,repair:false,outputs:1,wires:[["helperNode1"]]}, | ||||
|                     {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) { | ||||
|         var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"tail","v":3}],checkall:true,outputs:1,wires:[["helperNode1"]]}, | ||||
|     it('should take head of message sequence (repair)', function(done) { | ||||
|         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:[]}]; | ||||
|         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) { | ||||
|         var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"index","v":1,"v2":3}],checkall:true,outputs:1,wires:[["helperNode1"]]}, | ||||
|     it('should take head of message sequence (w. context)', function(done) { | ||||
|         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:[]}]; | ||||
|         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) { | ||||
| @@ -564,77 +608,34 @@ describe('switch Node', function() { | ||||
|                     {id:"helperNode1", type:"helper", wires:[]}]; | ||||
|         customFlowSwitchTest(flow, true, 9, done); | ||||
|     }); | ||||
|  | ||||
|     it('should repair message sequence', 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:[]}, | ||||
|                     {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 be able to use $I in JSONata expression', function(done) { | ||||
|         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"]]}, | ||||
|                     {id:"helperNode1", type:"helper", wires:[]}]; | ||||
|         customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [1, 3], true, undefined, done); | ||||
|     }); | ||||
|  | ||||
|     it('should create 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:[]}, // >0 | ||||
|                     {id:"n3", type:"helper", wires:[]}, // <0 | ||||
|                     {id:"n4", type:"helper", wires:[]}  // ==0 | ||||
|                    ]; | ||||
|     it('should be able to use $N in JSONata expression', function(done) { | ||||
|         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"]]}, | ||||
|                     {id:"helperNode1", type:"helper", wires:[]}]; | ||||
|         customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [3, 4], true, undefined, done); | ||||
|     }); | ||||
|  | ||||
|  | ||||
|     function customFlowSequenceMultiSwitchTest(flow, seq_in, outs, repair, done) { | ||||
|         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 = [ 1, -2, 2, 0, -1 ]; | ||||
|             var vals = [[1, 2], [-2, -1], [0]]; | ||||
|             var ids = [undefined, undefined, undefined]; | ||||
|             var counts = [0, 0, 0]; | ||||
|             var port_count = Object.keys(outs).length; | ||||
|             var sid; | ||||
|             var ids = new Array(port_count).fill(undefined); | ||||
|             var counts = new Array(port_count).fill(0); | ||||
|             var vals = new Array(port_count); | ||||
|             var recv_count = 0; | ||||
|             for (var id in outs) { | ||||
|                 var out = outs[id]; | ||||
|                 vals[out.port] = out.vals; | ||||
|                 recv_count += out.vals.length; | ||||
|             } | ||||
|             var count = 0; | ||||
|             function check_msg(msg, ix, vf) { | ||||
|                 try { | ||||
| @@ -644,23 +645,35 @@ describe('switch Node', function() { | ||||
|                     vf(payload).should.be.ok; | ||||
|                     var parts = msg.parts; | ||||
|                     var evals = vals[ix]; | ||||
|                     parts.should.have.property("count", evals.length); | ||||
|                     parts.should.have.property("id"); | ||||
|                     var id = parts.id; | ||||
|                     if (ids[ix] === undefined) { | ||||
|                         ids[ix] = id; | ||||
|                     if (repair) { | ||||
|                         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 { | ||||
|                         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 eindex = counts[ix]; | ||||
|                     var eval = evals[eindex]; | ||||
|                     payload.should.equal(eval); | ||||
|                     counts[ix]++; | ||||
|                     count++; | ||||
|                     if (count == 5) { | ||||
|                     if (count === recv_count) { | ||||
|                         done(); | ||||
|                     } | ||||
|                 } | ||||
| @@ -668,19 +681,84 @@ describe('switch Node', function() { | ||||
|                     done(e); | ||||
|                 } | ||||
|             } | ||||
|             n2.on("input", function(msg) { | ||||
|                 check_msg(msg, 0, function(x) { return(x > 0); }); | ||||
|             }); | ||||
|             n3.on("input", function(msg) { | ||||
|                 check_msg(msg, 1, function(x) { return(x < 0); }); | ||||
|             }); | ||||
|             n4.on("input", function(msg) { | ||||
|                 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 id in outs) { | ||||
|                 (function() { | ||||
|                     var node = helper.getNode(id); | ||||
|                     var port = outs[id].port; | ||||
|                     var vf = outs[id].vf; | ||||
|                     node.on("input", function(msg) { | ||||
|                         check_msg(msg, port, vf); | ||||
|                     }); | ||||
|                 })(); | ||||
|             } | ||||
|             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) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user