modules[moduleId]);
- sinon.stub(registry,"getModuleList").callsFake(() => modules)
- });
- afterEach(function() {
- events.removeListener("registry:plugin-added",handleEvent);
- registry.getModule.restore();
- registry.getModuleList.restore();
- })
-
- describe("registerPlugin", function() {
- it("registers a plugin", function() {
- let pluginDef = {}
- plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
- receivedEvents.length.should.eql(1);
- receivedEvents[0].should.eql("a-plugin");
- should.exist(modules['test-module'].plugins['test-set'].plugins[0])
- modules['test-module'].plugins['test-set'].plugins[0].should.equal(pluginDef)
- })
- it("calls a plugins onadd function", function() {
- let pluginDef = { onadd: sinon.stub() }
- plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
- pluginDef.onadd.called.should.be.true();
- })
- })
-
- describe("getPlugin", function() {
- it("returns a registered plugin", function() {
- let pluginDef = {}
- plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
- pluginDef.should.equal(plugins.getPlugin("a-plugin"));
- })
- })
- describe("getPluginsByType", function() {
- it("returns a plugins of a given type", function() {
- let pluginDef = {type: "foo"}
- let pluginDef2 = {type: "bar"}
- let pluginDef3 = {type: "foo"}
- plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
- plugins.registerPlugin("test-module/test-set","a-plugin2",pluginDef2);
- plugins.registerPlugin("test-module/test-set","a-plugin3",pluginDef3);
-
- let fooPlugins = plugins.getPluginsByType("foo");
- let barPlugins = plugins.getPluginsByType("bar");
- let noPlugins = plugins.getPluginsByType("none");
-
- noPlugins.should.be.of.length(0);
-
- fooPlugins.should.be.of.length(2);
- fooPlugins.should.containEql(pluginDef);
- fooPlugins.should.containEql(pluginDef3);
-
- barPlugins.should.be.of.length(1);
- barPlugins.should.containEql(pluginDef2);
-
- })
- })
-
- describe("getPluginConfigs", function() {
- it("gets all plugin configs", function() {
- let configs = plugins.getPluginConfigs("en-US");
- configs.should.eql(`
-
-test-module-config`)
- })
- })
-
-
- describe("getPluginList", function() {
- it("returns a plugins of a given type", function() {
- let pluginDef = {type: "foo"}
- let pluginDef2 = {type: "bar"}
- let pluginDef3 = {type: "foo"}
- plugins.registerPlugin("test-module/test-set","a-plugin",pluginDef);
- plugins.registerPlugin("test-module/test-set","a-plugin2",pluginDef2);
- plugins.registerPlugin("test-module/test-set","a-plugin3",pluginDef3);
-
- let pluginList = plugins.getPluginList();
- JSON.stringify(pluginList).should.eql(JSON.stringify(
- [
- {
- "id": "test-module/test-set",
- "enabled": true,
- "local": false,
- "user": false,
- "plugins": [
- {
- "type": "foo",
- "id": "a-plugin",
- "module": "test-module"
- },
- {
- "type": "bar",
- "id": "a-plugin2",
- "module": "test-module"
- },
- {
- "type": "foo",
- "id": "a-plugin3",
- "module": "test-module"
- }
- ]
- },
- {
- "id": "test-module/test-disabled-set",
- "enabled": false,
- "local": false,
- "user": false,
- "plugins": []
- }
- ]
- ))
- })
- })
- describe("exportPluginSettings", function() {
- it("exports plugin settings - default false", function() {
- plugins.init({ "a-plugin": { a: 123, b:234, c: 345} });
- plugins.registerPlugin("test-module/test-set","a-plugin",{
- settings: {
- a: { exportable: true },
- b: {exportable: false },
- d: { exportable: true, value: 456}
-
- }
- });
- var exportedSet = {};
- plugins.exportPluginSettings(exportedSet);
- exportedSet.should.have.property("a-plugin");
- // a is exportable
- exportedSet["a-plugin"].should.have.property("a",123);
- // b is explicitly not exportable
- exportedSet["a-plugin"].should.not.have.property("b");
- // c isn't listed and default false
- exportedSet["a-plugin"].should.not.have.property("c");
- // d has a default value
- exportedSet["a-plugin"].should.have.property("d",456);
- })
- it("exports plugin settings - default true", function() {
- plugins.init({ "a-plugin": { a: 123, b:234, c: 345} });
- plugins.registerPlugin("test-module/test-set","a-plugin",{
- settings: {
- '*': { exportable: true },
- a: { exportable: true },
- b: {exportable: false },
- d: { exportable: true, value: 456}
-
- }
- });
- var exportedSet = {};
- plugins.exportPluginSettings(exportedSet);
- exportedSet.should.have.property("a-plugin");
- // a is exportable
- exportedSet["a-plugin"].should.have.property("a",123);
- // b is explicitly not exportable
- exportedSet["a-plugin"].should.not.have.property("b");
- // c isn't listed, but default true
- exportedSet["a-plugin"].should.have.property("c");
- // d has a default value
- exportedSet["a-plugin"].should.have.property("d",456);
- })
- });
-});
diff --git a/test/unit/@node-red/registry/lib/registry_spec.js b/test/unit/@node-red/registry/lib/registry_spec.js
deleted file mode 100644
index 5501264a7..000000000
--- a/test/unit/@node-red/registry/lib/registry_spec.js
+++ /dev/null
@@ -1,614 +0,0 @@
-/**
- * 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 path = require("path");
-
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry");
-const { events } = NR_TEST_UTILS.require("@node-red/util");
-
-describe("red/nodes/registry/registry",function() {
-
- afterEach(function() {
- typeRegistry.clear();
- });
-
- function stubSettings(s,available,initialConfig) {
- s.available = function() {return available;};
- s.set = sinon.spy(function(s,v) { return Promise.resolve();});
- s.get = function(s) { return initialConfig;};
- return s;
- }
-
- var settings = stubSettings({},false,null);
- var settingsWithStorageAndInitialConfig = stubSettings({},true,{"node-red":{module:"testModule",name:"testName",version:"testVersion",nodes:{"node":{id:"node-red/testName",name:"test",types:["a","b"],enabled:true}}}});
-
- var testNodeSet1 = {
- id: "test-module/test-name",
- module: "test-module",
- name: "test-name",
- enabled: true,
- loaded: false,
- config: "configA",
- types: [ "test-a","test-b"]
- };
-
- var testNodeSet2 = {
- id: "test-module/test-name-2",
- module: "test-module",
- name: "test-name-2",
- enabled: true,
- loaded: false,
- config: "configB",
- types: [ "test-c","test-d"]
- };
- var testNodeSet2WithError = {
- id: "test-module/test-name-2",
- module: "test-module",
- name: "test-name-2",
- enabled: true,
- loaded: false,
- err: "I have an error",
- config: "configC",
- types: [ "test-c","test-d"]
- };
- var testNodeSet3 = {
- id: "test-module-2/test-name-3",
- module: "test-module-2",
- name: "test-name-3",
- enabled: true,
- loaded: false,
- config: "configB",
- types: [ "test-a","test-e"]
- };
-
-
-
- describe('#init/load', function() {
- it('loads initial config', function(done) {
- typeRegistry.init(settingsWithStorageAndInitialConfig,null);
- typeRegistry.getNodeList().should.have.lengthOf(0);
- typeRegistry.load();
- typeRegistry.getNodeList().should.have.lengthOf(1);
- done();
- });
-
- it('migrates legacy format', function(done) {
- var legacySettings = {
- available: function() { return true; },
- set: sinon.stub().returns(Promise.resolve()),
- get: function() { return {
- "123": {
- "name": "72-sentiment.js",
- "types": [
- "sentiment"
- ],
- "enabled": true
- },
- "456": {
- "name": "20-inject.js",
- "types": [
- "inject"
- ],
- "enabled": true
- },
- "789": {
- "name": "testModule:a-module.js",
- "types": [
- "example"
- ],
- "enabled":true,
- "module":"testModule"
- }
- }}
- };
- var expected = JSON.parse('{"node-red":{"name":"node-red","nodes":{"sentiment":{"name":"sentiment","types":["sentiment"],"enabled":true,"module":"node-red"},"inject":{"name":"inject","types":["inject"],"enabled":true,"module":"node-red"}}},"testModule":{"name":"testModule","nodes":{"a-module.js":{"name":"a-module.js","types":["example"],"enabled":true,"module":"testModule"}}}}');
- typeRegistry.init(legacySettings,null);
- typeRegistry.load();
- legacySettings.set.calledOnce.should.be.true();
- legacySettings.set.args[0][1].should.eql(expected);
- done();
- });
- });
-
-
- describe.skip('#addNodeSet', function() {
- it('adds a node set for an unknown module', function() {
-
- typeRegistry.init(settings,null);
-
- typeRegistry.getNodeList().should.have.lengthOf(0);
- typeRegistry.getModuleList().should.eql({});
-
- typeRegistry.addNodeSet("test-module/test-name",testNodeSet1, "0.0.1");
-
- typeRegistry.getNodeList().should.have.lengthOf(1);
- var moduleList = typeRegistry.getModuleList();
- moduleList.should.have.a.property("test-module");
- moduleList["test-module"].should.have.a.property("name","test-module");
- moduleList["test-module"].should.have.a.property("version","0.0.1");
- moduleList["test-module"].should.have.a.property("nodes");
- moduleList["test-module"].nodes.should.have.a.property("test-name");
-
- moduleList["test-module"].nodes["test-name"].should.eql({
- config: 'configA',
- id: 'test-module/test-name',
- module: 'test-module',
- name: 'test-name',
- enabled: true,
- loaded: false,
- types: [ 'test-a', 'test-b' ]
- });
-
- });
-
- it('adds a node set to an existing module', function() {
-
- typeRegistry.init(settings,null);
- typeRegistry.getNodeList().should.have.lengthOf(0);
- typeRegistry.getModuleList().should.eql({});
-
- typeRegistry.addNodeSet("test-module/test-name",testNodeSet1, "0.0.1");
-
- typeRegistry.getNodeList().should.have.lengthOf(1);
- var moduleList = typeRegistry.getModuleList();
- Object.keys(moduleList).should.have.a.lengthOf(1);
- moduleList.should.have.a.property("test-module");
- moduleList["test-module"].should.have.a.property("name","test-module");
- moduleList["test-module"].should.have.a.property("version","0.0.1");
- moduleList["test-module"].should.have.a.property("nodes");
-
- Object.keys(moduleList["test-module"].nodes).should.have.a.lengthOf(1);
- moduleList["test-module"].nodes.should.have.a.property("test-name");
-
-
- typeRegistry.addNodeSet("test-module/test-name-2",testNodeSet2);
-
- typeRegistry.getNodeList().should.have.lengthOf(2);
- moduleList = typeRegistry.getModuleList();
- Object.keys(moduleList).should.have.a.lengthOf(1);
- Object.keys(moduleList["test-module"].nodes).should.have.a.lengthOf(2);
- moduleList["test-module"].nodes.should.have.a.property("test-name");
- moduleList["test-module"].nodes.should.have.a.property("test-name-2");
- });
-
- it('doesnt add node set types if node set has an error', function() {
- typeRegistry.init(settings,null);
- typeRegistry.getNodeList().should.have.lengthOf(0);
- typeRegistry.getModuleList().should.eql({});
-
- typeRegistry.addNodeSet("test-module/test-name",testNodeSet1, "0.0.1");
-
- typeRegistry.getTypeId("test-a").should.eql("test-module/test-name");
-
- should.not.exist(typeRegistry.getTypeId("test-c"));
-
- typeRegistry.addNodeSet("test-module/test-name-2",testNodeSet2WithError, "0.0.1");
-
- should.not.exist(typeRegistry.getTypeId("test-c"));
- });
-
- it('doesnt add node set if type already exists', function() {
- typeRegistry.init(settings,null);
- typeRegistry.getNodeList().should.have.lengthOf(0);
- typeRegistry.getModuleList().should.eql({});
-
- should.not.exist(typeRegistry.getTypeId("test-e"));
-
- typeRegistry.addNodeSet("test-module/test-name",testNodeSet1, "0.0.1");
- typeRegistry.getNodeList().should.have.lengthOf(1);
- should.exist(typeRegistry.getTypeId("test-a"));
- typeRegistry.addNodeSet(testNodeSet3.id,testNodeSet3, "0.0.1");
- typeRegistry.getNodeList().should.have.lengthOf(2);
-
- // testNodeSet3 registers a duplicate test-a and unique test-e
- // as test-a is a duplicate, test-e should not get registered
- should.not.exist(typeRegistry.getTypeId("test-e"));
-
- var testNodeSet3Result = typeRegistry.getNodeList()[1];
- should.exist(testNodeSet3Result.err);
- testNodeSet3Result.err.code.should.equal("type_already_registered");
- testNodeSet3Result.err.details.type.should.equal("test-a");
- testNodeSet3Result.err.details.moduleA.should.equal("test-module");
- testNodeSet3Result.err.details.moduleB.should.equal("test-module-2");
-
- //
- // typeRegistry.addNodeSet("test-module/test-name-2",testNodeSet2WithError, "0.0.1");
- //
- // should.not.exist(typeRegistry.getTypeId("test-c"));
- });
-
-
- });
-
- describe("#enableNodeSet", function() {
- it('throws error if settings unavailable', function() {
- typeRegistry.init(settings,null);
- /*jshint immed: false */
- (function(){
- typeRegistry.enableNodeSet("test-module/test-name");
- }).should.throw("Settings unavailable");
- });
-
- it('throws error if module unknown', function() {
- typeRegistry.init(settingsWithStorageAndInitialConfig,null);
- /*jshint immed: false */
- (function(){
- typeRegistry.enableNodeSet("test-module/unknown");
- }).should.throw("Unrecognised id: test-module/unknown");
- });
- it.skip('enables the node',function(){})
-
- });
- describe("#disableNodeSet", function() {
- it('throws error if settings unavailable', function() {
- typeRegistry.init(settings,null);
- /*jshint immed: false */
- (function(){
- typeRegistry.disableNodeSet("test-module/test-name");
- }).should.throw("Settings unavailable");
- });
-
- it('throws error if module unknown', function() {
- typeRegistry.init(settingsWithStorageAndInitialConfig,null);
- /*jshint immed: false */
- (function(){
- typeRegistry.disableNodeSet("test-module/unknown");
- }).should.throw("Unrecognised id: test-module/unknown");
- });
- it.skip('disables the node',function(){})
- });
-
- describe('#getNodeConfig', function() {
- it('returns nothing for an unregistered type config', function(done) {
- typeRegistry.init(settings,null);
- var config = typeRegistry.getNodeConfig("imaginary-shark");
- (config === null).should.be.true();
- done();
- });
- });
-
- describe('#saveNodeList',function() {
- it('rejects when settings unavailable',function(done) {
- typeRegistry.init(stubSettings({},false,{}),null);
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {"test-name":{module:"test-module",name:"test-name",types:[]}}});
- typeRegistry.saveNodeList().catch(function(err) {
- done();
- });
- });
- it('saves the list',function(done) {
- var s = stubSettings({},true,{});
- typeRegistry.init(s,null);
-
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
- "test-name":testNodeSet1,
- "test-name-2":testNodeSet2WithError
- }});
-
- typeRegistry.saveNodeList().then(function() {
- s.set.called.should.be.true();
- s.set.lastCall.args[0].should.eql('nodes');
- var nodes = s.set.lastCall.args[1];
- nodes.should.have.property('test-module');
- for (var n in nodes['test-module'].nodes) {
- if (nodes['test-module'].nodes.hasOwnProperty(n)) {
- var nn = nodes['test-module'].nodes[n];
- nn.should.not.have.property('err');
- nn.should.not.have.property('id');
- }
- }
- done();
- }).catch(function(err) {
- done(err);
- });
- });
- });
-
- describe('#removeModule',function() {
- it('throws error for unknown module', function() {
- var s = stubSettings({},true,{});
- typeRegistry.init(s,null);
- /*jshint immed: false */
- (function(){
- typeRegistry.removeModule("test-module/unknown");
- }).should.throw("Unrecognised module: test-module/unknown");
- });
- it('throws error for unavaiable settings', function() {
- var s = stubSettings({},false,{});
- typeRegistry.init(s,null);
- /*jshint immed: false */
- (function(){
- typeRegistry.removeModule("test-module/unknown");
- }).should.throw("Settings unavailable");
- });
- it('removes a known module', function() {
- var s = stubSettings({},true,{});
- typeRegistry.init(s,null);
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
- "test-name":testNodeSet1
- }});
- var moduleList = typeRegistry.getModuleList();
- moduleList.should.have.a.property("test-module");
- typeRegistry.getNodeList().should.have.lengthOf(1);
-
- var info = typeRegistry.removeModule('test-module');
- moduleList = typeRegistry.getModuleList();
- moduleList.should.not.have.a.property("test-module");
- typeRegistry.getNodeList().should.have.lengthOf(0);
- });
- });
-
- describe('#get[All]NodeConfigs', function() {
- it('returns node config', function() {
- typeRegistry.init(settings,{
- getNodeHelp: function(config) { return "HE"+config.name+"LP" }
- });
-
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
- "test-name":{
- id: "test-module/test-name",
- module: "test-module",
- name: "test-name",
- enabled: true,
- loaded: false,
- config: "configA",
- types: [ "test-a","test-b"]
- },
- "test-name-2":{
- id: "test-module/test-name-2",
- module: "test-module",
- name: "test-name-2",
- enabled: true,
- loaded: false,
- config: "configB",
- types: [ "test-c","test-d"]
- }
- }});
- typeRegistry.getNodeConfig("test-module/test-name").should.eql('\nconfigAHEtest-nameLP');
- typeRegistry.getNodeConfig("test-module/test-name-2").should.eql('\nconfigBHEtest-name-2LP');
- typeRegistry.getAllNodeConfigs().should.eql('\n\nconfigAHEtest-nameLP\n\nconfigBHEtest-name-2LP');
- });
- });
- describe('#getModuleInfo', function() {
- it('returns module info', function() {
- typeRegistry.init(settings,{});
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
- "test-name":{
- id: "test-module/test-name",
- module: "test-module",
- name: "test-name",
- enabled: true,
- loaded: false,
- config: "configA",
- types: [ "test-a","test-b"],
- file: "abc"
- }
- }});
- var moduleInfo = typeRegistry.getModuleInfo("test-module");
- moduleInfo.should.have.a.property('name','test-module');
- moduleInfo.should.have.a.property('version','0.0.1');
- moduleInfo.should.have.a.property('nodes');
- moduleInfo.nodes.should.have.a.lengthOf(1);
- moduleInfo.nodes[0].should.have.a.property('id','test-module/test-name');
- moduleInfo.nodes[0].should.not.have.a.property('file');
- });
- });
- describe('#getNodeInfo', function() {
- it('returns node info', function() {
- typeRegistry.init(settings,{});
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
- "test-name":{
- id: "test-module/test-name",
- module: "test-module",
- name: "test-name",
- enabled: true,
- loaded: false,
- config: "configA",
- types: [ "test-a","test-b"],
- file: "abc"
- }
- }});
- var nodeSetInfo = typeRegistry.getNodeInfo("test-module/test-name");
- nodeSetInfo.should.have.a.property('id',"test-module/test-name");
- nodeSetInfo.should.not.have.a.property('config');
- nodeSetInfo.should.not.have.a.property('file');
- });
- });
- describe('#getFullNodeInfo', function() {
- it('returns node info', function() {
- typeRegistry.init(settings,{});
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
- "test-name":{
- id: "test-module/test-name",
- module: "test-module",
- name: "test-name",
- enabled: true,
- loaded: false,
- config: "configA",
- types: [ "test-a","test-b"],
- file: "abc"
-
- }
- }});
- var nodeSetInfo = typeRegistry.getFullNodeInfo("test-module/test-name");
- nodeSetInfo.should.have.a.property('id',"test-module/test-name");
- nodeSetInfo.should.have.a.property('config');
- nodeSetInfo.should.have.a.property('file');
- });
- });
- describe('#cleanModuleList', function() {
- it.skip("cleans the module list");
- });
- describe('#getNodeList', function() {
- it("returns a filtered list", function() {
- typeRegistry.init(settings,{});
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
- "test-name":{
- id: "test-module/test-name",
- module: "test-module",
- name: "test-name",
- enabled: true,
- loaded: false,
- config: "configA",
- types: [ "test-a","test-b"],
- file: "abc"
- },
- "test-name-2":{
- id: "test-module/test-name-2",
- module: "test-module",
- name: "test-name-2",
- enabled: true,
- loaded: false,
- config: "configB",
- types: [ "test-c","test-d"],
- file: "def"
- }
- }});
- var filterCallCount = 0;
- var filteredList = typeRegistry.getNodeList(function(n) { filterCallCount++; return n.name === 'test-name-2';});
- filterCallCount.should.eql(2);
- filteredList.should.have.a.lengthOf(1);
- filteredList[0].should.have.a.property('id',"test-module/test-name-2");
- });
- });
-
- describe('#registerNodeConstructor', function() {
- var TestNodeConstructor;
- beforeEach(function() {
- TestNodeConstructor = function TestNodeConstructor() {};
- sinon.stub(events,'emit');
- });
- afterEach(function() {
- events.emit.restore();
- });
- it('registers a node constructor', function() {
- typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor);
- events.emit.calledOnce.should.be.true();
- events.emit.lastCall.args[0].should.eql('type-registered');
- events.emit.lastCall.args[1].should.eql('node-type');
- })
- it('throws error on duplicate node registration', function() {
- typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor);
- events.emit.calledOnce.should.be.true();
- events.emit.lastCall.args[0].should.eql('type-registered');
- events.emit.lastCall.args[1].should.eql('node-type');
- /*jshint immed: false */
- (function(){
- typeRegistry.registerNodeConstructor('node-set','node-type',TestNodeConstructor);
- }).should.throw("node-type already registered");
- events.emit.calledOnce.should.be.true();
- });
- });
-
- describe('#getNodeIconPath', function() {
- it('returns the null when getting an unknown icon', function() {
- var iconPath = typeRegistry.getNodeIconPath('random-module','youwonthaveme.png');
- should.not.exist(iconPath);
- });
-
- it('returns a registered icon' , function() {
- var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/');
- typeRegistry.init(settings,{});
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
- "test-name":{
- id: "test-module/test-name",
- module: "test-module",
- name: "test-name",
- enabled: true,
- loaded: false,
- config: "configA",
- types: [ "test-a","test-b"],
- file: "abc"
- }
- },icons: [{path:testIcon,icons:['test_icon.png']}]});
- var iconPath = typeRegistry.getNodeIconPath('test-module','test_icon.png');
- iconPath.should.eql(path.resolve(testIcon+"/test_icon.png"));
- });
-
- it('returns null when getting an unknown module', function() {
- var debugIcon = path.resolve(__dirname+'/../../../public/icons/debug.png');
- var iconPath = typeRegistry.getNodeIconPath('unknown-module', 'debug.png');
- should.not.exist(iconPath);
- });
- });
-
- describe('#getNodeIcons', function() {
- it('returns empty icon list when no modules are registered', function() {
- var iconList = typeRegistry.getNodeIcons();
- iconList.should.eql({});
- });
-
- it('returns an icon list of registered node module', function() {
- var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/');
- typeRegistry.init(settings,{});
- typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
- "test-name":{
- id: "test-module/test-name",
- module: "test-module",
- name: "test-name",
- enabled: true,
- loaded: false,
- config: "configA",
- types: [ "test-a","test-b"],
- file: "abc"
- }
- },icons: [{path:testIcon,icons:['test_icon.png']}]});
- var iconList = typeRegistry.getNodeIcons();
- iconList.should.eql({"test-module":["test_icon.png"]});
- });
- });
-
- describe('#getModuleResource', function() {
- beforeEach(function() {
- typeRegistry.init(settings,{});
- typeRegistry.addModule({
- name: "test-module",version:"0.0.1",nodes: {
- "test-name":{
- id: "test-module/test-name",
- module: "test-module",
- name: "test-name",
- enabled: true,
- loaded: false,
- config: "configA",
- types: [ "test-a","test-b"],
- file: "abc"
- }
- },
- resources: {
- path: path.join(__dirname, "resources","examples")
- }
- });
- });
- it('Returns valid resource path', function() {
- const result = typeRegistry.getModuleResource("test-module","one.json");
- should.exist(result);
- result.should.eql(path.join(__dirname, "resources","examples","one.json"))
- });
- it('Returns null for path that tries to break out', function() {
- // Note - this path exists, but we don't allow .. in the resolved path to
- // avoid breaking out of the resources dir
- const result = typeRegistry.getModuleResource("test-module","../../index_spec.js");
- should.not.exist(result);
- });
- it('Returns null for path that does not exist', function() {
- const result = typeRegistry.getModuleResource("test-module","two.json");
- should.not.exist(result);
- });
- });
-});
diff --git a/test/unit/@node-red/registry/lib/resources/examples/one.json b/test/unit/@node-red/registry/lib/resources/examples/one.json
deleted file mode 100644
index e69de29bb..000000000
diff --git a/test/unit/@node-red/registry/lib/resources/local/DuffNode/DuffNode.js b/test/unit/@node-red/registry/lib/resources/local/DuffNode/DuffNode.js
deleted file mode 100644
index 41e2a0059..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/DuffNode/DuffNode.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function DuffNode(n) {}
- RED.nodes.registerType("duff-node",DuffNode);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/DuplicateTestNode/TestNode1.html b/test/unit/@node-red/registry/lib/resources/local/DuplicateTestNode/TestNode1.html
deleted file mode 100644
index b637ede21..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/DuplicateTestNode/TestNode1.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/test/unit/@node-red/registry/lib/resources/local/DuplicateTestNode/TestNode1.js b/test/unit/@node-red/registry/lib/resources/local/DuplicateTestNode/TestNode1.js
deleted file mode 100644
index e81214169..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/DuplicateTestNode/TestNode1.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function DuplicateTestNode(n) {}
- RED.nodes.registerType("test-node-1",DuplicateTestNode);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/MultipleNodes1/MultipleNodes1.html b/test/unit/@node-red/registry/lib/resources/local/MultipleNodes1/MultipleNodes1.html
deleted file mode 100644
index 5359644e5..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/MultipleNodes1/MultipleNodes1.html
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
diff --git a/test/unit/@node-red/registry/lib/resources/local/MultipleNodes1/MultipleNodes1.js b/test/unit/@node-red/registry/lib/resources/local/MultipleNodes1/MultipleNodes1.js
deleted file mode 100644
index 55747c0b3..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/MultipleNodes1/MultipleNodes1.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function TestNode1(n) {}
- RED.nodes.registerType("test-node-multiple-1a",TestNode1);
- function TestNode2(n) {}
- RED.nodes.registerType("test-node-multiple-1b",TestNode2);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/NestedNode.html b/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/NestedNode.html
deleted file mode 100644
index abc823e8f..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/NestedNode.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/NestedNode.js b/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/NestedNode.js
deleted file mode 100644
index cd3148a58..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/NestedNode.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function TestNode(n) {}
- RED.nodes.registerType("nested-node-1",TestNode);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/icons/arrow-in.png b/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/icons/arrow-in.png
deleted file mode 100644
index e38f3914600901b736f5fa18786ee11be6d41c28..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 393
zcmeAS@N?(olHy`uVBq!ia0vp^B0wz1!3HFCgzU0`6icy_X9x!n)NrJ90QsB+9+AZi
z3~X;em{G3O!W1YdS>hT|5}cn_Ql40p%1~Zju9umYU7Va)kgAtols@~NjT8d|Bb%p-
zV~9uR+N-+$hZ97Oeyp#Y$RU!&XX#m>@|$agvYL9Jz$O6}72y^gZVi>ZMeaH^t*Q|!
zLhVk<0xdko8zYVo#8M-LBBd8b>1kw|i?FO)bWqsy_rwQg27N4y
zeX6pqO$_Cex^^A7_NsS@+=bOASA^wN0&GKN(hlAguRU&q-
jTBY?`*L>xN+|S&+7B*edvmQhOgN?z{)z4*}Q$iB}+9!`i
diff --git a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.html b/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.html
deleted file mode 100644
index ac9235d26..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.js b/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.js
deleted file mode 100644
index 8af249b14..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/lib/ShouldNotLoad.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function TestNode(n) {}
- RED.nodes.registerType("should-not-load-1",TestNode);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/node_modules/ShouldNotLoad.html b/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/node_modules/ShouldNotLoad.html
deleted file mode 100644
index eb7c8a3f9..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/node_modules/ShouldNotLoad.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/node_modules/ShouldNotLoad.js b/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/node_modules/ShouldNotLoad.js
deleted file mode 100644
index 623e299b2..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/node_modules/ShouldNotLoad.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function TestNode(n) {}
- RED.nodes.registerType("should-not-load-2",TestNode);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.html b/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.html
deleted file mode 100644
index 4212fd589..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.js b/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.js
deleted file mode 100644
index 5856adada..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/NestedDirectoryNode/NestedNode/test/ShouldNotLoad.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function TestNode(n) {}
- RED.nodes.registerType("should-not-load-3",TestNode);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode1/TestNode1.html b/test/unit/@node-red/registry/lib/resources/local/TestNode1/TestNode1.html
deleted file mode 100644
index 97dbf1710..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNode1/TestNode1.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-this should be filtered out
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode1/TestNode1.js b/test/unit/@node-red/registry/lib/resources/local/TestNode1/TestNode1.js
deleted file mode 100644
index bfa3b65bd..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNode1/TestNode1.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function TestNode(n) {}
- RED.nodes.registerType("test-node-1",TestNode);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.html b/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.html
deleted file mode 100644
index 66b65909e..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.html
+++ /dev/null
@@ -1,4 +0,0 @@
-
-
-
-
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.js b/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.js
deleted file mode 100644
index 1bf2fa6c9..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNode2/TestNode2.js
+++ /dev/null
@@ -1,9 +0,0 @@
-// A test node that exports a function which returns a resolving promise
-
-module.exports = function(RED) {
- return new Promise(function(resolve,reject) {
- function TestNode(n) {}
- RED.nodes.registerType("test-node-2",TestNode);
- resolve();
- });
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.html b/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.html
deleted file mode 100644
index 9a0f6f7ea..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.js b/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.js
deleted file mode 100644
index b9ee6a624..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNode3/TestNode3.js
+++ /dev/null
@@ -1,7 +0,0 @@
-// A test node that exports a function which returns a rejecting promise
-
-module.exports = function(RED) {
- return new Promise(function(resolve,reject) {
- reject("fail");
- });
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode4/TestNode4.html b/test/unit/@node-red/registry/lib/resources/local/TestNode4/TestNode4.html
deleted file mode 100644
index 9a0f6f7ea..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNode4/TestNode4.html
+++ /dev/null
@@ -1,3 +0,0 @@
-
-
-
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNode4/TestNode4.js b/test/unit/@node-red/registry/lib/resources/local/TestNode4/TestNode4.js
deleted file mode 100644
index c31255852..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNode4/TestNode4.js
+++ /dev/null
@@ -1 +0,0 @@
-throw new Error("fail to require");
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/EmptyModule/file.txt b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/EmptyModule/file.txt
deleted file mode 100644
index 0ce8dcaed..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/EmptyModule/file.txt
+++ /dev/null
@@ -1 +0,0 @@
-This file exists just to ensure the parent directory is in the repository.
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule.html b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule.html
deleted file mode 100644
index 17483f7ca..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-this should be filtered out
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule.js b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule.js
deleted file mode 100644
index c79c2ceb6..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function TestNode(n) {}
- RED.nodes.registerType("test-node-mod-1",TestNode);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule2.html b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule2.html
deleted file mode 100644
index a1f1b6c79..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule2.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-this should be filtered out
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule2.js b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule2.js
deleted file mode 100644
index d359fb3f2..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/TestNodeModule2.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- throw new Error("fail to load");
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/icons/arrow-in.png b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/icons/arrow-in.png
deleted file mode 100644
index e38f3914600901b736f5fa18786ee11be6d41c28..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 393
zcmeAS@N?(olHy`uVBq!ia0vp^B0wz1!3HFCgzU0`6icy_X9x!n)NrJ90QsB+9+AZi
z3~X;em{G3O!W1YdS>hT|5}cn_Ql40p%1~Zju9umYU7Va)kgAtols@~NjT8d|Bb%p-
zV~9uR+N-+$hZ97Oeyp#Y$RU!&XX#m>@|$agvYL9Jz$O6}72y^gZVi>ZMeaH^t*Q|!
zLhVk<0xdko8zYVo#8M-LBBd8b>1kw|i?FO)bWqsy_rwQg27N4y
zeX6pqO$_Cex^^A7_NsS@+=bOASA^wN0&GKN(hlAguRU&q-
jTBY?`*L>xN+|S&+7B*edvmQhOgN?z{)z4*}Q$iB}+9!`i
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/icons/file.txt b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/icons/file.txt
deleted file mode 100644
index 59a29af14..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/icons/file.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This file exists just to ensure the 'icons' directory is in the repository.
-TODO: a future test needs to ensure the right icon files are loaded - this
- directory can be used for that
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/package.json b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/package.json
deleted file mode 100644
index 8eba5b04b..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/TestNodeModule/package.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "name" : "TestNodeModule",
- "version" : "0.0.1",
- "description" : "A test node module",
- "node-red" : {
- "nodes": {
- "TestNodeMod1": "TestNodeModule.js",
- "TestNodeMod2": "TestNodeModule2.js"
- }
- }
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule.html b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule.html
deleted file mode 100644
index 17483f7ca..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-this should be filtered out
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule.js b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule.js
deleted file mode 100644
index c79c2ceb6..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule.js
+++ /dev/null
@@ -1,5 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- function TestNode(n) {}
- RED.nodes.registerType("test-node-mod-1",TestNode);
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule2.html b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule2.html
deleted file mode 100644
index a1f1b6c79..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule2.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-this should be filtered out
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule2.js b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule2.js
deleted file mode 100644
index d359fb3f2..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/TestNodeModule2.js
+++ /dev/null
@@ -1,4 +0,0 @@
-// A test node that exports a function
-module.exports = function(RED) {
- throw new Error("fail to load");
-}
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/icons/file.txt b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/icons/file.txt
deleted file mode 100644
index 59a29af14..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/icons/file.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-This file exists just to ensure the 'icons' directory is in the repository.
-TODO: a future test needs to ensure the right icon files are loaded - this
- directory can be used for that
diff --git a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/package.json b/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/package.json
deleted file mode 100644
index 4f9e46518..000000000
--- a/test/unit/@node-red/registry/lib/resources/local/TestNodeModule/node_modules/VersionMismatchModule/package.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "name" : "VersionMismatchModule",
- "version" : "0.0.1",
- "description" : "A test node module",
- "node-red" : {
- "version": "100.0.0",
- "nodes": {
- "VersionMismatchMod1": "TestNodeModule.js",
- "VersionMismatchMod2": "TestNodeModule2.js"
- }
- }
-}
diff --git a/test/unit/@node-red/registry/lib/resources/userDir/lib/icons/file.txt b/test/unit/@node-red/registry/lib/resources/userDir/lib/icons/file.txt
deleted file mode 100644
index e69de29bb..000000000
diff --git a/test/unit/@node-red/registry/lib/resources/userDir/lib/icons/test_icon.png b/test/unit/@node-red/registry/lib/resources/userDir/lib/icons/test_icon.png
deleted file mode 100644
index 4b6b7b5e9b10ec790348eb59f73bdac596e2f3b8..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 163
zcmeAS@N?(olHy`uVBq!ia0vp^B0wz1$P6UK?yS)OQjEnx?oJHr&dIz4a@YcVLR^9L
z|NsA&-kg6IB%S2#?!wT)D(eB{a29w(76Vni0bxeDQVUa{AbW|YuPggKZdPtVo=;b%
zu>pm|JY5_^IIbrr*#Br`l>NUU`M`mYFm{Gnm$g4<{K@tLs$lSR^>bP0l+XkK5O^!s
diff --git a/test/unit/@node-red/registry/lib/resources/userDir/nodes/TestNode5/TestNode5.html b/test/unit/@node-red/registry/lib/resources/userDir/nodes/TestNode5/TestNode5.html
deleted file mode 100644
index f38a3a24d..000000000
--- a/test/unit/@node-red/registry/lib/resources/userDir/nodes/TestNode5/TestNode5.html
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
-
-
-this should be filtered out
diff --git a/test/unit/@node-red/registry/lib/resources/userDir/nodes/TestNode5/TestNode5.js b/test/unit/@node-red/registry/lib/resources/userDir/nodes/TestNode5/TestNode5.js
deleted file mode 100644
index c31255852..000000000
--- a/test/unit/@node-red/registry/lib/resources/userDir/nodes/TestNode5/TestNode5.js
+++ /dev/null
@@ -1 +0,0 @@
-throw new Error("fail to require");
diff --git a/test/unit/@node-red/registry/lib/subflow_spec.js b/test/unit/@node-red/registry/lib/subflow_spec.js
deleted file mode 100644
index 2aa7db203..000000000
--- a/test/unit/@node-red/registry/lib/subflow_spec.js
+++ /dev/null
@@ -1,3 +0,0 @@
-describe("red/nodes/registry/subflow",function() {
- it.skip("NEEDS TESTS");
-});
diff --git a/test/unit/@node-red/registry/lib/util_spec.js b/test/unit/@node-red/registry/lib/util_spec.js
deleted file mode 100644
index 7e94d4fe5..000000000
--- a/test/unit/@node-red/registry/lib/util_spec.js
+++ /dev/null
@@ -1,115 +0,0 @@
-/**
- * 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.
- **/
-
-const should = require("should");
-const sinon = require("sinon");
-
-const NR_TEST_UTILS = require("nr-test-utils");
-const registryUtil = NR_TEST_UTILS.require("@node-red/registry/lib/util");
-
-// Get the internal runtime api
-const runtime = NR_TEST_UTILS.require("@node-red/runtime")._;
-
-const i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
-
-describe("red/nodes/registry/util",function() {
- describe("createNodeApi", function() {
- let i18n_;
- let registerType;
- let registerSubflow;
-
- before(function() {
- i18n_ = sinon.stub(i18n,"_").callsFake(function() {
- return Array.prototype.slice.call(arguments,0);
- })
- registerType = sinon.stub(runtime.nodes,"registerType");
- registerSubflow = sinon.stub(runtime.nodes,"registerSubflow");
- });
- after(function() {
- i18n_.restore();
- registerType.restore();
- registerSubflow.restore();
- })
-
- it("builds node-specific view of runtime api", function() {
- registryUtil.init(runtime);
- var result = registryUtil.createNodeApi({id: "my-node", namespace: "my-namespace"})
- // Need a better strategy here.
- // For now, validate the node-custom functions
-
- var message = result._("message");
- // This should prepend the node's namespace to the message
- message.should.eql([ 'my-namespace:message' ]);
-
- var nodeConstructor = () => {};
- var nodeOpts = {};
- result.nodes.registerType("type",nodeConstructor, nodeOpts);
- registerType.called.should.be.true();
- registerType.lastCall.args[0].should.eql("my-node")
- registerType.lastCall.args[1].should.eql("type")
- registerType.lastCall.args[2].should.eql(nodeConstructor)
- registerType.lastCall.args[3].should.eql(nodeOpts)
-
- var subflowDef = {};
- result.nodes.registerSubflow(subflowDef);
- registerSubflow.called.should.be.true();
- registerSubflow.lastCall.args[0].should.eql("my-node")
- registerSubflow.lastCall.args[1].should.eql(subflowDef)
-
- });
- });
- describe("checkModuleAllowed", function() {
- function checkList(module, version, allowList, denyList) {
- return registryUtil.checkModuleAllowed(
- module,
- version,
- registryUtil.parseModuleList(allowList),
- registryUtil.parseModuleList(denyList)
- )
- }
-
- it("allows module with no allow/deny list provided", function() {
- checkList("abc","1.2.3",[],[]).should.be.true();
- })
- it("defaults allow to * when only deny list is provided", function() {
- checkList("abc","1.2.3",["*"],["def"]).should.be.true();
- checkList("def","1.2.3",["*"],["def"]).should.be.false();
- })
- it("uses most specific matching rule", function() {
- checkList("abc","1.2.3",["ab*"],["a*"]).should.be.true();
- checkList("def","1.2.3",["d*"],["de*"]).should.be.false();
- })
- it("checks version string using semver rules", function() {
- // Deny
- checkList("abc","1.2.3",["abc@1.2.2"],["*"]).should.be.false();
- checkList("abc","1.2.3",["abc@1.2.4"],["*"]).should.be.false();
- checkList("abc","1.2.3",["abc@>1.2.3"],["*"]).should.be.false();
- checkList("abc","1.2.3",["abc@>=1.2.3"],["abc"]).should.be.false();
-
-
- checkList("node-red-contrib-foo","1.2.3",["*"],["*contrib*"]).should.be.false();
-
-
- // Allow
- checkList("abc","1.2.3",["abc@1.2.3"],["*"]).should.be.true();
- checkList("abc","1.2.3",["abc@<1.2.4"],["*"]).should.be.true();
- checkList("abc","1.2.3",["abc"],["abc@>1.2.3"]).should.be.true();
- checkList("abc","1.2.3",["abc"],["abc@<1.2.3||>1.2.3"]).should.be.true();
- checkList("node-red-contrib-foo","1.2.3",["*contrib*"],["*"]).should.be.true();
- })
-
- })
-});
diff --git a/test/unit/@node-red/runtime/lib/api/comms_spec.js b/test/unit/@node-red/runtime/lib/api/comms_spec.js
deleted file mode 100644
index 0097f5ce8..000000000
--- a/test/unit/@node-red/runtime/lib/api/comms_spec.js
+++ /dev/null
@@ -1,321 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var comms = NR_TEST_UTILS.require("@node-red/runtime/lib/api/comms");
-var events = NR_TEST_UTILS.require("@node-red/util/lib/events");
-
-describe("runtime-api/comms", function() {
- describe("listens for events", function() {
- var messages = [];
- var clientConnection = {
- send: function(topic,data) {
- messages.push({topic,data})
- }
- }
- var eventHandlers = {};
- before(function(done) {
- sinon.stub(events,"removeListener").callsFake(function() {})
- sinon.stub(events,"on").callsFake(function(evt,handler) { eventHandlers[evt] = handler })
- comms.init({
- log: {
- trace: function(){}
- }
- })
- comms.addConnection({client: clientConnection}).then(done);
- })
- after(function(done) {
- comms.removeConnection({client: clientConnection}).then(done);
- events.removeListener.restore();
- events.on.restore();
- })
- afterEach(function() {
- messages = [];
- })
-
- it('runtime events',function(){
- eventHandlers.should.have.property('runtime-event');
- eventHandlers['runtime-event']({
- id: "my-event",
- payload: "my-payload"
- })
- messages.should.have.length(1);
- messages[0].should.have.property("topic","notification/my-event");
- messages[0].should.have.property("data","my-payload")
- })
- it('status events',function(){
- eventHandlers.should.have.property('node-status');
- eventHandlers['node-status']({
- id: "my-event",
- status: {text:"my-status",badProperty:"should be filtered"}
- })
- messages.should.have.length(1);
- messages[0].should.have.property("topic","status/my-event");
- messages[0].should.have.property("data");
- messages[0].data.should.have.property("text","my-status");
- messages[0].data.should.not.have.property("badProperty");
-
- })
- it('comms events',function(){
- eventHandlers.should.have.property('runtime-event');
- eventHandlers['comms']({
- topic: "my-topic",
- data: "my-payload"
- })
- messages.should.have.length(1);
- messages[0].should.have.property("topic","my-topic");
- messages[0].should.have.property("data","my-payload")
- })
- });
- describe("manages connections", function() {
- var eventHandlers = {};
- var messages = [];
- var clientConnection1 = {
- send: function(topic,data) {
- messages.push({topic,data})
- }
- }
- var clientConnection2 = {
- send: function(topic,data) {
- messages.push({topic,data})
- }
- }
- before(function() {
- sinon.stub(events,"removeListener").callsFake(function() {})
- sinon.stub(events,"on").callsFake(function(evt,handler) { eventHandlers[evt] = handler })
- comms.init({
- log: {
- trace: function(){}
- }
- })
- })
- after(function() {
- events.removeListener.restore();
- events.on.restore();
- })
- afterEach(function(done) {
- comms.removeConnection({client: clientConnection1}).then(function() {
- comms.removeConnection({client: clientConnection2}).then(done);
- });
- messages = [];
- })
- it('adds new connections',function(done){
- eventHandlers['comms']({
- topic: "my-topic",
- data: "my-payload"
- })
- messages.should.have.length(0);
- comms.addConnection({client: clientConnection1}).then(function() {
- eventHandlers['comms']({
- topic: "my-topic",
- data: "my-payload"
- })
- messages.should.have.length(1);
- comms.addConnection({client: clientConnection2}).then(function() {
- eventHandlers['comms']({
- topic: "my-topic",
- data: "my-payload"
- })
- messages.should.have.length(3);
- done();
- }).catch(done);
- });
- });
- it('removes connections',function(done){
- eventHandlers['comms']({
- topic: "my-topic",
- data: "my-payload"
- })
- messages.should.have.length(0);
- comms.addConnection({client: clientConnection1}).then(function() {
- comms.addConnection({client: clientConnection2}).then(function() {
- eventHandlers['comms']({
- topic: "my-topic",
- data: "my-payload"
- })
- messages.should.have.length(2);
- comms.removeConnection({client: clientConnection1}).then(function() {
- eventHandlers['comms']({
- topic: "my-topic",
- data: "my-payload"
- })
- messages.should.have.length(3);
- done();
- });
- }).catch(done);
- });
- })
- })
-
- describe("subscriptions", function() {
- var messages = [];
- var clientConnection = {
- send: function(topic,data) {
- messages.push({topic,data})
- }
- }
- var clientConnection2 = {
- send: function(topic,data) {
- messages.push({topic,data})
- }
- }
- var eventHandlers = {};
- before(function() {
- sinon.stub(events,"removeListener").callsFake(function() {})
- sinon.stub(events,"on").callsFake(function(evt,handler) { eventHandlers[evt] = handler })
- comms.init({
- log: {
- trace: function(){}
- }
- })
- })
- after(function() {
- events.removeListener.restore();
- events.on.restore();
- })
- afterEach(function(done) {
- messages = [];
- comms.removeConnection({client: clientConnection}).then(done);
- })
-
- it('subscribe triggers retained messages',function(done){
- eventHandlers['comms']({
- topic: "my-event",
- data: "my-payload",
- retain: true
- })
- messages.should.have.length(0);
- comms.addConnection({client: clientConnection}).then(function() {
- return comms.subscribe({client: clientConnection, topic: "my-event"}).then(function() {
- messages.should.have.length(1);
- messages[0].should.have.property("topic","my-event");
- messages[0].should.have.property("data","my-payload");
- done();
- });
- }).catch(done);
- })
- it('retains non-blank status message',function(done){
- eventHandlers['node-status']({
- id: "node1234",
- status: {text:"hello"}
- })
- messages.should.have.length(0);
- comms.addConnection({client: clientConnection}).then(function() {
- return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() {
- messages.should.have.length(1);
- messages[0].should.have.property("topic","status/node1234");
- messages[0].should.have.property("data",{text:"hello", fill: undefined, shape: undefined});
- done();
- });
- }).catch(done);
- })
- it('does not retain blank status message',function(done){
- eventHandlers['node-status']({
- id: "node1234",
- status: {}
- })
- messages.should.have.length(0);
- comms.addConnection({client: clientConnection}).then(function() {
- return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() {
- messages.should.have.length(0);
- done();
- });
- }).catch(done);
- })
- it('does not send blank status if first status',function(done){
- messages.should.have.length(0);
- comms.addConnection({client: clientConnection}).then(function() {
- return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() {
- eventHandlers['node-status']({
- id: "node5678",
- status: {}
- })
- messages.should.have.length(0);
- done()
- })
- }).catch(done);
- });
- it('sends blank status if replacing retained',function(done){
- eventHandlers['node-status']({
- id: "node5678",
- status: {text:"hello"}
- })
- messages.should.have.length(0);
- comms.addConnection({client: clientConnection}).then(function() {
- return comms.subscribe({client: clientConnection, topic: "status/#"}).then(function() {
- messages.should.have.length(1);
- eventHandlers['node-status']({
- id: "node5678",
- status: {}
- })
- messages.should.have.length(2);
- done()
- })
- }).catch(done);
- });
-
- it('does not retain initial status blank message',function(done){
- eventHandlers['node-status']({
- id: "my-event",
- status: {}
- })
- messages.should.have.length(0);
- comms.addConnection({client: clientConnection}).then(function() {
- return comms.subscribe({client: clientConnection, topic: "my-event"}).then(function() {
- messages.should.have.length(1);
- messages[0].should.have.property("topic","my-event");
- messages[0].should.have.property("data","my-payload");
- done();
- });
- }).catch(done);
- })
-
- it('retained messages get cleared',function(done) {
- eventHandlers['comms']({
- topic: "my-event",
- data: "my-payload",
- retain: true
- })
- messages.should.have.length(0);
- comms.addConnection({client: clientConnection}).then(function() {
- return comms.subscribe({client: clientConnection, topic: "my-event"}).then(function() {
- messages.should.have.length(1);
- messages[0].should.have.property("topic","my-event");
- messages[0].should.have.property("data","my-payload");
- // Now we have a retained message, clear it
- eventHandlers['comms']({
- topic: "my-event",
- data: "my-payload-cleared"
- });
- messages.should.have.length(2);
- messages[1].should.have.property("topic","my-event");
- messages[1].should.have.property("data","my-payload-cleared");
- // Now add a second client and subscribe - no message should arrive
- return comms.addConnection({client: clientConnection2}).then(function() {
- return comms.subscribe({client: clientConnection2, topic: "my-event"}).then(function() {
- messages.should.have.length(2);
- done();
- });
- });
- });
- }).catch(done);
- });
- })
-
-});
diff --git a/test/unit/@node-red/runtime/lib/api/context_spec.js b/test/unit/@node-red/runtime/lib/api/context_spec.js
deleted file mode 100644
index bf23e9cc6..000000000
--- a/test/unit/@node-red/runtime/lib/api/context_spec.js
+++ /dev/null
@@ -1,353 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var context = NR_TEST_UTILS.require("@node-red/runtime/lib/api/context");
-
-var mockLog = () => ({
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc";}
-});
-
-var mockContext = function(contents) {
- return {
- get: function(key,store,callback) {
- if (contents.hasOwnProperty(store) && contents[store].hasOwnProperty(key)) {
- callback(null,contents[store][key]);
- } else {
- callback(null,undefined);
- }
- },
- set: function (key, value, store, callback) {
- if (contents.hasOwnProperty(store)) {
- if (!value) {
- delete contents[store][key];
- callback(null);
- }
- } else {
- callback("err store");
- }
- },
- keys: function (store, callback) {
- if (contents.hasOwnProperty(store)) {
- callback(null, Object.keys(contents[store]));
- } else {
- callback("err store");
- }
- }
- };
-};
-
-describe("runtime-api/context", function() {
- var globalContext, flowContext, nodeContext, contexts;
-
- beforeEach(function() {
- globalContext = { default: { abc: 111 }, file: { abc: 222 } };
- flowContext = { default: { abc: 333 }, file: { abc: 444 } };
- nodeContext = { default: { abc: 555 }, file: { abc: 666 } };
- contexts = {
- global: mockContext(globalContext),
- flow1: mockContext(flowContext)
- };
- context.init({
- nodes: {
- listContextStores: function() {
- return { default: 'default', stores: [ 'default', 'file' ] };
- },
- getContext: function(id) {
- return contexts[id];
- },
- getNode: function(id) {
- if (id === 'known') {
- return {
- context: function() { return mockContext(nodeContext); }
- };
- } else {
- return null;
- }
- }
- },
- settings: {
- functionGlobalContext: {
- fgc:1234
- }
- },
- log: mockLog()
- });
- });
-
- describe("getValue", function() {
- it('gets global value of default store', function() {
- return context.getValue({
- scope: 'global',
- id: undefined,
- store: undefined, // use default
- key: 'abc'
- }).then(function(result) {
- result.should.have.property('msg','111');
- result.should.have.property('format','number');
- });
- });
-
- it('gets global value of specified store', function() {
- return context.getValue({
- scope: 'global',
- id: undefined,
- store: 'file',
- key: 'abc'
- }).then(function(result) {
- result.should.have.property('msg','222');
- result.should.have.property('format','number');
- });
- });
-
- it('gets flow value of default store', function() {
- return context.getValue({
- scope: 'flow',
- id: 'flow1',
- store: undefined, // use default
- key: 'abc'
- }).then(function(result) {
- result.should.have.property('msg','333');
- result.should.have.property('format','number');
- });
- });
-
- it('gets flow value of specified store', function() {
- return context.getValue({
- scope: 'flow',
- id: 'flow1',
- store: 'file',
- key: 'abc'
- }).then(function(result) {
- result.should.have.property('msg','444');
- result.should.have.property('format','number');
- });
- });
-
- it('gets node value of default store', function() {
- return context.getValue({
- scope: 'node',
- id: 'known',
- store: undefined, // use default
- key: 'abc'
- }).then(function(result) {
- result.should.have.property('msg','555');
- result.should.have.property('format','number');
- });
- });
-
- it('gets node value of specified store', function() {
- return context.getValue({
- scope: 'node',
- id: 'known',
- store: 'file',
- key: 'abc'
- }).then(function(result) {
- result.should.have.property('msg','666');
- result.should.have.property('format','number');
- });
- });
-
- it('404s for unknown store', function(done) {
- context.getValue({
- scope: 'global',
- id: undefined,
- store: 'unknown',
- key: 'abc'
- }).then(function(result) {
- done("getValue for unknown store should not resolve");
- }).catch(function(err) {
- err.should.have.property('code','not_found');
- err.should.have.property('status',404);
- done();
- });
- });
-
- it('gets all global value properties', function() {
- return context.getValue({
- scope: 'global',
- id: undefined,
- store: undefined, // use default
- key: undefined, //
- }).then(function(result) {
- result.should.eql({
- default: { abc: { msg: '111', format: 'number' } },
- file: { abc: { msg: '222', format: 'number' } }
- });
- });
- });
-
- it('gets all flow value properties', function() {
- return context.getValue({
- scope: 'flow',
- id: 'flow1',
- store: undefined, // use default
- key: undefined, //
- }).then(function(result) {
- result.should.eql({
- default: { abc: { msg: '333', format: 'number' } },
- file: { abc: { msg: '444', format: 'number' } }
- });
- });
- });
-
- it('gets all node value properties', function() {
- return context.getValue({
- scope: 'node',
- id: 'known',
- store: undefined, // use default
- key: undefined, //
- }).then(function(result) {
- result.should.eql({
- default: { abc: { msg: '555', format: 'number' } },
- file: { abc: { msg: '666', format: 'number' } }
- });
- });
- });
-
- it('gets empty object when specified context doesn\'t exist', function() {
- return context.getValue({
- scope: 'node',
- id: 'non-existent',
- store: 'file',
- key: 'abc'
- }).then(function(result) {
- result.should.be.an.Object();
- result.should.be.empty();
- });
- });
- });
-
- describe("delete", function () {
- it('deletes global value of default store', function () {
- return context.delete({
- scope: 'global',
- id: undefined,
- store: undefined, // use default
- key: 'abc'
- }).then(function () {
- globalContext.should.eql({
- default: {}, file: { abc: 222 }
- });
- });
- });
-
- it('deletes global value of specified store', function () {
- return context.delete({
- scope: 'global',
- id: undefined,
- store: 'file',
- key: 'abc'
- }).then(function () {
- globalContext.should.eql({
- default: { abc: 111 }, file: {}
- });
- });
- });
-
- it('deletes flow value of default store', function () {
- return context.delete({
- scope: 'flow',
- id: 'flow1',
- store: undefined, // use default
- key: 'abc'
- }).then(function () {
- flowContext.should.eql({
- default: {}, file: { abc: 444 }
- });
- });
- });
-
- it('deletes flow value of specified store', function () {
- return context.delete({
- scope: 'flow',
- id: 'flow1',
- store: 'file',
- key: 'abc'
- }).then(function () {
- flowContext.should.eql({
- default: { abc: 333 }, file: {}
- });
- });
- });
-
- it('deletes node value of default store', function () {
- return context.delete({
- scope: 'node',
- id: 'known',
- store: undefined, // use default
- key: 'abc'
- }).then(function () {
- nodeContext.should.eql({
- default: {}, file: { abc: 666 }
- });
- });
- });
-
- it('deletes node value of specified store', function () {
- return context.delete({
- scope: 'node',
- id: 'known',
- store: 'file',
- key: 'abc'
- }).then(function () {
- nodeContext.should.eql({
- default: { abc: 555 }, file: {}
- });
- });
- });
-
- it('does nothing when specified context doesn\'t exist', function() {
- return context.delete({
- scope: 'node',
- id: 'non-existent',
- store: 'file',
- key: 'abc'
- }).then(function(result) {
- should.not.exist(result);
- nodeContext.should.eql({
- default: { abc: 555 }, file: { abc: 666 }
- });
- });
- });
-
- it('404s for unknown store', function (done) {
- context.delete({
- scope: 'global',
- id: undefined,
- store: 'unknown',
- key: 'abc'
- }).then(function () {
- done("delete for unknown store should not resolve");
- }).catch(function (err) {
- err.should.have.property('code', 'not_found');
- err.should.have.property('status', 404);
- done();
- });
- });
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/api/flows_spec.js b/test/unit/@node-red/runtime/lib/api/flows_spec.js
deleted file mode 100644
index 9062ef52f..000000000
--- a/test/unit/@node-red/runtime/lib/api/flows_spec.js
+++ /dev/null
@@ -1,430 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/api/flows")
-
-var mockLog = () => ({
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc"}
-})
-
-describe("runtime-api/flows", function() {
- describe("getFlows", function() {
- it("returns the current flow configuration", function(done) {
- flows.init({
- log: mockLog(),
- flows: {
- getFlows: function() { return [1,2,3] }
- }
- });
- flows.getFlows({}).then(function(result) {
- result.should.eql([1,2,3]);
- done();
- }).catch(done);
- });
- });
-
- describe("setFlows", function() {
- var setFlows;
- var loadFlows;
- var reloadError = false;
- beforeEach(function() {
- setFlows = sinon.spy(function(flows,credentials,type) {
- if (flows[0] === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- }
- return Promise.resolve("newRev");
- });
- loadFlows = sinon.spy(function() {
- if (!reloadError) {
- return Promise.resolve("newLoadRev");
- } else {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- }
- })
- flows.init({
- log: mockLog(),
- flows: {
- getFlows: function() { return {rev:"currentRev",flows:[]} },
- setFlows: setFlows,
- loadFlows: loadFlows
- }
- })
-
- })
- it("defaults to full deploy", function(done) {
- flows.setFlows({
- flows: {flows:[4,5,6]}
- }).then(function(result) {
- result.should.eql({rev:"newRev"});
- setFlows.called.should.be.true();
- setFlows.lastCall.args[0].should.eql([4,5,6]);
- setFlows.lastCall.args[2].should.eql("full");
- done();
- }).catch(done);
- });
- it("includes credentials when part of the request", function(done) {
- flows.setFlows({
- flows: {flows:[4,5,6], credentials: {$:"creds"}},
- }).then(function(result) {
- result.should.eql({rev:"newRev"});
- setFlows.called.should.be.true();
- setFlows.lastCall.args[0].should.eql([4,5,6]);
- setFlows.lastCall.args[1].should.eql({$:"creds"});
- setFlows.lastCall.args[2].should.eql("full");
- done();
- }).catch(done);
- });
- it("passes through other deploy types", function(done) {
- flows.setFlows({
- deploymentType: "nodes",
- flows: {flows:[4,5,6]}
- }).then(function(result) {
- result.should.eql({rev:"newRev"});
- setFlows.called.should.be.true();
- setFlows.lastCall.args[0].should.eql([4,5,6]);
- setFlows.lastCall.args[2].should.eql("nodes");
- done();
- }).catch(done);
- });
- it("triggers a flow reload", function(done) {
- flows.setFlows({
- deploymentType: "reload"
- }).then(function(result) {
- result.should.eql({rev:"newLoadRev"});
- setFlows.called.should.be.false();
- loadFlows.called.should.be.true();
- done();
- }).catch(done);
- });
- it("allows update when revision matches", function(done) {
- flows.setFlows({
- deploymentType: "nodes",
- flows: {flows:[4,5,6],rev:"currentRev"}
- }).then(function(result) {
- result.should.eql({rev:"newRev"});
- setFlows.called.should.be.true();
- setFlows.lastCall.args[0].should.eql([4,5,6]);
- setFlows.lastCall.args[2].should.eql("nodes");
- done();
- }).catch(done);
- });
- it("rejects update when revision does not match", function(done) {
- flows.setFlows({
- deploymentType: "nodes",
- flows: {flows:[4,5,6],rev:"notTheCurrentRev"}
- }).then(function(result) {
- done(new Error("Did not reject rev mismatch"));
- }).catch(function(err) {
- err.should.have.property('code','version_mismatch');
- err.should.have.property('status',409);
- done();
- }).catch(done);
- });
- it("rejects when reload fails",function(done) {
- reloadError = true;
- flows.setFlows({
- deploymentType: "reload"
- }).then(function(result) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- done();
- }).catch(done);
- });
- it("rejects when update fails",function(done) {
- flows.setFlows({
- deploymentType: "full",
- flows: {flows:["error",5,6]}
- }).then(function(result) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- done();
- }).catch(done);
- });
- });
-
- describe("addFlow", function() {
- var addFlow;
- beforeEach(function() {
- addFlow = sinon.spy(function(flow) {
- if (flow === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- }
- return Promise.resolve("newId");
- });
- flows.init({
- log: mockLog(),
- flows: {
- addFlow: addFlow
- }
- });
- })
- it("adds a flow", function(done) {
- flows.addFlow({flow:{a:"123"}}).then(function(id) {
- addFlow.called.should.be.true();
- addFlow.lastCall.args[0].should.eql({a:"123"});
- id.should.eql("newId");
- done()
- }).catch(done);
- });
- it("rejects when add fails", function(done) {
- flows.addFlow({flow:"error"}).then(function(id) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- done();
- }).catch(done);
- });
- });
- describe("getFlow", function() {
- var getFlow;
- beforeEach(function() {
- getFlow = sinon.spy(function(flow) {
- if (flow === "unknown") {
- return null;
- }
- return [1,2,3];
- });
- flows.init({
- log: mockLog(),
- flows: {
- getFlow: getFlow
- }
- });
- })
- it("gets a flow", function(done) {
- flows.getFlow({id:"123"}).then(function(flow) {
- flow.should.eql([1,2,3]);
- done()
- }).catch(done);
- });
- it("rejects when flow not found", function(done) {
- flows.getFlow({id:"unknown"}).then(function(flow) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','not_found');
- err.should.have.property('status',404);
- done();
- }).catch(done);
- });
- });
-
- describe("updateFlow", function() {
- var updateFlow;
- beforeEach(function() {
- updateFlow = sinon.spy(function(id,flow) {
- if (id === "unknown") {
- var err = new Error();
- // TODO: quirk of internal api - uses .code for .status
- err.code = 404;
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else if (id === "error") {
- var err = new Error();
- // TODO: quirk of internal api - uses .code for .status
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- }
- return Promise.resolve();
- });
- flows.init({
- log: mockLog(),
- flows: {
- updateFlow: updateFlow
- }
- });
- })
- it("updates a flow", function(done) {
- flows.updateFlow({id:"123",flow:[1,2,3]}).then(function(id) {
- id.should.eql("123");
- updateFlow.called.should.be.true();
- updateFlow.lastCall.args[0].should.eql("123");
- updateFlow.lastCall.args[1].should.eql([1,2,3]);
- done()
- }).catch(done);
- });
- it("rejects when flow not found", function(done) {
- flows.updateFlow({id:"unknown"}).then(function(flow) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','not_found');
- err.should.have.property('status',404);
- done();
- }).catch(done);
- });
- it("rejects when update fails", function(done) {
- flows.updateFlow({id:"error"}).then(function(flow) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
-
- describe("deleteFlow", function() {
- var removeFlow;
- beforeEach(function() {
- removeFlow = sinon.spy(function(flow) {
- if (flow === "unknown") {
- var err = new Error();
- // TODO: quirk of internal api - uses .code for .status
- err.code = 404;
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else if (flow === "error") {
- var err = new Error();
- // TODO: quirk of internal api - uses .code for .status
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- }
- return Promise.resolve();
- });
- flows.init({
- log: mockLog(),
- flows: {
- removeFlow: removeFlow
- }
- });
- })
- it("deletes a flow", function(done) {
- flows.deleteFlow({id:"123"}).then(function() {
- removeFlow.called.should.be.true();
- removeFlow.lastCall.args[0].should.eql("123");
- done()
- }).catch(done);
- });
- it("rejects when flow not found", function(done) {
- flows.deleteFlow({id:"unknown"}).then(function(flow) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','not_found');
- err.should.have.property('status',404);
- done();
- }).catch(done);
- });
- it("rejects when delete fails", function(done) {
- flows.deleteFlow({id:"error"}).then(function(flow) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("getNodeCredentials", function() {
- beforeEach(function() {
- flows.init({
- log: mockLog(),
- nodes: {
- getCredentials: function(id) {
- if (id === "unknown") {
- return undefined;
- } else if (id === "known") {
- return {
- username: "abc",
- password: "123"
- }
- } else if (id === "known2") {
- return {
- username: "abc",
- password: ""
- }
- } else {
- return {};
- }
- },
- getCredentialDefinition: function(type) {
- if (type === "node") {
- return {
- username: {type:"text"},
- password: {type:"password"}
- }
- } else {
- return null;
- }
- }
- }
- });
- })
- it("returns an empty object for an unknown node", function(done) {
- flows.getNodeCredentials({id:"unknown", type:"node"}).then(function(result) {
- result.should.eql({});
- done();
- }).catch(done);
- });
- it("gets the filtered credentials for a known node with password", function(done) {
- flows.getNodeCredentials({id:"known", type:"node"}).then(function(result) {
- result.should.eql({
- username: "abc",
- has_password: true
- });
- done();
- }).catch(done);
- });
- it("gets the filtered credentials for a known node without password", function(done) {
- flows.getNodeCredentials({id:"known2", type:"node"}).then(function(result) {
- result.should.eql({
- username: "abc",
- has_password: false
- });
- done();
- }).catch(done);
- });
- it("gets the empty credentials for a known node without a registered definition", function(done) {
- flows.getNodeCredentials({id:"known2", type:"unknown-type"}).then(function(result) {
- result.should.eql({});
- done();
- }).catch(done);
- });
- });
-
-});
diff --git a/test/unit/@node-red/runtime/lib/api/index_spec.js b/test/unit/@node-red/runtime/lib/api/index_spec.js
deleted file mode 100644
index ecedf22ef..000000000
--- a/test/unit/@node-red/runtime/lib/api/index_spec.js
+++ /dev/null
@@ -1,55 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var index = NR_TEST_UTILS.require("@node-red/runtime/lib/api/index");
-
-
-describe("runtime-api/index", function() {
- before(function() {
- ["comms","flows","nodes","settings","library","projects"].forEach(n => {
- sinon.stub(NR_TEST_UTILS.require(`@node-red/runtime/lib/api/${n}`),"init").callsFake(()=>{});
- })
- });
- after(function() {
- ["comms","flows","nodes","settings","library","projects"].forEach(n => {
- NR_TEST_UTILS.require(`@node-red/runtime/lib/api/${n}`).init.restore()
- })
- })
- it('isStarted', function(done) {
- index.init({
- isStarted: ()=>true
- });
- index.isStarted({}).then(function(started) {
- started.should.be.true();
- done();
- }).catch(done);
- })
-
- it('isStarted', function(done) {
- index.init({
- version: ()=>"1.2.3.4"
- });
- index.version({}).then(function(version) {
- version.should.eql("1.2.3.4");
- done();
- }).catch(done);
- })
-
-});
diff --git a/test/unit/@node-red/runtime/lib/api/library_spec.js b/test/unit/@node-red/runtime/lib/api/library_spec.js
deleted file mode 100644
index 3fa5291d2..000000000
--- a/test/unit/@node-red/runtime/lib/api/library_spec.js
+++ /dev/null
@@ -1,167 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var library = NR_TEST_UTILS.require("@node-red/runtime/lib/api/library")
-
-var mockLog = {
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc"}
-}
-
-describe("runtime-api/library", function() {
- describe("getEntry", function() {
- before(function() {
- library.init({
- log: mockLog,
- library: {
- getEntry: function(library, type,path) {
- if (type === "known") {
- return Promise.resolve("known");
- } else if (type === "forbidden") {
- var err = new Error("forbidden");
- err.code = "forbidden";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else if (type === "not_found") {
- var err = new Error("forbidden");
- err.code = "not_found";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else if (type === "error") {
- var err = new Error("error");
- err.code = "unknown_error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else if (type === "blank") {
- return Promise.reject();
- }
- }
- }
- })
- })
- it("returns a known entry", function(done) {
- library.getEntry({library: "local",type: "known", path: "/abc"}).then(function(result) {
- result.should.eql("known")
- done();
- }).catch(done)
- })
- it("rejects a forbidden entry", function(done) {
- library.getEntry({library: "local",type: "forbidden", path: "/abc"}).then(function(result) {
- done(new Error("did not reject"));
- }).catch(function(err) {
- err.should.have.property("code","forbidden");
- err.should.have.property("status",403);
- done();
- }).catch(done)
- })
- it("rejects an unknown entry", function(done) {
- library.getEntry({library: "local",type: "not_found", path: "/abc"}).then(function(result) {
- done(new Error("did not reject"));
- }).catch(function(err) {
- err.should.have.property("code","not_found");
- err.should.have.property("status",404);
- done();
- }).catch(done)
- })
- it("rejects a blank (unknown) entry", function(done) {
- library.getEntry({library: "local",type: "blank", path: "/abc"}).then(function(result) {
- done(new Error("did not reject"));
- }).catch(function(err) {
- err.should.have.property("code","not_found");
- err.should.have.property("status",404);
- done();
- }).catch(done)
- })
- it("rejects unexpected error", function(done) {
- library.getEntry({library: "local",type: "error", path: "/abc"}).then(function(result) {
- done(new Error("did not reject"));
- }).catch(function(err) {
- err.should.have.property("status",400);
- done();
- }).catch(done)
- })
- })
- describe("saveEntry", function() {
- var opts;
- before(function() {
- library.init({
- log: mockLog,
- library: {
- saveEntry: function(library,type,path,meta,body) {
- opts = {type,path,meta,body};
- if (type === "known") {
- return Promise.resolve();
- } else if (type === "forbidden") {
- var err = new Error("forbidden");
- err.code = "forbidden";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else if (type === "not_found") {
- var err = new Error("forbidden");
- err.code = "not_found";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- }
- }
- }
- })
- })
-
- it("saves an entry", function(done) {
- library.saveEntry({library: "local",type: "known", path: "/abc", meta: {a:1}, body:"123"}).then(function() {
- opts.should.have.property("type","known");
- opts.should.have.property("path","/abc");
- opts.should.have.property("meta",{a:1});
- opts.should.have.property("body","123");
- done();
- }).catch(done)
- })
- it("rejects a forbidden entry", function(done) {
- library.saveEntry({library: "local",type: "forbidden", path: "/abc", meta: {a:1}, body:"123"}).then(function() {
- done(new Error("did not reject"));
- }).catch(function(err) {
- err.should.have.property("code","forbidden");
- err.should.have.property("status",403);
- done();
- }).catch(done)
- })
- it("rejects an unknown entry", function(done) {
- library.saveEntry({library: "local",type: "not_found", path: "/abc", meta: {a:1}, body:"123"}).then(function() {
- done(new Error("did not reject"));
- }).catch(function(err) {
- err.should.have.property("status",400);
- done();
- }).catch(done)
- })
- })
-
-});
diff --git a/test/unit/@node-red/runtime/lib/api/nodes_spec.js b/test/unit/@node-red/runtime/lib/api/nodes_spec.js
deleted file mode 100644
index 60c6d9edd..000000000
--- a/test/unit/@node-red/runtime/lib/api/nodes_spec.js
+++ /dev/null
@@ -1,1005 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var nodes = NR_TEST_UTILS.require("@node-red/runtime/lib/api/nodes")
-
-var mockLog = () => ({
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc"}
-})
-
-describe("runtime-api/nodes", function() {
- describe("getNodeInfo", function() {
- beforeEach(function() {
- nodes.init({
- log: mockLog(),
- nodes: {
- getNodeInfo: function(id) {
- if (id === "known") {
- return {id:"known"};
- } else {
- return null;
- }
- }
- }
- });
- })
- it("returns node info", function(done) {
- nodes.getNodeInfo({id:"known"}).then(function(result) {
- result.should.eql({id:"known"});
- done();
- }).catch(done);
- });
- it("returns 404 if node not known", function(done) {
- nodes.getNodeInfo({id:"unknown"}).then(function(result) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','not_found');
- err.should.have.property('status',404);
- done();
- }).catch(done);
- });
- });
- describe("getNodeList", function() {
- beforeEach(function() {
- nodes.init({
- log: mockLog(),
- nodes: {
- getNodeList: function() {
- return [1,2,3];
- }
- }
- });
- })
- it("returns node list", function(done) {
- nodes.getNodeList({}).then(function(result) {
- result.should.eql([1,2,3]);
- done();
- }).catch(done);
- });
- });
-
- describe("getNodeConfig", function() {
- beforeEach(function() {
- nodes.init({
- log: mockLog(),
- nodes: {
- getNodeConfig: function(id,lang) {
- if (id === "known") {
- return id+lang;
- } else {
- return null;
- }
- }
- }
- });
- })
- it("returns node config", function(done) {
- nodes.getNodeConfig({id:"known",lang:'lang'}).then(function(result) {
- result.should.eql("knownlang");
- done();
- }).catch(done);
- });
- it("returns 404 if node not known", function(done) {
- nodes.getNodeConfig({id:"unknown",lang:'lang'}).then(function(result) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','not_found');
- err.should.have.property('status',404);
- done();
- }).catch(done);
- });
- });
-
- describe("getNodeConfigs", function() {
- beforeEach(function() {
- nodes.init({
- log: mockLog(),
- nodes: {
- getNodeConfigs: function(lang) {
- return lang;
- }
- }
- });
- })
- it("returns all node configs", function(done) {
- nodes.getNodeConfigs({lang:'lang'}).then(function(result) {
- result.should.eql("lang");
- done();
- }).catch(done);
- });
- });
-
- describe("getModuleInfo", function() {
- beforeEach(function() {
- nodes.init({
- log: mockLog(),
- nodes: {
- getModuleInfo: function(id) {
- if (id === "known") {
- return {module:"known"};
- } else {
- return null;
- }
- }
- }
- });
- })
- it("returns node info", function(done) {
- nodes.getModuleInfo({module:"known"}).then(function(result) {
- result.should.eql({module:"known"});
- done();
- }).catch(done);
- });
- it("returns 404 if node not known", function(done) {
- nodes.getModuleInfo({module:"unknown"}).then(function(result) {
- done(new Error("Did not return internal error"));
- }).catch(function(err) {
- err.should.have.property('code','not_found');
- err.should.have.property('status',404);
- done();
- }).catch(done);
- });
- });
-
- describe.skip("addModule", function() {});
- describe.skip("removeModule", function() {});
- describe.skip("setModuleState", function() {});
- describe.skip("setNodeSetState", function() {});
-
- describe.skip("getModuleCatalogs", function() {});
- describe.skip("getModuleCatalog", function() {});
-
- describe.skip("getIconList", function() {});
- describe.skip("getIcon", function() {});
-
-
-});
-
-/*
-var should = require("should");
-var request = require('supertest');
-var express = require('express');
-var bodyParser = require('body-parser');
-var sinon = require('sinon');
-
-var nodes = require("../../../../red/api/admin/nodes");
-var apiUtil = require("../../../../red/api/util");
-
-describe("api/admin/nodes", function() {
-
- var app;
- function initNodes(runtime) {
- runtime.log = {
- audit:function(e){},//console.log(e)},
- _:function(){},
- info: function(){},
- warn: function(){}
- }
- runtime.events = {
- emit: function(){}
- }
- nodes.init(runtime);
-
- }
-
- before(function() {
- app = express();
- app.use(bodyParser.json());
- app.get("/nodes",nodes.getAll);
- app.post("/nodes",nodes.post);
- app.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,nodes.getModule);
- app.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,nodes.getSet);
- app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,nodes.putModule);
- app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,nodes.putSet);
- app.get("/getIcons",nodes.getIcons);
- app.delete("/nodes/:id",nodes.delete);
- sinon.stub(apiUtil,"determineLangFromHeaders").callsFake(function() {
- return "en-US";
- });
- });
- after(function() {
- apiUtil.determineLangFromHeaders.restore();
- })
-
- describe('get nodes', function() {
- it('returns node list', function(done) {
- initNodes({
- nodes:{
- getNodeList: function() {
- return [1,2,3];
- }
- }
- });
- request(app)
- .get('/nodes')
- .set('Accept', 'application/json')
- .expect(200)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.be.an.Array();
- res.body.should.have.lengthOf(3);
- done();
- });
- });
-
- it('returns node configs', function(done) {
- initNodes({
- nodes:{
- getNodeConfigs: function() {
- return "";
- }
- },
- i18n: {
- determineLangFromHeaders: function(){}
- }
- });
- request(app)
- .get('/nodes')
- .set('Accept', 'text/html')
- .expect(200)
- .expect("")
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('returns node module info', function(done) {
- initNodes({
- nodes:{
- getModuleInfo: function(id) {
- return {"node-red":{name:"node-red"}}[id];
- }
- }
- });
- request(app)
- .get('/nodes/node-red')
- .expect(200)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("name","node-red");
- done();
- });
- });
-
- it('returns 404 for unknown module', function(done) {
- initNodes({
- nodes:{
- getModuleInfo: function(id) {
- return {"node-red":{name:"node-red"}}[id];
- }
- }
- });
- request(app)
- .get('/nodes/node-blue')
- .expect(404)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('returns individual node info', function(done) {
- initNodes({
- nodes:{
- getNodeInfo: function(id) {
- return {"node-red/123":{id:"node-red/123"}}[id];
- }
- }
- });
- request(app)
- .get('/nodes/node-red/123')
- .set('Accept', 'application/json')
- .expect(200)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("id","node-red/123");
- done();
- });
- });
-
- it('returns individual node configs', function(done) {
- initNodes({
- nodes:{
- getNodeConfig: function(id) {
- return {"node-red/123":""}[id];
- }
- },
- i18n: {
- determineLangFromHeaders: function(){}
- }
- });
- request(app)
- .get('/nodes/node-red/123')
- .set('Accept', 'text/html')
- .expect(200)
- .expect("")
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('returns 404 for unknown node', function(done) {
- initNodes({
- nodes:{
- getNodeInfo: function(id) {
- return {"node-red/123":{id:"node-red/123"}}[id];
- }
- }
- });
- request(app)
- .get('/nodes/node-red/456')
- .set('Accept', 'application/json')
- .expect(404)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
- });
-
- describe('install', function() {
-
- it('returns 400 if settings are unavailable', function(done) {
- initNodes({
- settings:{available:function(){return false}}
- });
- request(app)
- .post('/nodes')
- .expect(400)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('returns 400 if request is invalid', function(done) {
- initNodes({
- settings:{available:function(){return true}}
- });
- request(app)
- .post('/nodes')
- .send({})
- .expect(400)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- describe('by module', function() {
- it('installs the module and returns module info', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function(id) { return null; },
- installModule: function() {
- return Promise.resolve({
- name:"foo",
- nodes:[{id:"123"}]
- });
- }
- }
- });
- request(app)
- .post('/nodes')
- .send({module: 'foo'})
- .expect(200)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("name","foo");
- res.body.should.have.property("nodes");
- res.body.nodes[0].should.have.property("id","123");
- done();
- });
- });
-
- it('fails the install if already installed', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function(id) { return {nodes:{id:"123"}}; },
- installModule: function() {
- return Promise.resolve({id:"123"});
- }
- }
- });
- request(app)
- .post('/nodes')
- .send({module: 'foo'})
- .expect(400)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('fails the install if module error', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function(id) { return null },
- installModule: function() {
- return Promise.reject(new Error("test error"));
- }
- }
- });
- request(app)
- .post('/nodes')
- .send({module: 'foo'})
- .expect(400)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("message","Error: test error");
- done();
- });
- });
- it('fails the install if module not found', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function(id) { return null },
- installModule: function() {
- var err = new Error("test error");
- err.code = 404;
- return Promise.reject(err);
- }
- }
- });
- request(app)
- .post('/nodes')
- .send({module: 'foo'})
- .expect(404)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
- });
- });
- describe('delete', function() {
- it('returns 400 if settings are unavailable', function(done) {
- initNodes({
- settings:{available:function(){return false}}
- });
-
- request(app)
- .del('/nodes/123')
- .expect(400)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- describe('by module', function() {
- it('uninstalls the module', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function(id) { return {nodes:[{id:"123"}]} },
- getNodeInfo: function() { return null },
- uninstallModule: function() { return Promise.resolve({id:"123"});}
- }
- });
- request(app)
- .del('/nodes/foo')
- .expect(204)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('fails the uninstall if the module is not installed', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function(id) { return null },
- getNodeInfo: function() { return null }
- }
- });
- request(app)
- .del('/nodes/foo')
- .expect(404)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('fails the uninstall if the module is not installed', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function(id) { return {nodes:[{id:"123"}]} },
- getNodeInfo: function() { return null },
- uninstallModule: function() { return Promise.reject(new Error("test error"));}
- }
- });
- request(app)
- .del('/nodes/foo')
- .expect(400)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("message","Error: test error");
- done();
- });
- });
- });
-
- });
-
- describe('enable/disable', function() {
- it('returns 400 if settings are unavailable', function(done) {
- initNodes({
- settings:{available:function(){return false}}
- });
- request(app)
- .put('/nodes/123')
- .expect(400)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('returns 400 for invalid node payload', function(done) {
- initNodes({
- settings:{available:function(){return true}}
- });
- request(app)
- .put('/nodes/node-red/foo')
- .send({})
- .expect(400)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("message","Invalid request");
- done();
- });
- });
-
- it('returns 400 for invalid module payload', function(done) {
- initNodes({
- settings:{available:function(){return true}}
- });
- request(app)
- .put('/nodes/foo')
- .send({})
- .expect(400)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("message","Invalid request");
-
- done();
- });
- });
-
- it('returns 404 for unknown node', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getNodeInfo: function() { return null }
- }
- });
-
- request(app)
- .put('/nodes/node-red/foo')
- .send({enabled:false})
- .expect(404)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('returns 404 for unknown module', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function(id) { return null }
- }
- });
-
- request(app)
- .put('/nodes/node-blue')
- .send({enabled:false})
- .expect(404)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- done();
- });
- });
-
- it('enables disabled node', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getNodeInfo: function() { return {id:"123",enabled: false} },
- enableNode: function() { return Promise.resolve({id:"123",enabled: true,types:['a']}); }
- }
- });
- request(app)
- .put('/nodes/node-red/foo')
- .send({enabled:true})
- .expect(200)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("id","123");
- res.body.should.have.property("enabled",true);
-
- done();
- });
- });
-
- it('disables enabled node', function(done) {
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getNodeInfo: function() { return {id:"123",enabled: true} },
- disableNode: function() { return Promise.resolve({id:"123",enabled: false,types:['a']}); }
- }
- });
- request(app)
- .put('/nodes/node-red/foo')
- .send({enabled:false})
- .expect(200)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("id","123");
- res.body.should.have.property("enabled",false);
-
- done();
- });
- });
-
- describe('no-ops if already in the right state', function() {
- function run(state,done) {
- var enableNode = sinon.spy(function() { return Promise.resolve({id:"123",enabled: true,types:['a']}) });
- var disableNode = sinon.spy(function() { return Promise.resolve({id:"123",enabled: false,types:['a']}) });
-
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getNodeInfo: function() { return {id:"123",enabled: state} },
- enableNode: enableNode,
- disableNode: disableNode
- }
- });
- request(app)
- .put('/nodes/node-red/foo')
- .send({enabled:state})
- .expect(200)
- .end(function(err,res) {
- var enableNodeCalled = enableNode.called;
- var disableNodeCalled = disableNode.called;
- if (err) {
- throw err;
- }
- enableNodeCalled.should.be.false();
- disableNodeCalled.should.be.false();
- res.body.should.have.property("id","123");
- res.body.should.have.property("enabled",state);
-
- done();
- });
- }
- it('already enabled', function(done) {
- run(true,done);
- });
- it('already disabled', function(done) {
- run(false,done);
- });
- });
-
- describe('does not no-op if err on node', function() {
- function run(state,done) {
- var enableNode = sinon.spy(function() { return Promise.resolve({id:"123",enabled: true,types:['a']}) });
- var disableNode = sinon.spy(function() { return Promise.resolve({id:"123",enabled: false,types:['a']}) });
-
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getNodeInfo: function() { return {id:"123",enabled: state, err:"foo"} },
- enableNode: enableNode,
- disableNode: disableNode
- }
- });
- request(app)
- .put('/nodes/node-red/foo')
- .send({enabled:state})
- .expect(200)
- .end(function(err,res) {
- var enableNodeCalled = enableNode.called;
- var disableNodeCalled = disableNode.called;
- if (err) {
- throw err;
- }
- enableNodeCalled.should.be.equal(state);
- disableNodeCalled.should.be.equal(!state);
- res.body.should.have.property("id","123");
- res.body.should.have.property("enabled",state);
-
- done();
- });
- }
- it('already enabled', function(done) {
- run(true,done);
- });
- it('already disabled', function(done) {
- run(false,done);
- });
- });
-
- it('enables disabled module', function(done) {
- var n1 = {id:"123",enabled:false,types:['a']};
- var n2 = {id:"456",enabled:false,types:['b']};
- var enableNode = sinon.stub();
- enableNode.onFirstCall().returns((function() {
- n1.enabled = true;
- return Promise.resolve(n1);
- })());
- enableNode.onSecondCall().returns((function() {
- n2.enabled = true;
- return Promise.resolve(n2);
- })());
- enableNode.returns(null);
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} },
- enableNode: enableNode
- }
- });
-
- request(app)
- .put('/nodes/node-red')
- .send({enabled:true})
- .expect(200)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("name","node-red");
- res.body.should.have.property("nodes");
- res.body.nodes[0].should.have.property("enabled",true);
- res.body.nodes[1].should.have.property("enabled",true);
-
- done();
- });
- });
-
- it('disables enabled module', function(done) {
- var n1 = {id:"123",enabled:true,types:['a']};
- var n2 = {id:"456",enabled:true,types:['b']};
- var disableNode = sinon.stub();
- disableNode.onFirstCall().returns((function() {
- n1.enabled = false;
- return Promise.resolve(n1);
- })());
- disableNode.onSecondCall().returns((function() {
- n2.enabled = false;
- return Promise.resolve(n2);
- })());
- disableNode.returns(null);
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} },
- disableNode: disableNode
- }
- });
-
- request(app)
- .put('/nodes/node-red')
- .send({enabled:false})
- .expect(200)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- res.body.should.have.property("name","node-red");
- res.body.should.have.property("nodes");
- res.body.nodes[0].should.have.property("enabled",false);
- res.body.nodes[1].should.have.property("enabled",false);
-
- done();
- });
- });
-
- describe('no-ops if a node in module already in the right state', function() {
- function run(state,done) {
- var node = {id:"123",enabled:state,types:['a']};
- var enableNode = sinon.spy(function(id) {
- node.enabled = true;
- return Promise.resolve(node);
- });
- var disableNode = sinon.spy(function(id) {
- node.enabled = false;
- return Promise.resolve(node);
- });
-
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function() { return {name:"node-red", nodes:[node]}; },
- enableNode: enableNode,
- disableNode: disableNode
- }
- });
- request(app)
- .put('/nodes/node-red')
- .send({enabled:state})
- .expect(200)
- .end(function(err,res) {
- var enableNodeCalled = enableNode.called;
- var disableNodeCalled = disableNode.called;
- if (err) {
- throw err;
- }
- enableNodeCalled.should.be.false();
- disableNodeCalled.should.be.false();
- res.body.should.have.property("name","node-red");
- res.body.should.have.property("nodes");
- res.body.nodes[0].should.have.property("enabled",state);
-
- done();
- });
- }
- it('already enabled', function(done) {
- run(true,done);
- });
- it('already disabled', function(done) {
- run(false,done);
- });
- });
-
- describe('does not no-op if err on a node in module', function() {
- function run(state,done) {
- var node = {id:"123",enabled:state,types:['a'],err:"foo"};
- var enableNode = sinon.spy(function(id) {
- node.enabled = true;
- return Promise.resolve(node);
- });
- var disableNode = sinon.spy(function(id) {
- node.enabled = false;
- return Promise.resolve(node);
- });
-
- initNodes({
- settings:{available:function(){return true}},
- nodes:{
- getModuleInfo: function() { return {name:"node-red", nodes:[node]}; },
- enableNode: enableNode,
- disableNode: disableNode
- }
- });
-
- request(app)
- .put('/nodes/node-red')
- .send({enabled:state})
- .expect(200)
- .end(function(err,res) {
- var enableNodeCalled = enableNode.called;
- var disableNodeCalled = disableNode.called;
- if (err) {
- throw err;
- }
- enableNodeCalled.should.be.equal(state);
- disableNodeCalled.should.be.equal(!state);
- res.body.should.have.property("name","node-red");
- res.body.should.have.property("nodes");
- res.body.nodes[0].should.have.property("enabled",state);
-
- done();
- });
- }
- it('already enabled', function(done) {
- run(true,done);
- });
- it('already disabled', function(done) {
- run(false,done);
- });
- });
- });
-
- describe('get icons', function() {
- it('returns icon list', function(done) {
- initNodes({
- nodes:{
- getNodeIcons: function() {
- return {"module":["1.png","2.png","3.png"]};
- }
- }
- });
- request(app)
- .get('/getIcons')
- .expect(200)
- .end(function(err,res) {
- if (err) {
- throw err;
- }
- console.log(res.body);
- res.body.should.have.property("module");
- res.body.module.should.be.an.Array();
- res.body.module.should.have.lengthOf(3);
- done();
- });
- });
- });
-});
-
-*/
diff --git a/test/unit/@node-red/runtime/lib/api/plugins_spec.js b/test/unit/@node-red/runtime/lib/api/plugins_spec.js
deleted file mode 100644
index 7ae6d8286..000000000
--- a/test/unit/@node-red/runtime/lib/api/plugins_spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-const should = require("should");
-const sinon = require("sinon");
-
-const NR_TEST_UTILS = require("nr-test-utils");
-const plugins = NR_TEST_UTILS.require("@node-red/runtime/lib/api/plugins")
-
-const mockLog = () => ({
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc"}
-})
-
-describe("runtime-api/plugins", function() {
- const pluginList = [{id:"one",module:'test-module'},{id:"two",module:"node-red"}];
- const pluginConfigs = "123";
-
- describe("getPluginList", function() {
- it("gets the plugin list", function() {
- plugins.init({
- log: mockLog(),
- plugins: {
- getPluginList: function() { return pluginList}
- }
- });
- return plugins.getPluginList({}).then(function(result) {
- result.should.eql(pluginList);
- })
- });
- });
- describe("getPluginConfigs", function() {
- it("gets the plugin configs", function() {
- plugins.init({
- log: mockLog(),
- plugins: {
- getPluginConfigs: function() { return pluginConfigs}
- }
- });
- return plugins.getPluginConfigs({}).then(function(result) {
- result.should.eql(pluginConfigs);
- })
- });
- });
- describe("getPluginCatalogs", function() {
- it("gets the plugin catalogs", function() {
- plugins.init({
- log: mockLog(),
- plugins: {
- getPluginList: function() { return pluginList}
- },
- i18n: {
- i: {
- changeLanguage: function(lang,done) { done && done() },
- getResourceBundle: function(lang, id) { return {lang,id}}
- }
- }
- });
- return plugins.getPluginCatalogs({lang: "en-US"}).then(function(result) {
- JSON.stringify(result).should.eql(JSON.stringify({ one: { lang: "en-US", id: "one" } }))
- })
- });
- });
-
-});
\ No newline at end of file
diff --git a/test/unit/@node-red/runtime/lib/api/projects_spec.js b/test/unit/@node-red/runtime/lib/api/projects_spec.js
deleted file mode 100644
index 2fe7ca221..000000000
--- a/test/unit/@node-red/runtime/lib/api/projects_spec.js
+++ /dev/null
@@ -1,1170 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var projects = NR_TEST_UTILS.require("@node-red/runtime/lib/api/projects")
-
-var mockLog = () => ({
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc"}
-})
-
-describe("runtime-api/settings", function() {
- describe("available", function() {
- it("resolves true if projects available", function(done) {
- projects.init({
- storage: {
- projects: {}
- }
- });
- projects.available().then(function(result) {
- result.should.be.true();
- done();
- }).catch(done);
- })
- it("resolves false if projects unavailable", function(done) {
- projects.init({
- storage: {
- }
- });
- projects.available().then(function(result) {
- result.should.be.false();
- done();
- }).catch(done);
- })
-
- });
- describe("listProjects", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- listProjects: sinon.spy(function(user) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve([1,2,3]);
- }
- }),
- getActiveProject: function(user) {
- if (user === "noActive") {
- return null;
- }
- return {name:"aProject"};
- }
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("lists the projects, without an active project", function(done) {
- projects.listProjects({user:"noActive"}).then(function(result) {
- result.should.have.property('projects',[1,2,3]);
- result.should.not.have.property('active');
- done();
- }).catch(done);
- });
- it("lists the projects, with an active project", function(done) {
- projects.listProjects({user:"foo"}).then(function(result) {
- result.should.have.property('projects',[1,2,3]);
- result.should.have.property('active','aProject');
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.listProjects({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- err.should.have.property('status',400);
- done();
- }).catch(done);
- });
-
- });
- describe("createProject", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- createProject: sinon.spy(function(user,project) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve(project);
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("create project", function(done) {
- projects.createProject({user:"known",project:{a:1}}).then(function(result) {
- result.should.eql({a:1});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.createProject({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
- describe("initialiseProject", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- initialiseProject: sinon.spy(function(user,id,project) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({id,project});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("intialise project", function(done) {
- projects.initialiseProject({user:"known",id:123, project:{a:1}}).then(function(result) {
- result.should.eql({id:123, project:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.initialiseProject({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("getActiveProject", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getActiveProject: sinon.spy(function(user) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve("123");
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("returns active project", function(done) {
- projects.getActiveProject({user:"known"}).then(function(result) {
- result.should.eql("123");
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getActiveProject({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("setActiveProject", function() {
- var activeProject;
- var runtime;
- beforeEach(function() {
- runtime = {
- log: mockLog(),
- storage: {projects: {
- getActiveProject: sinon.spy(function() { return activeProject;}),
- setActiveProject: sinon.spy(function(user,id) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id});
- }
- })
- }}};
- projects.init(runtime);
- })
- it("sets project if current project is unset", function(done) {
- activeProject = null;
- projects.setActiveProject({user:"known",id:123}).then(function(result) {
- result.should.eql({user:"known",id:123});
- done();
- }).catch(done);
- });
- it("sets project if current project is different", function(done) {
- activeProject = {name:456};
- projects.setActiveProject({user:"known",id:123}).then(function(result) {
- result.should.eql({user:"known",id:123});
- done();
- }).catch(done);
- });
- it("no-ops if current project is same", function(done) {
- activeProject = {name:123};
- projects.setActiveProject({user:"known",id:123}).then(function(result) {
- (result === undefined).should.be.true();
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.setActiveProject({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("getProject", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getProject: sinon.spy(function(user,id) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("returns project", function(done) {
- projects.getProject({user:"known",id:123}).then(function(result) {
- result.should.eql({user:"known",id:123});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getProject({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
- describe("updateProject", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- updateProject: sinon.spy(function(user,id,project) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,project});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("updates project", function(done) {
- projects.updateProject({user:"known",id:123,project:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,project:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.updateProject({user:"error",id:123,project:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("deleteProject", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- deleteProject: sinon.spy(function(user,id) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("deletes project", function(done) {
- projects.deleteProject({user:"known",id:123}).then(function(result) {
- result.should.eql({user:"known",id:123});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.deleteProject({user:"error",id:123}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("getStatus", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getStatus: sinon.spy(function(user,id,remote) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,remote});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("gets status", function(done) {
- projects.getStatus({user:"known",id:123,remote:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,remote:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getStatus({user:"error",id:123,project:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
- describe("getBranches", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getBranches: sinon.spy(function(user,id,remote) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,remote});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("gets branches", function(done) {
- projects.getBranches({user:"known",id:123,remote:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,remote:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getBranches({user:"error",id:123,remote:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
- describe("getBranchStatus", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getBranchStatus: sinon.spy(function(user,id,branch) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,branch});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("gets branch status", function(done) {
- projects.getBranchStatus({user:"known",id:123,branch:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,branch:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getBranchStatus({user:"error",id:123,branch:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("setBranch", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- setBranch: sinon.spy(function(user,id,branch,create) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,branch,create});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("commits", function(done) {
- projects.setBranch({user:"known",id:123,branch:{a:1},create:true}).then(function(result) {
- result.should.eql({user:"known",id:123,branch:{a:1},create:true});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.setBranch({user:"error",id:123,branch:{a:1},create:true}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("deleteBranch", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- deleteBranch: sinon.spy(function(user,id,branch,something,force) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,branch,force});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("commits", function(done) {
- projects.deleteBranch({user:"known",id:123,branch:{a:1},force:true}).then(function(result) {
- result.should.eql({user:"known",id:123,branch:{a:1},force:true});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.deleteBranch({user:"error",id:123,branch:{a:1},force:true}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("commit", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- commit: sinon.spy(function(user,id,message) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,message});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("commits", function(done) {
- projects.commit({user:"known",id:123,message:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,message:{message:{a:1}}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.commit({user:"error",id:123,message:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
- describe("getCommit", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getCommit: sinon.spy(function(user,id,sha) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,sha});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("gets commit", function(done) {
- projects.getCommit({user:"known",id:123,sha:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,sha:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getCommit({user:"error",id:123,sha:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("getCommits", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getCommits: sinon.spy(function(user,id,options) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,options});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("gets commits with default limit/before", function(done) {
- projects.getCommits({user:"known",id:123}).then(function(result) {
- result.should.eql({user:"known",id:123,options:{limit:20,before:undefined}});
- done();
- }).catch(done);
- });
- it("gets commits with provided limit/before", function(done) {
- projects.getCommits({user:"known",id:123,limit:10,before:456}).then(function(result) {
- result.should.eql({user:"known",id:123,options:{limit:10,before:456}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getCommits({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("abortMerge", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- abortMerge: sinon.spy(function(user,id) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("aborts merge", function(done) {
- projects.abortMerge({user:"known",id:123}).then(function(result) {
- result.should.eql({user:"known",id:123});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.abortMerge({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("resolveMerge", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- resolveMerge: sinon.spy(function(user,id,path,resolution) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,path,resolution});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("resolves merge", function(done) {
- projects.resolveMerge({user:"known",id:123,path:"/abc",resolution:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,path:"/abc",resolution:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.resolveMerge({user:"error",id:123,path:"/abc",resolution:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("getFiles", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getFiles: sinon.spy(function(user,id) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("gets files", function(done) {
- projects.getFiles({user:"known",id:123}).then(function(result) {
- result.should.eql({user:"known",id:123});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getFiles({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("getFile", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getFile: sinon.spy(function(user,id,path,tree) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,path,tree});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("gets file", function(done) {
- projects.getFile({user:"known",id:123,path:"/abc",tree:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,path:"/abc",tree:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getFile({user:"error",id:123,path:"/abc",tree:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("stageFile", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- stageFile: sinon.spy(function(user,id,path) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,path});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("stages a file", function(done) {
- projects.stageFile({user:"known",id:123,path:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,path:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.stageFile({user:"error",id:123,path:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
- describe("unstageFile", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- unstageFile: sinon.spy(function(user,id,path) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,path});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("unstages a file", function(done) {
- projects.unstageFile({user:"known",id:123,path:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,path:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.unstageFile({user:"error",id:123,path:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("revertFile", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- revertFile: sinon.spy(function(user,id,path) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,path});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("reverts a file", function(done) {
- projects.revertFile({user:"known",id:123,path:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,path:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.revertFile({user:"error",id:123,path:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("getFileDiff", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getFileDiff: sinon.spy(function(user,id,path,type) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,path,type});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("gets file diff", function(done) {
- projects.getFileDiff({user:"known",id:123,path:{a:1},type:"abc"}).then(function(result) {
- result.should.eql({user:"known",id:123,path:{a:1},type:"abc"});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getFileDiff({user:"error",id:123,path:{a:1},type:"abc"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("getRemotes", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- getRemotes: sinon.spy(function(user,id) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("gets remotes", function(done) {
- projects.getRemotes({user:"known",id:123}).then(function(result) {
- result.should.eql({user:"known",id:123});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.getRemotes({user:"error"}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("addRemote", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- addRemote: sinon.spy(function(user,id,remote) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,remote});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("adds a remote", function(done) {
- projects.addRemote({user:"known",id:123,remote:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,remote:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.addRemote({user:"error",id:123,remote:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("removeRemote", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- removeRemote: sinon.spy(function(user,id,remote) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,remote});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("removes a remote", function(done) {
- projects.removeRemote({user:"known",id:123,remote:{a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,remote:{a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.removeRemote({user:"error",id:123,remote:{a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
- describe("updateRemote", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- updateRemote: sinon.spy(function(user,id,name,remote) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,name,remote});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("updates a remote", function(done) {
- projects.updateRemote({user:"known",id:123,remote:{name:"abc",a:1}}).then(function(result) {
- result.should.eql({user:"known",id:123,name:"abc",remote:{name:"abc",a:1}});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.updateRemote({user:"error",id:123,remote:{name:"abc",a:1}}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
- describe("pull", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- pull: sinon.spy(function(user,id,remote,track,allowUnrelatedHistories) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,remote,track,allowUnrelatedHistories});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("pulls", function(done) {
- projects.pull({user:"known",id:123,remote:"abc",track:false,allowUnrelatedHistories:true}).then(function(result) {
- result.should.eql({user:"known",id:123,remote:"abc",track:false,allowUnrelatedHistories:true});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.pull({user:"error",id:123,remote:"abc",track:false,allowUnrelatedHistories:true}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
- describe("push", function() {
- var runtime = {
- log: mockLog(),
- storage: {projects: {
- push: sinon.spy(function(user,id,remote,track) {
- if (user === "error") {
- var err = new Error("error");
- err.code = "error";
- var p = Promise.reject(err);
- p.catch(()=>{});
- return p;
- } else {
- return Promise.resolve({user,id,remote,track});
- }
- })
- }}};
- before(function() {
- projects.init(runtime);
- })
- it("pulls", function(done) {
- projects.push({user:"known",id:123,remote:"abc",track:false}).then(function(result) {
- result.should.eql({user:"known",id:123,remote:"abc",track:false});
- done();
- }).catch(done);
- });
- it("rejects with internal error", function(done) {
- projects.push({user:"error",id:123,remote:"abc",track:false}).then(function(result) {
- done(new Error("Did not reject internal error"));
- }).catch(function(err) {
- err.should.have.property('code','error');
- // err.should.have.property('status',400);
- done();
- }).catch(done);
- });
- });
-
-
-});
diff --git a/test/unit/@node-red/runtime/lib/api/settings_spec.js b/test/unit/@node-red/runtime/lib/api/settings_spec.js
deleted file mode 100644
index 9b3b94229..000000000
--- a/test/unit/@node-red/runtime/lib/api/settings_spec.js
+++ /dev/null
@@ -1,988 +0,0 @@
-/**
- * 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 settings = NR_TEST_UTILS.require("@node-red/runtime/lib/api/settings")
-
-var mockLog = () => ({
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc"}
-})
-
-describe("runtime-api/settings", function() {
- describe("getRuntimeSettings", function() {
- it("gets the runtime settings", function() {
- settings.init({
- settings: {
- foo: 123,
- httpNodeRoot: "testHttpNodeRoot",
- version: "testVersion",
- paletteCategories :["red","blue","green"],
- exportNodeSettings: (obj) => {
- obj.testNodeSetting = "helloWorld";
- },
- },
- plugins: {
- exportPluginSettings: (obj) => {
- obj.testPluginSettings = "helloPluginWorld";
- }
- },
- nodes: {
- listContextStores: () => { return {stores:["file","memory"], default: "file"} },
- installerEnabled: () => false,
- getCredentialKeyType: () => "test-key-type"
- },
- library: {getLibraries: () => ["lib1"] },
- storage: {}
- })
- return settings.getRuntimeSettings({}).then(result => {
- result.should.have.property("httpNodeRoot","testHttpNodeRoot");
- result.should.have.property("version","testVersion");
- result.should.have.property("paletteCategories",["red","blue","green"]);
- result.should.have.property("libraries",["lib1"]);
- result.should.have.property("testNodeSetting","helloWorld");
- result.should.have.property("testPluginSettings","helloPluginWorld");
- result.should.not.have.property("foo",123);
- result.should.have.property("flowEncryptionType","test-key-type");
- result.should.not.have.property("user");
- result.should.have.property("externalModules");
- result.externalModules.should.eql({palette:{allowInstall:false, allowUpload: false}});
-
- })
- });
- it("gets the filtered user settings", function() {
- settings.init({
- settings: {
- foo: 123,
- httpNodeRoot: "testHttpNodeRoot",
- version: "testVersion",
- paletteCategories :["red","blue","green"],
- exportNodeSettings: (obj) => {
- obj.testNodeSetting = "helloWorld";
- },
- },
- plugins: {
- exportPluginSettings: (obj) => {
- obj.testPluginSettings = "helloPluginWorld";
- }
- },
- nodes: {
- listContextStores: () => { return {stores:["file","memory"], default: "file"} },
- installerEnabled: () => false,
- getCredentialKeyType: () => "test-key-type"
- },
- library: {getLibraries: () => { ["lib1"]} },
- storage: {}
- })
- return settings.getRuntimeSettings({
- user: {
- username: "nick",
- anonymous: false,
- image: "http://example.com",
- permissions: "*",
- private: "secret"
- }
- }).then(result => {
- result.should.have.property("user");
- result.user.should.have.property("username","nick");
- result.user.should.have.property("permissions","*");
- result.user.should.have.property("image","http://example.com");
- result.user.should.have.property("anonymous",false);
- result.user.should.not.have.property("private");
- })
- });
- it("gets the filtered settings when editor disabled ", function() {
- settings.init({
- settings: {
- disableEditor: true,
- foo: 123,
- httpNodeRoot: "testHttpNodeRoot",
- version: "testVersion",
- paletteCategories :["red","blue","green"],
- exportNodeSettings: (obj) => {
- obj.testNodeSetting = "helloWorld";
- },
- },
- plugins: {
- exportPluginSettings: (obj) => {
- obj.testPluginSettings = "helloPluginWorld";
- }
- },
- nodes: {
- listContextStores: () => { return {stores:["file","memory"], default: "file"} },
- installerEnabled: () => false,
- getCredentialKeyType: () => "test-key-type"
- },
- library: {getLibraries: () => { ["lib1"]} },
- storage: {
- projects: {
- getActiveProject: () => 'test-active-project',
- getFlowFilename: () => 'test-flow-file',
- getCredentialsFilename: () => 'test-creds-file',
- getGlobalGitUser: () => {return {name:'foo',email:'foo@example.com'}}
- }
- }
- })
- return settings.getRuntimeSettings({
- user: {
- username: "nick",
- anonymous: false,
- image: "http://example.com",
- permissions: "*",
- private: "secret"
- }
- }).then(result => {
- result.should.have.property("user");
- result.user.should.have.property("username","nick");
- result.user.should.have.property("permissions","*");
- result.user.should.have.property("image","http://example.com");
- result.user.should.have.property("anonymous",false);
- result.user.should.not.have.property("private");
-
- // Filtered out when disableEditor is true
- result.should.not.have.property("paletteCategories",["red","blue","green"]);
- result.should.not.have.property("testNodeSetting","helloWorld");
- result.should.not.have.property("foo",123);
- result.should.not.have.property("flowEncryptionType","test-key-type");
- result.should.not.have.property("project");
- result.should.not.have.property("git");
-
- })
- });
- it('includes project settings if projects available', function() {
- settings.init({
- settings: {
- foo: 123,
- httpNodeRoot: "testHttpNodeRoot",
- version: "testVersion",
- paletteCategories :["red","blue","green"],
- exportNodeSettings: (obj) => {
- obj.testNodeSetting = "helloWorld";
- },
- },
- plugins: {
- exportPluginSettings: (obj) => {
- obj.testPluginSettings = "helloPluginWorld";
- }
- },
- nodes: {
- listContextStores: () => { return {stores:["file","memory"], default: "file"} },
- installerEnabled: () => false,
- getCredentialKeyType: () => "test-key-type"
- },
- library: {getLibraries: () => { ["lib1"]} },
- storage: {
- projects: {
- getActiveProject: () => 'test-active-project',
- getFlowFilename: () => 'test-flow-file',
- getCredentialsFilename: () => 'test-creds-file',
- getGlobalGitUser: () => {return {name:'foo',email:'foo@example.com'}}
- }
- }
- })
- return settings.getRuntimeSettings({
- user: {
- username: "nick",
- anonymous: false,
- image: "http://example.com",
- permissions: "*",
- private: "secret"
- }
- }).then(result => {
- result.should.have.property("project","test-active-project");
- result.should.not.have.property("files");
- result.should.have.property("git");
- result.git.should.have.property("globalUser",{name:'foo',email:'foo@example.com'});
- });
- });
-
- it('includes existing files details if projects enabled but no active project and files exist', function() {
- settings.init({
- settings: {
- foo: 123,
- httpNodeRoot: "testHttpNodeRoot",
- version: "testVersion",
- paletteCategories :["red","blue","green"],
- exportNodeSettings: (obj) => {
- obj.testNodeSetting = "helloWorld";
- },
- },
- plugins: {
- exportPluginSettings: (obj) => {
- obj.testPluginSettings = "helloPluginWorld";
- }
- },
- nodes: {
- listContextStores: () => { return {stores:["file","memory"], default: "file"} },
- installerEnabled: () => false,
- getCredentialKeyType: () => "test-key-type"
- },
- library: {getLibraries: () => { ["lib1"]} },
- storage: {
- projects: {
- flowFileExists: () => true,
- getActiveProject: () => false,
- getFlowFilename: () => 'test-flow-file',
- getCredentialsFilename: () => 'test-creds-file',
- getGlobalGitUser: () => {return {name:'foo',email:'foo@example.com'}}
- }
- }
- })
- return settings.getRuntimeSettings({
- user: {
- username: "nick",
- anonymous: false,
- image: "http://example.com",
- permissions: "*",
- private: "secret"
- }
- }).then(result => {
- result.git.should.have.property("globalUser",{name:'foo',email:'foo@example.com'});
- result.should.not.have.property("project");
- result.should.have.property("files");
- result.files.should.have.property("flow",'test-flow-file');
- result.files.should.have.property("credentials",'test-creds-file');
- result.should.have.property("git");
- result.git.should.have.property("globalUser",{name:'foo',email:'foo@example.com'});
- });
- });
-
- it('does not include file details if projects enabled but no active project and files do not exist', function() {
- settings.init({
- settings: {
- foo: 123,
- httpNodeRoot: "testHttpNodeRoot",
- version: "testVersion",
- paletteCategories :["red","blue","green"],
- exportNodeSettings: (obj) => {
- obj.testNodeSetting = "helloWorld";
- },
- },
- plugins: {
- exportPluginSettings: (obj) => {
- obj.testPluginSettings = "helloPluginWorld";
- }
- },
- nodes: {
- listContextStores: () => { return {stores:["file","memory"], default: "file"} },
- installerEnabled: () => false,
- getCredentialKeyType: () => "test-key-type"
- },
- library: {getLibraries: () => { ["lib1"]} },
- storage: {
- projects: {
- flowFileExists: () => false,
- getActiveProject: () => false,
- getFlowFilename: () => 'test-flow-file',
- getCredentialsFilename: () => 'test-creds-file',
- getGlobalGitUser: () => {return {name:'foo',email:'foo@example.com'}}
- }
- }
- })
- return settings.getRuntimeSettings({
- user: {
- username: "nick",
- anonymous: false,
- image: "http://example.com",
- permissions: "*",
- private: "secret"
- }
- }).then(result => {
- result.should.not.have.property("project");
- result.should.not.have.property("files");
- result.should.have.property("git");
- result.git.should.have.property("globalUser",{name:'foo',email:'foo@example.com'});
- });
- });
- });
- describe("getUserSettings", function() {
- before(function() {
- settings.init({
- settings: {
- getUserSettings: username => username
- }
- });
- })
- it("returns default user settings", function() {
- return settings.getUserSettings({}).then(result => {
- result.should.eql("_");
- })
- })
- it("returns default user settings for anonymous", function() {
- return settings.getUserSettings({user:{anonymous:true}}).then(result => {
- result.should.eql("_");
- })
- })
- it("returns user settings", function() {
- return settings.getUserSettings({user:{username:'nick'}}).then(result => {
- result.should.eql("nick");
- })
- })
- });
-
- describe("updateUserSettings", function() {
- var userSettings;
- before(function() {
- settings.init({
- settings: {
- getUserSettings: username => clone(userSettings[username]),
- setUserSettings: (username, settings) => {
- if (username === 'error') {
- var p = Promise.reject(new Error("unknown user"));
- p.catch(()=>{});
- return p;
- } else if (username === 'throw') {
- throw new Error("thrown error");
- }
- userSettings[username] = clone(settings);
- return Promise.resolve();
- }
- },
- log: mockLog()
- });
- })
- beforeEach(function() {
- userSettings = {
- "_": { abc: 123 },
- "nick": {abc: 456}
- }
- })
- it('sets default user settings', function() {
- return settings.updateUserSettings({settings:{abc:789}}).then(function() {
- userSettings._.abc.should.eql(789)
- })
- })
- it('merges user settings', function() {
- return settings.updateUserSettings({settings:{def:789}}).then(function() {
- userSettings._.abc.should.eql(123)
- userSettings._.def.should.eql(789)
- })
- })
- it('sets default user settings for anonymous user', function() {
- return settings.updateUserSettings({user:{anonymous:true},settings:{def:789}}).then(function() {
- userSettings._.abc.should.eql(123)
- userSettings._.def.should.eql(789)
- })
- })
- it('sets named user settings', function() {
- return settings.updateUserSettings({user:{username:'nick'},settings:{def:789}}).then(function() {
- userSettings.nick.abc.should.eql(456)
- userSettings.nick.def.should.eql(789)
- })
- })
- it('rejects with suitable error', function(done) {
- settings.updateUserSettings({user:{username:'error'},settings:{def:789}}).then(result => {
- done("Unexpected resolve for error case");
- }).catch(err => {
- err.should.have.property('status', 400);
- done();
- }).catch(done);
- })
- it('rejects with suitable error - thrown', function(done) {
- settings.updateUserSettings({user:{username:'throw'},settings:{def:789}}).then(result => {
- done("Unexpected resolve for error case");
- }).catch(err => {
- err.should.have.property('status', 400);
- done();
- }).catch(done);
- })
- });
- describe("getUserKeys", function() {
- before(function() {
- settings.init({
- storage: {
- projects: {
- ssh: {
- listSSHKeys: username => {
- if (username === 'error') {
- var p = Promise.reject(new Error("unknown user"));
- p.catch(()=>{});
- return p;
- }
- return Promise.resolve([username])
- }
- }
- }
- }
- })
- })
- it('returns the default users keys', function() {
- return settings.getUserKeys({}).then(result => {
- result.should.eql(['__default']);
- })
- })
- it('returns the default users keys for anonymous', function() {
- return settings.getUserKeys({user:{anonymous:true}}).then(result => {
- result.should.eql(['__default']);
- })
- })
- it('returns the users keys', function() {
- return settings.getUserKeys({user:{username:'nick'}}).then(result => {
- result.should.eql(['nick']);
- })
- })
- it('rejects with suitable error', function(done) {
- settings.getUserKeys({user:{username:'error'}}).then(result => {
- done("Unexpected resolve for error case");
- }).catch(err => {
- err.should.have.property('status', 400);
- done();
- }).catch(done);
- })
- });
-
- describe("getUserKey", function() {
- before(function() {
- settings.init({
- storage: {
- projects: {
- ssh: {
- getSSHKey: (username, id) => {
- if (username === 'error') {
- var p = Promise.reject(new Error("unknown user"));
- p.catch(()=>{});
- return p;
- } else if (username === '404') {
- return Promise.resolve(null);
- }
- return Promise.resolve({username,id})
- }
- }
- }
- }
- })
- })
- it('returns the default user key', function() {
- return settings.getUserKey({id:'keyid'}).then(result => {
- result.should.eql({id:'keyid',username:"__default"});
- })
- })
- it('returns the default user key - anonymous', function() {
- return settings.getUserKey({user:{anonymous:true},id:'keyid'}).then(result => {
- result.should.eql({id:'keyid',username:"__default"});
- })
- })
- it('returns the user key', function() {
- return settings.getUserKey({user:{username:'nick'},id:'keyid'}).then(result => {
- result.should.eql({id:'keyid',username:"nick"});
- })
- })
- it('404s for unknown key', function(done) {
- settings.getUserKey({user:{username:'404'},id:'keyid'}).then(result => {
- done("Unexpected resolve for error case");
- }).catch(err => {
- err.should.have.property('status', 404);
- err.should.have.property('code', 'not_found');
- done();
- }).catch(done);
- })
- it('rejects with suitable error', function(done) {
- settings.getUserKey({user:{username:'error'}}).then(result => {
- done("Unexpected resolve for error case");
- }).catch(err => {
- err.should.have.property('status', 400);
- done();
- }).catch(done);
- })
- });
- describe("generateUserKey", function() {
- before(function() {
- settings.init({
- storage: {
- projects: {
- ssh: {
- generateSSHKey: (username, opts) => {
- if (username === 'error') {
- var p = Promise.reject(new Error("unknown user"));
- p.catch(()=>{});
- return p;
- }
- return Promise.resolve(JSON.stringify({username,opts}))
- }
- }
- }
- }
- })
- })
- it('generates for the default user', function() {
- return settings.generateUserKey({id:'keyid'}).then(result => {
- var data = JSON.parse(result);
- data.should.eql({opts:{id:'keyid'},username:"__default"});
- })
- })
- it('generates for the default user - anonymous', function() {
- return settings.generateUserKey({user:{anonymous:true},id:'keyid'}).then(result => {
- var data = JSON.parse(result);
- data.should.eql({opts:{user:{anonymous:true},id:'keyid'},username:"__default"});
- })
- })
- it('generates for the user', function() {
- return settings.generateUserKey({user:{username:'nick'},id:'keyid'}).then(result => {
- var data = JSON.parse(result);
- data.should.eql({opts:{user:{username:'nick'},id:'keyid'},username:"nick"});
- })
- })
- it('rejects with suitable error', function(done) {
- settings.generateUserKey({user:{username:'error'}}).then(result => {
- done("Unexpected resolve for error case");
- }).catch(err => {
- err.should.have.property('status', 400);
- done();
- }).catch(done);
- })
-
- });
- describe("removeUserKey", function() {
- var received = {};
- before(function() {
- settings.init({
- storage: {
- projects: {
- ssh: {
- deleteSSHKey: (username, id) => {
- if (username === 'error') {
- var p = Promise.reject(new Error("unknown user"));
- p.catch(()=>{});
- return p;
- }
- received.username = username;
- received.id = id;
- return Promise.resolve();
- }
- }
- }
- }
- })
- });
- beforeEach(function() {
- received.username = "";
- received.id = "";
- })
- it('removes for the default user', function() {
- return settings.removeUserKey({id:'keyid'}).then(() => {
- received.username.should.eql("__default");
- received.id.should.eql("keyid");
- })
- })
- it('removes for the default user key - anonymous', function() {
- return settings.removeUserKey({user:{anonymous:true},id:'keyid'}).then(() => {
- received.username.should.eql("__default");
- received.id.should.eql("keyid");
- })
- })
- it('returns the user key', function() {
- return settings.removeUserKey({user:{username:'nick'},id:'keyid'}).then(() => {
- received.username.should.eql("nick");
- received.id.should.eql("keyid");
- })
- })
- it('rejects with suitable error', function(done) {
- settings.removeUserKey({user:{username:'error'}}).then(result => {
- done("Unexpected resolve for error case");
- }).catch(err => {
- err.should.have.property('status', 400);
- done();
- }).catch(done);
- })
- });
-
-});
-
-
-
-/*
-
-
-var should = require("should");
-var sinon = require("sinon");
-var request = require("supertest");
-var express = require("express");
-var editorApi = require("../../../../red/api/editor");
-var comms = require("../../../../red/api/editor/comms");
-var info = require("../../../../red/api/editor/settings");
-var auth = require("../../../../red/api/auth");
-var sshkeys = require("../../../../red/api/editor/sshkeys");
-var bodyParser = require("body-parser");
-var fs = require("fs-extra");
-var fspath = require("path");
-
-
-describe("api/editor/sshkeys", function() {
- var app;
- var mockList = [
- 'library','theme','locales','credentials','comms'
- ]
- var isStarted = true;
- var errors = [];
- var session_data = {};
-
- var mockRuntime = {
- settings:{
- httpNodeRoot: true,
- httpAdminRoot: true,
- disableEditor: false,
- exportNodeSettings:function(){},
- storage: {
- getSessions: function(){
- return Promise.resolve(session_data);
- },
- setSessions: function(_session) {
- session_data = _session;
- return Promise.resolve();
- }
- }
- },
- log:{audit:function(){},error:function(msg){errors.push(msg)},trace:function(){}},
- storage: {
- projects: {
- ssh: {
- init: function(){},
- listSSHKeys: function(){},
- getSSHKey: function(){},
- generateSSHKey: function(){},
- deleteSSHKey: function(){}
- }
- }
- },
- events:{on:function(){},removeListener:function(){}},
- isStarted: function() { return isStarted; },
- nodes: {installerEnabled: function() { return false }}
- };
-
- before(function() {
- auth.init(mockRuntime);
- app = express();
- app.use(bodyParser.json());
- app.use(editorApi.init({},mockRuntime));
- });
- after(function() {
- })
-
- beforeEach(function() {
- sinon.stub(mockRuntime.storage.projects.ssh, "listSSHKeys");
- sinon.stub(mockRuntime.storage.projects.ssh, "getSSHKey");
- sinon.stub(mockRuntime.storage.projects.ssh, "generateSSHKey");
- sinon.stub(mockRuntime.storage.projects.ssh, "deleteSSHKey");
- })
- afterEach(function() {
- mockRuntime.storage.projects.ssh.listSSHKeys.restore();
- mockRuntime.storage.projects.ssh.getSSHKey.restore();
- mockRuntime.storage.projects.ssh.generateSSHKey.restore();
- mockRuntime.storage.projects.ssh.deleteSSHKey.restore();
- })
-
- it('GET /settings/user/keys --- return empty list', function(done) {
- mockRuntime.storage.projects.ssh.listSSHKeys.returns(Promise.resolve([]));
- request(app)
- .get("/settings/user/keys")
- .expect(200)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('keys');
- res.body.keys.should.be.empty();
- done();
- });
- });
-
- it('GET /settings/user/keys --- return normal list', function(done) {
- var fileList = [
- 'test_key01',
- 'test_key02'
- ];
- var retList = fileList.map(function(elem) {
- return {
- name: elem
- };
- });
- mockRuntime.storage.projects.ssh.listSSHKeys.returns(Promise.resolve(retList));
- request(app)
- .get("/settings/user/keys")
- .expect(200)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('keys');
- for (var item of retList) {
- res.body.keys.should.containEql(item);
- }
- done();
- });
- });
-
- it('GET /settings/user/keys --- return Error', function(done) {
- var errInstance = new Error("Messages here.....");
- errInstance.code = "test_code";
- var p = Promise.reject(errInstance);
- p.catch(()=>{});
- mockRuntime.storage.projects.ssh.listSSHKeys.returns(p);
- request(app)
- .get("/settings/user/keys")
- .expect(400)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('error');
- res.body.error.should.be.equal(errInstance.code);
- res.body.should.have.property('message');
- res.body.message.should.be.equal(errInstance.message);
- done();
- });
- });
-
- it('GET /settings/user/keys/ --- return 404', function(done) {
- mockRuntime.storage.projects.ssh.getSSHKey.returns(Promise.resolve(null));
- request(app)
- .get("/settings/user/keys/NOT_REAL")
- .expect(404)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- done();
- });
- });
- it('GET /settings/user/keys --- return Unexpected Error', function(done) {
- var errInstance = new Error("Messages.....");
- var p = Promise.reject(errInstance);
- p.catch(()=>{});
- mockRuntime.storage.projects.ssh.listSSHKeys.returns(p);
- request(app)
- .get("/settings/user/keys")
- .expect(400)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('error');
- res.body.error.should.be.equal("unexpected_error");
- res.body.should.have.property('message');
- res.body.message.should.be.equal(errInstance.toString());
- done();
- });
- });
-
- it('GET /settings/user/keys/ --- return content', function(done) {
- var key_file_name = "test_key";
- var fileContent = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD3a+sgtgzSbbliWxmOq5p6+H/mE+0gjWfLWrkIVmHENd1mifV4uCmIHAR2NfuadUYMQ3+bQ90kpmmEKTMYPsyentsKpHQZxTzG7wOCAIpJnbPTHDMxEJhVTaAwEjbVyMSIzTTPfnhoavWIBu0+uMgKDDlBm+RjlgkFlyhXyCN6UwFrIUUMH6Gw+eQHLiooKIl8ce7uDxIlt+9b7hFCU+sQ3kvuse239DZluu6+8buMWqJvrEHgzS9adRFKku8nSPAEPYn85vDi7OgVAcLQufknNgs47KHBAx9h04LeSrFJ/P5J1b//ItRpMOIme+O9d1BR46puzhvUaCHLdvO9czj+OmW+dIm+QIk6lZIOOMnppG72kZxtLfeKT16ur+2FbwAdL9ItBp4BI/YTlBPoa5mLMxpuWfmX1qHntvtGc9wEwS1P7YFfmF3XiK5apxalzrn0Qlr5UmDNbVIqJb1OlbC0w03Z0oktti1xT+R2DGOLWM4lBbpXDHV1BhQ7oYOvbUD8Cnof55lTP0WHHsOHlQc/BGDti1XA9aBX/OzVyzBUYEf0pkimsD0RYo6aqt7QwehJYdlz9x1NBguBffT0s4NhNb9IWr+ASnFPvNl2sw4XH/8U0J0q8ZkMpKkbLM1Zdp1Fv00GF0f5UNRokai6uM3w/ccantJ3WvZ6GtctqytWrw== \n";
- mockRuntime.storage.projects.ssh.getSSHKey.returns(Promise.resolve(fileContent));
- request(app)
- .get("/settings/user/keys/" + key_file_name)
- .expect(200)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- mockRuntime.storage.projects.ssh.getSSHKey.called.should.be.true();
- res.body.should.be.deepEqual({ publickey: fileContent });
- done();
- });
- });
-
- it('GET /settings/user/keys/ --- return Error', function(done) {
- var key_file_name = "test_key";
- var errInstance = new Error("Messages.....");
- errInstance.code = "test_code";
- var p = Promise.reject(errInstance);
- p.catch(()=>{});
- mockRuntime.storage.projects.ssh.getSSHKey.returns(p);
- request(app)
- .get("/settings/user/keys/" + key_file_name)
- .expect(400)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('error');
- res.body.error.should.be.equal(errInstance.code);
- res.body.should.have.property('message');
- res.body.message.should.be.equal(errInstance.message);
- done();
- });
- });
-
- it('GET /settings/user/keys/ --- return Unexpected Error', function(done) {
- var key_file_name = "test_key";
- var errInstance = new Error("Messages.....");
- var p = Promise.reject(errInstance);
- p.catch(()=>{});
- mockRuntime.storage.projects.ssh.getSSHKey.returns(p);
- request(app)
- .get("/settings/user/keys/" + key_file_name)
- .expect(400)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('error');
- res.body.error.should.be.equal("unexpected_error");
- res.body.should.have.property('message');
- res.body.message.should.be.equal(errInstance.toString());
- done();
- });
- });
-
- it('POST /settings/user/keys --- success', function(done) {
- var key_file_name = "test_key";
- mockRuntime.storage.projects.ssh.generateSSHKey.returns(Promise.resolve(key_file_name));
- request(app)
- .post("/settings/user/keys")
- .send({ name: key_file_name })
- .expect(200)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- done();
- });
- });
-
- it('POST /settings/user/keys --- return parameter error', function(done) {
- var key_file_name = "test_key";
- mockRuntime.storage.projects.ssh.generateSSHKey.returns(Promise.resolve(key_file_name));
- request(app)
- .post("/settings/user/keys")
- .expect(400)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('error');
- res.body.error.should.be.equal("unexpected_error");
- res.body.should.have.property('message');
- res.body.message.should.be.equal("You need to have body or body.name");
- done();
- });
- });
-
- it('POST /settings/user/keys --- return Error', function(done) {
- var key_file_name = "test_key";
- var errInstance = new Error("Messages.....");
- errInstance.code = "test_code";
- var p = Promise.reject(errInstance);
- p.catch(()=>{});
- mockRuntime.storage.projects.ssh.generateSSHKey.returns(p);
- request(app)
- .post("/settings/user/keys")
- .send({ name: key_file_name })
- .expect(400)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('error');
- res.body.error.should.be.equal("test_code");
- res.body.should.have.property('message');
- res.body.message.should.be.equal(errInstance.message);
- done();
- });
- });
-
- it('POST /settings/user/keys --- return Unexpected error', function(done) {
- var key_file_name = "test_key";
- var errInstance = new Error("Messages.....");
- var p = Promise.reject(errInstance);
- p.catch(()=>{});
- mockRuntime.storage.projects.ssh.generateSSHKey.returns(p);
- request(app)
- .post("/settings/user/keys")
- .send({ name: key_file_name })
- .expect(400)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('error');
- res.body.error.should.be.equal("unexpected_error");
- res.body.should.have.property('message');
- res.body.message.should.be.equal(errInstance.toString());
- done();
- });
- });
-
- it('DELETE /settings/user/keys/ --- success', function(done) {
- var key_file_name = "test_key";
- mockRuntime.storage.projects.ssh.deleteSSHKey.returns(Promise.resolve(true));
- request(app)
- .delete("/settings/user/keys/" + key_file_name)
- .expect(204)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.be.deepEqual({});
- done();
- });
- });
-
- it('DELETE /settings/user/keys/ --- return Error', function(done) {
- var key_file_name = "test_key";
- var errInstance = new Error("Messages.....");
- errInstance.code = "test_code";
- var p = Promise.reject(errInstance);
- p.catch(()=>{});
- mockRuntime.storage.projects.ssh.deleteSSHKey.returns(p);
- request(app)
- .delete("/settings/user/keys/" + key_file_name)
- .expect(400)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('error');
- res.body.error.should.be.equal("test_code");
- res.body.should.have.property('message');
- res.body.message.should.be.equal(errInstance.message);
- done();
- });
- });
-
- it('DELETE /settings/user/keys/ --- return Unexpected Error', function(done) {
- var key_file_name = "test_key";
- var errInstance = new Error("Messages.....");
- var p = Promise.reject(errInstance);
- p.catch(()=>{});
- mockRuntime.storage.projects.ssh.deleteSSHKey.returns(p);
- request(app)
- .delete("/settings/user/keys/" + key_file_name)
- .expect(400)
- .end(function(err,res) {
- if (err) {
- return done(err);
- }
- res.body.should.have.property('error');
- res.body.error.should.be.equal("unexpected_error");
- res.body.should.have.property('message');
- res.body.message.should.be.equal(errInstance.toString());
- done();
- });
- });
-});
-*/
diff --git a/test/unit/@node-red/runtime/lib/flows/Flow_spec.js b/test/unit/@node-red/runtime/lib/flows/Flow_spec.js
deleted file mode 100644
index eed4810c4..000000000
--- a/test/unit/@node-red/runtime/lib/flows/Flow_spec.js
+++ /dev/null
@@ -1,1327 +0,0 @@
-/**
- * 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 flowUtils = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/util");
-var Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Flow");
-var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows");
-var Node = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node");
-var hooks = NR_TEST_UTILS.require("@node-red/util/lib/hooks");
-var typeRegistry = NR_TEST_UTILS.require("@node-red/registry");
-
-
-describe('Flow', function() {
- var getType;
-
- var stoppedNodes = {};
- var stoppedOrder = [];
- var currentNodes = {};
- var rewiredNodes = {};
- var createCount = 0;
-
- beforeEach(function() {
- currentNodes = {};
- stoppedNodes = {};
- stoppedOrder =[];
- rewiredNodes = {};
- createCount = 0;
- Flow.init({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"}
- }});
- });
-
- 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;
- stoppedOrder.push(node.id)
- 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;
- stoppedOrder.push(node.id)
- 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;
- this.scope = n.scope;
- this.uncaught = n.uncaught;
- 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++;
- msg.handled = node.handled;
- node.messages.push(msg);
- node.send(msg);
- });
- this.on('close',function(done) {
- setTimeout(function() {
- node.stopped = true;
- stoppedNodes[node.id] = node;
- stoppedOrder.push(node.id)
- delete currentNodes[node.id];
- done();
- },node.closeDelay);
- });
- }
- util.inherits(TestAsyncNode,Node);
-
- var TestDoneNode = function(n) {
- Node.call(this,n);
- var node = this;
- this.scope = n.scope;
- this.uncaught = n.uncaught;
- 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, send, done) {
- node.handled++;
- node.messages.push(msg);
- send(msg);
- done();
- });
- this.on('close',function(done) {
- setTimeout(function() {
- node.stopped = true;
- stoppedNodes[node.id] = node;
- stoppedOrder.push(node.id)
- delete currentNodes[node.id];
- done();
- },node.closeDelay);
- });
- }
- util.inherits(TestDoneNode,Node);
-
- before(function() {
- getType = sinon.stub(typeRegistry,"get").callsFake(function(type) {
- if (type=="test") {
- return TestNode;
- } else if (type=="testError"){
- return TestErrorNode;
- } else if (type=="testDone"){
- return TestDoneNode;
- } else {
- return TestAsyncNode;
- }
- });
- });
- after(function() {
- getType.restore();
- });
-
- describe('#constructor',function() {
- it('called with an empty flow',function() {
- var config = flowUtils.parseConfig([]);
- var flow = Flow.create({},config);
-
- var nodeCount = 0;
- Object.keys(flow.getActiveNodes()).length.should.equal(0);
- });
- });
-
- describe('#start',function() {
- it("instantiates an initial configuration 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:"test",foo:"a",wires:["3"]},
- {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"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(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');
-
- currentNodes.should.have.a.property("1");
- currentNodes.should.have.a.property("2");
- currentNodes.should.have.a.property("3");
- currentNodes.should.have.a.property("4");
-
- currentNodes["1"].should.have.a.property("handled",0);
- currentNodes["2"].should.have.a.property("handled",0);
- currentNodes["3"].should.have.a.property("handled",0);
-
- currentNodes["3"].on("input", function() {
- currentNodes["1"].should.have.a.property("handled",1);
- currentNodes["2"].should.have.a.property("handled",1);
- currentNodes["3"].should.have.a.property("handled",1);
-
- flow.stop().then(function() {
- try {
- currentNodes.should.not.have.a.property("1");
- currentNodes.should.not.have.a.property("2");
- currentNodes.should.not.have.a.property("3");
- currentNodes.should.not.have.a.property("4");
- stoppedNodes.should.have.a.property("1");
- stoppedNodes.should.have.a.property("2");
- stoppedNodes.should.have.a.property("3");
- stoppedNodes.should.have.a.property("4");
- done();
- } catch(err) {
- done(err);
- }
- });
- });
- currentNodes["1"].receive({payload:"test"});
- });
-
- it("instantiates config nodes in the right order",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:"test",foo:"a",wires:["3"]},
- {id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
- {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"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(5);
-
-
- currentNodes.should.have.a.property("1");
- currentNodes.should.have.a.property("2");
- currentNodes.should.have.a.property("3");
- currentNodes.should.have.a.property("4");
- currentNodes.should.have.a.property("5");
-
- currentNodes["1"].should.have.a.property("_index",2);
- currentNodes["2"].should.have.a.property("_index",3);
- currentNodes["3"].should.have.a.property("_index",4);
- currentNodes["4"].should.have.a.property("_index",1);
- currentNodes["5"].should.have.a.property("_index",0);
-
- flow.stop().then(function() {
- currentNodes.should.not.have.a.property("1");
- currentNodes.should.not.have.a.property("2");
- currentNodes.should.not.have.a.property("3");
- currentNodes.should.not.have.a.property("4");
- currentNodes.should.not.have.a.property("5");
- stoppedNodes.should.have.a.property("1");
- stoppedNodes.should.have.a.property("2");
- stoppedNodes.should.have.a.property("3");
- stoppedNodes.should.have.a.property("4");
- stoppedNodes.should.have.a.property("5");
- done();
- });
- });
-
-
- it("detects dependency loops in config nodes",function() {
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab"},
- {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"]);
- /*jshint immed: false */
- (function(){
- flow.start();
- }).should.throw("Circular config node dependency detected: node1");
- });
-
- it("rewires nodes specified by diff",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:"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"]);
- createCount.should.equal(0);
- flow.start();
- //TODO: use update to pass in new wiring and verify the change
- createCount.should.equal(3);
- flow.start({rewired:["2"]});
- createCount.should.equal(3);
- rewiredNodes.should.have.a.property("2");
- done();
- });
-
- it("instantiates a node with environment variable property values",function(done) {
- after(function() {
- delete process.env.NODE_RED_TEST_VALUE;
- })
- process.env.NODE_RED_TEST_VALUE = "a-value";
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab"},
- {id:"1",x:10,y:10,z:"t1",type:"test",foo:"$(NODE_RED_TEST_VALUE)",wires:[]},
- {id:"2",x:10,y:10,z:"t1",type:"test",foo:{a:"$(NODE_RED_TEST_VALUE)"},wires:[]},
- {id:"3",x:10,y:10,z:"t1",type:"test",foo:" $(NODE_RED_TEST_VALUE)",wires:[]},
- {id:"4",x:10,y:10,z:"t1",type:"test",foo:"$(NODE_RED_TEST_VALUE) ",wires:[]},
- {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({getSetting:v=>process.env[v]},config,config.flows["t1"]);
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
-
- activeNodes["1"].foo.should.equal("a-value");
- activeNodes["2"].foo.a.should.equal("a-value");
- activeNodes["3"].foo.should.equal(" $(NODE_RED_TEST_VALUE)");
- activeNodes["4"].foo.should.equal("$(NODE_RED_TEST_VALUE) ");
- activeNodes["5"].foo.should.equal("$(NODE_RED_TEST_VALUE_NONE)");
- activeNodes["6"].foo[0].should.equal("a-value");
-
- flow.stop().then(function() {
- done();
- });
- });
-
- it("ignores disabled 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",d:true,type:"test",foo:"a",wires:["3"]},
- {id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
- {id:"4",z:"t1",type:"test",foo:"a"},
- {id:"5",z:"t1",type:"test",d:true,foo:"a"}
-
- ]);
- var flow = Flow.create({},config,config.flows["t1"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(3);
-
- flow.getNode('1').should.have.a.property('id','1');
- should.not.exist(flow.getNode('2'));
- flow.getNode('3').should.have.a.property('id','3');
- flow.getNode('4').should.have.a.property('id','4');
- should.not.exist(flow.getNode('5'));
-
- 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["1"].should.have.a.property("handled",0);
- currentNodes["3"].should.have.a.property("handled",0);
-
- currentNodes["1"].receive({payload:"test"});
-
- setTimeout(function() {
- currentNodes["1"].should.have.a.property("handled",1);
- // Message doesn't reach 3 as 2 is disabled
- currentNodes["3"].should.have.a.property("handled",0);
-
- flow.stop().then(function() {
- try {
- currentNodes.should.not.have.a.property("1");
- currentNodes.should.not.have.a.property("2");
- currentNodes.should.not.have.a.property("3");
- currentNodes.should.not.have.a.property("4");
- stoppedNodes.should.have.a.property("1");
- stoppedNodes.should.not.have.a.property("2");
- stoppedNodes.should.have.a.property("3");
- stoppedNodes.should.have.a.property("4");
- done();
- } catch(err) {
- done(err);
- }
- });
- },50);
- });
-
- });
-
- describe('#stop', function() {
-
-
- it("stops all 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:"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"]);
- flow.start();
-
-
- currentNodes.should.have.a.property("1");
- currentNodes.should.have.a.property("2");
- currentNodes.should.have.a.property("3");
-
- flow.stop().then(function() {
- currentNodes.should.not.have.a.property("1");
- currentNodes.should.not.have.a.property("2");
- currentNodes.should.not.have.a.property("3");
- stoppedNodes.should.have.a.property("1");
- stoppedNodes.should.have.a.property("2");
- stoppedNodes.should.have.a.property("3");
- done();
- }).catch(done);
- });
-
- it("stops specified 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:"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"]);
- flow.start();
-
- currentNodes.should.have.a.property("1");
- currentNodes.should.have.a.property("2");
- currentNodes.should.have.a.property("3");
-
- flow.stop(["2"]).then(function() {
- currentNodes.should.have.a.property("1");
- currentNodes.should.not.have.a.property("2");
- currentNodes.should.have.a.property("3");
- stoppedNodes.should.not.have.a.property("1");
- stoppedNodes.should.have.a.property("2");
- stoppedNodes.should.not.have.a.property("3");
- done();
- });
- });
-
- it("stops config nodes last",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:"c1",z:"t1",type:"test"},
- {id:"2",x:10,y:10,z:"t1",type:"test",foo:"a",wires:["3"]},
- {id:"c2",z:"t1",type:"test"},
- {id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
- {id:"c3",z:"t1",type:"test"}
- ]);
- var flow = Flow.create({},config,config.flows["t1"]);
- flow.start();
-
- currentNodes.should.have.a.property("1");
- currentNodes.should.have.a.property("2");
- currentNodes.should.have.a.property("3");
- currentNodes.should.have.a.property("c1");
- currentNodes.should.have.a.property("c2");
- currentNodes.should.have.a.property("c3");
- stoppedOrder.should.have.a.length(0);
-
- flow.stop().then(function() {
- stoppedOrder.should.eql([ '1', '2', '3', 'c1', 'c2', 'c3' ]);
- done();
- }).catch(done);
- });
-
-
- it("Times out a node that fails to close", function(done) {
- Flow.init({settings:{nodeCloseTimeout:50},log:{
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- _: function() { return "abc"}
- }});
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab"},
- {id:"1",x:10,y:10,z:"t1",type:"testAsync",closeDelay: 80, foo:"a",wires:["2"]},
- {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"]);
- flow.start();
-
- currentNodes.should.have.a.property("1");
- currentNodes.should.have.a.property("2");
- currentNodes.should.have.a.property("3");
-
- flow.stop().then(function() {
- currentNodes.should.have.a.property("1");
- currentNodes.should.not.have.a.property("2");
- currentNodes.should.not.have.a.property("3");
- stoppedNodes.should.not.have.a.property("1");
- stoppedNodes.should.have.a.property("2");
- stoppedNodes.should.have.a.property("3");
- setTimeout(function() {
- currentNodes.should.not.have.a.property("1");
- stoppedNodes.should.have.a.property("1");
- done();
- },40)
- });
- });
-
- });
-
- describe('#getNode',function() {
- it("gets a node known to the flow",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:"test",foo:"a",wires:["3"]},
- {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"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(4);
-
- flow.getNode('1').should.have.a.property('id','1');
-
- flow.stop().then(() => { done() });
- });
-
- it("passes to parent if node not known locally",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:"test",foo:"a",wires:["3"]},
- {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({
- getNode: id => { return {id:id}}
- },config,config.flows["t1"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(4);
-
- flow.getNode('1').should.have.a.property('id','1');
-
- flow.getNode('parentNode').should.have.a.property('id','parentNode');
-
-
- flow.stop().then(() => { done() });
- });
-
- it("does not pass to parent if cancelBubble set",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:"test",foo:"a",wires:["3"]},
- {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({
- getNode: id => { return {id:id}}
- },config,config.flows["t1"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(4);
-
- flow.getNode('1').should.have.a.property('id','1');
-
- should.not.exist(flow.getNode('parentNode',true));
- flow.stop().then(() => { done() });
- });
- });
-
- describe("#handleStatus",function() {
- it("passes a status event to the adjacent 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:"test",wires:["3"]},
- {id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
- {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"]);
-
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
- Object.keys(activeNodes).should.have.length(5);
-
-
- flow.handleStatus(config.flows["t1"].nodes["1"],{text:"my-status",random:"otherProperty"});
-
- setTimeout(function() {
-
- 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","1");
- statusMessage.status.source.should.have.a.property("type","test");
- statusMessage.status.source.should.have.a.property("name","a");
-
- currentNodes["sn2"].should.have.a.property("handled",1);
- statusMessage = currentNodes["sn2"].messages[0];
-
- statusMessage.should.have.a.property("status");
- statusMessage.status.should.have.a.property("text","my-status");
- statusMessage.status.should.have.a.property("random","otherProperty");
- statusMessage.status.should.have.a.property("source");
- statusMessage.status.source.should.have.a.property("id","1");
- statusMessage.status.source.should.have.a.property("type","test");
- statusMessage.status.source.should.have.a.property("name","a");
-
-
- flow.stop().then(function() {
- done();
- });
- },50)
- });
- it("passes a status event to the adjacent scoped 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:"test",wires:["3"]},
- {id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
- {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"]);
-
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
- Object.keys(activeNodes).should.have.length(5);
-
-
- flow.handleStatus(config.flows["t1"].nodes["1"],{text:"my-status"});
-
- setTimeout(function() {
- currentNodes["sn"].should.have.a.property("handled",0);
- currentNodes["sn2"].should.have.a.property("handled",1);
- var statusMessage = currentNodes["sn2"].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","1");
- statusMessage.status.source.should.have.a.property("type","test");
- statusMessage.status.source.should.have.a.property("name","a");
-
-
- flow.stop().then(function() {
- done();
- });
- },50);
- });
-
- });
-
- describe("#handleError",function() {
- it("passes an error event to the adjacent 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:"test",wires:["3"]},
- {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:[]},
- {id:"sn2",x:10,y:10,z:"t1",type:"catch",foo:"a",wires:[]},
- {id:"sn3",x:10,y:10,z:"t1",type:"catch",uncaught:true,wires:[]}
- ]);
- var flow = Flow.create({},config,config.flows["t1"]);
-
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
- Object.keys(activeNodes).should.have.length(6);
-
-
- flow.handleError(config.flows["t1"].nodes["1"],"my-error",{a:"foo"});
-
- setTimeout(function() {
- 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","1");
- statusMessage.error.source.should.have.a.property("type","test");
- statusMessage.error.source.should.have.a.property("name","a");
-
- currentNodes["sn2"].should.have.a.property("handled",1);
- statusMessage = currentNodes["sn2"].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","1");
- statusMessage.error.source.should.have.a.property("type","test");
- statusMessage.error.source.should.have.a.property("name","a");
-
- // Node sn3 has uncaught:true - so should not get called
- currentNodes["sn3"].should.have.a.property("handled",0);
-
-
- flow.stop().then(function() {
- done();
- });
- },50);
- });
- it("passes an error event to the adjacent scoped 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:"test",wires:["3"]},
- {id:"3",x:10,y:10,z:"t1",type:"test",foo:"a",wires:[]},
- {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:[]},
- {id:"sn3",x:10,y:10,z:"t1",type:"catch",uncaught:true,wires:[]},
- {id:"sn4",x:10,y:10,z:"t1",type:"catch",uncaught:true,wires:[]}
- ]);
- var flow = Flow.create({},config,config.flows["t1"]);
-
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
- Object.keys(activeNodes).should.have.length(7);
-
- flow.handleError(config.flows["t1"].nodes["1"],"my-error",{a:"foo"});
-
- setTimeout(function() {
- currentNodes["sn"].should.have.a.property("handled",0);
- currentNodes["sn2"].should.have.a.property("handled",1);
- var statusMessage = currentNodes["sn2"].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","1");
- statusMessage.error.source.should.have.a.property("type","test");
- statusMessage.error.source.should.have.a.property("name","a");
-
- // Node sn3/4 have uncaught:true - so should not get called
- currentNodes["sn3"].should.have.a.property("handled",0);
- currentNodes["sn4"].should.have.a.property("handled",0);
-
- // Inject error that sn1/2 will ignore - so should get picked up by sn3
- flow.handleError(config.flows["t1"].nodes["3"],"my-error-2",{a:"foo-2"});
- setTimeout(function() {
- currentNodes["sn"].should.have.a.property("handled",0);
- currentNodes["sn2"].should.have.a.property("handled",1);
- currentNodes["sn3"].should.have.a.property("handled",1);
- currentNodes["sn4"].should.have.a.property("handled",1);
-
- statusMessage = currentNodes["sn3"].messages[0];
- statusMessage.should.have.a.property("error");
- statusMessage.error.should.have.a.property("message","my-error-2");
- statusMessage.error.should.have.a.property("source");
- statusMessage.error.source.should.have.a.property("id","3");
- statusMessage.error.source.should.have.a.property("type","test");
-
- flow.stop().then(function() {
- done();
- });
- },50);
- },50);
- });
- it("moves any existing error object sideways",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:"test",wires:["3"]},
- {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"]);
-
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
-
- flow.handleError(config.flows["t1"].nodes["1"],"my-error",{a:"foo",error:"existing"});
- setTimeout(function() {
- currentNodes["sn"].should.have.a.property("handled",1);
- var statusMessage = currentNodes["sn"].messages[0];
-
- statusMessage.should.have.a.property("_error","existing");
- 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","1");
- statusMessage.error.source.should.have.a.property("type","test");
- statusMessage.error.source.should.have.a.property("name","a");
-
- flow.stop().then(function() {
- done();
- });
- },50);
- });
- it("prevents an error looping more than 10 times",function(){});
- });
-
- describe("#handleComplete",function() {
- it("passes a complete event to the adjacent Complete node",function(done) {
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab"},
- {id:"1",x:10,y:10,z:"t1",type:"testDone",name:"a",wires:["2"]},
- {id:"2",x:10,y:10,z:"t1",type:"test",wires:["3"]},
- {id:"3",x:10,y:10,z:"t1",type:"testDone",foo:"a",wires:[]},
- {id:"cn",x:10,y:10,z:"t1",type:"complete",scope:["1","3"],foo:"a",wires:[]}
- ]);
- var flow = Flow.create({},config,config.flows["t1"]);
-
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
- Object.keys(activeNodes).should.have.length(4);
-
- var msg = {payload: "hello world"}
- var n1 = currentNodes["1"].receive(msg);
- setTimeout(function() {
- currentNodes["cn"].should.have.a.property("handled",2);
- currentNodes["cn"].messages[0].should.have.a.property("handled",1);
- currentNodes["cn"].messages[1].should.have.a.property("handled",2);
- flow.stop().then(function() {
- done();
- });
- },50);
- });
- });
-
-
- describe("#send", function() {
- it("sends a message - no cloning", function(done) {
- var shutdownTest = function(err) {
- hooks.clear();
- flow.stop().then(() => { done(err) });
- }
- 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:"test",foo:"a",wires:["3"]}
- ]);
- var flow = Flow.create({},config,config.flows["t1"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(2);
-
- var n1 = flow.getNode('1');
- var n2 = flow.getNode('2');
- var messageReceived = false;
- n2.receive = function(msg) {
- messageReceived = true;
- try {
- msg.should.be.exactly(message);
- shutdownTest();
- } catch(err) {
- shutdownTest(err);
- }
- }
-
- var message = {payload:"hello"}
- flow.send([{
- msg: message,
- source: { id:"1", node: n1 },
- destination: { id:"2", node: undefined },
- cloneMessage: false
- }])
- messageReceived.should.be.false()
- })
- it("sends a message - cloning", function(done) {
- var shutdownTest = function(err) {
- hooks.clear();
- flow.stop().then(() => { done(err) });
- }
- 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:"test",foo:"a",wires:["3"]}
- ]);
- var flow = Flow.create({},config,config.flows["t1"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(2);
-
- var n1 = flow.getNode('1');
- var n2 = flow.getNode('2');
-
- n2.receive = function(msg) {
- try {
- // Message should be cloned
- msg.should.be.eql(message);
- msg.should.not.be.exactly(message);
- shutdownTest();
- } catch(err) {
- shutdownTest(err);
- }
- }
-
- var message = {payload:"hello"}
- flow.send([{
- msg: message,
- source: { id:"1", node: n1 },
- destination: { id:"2", node: undefined },
- cloneMessage: true
- }])
- })
- it("sends multiple messages", function(done) {
- var shutdownTest = function(err) {
- hooks.clear();
- flow.stop().then(() => { done(err) });
- }
- 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:"test",foo:"a",wires:["3"]}
- ]);
- var flow = Flow.create({},config,config.flows["t1"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(2);
-
- var n1 = flow.getNode('1');
- var n2 = flow.getNode('2');
-
- var messageCount = 0;
- n2.receive = function(msg) {
- try {
- msg.should.be.exactly(messages[messageCount++]);
- if (messageCount === 2) {
- shutdownTest();
- }
- } catch(err) {
- shutdownTest(err);
- }
- }
-
- var messages = [{payload:"hello"},{payload:"world"}];
-
- flow.send([{
- msg: messages[0],
- source: { id:"1", node: n1 },
- destination: { id:"2", node: undefined }
- },{
- msg: messages[1],
- source: { id:"1", node: n1 },
- destination: { id:"2", node: undefined }
- }])
- })
- it("sends a message - triggers hooks", function(done) {
- var hookErrors = [];
- var messageReceived = false;
- var hooksCalled = [];
- hooks.add("onSend", function(sendEvents) {
- hooksCalled.push("onSend")
- try {
- messageReceived.should.be.false()
- sendEvents.should.have.length(1);
- sendEvents[0].msg.should.be.exactly(message);
- } catch(err) {
- hookErrors.push(err);
- }
- })
- hooks.add("preRoute", function(sendEvent) {
- hooksCalled.push("preRoute")
- try {
- messageReceived.should.be.false()
- sendEvent.msg.should.be.exactly(message);
- should.not.exist(sendEvent.destination.node)
- } catch(err) {
- hookErrors.push(err);
- }
-
- })
- hooks.add("preDeliver", function(sendEvent) {
- hooksCalled.push("preDeliver")
- try {
- messageReceived.should.be.false()
- // Cloning should have happened
- sendEvent.msg.should.not.be.exactly(message);
- // Destinatino node populated
- should.exist(sendEvent.destination.node)
- } catch(err) {
- hookErrors.push(err);
- }
-
- })
- hooks.add("postDeliver", function(sendEvent) {
- hooksCalled.push("postDeliver")
- try {
- messageReceived.should.be.false()
-
- } catch(err) {
- hookErrors.push(err);
- }
-
- })
- var shutdownTest = function(err) {
- hooks.clear();
- flow.stop().then(() => { done(err) });
- }
- 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:"test",foo:"a",wires:["3"]}
- ]);
- var flow = Flow.create({},config,config.flows["t1"]);
- flow.start();
-
- Object.keys(flow.getActiveNodes()).should.have.length(2);
-
- var n1 = flow.getNode('1');
- var n2 = flow.getNode('2');
- n2.receive = function(msg) {
- messageReceived = true;
- try {
- msg.should.be.eql(message);
- msg.should.not.be.exactly(message);
- hooksCalled.should.eql(["onSend","preRoute","preDeliver","postDeliver"])
- if (hookErrors.length > 0) {
- shutdownTest(hookErrors[0])
- } else {
- shutdownTest();
- }
- } catch(err) {
- shutdownTest(err);
- }
- }
-
- var message = {payload:"hello"}
- flow.send([{
- msg: message,
- source: { id:"1", node: n1 },
- destination: { id:"2", node: undefined },
- cloneMessage: true
- }])
- })
-
- describe("errors thrown by hooks are reported to the sending node", function() {
- var flow;
- var n1,n2;
- var messageReceived = false;
- var errorReceived = null;
- before(function() {
- hooks.add("onSend", function(sendEvents) {
- if (sendEvents[0].msg.payload === "trigger-onSend") {
- throw new Error("onSend Error");
- }
- })
- hooks.add("preRoute", function(sendEvent) {
- if (sendEvent.msg.payload === "trigger-preRoute") {
- throw new Error("preRoute Error");
- }
- })
- hooks.add("preDeliver", function(sendEvent) {
- if (sendEvent.msg.payload === "trigger-preDeliver") {
- throw new Error("preDeliver Error");
- }
- })
- hooks.add("postDeliver", function(sendEvent) {
- if (sendEvent.msg.payload === "trigger-postDeliver") {
- throw new Error("postDeliver Error");
- }
- })
- 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:"test",foo:"a",wires:["3"]}
- ]);
- flow = Flow.create({},config,config.flows["t1"]);
- flow.start();
- n1 = flow.getNode('1');
- n2 = flow.getNode('2');
- n2.receive = function(msg) {
- messageReceived = true;
- }
- n1.error = function(err) {
- errorReceived = err;
- }
-
- })
- after(function(done) {
- hooks.clear();
- flow.stop().then(() => { done() });
- })
- beforeEach(function() {
- messageReceived = false;
- errorReceived = null;
- })
- function testHook(hook, msgExpected, done) {
- var message = {payload:"trigger-"+hook}
- flow.send([{
- msg: message,
- source: { id:"1", node: n1 },
- destination: { id:"2", node: undefined },
- cloneMessage: true
- }])
- setTimeout(function() {
- try {
- messageReceived.should.equal(msgExpected);
- should.exist(errorReceived)
- errorReceived.toString().should.containEql(hook);
- done();
- } catch(err) {
- done(err);
- }
- },10)
- }
-
- it("onSend", function(done) { testHook("onSend", false, done) })
- it("preRoute", function(done) { testHook("preRoute", false, done) })
- it("preDeliver", function(done) { testHook("preDeliver", false, done) })
- it("postDeliver", function(done) { testHook("postDeliver", true, done) })
- })
-
- describe("hooks can stop the sending of messages", function() {
- var flow;
- var n1,n2;
- var messageReceived = false;
- var errorReceived = false;
- before(function() {
- hooks.add("onSend", function(sendEvents) {
- if (sendEvents[0].msg.payload === "trigger-onSend") {
- return false
- }
- })
- hooks.add("preRoute", function(sendEvent) {
- if (sendEvent.msg.payload === "trigger-preRoute") {
- return false
- }
- })
- hooks.add("preDeliver", function(sendEvent) {
- if (sendEvent.msg.payload === "trigger-preDeliver") {
- return false
- }
- })
- hooks.add("postDeliver", function(sendEvent) {
- if (sendEvent.msg.payload === "trigger-postDeliver") {
- return false
- }
- })
- 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:"test",foo:"a",wires:["3"]}
- ]);
- flow = Flow.create({},config,config.flows["t1"]);
- flow.start();
- n1 = flow.getNode('1');
- n2 = flow.getNode('2');
- n2.receive = function(msg) {
- messageReceived = true;
- }
- n1.error = function(err) {
- errorReceived = true;
- }
-
- })
- after(function(done) {
- hooks.clear();
- flow.stop().then(() => { done() });
- })
- function testSend(payload,messageReceivedExpected,errorReceivedExpected,done) {
- messageReceived = false;
- errorReceived = false;
- flow.send([{
- msg: {payload: payload},
- source: { id:"1", node: n1 },
- destination: { id:"2", node: undefined },
- cloneMessage: true
- }])
- setTimeout(function() {
- try {
- messageReceived.should.eql(messageReceivedExpected)
- errorReceived.should.eql(errorReceivedExpected)
- done();
- } catch(err) {
- done(err);
- }
- },10)
- }
- function testHook(hook, done) {
- testSend("pass",true,false,err => {
- if (err) {
- done(err)
- } else {
- testSend("trigger-"+hook,false,false,done);
- }
- })
- }
-
- it("onSend", function(done) { testHook("onSend", done) })
- it("preRoute", function(done) { testHook("preRoute", done) })
- it("preDeliver", function(done) { testHook("preDeliver", done) })
- // postDeliver happens after delivery is scheduled so cannot stop it
- // it("postDeliver", function(done) { testHook("postDeliver", done) })
- })
- })
-
- describe("#env", function () {
- it("can instantiate a node with environment variable property values of group and tab", function (done) {
- try {
- after(function() {
- delete process.env.V0;
- delete process.env.V1;
- })
- process.env.V0 = "gv0";
- process.env.V1 = "gv1";
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab",env:[
- {"name": "V0", value: "v0", type: "str"}
- ]},
- {id:"g1",type:"group",z:"t1",env:[
- {"name": "V0", value: "v1", type: "str"},
- {"name": "V1", value: "v2", type: "str"}
- ]},
- {id:"g2",type:"group",z:"t1",g:"g1",env:[
- {"name": "V1", value: "v3", type: "str"}
- ]},
- {id:"1",x:10,y:10,z:"t1",type:"test",foo:"$(V0)",wires:[]},
- {id:"2",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"$(V0)",wires:[]},
- {id:"3",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"$(V1)",wires:[]},
- {id:"4",x:10,y:10,z:"t1",g:"g2",type:"test",foo:"$(V1)",wires:[]},
- {id:"5",x:10,y:10,z:"t1",type:"test",foo:"$(V1)",wires:[]},
- ]);
- var flow = Flow.create({getSetting:v=>process.env[v]},config,config.flows["t1"]);
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
-
- activeNodes["1"].foo.should.equal("v0");
- activeNodes["2"].foo.should.equal("v1");
- activeNodes["3"].foo.should.equal("v2");
- activeNodes["4"].foo.should.equal("v3");
- activeNodes["5"].foo.should.equal("gv1");
-
- flow.stop().then(function() {
- done();
- });
- }
- catch (e) {
- console.log(e.stack);
- done(e);
- }
-
- });
- it("can access environment variable property using $parent", function (done) {
- try {
- after(function() {
- delete process.env.V0;
- delete process.env.V1;
- })
- process.env.V0 = "gv0";
- process.env.V1 = "gv1";
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab",env:[
- {"name": "V0", value: "v0", type: "str"}
- ]},
- {id:"g1",type:"group",z:"t1",env:[
- {"name": "V0", value: "v1", type: "str"},
- {"name": "V1", value: "v2", type: "str"}
- ]},
- {id:"g2",type:"group",z:"t1",g:"g1",env:[
- {"name": "V1", value: "v3", type: "str"}
- ]},
- {id:"1",x:10,y:10,z:"t1",type:"test",foo:"${$parent.V0}",wires:[]},
- {id:"2",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"${$parent.V0}",wires:[]},
- {id:"3",x:10,y:10,z:"t1",g:"g1",type:"test",foo:"${$parent.V1}",wires:[]},
- {id:"4",x:10,y:10,z:"t1",g:"g2",type:"test",foo:"${$parent.V1}",wires:[]},
- {id:"5",x:10,y:10,z:"t1",type:"test",foo:"${$parent.V1}",wires:[]},
- ]);
- var flow = Flow.create({getSetting:v=>process.env[v]},config,config.flows["t1"]);
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
-
- activeNodes["1"].foo.should.equal("gv0");
- activeNodes["2"].foo.should.equal("v0");
- activeNodes["3"].foo.should.equal("gv1");
- activeNodes["4"].foo.should.equal("v2");
- activeNodes["5"].foo.should.equal("gv1");
-
- flow.stop().then(function() {
- done();
- });
- }
- catch (e) {
- console.log(e.stack);
- done(e);
- }
-
- });
-
- });
-
-});
diff --git a/test/unit/@node-red/runtime/lib/flows/Subflow_spec.js b/test/unit/@node-red/runtime/lib/flows/Subflow_spec.js
deleted file mode 100644
index c2e251447..000000000
--- a/test/unit/@node-red/runtime/lib/flows/Subflow_spec.js
+++ /dev/null
@@ -1,1006 +0,0 @@
-/**
- * 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/flows/Subflow");
-var Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Flow");
-
-var flowUtils = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/util");
-var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/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;
- this.received = null;
- currentNodes[node.id] = node;
- this.on('input',function(msg) {
- // console.log(this.id,msg.payload);
- node.handled++;
- node.received = msg.payload;
- 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);
-
- var TestEnvNode = function(n) {
- Node.call(this,n);
- this._index = createCount++;
- this.scope = n.scope;
- this.foo = n.foo;
- var node = this;
- this.stopped = false;
- this.received = null;
- currentNodes[node.id] = node;
- this.on('input',function(msg) {
- var flow = node._flow;
- var val = flow.getSetting("__KEY__");
- node.received = val;
- node.send({payload: val});
- });
- 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(TestEnvNode,Node);
-
- var TestNameEnvNode = function(n) {
- Node.call(this,n);
- this._index = createCount++;
- this.scope = n.scope;
- this.foo = n.foo;
- var node = this;
- this.stopped = false;
- this.received = null;
- currentNodes[node.id] = node;
- this.on('input',function(msg) {
- var flow = node._flow;
- var val = flow.getSetting("NR_NODE_NAME");
- node.received = val;
- node.send({payload: val});
- });
- 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(TestNameEnvNode,Node);
-
- var TestIDEnvNode = function(n) {
- Node.call(this,n);
- this._index = createCount++;
- this.scope = n.scope;
- this.foo = n.foo;
- var node = this;
- this.stopped = false;
- this.received = null;
- currentNodes[node.id] = node;
- this.on('input',function(msg) {
- var flow = node._flow;
- var val = flow.getSetting("NR_NODE_ID");
- node.received = val;
- node.send({payload: val});
- });
- 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(TestIDEnvNode,Node);
-
- before(function() {
- getType = sinon.stub(typeRegistry,"get").callsFake(function(type) {
- if (type=="test") {
- return TestNode;
- } else if (type=="testError"){
- return TestErrorNode;
- } else if (type=="testStatus"){
- return TestStatusNode;
- } else if (type=="testEnv"){
- return TestEnvNode;
- } else if (type=="testNameEnv"){
- return TestNameEnvNode;
- } else if (type=="testIDEnv"){
- return TestIDEnvNode;
- } 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"});
-
- setTimeout(function() {
- 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();
- });
- },150);
- });
- 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"});
-
- setTimeout(function() {
- 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();
- });
- },150);
- });
- 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"});
-
- setTimeout(function() {
- 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"});
- setTimeout(function() {
-
- 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();
- });
- },150);
- },150);
- });
- });
- 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 - all scope",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"});
- setTimeout(function() {
- 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();
- });
- },150);
- });
- it("passes a status event to the subflow's parent tab status node - targetted scope",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",scope:["2"],wires:[]}
- ]);
- var parentFlowStatusCalled = false;
-
- var flow = Flow.create({handleStatus:() => { parentFlowStatusCalled = true} },config,config.flows["t1"]);
-
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
-
- activeNodes["1"].receive({payload:"test"});
-
- setTimeout(function() {
- parentFlowStatusCalled.should.be.false();
-
- 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();
- });
- },150);
- });
- });
-
- describe("status node", function() {
- it("emits a status event when a message is passed to a subflow-status node - msg.payload as string", 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}]}],
- status:{wires:[{id:"sf1-1", port:0}]}
- },
- {id:"sf1-1",type:"test",name:"test","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-payload"});
-
- setTimeout(function() {
- 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-payload");
- statusMessage.status.should.have.a.property("source");
- statusMessage.status.source.should.have.a.property("id","2");
- statusMessage.status.source.should.have.a.property("type","subflow:sf1");
-
- flow.stop().then(function() {
-
- done();
- });
- },150);
- });
- it("emits a status event when a message is passed to a subflow-status node - msg.payload as status obj", 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}]}],
- status:{wires:[{id:"sf1-1", port:0}]}
- },
- {id:"sf1-1",type:"test",name:"test","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:{text:"payload-obj"}});
-
- setTimeout(function() {
- 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","payload-obj");
- statusMessage.status.should.have.a.property("source");
- statusMessage.status.source.should.have.a.property("id","2");
- statusMessage.status.source.should.have.a.property("type","subflow:sf1");
-
- flow.stop().then(function() {
-
- done();
- });
- },150);
- });
- it("emits a status event when a message is passed to a subflow-status node - msg.status", 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}]}],
- status:{wires:[{id:"sf1-1", port:0}]}
- },
- {id:"sf1-1",type:"test",name:"test","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({status:{text:"status-obj"}});
-
- setTimeout(function() {
- 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","status-obj");
- statusMessage.status.should.have.a.property("source");
- statusMessage.status.source.should.have.a.property("id","2");
- statusMessage.status.source.should.have.a.property("type","subflow:sf1");
-
- flow.stop().then(function() {
-
- done();
- });
- },150);
- });
- it("does not emit a regular status event if it contains a subflow-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}]}],
- status:{wires:[]}
- },
- {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-payload"});
-
- currentNodes["sn"].should.have.a.property("handled",0);
-
- flow.stop().then(function() {
-
- done();
- });
- });
- })
-
- describe("#handleError",function() {
- it("passes an error event to the subflow's parent tab catch node - all scope",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"});
-
- setTimeout(function() {
- 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();
- });
- },150);
- });
- it("passes an error event to the subflow's parent tab catch node - targetted scope",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",scope:["2"],wires:[]}
- ]);
- var parentFlowErrorCalled = false;
- var flow = Flow.create({handleError:() => { parentFlowErrorCalled = true} },config,config.flows["t1"]);
-
- flow.start();
-
- var activeNodes = flow.getActiveNodes();
-
- activeNodes["1"].receive({payload:"test"});
-
- setTimeout(function() {
- parentFlowErrorCalled.should.be.false();
-
- 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();
- });
- },150);
-
- });
- });
-
- describe("#env var", function() {
- // should be changed according to internal env var representation
- function setEnv(node, key, val) {
- var flow = node._flow;
- if (flow) {
- var env = flow.env;
- if (!env) {
- env = flow.env = {};
- }
- env[key] = {
- name: key,
- type: "str",
- value: val
- };
- }
- }
-
- it("can access process env var", function(done) {
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab"},
- {id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",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:"t1.3",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:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
- {id:"sf1-2",type:"testEnv",z:"sf1",foo:"sf1-cn",x:166,y:99,wires:[[]]}
- ]);
- var flow = Flow.create({
- getSetting: k=> process.env[k],
- handleError: (a,b,c) => { console.log(a,b,c); }
- },config,config.flows["t1"]);
-
- flow.start();
-
- process.env["__KEY__"] = "__VAL__";
-
- currentNodes["1"].receive({payload: "test"});
- setTimeout(function() {
- currentNodes["3"].should.have.a.property("received", "__VAL__");
-
- flow.stop().then(function() {
- done();
- });
- },150);
- });
-
- it("can access subflow env var", function(done) {
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab"},
- {id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",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:"t1.3",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:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
- {id:"sf1-2",type:"testEnv",z:"sf1",foo:"sf1.2",x:166,y:99,wires:[[]]}
- ]);
- var flow = Flow.create({
- getSetting: k=> process.env[k],
- handleError: (a,b,c) => { console.log(a,b,c); }
- },config,config.flows["t1"]);
-
- flow.start();
-
- var testenv_node = null;
- for (var n in currentNodes) {
- var node = currentNodes[n];
- if (node.type === "testEnv") {
- testenv_node = node;
- break;
- }
- }
- process.env["__KEY__"] = "__VAL0__";
- setEnv(testenv_node, "__KEY__", "__VAL1__");
-
- currentNodes["1"].receive({payload: "test"});
- setTimeout(function() {
- currentNodes["3"].should.have.a.property("received", "__VAL1__");
-
- flow.stop().then(function() {
- done();
- });
- },150);
- });
-
- it("can access nested subflow env var", function(done) {
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab"},
- {id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",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:"t1.3",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:[{id:"sf2-1"}]}],
- out:[{wires:[{id:"sf2-2",port:0}]}]},
- {id:"sf1-1",type:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
- {id:"sf1-2",type:"subflow:sf2",z:"sf1",x:166,y:99,wires:[[]]},
- {id:"sf2-1",type:"test",z:"sf2",foo:"sf2.1",x:166,y:99,wires:[["sf2-2"]]},
- {id:"sf2-2",type:"testEnv",z:"sf2",foo:"sf2.2",x:166,y:99,wires:[[]]},
- ]);
- var flow = Flow.create({
- getSetting: k=> process.env[k],
- handleError: (a,b,c) => { console.log(a,b,c); }
- },config,config.flows["t1"]);
-
- flow.start();
-
- var node_sf1_1 = null;
- var node_sf2_1 = null;
- var testenv_node = null;
- for (var n in currentNodes) {
- var node = currentNodes[n];
- if (node.foo === "sf1.1") {
- node_sf1_1 = node;
- }
- if (node.foo === "sf2.1") {
- node_sf2_1 = node;
- }
- }
-
- process.env["__KEY__"] = "__VAL0__";
- currentNodes["1"].receive({payload: "test"});
- setTimeout(function() {
- currentNodes["3"].should.have.a.property("received", "__VAL0__");
-
- setEnv(node_sf1_1, "__KEY__", "__VAL1__");
- currentNodes["1"].receive({payload: "test"});
- setTimeout(function() {
- currentNodes["3"].should.have.a.property("received", "__VAL1__");
-
- setEnv(node_sf2_1, "__KEY__", "__VAL2__");
- currentNodes["1"].receive({payload: "test"});
- setTimeout(function() {
- currentNodes["3"].should.have.a.property("received", "__VAL2__");
-
- flow.stop().then(function() {
- done();
- });
- },150);
- },150);
- },150);
- });
-
- it("can access name of subflow as env var", function(done) {
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab"},
- {id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
- {id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",name:"SFN",wires:["3"]},
- {id:"3",x:10,y:10,z:"t1",type:"test",foo:"t1.3",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:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
- {id:"sf1-2",type:"testNameEnv",z:"sf1",foo:"sf1.2",x:166,y:99,wires:[[]]}
- ]);
- var flow = Flow.create({
- getSetting: k=> process.env[k],
- handleError: (a,b,c) => { console.log(a,b,c); }
- },config,config.flows["t1"]);
-
- flow.start();
-
- currentNodes["1"].receive({payload: "test"});
- setTimeout(function() {
- currentNodes["3"].should.have.a.property("received", "SFN");
-
- flow.stop().then(function() {
- done();
- });
- },150);
- });
-
- it("can access id of subflow as env var", function(done) {
- var config = flowUtils.parseConfig([
- {id:"t1",type:"tab"},
- {id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
- {id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",name:"SFN",wires:["3"]},
- {id:"3",x:10,y:10,z:"t1",type:"test",foo:"t1.3",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:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
- {id:"sf1-2",type:"testIDEnv",z:"sf1",foo:"sf1.2",x:166,y:99,wires:[[]]}
- ]);
- var flow = Flow.create({
- getSetting: k=> process.env[k],
- handleError: (a,b,c) => { console.log(a,b,c); }
- },config,config.flows["t1"]);
-
- flow.start();
-
- currentNodes["1"].receive({payload: "test"});
- setTimeout(function() {
- currentNodes["3"].should.have.a.property("received", "2");
-
- flow.stop().then(function() {
- done();
- });
- },150);
- });
-
-
- });
-
-});
diff --git a/test/unit/@node-red/runtime/lib/flows/index_spec.js b/test/unit/@node-red/runtime/lib/flows/index_spec.js
deleted file mode 100644
index 737846100..000000000
--- a/test/unit/@node-red/runtime/lib/flows/index_spec.js
+++ /dev/null
@@ -1,669 +0,0 @@
-/**
- * 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(),
- 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() {
- 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() {
- 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',
- { 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");
- })
-});
diff --git a/test/unit/@node-red/runtime/lib/flows/util_spec.js b/test/unit/@node-red/runtime/lib/flows/util_spec.js
deleted file mode 100644
index 6a4571e87..000000000
--- a/test/unit/@node-red/runtime/lib/flows/util_spec.js
+++ /dev/null
@@ -1,801 +0,0 @@
-/**
- * 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 flowUtil = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/util");
-var typeRegistry = NR_TEST_UTILS.require("@node-red/registry");
-var redUtil = NR_TEST_UTILS.require("@node-red/util").util;
-
-describe('flows/util', function() {
- var getType;
-
- before(function() {
- getType = sinon.stub(typeRegistry,"get").callsFake(function(type) {
- return type!=='missing';
- });
- });
- after(function() {
- getType.restore();
- });
-
- describe('#mapEnvVarProperties',function() {
- before(function() {
- process.env.foo1 = "bar1";
- process.env.foo2 = "bar2";
- process.env.foo3 = "bar3";
- })
- after(function() {
- delete process.env.foo1;
- delete process.env.foo2;
- delete process.env.foo3;
- })
- it('handles ENV substitutions in an object - $()', function() {
- var foo = {a:"$(foo1)",b:"$(foo2)",c:{d:"$(foo3)"}};
- for (var p in foo) {
- if (foo.hasOwnProperty(p)) {
- flowUtil.mapEnvVarProperties(foo,p,{getSetting: p => process.env[p]});
- }
- }
- foo.should.eql({ a: 'bar1', b: 'bar2', c: { d: 'bar3' } } );
- });
- it('handles ENV substitutions in an object - ${}', function() {
- var foo = {a:"${foo1}",b:"${foo2}",c:{d:"${foo3}"}};
- for (var p in foo) {
- if (foo.hasOwnProperty(p)) {
- flowUtil.mapEnvVarProperties(foo,p,{getSetting: p => process.env[p]});
- }
- }
- foo.should.eql({ a: 'bar1', b: 'bar2', c: { d: 'bar3' } } );
- });
-
- it('gets ENV from parent flow', function() {
- var foo = {a:"$(unknown)",b:"$(foo2)",c:{d:"$(foo3)"}};
- for (var p in foo) {
- if (foo.hasOwnProperty(p)) {
- flowUtil.mapEnvVarProperties(foo,p,{
- getSetting: name => name[0]==='f'?name.toUpperCase():undefined
- });
- }
- }
- foo.should.eql({ a: '$(unknown)', b: 'FOO2', c: { d: 'FOO3' } } );
- });
- });
- describe('#getEnvVar',function() {
- before(function() {
- process.env.foo1 = "bar1";
- })
- after(function() {
- delete process.env.foo1;
- })
- it('returns a known env var', function() {
- flowUtil.init({settings:{}});
- flowUtil.getEnvVar("foo1").should.equal("bar1")
- })
- it('returns undefined for an unknown env var', function() {
- flowUtil.init({settings:{}});
- (flowUtil.getEnvVar("foo2") === undefined).should.be.true()
- })
- it('returns undefined for an excluded env var', function() {
- flowUtil.init({settings:{envVarExcludes:['foo1']}});
- (flowUtil.getEnvVar("foo1") === undefined).should.be.true()
- })
-
- });
-
- describe('#diffNodes',function() {
- it('handles a null old node', function() {
- flowUtil.diffNodes(null,{}).should.be.true();
- });
- it('ignores x/y changes', function() {
- flowUtil.diffNodes({x:10,y:10},{x:20,y:10}).should.be.false();
- flowUtil.diffNodes({x:10,y:10},{x:10,y:20}).should.be.false();
- });
- it('ignores wiring changes', function() {
- flowUtil.diffNodes({wires:[]},{wires:[1,2,3]}).should.be.false();
- });
- it('spots existing property change - string', function() {
- flowUtil.diffNodes({a:"foo"},{a:"bar"}).should.be.true();
- });
- it('spots existing property change - number', function() {
- flowUtil.diffNodes({a:0},{a:1}).should.be.true();
- });
- it('spots existing property change - boolean', function() {
- flowUtil.diffNodes({a:true},{a:false}).should.be.true();
- });
- it('spots existing property change - truthy', function() {
- flowUtil.diffNodes({a:true},{a:1}).should.be.true();
- });
- it('spots existing property change - falsey', function() {
- flowUtil.diffNodes({a:false},{a:0}).should.be.true();
- });
- it('spots existing property change - array', function() {
- flowUtil.diffNodes({a:[0,1,2]},{a:[0,2,3]}).should.be.true();
- });
- it('spots existing property change - object', function() {
- flowUtil.diffNodes({a:{a:[0,1,2]}},{a:{a:[0,2,3]}}).should.be.true();
- flowUtil.diffNodes({a:{a:[0,1,2]}},{a:{b:[0,1,2]}}).should.be.true();
- });
- it('spots added property', function() {
- flowUtil.diffNodes({a:"foo"},{a:"foo",b:"bar"}).should.be.true();
- });
- it('spots removed property', function() {
- flowUtil.diffNodes({a:"foo",b:"bar"},{a:"foo"}).should.be.true();
- });
-
-
- });
-
- describe('#parseConfig',function() {
-
- it('parses a single-tab flow', function() {
- var originalConfig = [
- {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
- {id:"t1",type:"tab"}
- ];
- var parsedConfig = flowUtil.parseConfig(originalConfig);
- var expectedConfig = {"allNodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]},"t1":{"id":"t1","type":"tab"}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]}}}},"groups":{},"missingTypes":[]};
- parsedConfig.should.eql(expectedConfig);
- });
-
- it('parses a single-tab flow with global config node', function() {
- var originalConfig = [
- {id:"t1-1",x:10,y:10,z:"t1",type:"test",foo:"cn", wires:[]},
- {id:"cn",type:"test"},
- {id:"t1",type:"tab"}
- ];
- var parsedConfig = flowUtil.parseConfig(originalConfig);
- var expectedConfig = {"allNodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]},"cn":{"id":"cn","type":"test"},"t1":{"id":"t1","type":"tab"}},"subflows":{},"configs":{"cn":{"id":"cn","type":"test","_users":["t1-1"]}},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]}}}},"groups":{},"missingTypes":[]};
- parsedConfig.should.eql(expectedConfig);
- });
-
- it('parses a multi-tab flow', function() {
- var originalConfig = [
- {id:"t1",type:"tab"},
- {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
- {id:"t2",type:"tab"},
- {id:"t2-1",x:10,y:10,z:"t2",type:"test",wires:[]}
- ];
- var parsedConfig = flowUtil.parseConfig(originalConfig);
- var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]},"t2":{"id":"t2","type":"tab"},"t2-1":{"id":"t2-1","x":10,"y":10,"z":"t2","type":"test","wires":[]}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]}}},"t2":{"id":"t2","type":"tab","subflows":{},"configs":{},"nodes":{"t2-1":{"id":"t2-1","x":10,"y":10,"z":"t2","type":"test","wires":[]}}}},"groups":{},"missingTypes":[]};
- parsedConfig.should.eql(expectedConfig);
- });
-
- it('parses a subflow flow', function() {
- var originalConfig = [
- {id:"t1",type:"tab"},
- {id:"t1-1",x:10,y:10,z:"t1",type:"subflow:sf1",wires:[]},
- {id:"sf1",type:"subflow"},
- {id:"sf1-1",x:10,y:10,z:"sf1",type:"test",wires:[]}
- ];
- var parsedConfig = flowUtil.parseConfig(originalConfig);
- var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"subflow:sf1","wires":[]},"sf1":{"id":"sf1","type":"subflow"},"sf1-1":{"id":"sf1-1","x":10,"y":10,"z":"sf1","type":"test","wires":[]}},"subflows":{"sf1":{"id":"sf1","type":"subflow","configs":{},"nodes":{"sf1-1":{"id":"sf1-1","x":10,"y":10,"z":"sf1","type":"test","wires":[]}},"instances":[{"id":"t1-1","x":10,"y":10,"z":"t1","type":"subflow:sf1","wires":[],"subflow":"sf1"}]}},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"subflow:sf1","wires":[],"subflow":"sf1"}}}},"groups":{},"missingTypes":[]};
- parsedConfig.should.eql(expectedConfig);
- });
-
- it('parses a flow with a missing type', function() {
- var originalConfig = [
- {id:"t1",type:"tab"},
- {id:"t1-1",x:10,y:10,z:"t1",type:"sf1",wires:[]},
- {id:"t1-2",x:10,y:10,z:"t1",type:"missing",wires:[]},
- ];
- var parsedConfig = flowUtil.parseConfig(originalConfig);
- parsedConfig.missingTypes.should.eql(['missing']);
- var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"sf1","wires":[]},"t1-2":{"id":"t1-2","x":10,"y":10,"z":"t1","type":"missing","wires":[]}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"sf1","wires":[]},'t1-2': { id: 't1-2', x: 10, y: 10, z: 't1', type: 'missing', wires: [] }}}},"groups":{},"missingTypes":["missing"]};
- redUtil.compareObjects(parsedConfig,expectedConfig).should.be.true();
- });
-
- it('parses a flow with a missing flow', function() {
- var originalConfig = [
- {id:"t1-1",x:10,y:10,z:"t1",type:"test",foo:"cn", wires:[]},
- {id:"cn",type:"test"},
- ];
- var parsedConfig = flowUtil.parseConfig(originalConfig);
- var expectedConfig = {"allNodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]},"cn":{"id":"cn","type":"test"}},"subflows":{},"configs":{"cn":{"id":"cn","type":"test","_users":["t1-1"]}},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","foo":"cn","wires":[]}}}},"groups":{},"missingTypes":[]};
- parsedConfig.should.eql(expectedConfig);
- });
-
- it('parses a flow including a group', function() {
- var originalConfig = [
- {id:"t1",type:"tab"},
- {id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
- {id:"g1",type:"group",z:"t1"}
- ];
- var parsedConfig = flowUtil.parseConfig(originalConfig);
- var expectedConfig = {"allNodes":{"t1":{"id":"t1","type":"tab"},"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]},"g1":{"id":"g1","type":"group","z":"t1"}},"subflows":{},"configs":{},"flows":{"t1":{"id":"t1","type":"tab","subflows":{},"configs":{},"nodes":{"t1-1":{"id":"t1-1","x":10,"y":10,"z":"t1","type":"test","wires":[]}}}},"groups":{"g1":{"id":"g1","type":"group","z":"t1"}},"missingTypes":[]}
- parsedConfig.should.eql(expectedConfig);
- });
-
- });
-
- describe('#diffConfigs', function() {
-
- it('handles an identical configuration', function() {
- var config = [{id:"123",type:"test",foo:"a",wires:[]}];
-
- var originalConfig = flowUtil.parseConfig(clone(config));
- var changedConfig = flowUtil.parseConfig(clone(config));
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
-
- diffResult.added.should.have.length(0);
- diffResult.changed.should.have.length(0);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.should.have.length(0);
- });
-
- 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 = clone(config);
- newConfig[0].foo = "b";
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.should.eql(["1"]);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.should.eql(["2"]);
-
- });
- 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 = clone(config);
- newConfig[1].bar = "c";
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.should.eql(["2"]);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.should.eql(["1"]);
- });
-
- it('identifies nodes with changed credentials, including downstream linked', function() {
- var config = [{id:"1",type:"test",wires:[]},{id:"2",type:"test",bar:"b",wires:[["1"]]},{id:"3",type:"test",foo:"a",wires:[]}];
- var newConfig = clone(config);
- newConfig[0].credentials = {};
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.should.eql(["1"]);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.should.eql(["2"]);
- });
-
- 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 = clone(config);
- newConfig[1].wires[0][0] = "3";
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.should.have.length(0);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.eql(["2"]);
- diffResult.linked.sort().should.eql(["1","3"]);
- });
-
- 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 = clone(config);
- newConfig[1].wires[0].push("1");
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.should.have.length(0);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.eql(["2"]);
- diffResult.linked.sort().should.eql(["1"]);
- });
-
- it('identifies nodes with changed wiring - node connected', function() {
- var config = [{id:"1",type:"test",foo:"a",wires:[["2"]]},{id:"2",type:"test",bar:"b",wires:[[]]},{id:"3",type:"test",foo:"a",wires:[]}];
- var newConfig = clone(config);
- newConfig[1].wires.push("3");
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.should.have.length(0);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.eql(["2"]);
- diffResult.linked.sort().should.eql(["1","3"]);
- });
-
- it('identifies new nodes', function() {
- var config = [{id:"1",type:"test",foo:"a",wires:[]},{id:"3",type:"test",foo:"a",wires:[]}];
- var newConfig = clone(config);
- newConfig.push({id:"2",type:"test",bar:"b",wires:[["1"]]});
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.eql(["2"]);
- diffResult.changed.should.have.length(0);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1"]);
- });
-
- 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 = clone(config);
- newConfig.splice(1,1);
- newConfig[0].wires = [];
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.should.have.length(0);
- diffResult.removed.should.eql(["2"]);
- diffResult.rewired.should.eql(["1"]);
- diffResult.linked.sort().should.eql(["3"]);
- });
-
- it('identifies config nodes changes, node->config', function() {
- var config = [
- {id:"1",type:"test",foo:"configNode",wires:[["2"]]},
- {id:"2",type:"test",bar:"b",wires:[["3"]]},
- {id:"3",type:"test",foo:"a",wires:[]},
- {id:"configNode",type:"testConfig"}
- ];
- var newConfig = clone(config);
- newConfig[3].foo = "bar";
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(["1","configNode"]);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["2","3"]);
- });
-
- it('identifies config nodes changes, node->config->config', function() {
- var config = [
- {id:"1",type:"test",foo:"configNode1",wires:[["2"]]},
- {id:"2",type:"test",bar:"b",wires:[["3"]]},
- {id:"3",type:"test",foo:"a",wires:[]},
- {id:"configNode1",foo:"configNode2",type:"testConfig"},
- {id:"configNode2",type:"testConfig"}
- ];
- var newConfig = clone(config);
- newConfig[4].foo = "bar";
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(["1","configNode1","configNode2"]);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["2","3"]);
- });
-
- it('marks a parent subflow as changed for an internal property change', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow"},
- {id:"sf1-1",z:"sf1",type:"test",foo:"a",wires:[]},
- {id:"4",type:"subflow:sf1",wires:[]}
- ];
-
- var newConfig = clone(config);
- newConfig[4].foo = "b";
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', '4', 'sf1']);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
-
-
- });
-
- it('marks a parent subflow as changed for an internal wiring change', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow"},
- {id:"sf1-1",z:"sf1",type:"test",wires:[]},
- {id:"sf1-2",z:"sf1",type:"test",wires:[]}
- ];
-
- var newConfig = clone(config);
- newConfig[4].wires = [["sf1-2"]];
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', 'sf1']);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
- });
-
- it('marks a parent subflow as changed for an internal node add', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow"},
- {id:"sf1-1",z:"sf1",type:"test",wires:[]},
- {id:"sf1-2",z:"sf1",type:"test",wires:[]}
- ];
-
- var newConfig = clone(config);
- newConfig.push({id:"sf1-3",z:"sf1",type:"test",wires:[]});
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', 'sf1']);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
-
- });
-
- it('marks a parent subflow as changed for an internal node delete', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow"},
- {id:"sf1-1",z:"sf1",type:"test",wires:[]},
- {id:"sf1-2",z:"sf1",type:"test",wires:[]}
- ];
-
- var newConfig = clone(config);
- newConfig.splice(5,1);
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', 'sf1']);
- diffResult.removed.should.have.length(1);
- diffResult.removed.sort().should.eql(['sf1-2']);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
-
- });
-
- it('marks a parent subflow as changed for an internal subflow wiring change - input removed', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow","in": [{"wires": [{"id": "sf1-1"}]}],"out": [{"wires": [{"id": "sf1-2","port": 0}]}]},
- {id:"sf1-1",z:"sf1",type:"test",wires:[]},
- {id:"sf1-2",z:"sf1",type:"test",wires:[]}
- ];
-
- var newConfig = clone(config);
- newConfig[3].in[0].wires = [];
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', 'sf1']);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
- });
-
- it('marks a parent subflow as changed for an internal subflow wiring change - input added', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow","in": [{"wires": [{"id": "sf1-1"}]}],"out": [{"wires": [{"id": "sf1-2","port": 0}]}]},
- {id:"sf1-1",z:"sf1",type:"test",wires:[]},
- {id:"sf1-2",z:"sf1",type:"test",wires:[]}
- ];
-
- var newConfig = clone(config);
- newConfig[3].in[0].wires.push({"id":"sf1-2"});
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', 'sf1']);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
- });
-
- it('marks a parent subflow as changed for an internal subflow wiring change - output added', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow","in": [{"wires": [{"id": "sf1-1"}]}],"out": [{"wires": [{"id": "sf1-2","port": 0}]}]},
- {id:"sf1-1",z:"sf1",type:"test",wires:[]},
- {id:"sf1-2",z:"sf1",type:"test",wires:[]}
- ];
-
- var newConfig = clone(config);
- newConfig[3].out[0].wires.push({"id":"sf1-2","port":0});
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', 'sf1']);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
- });
-
- it('marks a parent subflow as changed for an internal subflow wiring change - output removed', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow","in": [{"wires": [{"id": "sf1-1"}]}],"out": [{"wires": [{"id": "sf1-2","port": 0}]}]},
- {id:"sf1-1",z:"sf1",type:"test",wires:[]},
- {id:"sf1-2",z:"sf1",type:"test",wires:[]}
- ];
-
- var newConfig = clone(config);
- newConfig[3].out[0].wires = [];
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', 'sf1']);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
- });
-
- it('marks a parent subflow as changed for a global config node change', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow"},
- {id:"sf1-1",z:"sf1",prop:"configNode",type:"test",wires:[]},
- {id:"sf1-2",z:"sf1",type:"test",wires:[]},
- {id:"configNode",a:"foo",type:"test",wires:[]}
- ];
-
- var newConfig = clone(config);
- newConfig[6].a = "bar";
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', "configNode", 'sf1']);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
- });
-
- it('marks a parent subflow as changed for an internal subflow instance change', function() {
- var config = [
- {id:"1",type:"test",wires:[["2"]]},
- {id:"2",type:"subflow:sf1",wires:[["3"]]},
- {id:"3",type:"test",wires:[]},
- {id:"sf1",type:"subflow"},
- {id:"sf2",type:"subflow"},
- {id:"sf1-1",z:"sf1",type:"test",wires:[]},
- {id:"sf1-2",z:"sf1",type:"subflow:sf2",wires:[]},
- {id:"sf2-1",z:"sf2",type:"test",wires:[]},
- {id:"sf2-2",z:"sf2",type:"test",wires:[]},
- ];
-
- var newConfig = clone(config);
- newConfig[8].a = "bar";
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.sort().should.eql(['2', 'sf1', 'sf2']);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- diffResult.linked.sort().should.eql(["1","3"]);
- });
-
-
- it('ignores tab changes that are immaterial', function() {
- var config = [{id:"1",type:"tab",label:"fred"},{id:"2",type:"test",bar:"b",wires:[["1"]],z:"1"}];
- var newConfig = clone(config);
- newConfig[0].label = "barney";
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.should.have.length(0);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- });
-
-
- it('marks a deleted tab as removed', function() {
- var config = [{id:"f1",type:"tab",label:"fred"},{id:"n1",type:"test",bar:"b",wires:[["1"]],z:"f1"},
- {id:"f2",type:"tab",label:"fred"},{id:"n2",type:"test",bar:"b",wires:[["1"]],z:"f2"}];
- var newConfig = clone(config);
- newConfig = newConfig.slice(0,2);
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
- diffResult.added.should.have.length(0);
- diffResult.changed.should.have.length(0);
- diffResult.removed.sort().should.eql(['f2', 'n2']);
- diffResult.rewired.should.have.length(0);
- });
-
- it('marks all nodes as added when tab state changes disabled to enabled', function() {
- var config = [{id:"1",type:"tab",disabled:true,label:"fred"},{id:"2",type:"test",bar:"b",wires:[["1"]],z:"1"},{id:"3",type:"test"}];
- var newConfig = clone(config);
- newConfig[0].disabled = false;
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
-
- diffResult.added.should.have.length(2);
- diffResult.added.sort().should.eql(["1","2"]);
- diffResult.changed.should.have.length(0);
- diffResult.removed.should.have.length(0);
- diffResult.rewired.should.have.length(0);
- });
- it('marks all nodes as removed when tab state changes enabled to disabled', function() {
- var config = [{id:"1",type:"tab",disabled:false,label:"fred"},{id:"2",type:"test",bar:"b",wires:[["1"]],z:"1"},{id:"3",type:"test"}];
- var newConfig = clone(config);
- newConfig[0].disabled = true;
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
-
- diffResult.added.should.have.length(0);
- diffResult.changed.should.have.length(0);
- diffResult.removed.should.have.length(2);
- diffResult.removed.sort().should.eql(["1","2"]);
- diffResult.rewired.should.have.length(0);
- });
-
- it('marks a node as removed when its state changes enabled to disabled', function() {
- var config = [{id:"1",type:"tab",disabled:false,label:"fred"},{id:"2",type:"test",bar:"b",wires:[["1"]],z:"1"},{id:"3",type:"test"}];
- var newConfig = clone(config);
- newConfig[1].d = true;
-
- var originalConfig = flowUtil.parseConfig(config);
- var changedConfig = flowUtil.parseConfig(newConfig);
-
- originalConfig.missingTypes.should.have.length(0);
-
- var diffResult = flowUtil.diffConfigs(originalConfig,changedConfig);
-
- diffResult.added.should.have.length(0);
- diffResult.changed.should.have.length(2);
- diffResult.changed.sort().should.eql(["1","2"]);
- diffResult.removed.should.have.length(1);
- diffResult.removed.sort().should.eql(["2"]);
- diffResult.rewired.should.have.length(0);
- });
-
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/index_spec.js b/test/unit/@node-red/runtime/lib/index_spec.js
deleted file mode 100644
index 9041ba66e..000000000
--- a/test/unit/@node-red/runtime/lib/index_spec.js
+++ /dev/null
@@ -1,250 +0,0 @@
-/**
- * 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 path = require("path");
-
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var api = NR_TEST_UTILS.require("@node-red/runtime/lib/api");
-var runtime = NR_TEST_UTILS.require("@node-red/runtime");
-
-var redNodes = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes");
-var storage = NR_TEST_UTILS.require("@node-red/runtime/lib/storage");
-var settings = NR_TEST_UTILS.require("@node-red/runtime/lib/settings");
-var util = NR_TEST_UTILS.require("@node-red/util");
-
-var log = NR_TEST_UTILS.require("@node-red/util").log;
-var i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
-
-describe("runtime", function() {
- afterEach(function() {
- if (console.log.restore) {
- console.log.restore();
- }
- })
-
- before(function() {
- process.env.NODE_RED_HOME = NR_TEST_UTILS.resolve("node-red");
- });
- after(function() {
- delete process.env.NODE_RED_HOME;
- });
- function mockUtil(metrics) {
- sinon.stub(log,"log").callsFake(function(){})
- sinon.stub(log,"warn").callsFake(function(){})
- sinon.stub(log,"info").callsFake(function(){})
- sinon.stub(log,"trace").callsFake(function(){})
- sinon.stub(log,"metric").callsFake(function(){ return !!metrics })
- sinon.stub(log,"_").callsFake(function(){ return "abc"})
- sinon.stub(i18n,"registerMessageCatalog").callsFake(function(){ return Promise.resolve()})
- }
- function unmockUtil() {
- log.log.restore && log.log.restore();
- log.warn.restore && log.warn.restore();
- log.info.restore && log.info.restore();
- log.trace.restore && log.trace.restore();
- log.metric.restore && log.metric.restore();
- log._.restore && log._.restore();
- i18n.registerMessageCatalog.restore && i18n.registerMessageCatalog.restore();
- }
- describe("init", function() {
- beforeEach(function() {
- sinon.stub(log,"init").callsFake(function() {});
- sinon.stub(settings,"init").callsFake(function() {});
- sinon.stub(redNodes,"init").callsFake(function() {})
- mockUtil();
- });
- afterEach(function() {
- log.init.restore();
- settings.init.restore();
- redNodes.init.restore();
- unmockUtil();
- })
-
- it("initialises components", function() {
- runtime.init({testSettings: true, httpAdminRoot:"/"});
- settings.init.called.should.be.true();
- redNodes.init.called.should.be.true();
- });
-
- it("returns version", function() {
- runtime.init({testSettings: true, httpAdminRoot:"/"});
- return runtime.version().then(version => {
- /^\d+\.\d+\.\d+(-.*)?$/.test(version).should.be.true();
- });
-
-
- })
- });
-
- describe("start",function() {
- var storageInit;
- var settingsLoad;
- var redNodesInit;
- var redNodesLoad;
- var redNodesCleanModuleList;
- var redNodesGetNodeList;
- var redNodesLoadFlows;
- var redNodesStartFlows;
- var redNodesLoadContextsPlugin;
-
- beforeEach(function() {
- storageInit = sinon.stub(storage,"init").callsFake(function(settings) {return Promise.resolve();});
- redNodesInit = sinon.stub(redNodes,"init").callsFake(function() {});
- redNodesLoad = sinon.stub(redNodes,"load").callsFake(function() {return Promise.resolve()});
- redNodesCleanModuleList = sinon.stub(redNodes,"cleanModuleList").callsFake(function(){});
- redNodesLoadFlows = sinon.stub(redNodes,"loadFlows").callsFake(function() {return Promise.resolve()});
- redNodesStartFlows = sinon.stub(redNodes,"startFlows").callsFake(function() {});
- redNodesLoadContextsPlugin = sinon.stub(redNodes,"loadContextsPlugin").callsFake(function() {return Promise.resolve()});
- mockUtil();
- });
- afterEach(function() {
- storageInit.restore();
- redNodesInit.restore();
- redNodesLoad.restore();
- redNodesGetNodeList.restore();
- redNodesCleanModuleList.restore();
- redNodesLoadFlows.restore();
- redNodesStartFlows.restore();
- redNodesLoadContextsPlugin.restore();
- unmockUtil();
- });
- it("reports errored/missing modules",function(done) {
- redNodesGetNodeList = sinon.stub(redNodes,"getNodeList").callsFake(function(cb) {
- return [
- { err:"errored",name:"errName" }, // error
- { module:"module",enabled:true,loaded:false,types:["typeA","typeB"]} // missing
- ].filter(cb);
- });
- runtime.init({testSettings: true, httpAdminRoot:"/", load:function() { return Promise.resolve();}});
- // sinon.stub(console,"log");
- runtime.start().then(function() {
- // console.log.restore();
- try {
- storageInit.calledOnce.should.be.true();
- redNodesInit.calledOnce.should.be.true();
- redNodesLoad.calledOnce.should.be.true();
- redNodesLoadFlows.calledOnce.should.be.true();
-
- log.warn.calledWithMatch("Failed to register 1 node type");
- log.warn.calledWithMatch("Missing node modules");
- log.warn.calledWithMatch(" - module: typeA, typeB");
- redNodesCleanModuleList.calledOnce.should.be.true();
- done();
- } catch(err) {
- done(err);
- }
- }).catch(err=>{done(err)});
- });
- it("initiates load of missing modules",function(done) {
- redNodesGetNodeList = sinon.stub(redNodes,"getNodeList").callsFake(function(cb) {
- return [
- { err:"errored",name:"errName" }, // error
- { err:"errored",name:"errName" }, // error
- { module:"module",enabled:true,loaded:false,types:["typeA","typeB"]}, // missing
- { module:"node-red",enabled:true,loaded:false,types:["typeC","typeD"]} // missing
- ].filter(cb);
- });
- var serverInstallModule = sinon.stub(redNodes,"installModule").callsFake(function(name) { return Promise.resolve({nodes:[]});});
- runtime.init({testSettings: true, autoInstallModules:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}});
- sinon.stub(console,"log");
- runtime.start().then(function() {
- console.log.restore();
- try {
- log.warn.calledWithMatch("Failed to register 2 node types");
- log.warn.calledWithMatch("Missing node modules");
- log.warn.calledWithMatch(" - module: typeA, typeB");
- log.warn.calledWithMatch(" - node-red: typeC, typeD");
- redNodesCleanModuleList.calledOnce.should.be.false();
- serverInstallModule.calledOnce.should.be.true();
- serverInstallModule.calledWithMatch("module");
- done();
- } catch(err) {
- done(err);
- } finally {
- serverInstallModule.restore();
- }
- }).catch(err=>{done(err)});
- });
- it("reports errored modules when verbose is enabled",function(done) {
- redNodesGetNodeList = sinon.stub(redNodes,"getNodeList").callsFake(function(cb) {
- return [
- { err:"errored",name:"errName" } // error
- ].filter(cb);
- });
- runtime.init({testSettings: true, verbose:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}});
- sinon.stub(console,"log");
- runtime.start().then(function() {
- console.log.restore();
- try {
- log.warn.neverCalledWithMatch("Failed to register 1 node type");
- log.warn.calledWithMatch("[errName] errored");
- done();
- } catch(err) {
- done(err);
- }
- }).catch(err=>{done(err)});
- });
-
- it("reports runtime metrics",function(done) {
- var stopFlows = sinon.stub(redNodes,"stopFlows").callsFake(function() { return Promise.resolve();} );
- redNodesGetNodeList = sinon.stub(redNodes,"getNodeList").callsFake(function() {return []});
- unmockUtil();
- mockUtil(true);
- runtime.init(
- {testSettings: true, runtimeMetricInterval:200, httpAdminRoot:"/", load:function() { return Promise.resolve();}},
- {},
- undefined);
- // sinon.stub(console,"log");
- runtime.start().then(function() {
- // console.log.restore();
- setTimeout(function() {
- try {
- log.log.args.should.have.lengthOf(3);
- log.log.args[0][0].should.have.property("event","runtime.memory.rss");
- log.log.args[1][0].should.have.property("event","runtime.memory.heapTotal");
- log.log.args[2][0].should.have.property("event","runtime.memory.heapUsed");
- done();
- } catch(err) {
- done(err);
- } finally {
- runtime.stop();
- stopFlows.restore();
- }
- },300);
- }).catch(err=>{done(err)});
- });
-
-
- });
-
- it("stops components", function(done) {
- var stopFlows = sinon.stub(redNodes,"stopFlows").callsFake(function() { return Promise.resolve();} );
- var closeContextsPlugin = sinon.stub(redNodes,"closeContextsPlugin").callsFake(function() { return Promise.resolve();} );
- runtime.stop().then(function(){
- stopFlows.called.should.be.true();
- closeContextsPlugin.called.should.be.true();
- stopFlows.restore();
- closeContextsPlugin.restore();
- done();
- }).catch(function(err){
- stopFlows.restore();
- closeContextsPlugin.restore();
- return done(err)
- });
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/library/examples_spec.js b/test/unit/@node-red/runtime/lib/library/examples_spec.js
deleted file mode 100644
index d7f466d83..000000000
--- a/test/unit/@node-red/runtime/lib/library/examples_spec.js
+++ /dev/null
@@ -1,138 +0,0 @@
-/**
- * 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 fs = require("fs");
-
-var NR_TEST_UTILS = require("nr-test-utils");
-var examplesLibrary = NR_TEST_UTILS.require("@node-red/runtime/lib/library/examples")
-
-var mockLog = {
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc"}
-}
-
-describe("runtime/library/examples", function() {
- describe("getEntry", function() {
- before(function() {
- examplesLibrary.init({
- log: mockLog,
- storage: {
- getLibraryEntry: function(type,path) {
- return Promise.resolve({type,path});
- },
- getFlow: function(path) {
- return Promise.resolve({path});
- }
- },
- nodes: {
- getNodeExampleFlows: function() {
- return {
- "test-module": {
- f: ["abc"]
- },
- "@scope/test-module": {
- f: ["abc","throw"]
- }
-
- }
- },
- getNodeExampleFlowPath: function(module,entryPath) {
- if (module === "unknown") {
- return null;
- }
- return "/tmp/"+module+"/"+entryPath;
- }
- }
- });
- sinon.stub(fs,"readFile").callsFake(function(path,opts,callback) {
- if (path === "/tmp/test-module/abc") {
- callback(null,"Example flow result");
- } else if (path === "/tmp/@scope/test-module/abc") {
- callback(null,"Example scope flow result");
- } else if (path === "/tmp/test-module/throw") {
- throw new Error("Instant error")
- } else {
- callback(new Error("Unexpected path:"+path))
- }
- })
- });
- after(function() {
- fs.readFile.restore();
- })
-
- it ('returns a flow example entry', function(done) {
- examplesLibrary.getEntry("flows","test-module/abc").then(function(result) {
- result.should.eql("Example flow result");
- done();
- }).catch(done);
- });
-
- it ('returns a flow example listing - top level', function(done) {
- examplesLibrary.getEntry("flows","").then(function(result) {
- result.should.eql([ 'test-module', '@scope/test-module' ])
- done();
- }).catch(done);
- });
- it ('returns a flow example listing - in module', function(done) {
- examplesLibrary.getEntry("flows","test-module").then(function(result) {
- result.should.eql([{ fn: 'abc' }])
- done();
- }).catch(done);
- });
- it ('returns a flow example listing - in scoped module', function(done) {
- examplesLibrary.getEntry("flows","@scope/test-module").then(function(result) {
- result.should.eql([{ fn: 'abc' }, {fn: 'throw'}])
- done();
- }).catch(done);
- });
- it ('returns a flow example entry from scoped module', function(done) {
- examplesLibrary.getEntry("flows","@scope/test-module/abc").then(function(result) {
- result.should.eql("Example scope flow result");
- done();
- }).catch(done);
- });
- it ('returns an error for unknown flow example entry', function(done) {
- examplesLibrary.getEntry("flows","unknown/abc").then(function(result) {
- done(new Error("No error thrown"))
- }).catch(function(err) {
- err.should.have.property("code","not_found");
- done();
- });
- });
- it ('returns an error for file load error - async', function(done) {
- examplesLibrary.getEntry("flows","test-module/unknown").then(function(result) {
- done(new Error("No error thrown"))
- }).catch(function(err) {
- done();
- });
- });
- it ('returns an error for file load error - sync', function(done) {
- examplesLibrary.getEntry("flows","test-module/throw").then(function(result) {
- done(new Error("No error thrown"))
- }).catch(function(err) {
- done();
- });
- });
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/library/index_spec.js b/test/unit/@node-red/runtime/lib/library/index_spec.js
deleted file mode 100644
index 2499124c7..000000000
--- a/test/unit/@node-red/runtime/lib/library/index_spec.js
+++ /dev/null
@@ -1,199 +0,0 @@
-/**
- * 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.
- **/
-
-const should = require("should");
-const sinon = require("sinon");
-
-const NR_TEST_UTILS = require("nr-test-utils");
-const library = NR_TEST_UTILS.require("@node-red/runtime/lib/library/index")
-const localLibrary = NR_TEST_UTILS.require("@node-red/runtime/lib/library/local")
-const examplesLibrary = NR_TEST_UTILS.require("@node-red/runtime/lib/library/examples")
-const events = NR_TEST_UTILS.require("@node-red/util/lib/events")
-
-var mockLog = {
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc"}
-}
-
-
-describe("runtime/library", function() {
- before(function() {
- sinon.stub(localLibrary,"getEntry").callsFake(function(type,path) {
- return Promise.resolve({
- library: "local",
- type:type,
- path:path
- })
- });
- sinon.stub(localLibrary,"saveEntry").callsFake(function(type, path, meta, body) {
- return Promise.resolve({
- library: "local",
- type:type,
- path:path,
- meta:meta,
- body:body
- })
- });
- sinon.stub(examplesLibrary,"getEntry").callsFake(function(type,path) {
- return Promise.resolve({
- library: "_examples_",
- type:type,
- path:path
- })
- });
- });
- after(function() {
- localLibrary.getEntry.restore();
- localLibrary.saveEntry.restore();
- examplesLibrary.getEntry.restore();
- })
- describe("register", function() {
- // it("throws error for duplicate type", function() {
- // library.init({});
- // library.register("unknown","/abc");
- // should(()=>{library.register("unknown","/abc")} ).throw();
- // })
- })
-
- describe("getLibraries", function() {
- before(function() {
- library.init({});
- });
- it('returns the default and examples libraries', function() {
- const libs = library.getLibraries();
- libs.should.have.length(2);
- libs[0].should.have.property('id', 'local');
- libs[0].should.have.property('label','editor:library.types.local');
- libs[0].should.have.property("user", false);
- libs[0].should.have.property('icon', 'font-awesome/fa-hdd-o');
-
- libs[1].should.have.property('id', 'examples');
- libs[1].should.have.property('label','editor:library.types.examples');
- libs[1].should.have.property("user", false);
- libs[1].should.have.property('icon', 'font-awesome/fa-life-ring');
- libs[1].should.have.property('readOnly', true);
- libs[1].should.have.property('types', ['flows']);
- });
-
- it('returns the libraries from settings', function() {
- library.init({
- plugins: {
- getPlugin: id => { return {
- id: "test-library-plugin",
- type: "node-red-library-source",
- class: function() {}
- }
- }
- },
- settings: {
- editorTheme: {
- library: {
- sources: [
- {id: "test-plugin-id", type:"test-library-plugin"}
- ]
- }
- }
- }
- });
- let libs = library.getLibraries();
- libs.should.have.length(2);
-
- events.emit("registry:plugin-added","test-library-plugin" )
-
- libs = library.getLibraries();
- libs.should.have.length(3);
- libs[2].should.have.property('id', 'test-plugin-id');
- libs[2].should.have.property("user", false);
- });
- })
-
- describe("getEntry", function() {
- before(function() {
- library.init({});
- });
- it('throws error for unregistered type', function() {
- should(()=>{library.getEntry("local","unknown","/abc")} ).throw();
- });
- it('throws error for unknown library', function() {
- should(()=>{library.getEntry("unknown","unknown","/abc")} ).throw();
- });
-
- it('returns a registered non-flow entry', function(done) {
- library.register("test-module","test-type");
- library.getEntry("local","test-type","/abc").then(function(result) {
- result.should.have.property("library","local")
- result.should.have.property("type","test-type")
- result.should.have.property("path","/abc")
- done();
- }).catch(done);
- });
-
- it ('returns a flow entry', function(done) {
- library.getEntry("local","flows","/abc").then(function(result) {
- result.should.have.property("library","local")
- result.should.have.property("path","/abc")
- done();
- }).catch(done);
- });
-
- it ('returns a flow example entry', function(done) {
- library.getEntry("examples","flows","/test-module/abc").then(function(result) {
- result.should.have.property("library","_examples_")
- result.should.have.property("path","/test-module/abc")
- done();
- }).catch(done);
- });
- });
-
- describe("saveEntry", function() {
- before(function() {
- library.init({});
- });
- it('throws error for unknown library', function() {
- should(()=>{library.saveEntry("unknown","unknown","/abc",{id:"meta"},{id:"body"})} ).throw();
- });
- it('throws error for unregistered type', function() {
- should(()=>{library.saveEntry("local","unknown","/abc",{id:"meta"},{id:"body"})} ).throw();
- });
- it('throws error for save to readonly library', function() {
- should(()=>{library.saveEntry("_examples_","unknown","/abc",{id:"meta"},{id:"body"})} ).throw();
- });
- it('saves a flow entry', function(done) {
- library.saveEntry('local','flows','/abc',{id:"meta"},{id:"body"}).then(function(result) {
- result.should.have.property("path","/abc");
- result.should.have.property("body",{id:"body"});
- done();
- }).catch(done);
- })
- it('saves a non-flow entry', function(done) {
- library.register("test-module","test-type");
- library.saveEntry('local','test-type','/abc',{id:"meta"},{id:"body"}).then(function(result) {
- result.should.have.property("type","test-type");
- result.should.have.property("path","/abc");
- result.should.have.property("meta",{id:"meta"});
- result.should.have.property("body",{id:"body"});
- done();
- }).catch(done);
- })
-
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/library/local_spec.js b/test/unit/@node-red/runtime/lib/library/local_spec.js
deleted file mode 100644
index 965e5c87a..000000000
--- a/test/unit/@node-red/runtime/lib/library/local_spec.js
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var localLibrary = NR_TEST_UTILS.require("@node-red/runtime/lib/library/local")
-
-var mockLog = {
- log: sinon.stub(),
- debug: sinon.stub(),
- trace: sinon.stub(),
- warn: sinon.stub(),
- info: sinon.stub(),
- metric: sinon.stub(),
- audit: sinon.stub(),
- _: function() { return "abc"}
-}
-
-describe("runtime/library/local", function() {
-
- describe("getEntry", function() {
- before(function() {
- localLibrary.init({
- log: mockLog,
- storage: {
- getLibraryEntry: function(type,path) {
- return Promise.resolve({type,path});
- }
- }
- });
- });
-
- it('returns a registered non-flow entry', function(done) {
- localLibrary.getEntry("test-type","/abc").then(function(result) {
- result.should.have.property("type","test-type")
- result.should.have.property("path","/abc")
- done();
- }).catch(done);
- });
-
- it ('returns a flow entry', function(done) {
- localLibrary.getEntry("flows","/abc").then(function(result) {
- result.should.have.property("path","/abc")
- done();
- }).catch(done);
- });
- });
-
- describe("saveEntry", function() {
- before(function() {
- localLibrary.init({
- log: mockLog,
- storage: {
- saveLibraryEntry: function(type, path, meta, body) {
- return Promise.resolve({type,path,meta,body})
- }
- }
- });
- });
- it('saves a flow entry', function(done) {
- localLibrary.saveEntry('flows','/abc',{id:"meta"},{id:"body"}).then(function(result) {
- result.should.have.property("path","/abc");
- result.should.have.property("body",{id:"body"});
- done();
- }).catch(done);
- })
- it('saves a non-flow entry', function(done) {
- localLibrary.saveEntry('test-type','/abc',{id:"meta"},{id:"body"}).then(function(result) {
- result.should.have.property("type","test-type");
- result.should.have.property("path","/abc");
- result.should.have.property("meta",{id:"meta"});
- result.should.have.property("body",{id:"body"});
- done();
- }).catch(done);
- })
-
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/nodes/Node_spec.js b/test/unit/@node-red/runtime/lib/nodes/Node_spec.js
deleted file mode 100644
index 3fe676f1e..000000000
--- a/test/unit/@node-red/runtime/lib/nodes/Node_spec.js
+++ /dev/null
@@ -1,809 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var RedNode = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node");
-var Log = NR_TEST_UTILS.require("@node-red/util").log;
-var hooks = NR_TEST_UTILS.require("@node-red/util/lib/hooks");
-var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows");
-
-describe('Node', function() {
- describe('#constructor',function() {
- it('is called with an id and a type',function() {
- var n = new RedNode({id:'123',type:'abc'});
- n.should.have.property('id','123');
- n.should.have.property('type','abc');
- n.should.not.have.property('name');
- n.wires.should.be.empty();
- });
-
- it('is called with an id, a type and a name',function() {
- var n = new RedNode({id:'123',type:'abc',name:'barney'});
- n.should.have.property('id','123');
- n.should.have.property('type','abc');
- n.should.have.property('name','barney');
- n.wires.should.be.empty();
- });
-
- it('is called with an id, a type and some wires',function() {
- var n = new RedNode({id:'123',type:'abc',wires:['123','456']});
- n.should.have.property('id','123');
- n.should.have.property('type','abc');
- n.should.not.have.property('name');
- n.wires.should.have.length(2);
- });
-
- });
-
- describe('#close', function() {
- it('emits close event when closed',function(done) {
- var n = new RedNode({id:'123',type:'abc'});
- n.on('close',function() {
- done();
- });
- n.close();
- });
-
- it('returns a promise when provided a callback with a done parameter',function(testdone) {
- var n = new RedNode({id:'123',type:'abc'});
- n.on('close',function(done) {
- setTimeout(function() {
- done();
- },50);
- });
- var p = n.close();
- should.exist(p);
- p.then(function() {
- testdone();
- });
- });
- it('accepts a callback with "removed" and "done" parameters', function(testdone) {
- var n = new RedNode({id:'123',type:'abc'});
- var receivedRemoved;
- n.on('close',function(removed,done) {
- receivedRemoved = removed;
- setTimeout(function() {
- done();
- },50);
- });
- var p = n.close(true);
- should.exist(p);
- (receivedRemoved).should.be.true();
- p.then(function() {
- testdone();
- });
- })
- it('allows multiple close handlers to be registered',function(testdone) {
- var n = new RedNode({id:'123',type:'abc'});
- var callbacksClosed = 0;
- n.on('close',function(done) {
- setTimeout(function() {
- callbacksClosed++;
- done();
- },50);
- });
- n.on('close',function(done) {
- setTimeout(function() {
- callbacksClosed++;
- done();
- },75);
- });
- n.on('close',function() {
- callbacksClosed++;
- });
- var p = n.close();
- should.exist(p);
- p.then(function() {
- callbacksClosed.should.eql(3);
- testdone();
- }).catch(function(e) {
- testdone(e);
- });
- });
- });
-
-
- describe('#receive', function() {
- it('emits input event when called', function(done) {
- var n = new RedNode({id:'123',type:'abc'});
- var message = {payload:"hello world"};
- n.on('input',function(msg) {
- should.deepEqual(msg,message);
- done();
- });
- n.receive(message);
- });
-
- it('writes metric info with undefined msg', function(done){
- var n = new RedNode({id:'123',type:'abc'});
- n.on('input',function(msg) {
- (typeof msg).should.not.be.equal("undefined");
- (typeof msg._msgid).should.not.be.equal("undefined");
- done();
- });
- n.receive();
- });
-
- it('writes metric info with null msg', function(done){
- var n = new RedNode({id:'123',type:'abc'});
- n.on('input',function(msg) {
- (typeof msg).should.not.be.equal("undefined");
- (typeof msg._msgid).should.not.be.equal("undefined");
- done();
- });
- n.receive(null);
- });
-
- it('handles thrown errors', function(done) {
- var n = new RedNode({id:'123',type:'abc'});
- sinon.stub(n,"error").callsFake(function(err,msg) {});
- var message = {payload:"hello world"};
- n.on('input',function(msg) {
- throw new Error("test error");
- });
- n.receive(message);
- setTimeout(function() {
- n.error.called.should.be.true();
- n.error.firstCall.args[1].should.equal(message);
- done();
- },50);
- });
-
- it('calls parent flow handleComplete when callback provided', function(done) {
- var n = new RedNode({id:'123',type:'abc', _flow: {
- handleComplete: function(node,msg) {
- try {
- msg.should.deepEqual(message);
- done();
- } catch(err) {
- done(err);
- }
- }
- }});
-
- var message = {payload:"hello world"};
- n.on('input',function(msg, nodeSend, nodeDone) {
- nodeDone();
- });
- n.receive(message);
- });
-
- it('triggers onComplete hook when done callback provided', function(done) {
- var handleCompleteCalled = false;
- var hookCalled = false;
- var n = new RedNode({id:'123',type:'abc', _flow: {
- handleComplete: function(node,msg) {
- handleCompleteCalled = true;
- }
- }});
- var hookError;
- hooks.add("onComplete",function(completeEvent) {
- hookCalled = true;
- try {
- handleCompleteCalled.should.be.false("onComplete should be called before handleComplete")
- should.not.exist(completeEvent.error);
- completeEvent.msg.should.deepEqual(message);
- completeEvent.node.id.should.eql("123");
- completeEvent.node.node.should.equal(n);
- } catch(err) {
- hookError = err;
- }
- })
- var message = {payload:"hello world"};
- n.on('input',function(msg, nodeSend, nodeDone) {
- nodeDone();
- });
- n.receive(message);
- setTimeout(function() {
- if (hookError) {
- done(hookError);
- return
- }
- try {
- hookCalled.should.be.true("onComplete hook should be called");
- handleCompleteCalled.should.be.true("handleComplete should be called");
- done();
- } catch(err) {
- done(err);
- }
- })
- });
-
- it('triggers onComplete hook when done callback provided - with error', function(done) {
- var handleCompleteCalled = false;
- var hookCalled = false;
- var errorReported = false;
- var n = new RedNode({id:'123',type:'abc', _flow: {
- handleComplete: function(node,msg) {
- handleCompleteCalled = true;
- }
- }});
- var hookError;
- hooks.add("onComplete",function(completeEvent) {
- hookCalled = true;
- try {
- handleCompleteCalled.should.be.false("onComplete should be called before handleComplete")
- should.exist(completeEvent.error);
- completeEvent.error.toString().should.equal("Error: test error")
- completeEvent.msg.should.deepEqual(message);
- completeEvent.node.id.should.eql("123");
- completeEvent.node.node.should.equal(n);
- } catch(err) {
- hookError = err;
- }
- })
- var message = {payload:"hello world"};
- n.on('input',function(msg, nodeSend, nodeDone) {
- nodeDone(new Error("test error"));
- });
- n.error = function(err,msg) {
- errorReported = true;
- }
- n.receive(message);
- setTimeout(function() {
- if (hookError) {
- done(hookError);
- return
- }
- try {
- hookCalled.should.be.true("onComplete hook should be called");
- handleCompleteCalled.should.be.false("handleComplete should not be called");
- done();
- } catch(err) {
- done(err);
- }
- })
- });
- it('logs error if callback provides error', function(done) {
- var n = new RedNode({id:'123',type:'abc'});
- sinon.stub(n,"error").callsFake(function(err,msg) {});
-
- var message = {payload:"hello world"};
- n.on('input',function(msg, nodeSend, nodeDone) {
- nodeDone(new Error("test error"));
- setTimeout(function() {
- try {
- n.error.called.should.be.true();
- n.error.firstCall.args[0].toString().should.equal("Error: test error");
- n.error.firstCall.args[1].should.equal(message);
- done();
- } catch(err) {
- done(err);
- }
- },50);
- });
- n.receive(message);
- });
- it("triggers hooks when receiving a message", function(done) {
- var hookErrors = [];
- var messageReceived = false;
- var hooksCalled = [];
- hooks.add("onReceive", function(receiveEvent) {
- hooksCalled.push("onReceive")
- try {
- messageReceived.should.be.false("Message should not have been received before onReceive")
- receiveEvent.msg.should.be.exactly(message);
- receiveEvent.destination.id.should.equal("123")
- receiveEvent.destination.node.should.equal(n)
- } catch(err) {
- hookErrors.push(err);
- }
- })
- hooks.add("postReceive", function(receiveEvent) {
- hooksCalled.push("postReceive")
- try {
- messageReceived.should.be.true("Message should have been received before postReceive")
- receiveEvent.msg.should.be.exactly(message);
- receiveEvent.destination.id.should.equal("123")
- receiveEvent.destination.node.should.equal(n)
- } catch(err) {
- hookErrors.push(err);
- }
-
- })
- var n = new RedNode({id:'123',type:'abc'});
- var message = {payload:"hello world"};
- n.on('input',function(msg) {
- messageReceived = true;
- try {
- should.strictEqual(this,n);
- hooksCalled.should.eql(["onReceive"])
- should.deepEqual(msg,message);
- } catch(err) {
- hookErrors.push(err)
- }
- });
- n.receive(message);
- setTimeout(function() {
- hooks.clear();
- if (hookErrors.length > 0) {
- done(hookErrors[0])
- } else {
- done();
- }
- },10);
- });
- describe("errors thrown by hooks are reported", function() {
- before(function() {
- hooks.add("onReceive",function(recEvent) {
- if (recEvent.msg.payload === "trigger-onReceive") {
- throw new Error("onReceive Error")
- }
- })
- hooks.add("postReceive",function(recEvent) {
- if (recEvent.msg.payload === "trigger-postReceive") {
- throw new Error("postReceive Error")
- }
- })
- })
- after(function() {
- hooks.clear();
- })
- function testHook(hook, msgExpected, done) {
- var messageReceived = false;
- var errorReceived;
- var n = new RedNode({id:'123',type:'abc'});
- var message = {payload:"trigger-"+hook};
- n.on('input',function(msg) {
- messageReceived = true;
- });
- n.error = function (err) {
- errorReceived = err;
- }
-
- n.receive(message);
-
- setTimeout(function() {
- try {
- messageReceived.should.equal(msgExpected,`Hook ${hook} messageReceived expected ${msgExpected} actual ${messageReceived}`);
- should.exist(errorReceived);
- errorReceived.toString().should.containEql(hook)
- done()
- } catch(err) {
- done(err);
- }
- },10);
- }
- it("onReceive", function(done) { testHook("onReceive", false, done)})
- it("postReceive", function(done) { testHook("postReceive", true, done)})
- })
- });
-
- describe("hooks can halt receive", function() {
- before(function() {
- hooks.add("onReceive",function(recEvent) {
- if (recEvent.msg.payload === "trigger-onReceive") {
- return false;
- }
- })
- })
- after(function() {
- hooks.clear();
- })
-
- function testHook(hook, msgExpected, done) {
- var messageReceived = false;
- var errorReceived;
- var n = new RedNode({id:'123',type:'abc'});
- var message = {payload:"trigger-"+hook};
- n.on('input',function(msg) {
- messageReceived = true;
- });
- n.error = function (err) {
- errorReceived = err;
- }
-
- n.receive(message);
-
- setTimeout(function() {
- try {
- messageReceived.should.equal(msgExpected,`Hook ${hook} messageReceived expected ${msgExpected} actual ${messageReceived}`);
- should.not.exist(errorReceived);
- done()
- } catch(err) {
- done(err);
- }
- },10);
- }
- it("onReceive", function(done) { testHook("onReceive", false, done)})
- })
-
-
- describe('#send', function() {
-
- it('emits a single message', function(done) {
- var flow = {
- send: (sendEvents) => {
- try {
- sendEvents.should.have.length(1);
- sendEvents[0].msg.should.equal(message);
- sendEvents[0].destination.should.eql({id:"n2", node: undefined});
- sendEvents[0].source.should.eql({id:"n1", node: n1, port: 0})
- done();
- } catch(err) {
- done(err);
- }
- },
- };
- var n1 = new RedNode({_flow:flow,id:'n1',type:'abc',wires:[['n2']]});
- var message = {payload:"hello world"};
- n1.send(message);
- });
-
- it('emits a message with callback provided send', function(done) {
- var flow = {
- handleError: (node,logMessage,msg,reportingNode) => {done(logMessage)},
- handleComplete: (node,msg) => {},
- send: (sendEvents) => {
- try {
- sendEvents.should.have.length(1);
- sendEvents[0].msg.should.equal(message);
- sendEvents[0].destination.should.eql({id:"n2", node: undefined});
- sendEvents[0].source.should.eql({id:"n1", node: n1, port: 0});
- sendEvents[0].cloneMessage.should.be.false();
- done();
- } catch(err) {
- done(err);
- }
- },
- };
- var n1 = new RedNode({_flow:flow,id:'n1',type:'abc',wires:[['n2']]});
- var message = {payload:"hello world"};
- n1.on('input',function(msg,nodeSend,nodeDone) {
- nodeSend(msg);
- nodeDone();
- });
- n1.receive(message);
- });
-
- it('emits multiple messages on a single output', function(done) {
- var flow = {
- handleError: (node,logMessage,msg,reportingNode) => {done(logMessage)},
- send: (sendEvents) => {
- try {
- sendEvents.should.have.length(2);
- sendEvents[0].msg.should.equal(messages[0]);
- sendEvents[0].destination.should.eql({id:"n2", node: undefined});
- sendEvents[0].source.should.eql({id:"n1", node: n1, port: 0});
- sendEvents[0].cloneMessage.should.be.false();
-
- sendEvents[1].msg.should.equal(messages[1]);
- sendEvents[1].destination.should.eql({id:"n2", node: undefined});
- sendEvents[1].source.should.eql({id:"n1", node: n1, port: 0});
- sendEvents[1].cloneMessage.should.be.true();
-
- done();
- } catch(err) {
- done(err);
- }
- },
- };
- var n1 = new RedNode({_flow:flow,id:'n1',type:'abc',wires:[['n2']]});
-
- var messages = [
- {payload:"hello world"},
- {payload:"hello world again"}
- ];
-
- n1.send([messages]);
- });
-
- it('emits messages to multiple outputs', function(done) {
- var flow = {
- handleError: (node,logMessage,msg,reportingNode) => {done(logMessage)},
- send: (sendEvents) => {
- try {
- sendEvents.should.have.length(3);
- sendEvents[0].msg.should.equal(messages[0]);
- sendEvents[0].destination.should.eql({id:"n2", node: undefined});
- sendEvents[0].source.should.eql({id:"n1", node: n1, port: 0});
- sendEvents[0].cloneMessage.should.be.false();
- should.exist(sendEvents[0].msg._msgid);
- sendEvents[1].msg.should.equal(messages[2]);
- sendEvents[1].destination.should.eql({id:"n4", node: undefined});
- sendEvents[1].source.should.eql({id:"n1", node: n1, port: 2})
- sendEvents[1].cloneMessage.should.be.true();
- should.exist(sendEvents[1].msg._msgid);
- sendEvents[2].msg.should.equal(messages[2]);
- sendEvents[2].destination.should.eql({id:"n5", node: undefined});
- sendEvents[2].source.should.eql({id:"n1", node: n1, port: 2})
- sendEvents[2].cloneMessage.should.be.true();
- should.exist(sendEvents[2].msg._msgid);
-
- sendEvents[0].msg._msgid.should.eql(sendEvents[1].msg._msgid)
- sendEvents[1].msg._msgid.should.eql(sendEvents[2].msg._msgid)
-
- done();
- } catch(err) {
- done(err);
- }
- }
- };
- 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"},
- null,
- {payload:"hello world again"}
- ];
-
- var rcvdCount = 0;
-
- n1.send(messages);
- });
-
- it('emits no messages', function(done) {
- var flow = {
- handleError: (node,logMessage,msg,reportingNode) => {done(logMessage)},
- 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() {
- done();
- }, 200);
-
- n1.send();
- });
-
- // it('emits messages without cloning req or res', function(done) {
- // var flow = {
- // getNode: (id) => { return {'n1':n1,'n2':n2,'n3':n3}[id]},
- // send: (node,dst,msg) => { setImmediate(function() { flow.getNode(dst).receive(msg) })}
- // };
- // 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 = {};
- // var cloned = {};
- // var message = {payload: "foo", cloned: cloned, req: req, res: res};
- //
- // var rcvdCount = 0;
- //
- // // first message to be sent, so should not be cloned
- // n2.on('input',function(msg) {
- // should.deepEqual(msg, message);
- // msg.cloned.should.be.exactly(message.cloned);
- // msg.req.should.be.exactly(message.req);
- // msg.res.should.be.exactly(message.res);
- // rcvdCount += 1;
- // if (rcvdCount == 2) {
- // done();
- // }
- // });
- //
- // // second message to be sent, so should be cloned
- // // message uuids wont match since we've cloned
- // n3.on('input',function(msg) {
- // msg.payload.should.equal(message.payload);
- // msg.cloned.should.not.be.exactly(message.cloned);
- // msg.req.should.be.exactly(message.req);
- // msg.res.should.be.exactly(message.res);
- // rcvdCount += 1;
- // if (rcvdCount == 2) {
- // done();
- // }
- // });
- //
- // n1.send(message);
- // });
-
- // it("logs the uuid for all messages sent", function(done) {
- // var logHandler = {
- // msgIds:[],
- // messagesSent: 0,
- // emit: function(event, msg) {
- // if (msg.event == "node.abc.send" && msg.level == Log.METRIC) {
- // this.messagesSent++;
- // this.msgIds.push(msg.msgid);
- // (typeof msg.msgid).should.not.be.equal("undefined");
- // }
- // }
- // };
- //
- // Log.addHandler(logHandler);
- // var flow = {
- // getNode: (id) => { return {'n1':sender,'n2':receiver1,'n3':receiver2}[id]},
- // send: (node,dst,msg) => { setImmediate(function() { flow.getNode(dst).receive(msg) })}
- // };
- //
- // 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"});
- // setTimeout(function() {
- // try {
- // logHandler.messagesSent.should.equal(1);
- // should.exist(logHandler.msgIds[0])
- // Log.removeHandler(logHandler);
- // done();
- // } catch(err) {
- // Log.removeHandler(logHandler);
- // done(err);
- // }
- // },50)
- // })
- });
-
-
- describe('#log', function() {
- it('produces a log message', function(done) {
- var n = new RedNode({id:'123',type:'abc',z:'789', _flow: {log:function(msg) { loginfo = msg;}}});
- var loginfo = {};
- n.log("a log message");
- should.deepEqual({level:Log.INFO, id:n.id,
- type:n.type, msg:"a log message",z:'789'}, loginfo);
- done();
- });
- it('produces a log message with a name', function(done) {
- var n = new RedNode({id:'123', type:'abc', name:"barney", z:'789', _flow: {log:function(msg) { loginfo = msg;}}});
- var loginfo = {};
- n.log("a log message");
- should.deepEqual({level:Log.INFO, id:n.id, name: "barney",
- type:n.type, msg:"a log message",z:'789'}, loginfo);
- done();
- });
- });
-
- describe('#warn', function() {
- it('produces a warning message', function(done) {
- var n = new RedNode({id:'123',type:'abc',z:'789', _flow: {log:function(msg) { loginfo = msg;}}});
- var loginfo = {};
- n.warn("a warning");
- should.deepEqual({level:Log.WARN, id:n.id,
- type:n.type, msg:"a warning",z:'789'}, loginfo);
- done();
- });
- });
-
- describe('#error', function() {
- it('handles a null error message', function(done) {
- var flow = {
- handleError: sinon.stub(),
- log:sinon.stub()
- }
- var n = new RedNode({_flow:flow, id:'123',type:'abc',z:'789'});
- var message = {a:1};
- n.error(null,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);
-
- done();
- });
-
- it('produces an error message', function(done) {
- var flow = {
- handleError: sinon.stub(),
- log: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);
-
- 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);
-
- done();
- });
-
- });
-
- describe('#metric', function() {
- it('produces a metric message', function(done) {
- var n = new RedNode({id:'123',type:'abc'});
- var loginfo = {};
- sinon.stub(Log, 'log').callsFake(function(msg) {
- loginfo = msg;
- });
- var msg = {payload:"foo", _msgid:"987654321"};
- n.metric("test.metric",msg,"15mb");
- should.deepEqual({value:"15mb", level:Log.METRIC, nodeid:n.id,
- event:"node.abc.test.metric",msgid:"987654321"}, loginfo);
- Log.log.restore();
- done();
- });
- });
-
- describe('#metric', function() {
- it('returns metric value if eventname undefined', function(done) {
- var n = new RedNode({id:'123',type:'abc'});
- var loginfo = {};
- sinon.stub(Log, 'log').callsFake(function(msg) {
- loginfo = msg;
- });
- var msg = {payload:"foo", _msgid:"987654321"};
- var m = n.metric(undefined,msg,"15mb");
- m.should.be.a.Boolean();
- Log.log.restore();
- done();
- });
- it('returns not defined if eventname defined', function(done) {
- var n = new RedNode({id:'123',type:'abc'});
- var loginfo = {};
- sinon.stub(Log, 'log').callsFake(function(msg) {
- loginfo = msg;
- });
- var msg = {payload:"foo", _msgid:"987654321"};
- var m = n.metric("info",msg,"15mb");
- should(m).be.undefined;
- Log.log.restore();
- done();
- });
- });
-
- describe('#status', function() {
- it('publishes status', function(done) {
- var flow = {
- handleStatus: sinon.stub()
- }
- var n = new RedNode({_flow:flow,id:'123',type:'abc'});
- var status = {fill:"green",shape:"dot",text:"connected"};
-
- n.status(status);
-
- flow.handleStatus.called.should.be.true();
- flow.handleStatus.args[0][0].should.eql(n);
- flow.handleStatus.args[0][1].should.eql(status);
- done();
- });
- it('publishes status for plain string', function(done) {
- var flow = { handleStatus: sinon.stub() }
- var n = new RedNode({_flow:flow,id:'123',type:'abc'});
- n.status("text status");
- flow.handleStatus.called.should.be.true();
- flow.handleStatus.args[0][0].should.eql(n);
- flow.handleStatus.args[0][1].should.eql({text:"text status"});
- done();
- });
- it('publishes status for plain boolean', function(done) {
- var flow = { handleStatus: sinon.stub() }
- var n = new RedNode({_flow:flow,id:'123',type:'abc'});
- n.status(false);
- flow.handleStatus.called.should.be.true();
- flow.handleStatus.args[0][0].should.eql(n);
- flow.handleStatus.args[0][1].should.eql({text:"false"});
- done();
- });
- it('publishes status for plain number', function(done) {
- var flow = { handleStatus: sinon.stub() }
- var n = new RedNode({_flow:flow,id:'123',type:'abc'});
- n.status(123);
- flow.handleStatus.called.should.be.true();
- flow.handleStatus.args[0][0].should.eql(n);
- flow.handleStatus.args[0][1].should.eql({text:"123"});
- done();
- });
- });
-
-});
diff --git a/test/unit/@node-red/runtime/lib/nodes/context/index_spec.js b/test/unit/@node-red/runtime/lib/nodes/context/index_spec.js
deleted file mode 100644
index 591504e55..000000000
--- a/test/unit/@node-red/runtime/lib/nodes/context/index_spec.js
+++ /dev/null
@@ -1,1250 +0,0 @@
-/**
- * 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 path = require("path");
-var fs = require('fs-extra');
-var NR_TEST_UTILS = require("nr-test-utils");
-var Context = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/context/index");
-
-describe('context', function() {
- describe('local memory',function() {
- beforeEach(function() {
- Context.init({});
- Context.load();
- });
- afterEach(function() {
- Context.clean({allNodes:{}});
- return Context.close();
- });
- it('stores local property',function() {
- var flowContext = Context.getFlowContext("flowA")
- var context1 = Context.get("1","flowA");
- should.not.exist(context1.get("foo"));
- context1.set("foo","test");
- context1.get("foo").should.equal("test");
- });
- it('stores local property - creates parent properties',function() {
- var flowContext = Context.getFlowContext("flowA")
- var context1 = Context.get("1","flowA");
- context1.set("foo.bar","test");
- context1.get("foo").should.eql({bar:"test"});
- });
- it('deletes local property',function() {
- var flowContext = Context.getFlowContext("flowA")
- var context1 = Context.get("1","flowA");
- context1.set("foo.abc.bar1","test1");
- context1.set("foo.abc.bar2","test2");
- context1.get("foo.abc").should.eql({bar1:"test1",bar2:"test2"});
- context1.set("foo.abc.bar1",undefined);
- context1.get("foo.abc").should.eql({bar2:"test2"});
- context1.set("foo.abc",undefined);
- should.not.exist(context1.get("foo.abc"));
- context1.set("foo",undefined);
- should.not.exist(context1.get("foo"));
- });
- it('stores flow property',function() {
- var flowContext = Context.getFlowContext("flowA")
- var context1 = Context.get("1","flowA");
- should.not.exist(context1.flow.get("foo"));
- context1.flow.set("foo","test");
- context1.flow.get("foo").should.equal("test");
- });
- it('stores global property',function() {
- var flowContext = Context.getFlowContext("flowA")
- var context1 = Context.get("1","flowA");
- should.not.exist(context1.global.get("foo"));
- context1.global.set("foo","test");
- context1.global.get("foo").should.equal("test");
- });
-
- it('keeps local context local', function() {
- var flowContext = Context.getFlowContext("flowA")
- var context1 = Context.get("1","flowA");
- var context2 = Context.get("2","flowA");
-
- should.not.exist(context1.get("foo"));
- should.not.exist(context2.get("foo"));
- context1.set("foo","test");
-
- context1.get("foo").should.equal("test");
- should.not.exist(context2.get("foo"));
- });
- it('flow context accessible to all flow nodes', function() {
- var flowContext = Context.getFlowContext("flowA")
- var context1 = Context.get("1","flowA");
- var context2 = Context.get("2","flowA");
-
- should.not.exist(context1.flow.get("foo"));
- should.not.exist(context2.flow.get("foo"));
-
- context1.flow.set("foo","test");
- context1.flow.get("foo").should.equal("test");
- context2.flow.get("foo").should.equal("test");
- });
-
- it('flow context not shared to nodes on other flows', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var flowContextB = Context.getFlowContext("flowB")
- var context1 = Context.get("1","flowA");
- var context2 = Context.get("2","flowB");
-
- should.not.exist(context1.flow.get("foo"));
- should.not.exist(context2.flow.get("foo"));
-
- context1.flow.set("foo","test");
- context1.flow.get("foo").should.equal("test");
- should.not.exist(context2.flow.get("foo"));
- });
-
- it('global context shared to all nodes', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var flowContextB = Context.getFlowContext("flowB")
-
- var context1 = Context.get("1","flowA");
- var context2 = Context.get("2","flowB");
-
- should.not.exist(context1.global.get("foo"));
- should.not.exist(context2.global.get("foo"));
-
- context1.global.set("foo","test");
- context1.global.get("foo").should.equal("test");
- context2.global.get("foo").should.equal("test");
- });
-
- it('context.flow/global are not enumerable', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var context1 = Context.get("1","flowA");
- Object.keys(context1).length.should.equal(0);
- Object.keys(context1.flow).length.should.equal(0);
- Object.keys(context1.global).length.should.equal(0);
- })
-
- it('context.flow/global cannot be deleted', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var context1 = Context.get("1","flowA");
- delete context1.flow;
- should.exist(context1.flow);
- delete context1.global;
- should.exist(context1.global);
- })
-
- it('deletes context',function() {
- var flowContextA = Context.getFlowContext("flowA")
- var context = Context.get("1","flowA");
- should.not.exist(context.get("foo"));
- context.set("foo","abc");
- context.get("foo").should.equal("abc");
-
- return Context.delete("1","flowA").then(function(){
- context = Context.get("1","flowA");
- should.not.exist(context.get("foo"));
- });
- });
-
- it('deletes global context',function() {
- Context.init({functionGlobalContext: {foo:"bar"}});
- return Context.load().then(function(){
- var globalContextA = Context.get("global")
-
- globalContextA.get('foo').should.eql('bar')
- globalContextA.set("another","value");
-
- return Context.delete("global").then(function(){
- var globalContextB = Context.get("global")
- globalContextB.get('foo').should.eql('bar')
- should.not.exist(globalContextB.get("another"));
- });
- });
- });
-
- it('enumerates context keys - sync', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var context = Context.get("1","flowA");
-
- var keys = context.keys();
- keys.should.be.an.Array();
- keys.should.be.empty();
-
- context.set("foo","bar");
- keys = context.keys();
- keys.should.have.length(1);
- keys[0].should.equal("foo");
-
- context.set("abc.def","bar");
- keys = context.keys();
- keys.should.have.length(2);
- keys[1].should.equal("abc");
- });
-
- it('enumerates context keys - async', function(done) {
- var flowContextA = Context.getFlowContext("flowA")
- var context = Context.get("1","flowA");
-
- var keys = context.keys(function(err,keys) {
- keys.should.be.an.Array();
- keys.should.be.empty();
- context.set("foo","bar");
- keys = context.keys(function(err,keys) {
- keys.should.have.length(1);
- keys[0].should.equal("foo");
-
- context.set("abc.def","bar");
- keys = context.keys(function(err,keys) {
- keys.should.have.length(2);
- keys[1].should.equal("abc");
- done();
- });
- });
- });
- });
-
- it('should enumerate only context keys when GlobalContext was given - sync', function() {
- Context.init({functionGlobalContext: {foo:"bar"}});
- Context.load().then(function(){
- var flowContextA = Context.getFlowContext("flowA")
- var context = Context.get("1","flowA");
- context.global.set("foo2","bar2");
- var keys = context.global.keys();
- keys.should.have.length(2);
- keys[0].should.equal("foo");
- keys[1].should.equal("foo2");
- });
- });
-
- it('should enumerate only context keys when GlobalContext was given - async', function(done) {
- Context.init({functionGlobalContext: {foo:"bar"}});
- Context.load().then(function(){
- var flowContextA = Context.getFlowContext("flowA")
- var context = Context.get("1","flowA");
- context.global.set("foo2","bar2");
- context.global.keys(function(err,keys) {
- keys.should.have.length(2);
- keys[0].should.equal("foo");
- keys[1].should.equal("foo2");
- done();
- });
- }).catch(done);
- });
-
-
- it('returns functionGlobalContext value if store value undefined', function() {
- Context.init({functionGlobalContext: {foo:"bar"}});
- return Context.load().then(function(){
- var flowContextA = Context.getFlowContext("flowA")
- var context = Context.get("1","flowA");
- var v = context.global.get('foo');
- v.should.equal('bar');
- });
- })
-
- it('returns functionGlobalContext sub-value if store value undefined', function() {
- Context.init({functionGlobalContext: {foo:{bar:123}}});
- return Context.load().then(function(){
- var flowContextA = Context.getFlowContext("flowA")
- var context = Context.get("1","flowA");
- var v = context.global.get('foo.bar');
- should.equal(v,123);
- });
- })
-
- describe("$parent", function() {
- it('should get undefined for $parent without key', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var flowContextB = Context.getFlowContext("flowB","flowA")
- var context0 = Context.get("0","flowA");
- var context1 = Context.get("1","flowB");
- var parent = context1.get("$parent");
- should.equal(parent, undefined);
- });
-
- it('should get undefined for $parent of root', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var flowContextB = Context.getFlowContext("flowB","flowA")
- var context0 = Context.get("0","flowA");
- var context1 = Context.get("1","flowB");
- var parent = context1.flow.get("$parent.$parent.K");
- should.equal(parent, undefined);
- });
-
- it('should get undefined for $parent of root - callback', function(done) {
- var flowContextA = Context.getFlowContext("flowA")
- var flowContextB = Context.getFlowContext("flowB","flowA")
- var context0 = Context.get("0","flowA");
- var context1 = Context.get("1","flowB");
- context1.flow.get("$parent.$parent.K", function(err, result) {
- try {
- should.equal(err, undefined);
- should.equal(result, undefined);
- done();
- } catch(err) {
- done(err);
- }
- });
-
- });
-
- it('should get value in $parent', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var flowContextB = Context.getFlowContext("flowB","flowA")
- var context0 = Context.get("0","flowA");
- var context1 = Context.get("1","flowB");
- flowContextA.set("K", "v");
- var v = context1.flow.get("$parent.K");
- should.equal(v, "v");
- });
-
- it('should set value in $parent', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var flowContextB = Context.getFlowContext("flowB","flowA")
- var context0 = Context.get("0","flowA");
- var context1 = Context.get("1","flowB");
- context1.flow.set("$parent.K", "v");
- var v = flowContextA.get("K");
- should.equal(v, "v");
- });
-
- it('should not contain $parent in keys', function() {
- var flowContextA = Context.getFlowContext("flowA")
- var flowContextB = Context.getFlowContext("flowB","flowA")
- var context0 = Context.get("0","flowA");
- var context1 = Context.get("1","flowB");
- var parent = context1.get("$parent");
- flowContextA.set("K0", "v0");
- context1.set("K1", "v1");
- var keys = context1.keys();
- keys.should.have.length(1);
- keys[0].should.equal("K1");
- });
- });
-
-
- describe("clear", function() {
- it('clears all context',function() {
- Context.init({functionGlobalContext: {foo:"bar"}});
- return Context.load().then(function(){
- var globalContextA = Context.get("global")
- globalContextA.get('foo').should.eql('bar')
- globalContextA.set("another","value");
-
- var flowContextA = Context.getFlowContext("flowA")
- flowContextA.set("foo","abc");
- flowContextA.get("foo").should.equal("abc");
-
- return Context.clear().then(function(){
- var globalContextB = Context.getFlowContext("global")
- globalContextB.get('foo').should.eql('bar')
- should.not.exist(globalContextB.get("another"));
-
- flowContextA = Context.getFlowContext("flowA")
- should.not.exist(flowContextA.get("foo"))
-
- });
- });
- });
- })
- });
-
- describe('external context storage',function() {
- var resourcesDir = path.resolve(path.join(__dirname,"..","resources","context"));
- var sandbox = sinon.createSandbox();
- var stubGet = sandbox.stub();
- var stubSet = sandbox.stub();
- var stubKeys = sandbox.stub();
- var stubDelete = sandbox.stub().returns(Promise.resolve());
- var stubClean = sandbox.stub().returns(Promise.resolve());
- var stubOpen = sandbox.stub().returns(Promise.resolve());
- var stubClose = sandbox.stub().returns(Promise.resolve());
- var stubGet2 = sandbox.stub();
- var stubSet2 = sandbox.stub();
- var stubKeys2 = sandbox.stub();
- var stubDelete2 = sandbox.stub().returns(Promise.resolve());
- var stubClean2 = sandbox.stub().returns(Promise.resolve());
- var stubOpen2 = sandbox.stub().returns(Promise.resolve());
- var stubClose2 = sandbox.stub().returns(Promise.resolve());
- var testPlugin = function(config){
- function Test(){}
- Test.prototype.get = stubGet;
- Test.prototype.set = stubSet;
- Test.prototype.keys = stubKeys;
- Test.prototype.delete = stubDelete;
- Test.prototype.clean = stubClean;
- Test.prototype.open = stubOpen;
- Test.prototype.close = stubClose;
- return new Test(config);
- };
- var testPlugin2 = function(config){
- function Test2(){}
- Test2.prototype.get = stubGet2;
- Test2.prototype.set = stubSet2;
- Test2.prototype.keys = stubKeys2;
- Test2.prototype.delete = stubDelete2;
- Test2.prototype.clean = stubClean2;
- Test2.prototype.open = stubOpen2;
- Test2.prototype.close = stubClose2;
- return new Test2(config);
- };
- var contextStorage={
- test:{
- module: testPlugin,
- config:{}
- }
- };
- var contextDefaultStorage={
- default: {
- module: testPlugin2,
- config:{}
- },
- test:{
- module: testPlugin,
- config:{}
- }
- };
- var contextAlias={
- default: "test",
- test:{
- module: testPlugin,
- config:{}
- }
- };
- var memoryStorage ={
- memory:{
- module: "memory"
- }
- };
-
- afterEach(function() {
- sandbox.reset();
- return Context.clean({allNodes:{}}).then(function(){
- return Context.close();
- }).then(function(){
- return fs.remove(resourcesDir);
- });
- });
-
- describe('load modules',function(){
- it('should call open()', function() {
- Context.init({contextStorage:contextDefaultStorage});
- Context.load().then(function(){
- stubOpen.called.should.be.true();
- stubOpen2.called.should.be.true();
- });
- });
- it('should load memory module', function() {
- Context.init({contextStorage:{memory:{module:"memory"}}});
- return Context.load();
- });
- it('should load localfilesystem module', function() {
- Context.init({contextStorage:{file:{module:"localfilesystem",config:{dir:resourcesDir}}}});
- return Context.load();
- });
- it('should ignore reserved storage name `_`', function(done) {
- Context.init({contextStorage:{_:{module:testPlugin}}});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow")
- var context = Context.get("1","flow");
- var cb = function(){}
- context.set("foo","bar","_",cb);
- context.get("foo","_",cb);
- context.keys("_",cb);
- stubSet.called.should.be.false();
- stubGet.called.should.be.false();
- stubKeys.called.should.be.false();
- done();
- }).catch(done);
- });
-
- it('should fail when using invalid store name', function(done) {
- Context.init({contextStorage:{'Invalid name':{module:testPlugin}}});
- Context.load().then(function(){
- done("An error was not thrown");
- }).catch(function(){
- done();
- });
- });
- it('should fail when using invalid sign character', function (done) {
- Context.init({ contextStorage:{'abc-123':{module:testPlugin}}});
- Context.load().then(function () {
- done("An error was not thrown");
- }).catch(function () {
- done();
- });
- });
- it('should fail when using invalid default context', function(done) {
- Context.init({contextStorage:{default:"noexist"}});
- Context.load().then(function(){
- done("An error was not thrown");
- }).catch(function(){
- done();
- });
- });
- it('should fail for the storage with no module', function(done) {
- Context.init({ contextStorage: { test: {}}});
- Context.load().then(function(){
- done("An error was not thrown");
- }).catch(function(){
- done();
- });
- });
- it('should fail to load non-existent module', function(done) {
- Context.init({contextStorage:{ file:{module:"nonexistent"} }});
- Context.load().then(function(){
- done("An error was not thrown");
- }).catch(function(){
- done();
- });
- });
- it('should fail to load invalid module', function (done) {
- Context.init({contextStorage: {
- test: {
- module: function (config) {
- throw new Error("invalid plugin was loaded.");
- }
- }
- }});
- Context.load().then(function () {
- done("An error was not thrown");
- }).catch(function () {
- done();
- });
- });
- });
-
- describe('close modules',function(){
- it('should call close()', function(done) {
- Context.init({contextStorage:contextDefaultStorage});
- Context.load().then(function(){
- return Context.close().then(function(){
- stubClose.called.should.be.true();
- stubClose2.called.should.be.true();
- done();
- });
- }).catch(done);
- });
- });
-
- describe('store context',function() {
- it('should store local property to external context storage',function(done) {
- Context.init({contextStorage:contextStorage});
- var cb = function(){done("An error occurred")}
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.set("foo","bar","test",cb);
- context.get("foo","test",cb);
- context.keys("test",cb);
- stubSet.calledWithExactly("1:flow","foo","bar",cb).should.be.true();
- stubGet.calledWith("1:flow","foo").should.be.true();
- stubKeys.calledWithExactly("1:flow",cb).should.be.true();
- done();
- }).catch(done);
- });
- it('should store flow property to external context storage',function(done) {
- Context.init({contextStorage:contextStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- var cb = function(){done("An error occurred")}
- context.flow.set("foo","bar","test",cb);
- context.flow.get("foo","test",cb);
- context.flow.keys("test",cb);
- stubSet.calledWithExactly("flow","foo","bar",cb).should.be.true();
- stubGet.calledWith("flow","foo").should.be.true();
- stubKeys.calledWithExactly("flow",cb).should.be.true();
- done();
- }).catch(done);
- });
- it('should store global property to external context storage',function(done) {
- Context.init({contextStorage:contextStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- var cb = function(){done("An error occurred")}
- context.global.set("foo","bar","test",cb);
- context.global.get("foo","test",cb);
- context.global.keys("test",cb);
- stubSet.calledWithExactly("global","foo","bar",cb).should.be.true();
- stubGet.calledWith("global","foo").should.be.true();
- stubKeys.calledWith("global").should.be.true();
- done();
- }).catch(done);
- });
- it('should store data to the default context when non-existent context storage was specified', function(done) {
- Context.init({contextStorage:contextDefaultStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- var cb = function(){done("An error occurred")}
- context.set("foo","bar","nonexist",cb);
- context.get("foo","nonexist",cb);
- context.keys("nonexist",cb);
- stubGet.called.should.be.false();
- stubSet.called.should.be.false();
- stubKeys.called.should.be.false();
- stubSet2.calledWithExactly("1:flow","foo","bar",cb).should.be.true();
- stubGet2.calledWith("1:flow","foo").should.be.true();
- stubKeys2.calledWithExactly("1:flow",cb).should.be.true();
- done();
- }).catch(done);
- });
- it('should use the default context', function(done) {
- Context.init({contextStorage:contextDefaultStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- var cb = function(){done("An error occurred")}
- context.set("foo","bar","default",cb);
- context.get("foo","default",cb);
- context.keys("default",cb);
- stubGet.called.should.be.false();
- stubSet.called.should.be.false();
- stubKeys.called.should.be.false();
- stubSet2.calledWithExactly("1:flow","foo","bar",cb).should.be.true();
- stubGet2.calledWith("1:flow","foo").should.be.true();
- stubKeys2.calledWithExactly("1:flow",cb).should.be.true();
- done();
- }).catch(done);
- });
- it('should use the alias of default context', function(done) {
- Context.init({contextStorage:contextDefaultStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- var cb = function(){done("An error occurred")}
- context.set("foo","alias",cb);
- context.get("foo",cb);
- context.keys(cb);
- stubGet.called.should.be.false();
- stubSet.called.should.be.false();
- stubKeys.called.should.be.false();
- stubSet2.calledWithExactly("1:flow","foo","alias",cb).should.be.true();
- stubGet2.calledWith("1:flow","foo").should.be.true();
- stubKeys2.calledWithExactly("1:flow",cb).should.be.true();
- done();
- }).catch(done);
- });
-
- it('should allow the store name to be provide in the key', function(done) {
- Context.init({contextStorage:contextDefaultStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- var cb = function(){done("An error occurred")}
- context.set("#:(test)::foo","bar");
- context.get("#:(test)::foo");
- stubGet2.called.should.be.false();
- stubSet2.called.should.be.false();
- stubSet.calledWithExactly("1:flow","foo","bar",undefined).should.be.true();
- stubGet.calledWith("1:flow","foo").should.be.true();
- done();
- }).catch(done);
- });
-
-
- it('should use default as the alias of other context', function(done) {
- Context.init({contextStorage:contextAlias});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- var cb = function(){done("An error occurred")}
- context.set("foo","alias",cb);
- context.get("foo",cb);
- context.keys(cb);
- stubSet.calledWithExactly("1:flow","foo","alias",cb).should.be.true();
- stubGet.calledWith("1:flow","foo").should.be.true();
- stubKeys.calledWithExactly("1:flow",cb).should.be.true();
- done();
- }).catch(done);
- });
- it('should not throw an error using undefined storage for local context', function(done) {
- Context.init({contextStorage:contextStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- var cb = function(){done("An error occurred")}
- context.get("local","nonexist",cb);
- done()
- }).catch(done);
- });
- it('should throw an error using undefined storage for flow context', function(done) {
- Context.init({contextStorage:contextStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- var cb = function(){done("An error occurred")}
- context.flow.get("flow","nonexist",cb);
- done();
- }).catch(done);
- });
-
- it('should return functionGlobalContext value as a default - synchronous', function(done) {
- var fGC = { "foo": 456 };
- Context.init({contextStorage:memoryStorage, functionGlobalContext:fGC });
- Context.load().then(function() {
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- // Get foo - should be value from fGC
- var v = context.global.get("foo");
- v.should.equal(456);
-
- // Update foo - should not touch fGC object
- context.global.set("foo","new value");
- fGC.foo.should.equal(456);
-
- // Get foo - should be the updated value
- v = context.global.get("foo");
- v.should.equal("new value");
- done();
- }).catch(done);
- })
-
- it('should return functionGlobalContext value as a default - async', function(done) {
- var fGC = { "foo": 456 };
- Context.init({contextStorage:memoryStorage, functionGlobalContext:fGC });
- Context.load().then(function() {
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- // Get foo - should be value from fGC
- context.global.get("foo", function(err, v) {
- if (err) {
- done(err)
- } else {
- v.should.equal(456);
- // Update foo - should not touch fGC object
- context.global.set("foo","new value", function(err) {
- if (err) {
- done(err)
- } else {
- fGC.foo.should.equal(456);
- // Get foo - should be the updated value
- context.global.get("foo", function(err, v) {
- if (err) {
- done(err)
- } else {
- v.should.equal("new value");
- done();
- }
- });
- }
- });
- }
- });
- }).catch(done);
- })
-
- it('should return multiple values if key is an array', function(done) {
- Context.init({contextStorage:memoryStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.set("foo1","bar1","memory");
- context.set("foo2","bar2","memory");
- context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err) {
- done(err);
- } else {
- foo1.should.be.equal("bar1");
- foo2.should.be.equal("bar2");
- should.not.exist(foo3);
- done();
- }
- });
- }).catch(function(err){ done(err); });
- });
-
- it('should return multiple functionGlobalContext values if key is an array', function(done) {
- var fGC = { "foo1": 456, "foo2": {"bar":789} };
- Context.init({contextStorage:memoryStorage, functionGlobalContext:fGC });
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.global.get(["foo1","foo2.bar","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err) {
- done(err);
- } else {
- should.equal(foo1, 456);
- should.equal(foo2, 789);
- should.not.exist(foo3);
- done();
- }
- });
- }).catch(function(err){ done(err); });
- });
-
- it('should return an error if an error occurs in getting multiple store values', function(done) {
- Context.init({contextStorage:contextStorage});
- stubGet.onFirstCall().callsArgWith(2, "error2", "bar1");
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow")
- var context = Context.get("1","flow");
- context.global.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err === "error2") {
- done();
- } else {
- done("An error occurred");
- }
- });
- }).catch(function(err){ done(err); });
- });
-
- it('should return a first error if some errors occur in getting multiple store values', function(done) {
- Context.init({contextStorage:contextStorage});
- stubGet.onFirstCall().callsArgWith(2, "error1");
- stubGet.onSecondCall().callsArgWith(2, null, "bar2");
- stubGet.onThirdCall().callsArgWith(2, "error3");
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err === "error1") {
- done();
- } else {
- done("An error occurred");
- }
- });
- }).catch(function(err){ done(err); });
- });
-
- it('should store multiple properties if key and value are arrays', function(done) {
- Context.init({contextStorage:memoryStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.set(["foo1","foo2","foo3"], ["bar1","bar2","bar3"], "memory", function(err){
- if (err) {
- done(err);
- } else {
- context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err) {
- done(err);
- } else {
- foo1.should.be.equal("bar1");
- foo2.should.be.equal("bar2");
- foo3.should.be.equal("bar3");
- done();
- }
- });
- }
- });
- });
- });
-
- it('should deletes multiple properties', function(done) {
- Context.init({contextStorage:memoryStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.set(["foo1","foo2","foo3"], ["bar1","bar2","bar3"], "memory", function(err){
- if (err) {
- done(err);
- } else {
- context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err) {
- done(err);
- } else {
- foo1.should.be.equal("bar1");
- foo2.should.be.equal("bar2");
- foo3.should.be.equal("bar3");
- context.set(["foo1","foo2","foo3"], new Array(3), "memory", function(err){
- if (err) {
- done(err);
- } else {
- context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err) {
- done(err);
- } else {
- should.not.exist(foo1);
- should.not.exist(foo2);
- should.not.exist(foo3);
- done();
- }
- });
- }
- });
- }
- });
- }
- });
- });
- });
-
- it('should use null for missing values if the value array is shorter than the key array', function(done) {
- Context.init({contextStorage:memoryStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.set(["foo1","foo2","foo3"], ["bar1","bar2"], "memory", function(err){
- if (err) {
- done(err);
- } else {
- context.keys(function(err, keys){
- keys.should.have.length(3);
- keys.should.eql(["foo1","foo2","foo3"]);
- context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err) {
- done(err);
- } else {
- foo1.should.be.equal("bar1");
- foo2.should.be.equal("bar2");
- should(foo3).be.null();
- done();
- }
- });
- });
- }
- });
- });
- });
-
- it('should use null for missing values if the value is not array', function(done) {
- Context.init({contextStorage:memoryStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.set(["foo1","foo2","foo3"], "bar1", "memory", function(err){
- if (err) {
- done(err);
- } else {
- context.keys(function(err, keys){
- keys.should.have.length(3);
- keys.should.eql(["foo1","foo2","foo3"]);
- context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err) {
- done(err);
- } else {
- foo1.should.be.equal("bar1");
- should(foo2).be.null();
- should(foo3).be.null();
- done();
- }
- });
- });
- }
- });
- });
- });
-
- it('should ignore the extra values if the value array is longer than the key array', function(done) {
- Context.init({contextStorage:memoryStorage});
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.set(["foo1","foo2","foo3"], ["bar1","bar2","bar3","ignored"], "memory", function(err){
- if (err) {
- done(err);
- } else {
- context.keys(function(err, keys){
- keys.should.have.length(3);
- keys.should.eql(["foo1","foo2","foo3"]);
- context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
- if (err) {
- done(err);
- } else {
- foo1.should.be.equal("bar1");
- foo2.should.be.equal("bar2");
- foo3.should.be.equal("bar3");
- done();
- }
- });
- });
- }
- });
- });
- });
-
- it('should return an error if an error occurs in storing multiple values', function(done) {
- Context.init({contextStorage:contextStorage});
- stubSet.onFirstCall().callsArgWith(3, "error2");
- Context.load().then(function(){
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1","flow");
- context.set(["foo1","foo2","foo3"], ["bar1","bar2","bar3"], "memory", function(err){
- if (err === "error2") {
- done();
- } else {
- done("An error occurred");
- }
- });
- }).catch(function(err){ done(err); });
- });
-
- it('should throw an error if callback of context.get is not a function', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1", "flow");
- context.get("foo", "memory", "callback");
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
-
- it('should not throw an error if callback of context.get is not specified', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1", "flow");
- context.get("foo", "memory");
- done();
- }).catch(done);
- });
-
- it('should throw an error if callback of context.set is not a function', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1", "flow");
- context.set("foo", "bar", "memory", "callback");
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
-
- it('should not throw an error if callback of context.set is not specified', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1", "flow");
- context.set("foo", "bar", "memory");
- done();
- }).catch(done);
- });
-
- it('should throw an error if callback of context.keys is not a function', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1", "flow");
- context.keys("memory", "callback");
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
-
- it('should not throw an error if callback of context.keys is not specified', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var flowContext = Context.getFlowContext("flow");
- var context = Context.get("1", "flow");
- context.keys("memory");
- done();
- }).catch(done);
- });
- it('should throw an error in context.get if key is empty string', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.get("");
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.get if key is an object', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.get({});
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.get if key is a number', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.get(1);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.get if key array contains an empty string', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.get(["ok1", "", "ok2"]);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.get if key array contains an object', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.get(["ok1", {}, "ok2"]);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.get if key array contains a number', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.get(["ok1", 1, "ok2"]);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
-
- it('should throw an error in context.set if key is empty string', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.set("", 1);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.set if key is an object', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.set({}, 1);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.set if key is a number', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.set(1, 1);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.set if key array contains an empty string', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.set(["ok1", "", "ok2"], 1);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.set if key array contains an object', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.set(["ok1", {}, "ok2"], 1);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
- it('should throw an error in context.set if key array contains a number', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.set(["ok1", 1, "ok2"], 1);
- done("should throw an error.");
- }).catch(function () {
- done();
- });
- });
-
- it('should have an err set in callback for invalid key in context.get', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.get("", function(err) {
- if(err) {
- done();
- } else {
- done("should throw an error.");
- }
- });
- }).catch(done);
- });
-
- it('should have an err set in callback for invalid key in context.set', function (done) {
- Context.init({ contextStorage: memoryStorage });
- Context.load().then(function () {
- var context = Context.get("1", "flow");
- context.set("", "value", function(err) {
- if(err) {
- done();
- } else {
- done("should throw an error.");
- }
- });
- }).catch(done);
- });
- });
-
- describe('listStores', function () {
- it('should list context storages', function (done) {
- Context.init({ contextStorage: contextDefaultStorage });
- Context.load().then(function () {
- var list = Context.listStores();
- list.default.should.equal("default");
- list.stores.should.eql(["default", "test"]);
- done();
- }).catch(done);
- });
-
- it('should list context storages without default storage', function (done) {
- Context.init({ contextStorage: contextStorage });
- Context.load().then(function () {
- var list = Context.listStores();
- list.default.should.equal("test");
- list.stores.should.eql(["test"]);
- done();
- }).catch(done);
- });
- });
- describe('delete context',function(){
- it('should not call delete() when external context storage is used', function(done) {
- Context.init({contextStorage:contextDefaultStorage});
- Context.load().then(function(){
- Context.get("flowA");
- return Context.delete("flowA").then(function(){
- stubDelete.called.should.be.false();
- stubDelete2.called.should.be.false();
- done();
- });
- }).catch(done);
- });
- });
-
- describe('clean context',function(){
- it('should call clean()', function(done) {
- Context.init({contextStorage:contextDefaultStorage});
- Context.load().then(function(){
- return Context.clean({allNodes:{}}).then(function(){
- stubClean.calledWithExactly([]).should.be.true();
- stubClean2.calledWithExactly([]).should.be.true();
- done();
- });
- }).catch(done);
- });
- });
- });
-
-});
diff --git a/test/unit/@node-red/runtime/lib/nodes/context/localfilesystem_spec.js b/test/unit/@node-red/runtime/lib/nodes/context/localfilesystem_spec.js
deleted file mode 100644
index 26f9789f4..000000000
--- a/test/unit/@node-red/runtime/lib/nodes/context/localfilesystem_spec.js
+++ /dev/null
@@ -1,883 +0,0 @@
-/**
- * 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 fs = require('fs-extra');
-var path = require("path");
-var NR_TEST_UTILS = require("nr-test-utils");
-var LocalFileSystem = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/context/localfilesystem");
-
-var resourcesDir = path.resolve(path.join(__dirname,"..","resources","context"));
-
-var defaultContextBase = "context";
-
-describe('localfilesystem',function() {
-
- before(function() {
- return fs.remove(resourcesDir);
- });
-
- describe('#get/set',function() {
- var context;
- beforeEach(function() {
- context = LocalFileSystem({dir: resourcesDir, cache: false});
- return context.open();
- });
-
- afterEach(function() {
- return context.clean([]).then(function(){
- return context.close();
- }).then(function(){
- return fs.remove(resourcesDir);
- });
- });
-
- it('should store property',function(done) {
- context.get("nodeX","foo",function(err, value){
- if (err) { return done(err); }
- should.not.exist(value);
- context.set("nodeX","foo","test",function(err){
- if (err) { return done(err); }
- context.get("nodeX","foo",function(err, value){
- if (err) { return done(err); }
- value.should.be.equal("test");
- done();
- });
- });
- });
- });
-
- it('should store property - creates parent properties',function(done) {
- context.set("nodeX","foo.bar","test",function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.eql({bar:"test"});
- done();
- });
- });
- });
-
- it('should store local scope property', function (done) {
- context.set("abc:def", "foo.bar", "test", function (err) {
- context.get("abc:def", "foo", function (err, value) {
- value.should.be.eql({ bar: "test" });
- done();
- });
- });
- });
-
- it('should delete property',function(done) {
- context.set("nodeX","foo.abc.bar1","test1",function(err){
- context.set("nodeX","foo.abc.bar2","test2",function(err){
- context.get("nodeX","foo.abc",function(err, value){
- value.should.be.eql({bar1:"test1",bar2:"test2"});
- context.set("nodeX","foo.abc.bar1",undefined,function(err){
- context.get("nodeX","foo.abc",function(err, value){
- value.should.be.eql({bar2:"test2"});
- context.set("nodeX","foo.abc",undefined,function(err){
- context.get("nodeX","foo.abc",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo",undefined,function(err){
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- done();
- });
- });
- });
- });
- });
- });
- });
- });
- });
- });
-
- it('should not shared context with other scope', function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.get("nodeY","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo","testX",function(err){
- context.set("nodeY","foo","testY",function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.equal("testX");
- context.get("nodeY","foo",function(err, value){
- value.should.be.equal("testY");
- done();
- });
- });
- });
- });
- });
- });
- });
-
- it('should store string',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo","bar",function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.String();
- value.should.be.equal("bar");
- context.set("nodeX","foo","1",function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.String();
- value.should.be.equal("1");
- done();
- });
- });
- });
- });
- });
- });
-
- it('should store number',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo",1,function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.Number();
- value.should.be.equal(1);
- done();
- });
- });
- });
- });
-
- it('should store null',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo",null,function(err){
- context.get("nodeX","foo",function(err, value){
- should(value).be.null();
- done();
- });
- });
- });
- });
-
- it('should store boolean',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo",true,function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.Boolean().and.true();
- context.set("nodeX","foo",false,function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.Boolean().and.false();
- done();
- });
- });
- });
- });
- });
- });
-
- it('should store object',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo",{obj:"bar"},function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.Object();
- value.should.eql({obj:"bar"});
- done();
- });
- });
- });
- });
-
- it('should store array',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo",["a","b","c"],function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.Array();
- value.should.eql(["a","b","c"]);
- context.get("nodeX","foo[1]",function(err, value){
- value.should.be.String();
- value.should.equal("b");
- done();
- });
- });
- });
- });
- });
-
- it('should store array of arrays',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo",[["a","b","c"],[1,2,3,4],[true,false]],function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.Array();
- value.should.have.length(3);
- value[0].should.have.length(3);
- value[1].should.have.length(4);
- value[2].should.have.length(2);
- context.get("nodeX","foo[1]",function(err, value){
- value.should.be.Array();
- value.should.have.length(4);
- value.should.be.eql([1,2,3,4]);
- done();
- });
- });
- });
- });
- });
-
- it('should store array of objects',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo",[{obj:"bar1"},{obj:"bar2"},{obj:"bar3"}],function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.Array();
- value.should.have.length(3);
- value[0].should.be.Object();
- value[1].should.be.Object();
- value[2].should.be.Object();
- context.get("nodeX","foo[1]",function(err, value){
- value.should.be.Object();
- value.should.be.eql({obj:"bar2"});
- done();
- });
- });
- });
- });
- });
-
- it('should set/get multiple values', function(done) {
- context.set("nodeX",["one","two","three"],["test1","test2","test3"], function(err) {
- context.get("nodeX",["one","two"], function() {
- Array.prototype.slice.apply(arguments).should.eql([undefined,"test1","test2"])
- done();
- });
- });
- })
- it('should set/get multiple values - get unknown', function(done) {
- context.set("nodeX",["one","two","three"],["test1","test2","test3"], function(err) {
- context.get("nodeX",["one","two","unknown"], function() {
- Array.prototype.slice.apply(arguments).should.eql([undefined,"test1","test2",undefined])
- done();
- });
- });
- })
- it('should set/get multiple values - single value providd', function(done) {
- context.set("nodeX",["one","two","three"],"test1", function(err) {
- context.get("nodeX",["one","two"], function() {
- Array.prototype.slice.apply(arguments).should.eql([undefined,"test1",null])
- done();
- });
- });
- })
-
- it('should throw error if bad key included in multiple keys - get', function(done) {
- context.set("nodeX",["one","two","three"],["test1","test2","test3"], function(err) {
- context.get("nodeX",["one",".foo","three"], function(err) {
- should.exist(err);
- done();
- });
- });
- })
-
- it('should throw error if bad key included in multiple keys - set', function(done) {
- context.set("nodeX",["one",".foo","three"],["test1","test2","test3"], function(err) {
- should.exist(err);
- // Check 'one' didn't get set as a result
- context.get("nodeX","one",function(err,one) {
- should.not.exist(one);
- done();
- })
- });
- })
-
- it('should throw an error when getting a value with invalid key', function (done) {
- context.set("nodeX","foo","bar",function(err) {
- context.get("nodeX"," ",function(err,value) {
- should.exist(err);
- done();
- });
- });
- });
-
- it('should throw an error when setting a value with invalid key',function (done) {
- context.set("nodeX"," ","bar",function (err) {
- should.exist(err);
- done();
- });
- });
-
- it('should throw an error when callback of get() is not a function',function (done) {
- try {
- context.get("nodeX","foo","callback");
- done("should throw an error.");
- } catch (err) {
- done();
- }
- });
-
- it('should throw an error when callback of get() is not specified',function (done) {
- try {
- context.get("nodeX","foo");
- done("should throw an error.");
- } catch (err) {
- done();
- }
- });
-
- it('should throw an error when callback of set() is not a function',function (done) {
- try {
- context.set("nodeX","foo","bar","callback");
- done("should throw an error.");
- } catch (err) {
- done();
- }
- });
-
- it('should not throw an error when callback of set() is not specified', function (done) {
- try {
- context.set("nodeX"," ","bar");
- done();
- } catch (err) {
- done("should not throw an error.");
- }
- });
-
- it('should handle empty context file', function (done) {
- fs.outputFile(path.join(resourcesDir,defaultContextBase,"nodeX","flow.json"),"",function(){
- context.get("nodeX", "foo", function (err, value) {
- should.not.exist(value);
- context.set("nodeX", "foo", "test", function (err) {
- context.get("nodeX", "foo", function (err, value) {
- value.should.be.equal("test");
- done();
- });
- });
- });
- });
- });
-
- it('should throw an error when reading corrupt context file', function (done) {
- fs.outputFile(path.join(resourcesDir, defaultContextBase, "nodeX", "flow.json"),"{abc",function(){
- context.get("nodeX", "foo", function (err, value) {
- should.exist(err);
- done();
- });
- });
- });
- });
-
- describe('#keys',function() {
- var context;
- beforeEach(function() {
- context = LocalFileSystem({dir: resourcesDir, cache: false});
- return context.open();
- });
-
- afterEach(function() {
- return context.clean([]).then(function(){
- return context.close();
- }).then(function(){
- return fs.remove(resourcesDir);
- });
- });
-
- it('should enumerate context keys', function(done) {
- context.keys("nodeX",function(err, value){
- value.should.be.an.Array();
- value.should.be.empty();
- context.set("nodeX","foo","bar",function(err){
- context.keys("nodeX",function(err, value){
- value.should.have.length(1);
- value[0].should.equal("foo");
- context.set("nodeX","abc.def","bar",function(err){
- context.keys("nodeX",function(err, value){
- value.should.have.length(2);
- value[1].should.equal("abc");
- done();
- });
- });
- });
- });
- });
- });
-
- it('should enumerate context keys in each scopes', function(done) {
- context.keys("nodeX",function(err, value){
- value.should.be.an.Array();
- value.should.be.empty();
- context.keys("nodeY",function(err, value){
- value.should.be.an.Array();
- value.should.be.empty();
- context.set("nodeX","foo","bar",function(err){
- context.set("nodeY","hoge","piyo",function(err){
- context.keys("nodeX",function(err, value){
- value.should.have.length(1);
- value[0].should.equal("foo");
- context.keys("nodeY",function(err, value){
- value.should.have.length(1);
- value[0].should.equal("hoge");
- done();
- });
- });
- });
- });
- });
- });
- });
-
- it('should throw an error when callback of keys() is not a function', function (done) {
- try {
- context.keys("nodeX", "callback");
- done("should throw an error.");
- } catch (err) {
- done();
- }
- });
-
- it('should throw an error when callback of keys() is not specified', function (done) {
- try {
- context.keys("nodeX");
- done("should throw an error.");
- } catch (err) {
- done();
- }
- });
- });
-
- describe('#delete',function() {
- var context;
- beforeEach(function() {
- context = LocalFileSystem({dir: resourcesDir, cache: false});
- return context.open();
- });
-
- afterEach(function() {
- return context.clean([]).then(function(){
- return context.close();
- }).then(function(){
- return fs.remove(resourcesDir);
- });
- });
-
- it('should delete context',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.get("nodeY","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo","testX",function(err){
- context.set("nodeY","foo","testY",function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.be.equal("testX");
- context.get("nodeY","foo",function(err, value){
- value.should.be.equal("testY");
- context.delete("nodeX").then(function(){
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.get("nodeY","foo",function(err, value){
- value.should.be.equal("testY");
- done();
- });
- });
- }).catch(done);
- });
- });
- });
- });
- });
- });
- });
- });
-
- describe('#clean',function() {
- var context;
- var contextGet;
- var contextSet;
- beforeEach(function() {
- context = LocalFileSystem({dir: resourcesDir, cache: false});
- contextGet = function(scope,key) {
- return new Promise((res,rej) => {
- context.get(scope,key, function(err,value) {
- if (err) {
- rej(err);
- } else {
- res(value);
- }
- })
- });
- }
- contextSet = function(scope,key,value) {
- return new Promise((res,rej) => {
- context.set(scope,key,value, function(err) {
- if (err) {
- rej(err);
- } else {
- res();
- }
- })
- });
- }
- return context.open();
- });
-
- afterEach(function() {
- return context.clean([]).then(function(){
- return context.close().then(function(){
- return fs.remove(resourcesDir);
- });
- });
- });
- it('should clean unnecessary context',function(done) {
- contextSet("global","foo","testGlobal").then(function() {
- return contextSet("nodeX:flow1","foo","testX");
- }).then(function() {
- return contextSet("nodeY:flow2","foo","testY");
- }).then(function() {
- return contextGet("nodeX:flow1","foo");
- }).then(function(value) {
- value.should.be.equal("testX");
- }).then(function() {
- return contextGet("nodeY:flow2","foo");
- }).then(function(value) {
- value.should.be.equal("testY");
- }).then(function() {
- return context.clean([])
- }).then(function() {
- return contextGet("nodeX:flow1","foo");
- }).then(function(value) {
- should.not.exist(value);
- }).then(function() {
- return contextGet("nodeY:flow2","foo");
- }).then(function(value) {
- should.not.exist(value);
- }).then(function() {
- return contextGet("global","foo");
- }).then(function(value) {
- value.should.eql("testGlobal");
- }).then(done).catch(done);
- });
-
- it('should not clean active context',function(done) {
- contextSet("global","foo","testGlobal").then(function() {
- return contextSet("nodeX:flow1","foo","testX");
- }).then(function() {
- return contextSet("nodeY:flow2","foo","testY");
- }).then(function() {
- return contextGet("nodeX:flow1","foo");
- }).then(function(value) {
- value.should.be.equal("testX");
- }).then(function() {
- return contextGet("nodeY:flow2","foo");
- }).then(function(value) {
- value.should.be.equal("testY");
- }).then(function() {
- return context.clean(["flow1","nodeX"])
- }).then(function() {
- return contextGet("nodeX:flow1","foo");
- }).then(function(value) {
- value.should.be.equal("testX");
- }).then(function() {
- return contextGet("nodeY:flow2","foo");
- }).then(function(value) {
- should.not.exist(value);
- }).then(function() {
- return contextGet("global","foo");
- }).then(function(value) {
- value.should.eql("testGlobal");
- }).then(done).catch(done);
- });
- });
-
- describe('#if cache is enabled',function() {
-
- var context;
- beforeEach(function() {
- context = LocalFileSystem({dir: resourcesDir, cache: false});
- return context.open();
- });
-
- afterEach(function() {
- return context.clean([]).then(function(){
- return context.close();
- }).then(function(){
- return fs.remove(resourcesDir);
- });
- });
-
-
-
- it('should load contexts into the cache',function() {
- var globalData = {key:"global"};
- var flowData = {key:"flow"};
- var nodeData = {key:"node"};
- return Promise.all([
- fs.outputFile(path.join(resourcesDir,defaultContextBase,"global","global.json"), JSON.stringify(globalData,null,4), "utf8"),
- fs.outputFile(path.join(resourcesDir,defaultContextBase,"flow","flow.json"), JSON.stringify(flowData,null,4), "utf8"),
- fs.outputFile(path.join(resourcesDir,defaultContextBase,"flow","node.json"), JSON.stringify(nodeData,null,4), "utf8")
- ]).then(function(){
- context = LocalFileSystem({dir: resourcesDir, cache: true});
- return context.open();
- }).then(function(){
- return Promise.all([
- fs.remove(path.join(resourcesDir,defaultContextBase,"global","global.json")),
- fs.remove(path.join(resourcesDir,defaultContextBase,"flow","flow.json")),
- fs.remove(path.join(resourcesDir,defaultContextBase,"flow","node.json"))
- ]);
- }).then(function(){
- context.get("global","key").should.be.equal("global");
- context.get("flow","key").should.be.equal("flow");
- context.get("node:flow","key").should.be.equal("node");
- });
- });
-
- it('should store property to the cache',function() {
- context = LocalFileSystem({dir: resourcesDir, cache: true, flushInterval: 1});
- return context.open().then(function(){
- return new Promise(function(resolve, reject){
- context.set("global","foo","bar",function(err){
- if(err){
- reject(err);
- } else {
- fs.readJson(path.join(resourcesDir,defaultContextBase,"global","global.json")).then(function(data) {
- // File should not exist as flush hasn't happened
- reject("File global/global.json should not exist");
- }).catch(function(err) {
- setTimeout(function() {
- fs.readJson(path.join(resourcesDir,defaultContextBase,"global","global.json")).then(function(data) {
- data.should.eql({foo:'bar'});
- resolve();
- }).catch(function(err) {
- reject(err);
- });
- },1100)
- })
- }
- });
- });
- }).then(function(){
- return fs.remove(path.join(resourcesDir,defaultContextBase,"global","global.json"));
- }).then(function(){
- context.get("global","foo").should.be.equal("bar");
- })
- });
-
- it('should enumerate context keys in the cache',function() {
- var globalData = {foo:"bar"};
- return fs.outputFile(path.join(resourcesDir,defaultContextBase,"global","global.json"), JSON.stringify(globalData,null,4), "utf8").then(function(){
- context = LocalFileSystem({dir: resourcesDir, cache: true, flushInterval: 2});
- return context.open()
- }).then(function(){
- return fs.remove(path.join(resourcesDir,defaultContextBase,"global","global.json"));
- }).then(function(){
- var keys = context.keys("global");
- keys.should.have.length(1);
- keys[0].should.equal("foo");
- return new Promise(function(resolve, reject){
- context.set("global","foo2","bar2",function(err){
- if(err){
- reject(err);
- } else {
- resolve();
- }
- });
- });
- }).then(function(){
- return fs.remove(path.join(resourcesDir,defaultContextBase,"global","global.json"));
- }).then(function(){
- var keys = context.keys("global");
- keys.should.have.length(2);
- keys[1].should.equal("foo2");
- })
- });
-
- it('should delete context in the cache',function() {
- context = LocalFileSystem({dir: resourcesDir, cache: true, flushInterval: 2});
- return context.open().then(function(){
- return new Promise(function(resolve, reject){
- context.set("global","foo","bar",function(err){
- if(err){
- reject(err);
- } else {
- resolve();
- }
- });
- });
- }).then(function(){
- context.get("global","foo").should.be.equal("bar");
- return context.delete("global");
- }).then(function(){
- should.not.exist(context.get("global","foo"))
- })
- });
-
- it('should clean unnecessary context in the cache',function() {
- var flowAData = {key:"flowA"};
- var flowBData = {key:"flowB"};
- return Promise.all([
- fs.outputFile(path.join(resourcesDir,defaultContextBase,"flowA","flow.json"), JSON.stringify(flowAData,null,4), "utf8"),
- fs.outputFile(path.join(resourcesDir,defaultContextBase,"flowB","flow.json"), JSON.stringify(flowBData,null,4), "utf8")
- ]).then(function(){
- context = LocalFileSystem({dir: resourcesDir, cache: true, flushInterval: 2});
- return context.open();
- }).then(function(){
- context.get("flowA","key").should.be.equal("flowA");
- context.get("flowB","key").should.be.equal("flowB");
- return context.clean(["flowA"]);
- }).then(function(){
- context.get("flowA","key").should.be.equal("flowA");
- should.not.exist(context.get("flowB","key"));
- });
- });
- });
-
- describe('Configuration', function () {
- var context;
- beforeEach(function() {
- context = LocalFileSystem({dir: resourcesDir, cache: false});
- return context.open();
- });
-
- afterEach(function() {
- return context.clean([]).then(function(){
- return context.close();
- }).then(function(){
- return fs.remove(resourcesDir);
- });
- });
- it('should change a base directory', function (done) {
- var differentBaseContext = LocalFileSystem({
- base: "contexts2",
- dir: resourcesDir,
- cache: false
- });
- differentBaseContext.open().then(function () {
- differentBaseContext.set("node2", "foo2", "bar2", function (err) {
- differentBaseContext.get("node2", "foo2", function (err, value) {
- value.should.be.equal("bar2");
- context.get("node2", "foo2", function(err, value) {
- should.not.exist(value);
- done();
- });
- });
- });
- });
- });
-
- it('should use userDir', function (done) {
- var userDirContext = LocalFileSystem({
- base: "contexts2",
- cache: false,
- settings: {
- userDir: resourcesDir
- }
- });
- userDirContext.open().then(function () {
- userDirContext.set("node2", "foo2", "bar2", function (err) {
- userDirContext.get("node2", "foo2", function (err, value) {
- value.should.be.equal("bar2");
- context.get("node2", "foo2", function (err, value) {
- should.not.exist(value);
- done();
- });
- });
- });
- });
- });
-
- it('should use NODE_RED_HOME', function (done) {
- var oldNRH = process.env.NODE_RED_HOME;
- process.env.NODE_RED_HOME = resourcesDir;
- fs.ensureDirSync(resourcesDir);
- fs.writeFileSync(path.join(resourcesDir,".config.json"),"");
- var nrHomeContext = LocalFileSystem({
- base: "contexts2",
- cache: false
- });
- try {
- nrHomeContext.open().then(function () {
- nrHomeContext.set("node2", "foo2", "bar2", function (err) {
- nrHomeContext.get("node2", "foo2", function (err, value) {
- value.should.be.equal("bar2");
- context.get("node2", "foo2", function (err, value) {
- should.not.exist(value);
- done();
- });
- });
- });
- });
- } finally {
- process.env.NODE_RED_HOME = oldNRH;
- }
- });
-
- it('should use HOME_PATH', function (done) {
- var oldNRH = process.env.NODE_RED_HOME;
- var oldHOMEPATH = process.env.HOMEPATH;
- process.env.NODE_RED_HOME = resourcesDir;
- process.env.HOMEPATH = resourcesDir;
- var homePath = path.join(resourcesDir, ".node-red");
- fs.outputFile(path.join(homePath, ".config.json"),"",function(){
- var homeContext = LocalFileSystem({
- base: "contexts2",
- cache: false
- });
- try {
- homeContext.open().then(function () {
- homeContext.set("node2", "foo2", "bar2", function (err) {
- homeContext.get("node2", "foo2", function (err, value) {
- value.should.be.equal("bar2");
- context.get("node2", "foo2", function (err, value) {
- should.not.exist(value);
- done();
- });
- });
- });
- });
- } finally {
- process.env.NODE_RED_HOME = oldNRH;
- process.env.HOMEPATH = oldHOMEPATH;
- }
- });
- });
-
- it('should use HOME_PATH', function (done) {
- var oldNRH = process.env.NODE_RED_HOME;
- var oldHOMEPATH = process.env.HOMEPATH;
- var oldHOME = process.env.HOME;
- process.env.NODE_RED_HOME = resourcesDir;
- process.env.HOMEPATH = resourcesDir;
- process.env.HOME = resourcesDir;
- var homeContext = LocalFileSystem({
- base: "contexts2",
- cache: false
- });
- try {
- homeContext.open().then(function () {
- homeContext.set("node2", "foo2", "bar2", function (err) {
- homeContext.get("node2", "foo2", function (err, value) {
- value.should.be.equal("bar2");
- context.get("node2", "foo2", function (err, value) {
- should.not.exist(value);
- done();
- });
- });
- });
- });
- } finally {
- process.env.NODE_RED_HOME = oldNRH;
- process.env.HOMEPATH = oldHOMEPATH;
- process.env.HOME = oldHOME;
- }
- });
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/nodes/context/memory_spec.js b/test/unit/@node-red/runtime/lib/nodes/context/memory_spec.js
deleted file mode 100644
index 663ee46b7..000000000
--- a/test/unit/@node-red/runtime/lib/nodes/context/memory_spec.js
+++ /dev/null
@@ -1,321 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-
-var Memory = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/context/memory");
-
-describe('memory',function() {
- var context;
-
- beforeEach(function() {
- context = Memory({});
- return context.open();
- });
-
- afterEach(function() {
- return context.clean([]).then(function(){
- return context.close();
- });
- });
-
- describe('#get/set',function() {
- describe('sync',function() {
- it('should store property',function() {
- should.not.exist(context.get("nodeX","foo"));
- context.set("nodeX","foo","test");
- context.get("nodeX","foo").should.equal("test");
- });
-
- it('should store property - creates parent properties',function() {
- context.set("nodeX","foo.bar","test");
- context.get("nodeX","foo").should.eql({bar:"test"});
- });
-
- it('should delete property',function() {
- context.set("nodeX","foo.abc.bar1","test1");
- context.set("nodeX","foo.abc.bar2","test2");
- context.get("nodeX","foo.abc").should.eql({bar1:"test1",bar2:"test2"});
- context.set("nodeX","foo.abc.bar1",undefined);
- context.get("nodeX","foo.abc").should.eql({bar2:"test2"});
- context.set("nodeX","foo.abc",undefined);
- should.not.exist(context.get("nodeX","foo.abc"));
- context.set("nodeX","foo",undefined);
- should.not.exist(context.get("nodeX","foo"));
- });
-
- it('should not shared context with other scope', function() {
- should.not.exist(context.get("nodeX","foo"));
- should.not.exist(context.get("nodeY","foo"));
- context.set("nodeX","foo","testX");
- context.set("nodeY","foo","testY");
-
- context.get("nodeX","foo").should.equal("testX");
- context.get("nodeY","foo").should.equal("testY");
- });
-
- it('should throw the error if the error occurs', function() {
- try{
- context.set("nodeX",".foo","test");
- should.fail("Error was not thrown");
- }catch(err){
- should.exist(err);
- try{
- context.get("nodeX",".foo");
- should.fail("Error was not thrown");
- }catch(err){
- should.exist(err);
- }
- }
- });
-
- it('should get multiple values - all known', function() {
- context.set("nodeX","one","test1");
- context.set("nodeX","two","test2");
- context.set("nodeX","three","test3");
- context.set("nodeX","four","test4");
-
- var values = context.get("nodeX",["one","two","four"]);
- values.should.eql(["test1","test2","test4"])
- })
- it('should get multiple values - include unknown', function() {
- context.set("nodeX","one","test1");
- context.set("nodeX","two","test2");
- context.set("nodeX","three","test3");
- context.set("nodeX","four","test4");
-
- var values = context.get("nodeX",["one","unknown.with.multiple.levels"]);
- values.should.eql(["test1",undefined])
- })
- it('should throw error if bad key included in multiple keys', function() {
- context.set("nodeX","one","test1");
- context.set("nodeX","two","test2");
- context.set("nodeX","three","test3");
- context.set("nodeX","four","test4");
-
- try{
- var values = context.get("nodeX",["one",".foo","three"]);
- should.fail("Error was not thrown");
- }catch(err){
- should.exist(err);
- }
- })
-
-
- });
-
- describe('async',function() {
- it('should store property',function(done) {
- context.get("nodeX","foo",function(err, value){
- should.not.exist(value);
- context.set("nodeX","foo","test",function(err){
- context.get("nodeX","foo",function(err, value){
- value.should.equal("test");
- done();
- });
- });
- });
- });
-
- it('should pass the error to callback if the error occurs',function(done) {
- context.set("nodeX",".foo","test",function(err, value){
- should.exist(err);
- context.get("nodeX",".foo",function(err){
- should.exist(err);
- done();
- });
- });
- });
-
- it('should get multiple values - all known', function(done) {
- context.set("nodeX","one","test1");
- context.set("nodeX","two","test2");
- context.set("nodeX","three","test3");
- context.set("nodeX","four","test4");
-
- context.get("nodeX",["one","two","four"],function() {
- Array.prototype.slice.apply(arguments).should.eql([undefined,"test1","test2","test4"])
- done();
- });
- })
- it('should get multiple values - include unknown', function(done) {
- context.set("nodeX","one","test1");
- context.set("nodeX","two","test2");
- context.set("nodeX","three","test3");
- context.set("nodeX","four","test4");
-
- context.get("nodeX",["one","unknown"],function() {
- Array.prototype.slice.apply(arguments).should.eql([undefined,"test1",undefined])
- done();
- });
- })
- it('should throw error if bad key included in multiple keys', function(done) {
- context.set("nodeX","one","test1");
- context.set("nodeX","two","test2");
- context.set("nodeX","three","test3");
- context.set("nodeX","four","test4");
-
- context.get("nodeX",["one",".foo","three"], function(err) {
- should.exist(err);
- done();
- });
- })
- });
- });
-
- describe('#keys',function() {
- describe('sync',function() {
- it('should enumerate context keys', function() {
- var keys = context.keys("nodeX");
- keys.should.be.an.Array();
- keys.should.be.empty();
-
- context.set("nodeX","foo","bar");
- keys = context.keys("nodeX");
- keys.should.have.length(1);
- keys[0].should.equal("foo");
-
- context.set("nodeX","abc.def","bar");
- keys = context.keys("nodeX");
- keys.should.have.length(2);
- keys[1].should.equal("abc");
- });
-
- it('should enumerate context keys in each scopes', function() {
- var keysX = context.keys("nodeX");
- keysX.should.be.an.Array();
- keysX.should.be.empty();
-
- var keysY = context.keys("nodeY");
- keysY.should.be.an.Array();
- keysY.should.be.empty();
-
- context.set("nodeX","foo","bar");
- context.set("nodeY","hoge","piyo");
- keysX = context.keys("nodeX");
- keysX.should.have.length(1);
- keysX[0].should.equal("foo");
-
- keysY = context.keys("nodeY");
- keysY.should.have.length(1);
- keysY[0].should.equal("hoge");
- });
-
- it('should enumerate global context keys', function () {
- var keys = context.keys("global");
- keys.should.be.an.Array();
- keys.should.be.empty();
-
- context.set("global", "foo", "bar");
- keys = context.keys("global");
- keys.should.have.length(1);
- keys[0].should.equal("foo");
-
- context.set("global", "abc.def", "bar");
- keys = context.keys("global");
- keys.should.have.length(2);
- keys[1].should.equal("abc");
- });
-
- it('should not return specific keys as global context keys', function () {
- var keys = context.keys("global");
-
- context.set("global", "set", "bar");
- context.set("global", "get", "bar");
- context.set("global", "keys", "bar");
- keys = context.keys("global");
- keys.should.have.length(0);
- });
- });
-
- describe('async',function() {
- it('should enumerate context keys', function(done) {
- context.keys("nodeX", function(err, keys) {
- keys.should.be.an.Array();
- keys.should.be.empty();
- context.set("nodeX", "foo", "bar", function(err) {
- context.keys("nodeX", function(err, keys) {
- keys.should.have.length(1);
- keys[0].should.equal("foo");
- context.set("nodeX","abc.def","bar",function(err){
- context.keys("nodeX",function(err, keys){
- keys.should.have.length(2);
- keys[1].should.equal("abc");
- done();
- });
- });
- });
- });
- });
- });
- });
- });
-
- describe('#delete',function() {
- it('should delete context',function() {
- should.not.exist(context.get("nodeX","foo"));
- should.not.exist(context.get("nodeY","foo"));
- context.set("nodeX","foo","abc");
- context.set("nodeY","foo","abc");
- context.get("nodeX","foo").should.equal("abc");
- context.get("nodeY","foo").should.equal("abc");
-
- return context.delete("nodeX").then(function(){
- should.not.exist(context.get("nodeX","foo"));
- should.exist(context.get("nodeY","foo"));
- });
- });
- });
-
- describe('#clean',function() {
- it('should clean unnecessary context',function() {
- should.not.exist(context.get("nodeX","foo"));
- should.not.exist(context.get("nodeY","foo"));
- context.set("nodeX","foo","abc");
- context.set("nodeY","foo","abc");
- context.get("nodeX","foo").should.equal("abc");
- context.get("nodeY","foo").should.equal("abc");
-
- return context.clean([]).then(function(){
- should.not.exist(context.get("nodeX","foo"));
- should.not.exist(context.get("nodeY","foo"));
- });
- });
- it('should not clean active context',function() {
- should.not.exist(context.get("nodeX","foo"));
- should.not.exist(context.get("nodeY","foo"));
- context.set("nodeX","foo","abc");
- context.set("nodeY","foo","abc");
- context.get("nodeX","foo").should.equal("abc");
- context.get("nodeY","foo").should.equal("abc");
-
- return context.clean(["nodeX"]).then(function(){
- should.exist(context.get("nodeX","foo"));
- should.not.exist(context.get("nodeY","foo"));
- });
- });
- it('should not clean global context', function () {
- context.set("global", "foo", "abc");
- context.get("global", "foo").should.equal("abc");
-
- return context.clean(["global"]).then(function () {
- should.exist(context.get("global", "foo"));
- });
- });
- });
-
-});
diff --git a/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js b/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js
deleted file mode 100644
index 6db0b867b..000000000
--- a/test/unit/@node-red/runtime/lib/nodes/credentials_spec.js
+++ /dev/null
@@ -1,474 +0,0 @@
-/**
- * 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 util = require("util");
-
-var NR_TEST_UTILS = require("nr-test-utils");
-var index = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/index");
-var credentials = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/credentials");
-var log = NR_TEST_UTILS.require("@node-red/util").log;
-
-
-describe('red/runtime/nodes/credentials', function() {
-
- var encryptionDisabledSettings = {
- get: function(key) {
- return false;
- }
- }
-
- afterEach(function() {
- index.clearRegistry();
- });
-
- it('loads provided credentials',function() {
- credentials.init({
- log: log,
- settings: encryptionDisabledSettings
- });
-
- return credentials.load({"a":{"b":1,"c":2}}).then(function() {
- credentials.get("a").should.have.property('b',1);
- credentials.get("a").should.have.property('c',2);
- });
- });
- it('adds a new credential',function() {
- credentials.init({
- log: log,
- settings: encryptionDisabledSettings
- });
- return credentials.load({"a":{"b":1,"c":2}}).then(function() {
- credentials.dirty().should.be.false();
- should.not.exist(credentials.get("b"));
- return credentials.add("b",{"foo":"bar"}).then(function() {
- credentials.get("b").should.have.property("foo","bar");
- credentials.dirty().should.be.true();
- });
- });
- });
- it('deletes an existing credential',function() {
- credentials.init({
- log: log,
- settings: encryptionDisabledSettings
- });
- return credentials.load({"a":{"b":1,"c":2}}).then(function() {
- credentials.dirty().should.be.false();
- credentials.delete("a");
- should.not.exist(credentials.get("a"));
- credentials.dirty().should.be.true();
- });
- });
-
- it('exports the credentials, clearing dirty flag', function() {
- credentials.init({
- log: log,
- settings: encryptionDisabledSettings
- });
- var creds = {"a":{"b":1,"c":2}};
- return credentials.load(creds).then(function() {
- return credentials.add("b",{"foo":"bar"})
- }).then(function() {
- credentials.dirty().should.be.true();
- return credentials.export().then(function(exported) {
- exported.should.eql(creds);
- credentials.dirty().should.be.false();
- })
- });
- })
-
- describe("#clean",function() {
- it("removes credentials of unknown nodes",function() {
- credentials.init({
- log: log,
- settings: encryptionDisabledSettings,
- nodes: { getType: () => function(){} }
- });
- var creds = {"a":{"b":1,"c":2},"b":{"d":3}};
- return credentials.load(creds).then(function() {
- credentials.dirty().should.be.false();
- should.exist(credentials.get("a"));
- should.exist(credentials.get("b"));
- return credentials.clean([{id:"b"}]).then(function() {
- credentials.dirty().should.be.true();
- should.not.exist(credentials.get("a"));
- should.exist(credentials.get("b"));
- });
- });
- });
- it("extracts credentials of known nodes",function() {
- credentials.init({
- log: log,
- settings: encryptionDisabledSettings,
- nodes: { getType: () => function(){} }
- });
- credentials.register("testNode",{"b":"text","c":"password"})
- var creds = {"a":{"b":1,"c":2}};
- var newConfig = [{id:"a",type:"testNode",credentials:{"b":"newBValue","c":"newCValue"}}];
- return credentials.load(creds).then(function() {
- credentials.dirty().should.be.false();
- return credentials.clean(newConfig).then(function() {
- credentials.dirty().should.be.true();
- credentials.get("a").should.have.property('b',"newBValue");
- credentials.get("a").should.have.property('c',"newCValue");
- should.not.exist(newConfig[0].credentials);
- });
- });
- });
-
-
- });
-
- it('warns if a node has no credential definition', function() {
- credentials.init({
- log: log,
- settings: encryptionDisabledSettings,
- nodes: { getType: () => function(){} }
- });
- return credentials.load({}).then(function() {
- var node = {id:"node",type:"test",credentials:{
- user1:"newUser",
- password1:"newPassword"
- }};
- sinon.spy(log,"warn");
- credentials.extract(node);
- log.warn.called.should.be.true();
- should.not.exist(node.credentials);
- log.warn.restore();
- });
- })
-
- it('extract credential updates in the provided node', function(done) {
- credentials.init({
- log: log,
- settings: encryptionDisabledSettings,
- nodes: { getType: () => function(){} }
- });
- var defintion = {
- user1:{type:"text"},
- password1:{type:"password"},
- user2:{type:"text"},
- password2:{type:"password"},
- user3:{type:"text"},
- password3:{type:"password"}
-
- };
- credentials.register("test",defintion);
- var def = credentials.getDefinition("test");
- defintion.should.eql(def);
-
- credentials.load({"node":{user1:"abc",password1:"123",user2:"def",password2:"456",user3:"ghi",password3:"789"}}).then(function() {
- var node = {id:"node",type:"test",credentials:{
- // user1 unchanged
- password1:"__PWRD__",
- user2: "",
- password2:" ",
- user3:"newUser",
- password3:"newPassword"
- }};
- credentials.dirty().should.be.false();
- credentials.extract(node);
-
- node.should.not.have.a.property("credentials");
-
- credentials.dirty().should.be.true();
- var newCreds = credentials.get("node");
- newCreds.should.have.a.property("user1","abc");
- newCreds.should.have.a.property("password1","123");
- newCreds.should.not.have.a.property("user2");
- newCreds.should.not.have.a.property("password2");
- newCreds.should.have.a.property("user3","newUser");
- newCreds.should.have.a.property("password3","newPassword");
-
- done();
- });
- });
- it('extract ignores node without credentials', function(done) {
- credentials.init({
- log: log,
- settings: encryptionDisabledSettings,
- nodes: { getType: () => function(){} }
- });
- credentials.load({"node":{user1:"abc",password1:"123"}}).then(function() {
- var node = {id:"node",type:"test"};
-
- credentials.dirty().should.be.false();
- credentials.extract(node);
- credentials.dirty().should.be.false();
- done();
- });
- });
-
- describe("encryption",function() {
- var settings = {};
- var runtime = {
- log: log,
- settings: {
- get: function(key) {
- return settings[key];
- },
- set: function(key,value) {
- settings[key] = value;
- return Promise.resolve();
- },
- delete: function(key) {
- delete settings[key];
- return Promise.resolve();
- }
- },
- nodes: { getType: () => function(){} }
- }
- it('migrates to encrypted and generates default key', function(done) {
- settings = {};
- credentials.init(runtime);
- credentials.load({"node":{user1:"abc",password1:"123"}}).then(function() {
- settings.should.have.a.property("_credentialSecret");
- settings._credentialSecret.should.have.a.length(64);
- credentials.dirty().should.be.true();
- credentials.export().then(function(result) {
- result.should.have.a.property("$");
- // reset everything - but with _credentialSecret still set
- credentials.init(runtime);
- // load the freshly encrypted version
- credentials.load(result).then(function() {
- should.exist(credentials.get("node"));
- done();
- })
- });
- });
- });
- it('uses default key', function(done) {
- settings = {
- _credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a"
- };
- // {"node":{user1:"abc",password1:"123"}}
- var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
- credentials.init(runtime);
- credentials.load(cryptedFlows).then(function() {
- should.exist(credentials.get("node"));
- credentials.dirty().should.be.false();
- credentials.add("node",{user1:"def",password1:"456"});
- credentials.export().then(function(result) {
- result.should.have.a.property("$");
- // reset everything - but with _credentialSecret still set
- credentials.init(runtime);
- // load the freshly encrypted version
- credentials.load(result).then(function() {
- should.exist(credentials.get("node"));
- credentials.get("node").should.have.a.property("user1","def");
- credentials.get("node").should.have.a.property("password1","456");
- done();
- })
- });
- });
- });
- it('uses user key', function(done) {
- settings = {
- credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a"
- };
- // {"node":{user1:"abc",password1:"123"}}
- var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
- credentials.init(runtime);
- credentials.load(cryptedFlows).then(function() {
- credentials.dirty().should.be.false();
- should.exist(credentials.get("node"));
- credentials.add("node",{user1:"def",password1:"456"});
- credentials.export().then(function(result) {
- result.should.have.a.property("$");
-
- // reset everything - but with _credentialSecret still set
- credentials.init(runtime);
- // load the freshly encrypted version
- credentials.load(result).then(function() {
- should.exist(credentials.get("node"));
- credentials.get("node").should.have.a.property("user1","def");
- credentials.get("node").should.have.a.property("password1","456");
- done();
- })
- });
- });
- });
- it('uses user key - when settings are otherwise unavailable', function(done) {
- var runtime = {
- log: log,
- settings: {
- get: function(key) {
- if (key === 'credentialSecret') {
- return "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a";
- }
- throw new Error();
- },
- set: function(key,value) {
- throw new Error();
- }
- }
- }
- // {"node":{user1:"abc",password1:"123"}}
- var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
- credentials.init(runtime);
- credentials.load(cryptedFlows).then(function() {
- should.exist(credentials.get("node"));
- credentials.add("node",{user1:"def",password1:"456"});
- credentials.export().then(function(result) {
- result.should.have.a.property("$");
-
- // reset everything - but with _credentialSecret still set
- credentials.init(runtime);
- // load the freshly encrypted version
- credentials.load(result).then(function() {
- should.exist(credentials.get("node"));
- credentials.get("node").should.have.a.property("user1","def");
- credentials.get("node").should.have.a.property("password1","456");
- done();
- })
- });
- });
- });
- it('migrates from default key to user key', function() {
- settings = {
- _credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a",
- credentialSecret: "aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbcccccccccccccddddddddddddeeeee"
- };
- // {"node":{user1:"abc",password1:"123"}}
- var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
- credentials.init(runtime);
- return credentials.load(cryptedFlows).then(function() {
- credentials.dirty().should.be.true();
- should.exist(credentials.get("node"));
- return credentials.export().then(function(result) {
- result.should.have.a.property("$");
- settings.should.not.have.a.property("_credentialSecret");
-
- // reset everything - but with _credentialSecret still set
- credentials.init(runtime);
- // load the freshly encrypted version
- return credentials.load(result).then(function() {
- should.exist(credentials.get("node"));
- credentials.get("node").should.have.a.property("user1","abc");
- credentials.get("node").should.have.a.property("password1","123");
- })
- });
- });
- });
-
- it('migrates from default key to user key - unencrypted original', function(done) {
- settings = {
- _credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a",
- credentialSecret: "aaaaaaaaaaaaaaaaabbbbbbbbbbbbbbbbbcccccccccccccddddddddddddeeeee"
- };
- // {"node":{user1:"abc",password1:"123"}}
- var unencryptedFlows = {"node":{user1:"abc",password1:"123"}};
- credentials.init(runtime);
- credentials.load(unencryptedFlows).then(function() {
- credentials.dirty().should.be.true();
- should.exist(credentials.get("node"));
- credentials.export().then(function(result) {
- result.should.have.a.property("$");
- settings.should.not.have.a.property("_credentialSecret");
-
- // reset everything - but with _credentialSecret still set
- credentials.init(runtime);
- // load the freshly encrypted version
- credentials.load(result).then(function() {
- should.exist(credentials.get("node"));
- credentials.get("node").should.have.a.property("user1","abc");
- credentials.get("node").should.have.a.property("password1","123");
- done();
- })
- });
- });
- });
-
- it('migrates from default key to unencrypted', function(done) {
- settings = {
- _credentialSecret: "e3a36f47f005bf2aaa51ce3fc6fcaafd79da8d03f2b1a9281f8fb0a285e6255a",
- credentialSecret: false
- };
- // {"node":{user1:"abc",password1:"123"}}
- var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
- credentials.init(runtime);
- credentials.load(cryptedFlows).then(function() {
- credentials.dirty().should.be.true();
- should.exist(credentials.get("node"));
- credentials.export().then(function(result) {
- result.should.not.have.a.property("$");
- settings.should.not.have.a.property("_credentialSecret");
- result.should.eql({"node":{user1:"abc",password1:"123"}});
- done();
- });
- });
- });
- it('handles bad default key - resets credentials', function(done) {
- settings = {
- _credentialSecret: "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadb"
- };
- // {"node":{user1:"abc",password1:"123"}}
- var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
- credentials.init(runtime);
- credentials.load(cryptedFlows).then(function() {
- // credentials.dirty().should.be.true();
- // should.not.exist(credentials.get("node"));
- done();
- }).catch(function(err) {
- err.should.have.property('code','credentials_load_failed');
- done();
- });
- });
- it('handles bad user key - resets credentials', function(done) {
- settings = {
- credentialSecret: "badbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadbadb"
- };
- // {"node":{user1:"abc",password1:"123"}}
- var cryptedFlows = {"$":"5b89d8209b5158a3c313675561b1a5b5phN1gDBe81Zv98KqS/hVDmc9EKvaKqRIvcyXYvBlFNzzzJtvN7qfw06i"};
- credentials.init(runtime);
- credentials.load(cryptedFlows).then(function() {
- // credentials.dirty().should.be.true();
- // should.not.exist(credentials.get("node"));
- done();
- }).catch(function(err) {
- err.should.have.property('code','credentials_load_failed');
- done();
- });
- });
-
- it('handles unavailable settings - leaves creds unencrypted', function(done) {
- var runtime = {
- log: log,
- settings: {
- get: function(key) {
- throw new Error();
- },
- set: function(key,value) {
- throw new Error();
- }
- },
- nodes: { getType: () => function(){} }
- }
- // {"node":{user1:"abc",password1:"123"}}
- credentials.init(runtime);
- credentials.load({"node":{user1:"abc",password1:"123"}}).then(function() {
- credentials.dirty().should.be.false();
- should.exist(credentials.get("node"));
- credentials.export().then(function(result) {
- result.should.not.have.a.property("$");
- result.should.have.a.property("node");
- done();
- });
- });
- });
- })
-})
diff --git a/test/unit/@node-red/runtime/lib/nodes/index_spec.js b/test/unit/@node-red/runtime/lib/nodes/index_spec.js
deleted file mode 100644
index d6017db45..000000000
--- a/test/unit/@node-red/runtime/lib/nodes/index_spec.js
+++ /dev/null
@@ -1,404 +0,0 @@
-/**
- * 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 fs = require('fs-extra');
-var path = require('path');
-var sinon = require('sinon');
-var inherits = require("util").inherits;
-
-var NR_TEST_UTILS = require("nr-test-utils");
-var index = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/index");
-var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows");
-var registry = NR_TEST_UTILS.require("@node-red/registry")
-var Node = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node");
-
-describe("red/nodes/index", function() {
- before(function() {
- sinon.stub(index,"startFlows");
- process.env.NODE_RED_HOME = NR_TEST_UTILS.resolve("node-red");
- process.env.foo="bar";
- });
- after(function() {
- index.startFlows.restore();
- delete process.env.NODE_RED_HOME;
- delete process.env.foo;
- });
-
- afterEach(function() {
- index.clearRegistry();
- });
-
- var testFlows = [{"type":"test","id":"tab1","label":"Sheet 1"}];
- var testCredentials = {"tab1":{"b":1, "c":"2", "d":"$(foo)"}};
- var storage = {
- getFlows: function() {
- return Promise.resolve({red:123,flows:testFlows,credentials:testCredentials});
- },
- saveFlows: function(conf) {
- should.deepEqual(testFlows, conf.flows);
- return Promise.resolve(123);
- }
- };
-
- var settings = {
- available: function() { return false },
- get: function() { return false }
- };
-
- var EventEmitter = require('events').EventEmitter;
- var runtime = {
- settings: settings,
- storage: storage,
- log: {debug:function() {}, warn:function() {}},
- events: new EventEmitter()
- };
-
- function TestNode(n) {
- this._flow = {getSetting: p => process.env[p]};
- index.createNode(this, n);
- this.on("log", function() {
- // do nothing
- });
- }
-
- it('nodes are initialised with credentials',function(done) {
- index.init(runtime);
- index.registerType('test-node-set','test', TestNode);
- index.loadFlows().then(function() {
- var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});
- testnode.credentials.should.have.property('b',1);
- testnode.credentials.should.have.property('c',"2");
- testnode.credentials.should.have.property('d',"bar");
- done();
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('flows should be initialised',function(done) {
- index.init(runtime);
- index.loadFlows().then(function() {
- // console.log(testFlows);
- // console.log(index.getFlows());
- should.deepEqual(testFlows, index.getFlows().flows);
- done();
- }).catch(function(err) {
- done(err);
- });
-
- });
- describe("registerType", function() {
- describe("logs deprecated usage", function() {
- before(function() {
- sinon.stub(registry,"registerType");
- });
- after(function() {
- registry.registerType.restore();
- });
- it("called without node-set name", function() {
- var runtime = {
- settings: settings,
- storage: storage,
- log: {debug:function() {}, warn:sinon.spy()},
- events: new EventEmitter()
- }
- index.init(runtime);
-
- index.registerType(/*'test-node-set',*/'test', TestNode, {});
- runtime.log.warn.called.should.be.true();
- registry.registerType.called.should.be.true();
- registry.registerType.firstCall.args[0].should.eql('');
- registry.registerType.firstCall.args[1].should.eql('test');
- registry.registerType.firstCall.args[2].should.eql(TestNode);
- });
- });
- describe("extends constructor with Node constructor", function() {
- var TestNodeConstructor;
- before(function() {
- sinon.stub(registry,"registerType");
- });
- after(function() {
- registry.registerType.restore();
- });
- beforeEach(function() {
- TestNodeConstructor = function TestNodeConstructor() {};
- var runtime = {
- settings: settings,
- storage: storage,
- log: {debug:function() {}, warn:sinon.spy()},
- events: new EventEmitter()
- }
- index.init(runtime);
- })
- it('extends a constructor with the Node constructor', function() {
- TestNodeConstructor.prototype.should.not.be.an.instanceOf(Node);
- index.registerType('node-set','node-type',TestNodeConstructor);
- TestNodeConstructor.prototype.should.be.an.instanceOf(Node);
- });
- it('does not override a constructor prototype', function() {
- function Foo(){};
- inherits(TestNodeConstructor,Foo);
- TestNodeConstructor.prototype.should.be.an.instanceOf(Foo);
- TestNodeConstructor.prototype.should.not.be.an.instanceOf(Node);
-
- index.registerType('node-set','node-type',TestNodeConstructor);
-
- TestNodeConstructor.prototype.should.be.an.instanceOf(Node);
- TestNodeConstructor.prototype.should.be.an.instanceOf(Foo);
-
- index.registerType('node-set','node-type2',TestNodeConstructor);
- TestNodeConstructor.prototype.should.be.an.instanceOf(Node);
- TestNodeConstructor.prototype.should.be.an.instanceOf(Foo);
- });
- });
- describe("register credentials definition", function() {
- var http = require('http');
- var express = require('express');
- var app = express();
- var runtime = NR_TEST_UTILS.require("@node-red/runtime");
- var credentials = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/credentials");
- var localfilesystem = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem");
- var log = NR_TEST_UTILS.require("@node-red/util").log;
- var RED = NR_TEST_UTILS.require("node-red/lib/red.js");
-
- var userDir = path.join(__dirname,".testUserHome");
- before(function(done) {
- sinon.stub(log,"log").callsFake(function(){});
- fs.remove(userDir,function(err) {
- fs.mkdir(userDir,function() {
- sinon.stub(index, 'load').callsFake(function() {
- return new Promise(function(resolve,reject){
- resolve([]);
- });
- });
- sinon.stub(localfilesystem, 'getCredentials').callsFake(function() {
- return new Promise(function(resolve,reject) {
- resolve({"tab1":{"b":1,"c":2}});
- });
- }) ;
- RED.init(http.createServer(function(req,res){app(req,res)}),
- {userDir: userDir});
- runtime.start().then(function () {
- done();
- });
- });
- });
- });
-
- after(function(done) {
- fs.remove(userDir,function() {
- runtime.stop().then(function() {
- index.load.restore();
- localfilesystem.getCredentials.restore();
- log.log.restore();
- done();
- });
- });
- });
-
- it('definition defined',function() {
- index.registerType('test-node-set','test', TestNode, {
- credentials: {
- foo: {type:"test"}
- }
- });
- var testnode = new TestNode({id:'tab1',type:'test',name:'barney', '_alias':'tab1'});
- index.getCredentialDefinition("test").should.have.property('foo');
- });
- });
-
- describe("register settings definition", function() {
- beforeEach(function() {
- sinon.stub(registry,"registerType");
- })
- afterEach(function() {
- registry.registerType.restore();
- })
- it('registers valid settings',function() {
- var runtime = {
- settings: settings,
- storage: storage,
- log: {debug:function() {}, warn:function() {}},
- events: new EventEmitter()
- }
- runtime.settings.registerNodeSettings = sinon.spy();
- index.init(runtime);
-
- index.registerType('test-node-set','test', TestNode, {
- settings: {
- testOne: {}
- }
- });
- runtime.settings.registerNodeSettings.called.should.be.true();
- runtime.settings.registerNodeSettings.firstCall.args[0].should.eql('test');
- runtime.settings.registerNodeSettings.firstCall.args[1].should.eql({testOne: {}});
- });
- it('logs invalid settings',function() {
- var runtime = {
- settings: settings,
- storage: storage,
- log: {debug:function() {}, warn:sinon.spy()},
- events: new EventEmitter()
- }
- runtime.settings.registerNodeSettings = function() { throw new Error("pass");}
- index.init(runtime);
-
- index.registerType('test-node-set','test', TestNode, {
- settings: {
- testOne: {}
- }
- });
- runtime.log.warn.called.should.be.true();
- });
- });
- });
-
- describe('allows nodes to be added/removed/enabled/disabled from the registry', function() {
- var randomNodeInfo = {id:"5678",types:["random"]};
-
- beforeEach(function() {
- sinon.stub(registry,"getNodeInfo").callsFake(function(id) {
- if (id == "test") {
- return {id:"1234",types:["test"]};
- } else if (id == "doesnotexist") {
- return null;
- } else {
- return randomNodeInfo;
- }
- });
- sinon.stub(registry,"disableNode").callsFake(function(id) {
- return Promise.resolve(randomNodeInfo);
- });
- });
- afterEach(function() {
- registry.getNodeInfo.restore();
- registry.disableNode.restore();
- });
-
- it('allows an unused node type to be disabled',function(done) {
- index.init(runtime);
- index.registerType('test-node-set','test', TestNode);
- index.loadFlows().then(function() {
- return index.disableNode("5678").then(function(info) {
- registry.disableNode.calledOnce.should.be.true();
- registry.disableNode.calledWith("5678").should.be.true();
- info.should.eql(randomNodeInfo);
- done();
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('prevents disabling a node type that is in use',function(done) {
- index.init(runtime);
- index.registerType('test-node-set','test', TestNode);
- index.loadFlows().then(function() {
- /*jshint immed: false */
- (function() {
- index.disabledNode("test");
- }).should.throw();
-
- done();
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('prevents disabling a node type that is unknown',function(done) {
- index.init(runtime);
- index.registerType('test-node-set','test', TestNode);
- index.loadFlows().then(function() {
- /*jshint immed: false */
- (function() {
- index.disableNode("doesnotexist");
- }).should.throw();
-
- done();
- }).catch(function(err) {
- done(err);
- });
- });
- });
-
- describe('allows modules to be removed from the registry', function() {
- var randomNodeInfo = {id:"5678",types:["random"]};
- var randomModuleInfo = {
- name:"random",
- nodes: [randomNodeInfo]
- };
-
- before(function() {
- sinon.stub(registry,"getNodeInfo").callsFake(function(id) {
- if (id == "node-red/foo") {
- return {id:"1234",types:["test"]};
- } else if (id == "doesnotexist") {
- return null;
- } else {
- return randomNodeInfo;
- }
- });
- sinon.stub(registry,"getModuleInfo").callsFake(function(module) {
- if (module == "node-red") {
- return {nodes:[{name:"foo"}]};
- } else if (module == "doesnotexist") {
- return null;
- } else {
- return randomModuleInfo;
- }
- });
- sinon.stub(registry,"removeModule").callsFake(function(id) {
- return randomModuleInfo;
- });
- });
- after(function() {
- registry.getNodeInfo.restore();
- registry.getModuleInfo.restore();
- registry.removeModule.restore();
- });
-
- it('prevents removing a module that is in use',function(done) {
- index.init(runtime);
- index.registerType('test-node-set','test', TestNode);
- index.loadFlows().then(function() {
- /*jshint immed: false */
- (function() {
- index.removeModule("node-red");
- }).should.throw();
-
- done();
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('prevents removing a module that is unknown',function(done) {
- index.init(runtime);
- index.registerType('test-node-set','test', TestNode);
- index.loadFlows().then(function() {
- /*jshint immed: false */
- (function() {
- index.removeModule("doesnotexist");
- }).should.throw();
-
- done();
- }).catch(function(err) {
- done(err);
- });
- });
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/nodes/resources/local/NestedDirectoryNode/NestedNode/icons/arrow-in.png b/test/unit/@node-red/runtime/lib/nodes/resources/local/NestedDirectoryNode/NestedNode/icons/arrow-in.png
deleted file mode 100644
index e38f3914600901b736f5fa18786ee11be6d41c28..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 393
zcmeAS@N?(olHy`uVBq!ia0vp^B0wz1!3HFCgzU0`6icy_X9x!n)NrJ90QsB+9+AZi
z3~X;em{G3O!W1YdS>hT|5}cn_Ql40p%1~Zju9umYU7Va)kgAtols@~NjT8d|Bb%p-
zV~9uR+N-+$hZ97Oeyp#Y$RU!&XX#m>@|$agvYL9Jz$O6}72y^gZVi>ZMeaH^t*Q|!
zLhVk<0xdko8zYVo#8M-LBBd8b>1kw|i?FO)bWqsy_rwQg27N4y
zeX6pqO$_Cex^^A7_NsS@+=bOASA^wN0&GKN(hlAguRU&q-
jTBY?`*L>xN+|S&+7B*edvmQhOgN?z{)z4*}Q$iB}+9!`i
diff --git a/test/unit/@node-red/runtime/lib/nodes/resources/local/TestNodeModule/node_modules/TestNodeModule/icons/arrow-in.png b/test/unit/@node-red/runtime/lib/nodes/resources/local/TestNodeModule/node_modules/TestNodeModule/icons/arrow-in.png
deleted file mode 100644
index 59a29af14..000000000
--- a/test/unit/@node-red/runtime/lib/nodes/resources/local/TestNodeModule/node_modules/TestNodeModule/icons/arrow-in.png
+++ /dev/null
@@ -1,3 +0,0 @@
-This file exists just to ensure the 'icons' directory is in the repository.
-TODO: a future test needs to ensure the right icon files are loaded - this
- directory can be used for that
diff --git a/test/unit/@node-red/runtime/lib/plugins_spec.js b/test/unit/@node-red/runtime/lib/plugins_spec.js
deleted file mode 100644
index a78de643c..000000000
--- a/test/unit/@node-red/runtime/lib/plugins_spec.js
+++ /dev/null
@@ -1,13 +0,0 @@
-const should = require("should");
-const sinon = require("sinon");
-const NR_TEST_UTILS = require("nr-test-utils");
-
-const plugins = NR_TEST_UTILS.require("@node-red/runtime/lib/plugins");
-
-describe("runtime/plugins",function() {
-
- it.skip("delegates all functions to registry module", function() {
- // There's no easy way to test this as we can't stub the registry functions
- // before the plugin module gets a reference to them
- })
-});
diff --git a/test/unit/@node-red/runtime/lib/settings_spec.js b/test/unit/@node-red/runtime/lib/settings_spec.js
deleted file mode 100644
index 51c190fea..000000000
--- a/test/unit/@node-red/runtime/lib/settings_spec.js
+++ /dev/null
@@ -1,333 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var settings = NR_TEST_UTILS.require("@node-red/runtime/lib/settings");
-
-
-describe("runtime/settings", function() {
-
- afterEach(function() {
- settings.reset();
- });
-
- it('wraps the user settings as read-only properties', function() {
- var userSettings = {
- a: 123,
- b: "test",
- c: [1,2,3]
- }
- settings.init(userSettings);
-
- settings.available().should.be.false();
-
- settings.a.should.equal(123);
- settings.b.should.equal("test");
- settings.c.should.be.an.Array();
- settings.c.should.have.lengthOf(3);
-
- settings.get("a").should.equal(123);
- settings.get("b").should.equal("test");
- settings.get("c").should.be.an.Array();
- settings.get("c").should.have.lengthOf(3);
-
- /*jshint immed: false */
- (function() {
- settings.a = 456;
- }).should.throw();
-
- settings.c.push(5);
- settings.c.should.be.an.Array();
- settings.c.should.have.lengthOf(4);
-
- /*jshint immed: false */
- (function() {
- settings.set("a",456);
- }).should.throw();
-
- /*jshint immed: false */
- (function() {
- settings.set("a",456);
- }).should.throw();
-
- /*jshint immed: false */
- (function() {
- settings.get("unknown");
- }).should.throw();
-
- /*jshint immed: false */
- (function() {
- settings.set("unknown",456);
- }).should.throw();
-
- });
-
- it('loads global settings from storage', function(done) {
- var userSettings = {
- a: 123,
- b: "test",
- c: [1,2,3]
- }
- var savedSettings = null;
- var saveCount = 0;
- var storage = {
- getSettings: function() {
- return Promise.resolve({globalA:789});
- },
- saveSettings: function(settings) {
- saveCount++;
- savedSettings = settings;
- return Promise.resolve();
- }
- }
- settings.init(userSettings);
-
- settings.available().should.be.false();
-
- /*jshint immed: false */
- (function() {
- settings.get("unknown");
- }).should.throw();
- settings.load(storage).then(function() {
- settings.available().should.be.true();
- settings.get("globalA").should.equal(789);
- settings.set("globalA","abc").then(function() {
- savedSettings.globalA.should.equal("abc");
- saveCount.should.equal(1);
- settings.set("globalA","abc").then(function() {
- savedSettings.globalA.should.equal("abc");
- // setting to existing value should not trigger save
- saveCount.should.equal(1);
- done();
- });
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('removes persistent settings when reset', function() {
- var userSettings = {
- a: 123,
- b: "test",
- c: [1,2,3]
- }
- settings.init(userSettings);
-
- settings.available().should.be.false();
-
- settings.should.have.property("a",123);
- settings.should.have.property("b","test");
- settings.c.should.be.an.Array();
- settings.c.should.have.lengthOf(3);
-
- settings.reset();
-
- settings.should.not.have.property("a");
- settings.should.not.have.property("d");
- settings.should.not.have.property("c");
-
- });
-
- it('registers node settings and exports them', function() {
- var userSettings = {};
- settings.init(userSettings);
- settings.registerNodeSettings("inject", {injectColor:{value:"red", exportable:true}, injectSize:{value:"100", exportable:true}} );
- settings.registerNodeSettings("mqtt", {mqttColor:{value:"purple", exportable:false}, mqttSize:{value:"50", exportable:true}} );
- settings.registerNodeSettings("http request", {httpRequest1:{value:"a1", exportable:true}} );
- settings.registerNodeSettings(" http--request<> ", {httpRequest2:{value:"a2", exportable:true}} );
- settings.registerNodeSettings("_http_request_", {httpRequest3:{value:"a3", exportable:true}} );
- settings.registerNodeSettings("mQtT", {mQtTColor:{value:"purple", exportable:true}} );
- settings.registerNodeSettings("abc123", {abc123:{value:"def456", exportable:true}} );
- settings.registerNodeSettings("noValue", {noValueHasValue:{value:"123", exportable:true}, noValueNoValue:{exportable:true}} );
-
- var safeSettings = {};
- settings.exportNodeSettings(safeSettings);
- safeSettings.should.have.property("injectColor", "red");
- safeSettings.should.have.property("injectSize", "100");
- safeSettings.should.not.have.property("mqttColor");
- safeSettings.should.have.property("mqttSize", "50");
- safeSettings.should.have.property("httpRequest1", "a1");
- safeSettings.should.have.property("httpRequest2", "a2");
- safeSettings.should.have.property("httpRequest3", "a3");
- safeSettings.should.have.property("mQtTColor", "purple");
- safeSettings.should.have.property("abc123", "def456");
-
- safeSettings.should.have.property("noValueHasValue", "123");
- safeSettings.should.not.have.property("noValueNoValue");
- });
-
- it('prohibits registering the property whose name do not start with type name', function() {
- var userSettings = {};
- settings.init(userSettings);
- (function() {
- settings.registerNodeSettings("inject", {color:{value:"red", exportable:true}} );
- }).should.throw();
- (function() {
- settings.registerNodeSettings("_a_b_1_", {ab1Color:{value:"red", exportable:true}} );
- }).should.throw();
- (function() {
- settings.registerNodeSettings("AB2", {AB2Color:{value:"red", exportable:true}} );
- }).should.throw();
- (function() {
- settings.registerNodeSettings("abcDef", {abcColor:{value:"red", exportable:true}} );
- }).should.throw();
- var safeSettings = {};
- settings.exportNodeSettings(safeSettings);
- safeSettings.should.not.have.property("color");
- safeSettings.should.not.have.property("ab1Color", "blue");
- safeSettings.should.not.have.property("AB2Color");
- safeSettings.should.not.have.property("abcColor");
- });
-
- it('overwrites node settings with user settings', function() {
- var userSettings = {
- injectColor: "green",
- mqttColor: "yellow",
- abColor: [1,2,3]
- }
- settings.init(userSettings);
- settings.registerNodeSettings("inject", {injectColor:{value:"red", exportable:true}} );
- settings.registerNodeSettings("ab", {abColor:{value:"red", exportable:false}} );
- var safeSettings = {};
- settings.exportNodeSettings(safeSettings);
- safeSettings.should.have.property("injectColor", "green");
- safeSettings.should.not.have.property("mqttColor");
- safeSettings.should.not.have.property("abColor");
- });
-
- it('disables/enables node settings', function() {
- var userSettings = {};
- settings.init(userSettings);
-
- var safeSettings = {};
- settings.registerNodeSettings("inject", {injectColor:{value:"red", exportable:true}} );
- settings.registerNodeSettings("mqtt", {mqttColor:{value:"purple", exportable:true}} );
- settings.registerNodeSettings("http request", {httpRequestColor:{value:"yellow", exportable:true}} );
- settings.exportNodeSettings(safeSettings);
- safeSettings.should.have.property("injectColor", "red");
- safeSettings.should.have.property("mqttColor", "purple");
- safeSettings.should.have.property("httpRequestColor", "yellow");
-
- safeSettings = {};
- var types = ["inject", "mqtt"];
- settings.disableNodeSettings(types);
- settings.exportNodeSettings(safeSettings);
- safeSettings.should.not.have.property("injectColor");
- safeSettings.should.not.have.property("mqttColor");
- safeSettings.should.have.property("httpRequestColor", "yellow");
-
- safeSettings = {};
- types = ["inject"];
- settings.enableNodeSettings(types);
- settings.exportNodeSettings(safeSettings);
- safeSettings.should.have.property("injectColor", "red");
- safeSettings.should.not.have.property("mqttColor");
- safeSettings.should.have.property("httpRequestColor", "yellow");
- });
-
-
- it('delete global setting', function() {
- // read-only
- var localSettings = {a:1};
- // read-write
- var globalSettings = {b:2};
- var storage = {
- getSettings: function() {
- return Promise.resolve(globalSettings);
- },
- saveSettings: function() {
- return Promise.resolve();
- }
- }
- settings.init(localSettings);
- return settings.load(storage).then(function() {
- settings.get('a').should.eql(1);
- settings.get('b').should.eql(2);
- return settings.delete('b')
- }).then(function() {
- should.not.exist(settings.get('b'));
- })
- });
-
- it('refused to delete local setting', function(done) {
- // read-only
- var localSettings = {a:1};
- // read-write
- var globalSettings = {b:2};
- var storage = {
- getSettings: function() {
- return Promise.resolve(globalSettings);
- }
- }
- settings.init(localSettings);
- settings.load(storage).then(function() {
- settings.get('a').should.eql(1);
- settings.get('b').should.eql(2);
- try {
- settings.delete('a');
- return done("Did not throw error");
- } catch(err) {
- // expected
- }
- done();
- }).catch(done)
- });
-
-
- it('get user settings', function() {
- var userSettings = {
- admin: {a:1}
- }
- var storage = {
- getSettings: function() {
- return Promise.resolve({a:1,users:userSettings});
- }
- }
- settings.init(userSettings);
- return settings.load(storage).then(function() {
- var result = settings.getUserSettings('admin');
- result.should.eql(userSettings.admin);
- // Check it has been cloned
- result.should.not.equal(userSettings.admin);
- })
- })
- it('set user settings', function() {
- var userSettings = {
- admin: {a:1}
- }
- var savedSettings;
- var storage = {
- getSettings: function() {
- return Promise.resolve({c:3,users:userSettings});
- },
- saveSettings: function(s) {
- savedSettings = s;
- return Promise.resolve();
- }
- }
- settings.init(userSettings);
- return settings.load(storage).then(function() {
- return settings.setUserSettings('admin',{b:2})
- }).then(function() {
- savedSettings.should.have.property("c",3);
- savedSettings.should.have.property('users');
- savedSettings.users.should.eql({admin:{b:2}})
- })
- })
-
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/index_spec.js b/test/unit/@node-red/runtime/lib/storage/index_spec.js
deleted file mode 100644
index dd9fa6e9b..000000000
--- a/test/unit/@node-red/runtime/lib/storage/index_spec.js
+++ /dev/null
@@ -1,271 +0,0 @@
-/**
- * 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 paff = require('path');
-
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var storage = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/index");
-
-describe("red/storage/index", function() {
-
- it('rejects the promise when settings suggest loading a bad module', function(done) {
-
- var wrongModule = {
- settings:{
- storageModule : "thisaintloading"
- }
- };
-
- storage.init(wrongModule).then( function() {
- var one = 1;
- var zero = 0;
- try {
- zero.should.equal(one, "The initialization promise should never get resolved");
- } catch(err) {
- done(err);
- }
- }).catch(function(e) {
- done(); //successfully rejected promise
- });
- });
-
- it('non-string storage module', function(done) {
- var initSetsMeToTrue = false;
-
- var moduleWithBooleanSettingInit = {
- init : function() {
- initSetsMeToTrue = true;
- }
- };
-
- var setsBooleanModule = {
- settings: {
- storageModule : moduleWithBooleanSettingInit
- }
- };
-
- storage.init(setsBooleanModule);
- initSetsMeToTrue.should.be.true();
- done();
- });
-
- it('respects storage interface', function(done) {
- var calledFlagGetFlows = false;
- var calledFlagGetCredentials = false;
- var calledFlagGetAllFlows = false;
- var calledInit = false;
- var calledFlagGetSettings = false;
- var calledFlagGetSessions = false;
-
- var interfaceCheckerModule = {
- init : function (settings) {
- settings.should.be.an.Object();
- calledInit = true;
- },
- getFlows : function() {
- calledFlagGetFlows = true;
- return Promise.resolve([]);
- },
- saveFlows : function (flows) {
- flows.should.be.an.Array();
- flows.should.have.lengthOf(0);
- return Promise.resolve("");
- },
- getCredentials : function() {
- calledFlagGetCredentials = true;
- return Promise.resolve({});
- },
- saveCredentials : function(credentials) {
- credentials.should.be.true();
- },
- getSettings : function() {
- calledFlagGetSettings = true;
- },
- saveSettings : function(settings) {
- settings.should.be.true();
- },
- getSessions : function() {
- calledFlagGetSessions = true;
- },
- saveSessions : function(sessions) {
- sessions.should.be.true();
- },
- getAllFlows : function() {
- calledFlagGetAllFlows = true;
- },
- getFlow : function(fn) {
- fn.should.equal("name");
- },
- saveFlow : function(fn, data) {
- fn.should.equal("name");
- data.should.be.true();
- },
- getLibraryEntry : function(type, path) {
- type.should.be.true();
- path.should.equal("name");
- },
- saveLibraryEntry : function(type, path, meta, body) {
- type.should.be.true();
- path.should.equal("name");
- meta.should.be.true();
- body.should.be.true();
- }
- };
-
- var moduleToLoad = {
- settings: {
- storageModule : interfaceCheckerModule
- }
- };
-
- var promises = [];
- storage.init(moduleToLoad);
- promises.push(storage.getFlows());
- promises.push(storage.saveFlows({flows:[],credentials:{}}));
- storage.getSettings();
- storage.saveSettings(true);
- storage.getSessions();
- storage.saveSessions(true);
- storage.getAllFlows();
- storage.getFlow("name");
- storage.saveFlow("name", true);
- storage.getLibraryEntry(true, "name");
- storage.saveLibraryEntry(true, "name", true, true);
-
- Promise.all(promises).then(function() {
- try {
- calledInit.should.be.true();
- calledFlagGetFlows.should.be.true();
- calledFlagGetCredentials.should.be.true();
- calledFlagGetAllFlows.should.be.true();
- done();
- } catch(err) {
- done(err);
- }
- });
- });
-
- describe('respects deprecated flow library functions', function() {
-
- var savePath;
- var saveContent;
- var saveMeta;
- var saveType;
-
- var interfaceCheckerModule = {
- init : function (settings) {
- settings.should.be.an.Object();
- },
- getLibraryEntry : function(type, path) {
- if (type === "flows") {
- if (path === "/" || path === "\\") {
- return Promise.resolve(["a",{fn:"test.json"}]);
- } else if (path == "/a" || path == "\\a") {
- return Promise.resolve([{fn:"test2.json"}]);
- } else if (path == paff.join("","a","test2.json")) {
- return Promise.resolve("test content");
- }
- }
- },
- saveLibraryEntry : function(type, path, meta, body) {
- saveType = type;
- savePath = path;
- saveContent = body;
- saveMeta = meta;
- return Promise.resolve();
- }
- };
-
- var moduleToLoad = {
- settings: {
- storageModule : interfaceCheckerModule
- }
- };
- before(function() {
- storage.init(moduleToLoad);
- });
- it('getAllFlows',function(done) {
- storage.getAllFlows().then(function (res) {
- try {
- res.should.eql({ d: { a: { f: ['test2'] } }, f: [ 'test' ] });
- done();
- } catch(err) {
- done(err);
- }
- });
- });
-
- it('getFlow',function(done) {
- storage.getFlow(paff.join("a","test2.json")).then(function(res) {
- try {
- res.should.eql("test content");
- done();
- } catch(err) {
- done(err);
- }
- });
- });
-
- it ('saveFlow', function (done) {
- storage.saveFlow(paff.join("a","test2.json"),"new content").then(function(res) {
- try {
- savePath.should.eql(paff.join("a","test2.json"));
- saveContent.should.eql("new content");
- saveMeta.should.eql({});
- saveType.should.eql("flows");
- done();
- } catch(err) {
- done(err);
- }
- });
-
- });
- });
-
- describe('handles missing settings/sessions interface', function() {
- before(function() {
- var interfaceCheckerModule = {
- init : function () {}
- };
- storage.init({settings:{storageModule: interfaceCheckerModule}});
- });
-
- it('defaults missing getSettings',function(done) {
- storage.getSettings().then(function(settings) {
- should.not.exist(settings);
- done();
- });
- });
- it('defaults missing saveSettings',function(done) {
- storage.saveSettings({}).then(function() {
- done();
- });
- });
- it('defaults missing getSessions',function(done) {
- storage.getSessions().then(function(settings) {
- should.not.exist(settings);
- done();
- });
- });
- it('defaults missing saveSessions',function(done) {
- storage.saveSessions({}).then(function() {
- done();
- });
- });
- });
-
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/index_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/index_spec.js
deleted file mode 100644
index 65826c9f4..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/index_spec.js
+++ /dev/null
@@ -1,518 +0,0 @@
-/**
- * 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 fs = require('fs-extra');
-var path = require('path');
-var sinon = require('sinon');
-var NR_TEST_UTILS = require("nr-test-utils");
-var process = require("process");
-
-var localfilesystem = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem");
-var log = NR_TEST_UTILS.require("@node-red/util").log;
-
-describe('storage/localfilesystem', function() {
- var mockRuntime = {
- log:{
- _:function() { return "placeholder message"},
- info: function() { },
- warn: function() { },
- trace: function() {}
- }
- };
- var userDir = path.join(__dirname,".testUserHome");
- var testFlow = [{"type":"tab","id":"d8be2a6d.2741d8","label":"Sheet 1"}];
- beforeEach(function(done) {
- fs.remove(userDir,function(err) {
- fs.mkdir(userDir,done);
- });
- });
- afterEach(function(done) {
- fs.remove(userDir,done);
- });
-
- it('should initialise the user directory',function(done) {
- localfilesystem.init({userDir:userDir,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- fs.existsSync(path.join(userDir,"lib")).should.be.true();
- fs.existsSync(path.join(userDir,"lib",'flows')).should.be.true();
- done();
- }).catch(function(err) {
- done(err);
- });
- });
-
-
- it('should set userDir to NRH if .config.json presents',function(done) {
- var oldNRH = process.env.NODE_RED_HOME;
- process.env.NODE_RED_HOME = path.join(userDir,"NRH");
- fs.mkdirSync(process.env.NODE_RED_HOME);
- fs.writeFileSync(path.join(process.env.NODE_RED_HOME,".config.json"),"{}","utf8");
- var settings = {getUserSettings: () => {{}}};
- localfilesystem.init(settings, mockRuntime).then(function() {
- try {
- fs.existsSync(path.join(process.env.NODE_RED_HOME,"lib")).should.be.true();
- fs.existsSync(path.join(process.env.NODE_RED_HOME,"lib",'flows')).should.be.true();
- settings.userDir.should.equal(process.env.NODE_RED_HOME);
- done();
- } catch(err) {
- done(err);
- } finally {
- process.env.NODE_RED_HOME = oldNRH;
- }
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should set userDir to HOMEPATH/.node-red if .config.json presents',function(done) {
- var oldNRH = process.env.NODE_RED_HOME;
- process.env.NODE_RED_HOME = path.join(userDir,"NRH");
- var oldHOMEPATH = process.env.HOMEPATH;
- process.env.HOMEPATH = path.join(userDir,"HOMEPATH");
- fs.mkdirSync(process.env.HOMEPATH);
- fs.mkdirSync(path.join(process.env.HOMEPATH,".node-red"));
- fs.writeFileSync(path.join(process.env.HOMEPATH,".node-red",".config.json"),"{}","utf8");
- var settings = {getUserSettings: () => {{}}};
- localfilesystem.init(settings, mockRuntime).then(function() {
- try {
- fs.existsSync(path.join(process.env.HOMEPATH,".node-red","lib")).should.be.true();
- fs.existsSync(path.join(process.env.HOMEPATH,".node-red","lib",'flows')).should.be.true();
- settings.userDir.should.equal(path.join(process.env.HOMEPATH,".node-red"));
- done();
- } catch(err) {
- done(err);
- } finally {
- process.env.NODE_RED_HOME = oldNRH;
- process.env.NODE_HOMEPATH = oldHOMEPATH;
- }
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should set userDir to HOME/.node-red',function(done) {
- var oldNRH = process.env.NODE_RED_HOME;
- process.env.NODE_RED_HOME = path.join(userDir,"NRH");
- var oldHOME = process.env.HOME;
- process.env.HOME = path.join(userDir,"HOME");
- var oldHOMEPATH = process.env.HOMEPATH;
- process.env.HOMEPATH = path.join(userDir,"HOMEPATH");
-
- fs.mkdirSync(process.env.HOME);
- var settings = {getUserSettings: () => {{}}};
- localfilesystem.init(settings, mockRuntime).then(function() {
- try {
- fs.existsSync(path.join(process.env.HOME,".node-red","lib")).should.be.true();
- fs.existsSync(path.join(process.env.HOME,".node-red","lib",'flows')).should.be.true();
- settings.userDir.should.equal(path.join(process.env.HOME,".node-red"));
- done();
- } catch(err) {
- done(err);
- } finally {
- process.env.NODE_RED_HOME = oldNRH;
- process.env.HOME = oldHOME;
- process.env.HOMEPATH = oldHOMEPATH;
- }
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should set userDir to USERPROFILE/.node-red',function(done) {
- var oldNRH = process.env.NODE_RED_HOME;
- process.env.NODE_RED_HOME = path.join(userDir,"NRH");
- var oldHOME = process.env.HOME;
- process.env.HOME = "";
- var oldHOMEPATH = process.env.HOMEPATH;
- process.env.HOMEPATH = path.join(userDir,"HOMEPATH");
- var oldUSERPROFILE = process.env.USERPROFILE;
- process.env.USERPROFILE = path.join(userDir,"USERPROFILE");
-
- fs.mkdirSync(process.env.USERPROFILE);
- var settings = {getUserSettings: () => {{}}};
- localfilesystem.init(settings, mockRuntime).then(function() {
- try {
- fs.existsSync(path.join(process.env.USERPROFILE,".node-red","lib")).should.be.true();
- fs.existsSync(path.join(process.env.USERPROFILE,".node-red","lib",'flows')).should.be.true();
- settings.userDir.should.equal(path.join(process.env.USERPROFILE,".node-red"));
- done();
- } catch(err) {
- done(err);
- } finally {
- process.env.NODE_RED_HOME = oldNRH;
- process.env.HOME = oldHOME;
- process.env.HOMEPATH = oldHOMEPATH;
- process.env.USERPROFILE = oldUSERPROFILE;
- }
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should handle missing flow file',function(done) {
- localfilesystem.init({userDir:userDir,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- var flowFile = 'flows_'+require('os').hostname()+'.json';
- var flowFilePath = path.join(userDir,flowFile);
- fs.existsSync(flowFilePath).should.be.false();
- localfilesystem.getFlows().then(function(flows) {
- flows.should.eql([]);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should handle empty flow file, no backup',function(done) {
- localfilesystem.init({userDir:userDir,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- var flowFile = 'flows_'+require('os').hostname()+'.json';
- var flowFilePath = path.join(userDir,flowFile);
- var flowFileBackupPath = path.join(userDir,"."+flowFile+".backup");
- fs.closeSync(fs.openSync(flowFilePath, 'w'));
- fs.existsSync(flowFilePath).should.be.true();
- localfilesystem.getFlows().then(function(flows) {
- flows.should.eql([]);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should handle empty flow file, restores backup',function(done) {
- localfilesystem.init({userDir:userDir,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- var flowFile = 'flows_'+require('os').hostname()+'.json';
- var flowFilePath = path.join(userDir,flowFile);
- var flowFileBackupPath = path.join(userDir,"."+flowFile+".backup");
- fs.closeSync(fs.openSync(flowFilePath, 'w'));
- fs.existsSync(flowFilePath).should.be.true();
- fs.existsSync(flowFileBackupPath).should.be.false();
- fs.writeFileSync(flowFileBackupPath,JSON.stringify(testFlow));
- fs.existsSync(flowFileBackupPath).should.be.true();
- setTimeout(function() {
- localfilesystem.getFlows().then(function(flows) {
- flows.should.eql(testFlow);
- done();
- }).catch(function(err) {
- done(err);
- });
- },50);
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should save flows to the default file',function(done) {
- localfilesystem.init({userDir:userDir,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- var flowFile = 'flows_'+require('os').hostname()+'.json';
- var flowFilePath = path.join(userDir,flowFile);
- var flowFileBackupPath = path.join(userDir,"."+flowFile+".backup");
- fs.existsSync(flowFilePath).should.be.false();
- fs.existsSync(flowFileBackupPath).should.be.false();
- localfilesystem.saveFlows(testFlow).then(function() {
- fs.existsSync(flowFilePath).should.be.true();
- fs.existsSync(flowFileBackupPath).should.be.false();
- localfilesystem.getFlows().then(function(flows) {
- flows.should.eql(testFlow);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should save flows to the specified file',function(done) {
- var defaultFlowFile = 'flows_'+require('os').hostname()+'.json';
- var defaultFlowFilePath = path.join(userDir,defaultFlowFile);
- var flowFile = 'test.json';
- var flowFilePath = path.join(userDir,flowFile);
-
- localfilesystem.init({userDir:userDir, flowFile:flowFilePath,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- fs.existsSync(defaultFlowFilePath).should.be.false();
- fs.existsSync(flowFilePath).should.be.false();
-
- localfilesystem.saveFlows(testFlow).then(function() {
- fs.existsSync(defaultFlowFilePath).should.be.false();
- fs.existsSync(flowFilePath).should.be.true();
- localfilesystem.getFlows().then(function(flows) {
- flows.should.eql(testFlow);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should format the flows file when flowFilePretty specified',function(done) {
- var flowFile = 'test.json';
- var flowFilePath = path.join(userDir,flowFile);
- localfilesystem.init({userDir:userDir, flowFile:flowFilePath,flowFilePretty:true,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- localfilesystem.saveFlows(testFlow).then(function() {
- var content = fs.readFileSync(flowFilePath,"utf8");
- content.split("\n").length.should.be.above(1);
- localfilesystem.getFlows().then(function(flows) {
- flows.should.eql(testFlow);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should fsync the flows file',function(done) {
- var flowFile = 'test.json';
- var flowFilePath = path.join(userDir,flowFile);
- localfilesystem.init({editorTheme:{projects:{enabled:false}},userDir:userDir, flowFile:flowFilePath,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- sinon.spy(fs,"fsync");
- localfilesystem.saveFlows(testFlow).then(function() {
- fs.fsync.callCount.should.be.greaterThan(0);
- fs.fsync.restore();
- done();
- }).catch(function(err) {
- fs.fsync.restore();
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should log fsync errors and continue',function(done) {
- var flowFile = 'test.json';
- var flowFilePath = path.join(userDir,flowFile);
- localfilesystem.init({userDir:userDir, flowFile:flowFilePath,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- sinon.stub(fs,"fsync").callsFake(function(fd, cb) {
- cb(new Error());
- });
- sinon.spy(log,"warn");
- localfilesystem.saveFlows(testFlow).then(function() {
- fs.fsync.callCount.should.be.greaterThan(0);
- log.warn.restore();
- fs.fsync.callCount.should.be.greaterThan(0);
- fs.fsync.restore();
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should backup the flows file', function(done) {
- var defaultFlowFile = 'flows_'+require('os').hostname()+'.json';
- var defaultFlowFilePath = path.join(userDir,defaultFlowFile);
- var flowFile = 'test.json';
- var flowFilePath = path.join(userDir,flowFile);
- var flowFileBackupPath = path.join(userDir,"."+flowFile+".backup");
-
- localfilesystem.init({userDir:userDir, flowFile:flowFilePath,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- fs.existsSync(defaultFlowFilePath).should.be.false();
- fs.existsSync(flowFilePath).should.be.false();
- fs.existsSync(flowFileBackupPath).should.be.false();
-
- localfilesystem.saveFlows(testFlow).then(function() {
- fs.existsSync(flowFileBackupPath).should.be.false();
- fs.existsSync(defaultFlowFilePath).should.be.false();
- fs.existsSync(flowFilePath).should.be.true();
- var content = fs.readFileSync(flowFilePath,'utf8');
- var testFlow2 = [{"type":"tab","id":"bc5672ad.2741d8","label":"Sheet 2"}];
-
- localfilesystem.saveFlows(testFlow2).then(function() {
- fs.existsSync(flowFileBackupPath).should.be.true();
- fs.existsSync(defaultFlowFilePath).should.be.false();
- fs.existsSync(flowFilePath).should.be.true();
- var backupContent = fs.readFileSync(flowFileBackupPath,'utf8');
- content.should.equal(backupContent);
- var content2 = fs.readFileSync(flowFilePath,'utf8');
- content2.should.not.equal(backupContent);
- done();
-
- }).catch(function(err) {
- done(err);
- });
-
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
-
-
- });
-
- it('should handle missing credentials', function(done) {
- var flowFile = 'test.json';
- var flowFilePath = path.join(userDir,flowFile);
- var credFile = path.join(userDir,"test_cred.json");
- localfilesystem.init({userDir:userDir, flowFile:flowFilePath,getUserSettings: () => {{}}}, mockRuntime).then(function() {
- fs.existsSync(credFile).should.be.false();
-
- localfilesystem.getCredentials().then(function(creds) {
- creds.should.eql({});
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should handle credentials', function(done) {
- var flowFile = 'test.json';
- var flowFilePath = path.join(userDir,flowFile);
- var credFile = path.join(userDir,"test_cred.json");
-
- localfilesystem.init({userDir:userDir, flowFile:flowFilePath,getUserSettings: () => {{}}}, mockRuntime).then(function() {
-
- fs.existsSync(credFile).should.be.false();
-
- var credentials = {"abc":{"type":"creds"}};
-
- localfilesystem.saveCredentials(credentials).then(function() {
- fs.existsSync(credFile).should.be.true();
- localfilesystem.getCredentials().then(function(creds) {
- creds.should.eql(credentials);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
-
- it('should backup existing credentials', function(done) {
- var flowFile = 'test.json';
- var flowFilePath = path.join(userDir,flowFile);
- var credFile = path.join(userDir,"test_cred.json");
- var credFileBackup = path.join(userDir,".test_cred.json.backup");
-
- localfilesystem.init({userDir:userDir, flowFile:flowFilePath,getUserSettings: () => {{}}}, mockRuntime).then(function() {
-
- fs.writeFileSync(credFile,"{}","utf8");
-
- fs.existsSync(credFile).should.be.true();
- fs.existsSync(credFileBackup).should.be.false();
-
- var credentials = {"abc":{"type":"creds"}};
-
- localfilesystem.saveCredentials(credentials).then(function() {
- fs.existsSync(credFile).should.be.true();
- fs.existsSync(credFileBackup).should.be.true();
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should format the creds file when flowFilePretty specified',function(done) {
- var flowFile = 'test.json';
- var flowFilePath = path.join(userDir,flowFile);
- var credFile = path.join(userDir,"test_cred.json");
-
- localfilesystem.init({userDir:userDir, flowFile:flowFilePath, flowFilePretty:true,getUserSettings: () => {{}}}, mockRuntime).then(function() {
-
- fs.existsSync(credFile).should.be.false();
-
- var credentials = {"abc":{"type":"creds"}};
-
- localfilesystem.saveCredentials(credentials).then(function() {
- fs.existsSync(credFile).should.be.true();
- var content = fs.readFileSync(credFile,"utf8");
- content.split("\n").length.should.be.above(1);
- localfilesystem.getCredentials().then(function(creds) {
- creds.should.eql(credentials);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should handle flow file in random unc path and non-existent subfolder',function(done) {
- // only test on win32
- if (process.platform !== 'win32') {
- console.log('skipped test as not win32');
- done();
- return;
- }
-
- // get a real windows path
- var flowFile = path.win32.resolve(userDir+'/some/random/path');
- var rootdir = path.win32.resolve(userDir+'/some');
- // make it into a local UNC path
- flowFile = flowFile.replace('C:\\', '\\\\localhost\\c$\\');
- localfilesystem.init({userDir:userDir, flowFile:flowFile}, mockRuntime).then(function() {
- fs.existsSync(flowFile).should.be.false();
- localfilesystem.saveFlows(testFlow).then(function() {
- fs.existsSync(flowFile).should.be.true();
- localfilesystem.getFlows().then(function(flows) {
- flows.should.eql(testFlow);
- // cleanup
- fs.removeSync(rootdir);
- done();
- }).catch(function(err) {
- // cleanup
- fs.removeSync(rootdir);
- done(err);
- });
- }).catch(function(err) {
- // cleanup
- fs.removeSync(rootdir);
- done(err);
- });
- }).catch(function(err) {
- // cleanup
- fs.removeSync(rootdir);
- done(err);
- });
- });
-
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/library_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/library_spec.js
deleted file mode 100644
index 69b6e3da6..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/library_spec.js
+++ /dev/null
@@ -1,244 +0,0 @@
-/**
- * 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 fs = require('fs-extra');
-var path = require('path');
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var localfilesystemLibrary = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/library");
-
-describe('storage/localfilesystem/library', function() {
- var userDir = path.join(__dirname,".testUserHome");
- beforeEach(function(done) {
- fs.remove(userDir,function(err) {
- fs.mkdir(userDir,done);
- });
- });
- afterEach(function(done) {
- fs.remove(userDir,done);
- });
-
- it('should return an empty list of library objects',function(done) {
- localfilesystemLibrary.init({userDir:userDir}).then(function() {
- localfilesystemLibrary.getLibraryEntry('object','').then(function(flows) {
- flows.should.eql([]);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should return an empty list of library objects (path=/)',function(done) {
- localfilesystemLibrary.init({userDir:userDir}).then(function() {
- localfilesystemLibrary.getLibraryEntry('object','/').then(function(flows) {
- flows.should.eql([]);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should return an error for a non-existent library object',function(done) {
- localfilesystemLibrary.init({userDir:userDir}).then(function() {
- localfilesystemLibrary.getLibraryEntry('object','A/B').then(function(flows) {
- should.fail(null,null,"non-existent flow");
- }).catch(function(err) {
- should.exist(err);
- done();
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- function createObjectLibrary(type) {
- type = type || "object";
- var objLib = path.join(userDir, "lib", type);
- try {
- fs.mkdirSync(objLib);
- } catch (err) {
- }
- fs.mkdirSync(path.join(objLib, "A"));
- fs.mkdirSync(path.join(objLib, "B"));
- fs.mkdirSync(path.join(objLib, "B", "C"));
- fs.mkdirSync(path.join(objLib, "D"));
- if (type === "functions" || type === "object") {
- fs.writeFileSync(path.join(objLib, "file1.js"), "// abc: def\n// not a metaline \n\n Hi", 'utf8');
- fs.writeFileSync(path.join(objLib, "B", "file2.js"), "// ghi: jkl\n// not a metaline \n\n Hi", 'utf8');
- fs.writeFileSync(path.join(objLib, "D", "file3.js"), "// mno: 日本語テスト\n\nこんにちわ", 'utf8');
- }
- if (type === "flows" || type === "object") {
- fs.writeFileSync(path.join(objLib, "B", "flow.json"), "Hi", 'utf8');
- }
- }
-
- it('should return a directory listing of library objects', function (done) {
- localfilesystemLibrary.init({userDir: userDir}).then(function () {
- createObjectLibrary();
-
- localfilesystemLibrary.getLibraryEntry('object', '').then(function (flows) {
- flows.should.eql([ 'A', 'B', 'D', { abc: 'def', fn: 'file1.js' }]);
- localfilesystemLibrary.getLibraryEntry('object', 'B').then(function (flows) {
- flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' }, { fn: 'flow.json' }]);
- localfilesystemLibrary.getLibraryEntry('object', 'B/C').then(function (flows) {
- flows.should.eql([]);
- localfilesystemLibrary.getLibraryEntry('object', 'D').then(function (flows) {
- flows.should.eql([{ mno: '日本語テスト', fn: 'file3.js' }]);
- done();
- }).catch(function (err) {
- done(err);
- });
- }).catch(function (err) {
- done(err);
- });
- }).catch(function (err) {
- done(err);
- });
- }).catch(function (err) {
- done(err);
- });
- }).catch(function (err) {
- done(err);
- });
- });
-
- it('should load a flow library object with .json unspecified', function(done) {
- localfilesystemLibrary.init({userDir:userDir}).then(function() {
- createObjectLibrary("flows");
- localfilesystemLibrary.getLibraryEntry('flows','B/flow').then(function(flows) {
- flows.should.eql("Hi");
- done();
- }).catch(function(err) {
- done(err);
- });
- });
-
- });
-
- it('should return a library object',function(done) {
- localfilesystemLibrary.init({userDir:userDir}).then(function() {
- createObjectLibrary();
- localfilesystemLibrary.getLibraryEntry('object','B/file2.js').then(function(body) {
- body.should.eql("// not a metaline \n\n Hi");
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should return a newly saved library function',function(done) {
- localfilesystemLibrary.init({userDir:userDir}).then(function() {
- createObjectLibrary("functions");
- localfilesystemLibrary.getLibraryEntry('functions','B').then(function(flows) {
- flows.should.eql([ 'C', { ghi: 'jkl', fn: 'file2.js' } ]);
- var ft = path.join("B","D","file3.js");
- localfilesystemLibrary.saveLibraryEntry('functions',ft,{mno:'pqr'},"// another non meta line\n\n Hi There").then(function() {
- setTimeout(function() {
- localfilesystemLibrary.getLibraryEntry('functions',path.join("B","D")).then(function(flows) {
- flows.should.eql([ { mno: 'pqr', fn: 'file3.js' } ]);
- localfilesystemLibrary.getLibraryEntry('functions',ft).then(function(body) {
- body.should.eql("// another non meta line\n\n Hi There");
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- })
- }, 50);
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should return a newly saved library flow',function(done) {
- localfilesystemLibrary.init({userDir:userDir}).then(function() {
- createObjectLibrary("flows");
- localfilesystemLibrary.getLibraryEntry('flows','B').then(function(flows) {
- flows.should.eql([ 'C', {fn:'flow.json'} ]);
- var ft = path.join("B","D","file3");
- localfilesystemLibrary.saveLibraryEntry('flows',ft,{mno:'pqr'},"Hi").then(function() {
- setTimeout(function() {
- localfilesystemLibrary.getLibraryEntry('flows',path.join("B","D")).then(function(flows) {
- flows.should.eql([ { mno: 'pqr', fn: 'file3.json' } ]);
- localfilesystemLibrary.getLibraryEntry('flows',ft+".json").then(function(body) {
- body.should.eql("Hi");
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- })
- }, 50);
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should return a newly saved library flow (multi-byte character)',function(done) {
- localfilesystemLibrary.init({userDir:userDir}).then(function() {
- createObjectLibrary("flows");
- localfilesystemLibrary.getLibraryEntry('flows','B').then(function(flows) {
- flows.should.eql([ 'C', {fn:'flow.json'} ]);
- var ft = path.join("B","D","file4");
- localfilesystemLibrary.saveLibraryEntry('flows',ft,{mno:'pqr'},"こんにちわこんにちわこんにちわ").then(function() {
- setTimeout(function() {
- localfilesystemLibrary.getLibraryEntry('flows',path.join("B","D")).then(function(flows) {
- flows.should.eql([ { mno: 'pqr', fn: 'file4.json' } ]);
- localfilesystemLibrary.getLibraryEntry('flows',ft+".json").then(function(body) {
- body.should.eql("こんにちわこんにちわこんにちわ");
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- })
- }, 50);
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/Project_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/Project_spec.js
deleted file mode 100644
index ecf24cf40..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/Project_spec.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-
-describe("storage/localfilesystem/projects/Project", function() {
- it.skip("NEEDS TESTS WRITING",function() {});
-})
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/defaultFileSet_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/defaultFileSet_spec.js
deleted file mode 100644
index 3fab5a45c..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/defaultFileSet_spec.js
+++ /dev/null
@@ -1,64 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var defaultFileSet = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/projects/defaultFileSet");
-
-describe('storage/localfilesystem/projects/defaultFileSet', function() {
- var runtime = {
- i18n: {
- "_": function(name) {
- return name;
- }
- }
- };
- it('generates package.json for a project', function() {
- var generated = defaultFileSet["package.json"]({
- name: "A TEST NAME",
- summary: "A TEST SUMMARY",
- files: {
- flow: "MY FLOW FILE",
- credentials: "MY CREDENTIALS FILE"
- }
- }, runtime);
-
- var parsed = JSON.parse(generated);
- parsed.should.have.property('name',"A TEST NAME");
- parsed.should.have.property('description',"A TEST SUMMARY");
- parsed.should.have.property('node-red');
- parsed['node-red'].should.have.property('settings');
- parsed['node-red'].settings.should.have.property('flowFile',"MY FLOW FILE");
- parsed['node-red'].settings.should.have.property('credentialsFile',"MY CREDENTIALS FILE");
- });
-
- it('generates README.md for a project', function() {
- var generated = defaultFileSet["README.md"]({
- name: "A TEST NAME",
- summary: "A TEST SUMMARY"
- }, runtime);
- generated.should.match(/A TEST NAME/);
- generated.should.match(/A TEST SUMMARY/);
- });
- it('generates .gitignore for a project', function() {
- var generated = defaultFileSet[".gitignore"]({
- name: "A TEST NAME",
- summary: "A TEST SUMMARY"
- }, runtime);
- generated.length.should.be.greaterThan(0);
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/authCache_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/authCache_spec.js
deleted file mode 100644
index c1617bf90..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/authCache_spec.js
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var authCache = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/projects/git/authCache")
-
-describe("localfilesystem/projects/git/authCache", function() {
-
- beforeEach(function() {
- authCache.init();
- });
- afterEach(function() {
- authCache.init();
- });
-
- it('sets/clears auth details for a given project/remote/user', function() {
- should.not.exist(authCache.get("project","remote1","user1"));
- should.not.exist(authCache.get("project","remote1","user2"));
-
- authCache.set("project","remote1","user1",{foo1:"bar1"});
- authCache.set("project","remote1","user2",{foo2:"bar2"});
-
- var result = authCache.get("project","remote1","user1");
- result.should.have.property("foo1","bar1");
-
- result = authCache.get("project","remote1","user2");
- result.should.have.property("foo2","bar2");
-
- authCache.clear("project","remote1","user1");
- should.not.exist(authCache.get("project","remote1","user1"));
- should.exist(authCache.get("project","remote1","user2"));
-
- });
-
-
- it('clears auth details for all users on a given project/remote', function() {
-
- authCache.set("project","remote1","user1",{foo1:"bar1"});
- authCache.set("project","remote1","user2",{foo2:"bar2"});
- authCache.set("project","remote2","user1",{foo3:"bar3"});
-
- should.exist(authCache.get("project","remote1","user1"));
- should.exist(authCache.get("project","remote1","user2"));
- should.exist(authCache.get("project","remote2","user1"));
-
- authCache.clear("project","remote1");
- should.not.exist(authCache.get("project","remote1","user1"));
- should.not.exist(authCache.get("project","remote1","user2"));
- should.exist(authCache.get("project","remote2","user1"));
- });
-
- it('clears auth details for all remotes/users on a given project', function() {
-
- authCache.set("project1","remote1","user1",{foo1:"bar1"});
- authCache.set("project1","remote1","user2",{foo2:"bar2"});
- authCache.set("project2","remote2","user1",{foo3:"bar3"});
-
- should.exist(authCache.get("project1","remote1","user1"));
- should.exist(authCache.get("project1","remote1","user2"));
- should.exist(authCache.get("project2","remote2","user1"));
-
- authCache.clear("project2");
- should.exist(authCache.get("project1","remote1","user1"));
- should.exist(authCache.get("project1","remote1","user2"));
- should.not.exist(authCache.get("project2","remote2","user1"));
- });
-
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/authServer_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/authServer_spec.js
deleted file mode 100644
index 9b789a66b..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/authServer_spec.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * 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 net = require("net");
-var path = require("path");
-var os = require("os");
-var should = require("should");
-var sinon = require("sinon");
-var child_process = require("child_process");
-var fs = require("fs-extra");
-
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var authServer = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/projects/git/authServer");
-
-
-var sendPrompt = function(localPath, prompt) {
- return new Promise(function(resolve,reject) {
- var response;
- var socket = net.connect(localPath, function() {
- socket.on('data', function(data) { response = data; socket.end() });
- socket.on('end', function() {
- resolve(response);
- });
- socket.on('error',reject);
- socket.write(prompt+"\n", 'utf8');
- });
- socket.setEncoding('utf8');
- });
-}
-
-
-describe("localfilesystem/projects/git/authServer", function() {
- it("listens for user/pass prompts and returns provided auth", function(done) {
- authServer.ResponseServer({username: "TEST_USER", password: "TEST_PASS"}).then(function(rs) {
- sendPrompt(rs.path,"Username").then(function(response) {
- response.should.eql("TEST_USER");
- return sendPrompt(rs.path,"Password");
- }).then(function(response) {
- response.should.eql("TEST_PASS");
- }).then(() => {
- rs.close();
- done();
- }).catch(function(err) {
- rs.close();
- done(err);
- })
-
- })
- });
-
- it("listens for ssh prompts and returns provided auth", function(done) {
- authServer.ResponseSSHServer({passphrase: "TEST_PASSPHRASE"}).then(function(rs) {
- sendPrompt(rs.path,"The").then(function(response) {
- // TODO:
- response.should.eql("yes");
- return sendPrompt(rs.path,"Enter");
- }).then(function(response) {
- response.should.eql("TEST_PASSPHRASE");
- }).then(() => {
- rs.close();
- done();
- }).catch(function(err) {
- rs.close();
- done(err);
- })
-
- })
- })
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/authWriter_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/authWriter_spec.js
deleted file mode 100644
index c80cb8ad1..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/authWriter_spec.js
+++ /dev/null
@@ -1,83 +0,0 @@
-/**
- * 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 net = require("net");
-var path = require("path");
-var os = require("os");
-var should = require("should");
-var sinon = require("sinon");
-var child_process = require("child_process");
-var fs = require("fs-extra");
-
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var authWriter = NR_TEST_UTILS.resolve("@node-red/runtime/lib/storage/localfilesystem/projects/git/authWriter");
-
-function getListenPath() {
- var seed = (0x100000+Math.random()*0x999999).toString(16);
- var fn = 'node-red-git-askpass-'+seed+'-sock';
- var listenPath;
- if (process.platform === 'win32') {
- listenPath = '\\\\.\\pipe\\'+fn;
- } else {
- listenPath = path.join(process.env['XDG_RUNTIME_DIR'] || os.tmpdir(), fn);
- }
- // console.log(listenPath);
- return listenPath;
-}
-
-
-describe("localfilesystem/projects/git/authWriter", function() {
- it("connects to port and sends passphrase", function(done) {
- var receivedData = "";
- var server = net.createServer(function(connection) {
- connection.setEncoding('utf8');
- connection.on('data', function(data) {
- receivedData += data;
- var m = data.indexOf("\n");
- if (m !== -1) {
- connection.end();
- }
- });
- });
-
- var listenPath = getListenPath();
-
- server.listen(listenPath, function(ready) {
- child_process.exec('"'+process.execPath+'" "'+authWriter+'" "'+listenPath+'" TEST_PHRASE_FOO',{cwd:__dirname}, (error,stdout,stderr) => {
- server.close();
- try {
- should.not.exist(error);
- receivedData.should.eql("TEST_PHRASE_FOO\n");
- done();
- } catch(err) {
- done(err);
- }
- });
- });
- server.on('close', function() {
- // console.log("Closing response server");
- fs.removeSync(listenPath);
- });
- server.on('error',function(err) {
- console.log("ResponseServer unexpectedError:",err.toString());
- server.close();
- done(err);
- });
-
-
- })
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/index_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/index_spec.js
deleted file mode 100644
index 773342fa6..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/git/index_spec.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-
-describe("storage/localfilesystem/projects/git/index", function() {
- it.skip("NEEDS TESTS WRITING",function() {});
-})
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/index_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/index_spec.js
deleted file mode 100644
index f63a20522..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/index_spec.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-
-describe("storage/localfilesystem/projects/index", function() {
- it.skip("NEEDS TESTS WRITING",function() {});
-})
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/index_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/index_spec.js
deleted file mode 100644
index c6d0c533e..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/index_spec.js
+++ /dev/null
@@ -1,433 +0,0 @@
-/**
-* 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 fs = require('fs-extra');
-var path = require('path');
-
-var NR_TEST_UTILS = require("nr-test-utils");
-var sshkeys = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/projects/ssh");
-
-describe("storage/localfilesystem/projects/ssh", function() {
- var userDir = path.join(__dirname,".testSSHKeyUserHome");
- var mockSettings = {
- userDir: userDir
- };
- var mockRuntime = {
- log:{
- _:function() { return "placeholder message"},
- info: function() { },
- log: function() { },
- trace: function() { }
- }
- };
- var oldHOME;
-
- beforeEach(function(done) {
- oldHOME = process.env.HOME;
- process.env.HOME = "/tmp/doesnt/exist";
- fs.remove(userDir,function(err) {
- fs.mkdir(userDir,done);
- });
- });
- afterEach(function(done) {
- process.env.HOME = oldHOME;
- fs.remove(userDir,done);
- });
-
- it('should create sshkey directory when sshkey initializes', function(done) {
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- var ret = fs.existsSync(sshkeyDirPath);
- ret.should.be.true();
- done();
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should get sshkey empty list if there is no sshkey file', function(done) {
- var username = 'test';
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- sshkeys.listSSHKeys(username).then(function(retObj) {
- retObj.should.be.instanceOf(Array).and.have.lengthOf(0);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should get sshkey list', function(done) {
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var filenameList = ['test-key01', 'test-key02'];
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- for(var filename of filenameList) {
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename),"","utf8");
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename+".pub"),"","utf8");
- }
- sshkeys.listSSHKeys(username).then(function(retObj) {
- retObj.should.be.instanceOf(Array).and.have.lengthOf(filenameList.length);
- for(var filename of filenameList) {
- retObj.should.containEql({ name: filename });
- }
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should not get sshkey file if there is only private key', function(done) {
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var filenameList = ['test-key01', 'test-key02'];
- var onlyPrivateKeyFilenameList = ['test-key03', 'test-key04'];
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- for(var filename of filenameList) {
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename),"","utf8");
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename+".pub"),"","utf8");
- }
- for(var filename of onlyPrivateKeyFilenameList) {
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename),"","utf8");
- }
- sshkeys.listSSHKeys(username).then(function(retObj) {
- retObj.should.be.instanceOf(Array).and.have.lengthOf(filenameList.length);
- for(var filename of filenameList) {
- retObj.should.containEql({ name: filename });
- }
- for(var filename of onlyPrivateKeyFilenameList) {
- retObj.should.not.containEql({ name: filename });
- }
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should not get sshkey file if there is only public key', function(done) {
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var filenameList = ['test-key01', 'test-key02'];
- var directoryList = ['test-key03', '.test-key04'];
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- for(var filename of filenameList) {
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename),"","utf8");
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename+".pub"),"","utf8");
- }
- for(var filename of directoryList) {
- fs.ensureDirSync(path.join(sshkeyDirPath,filename));
- }
- sshkeys.listSSHKeys(username).then(function(retObj) {
- retObj.should.be.instanceOf(Array).and.have.lengthOf(filenameList.length);
- for(var filename of filenameList) {
- retObj.should.containEql({ name: filename });
- }
- for(var directoryname of directoryList) {
- retObj.should.not.containEql({ name: directoryname });
- }
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should get sshkey list that does not have directory', function(done) {
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var otherUsername = 'other';
- var filenameList = ['test-key01', 'test-key02'];
- var otherUserFilenameList = ['test-key03', 'test-key04'];
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- for(var filename of filenameList) {
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename),"","utf8");
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename+".pub"),"","utf8");
- }
- for(var filename of otherUserFilenameList) {
- fs.writeFileSync(path.join(sshkeyDirPath,otherUsername+"_"+filename),"","utf8");
- fs.writeFileSync(path.join(sshkeyDirPath,otherUsername+"_"+filename+".pub"),"","utf8");
- }
- sshkeys.listSSHKeys(username).then(function(retObj) {
- retObj.should.be.instanceOf(Array).and.have.lengthOf(filenameList.length);
- for(var filename of filenameList) {
- retObj.should.containEql({ name: filename });
- }
- for(var filename of otherUserFilenameList) {
- retObj.should.not.containEql({ name: filename });
- }
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should get sshkey list that have keys of specified user', function(done) {
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var otherUsername = 'other';
- var filenameList = ['test-key01', 'test-key02'];
- var otherUserFilenameList = ['test-key03', 'test-key04'];
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- for(var filename of filenameList) {
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename),"","utf8");
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename+".pub"),"","utf8");
- }
- for(var filename of otherUserFilenameList) {
- fs.writeFileSync(path.join(sshkeyDirPath,otherUsername+"_"+filename),"","utf8");
- fs.writeFileSync(path.join(sshkeyDirPath,otherUsername+"_"+filename+".pub"),"","utf8");
- }
- sshkeys.listSSHKeys(username).then(function(retObj) {
- retObj.should.be.instanceOf(Array).and.have.lengthOf(filenameList.length);
- for(var filename of filenameList) {
- retObj.should.containEql({ name: filename });
- }
- for(var filename of otherUserFilenameList) {
- retObj.should.not.containEql({ name: filename });
- }
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should generate sshkey file with empty data', function(done) {
- this.timeout(10000);
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var options = {
- name: 'test-key01'
- };
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- sshkeys.generateSSHKey(username, options).then(function(retObj) {
- retObj.should.be.equal(options.name);
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name)).should.be.true();
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name+'.pub')).should.be.true();
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should generate sshkey file with only comment data', function(done) {
- this.timeout(10000);
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var options = {
- comment: 'test@test.com',
- name: 'test-key01'
- };
-
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- sshkeys.generateSSHKey(username, options).then(function(retObj) {
- retObj.should.be.equal(options.name);
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name)).should.be.true();
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name+'.pub')).should.be.true();
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should generate sshkey file with password data', function(done) {
- this.timeout(10000);
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var options = {
- comment: 'test@test.com',
- name: 'test-key01',
- password: 'testtest'
- };
-
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- sshkeys.generateSSHKey(username, options).then(function(retObj) {
- retObj.should.be.equal(options.name);
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name)).should.be.true();
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name+'.pub')).should.be.true();
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should generate sshkey file with size data', function(done) {
- this.timeout(20000);
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var options = {
- comment: 'test@test.com',
- name: 'test-key01',
- size: 4096
- };
-
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- sshkeys.generateSSHKey(username, options).then(function(retObj) {
- retObj.should.be.equal(options.name);
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name)).should.be.true();
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name+'.pub')).should.be.true();
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should generate sshkey file with password & size data', function(done) {
- this.timeout(20000);
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var options = {
- comment: 'test@test.com',
- name: 'test-key01',
- password: 'testtest',
- size: 4096
- };
-
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- sshkeys.generateSSHKey(username, options).then(function(retObj) {
- retObj.should.be.equal(options.name);
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name)).should.be.true();
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+options.name+'.pub')).should.be.true();
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should not generate sshkey file with illegal size data', function(done) {
- this.timeout(10000);
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var options = {
- comment: 'test@test.com',
- name: 'test-key01',
- size: 1023
- };
-
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- sshkeys.generateSSHKey(username, options).then(function(retObj) {
- done(new Error('Does NOT throw error!'));
- }).catch(function(err) {
- try {
- err.should.have.property('code', 'key_length_too_short');
- done();
- }
- catch (error) {
- done(error);
- }
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should not generate sshkey file with illegal password', function(done) {
- this.timeout(10000);
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var options = {
- comment: 'test@test.com',
- name: 'test-key01',
- password: 'aa'
- };
-
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- sshkeys.generateSSHKey(username, options).then(function(retObj) {
- done(new Error('Does NOT throw error!'));
- }).catch(function(err) {
- try {
- err.should.have.property('code', 'key_passphrase_too_short');
- done();
- }
- catch (error) {
- done(error);
- }
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should get sshkey file content', function(done) {
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var filename = 'test-key01';
- var fileContent = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD3a+sgtgzSbbliWxmOq5p6+H/mE+0gjWfLWrkIVmHENd1mifV4uCmIHAR2NfuadUYMQ3+bQ90kpmmEKTMYPsyentsKpHQZxTzG7wOCAIpJnbPTHDMxEJhVTaAwEjbVyMSIzTTPfnhoavWIBu0+uMgKDDlBm+RjlgkFlyhXyCN6UwFrIUUMH6Gw+eQHLiooKIl8ce7uDxIlt+9b7hFCU+sQ3kvuse239DZluu6+8buMWqJvrEHgzS9adRFKku8nSPAEPYn85vDi7OgVAcLQufknNgs47KHBAx9h04LeSrFJ/P5J1b//ItRpMOIme+O9d1BR46puzhvUaCHLdvO9czj+OmW+dIm+QIk6lZIOOMnppG72kZxtLfeKT16ur+2FbwAdL9ItBp4BI/YTlBPoa5mLMxpuWfmX1qHntvtGc9wEwS1P7YFfmF3XiK5apxalzrn0Qlr5UmDNbVIqJb1OlbC0w03Z0oktti1xT+R2DGOLWM4lBbpXDHV1BhQ7oYOvbUD8Cnof55lTP0WHHsOHlQc/BGDti1XA9aBX/OzVyzBUYEf0pkimsD0RYo6aqt7QwehJYdlz9x1NBguBffT0s4NhNb9IWr+ASnFPvNl2sw4XH/8U0J0q8ZkMpKkbLM1Zdp1Fv00GF0f5UNRokai6uM3w/ccantJ3WvZ6GtctqytWrw== \n";
-
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename),"","utf8");
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename+".pub"),fileContent,"utf8");
- sshkeys.getSSHKey(username, filename).then(function(retObj) {
- retObj.should.be.equal(fileContent);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should delete sshkey files', function(done) {
- var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
- var username = 'test';
- var filename = 'test-key01';
- var fileContent = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQD3a+sgtgzSbbliWxmOq5p6+H/mE+0gjWfLWrkIVmHENd1mifV4uCmIHAR2NfuadUYMQ3+bQ90kpmmEKTMYPsyentsKpHQZxTzG7wOCAIpJnbPTHDMxEJhVTaAwEjbVyMSIzTTPfnhoavWIBu0+uMgKDDlBm+RjlgkFlyhXyCN6UwFrIUUMH6Gw+eQHLiooKIl8ce7uDxIlt+9b7hFCU+sQ3kvuse239DZluu6+8buMWqJvrEHgzS9adRFKku8nSPAEPYn85vDi7OgVAcLQufknNgs47KHBAx9h04LeSrFJ/P5J1b//ItRpMOIme+O9d1BR46puzhvUaCHLdvO9czj+OmW+dIm+QIk6lZIOOMnppG72kZxtLfeKT16ur+2FbwAdL9ItBp4BI/YTlBPoa5mLMxpuWfmX1qHntvtGc9wEwS1P7YFfmF3XiK5apxalzrn0Qlr5UmDNbVIqJb1OlbC0w03Z0oktti1xT+R2DGOLWM4lBbpXDHV1BhQ7oYOvbUD8Cnof55lTP0WHHsOHlQc/BGDti1XA9aBX/OzVyzBUYEf0pkimsD0RYo6aqt7QwehJYdlz9x1NBguBffT0s4NhNb9IWr+ASnFPvNl2sw4XH/8U0J0q8ZkMpKkbLM1Zdp1Fv00GF0f5UNRokai6uM3w/ccantJ3WvZ6GtctqytWrw== \n";
-
- sshkeys.init(mockSettings, mockRuntime).then(function() {
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename),"","utf8");
- fs.writeFileSync(path.join(sshkeyDirPath,username+"_"+filename+".pub"),fileContent,"utf8");
- sshkeys.deleteSSHKey(username, filename).then(function() {
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+filename)).should.be.false();
- fs.existsSync(path.join(sshkeyDirPath,username+'_'+filename+'.pub')).should.be.false();
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/keygen_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/keygen_spec.js
deleted file mode 100644
index f3487277b..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/projects/ssh/keygen_spec.js
+++ /dev/null
@@ -1,110 +0,0 @@
-/**
- * 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 child_process = require('child_process');
-var EventEmitter = require("events");
-
-var NR_TEST_UTILS = require("nr-test-utils");
-var keygen = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/projects/ssh/keygen")
-
-describe("localfilesystem/projects/ssh/keygen", function() {
-
- afterEach(function() {
- if (child_process.spawn.restore) {
- child_process.spawn.restore();
- }
- })
-
- it("invokes sshkeygen", function(done) {
- var command;
- var args;
- var opts;
- sinon.stub(child_process,"spawn").callsFake(function(_command,_args,_opts) {
- _command = command;
- _args = args;
- _opts = opts;
-
- var e = new EventEmitter();
- e.stdout = new EventEmitter();
- e.stderr = new EventEmitter();
- setTimeout(function() {
- e.stdout.emit("data","result");
- e.emit("close",0);
- },50)
- return e;
- });
-
- keygen.generateKey({
- size: 1024,
- location: 'location',
- comment: 'comment',
- password: 'password'
- }).then(function(output) {
- output.should.equal("result");
- done();
- }).catch(function(err) {
- done(err);
- })
- })
-
- it("reports passphrase too short", function(done) {
- var command;
- var args;
- var opts;
-
- try {
- keygen.generateKey({
- size: 1024,
- location: 'location',
- comment: 'comment',
- password: '123'
- }).then(function(output) {
- done(new Error("Error not thrown"));
- }).catch(function(err) {
- done(new Error("Error not thrown"));
- })
- } catch(err) {
- err.should.have.property("code","key_passphrase_too_short");
- done();
- }
- });
-
- it("reports key length too short", function(done) {
- var command;
- var args;
- var opts;
- try {
- keygen.generateKey({
- size: 123,
- location: 'location',
- comment: 'comment',
- password: 'password'
- }).then(function(output) {
- done(new Error("Error not thrown"));
- }).catch(function(err) {
- done(new Error("Error not thrown"));
- })
- } catch(err) {
- err.should.have.property("code","key_length_too_short");
- done();
-
- }
- });
-
-
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/sessions_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/sessions_spec.js
deleted file mode 100644
index 685886d67..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/sessions_spec.js
+++ /dev/null
@@ -1,80 +0,0 @@
-/**
- * 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 fs = require('fs-extra');
-var path = require('path');
-
-var NR_TEST_UTILS = require("nr-test-utils");
-var localfilesystemSessions = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/sessions");
-
-describe('storage/localfilesystem/sessions', function() {
- var userDir = path.join(__dirname,".testUserHome");
- beforeEach(function(done) {
- fs.remove(userDir,function(err) {
- fs.mkdir(userDir,done);
- });
- });
- afterEach(function(done) {
- fs.remove(userDir,done);
- });
- it('should handle non-existent sessions', function(done) {
- var sessionsFile = path.join(userDir,".sessions.json");
-
- localfilesystemSessions.init({userDir:userDir});
- fs.existsSync(sessionsFile).should.be.false();
- localfilesystemSessions.getSessions().then(function(sessions) {
- sessions.should.eql({});
- done();
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should handle corrupt sessions', function(done) {
- var sessionsFile = path.join(userDir,".sessions.json");
- fs.writeFileSync(sessionsFile,"[This is not json","utf8");
- localfilesystemSessions.init({userDir:userDir});
- fs.existsSync(sessionsFile).should.be.true();
- localfilesystemSessions.getSessions().then(function(sessions) {
- sessions.should.eql({});
- done();
- }).catch(function(err) {
- done(err);
- });
- });
-
- it('should handle sessions', function(done) {
- var sessionsFile = path.join(userDir,".sessions.json");
-
- localfilesystemSessions.init({userDir:userDir});
- fs.existsSync(sessionsFile).should.be.false();
-
- var sessions = {"abc":{"type":"creds"}};
-
- localfilesystemSessions.saveSessions(sessions).then(function() {
- fs.existsSync(sessionsFile).should.be.true();
- localfilesystemSessions.getSessions().then(function(_sessions) {
- _sessions.should.eql(sessions);
- done();
- }).catch(function(err) {
- done(err);
- });
- }).catch(function(err) {
- done(err);
- });
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/settings_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/settings_spec.js
deleted file mode 100644
index bd07ca27f..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/settings_spec.js
+++ /dev/null
@@ -1,134 +0,0 @@
-/**
- * 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.
- **/
-
-const should = require("should");
-const fs = require('fs-extra');
-const path = require('path');
-
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var localfilesystemSettings = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/settings");
-
-describe('storage/localfilesystem/settings', function() {
- var userDir = path.join(__dirname,".testUserHome");
- beforeEach(function(done) {
- fs.remove(userDir,function(err) {
- fs.mkdir(userDir,done);
- });
- });
- afterEach(function(done) {
- fs.remove(userDir,done);
- });
-
- it('should handle non-existent settings', function(done) {
- var settingsFile = path.join(userDir,".config.json");
- localfilesystemSettings.init({userDir:userDir}).then(function() {
- fs.existsSync(settingsFile).should.be.false();
- return localfilesystemSettings.getSettings();
- }).then(function(settings) {
- settings.should.eql({});
- done();
- }).catch(err => { done(err)});
- });
-
- it('should migrate single config.json to multiple files', function(done) {
- var settingsFile = path.join(userDir,".config.json");
- fs.writeFileSync(settingsFile,JSON.stringify({
- nodes:{a:1},
- _credentialSecret: "foo",
- users:{b:2},
- projects: {c:3}
- }),"utf8");
-
- async function checkFile(sectionName, expectedContents) {
- const file = path.join(userDir,".config."+sectionName+".json");
- fs.existsSync(file).should.be.true();
- var contents = await fs.readFile(file,'utf8');
- var data = JSON.parse(contents);
- data.should.eql(expectedContents)
- }
-
- localfilesystemSettings.init({userDir:userDir}).then(async function() {
- // (For now) leave the old settings file in place
- fs.existsSync(settingsFile).should.be.true();
- await checkFile("nodes",{a:1})
- await checkFile("users",{b:2})
- await checkFile("projects",{c:3})
- await checkFile("runtime",{_credentialSecret:"foo"})
- done();
- }).catch(err => { done(err)});
- });
-
- it('should load separate settings file', async function() {
- await fs.writeFile( path.join(userDir,".config.nodes.json"),JSON.stringify({a:1}),"utf8");
- await fs.writeFile( path.join(userDir,".config.users.json"),JSON.stringify({b:2}),"utf8");
- await fs.writeFile( path.join(userDir,".config.projects.json"),JSON.stringify({c:3}),"utf8");
- await fs.writeFile( path.join(userDir,".config.runtime.json"),JSON.stringify({_credentialSecret:"foo"}),"utf8");
-
- return localfilesystemSettings.init({userDir:userDir})
- .then(localfilesystemSettings.getSettings)
- .then(settings => {
- settings.should.eql({
- nodes:{a:1},
- _credentialSecret: "foo",
- users:{b:2},
- projects: {c:3}
- })
- })
- });
-
- it('should write only the files that need writing', async function() {
- await fs.writeFile( path.join(userDir,".config.nodes.json"),JSON.stringify({a:1}),"utf8");
- await fs.writeFile( path.join(userDir,".config.users.json"),JSON.stringify({b:2}),"utf8");
- await fs.writeFile( path.join(userDir,".config.projects.json"),JSON.stringify({c:3}),"utf8");
- await fs.writeFile( path.join(userDir,".config.runtime.json"),JSON.stringify({_credentialSecret:"foo"}),"utf8");
-
- const fsStatNodes = await fs.stat(path.join(userDir,".config.nodes.json"))
- const fsStatUsers = await fs.stat(path.join(userDir,".config.users.json"))
- const fsStatProjects = await fs.stat(path.join(userDir,".config.projects.json"))
- const fsStatRuntime = await fs.stat(path.join(userDir,".config.runtime.json"))
-
- return localfilesystemSettings.init({userDir:userDir}).then(function() {
- return new Promise(res => {
- setTimeout(function() {
- res();
- },10)
- });
- }).then(() => {
- return localfilesystemSettings.saveSettings({
- nodes:{d:4},
- _credentialSecret: "bar",
- users:{b:2},
- projects: {c:3}
- })
- }).then(async function() {
-
- const newFsStatNodes = await fs.stat(path.join(userDir,".config.nodes.json"))
- const newFsStatUsers = await fs.stat(path.join(userDir,".config.users.json"))
- const newFsStatProjects = await fs.stat(path.join(userDir,".config.projects.json"))
- const newFsStatRuntime = await fs.stat(path.join(userDir,".config.runtime.json"))
-
- // Not changed
- newFsStatUsers.mtimeMs.should.eql(fsStatUsers.mtimeMs);
- newFsStatProjects.mtimeMs.should.eql(fsStatProjects.mtimeMs);
-
- // Changed
- newFsStatNodes.mtimeMs.should.not.eql(fsStatNodes.mtimeMs);
- newFsStatRuntime.mtimeMs.should.not.eql(fsStatRuntime.mtimeMs);
-
- })
- });
-});
diff --git a/test/unit/@node-red/runtime/lib/storage/localfilesystem/util_spec.js b/test/unit/@node-red/runtime/lib/storage/localfilesystem/util_spec.js
deleted file mode 100644
index fa1e4bdb7..000000000
--- a/test/unit/@node-red/runtime/lib/storage/localfilesystem/util_spec.js
+++ /dev/null
@@ -1,32 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-var util = NR_TEST_UTILS.require("@node-red/runtime/lib/storage/localfilesystem/util");
-
-describe('storage/localfilesystem/util', function() {
- describe('parseJSON', function() {
- it('returns parsed JSON', function() {
- var result = util.parseJSON('{"a":123}');
- result.should.eql({a:123});
- })
- it('ignores BOM character', function() {
- var result = util.parseJSON('\uFEFF{"a":123}');
- result.should.eql({a:123});
- })
- })
-});
diff --git a/test/unit/@node-red/util/index_spec.js b/test/unit/@node-red/util/index_spec.js
deleted file mode 100644
index ee46fc504..000000000
--- a/test/unit/@node-red/util/index_spec.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-
-describe("node-red/red", function() {
- it.skip("NEEDS TESTS WRITING",function() {});
-});
diff --git a/test/unit/@node-red/util/lib/events_spec.js b/test/unit/@node-red/util/lib/events_spec.js
deleted file mode 100644
index 09f5d2ae0..000000000
--- a/test/unit/@node-red/util/lib/events_spec.js
+++ /dev/null
@@ -1,25 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-
-describe("@node-red/util/events", function() {
- it('can be required without errors', function() {
- NR_TEST_UTILS.require("@node-red/util/lib/events");
- });
- it.skip('more tests needed', function(){})
-});
diff --git a/test/unit/@node-red/util/lib/exec_spec.js b/test/unit/@node-red/util/lib/exec_spec.js
deleted file mode 100644
index 9b02fb3f1..000000000
--- a/test/unit/@node-red/util/lib/exec_spec.js
+++ /dev/null
@@ -1,140 +0,0 @@
-/**
- * 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 path = require("path");
-var EventEmitter = require("events").EventEmitter;
-
-
-var child_process = require('child_process');
-
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var events = NR_TEST_UTILS.require("@node-red/util/lib/events");
-var exec = NR_TEST_UTILS.require("@node-red/util/lib/exec");
-
-describe("runtime/exec", function() {
- var logEvents;
- var mockProcess;
- const eventLogHandler = function(ev) {
- logEvents.push(ev);
- }
-
- beforeEach(function() {
-
- logEvents = [];
- events.on("event-log", eventLogHandler);
-
- mockProcess = new EventEmitter();
- mockProcess.stdout = new EventEmitter();
- mockProcess.stderr = new EventEmitter();
- sinon.stub(child_process,'spawn').callsFake(function(command,args,options) {
- mockProcess._args = {command,args,options};
- return mockProcess;
- });
- });
-
- afterEach(function() {
- events.removeListener("event-log", eventLogHandler);
- if (child_process.spawn.restore) {
- child_process.spawn.restore();
- }
- });
-
- it("runs command and resolves on success - no emit", function(done) {
- var command = "cmd";
- var args = [1,2,3];
- var opts = { a: true };
- exec.run(command,args,opts).then(function(result) {
- command.should.eql(mockProcess._args.command);
- args.should.eql(mockProcess._args.args);
- opts.should.eql(mockProcess._args.options);
- logEvents.length.should.eql(0);
- result.code.should.eql(0);
- result.stdout.should.eql("123");
- result.stderr.should.eql("abc");
- done();
- }).catch(done);
-
- mockProcess.stdout.emit('data',"1");
- mockProcess.stderr.emit('data',"a");
- mockProcess.stderr.emit('data',"b");
- mockProcess.stdout.emit('data',"2");
- mockProcess.stdout.emit('data',"3");
- mockProcess.stderr.emit('data',"c");
- mockProcess.emit('close',0);
- });
-
- it("runs command and resolves on success - emit", function(done) {
- var command = "cmd";
- var args = [1,2,3];
- var opts = { a: true };
- exec.run(command,args,opts,true).then(function(result) {
- logEvents.length.should.eql(8);
- done();
- }).catch(done);
-
- mockProcess.stdout.emit('data',"1");
- mockProcess.stderr.emit('data',"a");
- mockProcess.stderr.emit('data',"b");
- mockProcess.stdout.emit('data',"2");
- mockProcess.stdout.emit('data',"3");
- mockProcess.stderr.emit('data',"c");
- mockProcess.emit('close',0);
- })
-
- it("runs command and rejects on error - close", function(done) {
- var command = "cmd";
- var args = [1,2,3];
- var opts = { a: true };
- exec.run(command,args,opts).then(function() {
- done("Command should have rejected");
- }).catch(function(result) {
- result
- result.code.should.eql(123);
- result.stdout.should.eql("123");
- result.stderr.should.eql("abc");
- done();
- }).catch(done);
-
- mockProcess.stdout.emit('data',"1");
- mockProcess.stderr.emit('data',"a");
- mockProcess.stderr.emit('data',"b");
- mockProcess.stdout.emit('data',"2");
- mockProcess.stdout.emit('data',"3");
- mockProcess.stderr.emit('data',"c");
- mockProcess.emit('close',123);
- })
-
- it("runs command and rejects on error - error", function(done) {
- var command = "cmd";
- var args = [1,2,3];
- var opts = { a: true };
- exec.run(command,args,opts).then(function() {
- done("Command should have rejected");
- }).catch(function(result) {
- result
- result.code.should.eql(456);
- result.stdout.should.eql("");
- result.stderr.should.eql("test-error");
- done();
- }).catch(done);
-
- mockProcess.emit('error',"test-error");
- mockProcess.emit('close',456);
- })
-
-});
diff --git a/test/unit/@node-red/util/lib/hooks_spec.js b/test/unit/@node-red/util/lib/hooks_spec.js
deleted file mode 100644
index 4b25f33d2..000000000
--- a/test/unit/@node-red/util/lib/hooks_spec.js
+++ /dev/null
@@ -1,338 +0,0 @@
-const should = require("should");
-const NR_TEST_UTILS = require("nr-test-utils");
-
-const hooks = NR_TEST_UTILS.require("@node-red/util/lib/hooks");
-
-describe("util/hooks", function() {
- afterEach(function() {
- hooks.clear();
- })
- it("allows a hook to be registered", function(done) {
- let calledWith = null;
- hooks.has("onSend").should.be.false();
- hooks.add("onSend", function(payload) { calledWith = payload } )
- hooks.has("onSend").should.be.true();
- let data = { a: 1 };
- hooks.trigger("onSend",data,err => {
- calledWith.should.equal(data);
- done(err);
- })
- })
- it("rejects invalid hook id", function(done) {
- try {
- hooks.add("foo", function(payload) {})
- done(new Error("Invalid hook accepted"))
- } catch(err) {
- done();
- }
- })
- it("calls hooks in the order they were registered", function(done) {
- hooks.add("onSend", function(payload) { payload.order.push("A") } )
- hooks.add("onSend", function(payload) { payload.order.push("B") } )
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql(["A","B"])
- done(err);
- })
- })
-
- it("does not allow multiple hooks with same id.label", function() {
- hooks.has("onSend.one").should.be.false();
- hooks.has("onSend").should.be.false();
- hooks.add("onSend.one", function(payload) { payload.order.push("A") } );
- hooks.has("onSend.one").should.be.true();
- hooks.has("onSend").should.be.true();
- (function() {
- hooks.add("onSend.one", function(payload) { payload.order.push("B") } )
- }).should.throw();
- })
-
- it("removes labelled hook", function(done) {
- hooks.has("onSend.A").should.be.false();
- hooks.has("onSend.B").should.be.false();
- hooks.has("onSend").should.be.false();
-
- hooks.add("onSend.A", function(payload) { payload.order.push("A") } )
-
- hooks.has("onSend.A").should.be.true();
- hooks.has("onSend.B").should.be.false();
- hooks.has("onSend").should.be.true();
-
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- hooks.has("onSend.A").should.be.true();
- hooks.has("onSend.B").should.be.true();
- hooks.has("onSend").should.be.true();
-
- hooks.remove("onSend.A");
-
- hooks.has("onSend.A").should.be.false();
- hooks.has("onSend.B").should.be.true();
- hooks.has("onSend").should.be.true();
-
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- try {
- data.order.should.eql(["B"])
-
- hooks.remove("onSend.B");
-
- hooks.has("onSend.A").should.be.false();
- hooks.has("onSend.B").should.be.false();
- hooks.has("onSend").should.be.false();
-
- done(err);
- } catch(err2) {
- done(err2);
- }
- })
- })
-
- it("cannot remove unlabelled hook", function() {
- hooks.add("onSend", function(payload) { payload.order.push("A") } );
- (function() {
- hooks.remove("onSend")
- }).should.throw();
- })
- it("removes all hooks with same label", function(done) {
- hooks.add("onSend.A", function(payload) { payload.order.push("A") } )
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
- hooks.add("preRoute.A", function(payload) { payload.order.push("C") } )
- hooks.add("preRoute.B", function(payload) { payload.order.push("D") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql(["A","B"])
- hooks.trigger("preRoute", data, err => {
- data.order.should.eql(["A","B","C","D"])
-
- data.order = [];
-
- hooks.remove("*.A");
-
- hooks.trigger("onSend",data,err => {
- data.order.should.eql(["B"])
- hooks.trigger("preRoute", data, err => {
- data.order.should.eql(["B","D"])
- })
- done(err);
- })
- })
- })
- })
- it("allows a hook to remove itself whilst being called", function(done) {
- let data = { order: [] }
- hooks.add("onSend.A", function(payload) { payload.order.push("A") } )
- hooks.add("onSend.B", function(payload) {
- hooks.remove("*.B");
- })
- hooks.add("onSend.C", function(payload) { payload.order.push("C") } )
- hooks.add("onSend.D", function(payload) { payload.order.push("D") } )
-
- hooks.trigger("onSend", data, err => {
- try {
- should.not.exist(err);
- data.order.should.eql(["A","C","D"])
- done();
- } catch(e) {
- done(e);
- }
- })
- });
-
- it("allows a hook to remove itself and others whilst being called", function(done) {
- let data = { order: [] }
- hooks.add("onSend.A", function(payload) { payload.order.push("A") } )
- hooks.add("onSend.B", function(payload) {
- hooks.remove("*.B");
- hooks.remove("*.C");
- })
- hooks.add("onSend.C", function(payload) { payload.order.push("C") } )
- hooks.add("onSend.D", function(payload) { payload.order.push("D") } )
-
- hooks.trigger("onSend", data, err => {
- try {
- should.not.exist(err);
- data.order.should.eql(["A","D"])
- done();
- } catch(e) {
- done(e);
- }
- })
- });
-
- it("halts execution on return false", function(done) {
- hooks.add("onSend.A", function(payload) { payload.order.push("A"); return false } )
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql(["A"])
- err.should.be.false();
- done();
- })
- })
- it("halts execution on thrown error", function(done) {
- hooks.add("onSend.A", function(payload) { payload.order.push("A"); throw new Error("error") } )
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql(["A"])
- should.exist(err);
- err.should.not.be.false()
- done();
- })
- })
-
- it("handler can use callback function", function(done) {
- hooks.add("onSend.A", function(payload, done) {
- setTimeout(function() {
- payload.order.push("A")
- done()
- },30)
- })
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql(["A","B"])
- done(err);
- })
- })
-
- it("handler can use callback function - halt execution", function(done) {
- hooks.add("onSend.A", function(payload, done) {
- setTimeout(function() {
- payload.order.push("A")
- done(false)
- },30)
- })
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql(["A"])
- err.should.be.false()
- done();
- })
- })
- it("handler can use callback function - halt on error", function(done) {
- hooks.add("onSend.A", function(payload, done) {
- setTimeout(function() {
- done(new Error("test error"))
- },30)
- })
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql([])
- should.exist(err);
- err.should.not.be.false()
- done();
- })
- })
-
- it("handler be an async function", function(done) {
- hooks.add("onSend.A", async function(payload) {
- return new Promise(resolve => {
- setTimeout(function() {
- payload.order.push("A")
- resolve()
- },30)
- });
- })
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql(["A","B"])
- done(err);
- })
- })
-
- it("handler be an async function - halt execution", function(done) {
- hooks.add("onSend.A", async function(payload) {
- return new Promise(resolve => {
- setTimeout(function() {
- payload.order.push("A")
- resolve(false)
- },30)
- });
- })
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql(["A"])
- done(err);
- })
- })
- it("handler be an async function - halt on error", function(done) {
- hooks.add("onSend.A", async function(payload) {
- return new Promise((resolve,reject) => {
- setTimeout(function() {
- reject(new Error("test error"))
- },30)
- });
- })
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data,err => {
- data.order.should.eql([])
- should.exist(err);
- err.should.not.be.false()
- done();
- })
- })
-
-
- it("handler can use callback function - promise API", function(done) {
- hooks.add("onSend.A", function(payload, done) {
- setTimeout(function() {
- payload.order.push("A")
- done()
- },30)
- })
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data).then(() => {
- data.order.should.eql(["A","B"])
- done()
- }).catch(done)
- })
-
- it("handler can halt execution - promise API", function(done) {
- hooks.add("onSend.A", function(payload, done) {
- setTimeout(function() {
- payload.order.push("A")
- done(false)
- },30)
- })
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data).then(() => {
- data.order.should.eql(["A"])
- done()
- }).catch(done)
- })
-
- it("handler can halt execution on error - promise API", function(done) {
- hooks.add("onSend.A", function(payload, done) {
- throw new Error("error");
- })
- hooks.add("onSend.B", function(payload) { payload.order.push("B") } )
-
- let data = { order:[] };
- hooks.trigger("onSend",data).then(() => {
- done("hooks.trigger resolved unexpectedly")
- }).catch(err => {
- done();
- })
- })
-});
diff --git a/test/unit/@node-red/util/lib/i18n_spec.js b/test/unit/@node-red/util/lib/i18n_spec.js
deleted file mode 100644
index 5deaba032..000000000
--- a/test/unit/@node-red/util/lib/i18n_spec.js
+++ /dev/null
@@ -1,26 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-
- var i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
-
-
-describe("@node-red/util/i18n", function() {
- it.skip('more tests needed', function(){})
-});
diff --git a/test/unit/@node-red/util/lib/index_spec.js b/test/unit/@node-red/util/lib/index_spec.js
deleted file mode 100644
index 3cf2347c1..000000000
--- a/test/unit/@node-red/util/lib/index_spec.js
+++ /dev/null
@@ -1,19 +0,0 @@
-/**
- * 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.
- **/
-
-describe("@node-red/util", function() {
- it.skip('more tests needed', function(){})
-});
diff --git a/test/unit/@node-red/util/lib/log_spec.js b/test/unit/@node-red/util/lib/log_spec.js
deleted file mode 100644
index 056f37672..000000000
--- a/test/unit/@node-red/util/lib/log_spec.js
+++ /dev/null
@@ -1,252 +0,0 @@
-/**
- * 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 util = require("util");
-
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var log = NR_TEST_UTILS.require("@node-red/util").log;
-
-
-describe("@node-red/util/log", function() {
- beforeEach(function () {
- var spy = sinon.stub(util, 'log').callsFake(function(arg){});
- var settings = {logging: { console: { level: 'metric', metrics: true } } };
- log.init(settings);
- });
-
- afterEach(function() {
- util.log.restore();
- });
-
- it('it can raise an error', function() {
- var ret = log.error("This is an error");
- sinon.assert.calledWithMatch(util.log,"[error] This is an error");
- });
-
- it('it can raise a trace', function() {
- var ret = log.trace("This is a trace");
- sinon.assert.calledWithMatch(util.log,"[trace] This is a trace");
- });
-
- it('it can raise a debug', function() {
- var ret = log.debug("This is a debug");
- sinon.assert.calledWithMatch(util.log,"[debug] This is a debug");
- });
-
- it('it can raise a info', function() {
- var ret = log.info("This is an info");
- sinon.assert.calledWithMatch(util.log,"[info] This is an info");
- });
-
- it('it can raise a warn', function() {
- var ret = log.warn("This is a warn");
- sinon.assert.calledWithMatch(util.log,"[warn] This is a warn");
- });
-
- it('it can raise a metric', function() {
- var metrics = {};
- metrics.level = log.METRIC;
- metrics.nodeid = "testid";
- metrics.event = "node.test.testevent";
- metrics.msgid = "12345";
- metrics.value = "the metric payload";
- var ret = log.log(metrics);
- util.log.calledOnce.should.be.true();
- util.log.firstCall.args[0].indexOf("[metric] ").should.equal(0);
- var body = JSON.parse(util.log.firstCall.args[0].substring(9));
- body.should.have.a.property("nodeid","testid");
- body.should.have.a.property("event","node.test.testevent");
- body.should.have.a.property("msgid","12345");
- body.should.have.a.property("value","the metric payload");
- body.should.have.a.property("timestamp");
- body.should.have.a.property("level",log.METRIC);
- });
-
- it('it checks metrics are enabled', function() {
- log.metric().should.equal(true);
- var sett = {logging: { console: { level: 'info', metrics: false } } };
- log.init(sett);
- log.metric().should.equal(false);
- });
-
- it('it logs node type and name if provided',function() {
- log.log({level:log.INFO,type:"nodeType",msg:"test",name:"nodeName",id:"nodeId"});
- util.log.calledOnce.should.be.true();
- util.log.firstCall.args[0].indexOf("[nodeType:nodeName]").should.not.equal(-1);
- });
- it('it logs node type and id if no name provided',function() {
- log.log({level:log.INFO,type:"nodeType",msg:"test",id:"nodeId"});
- util.log.calledOnce.should.be.true();
- util.log.firstCall.args[0].indexOf("[nodeType:nodeId]").should.not.equal(-1);
- });
-
- it('ignores lower level messages and metrics', function() {
- var settings = {logging: { console: { level: 'warn', metrics: false } } };
- log.init(settings);
- log.error("This is an error");
- log.warn("This is a warn");
- log.info("This is an info");
- log.debug("This is a debug");
- log.trace("This is a trace");
- log.log({level:log.METRIC,msg:"testMetric"});
- sinon.assert.calledWithMatch(util.log,"[error] This is an error");
- sinon.assert.calledWithMatch(util.log,"[warn] This is a warn");
- sinon.assert.neverCalledWithMatch(util.log,"[info] This is an info");
- sinon.assert.neverCalledWithMatch(util.log,"[debug] This is a debug");
- sinon.assert.neverCalledWithMatch(util.log,"[trace] This is a trace");
- sinon.assert.neverCalledWithMatch(util.log,"[metric] ");
- });
- it('ignores lower level messages but accepts metrics', function() {
- var settings = {logging: { console: { level: 'log', metrics: true } } };
- log.init(settings);
- log.error("This is an error");
- log.warn("This is a warn");
- log.info("This is an info");
- log.debug("This is a debug");
- log.trace("This is a trace");
- log.log({level:log.METRIC,msg:"testMetric"});
- sinon.assert.calledWithMatch(util.log,"[error] This is an error");
- sinon.assert.calledWithMatch(util.log,"[warn] This is a warn");
- sinon.assert.calledWithMatch(util.log,"[info] This is an info");
- sinon.assert.neverCalledWithMatch(util.log,"[debug] This is a debug");
- sinon.assert.neverCalledWithMatch(util.log,"[trace] This is a trace");
- sinon.assert.calledWithMatch(util.log,"[metric] ");
- });
-
- it('default settings set to INFO and metrics off', function() {
- log.init({logging:{}});
- log.error("This is an error");
- log.warn("This is a warn");
- log.info("This is an info");
- log.debug("This is a debug");
- log.trace("This is a trace");
- log.log({level:log.METRIC,msg:"testMetric"});
- sinon.assert.calledWithMatch(util.log,"[error] This is an error");
- sinon.assert.calledWithMatch(util.log,"[warn] This is a warn");
- sinon.assert.calledWithMatch(util.log,"[info] This is an info");
- sinon.assert.neverCalledWithMatch(util.log,"[debug] This is a debug");
- sinon.assert.neverCalledWithMatch(util.log,"[trace] This is a trace");
- sinon.assert.neverCalledWithMatch(util.log,"[metric] ");
- });
- it('no logger used if custom logger handler does not exist', function() {
- var settings = {logging: { customLogger: { level: 'trace', metrics: true } } };
- log.init(settings);
- log.error("This is an error");
- log.warn("This is a warn");
- log.info("This is an info");
- log.debug("This is a debug");
- log.trace("This is a trace");
- log.log({level:log.METRIC,msg:"testMetric"});
- sinon.assert.neverCalledWithMatch(util.log,"[error] This is an error");
- sinon.assert.neverCalledWithMatch(util.log,"[warn] This is a warn");
- sinon.assert.neverCalledWithMatch(util.log,"[info] This is an info");
- sinon.assert.neverCalledWithMatch(util.log,"[debug] This is a debug");
- sinon.assert.neverCalledWithMatch(util.log,"[trace] This is a trace");
- sinon.assert.neverCalledWithMatch(util.log,"[metric] ");
- });
-
- it('add a custom log handler directly', function() {
- var settings = {};
- log.init(settings);
-
- var logEvents = [];
- var loggerOne = {
- emit: function(event,msg) {
- logEvents.push({logger:1,msg:msg});
- }
- };
- var loggerTwo = {
- emit: function(event,msg) {
- logEvents.push({logger:2,msg:msg});
- }
- };
- log.addHandler(loggerOne);
- log.addHandler(loggerTwo);
-
- log.error("This is an error");
- log.warn("This is a warn");
- log.info("This is an info");
- log.debug("This is a debug");
- log.trace("This is a trace");
- log.log({level:log.METRIC,msg:"testMetric"});
-
- logEvents.filter(function(evt) { return evt.logger === 1}).should.have.lengthOf(6);
- logEvents.filter(function(evt) { return evt.logger === 2}).should.have.lengthOf(6);
- });
-
- it('remove a custom log handler directly', function() {
- var settings = {};
- log.init(settings);
-
- var logEvents = [];
- var loggerOne = {
- emit: function(event,msg) {
- logEvents.push({logger:1,msg:msg});
- }
- };
- var loggerTwo = {
- emit: function(event,msg) {
- logEvents.push({logger:2,msg:msg});
- }
- };
- log.addHandler(loggerOne);
- log.addHandler(loggerTwo);
-
- log.info("This is an info");
- logEvents.filter(function(evt) { return evt.logger === 1}).should.have.lengthOf(1);
- logEvents.filter(function(evt) { return evt.logger === 2}).should.have.lengthOf(1);
-
-
- log.removeHandler(loggerTwo);
- log.info("This is an info");
- logEvents.filter(function(evt) { return evt.logger === 1}).should.have.lengthOf(2);
- logEvents.filter(function(evt) { return evt.logger === 2}).should.have.lengthOf(1);
-
- log.removeHandler(loggerOne);
- log.info("This is an info");
- logEvents.filter(function(evt) { return evt.logger === 1}).should.have.lengthOf(2);
- logEvents.filter(function(evt) { return evt.logger === 2}).should.have.lengthOf(1);
-
-
- });
- it('it can log without exception', function() {
- var msg = {
- msg: {
- mystrangeobj:"hello",
- },
- };
- msg.msg.toString = function(){
- throw new Error('Exception in toString - should have been caught');
- }
- msg.msg.constructor = { name: "strangeobj" };
- var ret = log.info(msg.msg);
- });
- it('it can log an object but use .message', function() {
- var msg = {
- msg: {
- message: "my special message",
- mystrangeobj:"hello",
- },
- };
- var ret = log.info(msg.msg);
- sinon.assert.calledWithMatch(util.log,"my special message");
- });
-
-
-
-});
diff --git a/test/unit/@node-red/util/lib/util_spec.js b/test/unit/@node-red/util/lib/util_spec.js
deleted file mode 100644
index 2013f143e..000000000
--- a/test/unit/@node-red/util/lib/util_spec.js
+++ /dev/null
@@ -1,1110 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-
-var util = NR_TEST_UTILS.require("@node-red/util").util;
-
-describe("@node-red/util/util", function() {
- describe('generateId', function() {
- it('generates an id', function() {
- var id = util.generateId();
- var id2 = util.generateId();
- id.should.not.eql(id2);
- });
- });
- describe('compareObjects', function() {
- it('numbers', function() {
- util.compareObjects(0,0).should.equal(true);
- util.compareObjects(0,1).should.equal(false);
- util.compareObjects(1000,1001).should.equal(false);
- util.compareObjects(1000,1000).should.equal(true);
- util.compareObjects(0,"0").should.equal(false);
- util.compareObjects(1,"1").should.equal(false);
- util.compareObjects(0,null).should.equal(false);
- util.compareObjects(0,undefined).should.equal(false);
- });
- it('strings', function() {
- util.compareObjects("","").should.equal(true);
- util.compareObjects("a","a").should.equal(true);
- util.compareObjects("",null).should.equal(false);
- util.compareObjects("",undefined).should.equal(false);
- });
-
- it('arrays', function() {
- util.compareObjects(["a"],["a"]).should.equal(true);
- util.compareObjects(["a"],["a","b"]).should.equal(false);
- util.compareObjects(["a","b"],["b"]).should.equal(false);
- util.compareObjects(["a"],"a").should.equal(false);
- util.compareObjects([[1],["a"]],[[1],["a"]]).should.equal(true);
- util.compareObjects([[1],["a"]],[["a"],[1]]).should.equal(false);
- });
- it('objects', function() {
- util.compareObjects({"a":1},{"a":1,"b":1}).should.equal(false);
- util.compareObjects({"a":1,"b":1},{"a":1,"b":1}).should.equal(true);
- util.compareObjects({"b":1,"a":1},{"a":1,"b":1}).should.equal(true);
- });
- it('Buffer', function() {
- util.compareObjects(Buffer.from("hello"),Buffer.from("hello")).should.equal(true);
- util.compareObjects(Buffer.from("hello"),Buffer.from("hello ")).should.equal(false);
- util.compareObjects(Buffer.from("hello"),"hello").should.equal(false);
- });
-
- });
-
- describe('ensureString', function() {
- it('strings are preserved', function() {
- util.ensureString('string').should.equal('string');
- });
- it('Buffer is converted', function() {
- var s = util.ensureString(Buffer.from('foo'));
- s.should.equal('foo');
- (typeof s).should.equal('string');
- });
- it('Object is converted to JSON', function() {
- var s = util.ensureString({foo: "bar"});
- (typeof s).should.equal('string');
- should.deepEqual(JSON.parse(s), {foo:"bar"});
- });
- it('stringifies other things', function() {
- var s = util.ensureString(123);
- (typeof s).should.equal('string');
- s.should.equal('123');
- });
- });
-
- describe('ensureBuffer', function() {
- it('Buffers are preserved', function() {
- var b = Buffer.from('');
- util.ensureBuffer(b).should.equal(b);
- });
- it('string is converted', function() {
- var b = util.ensureBuffer('foo');
- var expected = Buffer.from('foo');
- for (var i = 0; i < expected.length; i++) {
- b[i].should.equal(expected[i]);
- }
- Buffer.isBuffer(b).should.equal(true);
- });
- it('Object is converted to JSON', function() {
- var obj = {foo: "bar"}
- var b = util.ensureBuffer(obj);
- Buffer.isBuffer(b).should.equal(true);
- should.deepEqual(JSON.parse(b), obj);
- });
- it('stringifies other things', function() {
- var b = util.ensureBuffer(123);
- Buffer.isBuffer(b).should.equal(true);
- var expected = Buffer.from('123');
- for (var i = 0; i < expected.length; i++) {
- b[i].should.equal(expected[i]);
- }
- });
- });
-
- describe('cloneMessage', function() {
- it('clones a simple message', function() {
- var msg = {string:"hi",array:[1,2,3],object:{a:1,subobject:{b:2}}};
-
- var cloned = util.cloneMessage(msg);
-
- cloned.should.eql(msg);
-
- cloned.should.not.equal(msg);
- cloned.array.should.not.equal(msg.string);
- cloned.object.should.not.equal(msg.object);
- cloned.object.subobject.should.not.equal(msg.object.subobject);
-
- cloned.should.not.have.property("req");
- cloned.should.not.have.property("res");
- });
- it('does not clone http req/res properties', function() {
- var msg = {req:{a:1},res:{b:2}};
-
- var cloned = util.cloneMessage(msg);
-
- cloned.should.eql(msg);
- cloned.should.not.equal(msg);
-
- cloned.req.should.equal(msg.req);
- cloned.res.should.equal(msg.res);
- });
- it('handles undefined values without throwing an error', function() {
- var result = util.cloneMessage(undefined);
- should.not.exist(result);
- })
- });
- describe('getObjectProperty', function() {
- it('gets a property beginning with "msg."', function() {
- // getMessageProperty strips off `msg.` prefixes.
- // getObjectProperty does not
- var obj = { msg: { a: "foo"}, a: "bar"};
- var v = util.getObjectProperty(obj,"msg.a");
- v.should.eql("foo");
- })
- });
- describe('getMessageProperty', function() {
- it('retrieves a simple property', function() {
- var v = util.getMessageProperty({a:"foo"},"msg.a");
- v.should.eql("foo");
- var v2 = util.getMessageProperty({a:"foo"},"a");
- v2.should.eql("foo");
- });
- it('retrieves a nested property', function() {
- var v = util.getMessageProperty({a:"foo",b:{foo:1,bar:2}},"msg.b[msg.a]");
- v.should.eql(1);
- var v2 = util.getMessageProperty({a:"bar",b:{foo:1,bar:2}},"b[msg.a]");
- v2.should.eql(2);
- });
-
- it('should return undefined if property does not exist', function() {
- var v = util.getMessageProperty({a:"foo"},"msg.b");
- should.not.exist(v);
- });
- it('should throw error if property parent does not exist', function() {
- /*jshint immed: false */
- (function() {
- util.getMessageProperty({a:"foo"},"msg.a.b.c");
- }).should.throw();
- });
- it('retrieves a property with array syntax', function() {
- var v = util.getMessageProperty({a:["foo","bar"]},"msg.a[0]");
- v.should.eql("foo");
- var v2 = util.getMessageProperty({a:[null,{b:"foo"}]},"a[1].b");
- v2.should.eql("foo");
- var v3 = util.getMessageProperty({a:[[["foo"]]]},"a[0][0][0]");
- v3.should.eql("foo");
- });
-
- });
- describe('setObjectProperty', function() {
- it('set a property beginning with "msg."', function() {
- // setMessageProperty strips off `msg.` prefixes.
- // setObjectProperty does not
- var obj = {};
- var result = util.setObjectProperty(obj,"msg.a","bar");
- result.should.be.true();
- obj.should.have.property("msg");
- obj.msg.should.have.property("a","bar");
- })
- });
- describe('setMessageProperty', function() {
- it('sets a property', function() {
- var msg = {a:"foo"};
- var result = util.setMessageProperty(msg,"msg.a","bar");
- result.should.be.true();
- msg.a.should.eql('bar');
- });
- it('sets a deep level property', function() {
- var msg = {a:{b:{c:"foo"}}};
- var result = util.setMessageProperty(msg,"msg.a.b.c","bar");
- result.should.be.true();
- msg.a.b.c.should.eql('bar');
- });
- it('creates missing parent properties by default', function() {
- var msg = {a:{}};
- var result = util.setMessageProperty(msg,"msg.a.b.c","bar");
- result.should.be.true();
- msg.a.b.c.should.eql('bar');
- })
- it('does not create missing parent properties', function() {
- var msg = {a:{}};
- var result = util.setMessageProperty(msg,"msg.a.b.c","bar",false);
- result.should.be.false();
- should.not.exist(msg.a.b);
- })
- it('does not create missing parent properties of array', function () {
- var msg = {a:{}};
- var result = util.setMessageProperty(msg, "msg.a.b[1].c", "bar", false);
- result.should.be.false();
- should.not.exist(msg.a.b);
- })
-
- it('does not create missing parent properties of string', function() {
- var msg = {a:"foo"};
- var result = util.setMessageProperty(msg, "msg.a.b.c", "bar", false);
- result.should.be.false();
- should.not.exist(msg.a.b);
- })
- it('does not set property of existing string property', function() {
- var msg = {a:"foo"};
- var result = util.setMessageProperty(msg, "msg.a.b", "bar", false);
- result.should.be.false();
- should.not.exist(msg.a.b);
- })
-
- it('does not set property of existing number property', function() {
- var msg = {a:123};
- var result = util.setMessageProperty(msg, "msg.a.b", "bar", false);
- result.should.be.false();
- should.not.exist(msg.a.b);
- })
- it('does not create missing parent properties of number', function() {
- var msg = {a:123};
- var result = util.setMessageProperty(msg, "msg.a.b.c", "bar", false);
- result.should.be.false();
- should.not.exist(msg.a.b);
- })
-
- it('does not set property of existing boolean property', function() {
- var msg = {a:true};
- var result = util.setMessageProperty(msg, "msg.a.b", "bar", false);
- result.should.be.false();
- should.not.exist(msg.a.b);
- })
- it('does not create missing parent properties of boolean', function() {
- var msg = {a:true};
- var result = util.setMessageProperty(msg, "msg.a.b.c", "bar", false);
- result.should.be.false();
- should.not.exist(msg.a.b);
- })
-
-
- it('deletes property if value is undefined', function() {
- var msg = {a:{b:{c:"foo"}}};
- var result = util.setMessageProperty(msg,"msg.a.b.c",undefined);
- result.should.be.true();
- should.not.exist(msg.a.b.c);
- })
- it('does not create missing parent properties if value is undefined', function() {
- var msg = {a:{}};
- var result = util.setMessageProperty(msg,"msg.a.b.c",undefined);
- result.should.be.false();
- should.not.exist(msg.a.b);
- });
- it('sets a property with array syntax', function() {
- var msg = {a:{b:["foo",{c:["",""]}]}};
- var result = util.setMessageProperty(msg,"msg.a.b[1].c[1]","bar");
- result.should.be.true();
- msg.a.b[1].c[1].should.eql('bar');
- });
- it('creates missing array elements - final property', function() {
- var msg = {a:[]};
- var result = util.setMessageProperty(msg,"msg.a[2]","bar");
- result.should.be.true();
- msg.a.should.have.length(3);
- msg.a[2].should.eql("bar");
- });
- it('creates missing array elements - mid property', function() {
- var msg = {};
- var result = util.setMessageProperty(msg,"msg.a[2].b","bar");
- result.should.be.true();
- msg.a.should.have.length(3);
- msg.a[2].b.should.eql("bar");
- });
- it('creates missing array elements - multi-arrays', function() {
- var msg = {};
- var result = util.setMessageProperty(msg,"msg.a[2][2]","bar");
- result.should.be.true();
- msg.a.should.have.length(3);
- msg.a.should.be.instanceOf(Array);
- msg.a[2].should.have.length(3);
- msg.a[2].should.be.instanceOf(Array);
- msg.a[2][2].should.eql("bar");
- });
- it('does not create missing array elements - mid property', function () {
- var msg = {a:[]};
- var result = util.setMessageProperty(msg, "msg.a[1][1]", "bar", false);
- result.should.be.false();
- msg.a.should.empty();
- });
- it('does not create missing array elements - final property', function() {
- var msg = {a:{}};
- var result = util.setMessageProperty(msg,"msg.a.b[2]","bar",false);
- result.should.be.false();
- should.not.exist(msg.a.b);
- // check it has not been misinterpreted
- msg.a.should.not.have.property("b[2]");
- });
- it('deletes property inside array if value is undefined', function() {
- var msg = {a:[1,2,3]};
- var result = util.setMessageProperty(msg,"msg.a[1]",undefined);
- result.should.be.true();
- msg.a.should.have.length(2);
- msg.a[0].should.eql(1);
- msg.a[1].should.eql(3);
- })
- it('handles nested message property references', function() {
- var obj = {a:"foo",b:{}};
- var result = util.setObjectProperty(obj,"b[msg.a]","bar");
- result.should.be.true();
- obj.b.should.have.property("foo","bar");
- });
- it('handles nested message property references', function() {
- var obj = {a:"foo",b:{"foo":[0,0,0]}};
- var result = util.setObjectProperty(obj,"b[msg.a][2]","bar");
- result.should.be.true();
- obj.b.foo.should.eql([0,0,"bar"])
- });
- });
-
- describe('evaluateNodeProperty', function() {
- it('returns string',function() {
- var result = util.evaluateNodeProperty('hello','str');
- result.should.eql('hello');
- });
- it('returns number',function() {
- var result = util.evaluateNodeProperty('0123','num');
- result.should.eql(123);
- });
- it('returns evaluated json',function() {
- var result = util.evaluateNodeProperty('{"a":123}','json');
- result.should.eql({a:123});
- });
- it('returns regex',function() {
- var result = util.evaluateNodeProperty('^abc$','re');
- result.toString().should.eql("/^abc$/");
- });
- it('returns boolean',function() {
- var result = util.evaluateNodeProperty('true','bool');
- result.should.be.true();
- result = util.evaluateNodeProperty('TrUe','bool');
- result.should.be.true();
- result = util.evaluateNodeProperty('false','bool');
- result.should.be.false();
- result = util.evaluateNodeProperty('','bool');
- result.should.be.false();
- });
- it('returns date',function() {
- var result = util.evaluateNodeProperty('','date');
- (Date.now() - result).should.be.approximately(0,50);
- });
- it('returns bin', function () {
- var result = util.evaluateNodeProperty('[1, 2]','bin');
- result[0].should.eql(1);
- result[1].should.eql(2);
- });
- it('returns msg property',function() {
- var result = util.evaluateNodeProperty('foo.bar','msg',{},{foo:{bar:"123"}});
- result.should.eql("123");
- });
- it('throws an error if callback is not defined', function (done) {
- try {
- util.evaluateNodeProperty(' ','msg',{},{foo:{bar:"123"}});
- done("should throw an error");
- } catch (err) {
- done();
- }
- });
- it('returns flow property',function() {
- var result = util.evaluateNodeProperty('foo.bar','flow',{
- context:function() { return {
- flow: { get: function(k) {
- if (k === 'foo.bar') {
- return '123';
- } else {
- return null;
- }
- }}
- }}
- },{});
- result.should.eql("123");
- });
- it('returns global property',function() {
- var result = util.evaluateNodeProperty('foo.bar','global',{
- context:function() { return {
- global: { get: function(k) {
- if (k === 'foo.bar') {
- return '123';
- } else {
- return null;
- }
- }}
- }}
- },{});
- result.should.eql("123");
- });
- it('returns jsonata result', function () {
- var result = util.evaluateNodeProperty('$abs(-1)','jsonata',{},{});
- result.should.eql(1);
- });
- it('returns null', function() {
- var result = util.evaluateNodeProperty(null,'null');
- (result === null).should.be.true();
- })
- describe('environment variable', function() {
- before(function() {
- process.env.NR_TEST_A = "foo";
- process.env.NR_TEST_B = "${NR_TEST_A}";
- })
- after(function() {
- delete process.env.NR_TEST_A;
- delete process.env.NR_TEST_B;
- })
-
- it('returns an environment variable - NR_TEST_A', function() {
- var result = util.evaluateNodeProperty('NR_TEST_A','env');
- result.should.eql('foo');
- });
- it('returns an environment variable - ${NR_TEST_A}', function() {
- var result = util.evaluateNodeProperty('${NR_TEST_A}','env');
- result.should.eql('foo');
- });
- it('returns an environment variable - ${NR_TEST_A', function() {
- var result = util.evaluateNodeProperty('${NR_TEST_A','env');
- result.should.eql('');
- });
- it('returns an environment variable - foo${NR_TEST_A}bar', function() {
- var result = util.evaluateNodeProperty('123${NR_TEST_A}456','env');
- result.should.eql('123foo456');
- });
- it('returns an environment variable - foo${NR_TEST_B}bar', function() {
- var result = util.evaluateNodeProperty('123${NR_TEST_B}456','env');
- result.should.eql('123${NR_TEST_A}456');
- });
-
- });
- });
-
- describe('normalisePropertyExpression', function() {
- function testABC(input,expected) {
- var result = util.normalisePropertyExpression(input);
- // console.log("+",input);
- // console.log(result);
- result.should.eql(expected);
- }
- function testABCWithMessage(input,msg,expected) {
- var result = util.normalisePropertyExpression(input,msg);
- // console.log("+",input);
- // console.log(result);
- result.should.eql(expected);
- }
- function testInvalid(input,msg) {
- /*jshint immed: false */
- (function() {
- util.normalisePropertyExpression(input,msg);
- }).should.throw();
- }
- function testToString(input,msg,expected) {
- var result = util.normalisePropertyExpression(input,msg,true);
- console.log("+",input);
- console.log(result);
- result.should.eql(expected);
- }
- it('pass a.b.c',function() { testABC('a.b.c',['a','b','c']); })
- it('pass a["b"]["c"]',function() { testABC('a["b"]["c"]',['a','b','c']); })
- it('pass a["b"].c',function() { testABC('a["b"].c',['a','b','c']); })
- it("pass a['b'].c",function() { testABC("a['b'].c",['a','b','c']); })
-
- it("pass a[0].c",function() { testABC("a[0].c",['a',0,'c']); })
- it("pass a.0.c",function() { testABC("a.0.c",['a',0,'c']); })
- it("pass a['a.b[0]'].c",function() { testABC("a['a.b[0]'].c",['a','a.b[0]','c']); })
- it("pass a[0][0][0]",function() { testABC("a[0][0][0]",['a',0,0,0]); })
- it("pass '1.2.3.4'",function() { testABC("'1.2.3.4'",['1.2.3.4']); })
- it("pass 'a.b'[1]",function() { testABC("'a.b'[1]",['a.b',1]); })
- it("pass 'a.b'.c",function() { testABC("'a.b'.c",['a.b','c']); })
-
- it("pass a[msg.b]",function() { testABC("a[msg.b]",["a",["msg","b"]]); })
- it("pass a[msg[msg.b]]",function() { testABC("a[msg[msg.b]]",["a",["msg",["msg","b"]]]); })
- it("pass a[msg.b]",function() { testABC("a[msg.b]",["a",["msg","b"]]); })
- it("pass a[msg.b]",function() { testABC("a[msg.b]",["a",["msg","b"]]); })
- it("pass a[msg['b]\"[']]",function() { testABC("a[msg['b]\"[']]",["a",["msg","b]\"["]]); })
- it("pass a[msg['b][']]",function() { testABC("a[msg['b][']]",["a",["msg","b]["]]); })
- it("pass b[msg.a][2]",function() { testABC("b[msg.a][2]",["b",["msg","a"],2])})
-
- it("pass b[msg.a][2] (with message)",function() { testABCWithMessage("b[msg.a][2]",{a: "foo"},["b","foo",2])})
-
- it('pass a.$b.c',function() { testABC('a.$b.c',['a','$b','c']); })
- it('pass a["$b"].c',function() { testABC('a["$b"].c',['a','$b','c']); })
- it('pass a._b.c',function() { testABC('a._b.c',['a','_b','c']); })
- it('pass a["_b"].c',function() { testABC('a["_b"].c',['a','_b','c']); })
-
- it("pass a['a.b[0]'].c",function() { testToString("a['a.b[0]'].c",null,'a["a.b[0]"]["c"]'); })
- it("pass a.b.c",function() { testToString("a.b.c",null,'a["b"]["c"]'); })
- it('pass a[msg.c][0]["fred"]',function() { testToString('a[msg.c][0]["fred"]',{c:"123"},'a["123"][0]["fred"]'); })
-
- it("fail a'b'.c",function() { testInvalid("a'b'.c"); })
- it("fail a['b'.c",function() { testInvalid("a['b'.c"); })
- it("fail a[]",function() { testInvalid("a[]"); })
- it("fail a]",function() { testInvalid("a]"); })
- it("fail a[",function() { testInvalid("a["); })
- it("fail a[0d]",function() { testInvalid("a[0d]"); })
- it("fail a['",function() { testInvalid("a['"); })
- it("fail a[']",function() { testInvalid("a[']"); })
- it("fail a[0']",function() { testInvalid("a[0']"); })
- it("fail a.[0]",function() { testInvalid("a.[0]"); })
- it("fail [0]",function() { testInvalid("[0]"); })
- it("fail a[0",function() { testInvalid("a[0"); })
- it("fail a.",function() { testInvalid("a."); })
- it("fail .a",function() { testInvalid(".a"); })
- it("fail a. b",function() { testInvalid("a. b"); })
- it("fail a.b",function() { testInvalid(" a.b"); })
- it("fail a[0].[1]",function() { testInvalid("a[0].[1]"); })
- it("fail a['']",function() { testInvalid("a['']"); })
- it("fail 'a.b'c",function() { testInvalid("'a.b'c"); })
- it("fail ",function() { testInvalid("");})
- it("fail a[b]",function() { testInvalid("a[b]"); })
- it("fail a[msg.]",function() { testInvalid("a[msg.]"); })
- it("fail a[msg[]",function() { testInvalid("a[msg[]"); })
- it("fail a[msg.[]]",function() { testInvalid("a[msg.[]]"); })
- it("fail a[msg['af]]",function() { testInvalid("a[msg['af]]"); })
- it("fail b[msg.undefined][2] (with message)",function() { testInvalid("b[msg.undefined][2]",{})})
-
- });
-
- describe('normaliseNodeTypeName', function() {
- function normalise(input, expected) {
- var result = util.normaliseNodeTypeName(input);
- result.should.eql(expected);
- }
-
- it('pass blank',function() { normalise("", "") });
- it('pass ab1',function() { normalise("ab1", "ab1") });
- it('pass AB1',function() { normalise("AB1", "aB1") });
- it('pass a b 1',function() { normalise("a b 1", "aB1") });
- it('pass a-b-1',function() { normalise("a-b-1", "aB1") });
- it('pass ab1 ',function() { normalise(" ab1 ", "ab1") });
- it('pass _a_b_1_',function() { normalise("_a_b_1_", "aB1") });
- it('pass http request',function() { normalise("http request", "httpRequest") });
- it('pass HttpRequest',function() { normalise("HttpRequest", "httpRequest") });
- });
-
- describe('prepareJSONataExpression', function() {
- it('prepares an expression', function() {
- var result = util.prepareJSONataExpression('payload',{});
- result.should.have.property('evaluate');
- result.should.have.property('assign');
- result.should.have.property('_legacyMode', false);
- });
- it('prepares a legacyMode expression', function() {
- var result = util.prepareJSONataExpression('msg.payload',{});
- result.should.have.property('evaluate');
- result.should.have.property('assign');
- result.should.have.property('_legacyMode', true);
- });
- });
- describe('evaluateJSONataExpression', function() {
- it('evaluates an expression', function() {
- var expr = util.prepareJSONataExpression('payload',{});
- var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
- result.should.eql("hello");
- });
- it('evaluates a legacyMode expression', function() {
- var expr = util.prepareJSONataExpression('msg.payload',{});
- var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
- result.should.eql("hello");
- });
- it('accesses flow context from an expression', function() {
- var expr = util.prepareJSONataExpression('$flowContext("foo")',{context:function() { return {flow:{get: function(key) { return {'foo':'bar'}[key]}}}}});
- var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
- result.should.eql("bar");
- });
- it('accesses undefined environment variable from an expression', function() {
- var expr = util.prepareJSONataExpression('$env("UTIL_ENV")',{});
- var result = util.evaluateJSONataExpression(expr,{});
- result.should.eql('');
- });
- it('accesses environment variable from an expression', function() {
- process.env.UTIL_ENV = 'foo';
- var expr = util.prepareJSONataExpression('$env("UTIL_ENV")',{});
- var result = util.evaluateJSONataExpression(expr,{});
- result.should.eql('foo');
- });
- it('accesses moment from an expression', function() {
- var expr = util.prepareJSONataExpression('$moment("2020-05-27", "YYYY-MM-DD").add(7, "days").add(1, "months").format("YYYY-MM-DD")',{});
- var result = util.evaluateJSONataExpression(expr,{});
- result.should.eql('2020-07-03');
- });
- it('accesses moment-timezone from an expression', function() {
- var expr = util.prepareJSONataExpression('$moment("2013-11-18 11:55Z").tz("Asia/Taipei").format()',{});
- var result = util.evaluateJSONataExpression(expr,{});
- result.should.eql('2013-11-18T19:55:00+08:00');
- });
- it('handles non-existant flow context variable', function() {
- var expr = util.prepareJSONataExpression('$flowContext("nonExistant")',{context:function() { return {flow:{get: function(key) { return {'foo':'bar'}[key]}}}}});
- var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
- should.not.exist(result);
- });
- it('handles non-existant global context variable', function() {
- var expr = util.prepareJSONataExpression('$globalContext("nonExistant")',{context:function() { return {global:{get: function(key) { return {'foo':'bar'}[key]}}}}});
- var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
- should.not.exist(result);
- });
- it('handles async flow context access', function(done) {
- var expr = util.prepareJSONataExpression('$flowContext("foo")',{context:function() { return {flow:{get: function(key,store,callback) { setTimeout(()=>{callback(null,{'foo':'bar'}[key])},10)}}}}});
- util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value) {
- try {
- should.not.exist(err);
- value.should.eql("bar");
- done();
- } catch(err2) {
- done(err2);
- }
- });
- })
- it('handles async global context access', function(done) {
- var expr = util.prepareJSONataExpression('$globalContext("foo")',{context:function() { return {global:{get: function(key,store,callback) { setTimeout(()=>{callback(null,{'foo':'bar'}[key])},10)}}}}});
- util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value) {
- try {
- should.not.exist(err);
- value.should.eql("bar");
- done();
- } catch(err2) {
- done(err2);
- }
- });
- })
- it('handles persistable store in flow context access', function(done) {
- var storeName;
- var expr = util.prepareJSONataExpression('$flowContext("foo", "flowStoreName")',{context:function() { return {flow:{get: function(key,store,callback) { storeName = store;setTimeout(()=>{callback(null,{'foo':'bar'}[key])},10)}}}}});
- util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value) {
- try {
- should.not.exist(err);
- value.should.eql("bar");
- storeName.should.equal("flowStoreName");
- done();
- } catch(err2) {
- done(err2);
- }
- });
- })
- it('handles persistable store in global context access', function(done) {
- var storeName;
- var expr = util.prepareJSONataExpression('$globalContext("foo", "globalStoreName")',{context:function() { return {global:{get: function(key,store,callback) { storeName = store;setTimeout(()=>{callback(null,{'foo':'bar'}[key])},10)}}}}});
- util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value) {
- try {
- should.not.exist(err);
- value.should.eql("bar");
- storeName.should.equal("globalStoreName");
- done();
- } catch(err2) {
- done(err2);
- }
- });
- })
- it('callbacks with error when invalid expression was specified', function (done) {
- var expr = util.prepareJSONataExpression('$abc(1)',{});
- var result = util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value){
- should.exist(err);
- done();
- });
- });
- });
-
- describe('encodeObject', function () {
- it('encodes Error with message', function() {
- var err = new Error("encode error");
- err.name = 'encodeError';
- var msg = {msg:err};
- var result = util.encodeObject(msg);
- result.format.should.eql("error");
- var resultJson = JSON.parse(result.msg);
- resultJson.name.should.eql('encodeError');
- resultJson.message.should.eql('encode error');
- });
- it('encodes Error without message', function() {
- var err = new Error();
- err.name = 'encodeError';
- err.toString = function(){return 'error message';}
- var msg = {msg:err};
- var result = util.encodeObject(msg);
- result.format.should.eql("error");
- var resultJson = JSON.parse(result.msg);
- resultJson.name.should.eql('encodeError');
- resultJson.message.should.eql('error message');
- });
- it('encodes Buffer', function() {
- var msg = {msg:Buffer.from("abc")};
- var result = util.encodeObject(msg,{maxLength:4});
- result.format.should.eql("buffer[3]");
- result.msg[0].should.eql('6');
- result.msg[1].should.eql('1');
- result.msg[2].should.eql('6');
- result.msg[3].should.eql('2');
- });
- it('encodes function', function() {
- var msg = {msg:function(){}};
- var result = util.encodeObject(msg);
- result.format.should.eql("function");
- result.msg.should.eql('[function]');
- });
- it('encodes boolean', function() {
- var msg = {msg:true};
- var result = util.encodeObject(msg);
- result.format.should.eql("boolean");
- result.msg.should.eql('true');
- });
- it('encodes number', function() {
- var msg = {msg:123};
- var result = util.encodeObject(msg);
- result.format.should.eql("number");
- result.msg.should.eql('123');
- });
- it('encodes 0', function() {
- var msg = {msg:0};
- var result = util.encodeObject(msg);
- result.format.should.eql("number");
- result.msg.should.eql('0');
- });
- it('encodes null', function() {
- var msg = {msg:null};
- var result = util.encodeObject(msg);
- result.format.should.eql("null");
- result.msg.should.eql('(undefined)');
- });
- it('encodes undefined', function() {
- var msg = {msg:undefined};
- var result = util.encodeObject(msg);
- result.format.should.eql("undefined");
- result.msg.should.eql('(undefined)');
- });
- it('encodes string', function() {
- var msg = {msg:'1234567890'};
- var result = util.encodeObject(msg,{maxLength:6});
- result.format.should.eql("string[10]");
- result.msg.should.eql('123456...');
- });
-
- it('encodes Map', function() {
- const m = new Map();
- m.set("a",1);
- m.set("b",2);
- var msg = {msg:m};
- var result = util.encodeObject(msg);
- result.format.should.eql("map");
- var resultJson = JSON.parse(result.msg);
- resultJson.should.have.property("__enc__",true);
- resultJson.should.have.property("type","map");
- resultJson.should.have.property("data",{"a":1,"b":2});
- resultJson.should.have.property("length",2)
- });
-
- it('encodes Set', function() {
- const m = new Set();
- m.add("a");
- m.add("b");
- var msg = {msg:m};
- var result = util.encodeObject(msg);
- result.format.should.eql("set[2]");
- var resultJson = JSON.parse(result.msg);
- resultJson.should.have.property("__enc__",true);
- resultJson.should.have.property("type","set");
- resultJson.should.have.property("data",["a","b"]);
- resultJson.should.have.property("length",2)
- });
-
-
- describe('encode object', function() {
- it('object', function() {
- var msg = { msg:{"foo":"bar"} };
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.foo.should.eql('bar');
- });
- it('object whose name includes error', function() {
- function MyErrorObj(){
- this.name = 'my error obj';
- this.message = 'my error message';
- };
- var msg = { msg:new MyErrorObj() };
- var result = util.encodeObject(msg);
- result.format.should.eql("MyErrorObj");
- var resultJson = JSON.parse(result.msg);
- resultJson.name.should.eql('my error obj');
- resultJson.message.should.eql('my error message');
- });
-
- it('object with undefined property', function() {
- var msg = { msg:{a:1,b:undefined,c:3 } };
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.should.have.property("a",1);
- resultJson.should.have.property("c",3);
- resultJson.should.have.property("b");
- resultJson.b.should.have.property("__enc__", true);
- resultJson.b.should.have.property("type", "undefined");
- });
- it('object with no prototype builtins', function() {
- const payload = new Object(null);
- payload.c = 3;
- var msg = { msg:{b:payload} };
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.should.have.property("b");
- resultJson.b.should.have.property("c", 3);
- });
- it('object with overriden hasOwnProperty', function() {
- var msg = { msg:{b:{hasOwnProperty:null}} };
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.should.have.property("b");
- resultJson.b.should.have.property("hasOwnProperty");
- });
- it('object with Map property', function() {
- const m = new Map();
- m.set("a",1);
- m.set("b",2);
- var msg = {msg:{"aMap":m}};
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.should.have.property("aMap");
- resultJson.aMap.should.have.property("__enc__",true);
- resultJson.aMap.should.have.property("type","map");
- resultJson.aMap.should.have.property("data",{"a":1,"b":2});
- resultJson.aMap.should.have.property("length",2)
- });
- it('object with Set property', function() {
- const m = new Set();
- m.add("a");
- m.add("b");
- var msg = {msg:{"aSet":m}};
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.should.have.property("aSet");
- resultJson.aSet.should.have.property("__enc__",true);
- resultJson.aSet.should.have.property("type","set");
- resultJson.aSet.should.have.property("data",["a","b"]);
- resultJson.aSet.should.have.property("length",2)
- });
- it('constructor of IncomingMessage', function() {
- function IncomingMessage(){};
- var msg = { msg:new IncomingMessage() };
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.should.empty();
- });
- it('_req key in msg', function() {
- function Socket(){};
- var msg = { msg:{"_req":123} };
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson._req.__enc__.should.eql(true);
- resultJson._req.type.should.eql('internal');
- });
- it('_res key in msg', function() {
- function Socket(){};
- var msg = { msg:{"_res":123} };
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson._res.__enc__.should.eql(true);
- resultJson._res.type.should.eql('internal');
- });
- it('array of error', function() {
- var msg = { msg:[new Error("encode error")] };
- var result = util.encodeObject(msg);
- result.format.should.eql("array[1]");
- var resultJson = JSON.parse(result.msg);
- resultJson[0].should.eql('Error: encode error');
- });
- it('long array in msg', function() {
- var msg = {msg:{array:[1,2,3,4]}};
- var result = util.encodeObject(msg,{maxLength:2});
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.array.__enc__.should.eql(true);
- resultJson.array.data[0].should.eql(1);
- resultJson.array.data[1].should.eql(2);
- resultJson.array.length.should.eql(4);
- });
- it('array of string', function() {
- var msg = { msg:["abcde","12345"] };
- var result = util.encodeObject(msg,{maxLength:3});
- result.format.should.eql("array[2]");
- var resultJson = JSON.parse(result.msg);
- resultJson[0].should.eql('abc...');
- resultJson[1].should.eql('123...');
- });
- it('array containing undefined', function() {
- var msg = { msg:[1,undefined,3]};
- var result = util.encodeObject(msg);
- result.format.should.eql("array[3]");
- var resultJson = JSON.parse(result.msg);
- resultJson[0].should.eql(1);
- resultJson[2].should.eql(3);
- resultJson[1].__enc__.should.be.true();
- resultJson[1].type.should.eql("undefined");
- });
- it('array of function', function() {
- var msg = { msg:[function(){}] };
- var result = util.encodeObject(msg);
- result.format.should.eql("array[1]");
- var resultJson = JSON.parse(result.msg);
- resultJson[0].__enc__.should.eql(true);
- resultJson[0].type.should.eql('function');
- });
- it('array of number', function() {
- var msg = { msg:[1,2,3] };
- var result = util.encodeObject(msg,{maxLength:2});
- result.format.should.eql("array[3]");
- var resultJson = JSON.parse(result.msg);
- resultJson.__enc__.should.eql(true);
- resultJson.data[0].should.eql(1);
- resultJson.data[1].should.eql(2);
- resultJson.data.length.should.eql(2);
- resultJson.length.should.eql(3);
- });
- it('array of special number', function() {
- var msg = { msg:[NaN,Infinity,-Infinity] };
- var result = util.encodeObject(msg);
- result.format.should.eql("array[3]");
- var resultJson = JSON.parse(result.msg);
- resultJson[0].__enc__.should.eql(true);
- resultJson[0].type.should.eql('number');
- resultJson[0].data.should.eql('NaN');
- resultJson[1].data.should.eql('Infinity');
- resultJson[2].data.should.eql('-Infinity');
- });
- it('constructor of Buffer in msg', function() {
- var msg = { msg:{buffer:Buffer.from([1,2,3,4])} };
- var result = util.encodeObject(msg,{maxLength:2});
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.buffer.__enc__.should.eql(true);
- resultJson.buffer.length.should.eql(4);
- resultJson.buffer.data[0].should.eql(1);
- resultJson.buffer.data[1].should.eql(2);
- });
- it('constructor of ServerResponse', function() {
- function ServerResponse(){};
- var msg = { msg: new ServerResponse() };
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.should.eql('[internal]');
- });
- it('constructor of Socket in msg', function() {
- function Socket(){};
- var msg = { msg: { socket: new Socket() } };
- var result = util.encodeObject(msg);
- result.format.should.eql("Object");
- var resultJson = JSON.parse(result.msg);
- resultJson.socket.should.eql('[internal]');
- });
- it('object which fails to serialise', function(done) {
- var msg = {
- msg: {
- obj:{
- cantserialise:{
- message:'this will not be displayed',
- toJSON: function(val) {
- throw 'this exception should have been caught';
- return 'should not display because we threw first';
- },
- },
- canserialise:{
- message:'this should be displayed',
- }
- },
- }
- };
- var result = util.encodeObject(msg);
- result.format.should.eql("error");
- var success = (result.msg.indexOf('cantserialise') > 0);
- success &= (result.msg.indexOf('this exception should have been caught') > 0);
- success &= (result.msg.indexOf('canserialise') > 0);
- success.should.eql(1);
- done();
- });
- it('object which fails to serialise - different error type', function(done) {
- var msg = {
- msg: {
- obj:{
- cantserialise:{
- message:'this will not be displayed',
- toJSON: function(val) {
- throw new Error('this exception should have been caught');
- return 'should not display because we threw first';
- },
- },
- canserialise:{
- message:'this should be displayed',
- }
- },
- }
- };
- var result = util.encodeObject(msg);
- result.format.should.eql("error");
- var success = (result.msg.indexOf('cantserialise') > 0);
- success &= (result.msg.indexOf('this exception should have been caught') > 0);
- success &= (result.msg.indexOf('canserialise') > 0);
- success.should.eql(1);
- done();
- });
- it('very large object which fails to serialise should be truncated', function(done) {
- var msg = {
- msg: {
- obj:{
- big:"",
- cantserialise:{
- message:'this will not be displayed',
- toJSON: function(val) {
- throw new Error('this exception should have been caught');
- return 'should not display because we threw first';
- },
- },
- canserialise:{
- message:'this should be displayed',
- }
- },
- }
- };
-
- for (var i = 0; i < 1000; i++) {
- msg.msg.obj.big += 'some more string ';
- }
-
- var result = util.encodeObject(msg);
- result.format.should.eql("error");
- var resultJson = JSON.parse(result.msg);
- var success = (resultJson.message.length <= 1000);
- success.should.eql(true);
- done();
- });
- it('test bad toString', function(done) {
- var msg = {
- msg: {
- mystrangeobj:"hello",
- },
- };
- msg.msg.toString = function(){
- throw new Error('Exception in toString - should have been caught');
- }
- msg.msg.constructor = { name: "strangeobj" };
-
- var result = util.encodeObject(msg);
- var success = (result.msg.indexOf('[Type not printable]') >= 0);
- success.should.eql(true);
- done();
- });
- it('test bad object constructor', function(done) {
- var msg = {
- msg: {
- mystrangeobj:"hello",
- constructor: {
- get name(){
- throw new Error('Exception in constructor name');
- }
- }
- },
- };
- var result = util.encodeObject(msg);
- done();
- });
-
- });
- });
-
-});
diff --git a/test/unit/_spec.js b/test/unit/_spec.js
deleted file mode 100644
index d099836f3..000000000
--- a/test/unit/_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-/**
- * 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.
- **/
-
-/**
- * This test simply checks that for every .js file there exists
- * a *_spec.js file under ./test correspondingly.
- */
-
-/**
- * Currently we're only checking the core components under ./red
- * TODO: Increase the scope of this check
- */
-
-var fs = require("fs-extra");
-var should = require("should");
-var path = require('path');
-
-// Directories to check with .js files and _spec.js files respectively
-var rootdir = path.resolve(__dirname, "../..");
-var jsdir = path.resolve(__dirname, "../../packages/node_modules/");
-var testdir = path.resolve(__dirname);
-
-var walkDirectory = function(dir) {
- var p = fs.readdir(dir);
- var errors = [];
- return p.then(function(list) {
- var promises = [];
- list.forEach(function(file) {
- var filePath = path.join(dir,file);
-
- if (!/@node-red\/(editor-client|nodes)/.test(filePath) && !/node-red\/settings\.js/.test(filePath) && !/\/docs\//.test(filePath)) {
- promises.push(fs.stat(filePath).then(function(stat){
- if (stat.isDirectory()) {
- return walkDirectory(filePath).then(function(results) {
- if (results) {
- errors = errors.concat(results);
- }
- });
- } else if (/\.js$/.test(filePath)) {
- var testFile = filePath.replace(jsdir, testdir).replace(".js", "_spec.js");
- return fs.exists(testFile).then(function(exists) {
- if (!exists) {
- errors.push(testFile.substring(rootdir.length+1));
- } else {
- return fs.stat(testFile).then(function(stat) {
- if (stat.size === 0) {
- errors.push("[empty] "+testFile.substring(rootdir.length+1));
- }
- })
- }
- });
- }
- }));
- }
- });
- return Promise.all(promises).then(function() {
- return errors;
- })
- });
-}
-
-describe('_spec.js', function() {
- this.timeout(50000); // we might not finish within the Mocha default timeout limit, project will also grow
- it('is checking if all .js files have a corresponding _spec.js test file.', function(done) {
- walkDirectory(jsdir).then(function(errors) {
- if (errors.length > 0) {
- var error = new Error("Missing/empty _spec files:\n\t"+errors.join("\n\t"));
- done(error);
- } else {
- done();
- }
- });
- });
-});
diff --git a/test/unit/node-red/lib/red_spec.js b/test/unit/node-red/lib/red_spec.js
deleted file mode 100644
index 4cd430822..000000000
--- a/test/unit/node-red/lib/red_spec.js
+++ /dev/null
@@ -1,76 +0,0 @@
-/**
- * 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 fs = require("fs");
-var path = require("path");
-
-
-var NR_TEST_UTILS = require("nr-test-utils");
-
-var api = NR_TEST_UTILS.require("@node-red/runtime/lib/api");
-
-var RED = NR_TEST_UTILS.require("node-red");
-
-var runtime = NR_TEST_UTILS.require("@node-red/runtime");
-var api = NR_TEST_UTILS.require("@node-red/runtime/lib/api");
-
-
-describe("red/red", function() {
-
- // describe("check build", function() {
- // beforeEach(function() {
- // sinon.stub(runtime,"init").callsFake(function() {});
- // sinon.stub(api,"init").callsFake(function() {});
- // // sinon.stub(RED,"version").callsFake(function() { return "version";});
- // });
- // afterEach(function() {
- // runtime.init.restore();
- // api.init.restore();
- // fs.statSync.restore();
- // // RED.version.restore();
- // });
- // it.skip('warns if build has not been run',function() {
- // sinon.stub(fs,"statSync").callsFake(function() { throw new Error();});
- //
- // /*jshint immed: false */
- // (function() {
- // RED.init({},{});
- // }).should.throw("Node-RED not built");
- // });
- // it('passed if build has been run',function() {
- // sinon.stub(fs,"statSync").callsFake(function() { });
- // RED.init({},{});
- // });
- // });
-
- describe("externals", function() {
- it('reports version', function() {
- /\d+\.\d+\.\d+(-git)?/.test(RED.version()).should.be.true();
- });
- it.skip('access server externals', function() {
- // TODO: unstubable accessors - need to make this testable
- // RED.app;
- // RED.httpAdmin;
- // RED.httpNode;
- // RED.server;
- });
- it.skip('only initialises api component if httpAdmin enabled');
- it.skip('stubs httpAdmin if httpAdmin disabled');
- it.skip('stubs httpNode if httpNode disabled');
- });
-
-});
diff --git a/test/unit/node-red/red_spec.js b/test/unit/node-red/red_spec.js
deleted file mode 100644
index ee46fc504..000000000
--- a/test/unit/node-red/red_spec.js
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * 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 NR_TEST_UTILS = require("nr-test-utils");
-
-describe("node-red/red", function() {
- it.skip("NEEDS TESTS WRITING",function() {});
-});
From f42f55226727740e7675de84003aa00c06deb474 Mon Sep 17 00:00:00 2001
From: "andrew.greene"
Date: Wed, 8 Dec 2021 18:08:01 -0700
Subject: [PATCH 24/65] Add input/output to comment node
---
.../@node-red/nodes/core/common/90-comment.html | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/packages/node_modules/@node-red/nodes/core/common/90-comment.html b/packages/node_modules/@node-red/nodes/core/common/90-comment.html
index cca7cd51d..579a92cc7 100644
--- a/packages/node_modules/@node-red/nodes/core/common/90-comment.html
+++ b/packages/node_modules/@node-red/nodes/core/common/90-comment.html
@@ -1,4 +1,4 @@
-
+
+
+
+
+
diff --git a/packages/node_modules/@node-red/nodes/core/common/guide.js b/packages/node_modules/@node-red/nodes/core/common/guide.js
new file mode 100644
index 000000000..44802d135
--- /dev/null
+++ b/packages/node_modules/@node-red/nodes/core/common/guide.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ **/
+
+// 2022 Modification Copyright - Defense Unicorns
+
+module.exports = function(RED) {
+ "use strict";
+ function GuideNode(n) {
+ RED.nodes.createNode(this,n);
+ }
+ RED.nodes.registerType("guide",GuideNode);
+}
diff --git a/packages/node_modules/@node-red/nodes/core/common/resource.html b/packages/node_modules/@node-red/nodes/core/common/resource.html
new file mode 100644
index 000000000..d4db2f931
--- /dev/null
+++ b/packages/node_modules/@node-red/nodes/core/common/resource.html
@@ -0,0 +1,67 @@
+
+
+
+
+
+
diff --git a/packages/node_modules/@node-red/nodes/core/common/resource.js b/packages/node_modules/@node-red/nodes/core/common/resource.js
new file mode 100644
index 000000000..180a600f2
--- /dev/null
+++ b/packages/node_modules/@node-red/nodes/core/common/resource.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ **/
+
+// 2022 Modification Copyright - Defense Unicorns
+
+module.exports = function(RED) {
+ "use strict";
+ function ResourceNode(n) {
+ RED.nodes.createNode(this,n);
+ }
+ RED.nodes.registerType("resource",ResourceNode);
+}
diff --git a/packages/node_modules/@node-red/nodes/core/common/task.html b/packages/node_modules/@node-red/nodes/core/common/task.html
new file mode 100644
index 000000000..c1f8ebdac
--- /dev/null
+++ b/packages/node_modules/@node-red/nodes/core/common/task.html
@@ -0,0 +1,67 @@
+
+
+
+
+
+
diff --git a/packages/node_modules/@node-red/nodes/core/common/task.js b/packages/node_modules/@node-red/nodes/core/common/task.js
new file mode 100644
index 000000000..ce1c1410e
--- /dev/null
+++ b/packages/node_modules/@node-red/nodes/core/common/task.js
@@ -0,0 +1,25 @@
+/**
+ * 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.
+ **/
+
+// 2022 Modification Copyright - Defense Unicorns
+
+module.exports = function(RED) {
+ "use strict";
+ function TaskNode(n) {
+ RED.nodes.createNode(this,n);
+ }
+ RED.nodes.registerType("task",TaskNode);
+}
diff --git a/packages/node_modules/@node-red/nodes/icons/guide.svg b/packages/node_modules/@node-red/nodes/icons/guide.svg
new file mode 100644
index 000000000..b46237cfb
--- /dev/null
+++ b/packages/node_modules/@node-red/nodes/icons/guide.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
From dee88cd5d5060df07ff781026d916c55b372f072 Mon Sep 17 00:00:00 2001
From: Jordan McClintock
Date: Thu, 24 Feb 2022 12:25:10 -0600
Subject: [PATCH 55/65] Updated flows to use new node types
---
data/flows.json | 137 +++++++++---------
.../@node-red/nodes/core/common/task.html | 2 +-
2 files changed, 70 insertions(+), 69 deletions(-)
diff --git a/data/flows.json b/data/flows.json
index e8985ee9d..3add6c9e2 100644
--- a/data/flows.json
+++ b/data/flows.json
@@ -62,7 +62,7 @@
},
{
"id": "73521b98841c6355",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Kubernetes",
"info": "# Description\n\n\n## Resources\n- https://kubernetes.io/docs/home/ ***\n- https://www.youtube.com/watch?v=VnvRFRk_51k \n- https://www.youtube.com/watch?v=X48VuDVv0do (long video, covers most topics in this flow)",
@@ -79,7 +79,7 @@
},
{
"id": "90665185044d3fc2",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Kubernetes Objects",
"info": "",
@@ -94,7 +94,7 @@
},
{
"id": "ccf8bad6e9ebfb6a",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Kubernetes Networking",
"info": "",
@@ -106,7 +106,7 @@
},
{
"id": "4146a7d5608cc03b",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Kubernetes Storage",
"info": "",
@@ -118,7 +118,7 @@
},
{
"id": "418551f904d62b20",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Kubernetes App Manifests",
"info": "",
@@ -130,7 +130,7 @@
},
{
"id": "0d309e7b063a4ce2",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Configurations",
"info": "",
@@ -145,7 +145,7 @@
},
{
"id": "d810b83f64f0bc5e",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Deployments",
"info": "",
@@ -159,7 +159,7 @@
},
{
"id": "752d2d1fc700d27e",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Pods",
"info": "",
@@ -171,7 +171,7 @@
},
{
"id": "c53965f3ddc770ad",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Configmaps",
"info": "",
@@ -183,7 +183,7 @@
},
{
"id": "e902145181ebd724",
- "type": "comment",
+ "type": "resource",
"z": "0ac7681ed1c2bc4b",
"name": "Secrets",
"info": "",
@@ -195,7 +195,7 @@
},
{
"id": "5dfd2ba38ec5178d",
- "type": "comment",
+ "type": "resource",
"z": "eb7909bcf5fcaf8a",
"name": "Containerization",
"info": "",
@@ -209,7 +209,7 @@
},
{
"id": "8c04bec4a15f6702",
- "type": "comment",
+ "type": "resource",
"z": "eb7909bcf5fcaf8a",
"name": "Helm",
"info": "",
@@ -223,7 +223,7 @@
},
{
"id": "fc01372231b580db",
- "type": "comment",
+ "type": "resource",
"z": "eb7909bcf5fcaf8a",
"name": "Custom Resource Definitions",
"info": "",
@@ -237,7 +237,7 @@
},
{
"id": "09d8e90d5b4ade12",
- "type": "comment",
+ "type": "resource",
"z": "eb7909bcf5fcaf8a",
"name": "Kustomization",
"info": "",
@@ -251,7 +251,7 @@
},
{
"id": "71a96ec4058930db",
- "type": "comment",
+ "type": "resource",
"z": "eb7909bcf5fcaf8a",
"name": "GitOps",
"info": "",
@@ -265,7 +265,7 @@
},
{
"id": "98df2d11adb09046",
- "type": "comment",
+ "type": "resource",
"z": "eb7909bcf5fcaf8a",
"name": "git",
"info": "# Description\n\n[Git](https://git-scm.com/) is a free and open source distributed version control system.\n\n## Resources\n- https://git-scm.com/docs\n\n\n## Examples\n- github.com\n- gitlab.com\n- https://gitea.com/",
@@ -279,7 +279,7 @@
},
{
"id": "45465f711df6da7e",
- "type": "comment",
+ "type": "resource",
"z": "eb7909bcf5fcaf8a",
"name": "Flux",
"info": "",
@@ -293,7 +293,7 @@
},
{
"id": "e328f5849309e731",
- "type": "comment",
+ "type": "resource",
"z": "eb7909bcf5fcaf8a",
"name": "Big Bang",
"info": "",
@@ -322,7 +322,7 @@
},
{
"id": "81348cdecdf51fd9",
- "type": "comment",
+ "type": "resource",
"z": "eb7909bcf5fcaf8a",
"name": "Operators",
"info": "https://www.youtube.com/watch?v=ha3LjlD6g7g",
@@ -336,27 +336,28 @@
},
{
"id": "40bfe328130d9c41",
- "type": "comment",
+ "type": "guide",
"z": "c86af370eff94afa",
"name": "Deploy K3d",
"info": "Throughout this guide you will be using K3d to deploy and manage kubernetes instances.\n\n## Choose your platform\nThe preferred free VM software is [VirtualBox](https://www.virtualbox.org/); however, it is not compatible with M1 chips! So, if you are using an M1 Mac, we highly recommend you go with the [Cloud](#Cloud) option below\n\n### Cloud\nRecommend using an EC2 instance with the following specs:\n- AMI: Ubuntu Server (64-bit, x86)\n- Instance Type: t3a.2xlarge\n- 100 GB EBS\n- Security group rules for allowing web traffic\n\n### Local VM\nUse [Vagrant](https://www.vagrantup.com/) to spin up a VM with at least the following specs:\n- 10GB RAM\n- 4 CPU cores\n- An IP that can be [accessed](https://www.vagrantup.com/docs/networking/private_network#static-ip) from the host machine. \n\n### Local\nAny Docker installation except a non-WSL2 Windows installation will work with K3d natively.\n\n## K3d setup\n\nSetup instructions for K3d can be found at the link below.\n\nhttps://k3d.io/v5.2.2/\n\n## Cluster creation\n\nOnce you have a host for deploying a k3d cluster - you can configure a cluster for future nodes in this training.\n\nOne possible configuration would be a 3 node cluster with 1 server and 2 agents (to get started).\n\nAnother consideration is exposing applications after the cluster is running and apps have been deployed w/ services and ingresses.\n\nDepending on RAM/CPU availability, you may want to run 2 or more K3d nodes\n\nA possible configuration might look like:\n\n`k3d cluster create -s 1 -a 2 -p \"8081:80@loadbalancer\" dev-cluster`\n\n-s 1 represents 1 server node\n-a 2 represents 2 agent nodes\n\n-p \"8081:80@loadbalancer\" represents mapping 8081 on this k3d host to ports 80 internally.",
- "x": 510,
- "y": 40,
+ "x": 360,
+ "y": 60,
"wires": [
[
"691424f6cfd58372",
- "1458b18889c13942"
+ "1458b18889c13942",
+ "6d2d525b92151db2"
]
]
},
{
"id": "691424f6cfd58372",
- "type": "comment",
+ "type": "guide",
"z": "c86af370eff94afa",
"name": "Deploy a pod info application (with Kustomize)",
"info": "# Kustomize\n\n\"Kustomize is a command-line configuration manager for Kubernetes objects. Integrated with kubectl since 1.14, it allows you to make declarative changes to your configurations without touching a template.\"\n\n## Recommended Reading\n\n`https://www.mirantis.com/blog/introduction-to-kustomize-part-1-creating-a-kubernetes-app-out-of-multiple-pieces/`\n\nThe above tutorial can be run on the k3d cluster you have created. This is a much more complex example than the podinfo example you will deploy below.\n\n## Podinfo\n\n\"Podinfo is a tiny web application made with Go that showcases best practices of running microservices in Kubernetes\"\n\n### Deployment\n\nNavigate to `https://github.com/stefanprodan/podinfo`\n\nClone the repository to your local machine\n\nFrom within the cloned directory, we can execute kustomize through the built in functionality in `kubectl`.\n\n`kubectl kustomize ./kustomize`\n\nThis will return the built manifest for the application to be deployed. You can then deploy the application to the cluster through `kubectl apply -k ./kustomize`\n\n## Success Criteria\n\n- 2 podinfo pods in the target namespace (default if not specified)\n- A podinfo service\n- A horizontal pod autoscaler\n\nWe can port-forward this applications service and visit it in browser to confirm functionality.\n\n`kubectl port-forward service/podinfo 9898:http`\n\nThis port fowards the podinfo service `http` port (as defined in the service) to the 9898 host port.",
- "x": 630,
- "y": 130,
+ "x": 420,
+ "y": 190,
"wires": [
[
"2d66fece0a8f5fdf"
@@ -365,12 +366,12 @@
},
{
"id": "2d66fece0a8f5fdf",
- "type": "comment",
+ "type": "task",
"z": "c86af370eff94afa",
"name": "Expose podinfo with an Ingress",
"info": "# Ingress\n\nIn the previous exercise, we deployed the podinfo application and confirmed functionality by visiting it in-browser through port-forwarding with kubectl. We can instead use an ingress and the default traefik ingress-controller to handle this functionaity more natively. \n\nOfficial k3d docs: https://k3d.io/v5.0.0/usage/exposing_services/\n\n## Ingress deployment\nDue to the cluster configuration that we executed in the first node (See the -p loadbalancer parameter). we can configure an ingress to expose the application, as is one of a few standard practices for exposing internal applications to external traffic.\n\n### Ingress template\n\nIngress docs: https://kubernetes.io/docs/concepts/services-networking/ingress/\n\nGiven the template from the docs/tutorial we can write an ingress to support this traffic.\n\n## Success Criteria\n\nAfter the ingress is deployed (and given you configured your cluster as described in the first node), then you should be able to access the podinfo application without port-forwarding at `http://localhost:8081` \n\n## Cleanup\n\nThis concludes this deployment of podinfo. You'll want to cleanup the resources we have created. ",
- "x": 630,
- "y": 200,
+ "x": 420,
+ "y": 260,
"wires": [
[
"52eb692e4c51108f"
@@ -379,12 +380,12 @@
},
{
"id": "52eb692e4c51108f",
- "type": "comment",
+ "type": "guide",
"z": "c86af370eff94afa",
"name": "Create a podinfo helm chart",
"info": "# Helm\n\"Helm is the package manager for Kubernetes\"\n\n## Recommended Reading\nhttps://helm.sh/\nhttps://helm.sh/docs/intro/\n\n## Podinfo Helm Chart from Scratch\n\nTODO - Insert content for:\n- deployment\n- service\n- ingress\n- HPA\n* All templated from scratch\n\n## Deploy the official podinfo chart from local files\n\nPreviously we cloned the podinfo repository to our/a local machine. Under the root of the project there is a `charts` directory with a `podinfo` directory that contains the podinfo chart content.\n\n## Basic deployment\n\nLet's create a testing namespace for our target\n`kubectl create ns testing`\n\nWith Helm installed and our k3d cluster still running/configured, we can install the chart in it's vanilla form (without enabling any additional content).\n\n(From the charts directory)\n`helm install podinfo-dev ./podinfo -n testing`\n\nThis will deploy the chart which results in the deployment and service creation in the target namespace.\n\n## Customizations\nWe can inject exposed customizations as outlined in the README/values.yaml for the purpose of configuring the end package being suited for our needs.\n\nWe can make an edit to the values.yaml and upgrade our application.\n\nhpa:\n enabled: true\n \n`helm upgrade podinfo-dev -n testing ./podinfo`\n\nThis should result in an HPA being deployed to our namespace for the application.\n",
- "x": 630,
- "y": 270,
+ "x": 420,
+ "y": 330,
"wires": [
[
"5361df412a99db12"
@@ -393,12 +394,12 @@
},
{
"id": "5361df412a99db12",
- "type": "comment",
+ "type": "guide",
"z": "c86af370eff94afa",
"name": "Deploy BigBang on a new K3d cluster",
"info": "# Big Bang\n\nUsing our machine with k3d, we can instantiate a development/prototype deployment of Big Bang.\n\n## Objective\n\nFollow the qiuckstart here:\nhttps://repo1.dso.mil/platform-one/big-bang/bigbang/-/blob/master/docs/guides/deployment_scenarios/quickstart.md\n\n## Success Criteria\n\nAs noted in step 13 - the web UI's should be resolvable and accessible. All pods should be up and healthy (running). ",
- "x": 630,
- "y": 340,
+ "x": 420,
+ "y": 400,
"wires": [
[
"67415f95eb8ab46c"
@@ -407,12 +408,12 @@
},
{
"id": "67415f95eb8ab46c",
- "type": "comment",
+ "type": "task",
"z": "c86af370eff94afa",
"name": "Deploy podinfo helmchart in a bigbang cluster",
"info": "# Big Bang Extensibility\n\nUp to now - we have configured and deployed k3d clusters, we've used `kustomize` and `Helm` to orchestrate deploying `podinfo` to our cluster.\n\nWe then used flux and it's controllers to deploy bigbang (which is using helm and kustomize under the hood).\n\n## Recommended Reading\n\n## Objective\nNow we will look at extending the big bang deployment to include deploying the podinfo helm chart and ensuring the deployment architecture aligns with the Big Bang \"Core\" technologies.\n\nThis is a precursory step to follow-on nodes in this flow. \n\n## Execution\n\nClone the podinfo repository if not done already.\n\nCreate a namespace with the label:\n`istio-injection: enabled`\n\nDeploy the helm chart for the podinfo applicaiton as we have done previously.\n\n## Success Criteria\nDeploy the podinfo helm chart into your cluster that already has big bang deployed.\n\nThe application should come online and be able to be reached via `kubectl port-forward`\n\nContinue to the next node for extending this with Istio",
- "x": 630,
- "y": 410,
+ "x": 420,
+ "y": 470,
"wires": [
[
"9b8fdffdc9b5cc53"
@@ -421,12 +422,12 @@
},
{
"id": "9b8fdffdc9b5cc53",
- "type": "comment",
+ "type": "task",
"z": "c86af370eff94afa",
"name": "Add Istio Virtual Service for the podinfo deployment",
"info": "# Istio VirtualServices\n\n## Recommended Reading\n\n- https://istio.io/latest/docs/reference/config/networking/virtual-service/\n\n### Example\n- https://repo1.dso.mil/platform-one/big-bang/apps/core/kiali/-/blob/main/chart/values.yaml#:~:text=istio%3A,kiali.%7B%7B%20.Values.hostname%20%7D%7D\n- https://repo1.dso.mil/platform-one/big-bang/apps/core/kiali/-/blob/main/chart/templates/bigbang/virtualservice.yaml\n\n## Objective\nWith the podinfo helm chart deployed (in it's basic state), we will look to leverage some of th technologies that Big Bang has reconciled and configured.\n\nBig Bang exposes cluster applications to external traffic through an Istio Ingress Gateway.\n\nVirtual services are then used to link kubernetes services to traffic from the ingresss gateways.\n\n## Execution\n\n\n\n## Success Criteria\nWrite a virtual service resource definition file for the podinfo application that was deployed as part of the last node.\n\nIf you add the `podinfo.bigbang.dev` endpoint to your hosts file, then it should be resolveable from the browser.\n\n## Solution\nshow \n\n\n```\napiVersion: networking.istio.io/v1beta1\nkind: VirtualService\nmetadata:\n name: podinfo\n namespace: podinfo\nspec:\n gateways:\n - istio-system/public\n hosts:\n - podinfo.bigbang.dev\n http:\n - route:\n - destination:\n host: podinfo.podinfo.svc.cluster.local\n port:\n number: 9898\n```\n\n
\n ",
- "x": 630,
- "y": 480,
+ "x": 420,
+ "y": 540,
"wires": [
[
"339481fd79e107a6"
@@ -435,12 +436,12 @@
},
{
"id": "339481fd79e107a6",
- "type": "comment",
+ "type": "task",
"z": "c86af370eff94afa",
"name": "Deploy podinfo as a Flux HelmRelease",
"info": "# Flux helm release reconciliation\n\"Big Bang follows a GitOps approach to configuration management, using Flux v2 to reconcile Git with the cluster. Environments (e.g. dev, prod) and packages (e.g. istio) can be fully configured to suit the deployment needs.\"\n\n## Prerequisites\n- Remove all prior content for podinfo from your cluster. \n\n## Recommended Reading\n- https://repo1.dso.mil/platform-one/big-bang/bigbang/-/blob/master/README.md\n\n## Objective\nFollowing the umbrella structure in the Big Bang chart, we can create the templates under a `podinfo` directory (under the templates dir).\n\nNote: there are many ways to accomplish this task - the podinfo directory under the templates directory most-accurately represents how the umbrella structure works.\n\n### Minimum Requirements\n- namespace resource\n- git repository resource\n- helm release resource\n- virtual service resource\n\nThis would meet the bare minimum requirements.\n\n### Additional Content\n- values file (a helper generates a secret resource from this)\n\n## Success Criteria\nIf we run the `helm upgrade` command against the modified Big Bang helm chart, it should deploy the podinfo chart (if properly enabled) with the ability to access/resolve the application through the `Ingress Gateway`.",
- "x": 630,
- "y": 550,
+ "x": 420,
+ "y": 610,
"wires": [
[
"0f9889d8e9cb7edb"
@@ -449,36 +450,36 @@
},
{
"id": "0f9889d8e9cb7edb",
- "type": "comment",
+ "type": "guide",
"z": "c86af370eff94afa",
"name": "Play DOOM using ZARF",
"info": "# Zarf!\n\nZarf is a Defense Unicorns developed tool - please read about it below!\n\n## Recommended Reading\n- https://github.com/defenseunicorns/zarf\n\n\n## Objective\nUsing Zarf, we will follow the guide below in order to play DOOM.\n\nhttps://github.com/defenseunicorns/zarf/tree/master/examples/game\n\n## Success Criteria\nPackaging, Deployment and execution of playing DOOM from within the browser.",
- "x": 630,
- "y": 620,
+ "x": 420,
+ "y": 680,
"wires": [
[]
]
},
{
"id": "1458b18889c13942",
- "type": "comment",
+ "type": "guide",
"z": "c86af370eff94afa",
"name": "Deploy and Access the Kubernetes Dashboard",
"info": "# Description\n\n# Resources\n\n# Unicorn SME(s)\n",
- "x": 240,
- "y": 130,
+ "x": 800,
+ "y": 190,
"wires": [
[]
]
},
{
"id": "6d2d525b92151db2",
- "type": "comment",
+ "type": "resource",
"z": "c86af370eff94afa",
"name": "Kustomize",
"info": "# Description\n\n# Resources\n\n# Unicorn SME(s)\n",
- "x": 740,
- "y": 40,
+ "x": 230,
+ "y": 120,
"wires": [
[
"691424f6cfd58372"
@@ -487,12 +488,12 @@
},
{
"id": "a25127e60aa3afac",
- "type": "comment",
+ "type": "resource",
"z": "c86af370eff94afa",
"name": "Helm",
"info": "# Description\n\n# Resources\n\n# Unicorn SME(s)\n",
- "x": 910,
- "y": 200,
+ "x": 150,
+ "y": 260,
"wires": [
[
"52eb692e4c51108f"
@@ -501,12 +502,12 @@
},
{
"id": "bd30d9f248bb244a",
- "type": "comment",
+ "type": "resource",
"z": "c86af370eff94afa",
"name": "Big Bang",
"info": "# Description\n\n# Resources\n\n# Unicorn SME(s)\n",
- "x": 910,
- "y": 270,
+ "x": 150,
+ "y": 330,
"wires": [
[
"5361df412a99db12"
@@ -515,12 +516,12 @@
},
{
"id": "f17eae05b57f6a2e",
- "type": "comment",
+ "type": "resource",
"z": "c86af370eff94afa",
"name": "Istio",
"info": "# Description\n\n# Resources\n\n# Unicorn SME(s)\n",
- "x": 910,
- "y": 410,
+ "x": 150,
+ "y": 470,
"wires": [
[
"9b8fdffdc9b5cc53"
@@ -529,12 +530,12 @@
},
{
"id": "3a185c296c95de08",
- "type": "comment",
+ "type": "resource",
"z": "c86af370eff94afa",
"name": "Flux",
"info": "# Description\n\n# Resources\n\n# Unicorn SME(s)\n",
- "x": 910,
- "y": 480,
+ "x": 150,
+ "y": 540,
"wires": [
[
"339481fd79e107a6"
@@ -543,12 +544,12 @@
},
{
"id": "14c8378318de0a59",
- "type": "comment",
+ "type": "resource",
"z": "c86af370eff94afa",
"name": "Traefix Ingress",
"info": "# Description\n\n# Resources\n\n# Unicorn SME(s)\n",
- "x": 910,
- "y": 130,
+ "x": 150,
+ "y": 190,
"wires": [
[
"2d66fece0a8f5fdf"
diff --git a/packages/node_modules/@node-red/nodes/core/common/task.html b/packages/node_modules/@node-red/nodes/core/common/task.html
index c1f8ebdac..c59c309b8 100644
--- a/packages/node_modules/@node-red/nodes/core/common/task.html
+++ b/packages/node_modules/@node-red/nodes/core/common/task.html
@@ -17,7 +17,7 @@