Tidy up API passed to node modules

This commit is contained in:
Nick O'Leary 2015-11-24 22:38:42 +00:00
parent 043b8a3105
commit f03aff7006
18 changed files with 195 additions and 99 deletions

View File

@ -42,7 +42,6 @@ function init(_server,runtime) {
runtime.events.on("node-status",handleStatus); runtime.events.on("node-status",handleStatus);
} }
function start() { function start() {
var Tokens = require("./auth/tokens"); var Tokens = require("./auth/tokens");
var Users = require("./auth/users"); var Users = require("./auth/users");

View File

@ -20,7 +20,7 @@ var api;
module.exports = { module.exports = {
init: function(runtime) { init: function(runtime) {
log = runtime.log; log = runtime.log;
api = runtime.api; api = runtime.nodes;
}, },
get: function (req, res) { get: function (req, res) {
// TODO: It should verify the given node id is of the type specified - // TODO: It should verify the given node id is of the type specified -

View File

@ -21,7 +21,7 @@ var settings;
module.exports = { module.exports = {
init: function(runtime) { init: function(runtime) {
settings = runtime.settings; settings = runtime.settings;
redNodes = runtime.api; redNodes = runtime.nodes;
log = runtime.log; log = runtime.log;
}, },
get: function(req,res) { get: function(req,res) {

View File

@ -1,5 +1,5 @@
/** /**
* Copyright 2014 IBM Corp. * Copyright 2014, 2015 IBM Corp.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@ -38,6 +38,7 @@ var i18n;
var log; var log;
var adminApp; var adminApp;
var nodeApp; var nodeApp;
var server;
var errorHandler = function(err,req,res,next) { var errorHandler = function(err,req,res,next) {
if (err.message === "request entity too large") { if (err.message === "request entity too large") {
@ -49,7 +50,8 @@ var errorHandler = function(err,req,res,next) {
res.status(400).json({error:"unexpected_error", message:err.toString()}); res.status(400).json({error:"unexpected_error", message:err.toString()});
}; };
function init(server,runtime) { function init(_server,runtime) {
server = _server;
var settings = runtime.settings; var settings = runtime.settings;
i18n = runtime.i18n; i18n = runtime.i18n;
log = runtime.log; log = runtime.log;
@ -150,6 +152,7 @@ module.exports = {
comms: { comms: {
publish: comms.publish publish: comms.publish
}, },
adminApp: function() { return adminApp; }, get adminApp() { return adminApp; },
nodeApp: function() { return nodeApp; } get nodeApp() { return nodeApp; },
get server() { return server; }
}; };

View File

@ -24,7 +24,7 @@ var settings;
module.exports = { module.exports = {
init: function(runtime) { init: function(runtime) {
redNodes = runtime.api; redNodes = runtime.nodes;
log = runtime.log; log = runtime.log;
i18n = runtime.i18n; i18n = runtime.i18n;
settings = runtime.settings; settings = runtime.settings;

View File

@ -40,29 +40,22 @@ function checkBuild() {
module.exports = { module.exports = {
init: function(httpServer,userSettings) { init: function(httpServer,userSettings) {
server = httpServer;
if (!userSettings.SKIP_BUILD_CHECK) { if (!userSettings.SKIP_BUILD_CHECK) {
checkBuild(); checkBuild();
} }
runtime.init(userSettings);
if (userSettings.httpAdminRoot !== false || userSettings.httpNodeRoot !== false) {
api.init(server,runtime);
adminApp = api.adminApp();
nodeApp = api.nodeApp();
}
if (adminApp === null) { if (userSettings.httpAdminRoot !== false || userSettings.httpNodeRoot !== false) {
adminApp = { runtime.init(userSettings,api);
get:function(){}, api.init(httpServer,runtime);
post: function(){},
put: function(){},
delete: function(){}
}
} else {
apiEnabled = true; apiEnabled = true;
} else {
runtime.init(userSettings);
apiEnabled = false;
} }
return runtime.app; adminApp = runtime.adminApi.adminApp;
nodeApp = runtime.adminApi.nodeApp;
server = runtime.adminApi.server;
return;
}, },
start: function() { start: function() {
return runtime.start().then(function() { return runtime.start().then(function() {
@ -78,7 +71,7 @@ module.exports = {
} }
}) })
}, },
nodes: runtime.api, nodes: runtime.nodes,
log: runtime.log, log: runtime.log,
settings:runtime.settings, settings:runtime.settings,
util: runtime.util, util: runtime.util,

View File

@ -27,10 +27,36 @@ var fs = require("fs");
var runtimeMetricInterval = null; var runtimeMetricInterval = null;
function init(userSettings) { var stubbedExpressApp = {
get: function() {},
post: function() {},
put: function() {},
delete: function(){}
}
var adminApi = {
library: {
register: function(){}
},
auth: {
needsPermission: function(){}
},
comms: {
publish: function(){}
},
adminApp: stubbedExpressApp,
nodeApp: stubbedExpressApp,
server: {}
}
function init(userSettings,_adminApi) {
userSettings.version = getVersion(); userSettings.version = getVersion();
log.init(userSettings); log.init(userSettings);
settings.init(userSettings); settings.init(userSettings);
if (_adminApi) {
adminApi = _adminApi;
}
redNodes.init(runtime);
} }
var version; var version;
@ -69,7 +95,6 @@ function start() {
} }
log.info(log._("runtime.version",{component:"Node.js ",version:process.version})); log.info(log._("runtime.version",{component:"Node.js ",version:process.version}));
log.info(log._("server.loading")); log.info(log._("server.loading"));
redNodes.init(runtime);
return redNodes.load().then(function() { return redNodes.load().then(function() {
var i; var i;
@ -159,6 +184,7 @@ var runtime = module.exports = {
settings: settings, settings: settings,
storage: storage, storage: storage,
events: events, events: events,
api: redNodes, nodes: redNodes,
util: require("./util") util: require("./util"),
get adminApi() { return adminApi }
} }

View File

@ -50,9 +50,9 @@ var LogHandler = function(settings) {
this.logLevel = settings ? levels[settings.level]||levels.info : levels.info; this.logLevel = settings ? levels[settings.level]||levels.info : levels.info;
this.metricsOn = settings ? settings.metrics||false : false; this.metricsOn = settings ? settings.metrics||false : false;
this.auditOn = settings ? settings.audit||false : false; this.auditOn = settings ? settings.audit||false : false;
metricsEnabled = metricsEnabled || this.metricsOn; metricsEnabled = metricsEnabled || this.metricsOn;
this.handler = (settings && settings.handler) ? settings.handler(settings) : consoleLogger; this.handler = (settings && settings.handler) ? settings.handler(settings) : consoleLogger;
this.on("log",function(msg) { this.on("log",function(msg) {
if (this.shouldReportMessage(msg.level)) { if (this.shouldReportMessage(msg.level)) {
@ -134,7 +134,7 @@ var log = module.exports = {
metric: function() { metric: function() {
return metricsEnabled; return metricsEnabled;
}, },
audit: function(msg,req) { audit: function(msg,req) {
msg.level = log.AUDIT; msg.level = log.AUDIT;
if (req) { if (req) {

View File

@ -32,6 +32,7 @@ function Flow(global,flow) {
this.start = function(diff) { this.start = function(diff) {
var node; var node;
var newNode;
var id; var id;
catchNodeMap = {}; catchNodeMap = {};
statusNodeMap = {}; statusNodeMap = {};
@ -39,7 +40,10 @@ function Flow(global,flow) {
if (flow.configs.hasOwnProperty(id)) { if (flow.configs.hasOwnProperty(id)) {
node = flow.configs[id]; node = flow.configs[id];
if (!activeNodes[id]) { if (!activeNodes[id]) {
activeNodes[id] = createNode(node.type,node); newNode = createNode(node.type,node);
if (newNode) {
activeNodes[id] = newNode;
}
} }
} }
} }
@ -57,7 +61,10 @@ function Flow(global,flow) {
node = flow.nodes[id]; node = flow.nodes[id];
if (!node.subflow) { if (!node.subflow) {
if (!activeNodes[id]) { if (!activeNodes[id]) {
activeNodes[id] = createNode(node.type,node); newNode = createNode(node.type,node);
if (newNode) {
activeNodes[id] = newNode;
}
} }
} else { } else {
if (!subflowInstanceNodes[id]) { if (!subflowInstanceNodes[id]) {
@ -65,7 +72,9 @@ function Flow(global,flow) {
var nodes = createSubflow(flow.subflows[node.subflow]||global.subflows[node.subflow],node,flow.subflows,global.subflows,activeNodes); var nodes = createSubflow(flow.subflows[node.subflow]||global.subflows[node.subflow],node,flow.subflows,global.subflows,activeNodes);
subflowInstanceNodes[id] = nodes.map(function(n) { return n.id}); subflowInstanceNodes[id] = nodes.map(function(n) { return n.id});
for (var i=0;i<nodes.length;i++) { for (var i=0;i<nodes.length;i++) {
activeNodes[nodes[i].id] = nodes[i]; if (nodes[i]) {
activeNodes[nodes[i].id] = nodes[i];
}
} }
} catch(err) { } catch(err) {
console.log(err.stack) console.log(err.stack)
@ -438,8 +447,10 @@ function createSubflow(sf,sfn,subflows,globalSubflows,activeNodes) {
var m = /^subflow:(.+)$/.exec(type); var m = /^subflow:(.+)$/.exec(type);
if (!m) { if (!m) {
var newNode = createNode(type,node); var newNode = createNode(type,node);
activeNodes[node.id] = newNode; if (newNode) {
nodes.push(newNode); activeNodes[node.id] = newNode;
nodes.push(newNode);
}
} else { } else {
var subflowId = m[1]; var subflowId = m[1];
nodes = nodes.concat(createSubflow(subflows[subflowId]||globalSubflows[subflowId],node,subflows,globalSubflows,activeNodes)); nodes = nodes.concat(createSubflow(subflows[subflowId]||globalSubflows[subflowId],node,subflows,globalSubflows,activeNodes));

View File

@ -222,7 +222,7 @@ function start(type,diff) {
log.info(log._("nodes.flows.missing-type-install-2")); log.info(log._("nodes.flows.missing-type-install-2"));
log.info(" "+settings.userDir); log.info(" "+settings.userDir);
} }
return; return when.resolve();
} }
if (diff) { if (diff) {
log.info(log._("nodes.flows.starting-modified-"+type)); log.info(log._("nodes.flows.starting-modified-"+type));
@ -270,6 +270,7 @@ function start(type,diff) {
} else { } else {
log.info(log._("nodes.flows.started-flows")); log.info(log._("nodes.flows.started-flows"));
} }
return when.resolve();
} }
function stop(type,diff) { function stop(type,diff) {
@ -387,6 +388,7 @@ module.exports = {
*/ */
stopFlows: stop, stopFlows: stop,
started: function() { return started },
handleError: handleError, handleError: handleError,
handleStatus: handleStatus, handleStatus: handleStatus,

View File

@ -22,7 +22,6 @@ var semver = require("semver");
var localfilesystem = require("./localfilesystem"); var localfilesystem = require("./localfilesystem");
var registry = require("./registry"); var registry = require("./registry");
var RED;
var settings; var settings;
var runtime; var runtime;
@ -30,7 +29,6 @@ function init(_runtime) {
runtime = _runtime; runtime = _runtime;
settings = runtime.settings; settings = runtime.settings;
localfilesystem.init(runtime); localfilesystem.init(runtime);
RED = require('../../../red');
} }
function load(defaultNodesDir,disableNodePathScan) { function load(defaultNodesDir,disableNodePathScan) {
@ -43,6 +41,66 @@ function load(defaultNodesDir,disableNodePathScan) {
return loadNodeFiles(nodeFiles); return loadNodeFiles(nodeFiles);
} }
function copyObjectProperties(src,dst,copyList,blockList) {
if (!src) {
return;
}
if (copyList && !blockList) {
copyList.forEach(function(i) {
if (src.hasOwnProperty(i)) {
var propDescriptor = Object.getOwnPropertyDescriptor(src,i);
Object.defineProperty(dst,i,propDescriptor);
}
});
} else if (!copyList && blockList) {
for (var i in src) {
if (src.hasOwnProperty(i) && blockList.indexOf(i) === -1) {
var propDescriptor = Object.getOwnPropertyDescriptor(src,i);
Object.defineProperty(dst,i,propDescriptor);
}
}
}
}
function createNodeApi(node) {
var red = {
nodes: {},
log: {},
settings: {},
util: runtime.util,
version: runtime.version,
}
copyObjectProperties(runtime.nodes,red.nodes,["createNode","getNode","eachNode","registerType","addCredentials","getCredentials","deleteCredentials" ]);
copyObjectProperties(runtime.log,red.log,null,["init"]);
copyObjectProperties(runtime.settings,red.settings,null,["init","load","reset"]);
if (runtime.adminApi) {
red.comms = runtime.adminApi.comms;
red.library = runtime.adminApi.library;
red.auth = runtime.adminApi.auth;
red.httpAdmin = runtime.adminApi.adminApp;
red.httpNode = runtime.adminApi.nodeApp;
red.server = runtime.adminApi.server;
} else {
red.comms = {
publish: function(){}
};
red.library = {
register: function(){}
};
red.auth = {
needsPermission: function() {}
};
// TODO: stub out httpAdmin/httpNode/server
}
red["_"] = function() {
var args = Array.prototype.slice.call(arguments, 0);
args[0] = node.namespace+":"+args[0];
return runtime.i18n._.apply(null,args);
}
return red;
}
function loadNodeFiles(nodeFiles) { function loadNodeFiles(nodeFiles) {
var promises = []; var promises = [];
for (var module in nodeFiles) { for (var module in nodeFiles) {
@ -225,18 +283,7 @@ function loadNodeSet(node) {
var r = require(node.file); var r = require(node.file);
if (typeof r === "function") { if (typeof r === "function") {
var red = {}; var red = createNodeApi(node);
for (var i in RED) {
if (RED.hasOwnProperty(i) && !/^(init|start|stop)$/.test(i)) {
var propDescriptor = Object.getOwnPropertyDescriptor(RED,i);
Object.defineProperty(red,i,propDescriptor);
}
}
red["_"] = function() {
var args = Array.prototype.slice.call(arguments, 0);
args[0] = node.namespace+":"+args[0];
return runtime.i18n._.apply(null,args);
}
var promise = r(red); var promise = r(red);
if (promise != null && typeof promise.then === "function") { if (promise != null && typeof promise.then === "function") {
loadPromise = promise.then(function() { loadPromise = promise.then(function() {

View File

@ -314,6 +314,18 @@ function getModuleInfo(module) {
} }
} }
function getCaller(){
var orig = Error.prepareStackTrace;
Error.prepareStackTrace = function(_, stack){ return stack; };
var err = new Error;
Error.captureStackTrace(err, arguments.callee);
var stack = err.stack;
Error.prepareStackTrace = orig;
stack.shift();
stack.shift();
return stack[0].getFileName();
}
function registerNodeConstructor(type,constructor) { function registerNodeConstructor(type,constructor) {
if (nodeConstructors[type]) { if (nodeConstructors[type]) {
throw new Error(type+" already registered"); throw new Error(type+" already registered");

View File

@ -30,7 +30,7 @@ describe('credentials api', function() {
app.get('/credentials/:type/:id',credentials.get); app.get('/credentials/:type/:id',credentials.get);
credentials.init({ credentials.init({
log:{audit:function(){}}, log:{audit:function(){}},
api:{ nodes:{
getCredentials: function(id) { getCredentials: function(id) {
if (id === "n1") { if (id === "n1") {
return {user1:"abc",password1:"123"}; return {user1:"abc",password1:"123"};

View File

@ -37,7 +37,7 @@ describe("flows api", function() {
it('returns flow', function(done) { it('returns flow', function(done) {
flows.init({ flows.init({
log:{warn:function(){},_:function(){},audit:function(){}}, log:{warn:function(){},_:function(){},audit:function(){}},
api:{ nodes:{
getFlows: function() { return [1,2,3]; } getFlows: function() { return [1,2,3]; }
} }
}); });
@ -58,7 +58,7 @@ describe("flows api", function() {
var setFlows = sinon.spy(function() { return when.resolve();}); var setFlows = sinon.spy(function() { return when.resolve();});
flows.init({ flows.init({
log:{warn:function(){},_:function(){},audit:function(){}}, log:{warn:function(){},_:function(){},audit:function(){}},
api:{ nodes:{
setFlows: setFlows setFlows: setFlows
} }
}); });
@ -79,7 +79,7 @@ describe("flows api", function() {
var setFlows = sinon.spy(function() { return when.resolve();}); var setFlows = sinon.spy(function() { return when.resolve();});
flows.init({ flows.init({
log:{warn:function(){},_:function(){},audit:function(){}}, log:{warn:function(){},_:function(){},audit:function(){}},
api:{ nodes:{
setFlows: setFlows setFlows: setFlows
} }
}); });
@ -102,7 +102,7 @@ describe("flows api", function() {
var loadFlows = sinon.spy(function() { return when.resolve(); }); var loadFlows = sinon.spy(function() { return when.resolve(); });
flows.init({ flows.init({
log:{warn:function(){},_:function(){},audit:function(){}}, log:{warn:function(){},_:function(){},audit:function(){}},
api:{ nodes:{
loadFlows: loadFlows loadFlows: loadFlows
} }
}); });
@ -123,7 +123,7 @@ describe("flows api", function() {
it('returns error when set fails', function(done) { it('returns error when set fails', function(done) {
flows.init({ flows.init({
log:{warn:function(){},_:function(){},audit:function(){}}, log:{warn:function(){},_:function(){},audit:function(){}},
api:{ nodes:{
setFlows: function() { return when.reject(new Error("expected error")); } setFlows: function() { return when.reject(new Error("expected error")); }
} }
}); });

View File

@ -32,7 +32,7 @@ describe("api index", function() {
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:true}, settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:true},
events: {on:function(){},removeListener: function(){}} events: {on:function(){},removeListener: function(){}}
}); });
app = api.adminApp(); app = api.adminApp;
}); });
it('does not serve the editor', function(done) { it('does not serve the editor', function(done) {
@ -72,7 +72,7 @@ describe("api index", function() {
storage:{getSessions:function(){return when.resolve({})}}, storage:{getSessions:function(){return when.resolve({})}},
events:{on:function(){},removeListener:function(){}} events:{on:function(){},removeListener:function(){}}
}); });
app = api.adminApp(); app = api.adminApp;
}); });
it('it now serves auth', function(done) { it('it now serves auth', function(done) {
@ -109,7 +109,7 @@ describe("api index", function() {
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false}, settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false},
events:{on:function(){},removeListener:function(){}} events:{on:function(){},removeListener:function(){}}
}); });
app = api.adminApp(); app = api.adminApp;
}); });
it('serves the editor', function(done) { it('serves the editor', function(done) {
request(app) request(app)

View File

@ -62,7 +62,7 @@ describe("nodes api", function() {
describe('get nodes', function() { describe('get nodes', function() {
it('returns node list', function(done) { it('returns node list', function(done) {
initNodes({ initNodes({
api:{ nodes:{
getNodeList: function() { getNodeList: function() {
return [1,2,3]; return [1,2,3];
} }
@ -83,7 +83,7 @@ describe("nodes api", function() {
it('returns node configs', function(done) { it('returns node configs', function(done) {
initNodes({ initNodes({
api:{ nodes:{
getNodeConfigs: function() { getNodeConfigs: function() {
return "<script></script>"; return "<script></script>";
} }
@ -107,7 +107,7 @@ describe("nodes api", function() {
it('returns node module info', function(done) { it('returns node module info', function(done) {
initNodes({ initNodes({
api:{ nodes:{
getModuleInfo: function(id) { getModuleInfo: function(id) {
return {"node-red":{name:"node-red"}}[id]; return {"node-red":{name:"node-red"}}[id];
} }
@ -127,7 +127,7 @@ describe("nodes api", function() {
it('returns 404 for unknown module', function(done) { it('returns 404 for unknown module', function(done) {
initNodes({ initNodes({
api:{ nodes:{
getModuleInfo: function(id) { getModuleInfo: function(id) {
return {"node-red":{name:"node-red"}}[id]; return {"node-red":{name:"node-red"}}[id];
} }
@ -146,7 +146,7 @@ describe("nodes api", function() {
it('returns individual node info', function(done) { it('returns individual node info', function(done) {
initNodes({ initNodes({
api:{ nodes:{
getNodeInfo: function(id) { getNodeInfo: function(id) {
return {"node-red/123":{id:"node-red/123"}}[id]; return {"node-red/123":{id:"node-red/123"}}[id];
} }
@ -167,7 +167,7 @@ describe("nodes api", function() {
it('returns individual node configs', function(done) { it('returns individual node configs', function(done) {
initNodes({ initNodes({
api:{ nodes:{
getNodeConfig: function(id) { getNodeConfig: function(id) {
return {"node-red/123":"<script></script>"}[id]; return {"node-red/123":"<script></script>"}[id];
} }
@ -191,7 +191,7 @@ describe("nodes api", function() {
it('returns 404 for unknown node', function(done) { it('returns 404 for unknown node', function(done) {
initNodes({ initNodes({
api:{ nodes:{
getNodeInfo: function(id) { getNodeInfo: function(id) {
return {"node-red/123":{id:"node-red/123"}}[id]; return {"node-red/123":{id:"node-red/123"}}[id];
} }
@ -247,7 +247,7 @@ describe("nodes api", function() {
it('installs the module and returns module info', function(done) { it('installs the module and returns module info', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function(id) { return null; }, getModuleInfo: function(id) { return null; },
installModule: function() { installModule: function() {
return when.resolve({ return when.resolve({
@ -275,7 +275,7 @@ describe("nodes api", function() {
it('fails the install if already installed', function(done) { it('fails the install if already installed', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function(id) { return {nodes:{id:"123"}}; }, getModuleInfo: function(id) { return {nodes:{id:"123"}}; },
installModule: function() { installModule: function() {
return when.resolve({id:"123"}); return when.resolve({id:"123"});
@ -297,7 +297,7 @@ describe("nodes api", function() {
it('fails the install if module error', function(done) { it('fails the install if module error', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function(id) { return null }, getModuleInfo: function(id) { return null },
installModule: function() { installModule: function() {
return when.reject(new Error("test error")); return when.reject(new Error("test error"));
@ -319,7 +319,7 @@ describe("nodes api", function() {
it('fails the install if module not found', function(done) { it('fails the install if module not found', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function(id) { return null }, getModuleInfo: function(id) { return null },
installModule: function() { installModule: function() {
var err = new Error("test error"); var err = new Error("test error");
@ -362,7 +362,7 @@ describe("nodes api", function() {
it('uninstalls the module', function(done) { it('uninstalls the module', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function(id) { return {nodes:[{id:"123"}]} }, getModuleInfo: function(id) { return {nodes:[{id:"123"}]} },
getNodeInfo: function() { return null }, getNodeInfo: function() { return null },
uninstallModule: function() { return when.resolve({id:"123"});} uninstallModule: function() { return when.resolve({id:"123"});}
@ -382,7 +382,7 @@ describe("nodes api", function() {
it('fails the uninstall if the module is not installed', function(done) { it('fails the uninstall if the module is not installed', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function(id) { return null }, getModuleInfo: function(id) { return null },
getNodeInfo: function() { return null } getNodeInfo: function() { return null }
} }
@ -401,7 +401,7 @@ describe("nodes api", function() {
it('fails the uninstall if the module is not installed', function(done) { it('fails the uninstall if the module is not installed', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function(id) { return {nodes:[{id:"123"}]} }, getModuleInfo: function(id) { return {nodes:[{id:"123"}]} },
getNodeInfo: function() { return null }, getNodeInfo: function() { return null },
uninstallModule: function() { return when.reject(new Error("test error"));} uninstallModule: function() { return when.reject(new Error("test error"));}
@ -476,7 +476,7 @@ describe("nodes api", function() {
it('returns 404 for unknown node', function(done) { it('returns 404 for unknown node', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getNodeInfo: function() { return null } getNodeInfo: function() { return null }
} }
}); });
@ -496,7 +496,7 @@ describe("nodes api", function() {
it('returns 404 for unknown module', function(done) { it('returns 404 for unknown module', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function(id) { return null } getModuleInfo: function(id) { return null }
} }
}); });
@ -516,7 +516,7 @@ describe("nodes api", function() {
it('enables disabled node', function(done) { it('enables disabled node', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getNodeInfo: function() { return {id:"123",enabled: false} }, getNodeInfo: function() { return {id:"123",enabled: false} },
enableNode: function() { return when.resolve({id:"123",enabled: true,types:['a']}); } enableNode: function() { return when.resolve({id:"123",enabled: true,types:['a']}); }
} }
@ -539,7 +539,7 @@ describe("nodes api", function() {
it('disables enabled node', function(done) { it('disables enabled node', function(done) {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getNodeInfo: function() { return {id:"123",enabled: true} }, getNodeInfo: function() { return {id:"123",enabled: true} },
disableNode: function() { return when.resolve({id:"123",enabled: false,types:['a']}); } disableNode: function() { return when.resolve({id:"123",enabled: false,types:['a']}); }
} }
@ -566,7 +566,7 @@ describe("nodes api", function() {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getNodeInfo: function() { return {id:"123",enabled: state} }, getNodeInfo: function() { return {id:"123",enabled: state} },
enableNode: enableNode, enableNode: enableNode,
disableNode: disableNode disableNode: disableNode
@ -605,7 +605,7 @@ describe("nodes api", function() {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getNodeInfo: function() { return {id:"123",enabled: state, err:"foo"} }, getNodeInfo: function() { return {id:"123",enabled: state, err:"foo"} },
enableNode: enableNode, enableNode: enableNode,
disableNode: disableNode disableNode: disableNode
@ -652,7 +652,7 @@ describe("nodes api", function() {
enableNode.returns(null); enableNode.returns(null);
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} }, getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} },
enableNode: enableNode enableNode: enableNode
} }
@ -690,7 +690,7 @@ describe("nodes api", function() {
disableNode.returns(null); disableNode.returns(null);
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} }, getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} },
disableNode: disableNode disableNode: disableNode
} }
@ -727,7 +727,7 @@ describe("nodes api", function() {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function() { return {name:"node-red", nodes:[node]}; }, getModuleInfo: function() { return {name:"node-red", nodes:[node]}; },
enableNode: enableNode, enableNode: enableNode,
disableNode: disableNode disableNode: disableNode
@ -774,7 +774,7 @@ describe("nodes api", function() {
initNodes({ initNodes({
settings:{available:function(){return true}}, settings:{available:function(){return true}},
api:{ nodes:{
getModuleInfo: function() { return {name:"node-red", nodes:[node]}; }, getModuleInfo: function() { return {name:"node-red", nodes:[node]}; },
enableNode: enableNode, enableNode: enableNode,
disableNode: disableNode disableNode: disableNode

View File

@ -44,16 +44,19 @@ describe("runtime", function() {
beforeEach(function() { beforeEach(function() {
sinon.stub(log,"init",function() {}); sinon.stub(log,"init",function() {});
sinon.stub(settings,"init",function() {}); sinon.stub(settings,"init",function() {});
sinon.stub(redNodes,"init",function() {})
}); });
afterEach(function() { afterEach(function() {
log.init.restore(); log.init.restore();
settings.init.restore(); settings.init.restore();
redNodes.init.restore();
}) })
it("initialises components", function() { it("initialises components", function() {
runtime.init({testSettings: true, httpAdminRoot:"/"}); runtime.init({testSettings: true, httpAdminRoot:"/"});
log.init.called.should.be.true; log.init.called.should.be.true;
settings.init.called.should.be.true; settings.init.called.should.be.true;
redNodes.init.called.should.be.true;
}); });
it("returns version", function() { it("returns version", function() {

View File

@ -44,7 +44,7 @@ describe("red/nodes/registry/loader",function() {
}) })
describe("#init",function() { describe("#init",function() {
it("init",function() { it("init",function() {
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}}});
localfilesystem.init.called.should.be.true; localfilesystem.init.called.should.be.true;
}); });
}); });
@ -53,7 +53,7 @@ describe("red/nodes/registry/loader",function() {
it("load empty set without settings available", function(done) { it("load empty set without settings available", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};})); stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};})); stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};}));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}});
loader.load("foo",true).then(function() { loader.load("foo",true).then(function() {
localfilesystem.getNodeFiles.called.should.be.true; localfilesystem.getNodeFiles.called.should.be.true;
localfilesystem.getNodeFiles.lastCall.args[0].should.eql('foo'); localfilesystem.getNodeFiles.lastCall.args[0].should.eql('foo');
@ -65,7 +65,7 @@ describe("red/nodes/registry/loader",function() {
it("load empty set with settings available triggers registery save", function(done) { it("load empty set with settings available triggers registery save", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};})); stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};})); stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};}));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}});
loader.load("foo",true).then(function() { loader.load("foo",true).then(function() {
registry.saveNodeList.called.should.be.true; registry.saveNodeList.called.should.be.true;
done(); done();
@ -96,7 +96,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true; registry.addNodeSet.called.should.be.true;
registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode1"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode1");
@ -143,7 +143,7 @@ describe("red/nodes/registry/loader",function() {
// This module isn't already loaded // This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true; registry.addNodeSet.called.should.be.true;
registry.addNodeSet.lastCall.args[0].should.eql("node-red/MultipleNodes1"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/MultipleNodes1");
@ -194,7 +194,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true; registry.addNodeSet.called.should.be.true;
registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode2"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode2");
@ -243,7 +243,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true; registry.addNodeSet.called.should.be.true;
registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode3"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/TestNode3");
@ -290,7 +290,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; })); stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) { loader.load().then(function(result) {
registry.addNodeSet.called.should.be.true; registry.addNodeSet.called.should.be.true;
registry.addNodeSet.lastCall.args[0].should.eql("node-red/DoesNotExist"); registry.addNodeSet.lastCall.args[0].should.eql("node-red/DoesNotExist");
@ -317,7 +317,7 @@ describe("red/nodes/registry/loader",function() {
describe("#addModule",function() { describe("#addModule",function() {
it("throws error if settings unavailable", function() { it("throws error if settings unavailable", function() {
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return false;}}});
/*jshint immed: false */ /*jshint immed: false */
(function(){ (function(){
loader.addModule("test-module"); loader.addModule("test-module");
@ -326,7 +326,7 @@ describe("red/nodes/registry/loader",function() {
it("returns rejected error if module already loaded", function(done) { it("returns rejected error if module already loaded", function(done) {
stubs.push(sinon.stub(registry,"getModuleInfo",function(){return{}})); stubs.push(sinon.stub(registry,"getModuleInfo",function(){return{}}));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}});
loader.addModule("test-module").otherwise(function(err) { loader.addModule("test-module").otherwise(function(err) {
err.code.should.eql("module_already_loaded"); err.code.should.eql("module_already_loaded");
@ -338,7 +338,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(localfilesystem,"getModuleFiles",function() { stubs.push(sinon.stub(localfilesystem,"getModuleFiles",function() {
throw new Error("failure"); throw new Error("failure");
})); }));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}});
loader.addModule("test-module").otherwise(function(err) { loader.addModule("test-module").otherwise(function(err) {
err.message.should.eql("failure"); err.message.should.eql("failure");
done(); done();
@ -370,7 +370,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" })); stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" }));
stubs.push(sinon.stub(registry,"addNodeSet", function(){ return })); stubs.push(sinon.stub(registry,"addNodeSet", function(){ return }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},settings:{available:function(){return true;}}});
loader.addModule("TestNodeModule").then(function(result) { loader.addModule("TestNodeModule").then(function(result) {
result.should.eql("a node list"); result.should.eql("a node list");
registry.addNodeSet.calledOnce.should.be.true; registry.addNodeSet.calledOnce.should.be.true;
@ -420,7 +420,7 @@ describe("red/nodes/registry/loader",function() {
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" })); stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" }));
stubs.push(sinon.stub(registry,"addNodeSet", function(){ return })); stubs.push(sinon.stub(registry,"addNodeSet", function(){ return }));
stubs.push(sinon.stub(nodes,"registerType")); stubs.push(sinon.stub(nodes,"registerType"));
loader.init({i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},version: function() { return "0.12.0"}, settings:{available:function(){return true;}}}); loader.init({nodes:nodes,i18n:{defaultLang:"en-US"},events:{on:function(){},removeListener:function(){}},version: function() { return "0.12.0"}, settings:{available:function(){return true;}}});
loader.addModule("TestNodeModule").then(function(result) { loader.addModule("TestNodeModule").then(function(result) {
result.should.eql("a node list"); result.should.eql("a node list");
registry.addNodeSet.called.should.be.false; registry.addNodeSet.called.should.be.false;