2015-01-15 18:10:32 +01:00
|
|
|
/**
|
|
|
|
* Copyright 2015 IBM Corp.
|
|
|
|
*
|
|
|
|
* 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 Flow = require("../../../red/nodes/Flow");
|
|
|
|
|
|
|
|
var typeRegistry = require("../../../red/nodes/registry");
|
|
|
|
var credentials = require("../../../red/nodes/credentials");
|
|
|
|
|
|
|
|
|
|
|
|
describe('Flow', function() {
|
|
|
|
describe('#constructor',function() {
|
|
|
|
it('called with an empty flow',function() {
|
|
|
|
var config = [];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
config.should.eql(flow.getFlow());
|
|
|
|
|
|
|
|
var nodeCount = 0;
|
|
|
|
flow.eachNode(function(node) {
|
|
|
|
nodeCount++;
|
|
|
|
});
|
|
|
|
|
|
|
|
nodeCount.should.equal(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('called with a non-empty flow with no missing types', function() {
|
|
|
|
var getType = sinon.stub(typeRegistry,"get",function(type) {
|
|
|
|
// For this test, don't care what the actual type is, just
|
|
|
|
// that this returns a non-false result
|
|
|
|
return {};
|
|
|
|
});
|
|
|
|
try {
|
|
|
|
var config = [{id:"123",type:"test"}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
config.should.eql(flow.getFlow());
|
|
|
|
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
} finally {
|
|
|
|
getType.restore();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
it('identifies missing types in a flow', function() {
|
|
|
|
var getType = sinon.stub(typeRegistry,"get",function(type) {
|
|
|
|
if (type == "test") {
|
|
|
|
return {};
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
try {
|
|
|
|
var config = [{id:"123",type:"test"},{id:"456",type:"test1"},{id:"789",type:"test2"}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
config.should.eql(flow.getFlow());
|
|
|
|
|
|
|
|
flow.getMissingTypes().should.eql(["test1","test2"]);
|
|
|
|
} finally {
|
|
|
|
getType.restore();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
it('extracts node credentials', function() {
|
|
|
|
var getType = sinon.stub(typeRegistry,"get",function(type) {
|
|
|
|
// For this test, don't care what the actual type is, just
|
|
|
|
// that this returns a non-false result
|
|
|
|
return {};
|
|
|
|
});
|
|
|
|
|
|
|
|
try {
|
|
|
|
var config = [{id:"123",type:"test",credentials:{a:1,b:2}}];
|
|
|
|
var resultingConfig = clone(config);
|
|
|
|
delete resultingConfig[0].credentials;
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getFlow().should.eql(resultingConfig);
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
} finally {
|
|
|
|
getType.restore();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
describe('#start',function() {
|
|
|
|
|
|
|
|
it('prevents a flow with missing types from starting', function() {
|
|
|
|
var getType = sinon.stub(typeRegistry,"get",function(type) {
|
|
|
|
if (type == "test") {
|
|
|
|
return {};
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
try {
|
|
|
|
var config = [{id:"123",type:"test"},{id:"456",type:"test1"},{id:"789",type:"test2"}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getMissingTypes().should.have.length(2);
|
|
|
|
|
|
|
|
/*jshint immed: false */
|
|
|
|
(function() {
|
|
|
|
flow.start();
|
|
|
|
}).should.throw();
|
|
|
|
} finally {
|
|
|
|
getType.restore();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('missing types',function() {
|
|
|
|
it('removes missing types as they are registered', function() {
|
|
|
|
var getType = sinon.stub(typeRegistry,"get",function(type) {
|
|
|
|
if (type == "test") {
|
|
|
|
return {};
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
var flowStart;
|
|
|
|
try {
|
|
|
|
var config = [{id:"123",type:"test"},{id:"456",type:"test1"},{id:"789",type:"test2"}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
|
|
|
|
flowStart = sinon.stub(flow,"start",function() {this.started = true;});
|
|
|
|
config.should.eql(flow.getFlow());
|
|
|
|
|
|
|
|
flow.getMissingTypes().should.eql(["test1","test2"]);
|
|
|
|
|
|
|
|
flow.typeRegistered("test1");
|
|
|
|
flow.getMissingTypes().should.eql(["test2"]);
|
|
|
|
flowStart.called.should.be.false;
|
|
|
|
|
|
|
|
flow.typeRegistered("test2");
|
|
|
|
flow.getMissingTypes().should.eql([]);
|
|
|
|
flowStart.called.should.be.false;
|
|
|
|
} finally {
|
|
|
|
flowStart.restore();
|
|
|
|
getType.restore();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
it('starts flows once all missing types are registered', function() {
|
|
|
|
var getType = sinon.stub(typeRegistry,"get",function(type) {
|
|
|
|
if (type == "test") {
|
|
|
|
return {};
|
|
|
|
} else {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
var flowStart;
|
|
|
|
try {
|
|
|
|
var config = [{id:"123",type:"test"},{id:"456",type:"test1"},{id:"789",type:"test2"}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
|
|
|
|
// First call to .start throws err due to missing types
|
|
|
|
/*jshint immed: false */
|
|
|
|
(function() {
|
|
|
|
flow.start();
|
|
|
|
}).should.throw();
|
|
|
|
|
|
|
|
// Stub .start so when missing types are registered, we don't actually try starting them
|
|
|
|
flowStart = sinon.stub(flow,"start",function() {});
|
|
|
|
config.should.eql(flow.getFlow());
|
|
|
|
|
|
|
|
flow.getMissingTypes().should.eql(["test1","test2"]);
|
|
|
|
|
|
|
|
flow.typeRegistered("test1");
|
|
|
|
flow.typeRegistered("test2");
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
flowStart.called.should.be.true;
|
|
|
|
} finally {
|
|
|
|
flowStart.restore();
|
|
|
|
getType.restore();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('#diffFlow',function() {
|
|
|
|
var getType;
|
|
|
|
before(function() {
|
|
|
|
getType = sinon.stub(typeRegistry,"get",function(type) {
|
|
|
|
// For this test, don't care what the actual type is, just
|
|
|
|
// that this returns a non-false result
|
|
|
|
return {};
|
|
|
|
});
|
|
|
|
|
|
|
|
});
|
|
|
|
after(function() {
|
|
|
|
getType.restore();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('handles an identical configuration', function() {
|
|
|
|
var config = [{id:"123",type:"test",foo:"a",wires:[]}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
|
|
|
|
var diffResult = flow.diffFlow(config);
|
|
|
|
|
|
|
|
diffResult.should.have.property("deleted",[]);
|
|
|
|
diffResult.should.have.property("changed",[]);
|
|
|
|
diffResult.should.have.property("linked",[]);
|
|
|
|
diffResult.should.have.property("wiringChanged",[]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('identifies nodes with changed properties, including downstream linked', function() {
|
|
|
|
var config = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"b",wires:[[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var newConfig = [{id:"1",type:"test",foo:"b",wires:[]},{id:"2",type:"test",bar:"b",wires:[[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
|
|
|
|
var diffResult = flow.diffFlow(newConfig);
|
|
|
|
|
|
|
|
diffResult.should.have.property("deleted",[]);
|
|
|
|
diffResult.should.have.property("changed",["1"]);
|
|
|
|
diffResult.should.have.property("linked",["2"]);
|
|
|
|
diffResult.should.have.property("wiringChanged",[]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('identifies nodes with changed properties, including upstream linked', function() {
|
|
|
|
var config = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"b",wires:[[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var newConfig = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"c",wires:[[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
|
|
|
|
var diffResult = flow.diffFlow(newConfig);
|
|
|
|
|
|
|
|
diffResult.should.have.property("deleted",[]);
|
|
|
|
diffResult.should.have.property("changed",["2"]);
|
|
|
|
diffResult.should.have.property("linked",["1"]);
|
|
|
|
diffResult.should.have.property("wiringChanged",[]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('identifies nodes with changed wiring', function() {
|
|
|
|
var config = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"b",wires:[[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var newConfig = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"b",wires:[[2]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
|
|
|
|
var diffResult = flow.diffFlow(newConfig);
|
|
|
|
|
|
|
|
diffResult.should.have.property("deleted",[]);
|
|
|
|
diffResult.should.have.property("changed",[]);
|
|
|
|
diffResult.should.have.property("linked",["1","2"]);
|
|
|
|
diffResult.should.have.property("wiringChanged",["2"]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('identifies nodes with changed wiring - second connection added', function() {
|
|
|
|
var config = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"b",wires:[[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var newConfig = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"b",wires:[[1],[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
|
|
|
|
var diffResult = flow.diffFlow(newConfig);
|
|
|
|
|
|
|
|
diffResult.should.have.property("deleted",[]);
|
|
|
|
diffResult.should.have.property("changed",[]);
|
|
|
|
diffResult.should.have.property("linked",["1","2"]);
|
|
|
|
diffResult.should.have.property("wiringChanged",["2"]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('identifies nodes with changed wiring - second connection removed', function() {
|
|
|
|
var config = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"b",wires:[[1],[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var newConfig = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"b",wires:[[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
|
|
|
|
var diffResult = flow.diffFlow(newConfig);
|
|
|
|
|
|
|
|
diffResult.should.have.property("deleted",[]);
|
|
|
|
diffResult.should.have.property("changed",[]);
|
|
|
|
diffResult.should.have.property("linked",["1","2"]);
|
|
|
|
diffResult.should.have.property("wiringChanged",["2"]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('identifies new nodes', function() {
|
|
|
|
var config = [{id:"1",type:"test",foo:"a",wires:[]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var newConfig = [{id:"1",type:"test",foo:"a",wires:[]},{id:"2",type:"test",bar:"b",wires:[[1]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
|
|
|
|
var diffResult = flow.diffFlow(newConfig);
|
|
|
|
|
|
|
|
diffResult.should.have.property("deleted",[]);
|
|
|
|
diffResult.should.have.property("changed",["2"]);
|
|
|
|
diffResult.should.have.property("linked",["1"]);
|
|
|
|
diffResult.should.have.property("wiringChanged",[]);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('identifies deleted nodes', function() {
|
|
|
|
var config = [{id:"1",type:"test",foo:"a",wires:[[2]]},{id:"2",type:"test",bar:"b",wires:[[3]]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var newConfig = [{id:"1",type:"test",foo:"a",wires:[]},{id:"3",type:"test",foo:"a",wires:[]}];
|
|
|
|
var flow = new Flow(config);
|
|
|
|
flow.getMissingTypes().should.have.length(0);
|
|
|
|
|
|
|
|
var diffResult = flow.diffFlow(newConfig);
|
|
|
|
|
|
|
|
diffResult.should.have.property("deleted",["2"]);
|
|
|
|
diffResult.should.have.property("changed",[]);
|
|
|
|
diffResult.should.have.property("linked",["1","3"]);
|
|
|
|
diffResult.should.have.property("wiringChanged",["1"]);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|