mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
1425 lines
56 KiB
JavaScript
1425 lines
56 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 credentialsAdd;
|
|
|
|
// var flowCreate;
|
|
// var getType;
|
|
// var checkFlowDependencies;
|
|
|
|
// 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").callsFake(function(type) {
|
|
// return type.indexOf('missing') === -1;
|
|
// });
|
|
// checkFlowDependencies = sinon.stub(typeRegistry, "checkFlowDependencies").callsFake(async function(flow) {
|
|
// if (flow[0].id === "node-with-missing-modules") {
|
|
// throw new Error("Missing module");
|
|
// }
|
|
// });
|
|
// });
|
|
|
|
// after(function() {
|
|
// getType.restore();
|
|
// checkFlowDependencies.restore();
|
|
// });
|
|
|
|
|
|
// beforeEach(function() {
|
|
// eventsOn = sinon.spy(events,"on");
|
|
// credentialsClean = sinon.stub(credentials,"clean").callsFake(function(conf) {
|
|
// conf.forEach(function(n) {
|
|
// delete n.credentials;
|
|
// });
|
|
// return Promise.resolve();
|
|
// });
|
|
// credentialsLoad = sinon.stub(credentials,"load").callsFake(function(creds) {
|
|
// if (creds && creds.hasOwnProperty("$") && creds['$'] === "fail") {
|
|
// return Promise.reject("creds error");
|
|
// }
|
|
// return Promise.resolve();
|
|
// });
|
|
// credentialsAdd = sinon.stub(credentials,"add").callsFake(async function(id, conf){})
|
|
// flowCreate = sinon.stub(Flow,"create").callsFake(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(async() => {}),
|
|
// 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();
|
|
// credentialsAdd.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.true();
|
|
// credentialsAdd.called.should.be.true();
|
|
// credentialsAdd.lastCall.args[0].should.eql("t1-1");
|
|
// credentialsAdd.lastCall.args[1].should.eql({"a":1});
|
|
// 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() {
|
|
// events.once('flows:started', function() {
|
|
// try {
|
|
// 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();
|
|
// } catch(err) {
|
|
// done(err)
|
|
// }
|
|
// })
|
|
// flows.setFlows(newConfig,"nodes")
|
|
// });
|
|
|
|
// 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() {
|
|
// events.once('flows:started',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.setFlows(newConfig,"nodes")
|
|
// });
|
|
|
|
// 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() {
|
|
// return 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() {
|
|
// return flows.startFlows();
|
|
// }).then(() => {
|
|
// try {
|
|
// flowCreate.called.should.be.false();
|
|
// done();
|
|
// } catch(err) {
|
|
// done(err);
|
|
// }
|
|
// });
|
|
// });
|
|
|
|
// 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() {
|
|
// return flows.startFlows();
|
|
// }).then(() => {
|
|
// 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);
|
|
// });
|
|
// });
|
|
|
|
// it('does not start if external modules missing', function(done) {
|
|
// var originalConfig = [
|
|
// {id:"node-with-missing-modules",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
// {id:"t1",type:"tab"}
|
|
// ];
|
|
|
|
// storage.getFlows = function() {
|
|
// return Promise.resolve({flows:originalConfig});
|
|
// }
|
|
// var receivedEvent = null;
|
|
// var handleEvent = function(payload) {
|
|
// receivedEvent = payload;
|
|
// }
|
|
|
|
// events.on("runtime-event",handleEvent);
|
|
|
|
// //{id:"runtime-state",payload:{error:"missing-modules", type:"warning",text:"notification.warnings.missing-modules",modules:missingModules},retain:true});"
|
|
|
|
|
|
// flows.init({log:mockLog, settings:{},storage:storage});
|
|
// flows.load().then(flows.startFlows).then(() => {
|
|
// events.removeListener("runtime-event",handleEvent);
|
|
// try {
|
|
// flowCreate.called.should.be.false();
|
|
// receivedEvent.should.have.property('id','runtime-state');
|
|
// receivedEvent.should.have.property('payload', {
|
|
// state: 'stop',
|
|
// error: 'missing-modules',
|
|
// type: 'warning',
|
|
// text: 'notification.warnings.missing-modules',
|
|
// modules: []
|
|
// });
|
|
|
|
// done();
|
|
// }catch(err) {
|
|
// done(err)
|
|
// }
|
|
// });
|
|
// });
|
|
|
|
// });
|
|
|
|
// 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").callsFake(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");
|
|
// })
|
|
// });
|
|
|
|
|
|
//***************************************************************************************************************** */
|
|
|
|
//MY code
|
|
// const should = require("should");
|
|
// const sinon = require("sinon");
|
|
// const clone = require("clone");
|
|
// const NR_TEST_UTILS = require("nr-test-utils");
|
|
|
|
// const flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows");
|
|
// const Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Flow");
|
|
// const events = NR_TEST_UTILS.require("@node-red/util/lib/events");
|
|
// const credentials = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/credentials");
|
|
// const typeRegistry = NR_TEST_UTILS.require("@node-red/registry");
|
|
|
|
// describe('flows/index', function() {
|
|
// let storage;
|
|
// let eventsOn;
|
|
// let credentialsClean;
|
|
// let credentialsLoad;
|
|
// let credentialsAdd;
|
|
// let flowCreate;
|
|
// let getType;
|
|
// let checkFlowDependencies;
|
|
// let mockLog;
|
|
|
|
// before(function() {
|
|
// getType = sinon.stub(typeRegistry, "get").callsFake(type => type.indexOf('missing') === -1);
|
|
// checkFlowDependencies = sinon.stub(typeRegistry, "checkFlowDependencies").callsFake(async flow => {
|
|
// if (flow[0].id === "node-with-missing-modules") {
|
|
// throw new Error("Missing module");
|
|
// }
|
|
// });
|
|
// });
|
|
|
|
// after(function() {
|
|
// getType.restore();
|
|
// checkFlowDependencies.restore();
|
|
// });
|
|
|
|
// beforeEach(function() {
|
|
// eventsOn = sinon.spy(events, "on");
|
|
// credentialsClean = sinon.stub(credentials, "clean").callsFake(conf => {
|
|
// conf.forEach(n => delete n.credentials);
|
|
// return Promise.resolve();
|
|
// });
|
|
// credentialsLoad = sinon.stub(credentials, "load").callsFake(creds => {
|
|
// if (creds && creds.hasOwnProperty("$") && creds['$'] === "fail") {
|
|
// return Promise.reject("creds error");
|
|
// }
|
|
// return Promise.resolve();
|
|
// });
|
|
// credentialsAdd = sinon.stub(credentials, "add").callsFake(async (id, conf) => {});
|
|
|
|
// flowCreate = sinon.stub(Flow, "create").callsFake((parent, global, flow) => {
|
|
// let id = flow?.id ?? '_GLOBAL_';
|
|
// flowCreate.flows[id] = {
|
|
// flow,
|
|
// global,
|
|
// start: sinon.spy(async () => {}),
|
|
// update: sinon.spy(),
|
|
// stop: sinon.spy(),
|
|
// getActiveNodes: () => flow.nodes || {},
|
|
// handleError: sinon.spy(),
|
|
// handleStatus: sinon.spy()
|
|
// };
|
|
// return flowCreate.flows[id];
|
|
// });
|
|
// flowCreate.flows = {};
|
|
|
|
// storage = {
|
|
// saveFlows: conf => {
|
|
// storage.conf = conf;
|
|
// return Promise.resolve();
|
|
// }
|
|
// };
|
|
|
|
// mockLog = {
|
|
// log: sinon.stub(),
|
|
// debug: sinon.stub(),
|
|
// trace: sinon.stub(),
|
|
// warn: sinon.stub(),
|
|
// info: sinon.stub(),
|
|
// metric: sinon.stub(),
|
|
// _: () => "abc"
|
|
// };
|
|
// });
|
|
|
|
// afterEach(function(done) {
|
|
// eventsOn.restore();
|
|
// credentialsClean.restore();
|
|
// credentialsLoad.restore();
|
|
// credentialsAdd.restore();
|
|
// flowCreate.restore();
|
|
// flows.stopFlows().then(done);
|
|
// });
|
|
|
|
// describe('#setFlows', function() {
|
|
// it('sets the full flow', function(done) {
|
|
// const originalConfig = [
|
|
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
// {id:"t1",type:"tab"}
|
|
// ];
|
|
// flows.init({log:mockLog, settings:{},storage});
|
|
// flows.setFlows(originalConfig).then(() => {
|
|
// credentialsClean.called.should.be.true();
|
|
// storage.should.have.property('conf');
|
|
// flows.getFlows().flows.should.eql(originalConfig);
|
|
// done();
|
|
// }).catch(done);
|
|
// });
|
|
|
|
// it('loads the full flow for type load', function(done) {
|
|
// const originalConfig = [
|
|
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
// {id:"t1",type:"tab"}
|
|
// ];
|
|
// const 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(() => {
|
|
// credentialsClean.called.should.be.false();
|
|
// loadStorage.should.not.have.property('conf');
|
|
// flows.getFlows().flows.should.eql(originalConfig);
|
|
// done();
|
|
// }).catch(done);
|
|
// });
|
|
|
|
// it('extracts credentials from the full flow', function(done) {
|
|
// const 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});
|
|
// flows.setFlows(originalConfig).then(() => {
|
|
// credentialsClean.called.should.be.true();
|
|
// storage.should.have.property('conf');
|
|
// const 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();
|
|
// }).catch(done);
|
|
// });
|
|
|
|
// it('sets the full flow including credentials', function(done) {
|
|
// const originalConfig = [
|
|
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
// {id:"t1",type:"tab"}
|
|
// ];
|
|
// const credentials = {"t1-1": {"a":1}};
|
|
// flows.init({log:mockLog, settings:{},storage});
|
|
// flows.setFlows(originalConfig, credentials).then(() => {
|
|
// credentialsClean.called.should.be.true();
|
|
// credentialsAdd.called.should.be.true();
|
|
// credentialsAdd.lastCall.args[0].should.eql("t1-1");
|
|
// credentialsAdd.lastCall.args[1].should.eql({"a":1});
|
|
// flows.getFlows().flows.should.eql(originalConfig);
|
|
// done();
|
|
// }).catch(done);
|
|
// });
|
|
|
|
// it('updates existing flows with partial deployment - nodes', function(done) {
|
|
// const originalConfig = [
|
|
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
// {id:"t1",type:"tab"}
|
|
// ];
|
|
// const 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 = () => Promise.resolve({flows:originalConfig});
|
|
|
|
// events.once('flows:started', () => {
|
|
// events.once('flows:started', () => {
|
|
// try {
|
|
// 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();
|
|
// } catch(err) {
|
|
// done(err);
|
|
// }
|
|
// });
|
|
// flows.setFlows(newConfig, "nodes");
|
|
// });
|
|
|
|
// flows.init({log:mockLog, settings:{},storage});
|
|
// flows.load().then(flows.startFlows).catch(done);
|
|
// });
|
|
|
|
// it('updates existing flows with partial deployment - flows', function(done) {
|
|
// const originalConfig = [
|
|
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
// {id:"t1",type:"tab"}
|
|
// ];
|
|
// const 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 = () => Promise.resolve({flows:originalConfig});
|
|
|
|
// events.once('flows:started', () => {
|
|
// events.once('flows:started', () => {
|
|
// 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).catch(done);
|
|
// });
|
|
// flows.setFlows(newConfig, "flows");
|
|
// });
|
|
|
|
// flows.init({log:mockLog, settings:{},storage});
|
|
// flows.load().then(flows.startFlows).catch(done);
|
|
// });
|
|
|
|
// it('retains missing flows with partial deployment - nodes', function(done) {
|
|
// const originalConfig = [
|
|
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
// {id:"t1",type:"tab"},
|
|
// {id:"t1-2",x:10,y:10,z:"t1",type:"test",wires:[]}
|
|
// ];
|
|
// const newConfig = [
|
|
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
// {id:"t1",type:"tab"}
|
|
// ];
|
|
// storage.getFlows = () => Promise.resolve({flows:originalConfig});
|
|
|
|
// events.once('flows:started', () => {
|
|
// events.once('flows:started', () => {
|
|
// flows.getFlows().flows.should.eql(originalConfig);
|
|
// flowCreate.flows['t1'].update.called.should.be.true();
|
|
// done();
|
|
// });
|
|
// flows.setFlows(newConfig, "nodes");
|
|
// });
|
|
|
|
// flows.init({log:mockLog, settings:{},storage});
|
|
// flows.load().then(flows.startFlows).catch(done);
|
|
// });
|
|
// });
|
|
|
|
// describe('#startFlows', function() {
|
|
// it('starts empty flow configuration', function(done) {
|
|
// flows.init({log:mockLog, settings:{},storage});
|
|
// flows.startFlows().then(() => {
|
|
// flows.getFlows().flows.should.eql([]);
|
|
// done();
|
|
// }).catch(done);
|
|
// });
|
|
// });
|
|
|
|
// describe('#stopFlows', function() {
|
|
// it('stops running flow configuration', function(done) {
|
|
// const originalConfig = [
|
|
// {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
// {id:"t1",type:"tab"}
|
|
// ];
|
|
// storage.getFlows = () => Promise.resolve({flows:originalConfig});
|
|
|
|
// flows.init({log:mockLog, settings:{},storage});
|
|
// flows.load().then(flows.startFlows).then(() => {
|
|
// flows.getFlows().flows.should.eql(originalConfig);
|
|
// return flows.stopFlows();
|
|
// }).then(() => {
|
|
// Object.keys(flowCreate.flows).forEach(id => {
|
|
// flowCreate.flows[id].stop.called.should.be.true();
|
|
// });
|
|
// done();
|
|
// }).catch(done);
|
|
// });
|
|
// });
|
|
// });
|
|
|
|
//***************************************************************** */
|
|
|
|
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 credentialsAdd;
|
|
|
|
var flowCreate;
|
|
var getType;
|
|
var checkFlowDependencies;
|
|
|
|
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").callsFake(function(type) {
|
|
return type.indexOf('missing') === -1;
|
|
});
|
|
checkFlowDependencies = sinon.stub(typeRegistry, "checkFlowDependencies").callsFake(async function(flow) {
|
|
if (flow[0].id === "node-with-missing-modules") {
|
|
throw new Error("Missing module");
|
|
}
|
|
});
|
|
});
|
|
|
|
after(function() {
|
|
getType.restore();
|
|
checkFlowDependencies.restore();
|
|
});
|
|
|
|
|
|
beforeEach(function() {
|
|
eventsOn = sinon.spy(events,"on");
|
|
credentialsClean = sinon.stub(credentials,"clean").callsFake(function(conf) {
|
|
conf.forEach(function(n) {
|
|
delete n.credentials;
|
|
});
|
|
return Promise.resolve();
|
|
});
|
|
credentialsLoad = sinon.stub(credentials,"load").callsFake(function(creds) {
|
|
if (creds && creds.hasOwnProperty("$") && creds['$'] === "fail") {
|
|
return Promise.reject("creds error");
|
|
}
|
|
return Promise.resolve();
|
|
});
|
|
credentialsAdd = sinon.stub(credentials,"add").callsFake(async function(id, conf){})
|
|
flowCreate = sinon.stub(Flow,"create").callsFake(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(async() => {}),
|
|
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();
|
|
credentialsAdd.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.true();
|
|
credentialsAdd.called.should.be.true();
|
|
credentialsAdd.lastCall.args[0].should.eql("t1-1");
|
|
credentialsAdd.lastCall.args[1].should.eql({"a":1});
|
|
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() {
|
|
events.once('flows:started', function() {
|
|
try {
|
|
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();
|
|
} catch(err) {
|
|
done(err)
|
|
}
|
|
})
|
|
flows.setFlows(newConfig,"nodes")
|
|
});
|
|
|
|
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() {
|
|
events.once('flows:started',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.setFlows(newConfig,"flows")
|
|
});
|
|
|
|
flows.init({log:mockLog, settings:{},storage:storage});
|
|
flows.load().then(function() {
|
|
flows.startFlows();
|
|
});
|
|
});
|
|
|
|
it('updates existing flows with partial deployment - full', 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() {
|
|
events.once('flows:started',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.setFlows(newConfig,"full")
|
|
});
|
|
|
|
flows.init({log:mockLog, settings:{},storage:storage});
|
|
flows.load().then(function() {
|
|
flows.startFlows();
|
|
});
|
|
});
|
|
|
|
it('removes a tab with partial deployment - nodes', function(done) {
|
|
var originalConfig = [
|
|
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
{id:"t1",type:"tab"},
|
|
{id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]},
|
|
{id:"t2",type:"tab"}
|
|
];
|
|
var newConfig = [
|
|
{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.getFlows().flows.should.eql(newConfig);
|
|
should.not.exist(flowCreate.flows['t2']);
|
|
flowCreate.flows['t1'].update.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().then(function() {
|
|
flows.setFlows(newConfig,"nodes")
|
|
});
|
|
});
|
|
});
|
|
|
|
it('removes a tab with partial deployment - flows', function(done) {
|
|
var originalConfig = [
|
|
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
{id:"t1",type:"tab"},
|
|
{id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]},
|
|
{id:"t2",type:"tab"}
|
|
];
|
|
var newConfig = [
|
|
{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.getFlows().flows.should.eql(newConfig);
|
|
should.not.exist(flowCreate.flows['t2']);
|
|
flowCreate.flows['t1'].update.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().then(function() {
|
|
flows.setFlows(newConfig,"flows")
|
|
});
|
|
});
|
|
});
|
|
|
|
it('removes a tab with partial deployment - full', function(done) {
|
|
var originalConfig = [
|
|
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
|
{id:"t1",type:"tab"},
|
|
{id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]},
|
|
{id:"t2",type:"tab"}
|
|
];
|
|
var newConfig = [
|
|
{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.getFlows().flows.should.eql(newConfig);
|
|
should.not.exist(flowCreate.flows['t2']);
|
|
flowCreate.flows['t1'].update.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().then(function() {
|
|
flows.setFlows(newConfig,"full")
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#startFlows', function() {
|
|
it('starts an empty flow', function(done) {
|
|
var originalConfig = [];
|
|
storage.getFlows = function() {
|
|
return Promise.resolve({flows:originalConfig});
|
|
}
|
|
flows.init({log:mockLog, settings:{},storage:storage});
|
|
flows.load().then(function() {
|
|
flows.startFlows().then(function() {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
it('starts an empty flow with credentials error', function(done) {
|
|
var originalConfig = [];
|
|
storage.getFlows = function() {
|
|
return Promise.resolve({flows:originalConfig,credentials:{$:"fail"}});
|
|
}
|
|
flows.init({log:mockLog, settings:{},storage:storage});
|
|
flows.load().then(function() {
|
|
flows.startFlows().then(function() {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
it('starts a non-empty 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});
|
|
}
|
|
flows.init({log:mockLog, settings:{},storage:storage});
|
|
flows.load().then(function() {
|
|
flows.startFlows().then(function() {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('#stopFlows', function() {
|
|
it('stops an empty flow', function(done) {
|
|
var originalConfig = [];
|
|
storage.getFlows = function() {
|
|
return Promise.resolve({flows:originalConfig});
|
|
}
|
|
flows.init({log:mockLog, settings:{},storage:storage});
|
|
flows.load().then(function() {
|
|
flows.startFlows().then(function() {
|
|
flows.stopFlows().then(function() {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
it('stops a non-empty 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});
|
|
}
|
|
flows.init({log:mockLog, settings:{},storage:storage});
|
|
flows.load().then(function() {
|
|
flows.startFlows().then(function() {
|
|
flows.stopFlows().then(function() {
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
}); |