mirror of https://github.com/node-red/node-red.git
				
				
				
			
		
			
				
	
	
		
			616 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
			
		
		
	
	
			616 lines
		
	
	
		
			23 KiB
		
	
	
	
		
			JavaScript
		
	
	
/**
 | 
						|
 * 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 NR_TEST_UTILS = require("nr-test-utils");
 | 
						|
 | 
						|
var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows");
 | 
						|
var RedNode = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node");
 | 
						|
var RED = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes");
 | 
						|
var events = NR_TEST_UTILS.require("@node-red/util/lib/events");
 | 
						|
var credentials = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/credentials");
 | 
						|
var typeRegistry = NR_TEST_UTILS.require("@node-red/registry")
 | 
						|
var Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Flow");
 | 
						|
 | 
						|
describe('flows/index', function() {
 | 
						|
 | 
						|
    var storage;
 | 
						|
    var eventsOn;
 | 
						|
    var credentialsClean;
 | 
						|
    var credentialsLoad;
 | 
						|
 | 
						|
    var flowCreate;
 | 
						|
    var getType;
 | 
						|
 | 
						|
    var mockLog = {
 | 
						|
        log: sinon.stub(),
 | 
						|
        debug: sinon.stub(),
 | 
						|
        trace: sinon.stub(),
 | 
						|
        warn: sinon.stub(),
 | 
						|
        info: sinon.stub(),
 | 
						|
        metric: sinon.stub(),
 | 
						|
        _: function() { return "abc"}
 | 
						|
    }
 | 
						|
 | 
						|
 | 
						|
    before(function() {
 | 
						|
        getType = sinon.stub(typeRegistry,"get",function(type) {
 | 
						|
            return type.indexOf('missing') === -1;
 | 
						|
        });
 | 
						|
    });
 | 
						|
    after(function() {
 | 
						|
        getType.restore();
 | 
						|
    });
 | 
						|
 | 
						|
 | 
						|
    beforeEach(function() {
 | 
						|
        eventsOn = sinon.spy(events,"on");
 | 
						|
        credentialsClean = sinon.stub(credentials,"clean",function(conf) {
 | 
						|
            conf.forEach(function(n) {
 | 
						|
                delete n.credentials;
 | 
						|
            });
 | 
						|
            return Promise.resolve();
 | 
						|
        });
 | 
						|
        credentialsLoad = sinon.stub(credentials,"load",function(creds) {
 | 
						|
            if (creds && creds.hasOwnProperty("$") && creds['$'] === "fail") {
 | 
						|
                return Promise.reject("creds error");
 | 
						|
            }
 | 
						|
            return Promise.resolve();
 | 
						|
        });
 | 
						|
        flowCreate = sinon.stub(Flow,"create",function(parent, global, flow) {
 | 
						|
            var id;
 | 
						|
            if (typeof flow === 'undefined') {
 | 
						|
                flow = global;
 | 
						|
                id = '_GLOBAL_';
 | 
						|
            } else {
 | 
						|
                id = flow.id;
 | 
						|
            }
 | 
						|
            flowCreate.flows[id] = {
 | 
						|
                flow: flow,
 | 
						|
                global: global,
 | 
						|
                start: sinon.spy(),
 | 
						|
                update: sinon.spy(),
 | 
						|
                stop: sinon.spy(),
 | 
						|
                getActiveNodes: function() {
 | 
						|
                    return flow.nodes||{};
 | 
						|
                },
 | 
						|
                handleError: sinon.spy(),
 | 
						|
                handleStatus: sinon.spy()
 | 
						|
 | 
						|
            }
 | 
						|
            return flowCreate.flows[id];
 | 
						|
        });
 | 
						|
        flowCreate.flows = {};
 | 
						|
 | 
						|
        storage = {
 | 
						|
            saveFlows: function(conf) {
 | 
						|
                storage.conf = conf;
 | 
						|
                return Promise.resolve();
 | 
						|
            }
 | 
						|
        }
 | 
						|
    });
 | 
						|
 | 
						|
    afterEach(function(done) {
 | 
						|
        eventsOn.restore();
 | 
						|
        credentialsClean.restore();
 | 
						|
        credentialsLoad.restore();
 | 
						|
        flowCreate.restore();
 | 
						|
 | 
						|
        flows.stopFlows().then(done);
 | 
						|
 | 
						|
    });
 | 
						|
    // describe('#init',function() {
 | 
						|
    //     it('registers the type-registered handler', function() {
 | 
						|
    //         flows.init({},{});
 | 
						|
    //         eventsOn.calledOnce.should.be.true();
 | 
						|
    //     });
 | 
						|
    // });
 | 
						|
 | 
						|
    describe('#setFlows', function() {
 | 
						|
        it('sets the full flow', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.setFlows(originalConfig).then(function() {
 | 
						|
                credentialsClean.called.should.be.true();
 | 
						|
                storage.hasOwnProperty('conf').should.be.true();
 | 
						|
                flows.getFlows().flows.should.eql(originalConfig);
 | 
						|
                done();
 | 
						|
            });
 | 
						|
 | 
						|
        });
 | 
						|
        it('loads the full flow for type load', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            var loadStorage = {
 | 
						|
                saveFlows: function(conf) {
 | 
						|
                    loadStorage.conf = conf;
 | 
						|
                    return Promise.resolve(456);
 | 
						|
                },
 | 
						|
                getFlows: function() {
 | 
						|
                    return Promise.resolve({flows:originalConfig,rev:123})
 | 
						|
                }
 | 
						|
            }
 | 
						|
            flows.init({log:mockLog, settings:{},storage:loadStorage});
 | 
						|
            flows.setFlows(originalConfig,"load").then(function() {
 | 
						|
                credentialsClean.called.should.be.false();
 | 
						|
                // 'load' type does not trigger a save
 | 
						|
                loadStorage.hasOwnProperty('conf').should.be.false();
 | 
						|
                flows.getFlows().flows.should.eql(originalConfig);
 | 
						|
                done();
 | 
						|
            });
 | 
						|
 | 
						|
        });
 | 
						|
 | 
						|
        it('extracts credentials from the full flow', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[],credentials:{"a":1}},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.setFlows(originalConfig).then(function() {
 | 
						|
                credentialsClean.called.should.be.true();
 | 
						|
                storage.hasOwnProperty('conf').should.be.true();
 | 
						|
                var cleanedFlows = flows.getFlows();
 | 
						|
                storage.conf.flows.should.eql(cleanedFlows.flows);
 | 
						|
                cleanedFlows.flows.should.not.eql(originalConfig);
 | 
						|
                cleanedFlows.flows[0].credentials = {"a":1};
 | 
						|
                cleanedFlows.flows.should.eql(originalConfig);
 | 
						|
                done();
 | 
						|
            });
 | 
						|
        });
 | 
						|
 | 
						|
        it('sets the full flow including credentials', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            var credentials = {"t1-1":{"a":1}};
 | 
						|
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.setFlows(originalConfig,credentials).then(function() {
 | 
						|
                credentialsClean.called.should.be.false();
 | 
						|
                credentialsLoad.called.should.be.true();
 | 
						|
                credentialsLoad.lastCall.args[0].should.eql(credentials);
 | 
						|
                flows.getFlows().flows.should.eql(originalConfig);
 | 
						|
                done();
 | 
						|
            });
 | 
						|
        });
 | 
						|
 | 
						|
        it('updates existing flows with partial deployment - nodes', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            var newConfig = clone(originalConfig);
 | 
						|
            newConfig.push({id:"t1-2",x:10,y:10,z:"t1",type:"test",wires:[]});
 | 
						|
            newConfig.push({id:"t2",type:"tab"});
 | 
						|
            newConfig.push({id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]});
 | 
						|
            storage.getFlows = function() {
 | 
						|
                return Promise.resolve({flows:originalConfig});
 | 
						|
            }
 | 
						|
            events.once('flows:started',function() {
 | 
						|
                flows.setFlows(newConfig,"nodes").then(function() {
 | 
						|
                    flows.getFlows().flows.should.eql(newConfig);
 | 
						|
                    flowCreate.flows['t1'].update.called.should.be.true();
 | 
						|
                    flowCreate.flows['t2'].start.called.should.be.true();
 | 
						|
                    flowCreate.flows['_GLOBAL_'].update.called.should.be.true();
 | 
						|
                    done();
 | 
						|
                })
 | 
						|
            });
 | 
						|
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.load().then(function() {
 | 
						|
                flows.startFlows();
 | 
						|
            });
 | 
						|
        });
 | 
						|
 | 
						|
        it('updates existing flows with partial deployment - flows', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            var newConfig = clone(originalConfig);
 | 
						|
            newConfig.push({id:"t1-2",x:10,y:10,z:"t1",type:"test",wires:[]});
 | 
						|
            newConfig.push({id:"t2",type:"tab"});
 | 
						|
            newConfig.push({id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]});
 | 
						|
            storage.getFlows = function() {
 | 
						|
                return Promise.resolve({flows:originalConfig});
 | 
						|
            }
 | 
						|
 | 
						|
            events.once('flows:started',function() {
 | 
						|
                flows.setFlows(newConfig,"nodes").then(function() {
 | 
						|
                    flows.getFlows().flows.should.eql(newConfig);
 | 
						|
                    flowCreate.flows['t1'].update.called.should.be.true();
 | 
						|
                    flowCreate.flows['t2'].start.called.should.be.true();
 | 
						|
                    flowCreate.flows['_GLOBAL_'].update.called.should.be.true();
 | 
						|
                    flows.stopFlows().then(done);
 | 
						|
                })
 | 
						|
            });
 | 
						|
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.load().then(function() {
 | 
						|
                flows.startFlows();
 | 
						|
            });
 | 
						|
        });
 | 
						|
 | 
						|
        it('returns error if it cannot decrypt credentials', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            var credentials = {"$":"fail"};
 | 
						|
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.setFlows(originalConfig,credentials).then(function() {
 | 
						|
                done("Unexpected success when credentials couldn't be decrypted")
 | 
						|
            }).catch(function(err) {
 | 
						|
                done();
 | 
						|
            });
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('#load', function() {
 | 
						|
        it('loads the flow config', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            storage.getFlows = function() {
 | 
						|
                return Promise.resolve({flows:originalConfig});
 | 
						|
            }
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.load().then(function() {
 | 
						|
                credentialsLoad.called.should.be.true();
 | 
						|
                // 'load' type does not trigger a save
 | 
						|
                storage.hasOwnProperty('conf').should.be.false();
 | 
						|
                flows.getFlows().flows.should.eql(originalConfig);
 | 
						|
                done();
 | 
						|
            });
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('#startFlows', function() {
 | 
						|
        it('starts the loaded config', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            storage.getFlows = function() {
 | 
						|
                return Promise.resolve({flows:originalConfig});
 | 
						|
            }
 | 
						|
 | 
						|
            events.once('flows:started',function() {
 | 
						|
                Object.keys(flowCreate.flows).should.eql(['_GLOBAL_','t1']);
 | 
						|
                done();
 | 
						|
            });
 | 
						|
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.load().then(function() {
 | 
						|
                flows.startFlows();
 | 
						|
            });
 | 
						|
        });
 | 
						|
        it('does not start if nodes missing', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1-2",x:10,y:10,z:"t1",type:"missing",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            storage.getFlows = function() {
 | 
						|
                return Promise.resolve({flows:originalConfig});
 | 
						|
            }
 | 
						|
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.load().then(function() {
 | 
						|
                flows.startFlows();
 | 
						|
                flowCreate.called.should.be.false();
 | 
						|
                done();
 | 
						|
            });
 | 
						|
        });
 | 
						|
 | 
						|
        it('starts when missing nodes registered', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1-2",x:10,y:10,z:"t1",type:"missing",wires:[]},
 | 
						|
                {id:"t1-3",x:10,y:10,z:"t1",type:"missing2",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            storage.getFlows = function() {
 | 
						|
                return Promise.resolve({flows:originalConfig});
 | 
						|
            }
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.load().then(function() {
 | 
						|
                flows.startFlows();
 | 
						|
                flowCreate.called.should.be.false();
 | 
						|
 | 
						|
                events.emit("type-registered","missing");
 | 
						|
                setTimeout(function() {
 | 
						|
                    flowCreate.called.should.be.false();
 | 
						|
                    events.emit("type-registered","missing2");
 | 
						|
                    setTimeout(function() {
 | 
						|
                        flowCreate.called.should.be.true();
 | 
						|
                        done();
 | 
						|
                    },10);
 | 
						|
                },10);
 | 
						|
            });
 | 
						|
        });
 | 
						|
 | 
						|
 | 
						|
 | 
						|
    });
 | 
						|
 | 
						|
    describe.skip('#get',function() {
 | 
						|
 | 
						|
    });
 | 
						|
 | 
						|
    describe('#eachNode', function() {
 | 
						|
        it('iterates the flow nodes', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            storage.getFlows = function() {
 | 
						|
                return Promise.resolve({flows:originalConfig});
 | 
						|
            }
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.load().then(function() {
 | 
						|
                var c = 0;
 | 
						|
                flows.eachNode(function(node) {
 | 
						|
                    c++
 | 
						|
                })
 | 
						|
                c.should.equal(2);
 | 
						|
                done();
 | 
						|
            });
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    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 Promise.resolve({flows:originalConfig});
 | 
						|
    //         }
 | 
						|
    //
 | 
						|
    //         events.once('flows: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 Promise.resolve({flows:originalConfig});
 | 
						|
    //         }
 | 
						|
    //
 | 
						|
    //         events.once('flows: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 Promise.resolve({flows:originalConfig});
 | 
						|
    //         }
 | 
						|
    //
 | 
						|
    //         events.once('flows: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 Promise.resolve({flows:originalConfig});
 | 
						|
    //         }
 | 
						|
    //
 | 
						|
    //         events.once('flows: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() {
 | 
						|
 | 
						|
        before(function() {
 | 
						|
            sinon.stub(typeRegistry,"getNodeInfo",function(id) {
 | 
						|
                if (id === 'unused-module') {
 | 
						|
                    return {types:['one','two','three']}
 | 
						|
                } else {
 | 
						|
                    return {types:['one','test','three']}
 | 
						|
                }
 | 
						|
            });
 | 
						|
        });
 | 
						|
 | 
						|
        after(function() {
 | 
						|
            typeRegistry.getNodeInfo.restore();
 | 
						|
        });
 | 
						|
 | 
						|
        it('returns cleanly if type not is use', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.setFlows(originalConfig).then(function() {
 | 
						|
                flows.checkTypeInUse("unused-module");
 | 
						|
                done();
 | 
						|
            });
 | 
						|
        });
 | 
						|
        it('throws error if type is in use', function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.setFlows(originalConfig).then(function() {
 | 
						|
                /*jshint immed: false */
 | 
						|
                try {
 | 
						|
                    flows.checkTypeInUse("used-module");
 | 
						|
                    done("type_in_use error not thrown");
 | 
						|
                } catch(err) {
 | 
						|
                    err.code.should.eql("type_in_use");
 | 
						|
                    done();
 | 
						|
                }
 | 
						|
            });
 | 
						|
        });
 | 
						|
    });
 | 
						|
 | 
						|
    describe('#addFlow', function() {
 | 
						|
        it("rejects duplicate node id",function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            storage.getFlows = function() {
 | 
						|
                return Promise.resolve({flows:originalConfig});
 | 
						|
            }
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.load().then(function() {
 | 
						|
                flows.addFlow({
 | 
						|
                    label:'new flow',
 | 
						|
                    nodes:[
 | 
						|
                        {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]}
 | 
						|
                    ]
 | 
						|
                }).then(function() {
 | 
						|
                    done(new Error('failed to reject duplicate node id'));
 | 
						|
                }).catch(function(err) {
 | 
						|
                    done();
 | 
						|
                })
 | 
						|
            });
 | 
						|
 | 
						|
        });
 | 
						|
 | 
						|
        it("addFlow",function(done) {
 | 
						|
            var originalConfig = [
 | 
						|
                {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                {id:"t1",type:"tab"}
 | 
						|
            ];
 | 
						|
            storage.getFlows = function() {
 | 
						|
                return Promise.resolve({flows:originalConfig});
 | 
						|
            }
 | 
						|
            storage.setFlows = function() {
 | 
						|
                return Promise.resolve();
 | 
						|
            }
 | 
						|
            flows.init({log:mockLog, settings:{},storage:storage});
 | 
						|
            flows.load().then(function() {
 | 
						|
                return flows.startFlows();
 | 
						|
            }).then(function() {
 | 
						|
                flows.addFlow({
 | 
						|
                    label:'new flow',
 | 
						|
                    nodes:[
 | 
						|
                        {id:"t2-1",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                        {id:"t2-2",x:10,y:10,z:"t1",type:"test",wires:[]},
 | 
						|
                        {id:"t2-3",z:"t1",type:"test"}
 | 
						|
                    ]
 | 
						|
                }).then(function(id) {
 | 
						|
                    flows.getFlows().flows.should.have.lengthOf(6);
 | 
						|
                    var createdFlows = Object.keys(flowCreate.flows);
 | 
						|
                    createdFlows.should.have.lengthOf(3);
 | 
						|
                    createdFlows[2].should.eql(id);
 | 
						|
                    done();
 | 
						|
                }).catch(function(err) {
 | 
						|
                    done(err);
 | 
						|
                })
 | 
						|
            });
 | 
						|
 | 
						|
        });
 | 
						|
    })
 | 
						|
    describe('#updateFlow', function() {
 | 
						|
        it.skip("updateFlow");
 | 
						|
    })
 | 
						|
    describe('#removeFlow', function() {
 | 
						|
        it.skip("removeFlow");
 | 
						|
    })
 | 
						|
    describe('#disableFlow', function() {
 | 
						|
        it.skip("disableFlow");
 | 
						|
    })
 | 
						|
    describe('#enableFlow', function() {
 | 
						|
        it.skip("enableFlow");
 | 
						|
    })
 | 
						|
});
 |