mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Refactor Subflow logic into own class
This commit is contained in:
@@ -167,18 +167,17 @@ describe('Node', function() {
|
||||
describe('#send', function() {
|
||||
|
||||
it('emits a single message', function(done) {
|
||||
var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
|
||||
var n2 = new RedNode({id:'n2',type:'abc'});
|
||||
var flowGet = sinon.stub(flows,"get",function(id) {
|
||||
return {'n1':n1,'n2':n2}[id];
|
||||
});
|
||||
var flow = {
|
||||
getNode: (id) => { return {'n1':n1,'n2':n2}[id]},
|
||||
};
|
||||
var n1 = new RedNode({_flow:flow,id:'n1',type:'abc',wires:[['n2']]});
|
||||
var n2 = new RedNode({_flow:flow,id:'n2',type:'abc'});
|
||||
var message = {payload:"hello world"};
|
||||
|
||||
n2.on('input',function(msg) {
|
||||
// msg equals message, and is not a new copy
|
||||
should.deepEqual(msg,message);
|
||||
should.strictEqual(msg,message);
|
||||
flowGet.restore();
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -186,11 +185,11 @@ describe('Node', function() {
|
||||
});
|
||||
|
||||
it('emits multiple messages on a single output', function(done) {
|
||||
var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
|
||||
var n2 = new RedNode({id:'n2',type:'abc'});
|
||||
var flowGet = sinon.stub(flows,"get",function(id) {
|
||||
return {'n1':n1,'n2':n2}[id];
|
||||
});
|
||||
var flow = {
|
||||
getNode: (id) => { return {'n1':n1,'n2':n2}[id]},
|
||||
};
|
||||
var n1 = new RedNode({_flow:flow,id:'n1',type:'abc',wires:[['n2']]});
|
||||
var n2 = new RedNode({_flow:flow,id:'n2',type:'abc'});
|
||||
|
||||
var messages = [
|
||||
{payload:"hello world"},
|
||||
@@ -209,7 +208,6 @@ describe('Node', function() {
|
||||
// second msg sent, clone
|
||||
msg.payload.should.equal(messages[rcvdCount].payload);
|
||||
should.notStrictEqual(msg,messages[rcvdCount]);
|
||||
flowGet.restore();
|
||||
done();
|
||||
}
|
||||
});
|
||||
@@ -217,14 +215,14 @@ describe('Node', function() {
|
||||
});
|
||||
|
||||
it('emits messages to multiple outputs', function(done) {
|
||||
var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2'],['n3'],['n4','n5']]});
|
||||
var n2 = new RedNode({id:'n2',type:'abc'});
|
||||
var n3 = new RedNode({id:'n3',type:'abc'});
|
||||
var n4 = new RedNode({id:'n4',type:'abc'});
|
||||
var n5 = new RedNode({id:'n5',type:'abc'});
|
||||
var flowGet = sinon.stub(flows,"get",function(id) {
|
||||
return {'n1':n1,'n2':n2,'n3':n3,'n4':n4,'n5':n5}[id];
|
||||
});
|
||||
var flow = {
|
||||
getNode: (id) => { return {'n1':n1,'n2':n2,'n3':n3,'n4':n4,'n5':n5}[id]},
|
||||
};
|
||||
var n1 = new RedNode({_flow:flow, id:'n1',type:'abc',wires:[['n2'],['n3'],['n4','n5']]});
|
||||
var n2 = new RedNode({_flow:flow, id:'n2',type:'abc'});
|
||||
var n3 = new RedNode({_flow:flow, id:'n3',type:'abc'});
|
||||
var n4 = new RedNode({_flow:flow, id:'n4',type:'abc'});
|
||||
var n5 = new RedNode({_flow:flow, id:'n5',type:'abc'});
|
||||
|
||||
var messages = [
|
||||
{payload:"hello world"},
|
||||
@@ -241,7 +239,6 @@ describe('Node', function() {
|
||||
should.strictEqual(msg,messages[0]);
|
||||
rcvdCount += 1;
|
||||
if (rcvdCount == 3) {
|
||||
flowGet.restore();
|
||||
done();
|
||||
}
|
||||
});
|
||||
@@ -257,7 +254,6 @@ describe('Node', function() {
|
||||
should.notStrictEqual(msg,messages[2]);
|
||||
rcvdCount += 1;
|
||||
if (rcvdCount == 3) {
|
||||
flowGet.restore();
|
||||
done();
|
||||
}
|
||||
});
|
||||
@@ -269,7 +265,6 @@ describe('Node', function() {
|
||||
should.notStrictEqual(msg,messages[2]);
|
||||
rcvdCount += 1;
|
||||
if (rcvdCount == 3) {
|
||||
flowGet.restore();
|
||||
done();
|
||||
}
|
||||
});
|
||||
@@ -278,18 +273,17 @@ describe('Node', function() {
|
||||
});
|
||||
|
||||
it('emits no messages', function(done) {
|
||||
var n1 = new RedNode({id:'n1',type:'abc',wires:[['n2']]});
|
||||
var n2 = new RedNode({id:'n2',type:'abc'});
|
||||
var flowGet = sinon.stub(flows,"get",function(id) {
|
||||
return {'n1':n1,'n2':n2}[id];
|
||||
});
|
||||
var flow = {
|
||||
getNode: (id) => { return {'n1':n1,'n2':n2}[id]},
|
||||
};
|
||||
var n1 = new RedNode({_flow:flow,id:'n1',type:'abc',wires:[['n2']]});
|
||||
var n2 = new RedNode({_flow:flow,id:'n2',type:'abc'});
|
||||
|
||||
n2.on('input',function(msg) {
|
||||
should.fail(null,null,"unexpected message");
|
||||
});
|
||||
|
||||
setTimeout(function() {
|
||||
flowGet.restore();
|
||||
done();
|
||||
}, 200);
|
||||
|
||||
@@ -297,11 +291,11 @@ describe('Node', function() {
|
||||
});
|
||||
|
||||
it('emits messages ignoring non-existent nodes', function(done) {
|
||||
var n1 = new RedNode({id:'n1',type:'abc',wires:[['n9'],['n2']]});
|
||||
var n2 = new RedNode({id:'n2',type:'abc'});
|
||||
var flowGet = sinon.stub(flows,"get",function(id) {
|
||||
return {'n1':n1,'n2':n2}[id];
|
||||
});
|
||||
var flow = {
|
||||
getNode: (id) => { return {'n1':n1,'n2':n2}[id]},
|
||||
};
|
||||
var n1 = new RedNode({_flow:flow,id:'n1',type:'abc',wires:[['n9'],['n2']]});
|
||||
var n2 = new RedNode({_flow:flow,id:'n2',type:'abc'});
|
||||
|
||||
var messages = [
|
||||
{payload:"hello world"},
|
||||
@@ -312,7 +306,6 @@ describe('Node', function() {
|
||||
n2.on('input',function(msg) {
|
||||
should.deepEqual(msg,messages[1]);
|
||||
should.strictEqual(msg,messages[1]);
|
||||
flowGet.restore();
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -320,12 +313,12 @@ describe('Node', function() {
|
||||
});
|
||||
|
||||
it('emits messages without cloning req or res', function(done) {
|
||||
var n1 = new RedNode({id:'n1',type:'abc',wires:[[['n2'],['n3']]]});
|
||||
var n2 = new RedNode({id:'n2',type:'abc'});
|
||||
var n3 = new RedNode({id:'n3',type:'abc'});
|
||||
var flowGet = sinon.stub(flows,"get",function(id) {
|
||||
return {'n1':n1,'n2':n2,'n3':n3}[id];
|
||||
});
|
||||
var flow = {
|
||||
getNode: (id) => { return {'n1':n1,'n2':n2,'n3':n3}[id]},
|
||||
};
|
||||
var n1 = new RedNode({_flow:flow,id:'n1',type:'abc',wires:[[['n2'],['n3']]]});
|
||||
var n2 = new RedNode({_flow:flow,id:'n2',type:'abc'});
|
||||
var n3 = new RedNode({_flow:flow,id:'n3',type:'abc'});
|
||||
|
||||
var req = {};
|
||||
var res = {};
|
||||
@@ -342,7 +335,6 @@ describe('Node', function() {
|
||||
msg.res.should.be.exactly(message.res);
|
||||
rcvdCount += 1;
|
||||
if (rcvdCount == 2) {
|
||||
flowGet.restore();
|
||||
done();
|
||||
}
|
||||
});
|
||||
@@ -356,7 +348,6 @@ describe('Node', function() {
|
||||
msg.res.should.be.exactly(message.res);
|
||||
rcvdCount += 1;
|
||||
if (rcvdCount == 2) {
|
||||
flowGet.restore();
|
||||
done();
|
||||
}
|
||||
});
|
||||
@@ -365,26 +356,25 @@ describe('Node', function() {
|
||||
});
|
||||
|
||||
it("logs the uuid for all messages sent", function(done) {
|
||||
var flowGet = sinon.stub(flows,"get",function(id) {
|
||||
return {'n1':sender,'n2':receiver1,'n3':receiver2}[id];
|
||||
});
|
||||
var logHandler = {
|
||||
messagesSent: 0,
|
||||
emit: function(event, msg) {
|
||||
if (msg.event == "node.abc.send" && msg.level == Log.METRIC) {
|
||||
this.messagesSent++;
|
||||
(typeof msg.msgid).should.not.be.equal("undefined");
|
||||
flowGet.restore();
|
||||
done();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Log.addHandler(logHandler);
|
||||
var flow = {
|
||||
getNode: (id) => { return {'n1':sender,'n2':receiver1,'n3':receiver2}[id]},
|
||||
};
|
||||
|
||||
var sender = new RedNode({id:'n1',type:'abc', wires:[['n2', 'n3']]});
|
||||
var receiver1 = new RedNode({id:'n2',type:'abc'});
|
||||
var receiver2 = new RedNode({id:'n3',type:'abc'});
|
||||
var sender = new RedNode({_flow:flow,id:'n1',type:'abc', wires:[['n2', 'n3']]});
|
||||
var receiver1 = new RedNode({_flow:flow,id:'n2',type:'abc'});
|
||||
var receiver2 = new RedNode({_flow:flow,id:'n3',type:'abc'});
|
||||
sender.send({"some": "message"});
|
||||
})
|
||||
});
|
||||
@@ -434,50 +424,35 @@ describe('Node', function() {
|
||||
|
||||
describe('#error', function() {
|
||||
it('handles a null error message', function(done) {
|
||||
var n = new RedNode({id:'123',type:'abc',z:'789'});
|
||||
var loginfo = {};
|
||||
sinon.stub(Log, 'log', function(msg) {
|
||||
loginfo = msg;
|
||||
});
|
||||
sinon.stub(flows,"handleError", function(node,message,msg) {
|
||||
});
|
||||
|
||||
var flow = {
|
||||
handleError: sinon.stub()
|
||||
}
|
||||
var n = new RedNode({_flow:flow, id:'123',type:'abc',z:'789'});
|
||||
var message = {a:1};
|
||||
|
||||
n.error(null,message);
|
||||
should.deepEqual({level:Log.ERROR, id:n.id, type:n.type, msg:"",z:'789'}, loginfo);
|
||||
|
||||
flows.handleError.called.should.be.true();
|
||||
flows.handleError.args[0][0].should.eql(n);
|
||||
flows.handleError.args[0][1].should.eql("");
|
||||
flows.handleError.args[0][2].should.eql(message);
|
||||
flow.handleError.called.should.be.true();
|
||||
flow.handleError.args[0][0].should.eql(n);
|
||||
flow.handleError.args[0][1].should.eql("");
|
||||
flow.handleError.args[0][2].should.eql(message);
|
||||
|
||||
Log.log.restore();
|
||||
flows.handleError.restore();
|
||||
done();
|
||||
});
|
||||
|
||||
it('produces an error message', function(done) {
|
||||
var n = new RedNode({id:'123',type:'abc',z:'789'});
|
||||
var loginfo = {};
|
||||
sinon.stub(Log, 'log', function(msg) {
|
||||
loginfo = msg;
|
||||
});
|
||||
sinon.stub(flows,"handleError", function(node,message,msg) {
|
||||
});
|
||||
|
||||
var flow = {
|
||||
handleError: sinon.stub()
|
||||
}
|
||||
var n = new RedNode({_flow:flow, id:'123',type:'abc',z:'789'});
|
||||
var message = {a:2};
|
||||
|
||||
n.error("This is an error",message);
|
||||
should.deepEqual({level:Log.ERROR, id:n.id, type:n.type, msg:"This is an error",z:'789'}, loginfo);
|
||||
|
||||
flows.handleError.called.should.be.true();
|
||||
flows.handleError.args[0][0].should.eql(n);
|
||||
flows.handleError.args[0][1].should.eql("This is an error");
|
||||
flows.handleError.args[0][2].should.eql(message);
|
||||
flow.handleError.called.should.be.true();
|
||||
flow.handleError.args[0][0].should.eql(n);
|
||||
flow.handleError.args[0][1].should.eql("This is an error");
|
||||
flow.handleError.args[0][2].should.eql(message);
|
||||
|
||||
Log.log.restore();
|
||||
flows.handleError.restore();
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -528,8 +503,10 @@ describe('Node', function() {
|
||||
|
||||
describe('#status', function() {
|
||||
it('publishes status', function(done) {
|
||||
sinon.stub(flows,"handleStatus", function(node,message,msg) {});
|
||||
var n = new RedNode({id:'123',type:'abc'});
|
||||
var flow = {
|
||||
handleStatus: sinon.stub()
|
||||
}
|
||||
var n = new RedNode({_flow:flow,id:'123',type:'abc'});
|
||||
var status = {fill:"green",shape:"dot",text:"connected"};
|
||||
var topic;
|
||||
var message;
|
||||
@@ -537,10 +514,9 @@ describe('Node', function() {
|
||||
|
||||
n.status(status);
|
||||
|
||||
flows.handleStatus.called.should.be.true();
|
||||
flows.handleStatus.args[0][0].should.eql(n);
|
||||
flows.handleStatus.args[0][1].should.eql(status);
|
||||
flows.handleStatus.restore();
|
||||
flow.handleStatus.called.should.be.true();
|
||||
flow.handleStatus.args[0][0].should.eql(n);
|
||||
flow.handleStatus.args[0][1].should.eql(status);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@@ -31,7 +31,6 @@ var typeRegistry = NR_TEST_UTILS.require("@node-red/registry");
|
||||
|
||||
describe('Flow', function() {
|
||||
var getType;
|
||||
var getNode;
|
||||
|
||||
var stoppedNodes = {};
|
||||
var currentNodes = {};
|
||||
@@ -44,11 +43,11 @@ describe('Flow', function() {
|
||||
rewiredNodes = {};
|
||||
createCount = 0;
|
||||
Flow.init({settings:{},log:{
|
||||
log: sinon.stub(),
|
||||
debug: sinon.stub(),
|
||||
trace: sinon.stub(),
|
||||
warn: sinon.stub(),
|
||||
info: sinon.stub(),
|
||||
log: sinon.stub(), // function() { console.log("l",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//
|
||||
debug: sinon.stub(), // function() { console.log("d",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//sinon.stub(),
|
||||
trace: sinon.stub(), // function() { console.log("t",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//sinon.stub(),
|
||||
warn: sinon.stub(), // function() { console.log("w",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//sinon.stub(),
|
||||
info: sinon.stub(), // function() { console.log("i",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//sinon.stub(),
|
||||
metric: sinon.stub(),
|
||||
_: function() { return "abc"}
|
||||
}});
|
||||
@@ -64,6 +63,7 @@ describe('Flow', function() {
|
||||
this.stopped = false;
|
||||
currentNodes[node.id] = node;
|
||||
this.on('input',function(msg) {
|
||||
// console.log(this.id,msg.payload);
|
||||
node.handled++;
|
||||
node.send(msg);
|
||||
});
|
||||
@@ -81,6 +81,34 @@ describe('Flow', function() {
|
||||
}
|
||||
util.inherits(TestNode,Node);
|
||||
|
||||
var TestErrorNode = function(n) {
|
||||
Node.call(this,n);
|
||||
this._index = createCount++;
|
||||
this.scope = n.scope;
|
||||
this.name = n.name;
|
||||
var node = this;
|
||||
this.foo = n.foo;
|
||||
this.handled = 0;
|
||||
this.stopped = false;
|
||||
currentNodes[node.id] = node;
|
||||
this.on('input',function(msg) {
|
||||
node.handled++;
|
||||
node.error("test error",msg);
|
||||
});
|
||||
this.on('close',function() {
|
||||
node.stopped = true;
|
||||
stoppedNodes[node.id] = node;
|
||||
delete currentNodes[node.id];
|
||||
});
|
||||
this.__updateWires = this.updateWires;
|
||||
this.updateWires = function(newWires) {
|
||||
rewiredNodes[node.id] = node;
|
||||
node.newWires = newWires;
|
||||
node.__updateWires(newWires);
|
||||
};
|
||||
}
|
||||
util.inherits(TestErrorNode,Node);
|
||||
|
||||
var TestAsyncNode = function(n) {
|
||||
Node.call(this,n);
|
||||
var node = this;
|
||||
@@ -111,26 +139,21 @@ describe('Flow', function() {
|
||||
getType = sinon.stub(typeRegistry,"get",function(type) {
|
||||
if (type=="test") {
|
||||
return TestNode;
|
||||
} else if (type=="testError"){
|
||||
return TestErrorNode;
|
||||
} else {
|
||||
return TestAsyncNode;
|
||||
}
|
||||
});
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return currentNodes[id];
|
||||
});
|
||||
|
||||
});
|
||||
after(function() {
|
||||
getType.restore();
|
||||
getNode.restore();
|
||||
});
|
||||
|
||||
|
||||
|
||||
describe('#constructor',function() {
|
||||
it('called with an empty flow',function() {
|
||||
var config = flowUtils.parseConfig([]);
|
||||
var flow = Flow.create(config);
|
||||
var flow = Flow.create({},config);
|
||||
|
||||
var nodeCount = 0;
|
||||
Object.keys(flow.getActiveNodes()).length.should.equal(0);
|
||||
@@ -145,7 +168,7 @@ describe('Flow', function() {
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"4",z:"t1",type:"test",foo:"a"}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
flow.start();
|
||||
|
||||
Object.keys(flow.getActiveNodes()).should.have.length(4);
|
||||
@@ -188,7 +211,6 @@ describe('Flow', function() {
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
it("instantiates config nodes in the right order",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
@@ -198,7 +220,7 @@ describe('Flow', function() {
|
||||
{id:"4",z:"t1",type:"test",foo:"5"}, // This node depends on #5
|
||||
{id:"5",z:"t1",type:"test"}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
flow.start();
|
||||
|
||||
Object.keys(flow.getActiveNodes()).should.have.length(5);
|
||||
@@ -238,130 +260,12 @@ describe('Flow', function() {
|
||||
{id:"node1",z:"t1",type:"test",foo:"node2"}, // This node depends on #5
|
||||
{id:"node2",z:"t1",type:"test",foo:"node1"}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
/*jshint immed: false */
|
||||
(function(){
|
||||
flow.start();
|
||||
}).should.throw("Circular config node dependency detected: node1");
|
||||
});
|
||||
it("instantiates a subflow and stops it",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3","4"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"4",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-2","port":0}]},{"wires":[{"id":"sf1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test","z":"sf1",x:166,y:99,"wires":[["sf1-2"]]},
|
||||
{id:"sf1-2",type:"test","z":"sf1",foo:"sf1-cn",x:166,y:99,"wires":[[]]},
|
||||
{id:"sf1-cn",type:"test","z":"sf1"}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
Object.keys(activeNodes).should.have.length(7);
|
||||
var sfInstanceId = Object.keys(activeNodes)[5];
|
||||
var sfInstanceId2 = Object.keys(activeNodes)[6];
|
||||
var sfConfigId = Object.keys(activeNodes)[4];
|
||||
|
||||
flow.getNode('1').should.have.a.property('id','1');
|
||||
flow.getNode('2').should.have.a.property('id','2');
|
||||
flow.getNode('3').should.have.a.property('id','3');
|
||||
flow.getNode('4').should.have.a.property('id','4');
|
||||
flow.getNode(sfInstanceId).should.have.a.property('id',sfInstanceId);
|
||||
flow.getNode(sfInstanceId2).should.have.a.property('id',sfInstanceId2);
|
||||
flow.getNode(sfConfigId).should.have.a.property('id',sfConfigId);
|
||||
|
||||
flow.getNode(sfInstanceId2).should.have.a.property('foo',sfConfigId);
|
||||
|
||||
currentNodes.should.have.a.property("1");
|
||||
currentNodes.should.not.have.a.property("2");
|
||||
currentNodes.should.have.a.property("3");
|
||||
currentNodes.should.have.a.property("4");
|
||||
currentNodes.should.have.a.property(sfInstanceId);
|
||||
currentNodes.should.have.a.property(sfInstanceId2);
|
||||
currentNodes.should.have.a.property(sfConfigId);
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",0);
|
||||
currentNodes["3"].should.have.a.property("handled",0);
|
||||
currentNodes["4"].should.have.a.property("handled",0);
|
||||
currentNodes[sfInstanceId].should.have.a.property("handled",0);
|
||||
currentNodes[sfInstanceId2].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes["1"].receive({payload:"test"});
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
currentNodes[sfInstanceId].should.have.a.property("handled",1);
|
||||
currentNodes[sfInstanceId2].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",1);
|
||||
|
||||
|
||||
|
||||
flow.stop().then(function() {
|
||||
currentNodes.should.not.have.a.property("1");
|
||||
currentNodes.should.not.have.a.property("3");
|
||||
currentNodes.should.not.have.a.property("4");
|
||||
currentNodes.should.not.have.a.property(sfInstanceId);
|
||||
currentNodes.should.not.have.a.property(sfInstanceId2);
|
||||
currentNodes.should.not.have.a.property(sfConfigId);
|
||||
stoppedNodes.should.have.a.property("1");
|
||||
stoppedNodes.should.have.a.property("3");
|
||||
stoppedNodes.should.have.a.property("4");
|
||||
stoppedNodes.should.have.a.property(sfInstanceId);
|
||||
stoppedNodes.should.have.a.property(sfInstanceId2);
|
||||
stoppedNodes.should.have.a.property(sfConfigId);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("instantiates a subflow inside a subflow and stops it",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3","4"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"4",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 1","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-2","port":0}]}]},
|
||||
{id:"sf2",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{wires:[]}],"out":[{"wires":[{"id":"sf2","port":0}]}]},
|
||||
{id:"sf1-1",type:"test","z":"sf1",x:166,y:99,"wires":[["sf1-2"]]},
|
||||
{id:"sf1-2",type:"subflow:sf2","z":"sf1",x:166,y:99,"wires":[[]]}
|
||||
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",0);
|
||||
currentNodes["3"].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes["1"].receive({payload:"test"});
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
|
||||
|
||||
|
||||
flow.stop().then(function() {
|
||||
Object.keys(currentNodes).should.have.length(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("rewires nodes specified by diff",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
@@ -371,7 +275,7 @@ describe('Flow', function() {
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]}
|
||||
]);
|
||||
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
createCount.should.equal(0);
|
||||
flow.start();
|
||||
//TODO: use update to pass in new wiring and verify the change
|
||||
@@ -382,72 +286,6 @@ describe('Flow', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
it("rewires a subflow node on update/start",function(done){
|
||||
|
||||
var rawConfig = [
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"4",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-2","port":0}]}]},
|
||||
{id:"sf1-1",type:"test1","z":"sf1",x:166,y:99,"wires":[["sf1-2"]]},
|
||||
{id:"sf1-2",type:"test2","z":"sf1",x:166,y:99,"wires":[[]]}
|
||||
];
|
||||
|
||||
var config = flowUtils.parseConfig(clone(rawConfig));
|
||||
|
||||
rawConfig[2].wires = [["4"]];
|
||||
|
||||
var newConfig = flowUtils.parseConfig(rawConfig);
|
||||
var diff = flowUtils.diffConfigs(config,newConfig);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
Object.keys(activeNodes).should.have.length(6);
|
||||
var sfInstanceId = Object.keys(activeNodes)[4];
|
||||
var sfInstanceId2 = Object.keys(activeNodes)[5];
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",0);
|
||||
currentNodes["3"].should.have.a.property("handled",0);
|
||||
currentNodes["4"].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes["1"].receive({payload:"test"});
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
currentNodes[sfInstanceId].should.have.a.property("handled",1);
|
||||
currentNodes[sfInstanceId2].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",0);
|
||||
|
||||
flow.update(newConfig,newConfig.flows["t1"]);
|
||||
flow.start(diff)
|
||||
|
||||
currentNodes["1"].receive({payload:"test2"});
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",2);
|
||||
currentNodes[sfInstanceId].should.have.a.property("handled",2);
|
||||
currentNodes[sfInstanceId2].should.have.a.property("handled",2);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",1);
|
||||
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
|
||||
|
||||
});
|
||||
|
||||
|
||||
it("instantiates a node with environment variable property values",function(done) {
|
||||
after(function() {
|
||||
delete process.env.NODE_RED_TEST_VALUE;
|
||||
@@ -462,7 +300,7 @@ describe('Flow', function() {
|
||||
{id:"5",x:10,y:10,z:"t1",type:"test",foo:"$(NODE_RED_TEST_VALUE_NONE)",wires:[]},
|
||||
{id:"6",x:10,y:10,z:"t1",type:"test",foo:["$(NODE_RED_TEST_VALUE)"],wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
@@ -492,7 +330,7 @@ describe('Flow', function() {
|
||||
{id:"2",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"asyncTest",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
flow.start();
|
||||
|
||||
|
||||
@@ -518,7 +356,7 @@ describe('Flow', function() {
|
||||
{id:"2",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
flow.start();
|
||||
|
||||
currentNodes.should.have.a.property("1");
|
||||
@@ -536,35 +374,6 @@ describe('Flow', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it("stops subflow instance nodes",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test","z":"sf1",x:166,y:99,"wires":[[]]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
Object.keys(activeNodes).should.have.length(4);
|
||||
var sfInstanceId = Object.keys(activeNodes)[3];
|
||||
flow.stop(["2"]).then(function() {
|
||||
currentNodes.should.not.have.a.property(sfInstanceId);
|
||||
stoppedNodes.should.have.a.property(sfInstanceId);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("Times out a node that fails to close", function(done) {
|
||||
Flow.init({settings:{nodeCloseTimeout:50},log:{
|
||||
log: sinon.stub(),
|
||||
@@ -581,7 +390,7 @@ describe('Flow', function() {
|
||||
{id:"2",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
flow.start();
|
||||
|
||||
currentNodes.should.have.a.property("1");
|
||||
@@ -615,12 +424,7 @@ describe('Flow', function() {
|
||||
{id:"sn",x:10,y:10,z:"t1",type:"status",foo:"a",wires:[]},
|
||||
{id:"sn2",x:10,y:10,z:"t1",type:"status",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
@@ -664,12 +468,7 @@ describe('Flow', function() {
|
||||
{id:"sn",x:10,y:10,z:"t1",type:"status",scope:["2"],foo:"a",wires:[]},
|
||||
{id:"sn2",x:10,y:10,z:"t1",type:"status",scope:["1"],foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
@@ -696,147 +495,6 @@ describe('Flow', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it("passes a status event to the adjacent status node in subflow",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test2","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||
{id:"sf1-sn",x:10,y:10,z:"sf1",type:"status",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
var sfInstanceId = Object.keys(activeNodes)[3];
|
||||
var statusInstanceId = Object.keys(activeNodes)[4];
|
||||
|
||||
flow.handleStatus(activeNodes[sfInstanceId],{text:"my-status"});
|
||||
|
||||
currentNodes[statusInstanceId].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes[statusInstanceId].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","my-status");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id",sfInstanceId);
|
||||
statusMessage.status.source.should.have.a.property("type","test2");
|
||||
statusMessage.status.source.should.have.a.property("name",undefined);
|
||||
flow.stop().then(function() {
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("passes a status event to the multiple adjacent status nodes in subflow",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"4",x:10,y:10,z:"t1",type:"status",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test2","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||
{id:"sf1-sn",x:10,y:10,z:"sf1",type:"status",foo:"a",wires:[]},
|
||||
{id:"sf1-sn2",x:10,y:10,z:"sf1",type:"status",scope:["none"],wires:[]},
|
||||
{id:"sf1-sn3",x:10,y:10,z:"sf1",type:"status",scope:["sf1-1"],wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
var sfInstanceId = Object.keys(activeNodes)[4];
|
||||
var statusInstanceId = Object.keys(activeNodes)[5];
|
||||
var statusInstanceId2 = Object.keys(activeNodes)[6];
|
||||
var statusInstanceId3 = Object.keys(activeNodes)[7];
|
||||
|
||||
flow.handleStatus(activeNodes[sfInstanceId],{text:"my-status"});
|
||||
|
||||
currentNodes[statusInstanceId].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes[statusInstanceId].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","my-status");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id",sfInstanceId);
|
||||
statusMessage.status.source.should.have.a.property("type","test2");
|
||||
statusMessage.status.source.should.have.a.property("name",undefined);
|
||||
|
||||
activeNodes["4"].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes[statusInstanceId2].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes[statusInstanceId3].should.have.a.property("handled",1);
|
||||
statusMessage = currentNodes[statusInstanceId3].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","my-status");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id",sfInstanceId);
|
||||
statusMessage.status.source.should.have.a.property("type","test2");
|
||||
statusMessage.status.source.should.have.a.property("name",undefined);
|
||||
|
||||
flow.stop().then(function() {
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("passes a status event to the subflow's parent tab status node",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test2","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||
{id:"sn",x:10,y:10,z:"t1",type:"status",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
var sfInstanceId = Object.keys(activeNodes)[3];
|
||||
|
||||
flow.handleStatus(activeNodes[sfInstanceId],{text:"my-status"});
|
||||
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","my-status");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("id",sfInstanceId);
|
||||
statusMessage.status.source.should.have.a.property("type","test2");
|
||||
statusMessage.status.source.should.have.a.property("name",undefined);
|
||||
|
||||
flow.stop().then(function() {
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -850,12 +508,7 @@ describe('Flow', function() {
|
||||
{id:"sn",x:10,y:10,z:"t1",type:"catch",foo:"a",wires:[]},
|
||||
{id:"sn2",x:10,y:10,z:"t1",type:"catch",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
@@ -899,12 +552,7 @@ describe('Flow', function() {
|
||||
{id:"sn",x:10,y:10,z:"t1",type:"catch",scope:["2"],foo:"a",wires:[]},
|
||||
{id:"sn2",x:10,y:10,z:"t1",type:"catch",scope:["1"],foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
@@ -930,143 +578,7 @@ describe('Flow', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it("passes an error event to the adjacent catch node in subflow",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test2","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||
{id:"sf1-sn",x:10,y:10,z:"sf1",type:"catch",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
var sfInstanceId = Object.keys(activeNodes)[3];
|
||||
var catchInstanceId = Object.keys(activeNodes)[4];
|
||||
|
||||
flow.handleError(activeNodes[sfInstanceId],"my-error",{a:"foo"});
|
||||
|
||||
currentNodes[catchInstanceId].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes[catchInstanceId].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("error");
|
||||
statusMessage.error.should.have.a.property("message","my-error");
|
||||
statusMessage.error.should.have.a.property("source");
|
||||
statusMessage.error.source.should.have.a.property("id",sfInstanceId);
|
||||
statusMessage.error.source.should.have.a.property("type","test2");
|
||||
statusMessage.error.source.should.have.a.property("name",undefined);
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("passes an error event to the multiple adjacent catch nodes in subflow",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test2","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||
{id:"sf1-sn",x:10,y:10,z:"sf1",type:"catch",foo:"a",wires:[]},
|
||||
{id:"sf1-sn2",x:10,y:10,z:"sf1",type:"catch",scope:["none"],wires:[]},
|
||||
{id:"sf1-sn3",x:10,y:10,z:"sf1",type:"catch",scope:["sf1-1"],wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
var sfInstanceId = Object.keys(activeNodes)[3];
|
||||
var catchInstanceId = Object.keys(activeNodes)[4];
|
||||
var catchInstanceId2 = Object.keys(activeNodes)[5];
|
||||
var catchInstanceId3 = Object.keys(activeNodes)[6];
|
||||
|
||||
flow.handleError(activeNodes[sfInstanceId],"my-error",{a:"foo"});
|
||||
|
||||
currentNodes[catchInstanceId].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes[catchInstanceId].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("error");
|
||||
statusMessage.error.should.have.a.property("message","my-error");
|
||||
statusMessage.error.should.have.a.property("source");
|
||||
statusMessage.error.source.should.have.a.property("id",sfInstanceId);
|
||||
statusMessage.error.source.should.have.a.property("type","test2");
|
||||
statusMessage.error.source.should.have.a.property("name",undefined);
|
||||
|
||||
currentNodes[catchInstanceId2].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes[catchInstanceId3].should.have.a.property("handled",1);
|
||||
statusMessage = currentNodes[catchInstanceId3].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("error");
|
||||
statusMessage.error.should.have.a.property("message","my-error");
|
||||
statusMessage.error.should.have.a.property("source");
|
||||
statusMessage.error.source.should.have.a.property("id",sfInstanceId);
|
||||
statusMessage.error.source.should.have.a.property("type","test2");
|
||||
statusMessage.error.source.should.have.a.property("name",undefined);
|
||||
|
||||
flow.stop().then(function() {
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("passes an error event to the subflow's parent tab catch node",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test2","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||
{id:"sn",x:10,y:10,z:"t1",type:"catch",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
var sfInstanceId = Object.keys(activeNodes)[3];
|
||||
|
||||
flow.handleError(activeNodes[sfInstanceId],"my-error",{a:"foo"});
|
||||
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("error");
|
||||
statusMessage.error.should.have.a.property("message","my-error");
|
||||
statusMessage.error.should.have.a.property("source");
|
||||
statusMessage.error.source.should.have.a.property("id",sfInstanceId);
|
||||
statusMessage.error.source.should.have.a.property("type","test2");
|
||||
statusMessage.error.source.should.have.a.property("name",undefined);
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("moves any existing error object sideways",function(done){
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
@@ -1075,12 +587,7 @@ describe('Flow', function() {
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sn",x:10,y:10,z:"t1",type:"catch",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create(config,config.flows["t1"]);
|
||||
|
||||
getNode.restore();
|
||||
getNode = sinon.stub(flows,"get",function(id) {
|
||||
return flow.getNode(id);
|
||||
});
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
|
460
test/unit/@node-red/runtime/lib/nodes/flows/Subflow_spec.js
Normal file
460
test/unit/@node-red/runtime/lib/nodes/flows/Subflow_spec.js
Normal file
@@ -0,0 +1,460 @@
|
||||
/**
|
||||
* 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 clone = require('clone');
|
||||
var util = require("util");
|
||||
|
||||
var NR_TEST_UTILS = require("nr-test-utils");
|
||||
|
||||
var Subflow = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/flows/Subflow");
|
||||
var Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/flows/Flow");
|
||||
|
||||
var flowUtils = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/flows/util");
|
||||
var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/flows");
|
||||
var Node = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node");
|
||||
var typeRegistry = NR_TEST_UTILS.require("@node-red/registry");
|
||||
|
||||
describe('Subflow', function() {
|
||||
var getType;
|
||||
|
||||
var stoppedNodes = {};
|
||||
var currentNodes = {};
|
||||
var rewiredNodes = {};
|
||||
var createCount = 0;
|
||||
|
||||
beforeEach(function() {
|
||||
currentNodes = {};
|
||||
stoppedNodes = {};
|
||||
rewiredNodes = {};
|
||||
createCount = 0;
|
||||
var runtime = {
|
||||
settings:{},
|
||||
log:{
|
||||
log: sinon.stub(), // function() { console.log("l",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//
|
||||
debug: sinon.stub(), // function() { console.log("d",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//sinon.stub(),
|
||||
trace: sinon.stub(), // function() { console.log("t",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//sinon.stub(),
|
||||
warn: sinon.stub(), // function() { console.log("w",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//sinon.stub(),
|
||||
info: sinon.stub(), // function() { console.log("i",[...arguments].map(a => JSON.stringify(a)).join(" ")) },//sinon.stub(),
|
||||
metric: sinon.stub(),
|
||||
_: function() { return "abc"}
|
||||
}
|
||||
}
|
||||
Flow.init(runtime);
|
||||
Subflow.init(runtime);
|
||||
});
|
||||
|
||||
var TestNode = function(n) {
|
||||
Node.call(this,n);
|
||||
this._index = createCount++;
|
||||
this.scope = n.scope;
|
||||
var node = this;
|
||||
this.foo = n.foo;
|
||||
this.handled = 0;
|
||||
this.stopped = false;
|
||||
currentNodes[node.id] = node;
|
||||
this.on('input',function(msg) {
|
||||
// console.log(this.id,msg.payload);
|
||||
node.handled++;
|
||||
node.send(msg);
|
||||
});
|
||||
this.on('close',function() {
|
||||
node.stopped = true;
|
||||
stoppedNodes[node.id] = node;
|
||||
delete currentNodes[node.id];
|
||||
});
|
||||
this.__updateWires = this.updateWires;
|
||||
this.updateWires = function(newWires) {
|
||||
rewiredNodes[node.id] = node;
|
||||
node.newWires = newWires;
|
||||
node.__updateWires(newWires);
|
||||
};
|
||||
}
|
||||
util.inherits(TestNode,Node);
|
||||
|
||||
var TestErrorNode = function(n) {
|
||||
Node.call(this,n);
|
||||
this._index = createCount++;
|
||||
this.scope = n.scope;
|
||||
this.name = n.name;
|
||||
var node = this;
|
||||
this.foo = n.foo;
|
||||
this.handled = 0;
|
||||
this.stopped = false;
|
||||
currentNodes[node.id] = node;
|
||||
this.on('input',function(msg) {
|
||||
node.handled++;
|
||||
node.error("test error",msg);
|
||||
});
|
||||
this.on('close',function() {
|
||||
node.stopped = true;
|
||||
stoppedNodes[node.id] = node;
|
||||
delete currentNodes[node.id];
|
||||
});
|
||||
this.__updateWires = this.updateWires;
|
||||
this.updateWires = function(newWires) {
|
||||
rewiredNodes[node.id] = node;
|
||||
node.newWires = newWires;
|
||||
node.__updateWires(newWires);
|
||||
};
|
||||
}
|
||||
util.inherits(TestErrorNode,Node);
|
||||
|
||||
|
||||
var TestStatusNode = function(n) {
|
||||
Node.call(this,n);
|
||||
this._index = createCount++;
|
||||
this.scope = n.scope;
|
||||
this.name = n.name;
|
||||
var node = this;
|
||||
this.foo = n.foo;
|
||||
this.handled = 0;
|
||||
this.stopped = false;
|
||||
currentNodes[node.id] = node;
|
||||
this.on('input',function(msg) {
|
||||
node.handled++;
|
||||
node.status({text:"test status"});
|
||||
});
|
||||
this.on('close',function() {
|
||||
node.stopped = true;
|
||||
stoppedNodes[node.id] = node;
|
||||
delete currentNodes[node.id];
|
||||
});
|
||||
this.__updateWires = this.updateWires;
|
||||
this.updateWires = function(newWires) {
|
||||
rewiredNodes[node.id] = node;
|
||||
node.newWires = newWires;
|
||||
node.__updateWires(newWires);
|
||||
};
|
||||
}
|
||||
util.inherits(TestStatusNode,Node);
|
||||
|
||||
var TestAsyncNode = function(n) {
|
||||
Node.call(this,n);
|
||||
var node = this;
|
||||
this.scope = n.scope;
|
||||
this.foo = n.foo;
|
||||
this.handled = 0;
|
||||
this.messages = [];
|
||||
this.stopped = false;
|
||||
this.closeDelay = n.closeDelay || 50;
|
||||
currentNodes[node.id] = node;
|
||||
this.on('input',function(msg) {
|
||||
node.handled++;
|
||||
node.messages.push(msg);
|
||||
node.send(msg);
|
||||
});
|
||||
this.on('close',function(done) {
|
||||
setTimeout(function() {
|
||||
node.stopped = true;
|
||||
stoppedNodes[node.id] = node;
|
||||
delete currentNodes[node.id];
|
||||
done();
|
||||
},node.closeDelay);
|
||||
});
|
||||
}
|
||||
util.inherits(TestAsyncNode,Node);
|
||||
|
||||
before(function() {
|
||||
getType = sinon.stub(typeRegistry,"get",function(type) {
|
||||
if (type=="test") {
|
||||
return TestNode;
|
||||
} else if (type=="testError"){
|
||||
return TestErrorNode;
|
||||
} else if (type=="testStatus"){
|
||||
return TestStatusNode;
|
||||
} else {
|
||||
return TestAsyncNode;
|
||||
}
|
||||
});
|
||||
});
|
||||
after(function() {
|
||||
getType.restore();
|
||||
});
|
||||
describe('#start',function() {
|
||||
it("instantiates a subflow and stops it",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3","4"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"4",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-2","port":0}]},{"wires":[{"id":"sf1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test","z":"sf1",x:166,y:99,"wires":[["sf1-2"]]},
|
||||
{id:"sf1-2",type:"test","z":"sf1",foo:"sf1-cn",x:166,y:99,"wires":[[]]},
|
||||
{id:"sf1-cn",type:"test","z":"sf1"}
|
||||
]);
|
||||
var flow = Flow.create({handleError: (a,b,c) => { console.log(a,b,c); }},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
Object.keys(activeNodes).should.have.length(4);
|
||||
// var sfInstanceId = Object.keys(activeNodes)[5];
|
||||
// var sfInstanceId2 = Object.keys(activeNodes)[6];
|
||||
var sfConfigId = Object.keys(activeNodes)[4];
|
||||
|
||||
flow.getNode('1').should.have.a.property('id','1');
|
||||
flow.getNode('2').should.have.a.property('id','2');
|
||||
flow.getNode('3').should.have.a.property('id','3');
|
||||
flow.getNode('4').should.have.a.property('id','4');
|
||||
// flow.getNode(sfInstanceId).should.have.a.property('id',sfInstanceId);
|
||||
// flow.getNode(sfInstanceId2).should.have.a.property('id',sfInstanceId2);
|
||||
// flow.getNode(sfConfigId).should.have.a.property('id',sfConfigId);
|
||||
|
||||
// flow.getNode(sfInstanceId2).should.have.a.property('foo',sfConfigId);
|
||||
|
||||
Object.keys(currentNodes).should.have.length(6);
|
||||
|
||||
currentNodes.should.have.a.property("1");
|
||||
currentNodes.should.not.have.a.property("2");
|
||||
currentNodes.should.have.a.property("3");
|
||||
currentNodes.should.have.a.property("4");
|
||||
// currentNodes.should.have.a.property(sfInstanceId);
|
||||
// currentNodes.should.have.a.property(sfInstanceId2);
|
||||
// currentNodes.should.have.a.property(sfConfigId);
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",0);
|
||||
currentNodes["3"].should.have.a.property("handled",0);
|
||||
currentNodes["4"].should.have.a.property("handled",0);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",0);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes["1"].receive({payload:"test"});
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",1);
|
||||
|
||||
|
||||
|
||||
flow.stop().then(function() {
|
||||
Object.keys(currentNodes).should.have.length(0);
|
||||
Object.keys(stoppedNodes).should.have.length(6);
|
||||
|
||||
// currentNodes.should.not.have.a.property("1");
|
||||
// currentNodes.should.not.have.a.property("3");
|
||||
// currentNodes.should.not.have.a.property("4");
|
||||
// // currentNodes.should.not.have.a.property(sfInstanceId);
|
||||
// // currentNodes.should.not.have.a.property(sfInstanceId2);
|
||||
// // currentNodes.should.not.have.a.property(sfConfigId);
|
||||
// stoppedNodes.should.have.a.property("1");
|
||||
// stoppedNodes.should.have.a.property("3");
|
||||
// stoppedNodes.should.have.a.property("4");
|
||||
// // stoppedNodes.should.have.a.property(sfInstanceId);
|
||||
// // stoppedNodes.should.have.a.property(sfInstanceId2);
|
||||
// // stoppedNodes.should.have.a.property(sfConfigId);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it("instantiates a subflow inside a subflow and stops it",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3","4"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"4",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 1","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-2","port":0}]}]},
|
||||
{id:"sf2",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{wires:[]}],"out":[{"wires":[{"id":"sf2","port":0}]}]},
|
||||
{id:"sf1-1",type:"test","z":"sf1",x:166,y:99,"wires":[["sf1-2"]]},
|
||||
{id:"sf1-2",type:"subflow:sf2","z":"sf1",x:166,y:99,"wires":[[]]}
|
||||
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",0);
|
||||
currentNodes["3"].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes["1"].receive({payload:"test"});
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
|
||||
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
|
||||
|
||||
|
||||
flow.stop().then(function() {
|
||||
Object.keys(currentNodes).should.have.length(0);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("rewires a subflow node on update/start",function(done){
|
||||
|
||||
var rawConfig = [
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"4",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-2","port":0}]}]},
|
||||
{id:"sf1-1",type:"test1","z":"sf1",x:166,y:99,"wires":[["sf1-2"]]},
|
||||
{id:"sf1-2",type:"test2","z":"sf1",x:166,y:99,"wires":[[]]}
|
||||
];
|
||||
|
||||
var config = flowUtils.parseConfig(clone(rawConfig));
|
||||
|
||||
rawConfig[2].wires = [["4"]];
|
||||
|
||||
var newConfig = flowUtils.parseConfig(rawConfig);
|
||||
var diff = flowUtils.diffConfigs(config,newConfig);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
Object.keys(activeNodes).should.have.length(4);
|
||||
// var sfInstanceId = Object.keys(activeNodes)[4];
|
||||
// var sfInstanceId2 = Object.keys(activeNodes)[5];
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",0);
|
||||
currentNodes["3"].should.have.a.property("handled",0);
|
||||
currentNodes["4"].should.have.a.property("handled",0);
|
||||
|
||||
currentNodes["1"].receive({payload:"test"});
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",1);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",1);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",0);
|
||||
|
||||
flow.update(newConfig,newConfig.flows["t1"]);
|
||||
flow.start(diff)
|
||||
|
||||
currentNodes["1"].receive({payload:"test2"});
|
||||
|
||||
currentNodes["1"].should.have.a.property("handled",2);
|
||||
// currentNodes[sfInstanceId].should.have.a.property("handled",2);
|
||||
// currentNodes[sfInstanceId2].should.have.a.property("handled",2);
|
||||
currentNodes["3"].should.have.a.property("handled",1);
|
||||
currentNodes["4"].should.have.a.property("handled",1);
|
||||
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#stop', function() {
|
||||
it("stops subflow instance nodes",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",type:"test","z":"sf1",x:166,y:99,"wires":[[]]}
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
Object.keys(activeNodes).should.have.length(3);
|
||||
Object.keys(stoppedNodes).should.have.length(0);
|
||||
flow.stop(["2"]).then(function() {
|
||||
Object.keys(currentNodes).should.have.length(2);
|
||||
Object.keys(stoppedNodes).should.have.length(1);
|
||||
done();
|
||||
}).catch(done);
|
||||
});
|
||||
});
|
||||
describe("#handleStatus",function() {
|
||||
it("passes a status event to the subflow's parent tab status node",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",type:"testStatus",name:"test-status-node","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||
{id:"sn",x:10,y:10,z:"t1",type:"status",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].receive({payload:"test"});
|
||||
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("status");
|
||||
statusMessage.status.should.have.a.property("text","test status");
|
||||
statusMessage.status.should.have.a.property("source");
|
||||
statusMessage.status.source.should.have.a.property("type","testStatus");
|
||||
statusMessage.status.source.should.have.a.property("name","test-status-node");
|
||||
|
||||
flow.stop().then(function() {
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("#handleError",function() {
|
||||
it("passes an error event to the subflow's parent tab catch node",function(done) {
|
||||
var config = flowUtils.parseConfig([
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"1",x:10,y:10,z:"t1",type:"test",name:"a",wires:["2"]},
|
||||
{id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
|
||||
{id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
|
||||
{id:"sf1",type:"subflow","name":"Subflow 2","info":"",
|
||||
"in":[{"wires":[{"id":"sf1-1"}]}],"out":[{"wires":[{"id":"sf1-1","port":0}]}]},
|
||||
{id:"sf1-1",name:"test-error-node",type:"testError","z":"sf1",x:166,y:99,"wires":[[]]},
|
||||
{id:"sn",x:10,y:10,z:"t1",type:"catch",foo:"a",wires:[]}
|
||||
]);
|
||||
var flow = Flow.create({},config,config.flows["t1"]);
|
||||
|
||||
flow.start();
|
||||
|
||||
var activeNodes = flow.getActiveNodes();
|
||||
|
||||
activeNodes["1"].receive({payload:"test"});
|
||||
|
||||
currentNodes["sn"].should.have.a.property("handled",1);
|
||||
var statusMessage = currentNodes["sn"].messages[0];
|
||||
|
||||
statusMessage.should.have.a.property("error");
|
||||
statusMessage.error.should.have.a.property("message","test error");
|
||||
statusMessage.error.should.have.a.property("source");
|
||||
statusMessage.error.source.should.have.a.property("type","testError");
|
||||
statusMessage.error.source.should.have.a.property("name","test-error-node");
|
||||
|
||||
flow.stop().then(function() {
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
});
|
@@ -70,7 +70,7 @@ describe('flows/index', function() {
|
||||
credentialsLoad = sinon.stub(credentials,"load",function() {
|
||||
return when.resolve();
|
||||
});
|
||||
flowCreate = sinon.stub(Flow,"create",function(global, flow) {
|
||||
flowCreate = sinon.stub(Flow,"create",function(parent, global, flow) {
|
||||
var id;
|
||||
if (typeof flow === 'undefined') {
|
||||
flow = global;
|
||||
@@ -354,113 +354,113 @@ describe('flows/index', function() {
|
||||
describe('#stopFlows', function() {
|
||||
|
||||
});
|
||||
describe('#handleError', function() {
|
||||
it('passes error to correct flow', function(done) {
|
||||
var originalConfig = [
|
||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
||||
{id:"t1",type:"tab"}
|
||||
];
|
||||
storage.getFlows = function() {
|
||||
return when.resolve({flows:originalConfig});
|
||||
}
|
||||
|
||||
events.once('nodes-started',function() {
|
||||
flows.handleError(originalConfig[0],"message",{});
|
||||
flowCreate.flows['t1'].handleError.called.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
flows.init({log:mockLog, settings:{},storage:storage});
|
||||
flows.load().then(function() {
|
||||
flows.startFlows();
|
||||
});
|
||||
});
|
||||
it('passes error to flows that use the originating global config', function(done) {
|
||||
var originalConfig = [
|
||||
{id:"configNode",type:"test"},
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",config:"configNode",wires:[]},
|
||||
{id:"t2",type:"tab"},
|
||||
{id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]},
|
||||
{id:"t3",type:"tab"},
|
||||
{id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]}
|
||||
];
|
||||
storage.getFlows = function() {
|
||||
return when.resolve({flows:originalConfig});
|
||||
}
|
||||
|
||||
events.once('nodes-started',function() {
|
||||
flows.handleError(originalConfig[0],"message",{});
|
||||
try {
|
||||
flowCreate.flows['t1'].handleError.called.should.be.true();
|
||||
flowCreate.flows['t2'].handleError.called.should.be.false();
|
||||
flowCreate.flows['t3'].handleError.called.should.be.true();
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
|
||||
flows.init({log:mockLog, settings:{},storage:storage});
|
||||
flows.load().then(function() {
|
||||
flows.startFlows();
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('#handleStatus', function() {
|
||||
it('passes status to correct flow', function(done) {
|
||||
var originalConfig = [
|
||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
||||
{id:"t1",type:"tab"}
|
||||
];
|
||||
storage.getFlows = function() {
|
||||
return when.resolve({flows:originalConfig});
|
||||
}
|
||||
|
||||
events.once('nodes-started',function() {
|
||||
flows.handleStatus(originalConfig[0],"message");
|
||||
flowCreate.flows['t1'].handleStatus.called.should.be.true();
|
||||
done();
|
||||
});
|
||||
|
||||
flows.init({log:mockLog, settings:{},storage:storage});
|
||||
flows.load().then(function() {
|
||||
flows.startFlows();
|
||||
});
|
||||
});
|
||||
|
||||
it('passes status to flows that use the originating global config', function(done) {
|
||||
var originalConfig = [
|
||||
{id:"configNode",type:"test"},
|
||||
{id:"t1",type:"tab"},
|
||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",config:"configNode",wires:[]},
|
||||
{id:"t2",type:"tab"},
|
||||
{id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]},
|
||||
{id:"t3",type:"tab"},
|
||||
{id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]}
|
||||
];
|
||||
storage.getFlows = function() {
|
||||
return when.resolve({flows:originalConfig});
|
||||
}
|
||||
|
||||
events.once('nodes-started',function() {
|
||||
flows.handleStatus(originalConfig[0],"message");
|
||||
try {
|
||||
flowCreate.flows['t1'].handleStatus.called.should.be.true();
|
||||
flowCreate.flows['t2'].handleStatus.called.should.be.false();
|
||||
flowCreate.flows['t3'].handleStatus.called.should.be.true();
|
||||
done();
|
||||
} catch(err) {
|
||||
done(err);
|
||||
}
|
||||
});
|
||||
|
||||
flows.init({log:mockLog, settings:{},storage:storage});
|
||||
flows.load().then(function() {
|
||||
flows.startFlows();
|
||||
});
|
||||
});
|
||||
});
|
||||
// describe('#handleError', function() {
|
||||
// it('passes error to correct flow', function(done) {
|
||||
// var originalConfig = [
|
||||
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
||||
// {id:"t1",type:"tab"}
|
||||
// ];
|
||||
// storage.getFlows = function() {
|
||||
// return when.resolve({flows:originalConfig});
|
||||
// }
|
||||
//
|
||||
// events.once('nodes-started',function() {
|
||||
// flows.handleError(originalConfig[0],"message",{});
|
||||
// flowCreate.flows['t1'].handleError.called.should.be.true();
|
||||
// done();
|
||||
// });
|
||||
//
|
||||
// flows.init({log:mockLog, settings:{},storage:storage});
|
||||
// flows.load().then(function() {
|
||||
// flows.startFlows();
|
||||
// });
|
||||
// });
|
||||
// it('passes error to flows that use the originating global config', function(done) {
|
||||
// var originalConfig = [
|
||||
// {id:"configNode",type:"test"},
|
||||
// {id:"t1",type:"tab"},
|
||||
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",config:"configNode",wires:[]},
|
||||
// {id:"t2",type:"tab"},
|
||||
// {id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]},
|
||||
// {id:"t3",type:"tab"},
|
||||
// {id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]}
|
||||
// ];
|
||||
// storage.getFlows = function() {
|
||||
// return when.resolve({flows:originalConfig});
|
||||
// }
|
||||
//
|
||||
// events.once('nodes-started',function() {
|
||||
// flows.handleError(originalConfig[0],"message",{});
|
||||
// try {
|
||||
// flowCreate.flows['t1'].handleError.called.should.be.true();
|
||||
// flowCreate.flows['t2'].handleError.called.should.be.false();
|
||||
// flowCreate.flows['t3'].handleError.called.should.be.true();
|
||||
// done();
|
||||
// } catch(err) {
|
||||
// done(err);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// flows.init({log:mockLog, settings:{},storage:storage});
|
||||
// flows.load().then(function() {
|
||||
// flows.startFlows();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
// describe('#handleStatus', function() {
|
||||
// it('passes status to correct flow', function(done) {
|
||||
// var originalConfig = [
|
||||
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
||||
// {id:"t1",type:"tab"}
|
||||
// ];
|
||||
// storage.getFlows = function() {
|
||||
// return when.resolve({flows:originalConfig});
|
||||
// }
|
||||
//
|
||||
// events.once('nodes-started',function() {
|
||||
// flows.handleStatus(originalConfig[0],"message");
|
||||
// flowCreate.flows['t1'].handleStatus.called.should.be.true();
|
||||
// done();
|
||||
// });
|
||||
//
|
||||
// flows.init({log:mockLog, settings:{},storage:storage});
|
||||
// flows.load().then(function() {
|
||||
// flows.startFlows();
|
||||
// });
|
||||
// });
|
||||
//
|
||||
// it('passes status to flows that use the originating global config', function(done) {
|
||||
// var originalConfig = [
|
||||
// {id:"configNode",type:"test"},
|
||||
// {id:"t1",type:"tab"},
|
||||
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",config:"configNode",wires:[]},
|
||||
// {id:"t2",type:"tab"},
|
||||
// {id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]},
|
||||
// {id:"t3",type:"tab"},
|
||||
// {id:"t3-1",x:10,y:10,z:"t3",type:"test",config:"configNode",wires:[]}
|
||||
// ];
|
||||
// storage.getFlows = function() {
|
||||
// return when.resolve({flows:originalConfig});
|
||||
// }
|
||||
//
|
||||
// events.once('nodes-started',function() {
|
||||
// flows.handleStatus(originalConfig[0],"message");
|
||||
// try {
|
||||
// flowCreate.flows['t1'].handleStatus.called.should.be.true();
|
||||
// flowCreate.flows['t2'].handleStatus.called.should.be.false();
|
||||
// flowCreate.flows['t3'].handleStatus.called.should.be.true();
|
||||
// done();
|
||||
// } catch(err) {
|
||||
// done(err);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// flows.init({log:mockLog, settings:{},storage:storage});
|
||||
// flows.load().then(function() {
|
||||
// flows.startFlows();
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
|
||||
describe('#checkTypeInUse', function() {
|
||||
|
||||
|
Reference in New Issue
Block a user