From 53563736816c0ab086a8d89256c07de62d87ef78 Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Thu, 9 Mar 2017 21:06:49 +0000 Subject: [PATCH] Finalise nodeSettings and update tlsConfigDisableLocalFiles - increase test coverage around registerType --- nodes/core/io/05-tls.js | 2 +- red/api/info.js | 6 +- red/runtime/nodes/index.js | 9 +- red/runtime/settings.js | 18 +- test/red/runtime/nodes/index_spec.js | 311 +++++++++++++++++---------- test/red/runtime/settings_spec.js | 21 +- 6 files changed, 225 insertions(+), 142 deletions(-) diff --git a/nodes/core/io/05-tls.js b/nodes/core/io/05-tls.js index a3e3a75fc..4d9e7374e 100644 --- a/nodes/core/io/05-tls.js +++ b/nodes/core/io/05-tls.js @@ -82,7 +82,7 @@ module.exports = function(RED) { settings: { tlsConfigDisableLocalFiles: { value: false, - exportable: false + exportable: true } } }); diff --git a/red/api/info.js b/red/api/info.js index a1f4ca310..b34f41662 100644 --- a/red/api/info.js +++ b/red/api/info.js @@ -43,16 +43,12 @@ module.exports = { safeSettings.flowFilePretty = settings.flowFilePretty; } - if (settings.tlsDisableLocalFiles) { - safeSettings.tlsDisableLocalFiles = settings.tlsDisableLocalFiles; - } - if (!runtime.nodes.paletteEditorEnabled()) { safeSettings.editorTheme = safeSettings.editorTheme || {}; safeSettings.editorTheme.palette = safeSettings.editorTheme.palette || {}; safeSettings.editorTheme.palette.editable = false; } - + settings.exportNodeSettings(safeSettings); res.json(safeSettings); diff --git a/red/runtime/nodes/index.js b/red/runtime/nodes/index.js index 5be548549..20634c1d9 100644 --- a/red/runtime/nodes/index.js +++ b/red/runtime/nodes/index.js @@ -24,7 +24,7 @@ var flows = require("./flows"); var flowUtil = require("./flows/util") var context = require("./context"); var Node = require("./Node"); -var log = require("../log"); +var log = null; var library = require("./library"); var events = require("../events"); @@ -55,7 +55,11 @@ function registerType(nodeSet,type,constructor,opts) { credentials.register(type,opts.credentials); } if (opts.settings) { - settings.registerNodeSettings(type,opts.settings); + try { + settings.registerNodeSettings(type,opts.settings); + } catch(err) { + log.warn("["+type+"] "+err.message); + } } } registry.registerType(nodeSet,type,constructor); @@ -90,6 +94,7 @@ function createNode(node,def) { function init(runtime) { settings = runtime.settings; + log = runtime.log; credentials.init(runtime); flows.init(runtime); registry.init(runtime); diff --git a/red/runtime/settings.js b/red/runtime/settings.js index cb7ae91bc..14cc33b8d 100644 --- a/red/runtime/settings.js +++ b/red/runtime/settings.js @@ -106,19 +106,15 @@ var persistentSettings = { storage = null; }, registerNodeSettings: function(type, opts) { - try { - for (var property in opts) { - if (opts.hasOwnProperty(property)) { - var normalisedType = util.normaliseNodeTypeName(type); - if (!property.startsWith(normalisedType)) { - throw new Error("The name of node setting property " + property + " must start with \"" + normalisedType + "\" (case sensitive)."); - } + var normalisedType = util.normaliseNodeTypeName(type); + for (var property in opts) { + if (opts.hasOwnProperty(property)) { + if (!property.startsWith(normalisedType)) { + throw new Error("Registered invalid property name '"+property+"'. Properties for this node must start with '"+normalisedType+"'"); } } - nodeSettings[type] = opts; - } catch (err) { - console.log(err.toString()); } + nodeSettings[type] = opts; }, exportNodeSettings: function(safeSettings) { safeSettings["nodeSettings"] = {}; @@ -131,7 +127,7 @@ var persistentSettings = { if (setting.exportable) { if (userSettings.hasOwnProperty(property)) { safeSettings["nodeSettings"][property] = userSettings[property]; - } else { + } else if (setting.hasOwnProperty('value')) { safeSettings["nodeSettings"][property] = setting.value; } } diff --git a/test/red/runtime/nodes/index_spec.js b/test/red/runtime/nodes/index_spec.js index 045d084a7..a26474a24 100644 --- a/test/red/runtime/nodes/index_spec.js +++ b/test/red/runtime/nodes/index_spec.js @@ -72,9 +72,9 @@ describe("red/nodes/index", function() { }); } - it('nodes are initialised with credentials',function(done) { + it('nodes are initialised with credentials',function(done) { index.init(runtime); - index.registerType('test', TestNode); + 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); @@ -86,11 +86,11 @@ describe("red/nodes/index", function() { }); }); - it('flows should be initialised',function(done) { + it('flows should be initialised',function(done) { index.init(runtime); index.loadFlows().then(function() { - console.log(testFlows); - console.log(index.getFlows()); + // console.log(testFlows); + // console.log(index.getFlows()); should.deepEqual(testFlows, index.getFlows().flows); done(); }).otherwise(function(err) { @@ -98,86 +98,159 @@ describe("red/nodes/index", function() { }); }); + 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); - describe("registerType should register credentials definition", function() { - var http = require('http'); - var express = require('express'); - var app = express(); - var runtime = require("../../../../red/runtime"); - var credentials = require("../../../../red/runtime/nodes/credentials"); - var localfilesystem = require("../../../../red/runtime/storage/localfilesystem"); - var RED = require("../../../../red/red.js"); + 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); + }); + }); - var userDir = path.join(__dirname,".testUserHome"); - before(function(done) { - fs.remove(userDir,function(err) { - fs.mkdir(userDir,function() { - sinon.stub(index, 'load', function() { - return when.promise(function(resolve,reject){ - resolve([]); - }); - }); - sinon.stub(localfilesystem, 'getCredentials', function() { - return when.promise(function(resolve,reject) { - resolve({"tab1":{"b":1,"c":2}}); + describe("register credentials definition", function() { + var http = require('http'); + var express = require('express'); + var app = express(); + var runtime = require("../../../../red/runtime"); + var credentials = require("../../../../red/runtime/nodes/credentials"); + var localfilesystem = require("../../../../red/runtime/storage/localfilesystem"); + var log = require("../../../../red/runtime/log"); + var RED = require("../../../../red/red.js"); + + var userDir = path.join(__dirname,".testUserHome"); + before(function(done) { + sinon.stub(log,"log"); + fs.remove(userDir,function(err) { + fs.mkdir(userDir,function() { + sinon.stub(index, 'load', function() { + return when.promise(function(resolve,reject){ + resolve([]); + }); + }); + sinon.stub(localfilesystem, 'getCredentials', function() { + return when.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(); }); - }) ; - 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(); - 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', TestNode, { - credentials: { - foo: {type:"test"} - } - }); - var testnode = new TestNode({id:'tab1',type:'test',name:'barney', '_alias':'tab1'}); - index.getCredentialDefinition("test").should.have.property('foo'); - }); + 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); - describe('allows nodes to be added/removed/enabled/disabled from the registry', function() { - var randomNodeInfo = {id:"5678",types:["random"]}; + 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); - beforeEach(function() { - sinon.stub(registry,"getNodeInfo",function(id) { - if (id == "test") { - return {id:"1234",types:["test"]}; - } else if (id == "doesnotexist") { - return null; - } else { - return randomNodeInfo; - } - }); - sinon.stub(registry,"disableNode",function(id) { - return randomNodeInfo; - }); - }); - afterEach(function() { - registry.getNodeInfo.restore(); - registry.disableNode.restore(); - }); + index.registerType('test-node-set','test', TestNode, { + settings: { + testOne: {} + } + }); + runtime.log.warn.called.should.be.true(); + }); + }); + }); - it(': allows an unused node type to be disabled',function(done) { + 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",function(id) { + if (id == "test") { + return {id:"1234",types:["test"]}; + } else if (id == "doesnotexist") { + return null; + } else { + return randomNodeInfo; + } + }); + sinon.stub(registry,"disableNode",function(id) { + return 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', TestNode); + index.registerType('test-node-set','test', TestNode); index.loadFlows().then(function() { var info = index.disableNode("5678"); registry.disableNode.calledOnce.should.be.true(); @@ -187,11 +260,11 @@ describe("red/nodes/index", function() { }).otherwise(function(err) { done(err); }); - }); + }); - it(': prevents disabling a node type that is in use',function(done) { + it('prevents disabling a node type that is in use',function(done) { index.init(runtime); - index.registerType('test', TestNode); + index.registerType('test-node-set','test', TestNode); index.loadFlows().then(function() { /*jshint immed: false */ (function() { @@ -202,11 +275,11 @@ describe("red/nodes/index", function() { }).otherwise(function(err) { done(err); }); - }); + }); - it(': prevents disabling a node type that is unknown',function(done) { + it('prevents disabling a node type that is unknown',function(done) { index.init(runtime); - index.registerType('test', TestNode); + index.registerType('test-node-set','test', TestNode); index.loadFlows().then(function() { /*jshint immed: false */ (function() { @@ -220,46 +293,46 @@ describe("red/nodes/index", function() { }); }); - describe('allows modules to be removed from the registry', function() { - var registry = require("../../../../red/runtime/nodes/registry"); - var randomNodeInfo = {id:"5678",types:["random"]}; - var randomModuleInfo = { - name:"random", - nodes: [randomNodeInfo] + describe('allows modules to be removed from the registry', function() { + var registry = require("../../../../red/runtime/nodes/registry"); + var randomNodeInfo = {id:"5678",types:["random"]}; + var randomModuleInfo = { + name:"random", + nodes: [randomNodeInfo] }; - before(function() { - sinon.stub(registry,"getNodeInfo",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",function(module) { - if (module == "node-red") { - return {nodes:[{name:"foo"}]}; - } else if (module == "doesnotexist") { - return null; - } else { - return randomModuleInfo; - } - }); - sinon.stub(registry,"removeModule",function(id) { - return randomModuleInfo; - }); - }); - after(function() { - registry.getNodeInfo.restore(); - registry.getModuleInfo.restore(); - registry.removeModule.restore(); - }); + before(function() { + sinon.stub(registry,"getNodeInfo",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",function(module) { + if (module == "node-red") { + return {nodes:[{name:"foo"}]}; + } else if (module == "doesnotexist") { + return null; + } else { + return randomModuleInfo; + } + }); + sinon.stub(registry,"removeModule",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) { + it('prevents removing a module that is in use',function(done) { index.init(runtime); - index.registerType('test', TestNode); + index.registerType('test-node-set','test', TestNode); index.loadFlows().then(function() { /*jshint immed: false */ (function() { @@ -270,11 +343,11 @@ describe("red/nodes/index", function() { }).otherwise(function(err) { done(err); }); - }); + }); - it(': prevents removing a module that is unknown',function(done) { + it('prevents removing a module that is unknown',function(done) { index.init(runtime); - index.registerType('test', TestNode); + index.registerType('test-node-set','test', TestNode); index.loadFlows().then(function() { /*jshint immed: false */ (function() { diff --git a/test/red/runtime/settings_spec.js b/test/red/runtime/settings_spec.js index ec995155b..a53fe792f 100644 --- a/test/red/runtime/settings_spec.js +++ b/test/red/runtime/settings_spec.js @@ -153,6 +153,8 @@ describe("red/settings", function() { 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["nodeSettings"].should.have.property("injectColor", "red"); @@ -164,15 +166,26 @@ describe("red/settings", function() { safeSettings["nodeSettings"].should.have.property("httpRequest3", "a3"); safeSettings["nodeSettings"].should.have.property("mQtTColor", "purple"); safeSettings["nodeSettings"].should.have.property("abc123", "def456"); + + safeSettings["nodeSettings"].should.have.property("noValueHasValue", "123"); + safeSettings["nodeSettings"].should.not.have.property("noValueNoValue"); }); it('prohibits registering the property whose name do not start with type name', function() { var userSettings = {}; settings.init(userSettings); - settings.registerNodeSettings("inject", {color:{value:"red", exportable:true}} ); - settings.registerNodeSettings("_a_b_1_", {ab1Color:{value:"red", exportable:true}} ); - settings.registerNodeSettings("AB2", {AB2Color:{value:"red", exportable:true}} ); - settings.registerNodeSettings("abcDef", {abcColor:{value:"red", exportable:true}} ); + (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["nodeSettings"].should.not.have.property("color");