Move exec and events components to util module

The exec and events components are common components that
are used by both runtime and registry. It makes sense to
move them into the util package.

This also adds some docs to the registry module
This commit is contained in:
Nick O'Leary 2020-12-02 09:25:10 +00:00
parent a1f565f756
commit 6fb96fa3c1
No known key found for this signature in database
GPG Key ID: 4F2157149161A6C9
33 changed files with 491 additions and 319 deletions

2
API.md
View File

@ -10,6 +10,6 @@ Module | Description
[@node-red/editor-api](@node-red_editor-api.html) | an Express application that serves the Node-RED editor and provides the Admin HTTP API [@node-red/editor-api](@node-red_editor-api.html) | an Express application that serves the Node-RED editor and provides the Admin HTTP API
[@node-red/runtime](@node-red_runtime.html) | the core runtime of Node-RED [@node-red/runtime](@node-red_runtime.html) | the core runtime of Node-RED
[@node-red/util](@node-red_util.html) | common utilities for the Node-RED runtime and editor modules [@node-red/util](@node-red_util.html) | common utilities for the Node-RED runtime and editor modules
@node-red/registry | the internal node registry [@node-red/registry](@node-red_registry.html) | the internal node registry
@node-red/nodes | the default set of core nodes @node-red/nodes | the default set of core nodes
@node-red/editor-client | the client-side resources of the Node-RED editor application @node-red/editor-client | the client-side resources of the Node-RED editor application

View File

@ -461,7 +461,8 @@ module.exports = function(grunt) {
'packages/node_modules/@node-red/runtime/lib/hooks.js', 'packages/node_modules/@node-red/runtime/lib/hooks.js',
'packages/node_modules/@node-red/util/**/*.js', 'packages/node_modules/@node-red/util/**/*.js',
'packages/node_modules/@node-red/editor-api/lib/index.js', 'packages/node_modules/@node-red/editor-api/lib/index.js',
'packages/node_modules/@node-red/editor-api/lib/auth/index.js' 'packages/node_modules/@node-red/editor-api/lib/auth/index.js',
'packages/node_modules/@node-red/registry/lib/index.js'
], ],
options: { options: {
destination: 'docs', destination: 'docs',

View File

@ -1,4 +1,4 @@
/** /*!
* Copyright JS Foundation and other contributors, http://js.foundation * Copyright JS Foundation and other contributors, http://js.foundation
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -29,16 +29,27 @@ var loader = require("./loader");
var installer = require("./installer"); var installer = require("./installer");
var library = require("./library"); var library = require("./library");
var settings; /**
* Initialise the registry with a reference to a runtime object
* @param {Object} runtime - a runtime object
* @memberof @node-red/registry
*/
function init(runtime) { function init(runtime) {
settings = runtime.settings; installer.init(runtime.settings);
installer.init(runtime); // Loader requires the full runtime object because it initialises
// the util module it. The Util module is responsible for constructing the
// RED object passed to node modules when they are loaded.
loader.init(runtime); loader.init(runtime);
registry.init(settings,loader,runtime.events); registry.init(runtime.settings,loader);
library.init(); library.init();
} }
/**
* Triggers the intial discovery and loading of all Node-RED node modules.
* found on the node path.
* @return {Promise} - resolves when the registry has finised discovering node modules.
* @memberof @node-red/registry
*/
function load() { function load() {
registry.load(); registry.load();
return installer.checkPrereq().then(loader.load); return installer.checkPrereq().then(loader.load);
@ -66,34 +77,221 @@ module.exports = {
init:init, init:init,
load:load, load:load,
clear: registry.clear, clear: registry.clear,
/**
* Register a node constructor function.
*
* @param {Object} nodeSet - the Node Set object the constructor is for
* @param {String} type - the node type
* @param {Function} constructor - the node constructor function
* @function
* @memberof @node-red/registry
*/
registerType: registry.registerNodeConstructor, registerType: registry.registerNodeConstructor,
/**
* Get a node constructor function.
*
* @param {String} type - the node type
* @return {Function} the node constructor function
* @function
* @memberof @node-red/registry
*/
get: registry.getNodeConstructor, get: registry.getNodeConstructor,
/**
* Get a node's set information.
*
* @param {String} type - the node type or set identifier
* @return {Object} the node set information
* @function
* @memberof @node-red/registry
*/
getNodeInfo: registry.getNodeInfo, getNodeInfo: registry.getNodeInfo,
/**
* Get a list of all nodes in the registry.
*
* @return {Object} the node list
* @function
* @memberof @node-red/registry
*/
getNodeList: registry.getNodeList, getNodeList: registry.getNodeList,
/**
* Get a modules's information.
*
* @param {String} type - the module identifier
* @return {Object} the module information
* @function
* @memberof @node-red/registry
*/
getModuleInfo: registry.getModuleInfo, getModuleInfo: registry.getModuleInfo,
/**
* Get a list of all moduless in the registry.
*
* @return {Object} the module list
* @function
* @memberof @node-red/registry
*/
getModuleList: registry.getModuleList, getModuleList: registry.getModuleList,
/**
* Get the HTML configs for all nodes in the registry.
*
* @param {String} lang - the language to return, default `en-US`
* @return {String} the node configs
* @function
* @memberof @node-red/registry
*/
getNodeConfigs: registry.getAllNodeConfigs, getNodeConfigs: registry.getAllNodeConfigs,
/**
* Get the HTML config for a single node set.
*
* @param {String} id - the node identifier
* @param {String} lang - the language to return, default `en-US`
* @return {String} the node config
* @function
* @memberof @node-red/registry
*/
getNodeConfig: registry.getNodeConfig, getNodeConfig: registry.getNodeConfig,
/**
* Get the local path to a node's icon file.
*
* @param {String} module - the module that provides the icon
* @param {String} icon - the name of the icon
* @return {String} the local path to the icon
* @function
* @memberof @node-red/registry
*/
getNodeIconPath: registry.getNodeIconPath, getNodeIconPath: registry.getNodeIconPath,
/**
* Get the full list of all icons available.
*
* @return {String} the icon list
* @function
* @memberof @node-red/registry
*/
getNodeIcons: registry.getNodeIcons, getNodeIcons: registry.getNodeIcons,
/**
* Enables a node set, making it available for use.
*
* @param {String} type - the node type or set identifier
* @return {Promise} A promise that resolves when the node set has been enabled
* @throws if the identifier is not recognised or runtime settings are unavailable
* @function
* @memberof @node-red/registry
*/
enableNode: enableNodeSet, enableNode: enableNodeSet,
/**
* Disables a node set, making it unavailable for use.
*
* @param {String} type - the node type or set identifier
* @return {Promise} A promise that resolves when the node set has been disabled
* @throws if the identifier is not recognised or runtime settings are unavailable
* @function
* @memberof @node-red/registry
*/
disableNode: registry.disableNodeSet, disableNode: registry.disableNodeSet,
/**
* Loads a new module into the registry.
*
* This will rescan the node module paths looking for this module.
*
* @param {String} module - the name of the module to add
* @return {Promise<Object>} A promise that resolves with the module information once it has been added
* @throws if the module has already been added or the runtime settings are unavailable
* @function
* @memberof @node-red/registry
*/
addModule: addModule, addModule: addModule,
/**
* Removes a module from the registry.
*
* @param {String} module - the name of the module to remove
* @return {Promise<Array>} A promise that resolves with the list of removed node sets
* @throws if the module is not found or the runtime settings are unavailable
* @function
* @memberof @node-red/registry
*/
removeModule: registry.removeModule, removeModule: registry.removeModule,
/**
* Installs a new node module using npm and then add to the registry
*
* @param {String|Buffer} module - the name of the module to install, or a Buffer containing a module tar file
* @param {String} version - the version of the module to install, default: `latest`
* @param {String} url - (optional) a url to install the module from
* @return {Promise<Array>} A promise that resolves with the module information once it has been installed
* @function
* @memberof @node-red/registry
*/
installModule: installer.installModule, installModule: installer.installModule,
/**
* Uninstalls a module using npm
*
* @param {String} module - the name of the module to uninstall
* @return {Promise<Array>} A promise that resolves when the module has been removed
* @function
* @memberof @node-red/registry
*/
uninstallModule: installer.uninstallModule, uninstallModule: installer.uninstallModule,
/**
* Update to internal list of available modules based on what has been actually
* loaded.
*
* The `autoInstallModules` runtime option means the runtime may try to install
* missing modules after the initial load is complete. If that flag is not set
* this function is used to remove the modules from the registry's saved list.
* @function
* @memberof @node-red/registry
*/
cleanModuleList: registry.cleanModuleList, cleanModuleList: registry.cleanModuleList,
/**
* Check if the regisrty is able to install/remove modules.
*
* This is based on whether it has found `npm` on the command-line.
* @return {Boolean} whether the installer is enabled
*
* @function
* @memberof @node-red/registry
*/
paletteEditorEnabled: installer.paletteEditorEnabled, paletteEditorEnabled: installer.paletteEditorEnabled,
/**
* Get a list of all example flows provided by nodes in the registry.
* @return {Object} an object, indexed by module, listing all example flows
*
* @function
* @memberof @node-red/registry
*/
getNodeExampleFlows: library.getExampleFlows, getNodeExampleFlows: library.getExampleFlows,
/**
* Gets the full path to a node example
* @param {String} module - the name of the module providing the example
* @param {String} path - the relative path of the example
* @return {String} the full path to the example
*
* @function
* @memberof @node-red/registry
*/
getNodeExampleFlowPath: library.getExampleFlowPath, getNodeExampleFlowPath: library.getExampleFlowPath,
deprecated: require("./deprecated") deprecated: require("./deprecated")

View File

@ -22,11 +22,7 @@ var tar = require("tar");
var registry = require("./registry"); var registry = require("./registry");
var library = require("./library"); var library = require("./library");
var log; const {exec,log,events} = require("@node-red/util");
var exec;
var events;
var child_process = require('child_process'); var child_process = require('child_process');
var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm';
var paletteEditorEnabled = false; var paletteEditorEnabled = false;
@ -37,11 +33,8 @@ const slashRe = process.platform === "win32" ? /\\|[/]/ : /[/]/;
const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//; const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//;
const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/; const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/;
function init(runtime) { function init(_settings) {
events = runtime.events; settings = _settings;
settings = runtime.settings;
log = runtime.log;
exec = runtime.exec;
} }
var activePromise = Promise.resolve(); var activePromise = Promise.resolve();

View File

@ -14,7 +14,7 @@
* limitations under the License. * limitations under the License.
**/ **/
var fs = require('fs'); var fs = require('fs-extra');
var fspath = require('path'); var fspath = require('path');
var runtime; var runtime;
@ -22,38 +22,34 @@ var runtime;
var exampleRoots = {}; var exampleRoots = {};
var exampleFlows = null; var exampleFlows = null;
function getFlowsFromPath(path) { async function getFlowsFromPath(path) {
return new Promise(function(resolve,reject) { var result = {};
var result = {}; var validFiles = [];
fs.readdir(path,function(err,files) { return fs.readdir(path).then(files => {
var promises = []; var promises = [];
var validFiles = []; files.forEach(function(file) {
files.forEach(function(file) { var fullPath = fspath.join(path,file);
var fullPath = fspath.join(path,file); var stats = fs.lstatSync(fullPath);
var stats = fs.lstatSync(fullPath); if (stats.isDirectory()) {
if (stats.isDirectory()) { validFiles.push(file);
validFiles.push(file); promises.push(getFlowsFromPath(fullPath));
promises.push(getFlowsFromPath(fullPath)); } else if (/\.json$/.test(file)){
} else if (/\.json$/.test(file)){ validFiles.push(file);
validFiles.push(file); promises.push(Promise.resolve(file.split(".")[0]))
promises.push(Promise.resolve(file.split(".")[0])) }
} })
}) return Promise.all(promises)
var i=0; }).then(results => {
Promise.all(promises).then(function(results) { results.forEach(function(r,i) {
results.forEach(function(r) { if (typeof r === 'string') {
if (typeof r === 'string') { result.f = result.f||[];
result.f = result.f||[]; result.f.push(r);
result.f.push(r); } else {
} else { result.d = result.d||{};
result.d = result.d||{}; result.d[validFiles[i]] = r;
result.d[validFiles[i]] = r; }
} })
i++; return result;
})
resolve(result);
})
});
}) })
} }

View File

@ -22,15 +22,14 @@ var localfilesystem = require("./localfilesystem");
var registry = require("./registry"); var registry = require("./registry");
var registryUtil = require("./util") var registryUtil = require("./util")
var i18n = require("@node-red/util").i18n; var i18n = require("@node-red/util").i18n;
var log = require("@node-red/util").log;
var settings; var settings;
var runtime;
function init(_runtime) { function init(_runtime) {
runtime = _runtime; settings = _runtime.settings;
settings = runtime.settings; localfilesystem.init(settings);
localfilesystem.init(runtime); registryUtil.init(_runtime);
registryUtil.init(runtime);
} }
function load(disableNodePathScan) { function load(disableNodePathScan) {
@ -38,7 +37,7 @@ function load(disableNodePathScan) {
// We should expose that as an option at some point, although the // We should expose that as an option at some point, although the
// performance gains are minimal. // performance gains are minimal.
//return loadNodeFiles(registry.getModuleList()); //return loadNodeFiles(registry.getModuleList());
runtime.log.info(runtime.log._("server.loading")); log.info(log._("server.loading"));
var nodeFiles = localfilesystem.getNodeFiles(disableNodePathScan); var nodeFiles = localfilesystem.getNodeFiles(disableNodePathScan);
return loadNodeFiles(nodeFiles); return loadNodeFiles(nodeFiles);
@ -51,9 +50,9 @@ function loadNodeFiles(nodeFiles) {
/* istanbul ignore else */ /* istanbul ignore else */
if (nodeFiles.hasOwnProperty(module)) { if (nodeFiles.hasOwnProperty(module)) {
if (nodeFiles[module].redVersion && if (nodeFiles[module].redVersion &&
!semver.satisfies(runtime.version().replace(/(\-[1-9A-Za-z-][0-9A-Za-z-\.]*)?(\+[0-9A-Za-z-\.]+)?$/,""), nodeFiles[module].redVersion)) { !semver.satisfies((settings.version||"0.0.0").replace(/(\-[1-9A-Za-z-][0-9A-Za-z-\.]*)?(\+[0-9A-Za-z-\.]+)?$/,""), nodeFiles[module].redVersion)) {
//TODO: log it //TODO: log it
runtime.log.warn("["+module+"] "+runtime.log._("server.node-version-mismatch",{version:nodeFiles[module].redVersion})); log.warn("["+module+"] "+log._("server.node-version-mismatch",{version:nodeFiles[module].redVersion}));
nodeFiles[module].err = "version_mismatch"; nodeFiles[module].err = "version_mismatch";
continue; continue;
} }

View File

@ -16,9 +16,6 @@
var fs = require("fs"); var fs = require("fs");
var path = require("path"); var path = require("path");
var log;
var log = require("@node-red/util").log; var log = require("@node-red/util").log;
var i18n = require("@node-red/util").i18n; var i18n = require("@node-red/util").i18n;
@ -26,8 +23,8 @@ var settings;
var disableNodePathScan = false; var disableNodePathScan = false;
var iconFileExtensions = [".png", ".gif", ".svg"]; var iconFileExtensions = [".png", ".gif", ".svg"];
function init(runtime) { function init(_settings) {
settings = runtime.settings; settings = _settings;
} }
function isIncluded(name) { function isIncluded(name) {

View File

@ -19,8 +19,7 @@ var path = require("path");
var fs = require("fs"); var fs = require("fs");
var library = require("./library"); var library = require("./library");
const {events} = require("@node-red/util")
var events;
var settings; var settings;
var loader; var loader;
@ -31,10 +30,9 @@ var nodeConstructors = {};
var nodeTypeToId = {}; var nodeTypeToId = {};
var moduleNodes = {}; var moduleNodes = {};
function init(_settings,_loader, _events) { function init(_settings,_loader) {
settings = _settings; settings = _settings;
loader = _loader; loader = _loader;
events = _events;
moduleNodes = {}; moduleNodes = {};
nodeTypeToId = {}; nodeTypeToId = {};
nodeConstructors = {}; nodeConstructors = {};

View File

@ -14,9 +14,8 @@
* limitations under the License. * limitations under the License.
**/ **/
var path = require("path"); const path = require("path");
var i18n = require("@node-red/util").i18n; const {events,i18n,log} = require("@node-red/util");
var registry;
var runtime; var runtime;
function copyObjectProperties(src,dst,copyList,blockList) { function copyObjectProperties(src,dst,copyList,blockList) {
@ -40,7 +39,7 @@ function copyObjectProperties(src,dst,copyList,blockList) {
} }
} }
function requireModule(name) { function requireModule(name) {
var moduleInfo = registry.getModuleInfo(name); var moduleInfo = require("./index").getModuleInfo(name);
if (moduleInfo && moduleInfo.path) { if (moduleInfo && moduleInfo.path) {
var relPath = path.relative(__dirname, moduleInfo.path); var relPath = path.relative(__dirname, moduleInfo.path);
return require(relPath); return require(relPath);
@ -56,14 +55,14 @@ function createNodeApi(node) {
nodes: {}, nodes: {},
log: {}, log: {},
settings: {}, settings: {},
events: runtime.events, events: events,
hooks: runtime.hooks, hooks: runtime.hooks,
util: runtime.util, util: runtime.util,
version: runtime.version, version: runtime.version,
require: requireModule, require: requireModule,
comms: { comms: {
publish: function(topic,data,retain) { publish: function(topic,data,retain) {
runtime.events.emit("comms",{ events.emit("comms",{
topic: topic, topic: topic,
data: data, data: data,
retain: retain retain: retain
@ -83,7 +82,7 @@ function createNodeApi(node) {
red.nodes.registerType = function(type,constructor,opts) { red.nodes.registerType = function(type,constructor,opts) {
runtime.nodes.registerType(node.id,type,constructor,opts); runtime.nodes.registerType(node.id,type,constructor,opts);
} }
copyObjectProperties(runtime.log,red.log,null,["init"]); copyObjectProperties(log,red.log,null,["init"]);
copyObjectProperties(runtime.settings,red.settings,null,["init","load","reset"]); copyObjectProperties(runtime.settings,red.settings,null,["init","load","reset"]);
if (runtime.adminApi) { if (runtime.adminApi) {
red.auth = runtime.adminApi.auth; red.auth = runtime.adminApi.auth;
@ -108,7 +107,6 @@ function createNodeApi(node) {
module.exports = { module.exports = {
init: function(_runtime) { init: function(_runtime) {
runtime = _runtime; runtime = _runtime;
registry = require("@node-red/registry/lib");
}, },
createNodeApi: createNodeApi createNodeApi: createNodeApi
} }

View File

@ -33,6 +33,7 @@ var runtime;
var retained = {}; var retained = {};
var connections = []; var connections = [];
const events = require("@node-red/util").events;
function handleCommsEvent(event) { function handleCommsEvent(event) {
publish(event.topic,event.data,event.retain); publish(event.topic,event.data,event.retain);
@ -88,14 +89,14 @@ var api = module.exports = {
runtime = _runtime; runtime = _runtime;
connections = []; connections = [];
retained = {}; retained = {};
runtime.events.removeListener("node-status",handleStatusEvent); events.removeListener("node-status",handleStatusEvent);
runtime.events.on("node-status",handleStatusEvent); events.on("node-status",handleStatusEvent);
runtime.events.removeListener("runtime-event",handleRuntimeEvent); events.removeListener("runtime-event",handleRuntimeEvent);
runtime.events.on("runtime-event",handleRuntimeEvent); events.on("runtime-event",handleRuntimeEvent);
runtime.events.removeListener("comms",handleCommsEvent); events.removeListener("comms",handleCommsEvent);
runtime.events.on("comms",handleCommsEvent); events.on("comms",handleCommsEvent);
runtime.events.removeListener("event-log",handleEventLog); events.removeListener("event-log",handleEventLog);
runtime.events.on("event-log",handleEventLog); events.on("event-log",handleEventLog);
}, },
/** /**

View File

@ -376,16 +376,18 @@ var api = module.exports = {
var lang = opts.lang; var lang = opts.lang;
var prevLang = runtime.i18n.i.language; var prevLang = runtime.i18n.i.language;
// Trigger a load from disk of the language if it is not the default // Trigger a load from disk of the language if it is not the default
return runtime.i18n.i.changeLanguage(lang, function(){ return new Promise( (resolve,reject) => {
var nodeList = runtime.nodes.getNodeList(); runtime.i18n.i.changeLanguage(lang, function(){
var result = {}; var nodeList = runtime.nodes.getNodeList();
nodeList.forEach(function(n) { var result = {};
if (n.module !== "node-red") { nodeList.forEach(function(n) {
result[n.id] = runtime.i18n.i.getResourceBundle(lang, n.id)||{}; if (n.module !== "node-red") {
} result[n.id] = runtime.i18n.i.getResourceBundle(lang, n.id)||{};
}
});
runtime.i18n.i.changeLanguage(prevLang);
resolve(result);
}); });
runtime.i18n.i.changeLanguage(prevLang);
return result;
}); });
}, },

View File

@ -16,8 +16,8 @@
var clone = require("clone"); var clone = require("clone");
var redUtil = require("@node-red/util").util; var redUtil = require("@node-red/util").util;
const events = require("@node-red/util").events;
var flowUtil = require("./util"); var flowUtil = require("./util");
var events = require("../events");
const context = require('../nodes/context'); const context = require('../nodes/context');
const hooks = require("../hooks"); const hooks = require("../hooks");
@ -679,7 +679,6 @@ module.exports = {
asyncMessageDelivery = !runtime.settings.runtimeSyncDelivery asyncMessageDelivery = !runtime.settings.runtimeSyncDelivery
Log = runtime.log; Log = runtime.log;
Subflow = require("./Subflow"); Subflow = require("./Subflow");
Subflow.init(runtime);
}, },
create: function(parent,global,conf) { create: function(parent,global,conf) {
return new Flow(parent,global,conf); return new Flow(parent,global,conf);

View File

@ -18,16 +18,11 @@ const clone = require("clone");
const Flow = require('./Flow').Flow; const Flow = require('./Flow').Flow;
const context = require('../nodes/context'); const context = require('../nodes/context');
const util = require("util"); const util = require("util");
const events = require("../events");
const redUtil = require("@node-red/util").util; const redUtil = require("@node-red/util").util;
const events = require("@node-red/util").events;
const flowUtil = require("./util"); const flowUtil = require("./util");
const credentials = require("../nodes/credentials"); const credentials = require("../nodes/credentials");
var Log;
/** /**
* Create deep copy of object * Create deep copy of object
*/ */
@ -509,8 +504,6 @@ function createSubflow(parent,globalFlow,subflowDef,subflowInstance) {
} }
module.exports = { module.exports = {
init: function(runtime) { init: function(runtime) {},
Log = runtime.log;
},
create: createSubflow create: createSubflow
} }

View File

@ -25,9 +25,8 @@ var context = require("../nodes/context")
var credentials = require("../nodes/credentials"); var credentials = require("../nodes/credentials");
var flowUtil = require("./util"); var flowUtil = require("./util");
var log; var log;
var events = require("../events"); const events = require("@node-red/util").events;
var redUtil = require("@node-red/util").util; var redUtil = require("@node-red/util").util;
const hooks = require("../hooks");
var storage = null; var storage = null;
var settings = null; var settings = null;
@ -712,7 +711,7 @@ module.exports = {
*/ */
load: load, load: load,
loadFlows: load, loadFlows: load,
get:getNode, get:getNode,
eachNode: eachNode, eachNode: eachNode,

View File

@ -20,19 +20,15 @@ var redNodes = require("./nodes");
var flows = require("./flows"); var flows = require("./flows");
var storage = require("./storage"); var storage = require("./storage");
var library = require("./library"); var library = require("./library");
var events = require("./events");
var hooks = require("./hooks"); var hooks = require("./hooks");
var settings = require("./settings"); var settings = require("./settings");
var exec = require("./exec");
var express = require("express"); var express = require("express");
var path = require('path'); var path = require('path');
var fs = require("fs"); var fs = require("fs");
var os = require("os"); var os = require("os");
var redUtil = require("@node-red/util"); const {log,i18n,events,exec,util} = require("@node-red/util");
var log = redUtil.log;
var i18n = redUtil.i18n;
var runtimeMetricInterval = null; var runtimeMetricInterval = null;
@ -65,7 +61,7 @@ var server;
* better abstracted. * better abstracted.
* @memberof @node-red/runtime * @memberof @node-red/runtime
*/ */
function init(userSettings,httpServer,_adminApi,__util) { function init(userSettings,httpServer,_adminApi) {
server = httpServer; server = httpServer;
userSettings.version = getVersion(); userSettings.version = getVersion();
settings.init(userSettings); settings.init(userSettings);
@ -79,14 +75,6 @@ function init(userSettings,httpServer,_adminApi,__util) {
redNodes.init(runtime); redNodes.init(runtime);
library.init(runtime); library.init(runtime);
externalAPI.init(runtime); externalAPI.init(runtime);
exec.init(runtime);
if (__util) {
log = __util.log;
i18n = __util.i18n;
} else {
log = redUtil.log;
i18n = redUtil.i18n;
}
} }
var version; var version;
@ -246,6 +234,10 @@ function reportMetrics() {
/** /**
* Stops the runtime. * Stops the runtime.
*
* Once called, Node-RED should not be restarted until the Node.JS process is
* restarted.
*
* @return {Promise} - resolves when the runtime is stopped. * @return {Promise} - resolves when the runtime is stopped.
* @memberof @node-red/runtime * @memberof @node-red/runtime
*/ */
@ -266,17 +258,17 @@ function stop() {
// This is the internal api // This is the internal api
var runtime = { var runtime = {
version: getVersion, version: getVersion,
get log() { return log }, log: log,
get i18n() { return i18n }, i18n: i18n,
events: events,
settings: settings, settings: settings,
storage: storage, storage: storage,
events: events,
hooks: hooks, hooks: hooks,
nodes: redNodes, nodes: redNodes,
flows: flows, flows: flows,
library: library, library: library,
exec: exec, exec: exec,
util: require("@node-red/util").util, util: util,
get adminApi() { return adminApi }, get adminApi() { return adminApi },
get adminApp() { return adminApp }, get adminApp() { return adminApp },
get nodeApp() { return nodeApp }, get nodeApp() { return nodeApp },

View File

@ -28,7 +28,7 @@ var context = require("./context");
var Node = require("./Node"); var Node = require("./Node");
var log; var log;
var events = require("../events"); const events = require("@node-red/util").events;
var settings; var settings;

View File

@ -17,7 +17,7 @@
var Path = require('path'); var Path = require('path');
var crypto = require('crypto'); var crypto = require('crypto');
var log = require("@node-red/util").log; // TODO: separate module var log = require("@node-red/util").log;
var runtime; var runtime;
var storageModule; var storageModule;

View File

@ -26,6 +26,7 @@ var sshKeys = require("./ssh");
var settings; var settings;
var runtime; var runtime;
var log = require("@node-red/util").log; var log = require("@node-red/util").log;
const events = require("@node-red/util").events;
var projectsDir; var projectsDir;
@ -532,7 +533,7 @@ Project.prototype.status = function(user, includeRemote) {
result.merging = true; result.merging = true;
if (!self.merging) { if (!self.merging) {
self.merging = true; self.merging = true;
runtime.events.emit("runtime-event",{ events.emit("runtime-event",{
id:"runtime-state", id:"runtime-state",
payload:{ payload:{
type:"warning", type:"warning",
@ -556,7 +557,7 @@ Project.prototype.status = function(user, includeRemote) {
} }
if (result.commits.total === 0 && Object.keys(result.files).length === 0) { if (result.commits.total === 0 && Object.keys(result.files).length === 0) {
if (!self.empty) { if (!self.empty) {
runtime.events.emit("runtime-event",{ events.emit("runtime-event",{
id:"runtime-state", id:"runtime-state",
payload:{ payload:{
type:"warning", type:"warning",
@ -570,9 +571,9 @@ Project.prototype.status = function(user, includeRemote) {
} else { } else {
if (self.empty) { if (self.empty) {
if (self.paths.flowFile) { if (self.paths.flowFile) {
runtime.events.emit("runtime-event",{id:"runtime-state",retain:true}); events.emit("runtime-event",{id:"runtime-state",retain:true});
} else { } else {
runtime.events.emit("runtime-event",{ events.emit("runtime-event",{
id:"runtime-state", id:"runtime-state",
payload:{ payload:{
type:"warning", type:"warning",

View File

@ -14,8 +14,6 @@
* limitations under the License. * limitations under the License.
**/ **/
var exec = require("../../../../exec");
var authResponseServer = require('./authServer').ResponseServer; var authResponseServer = require('./authServer').ResponseServer;
var sshResponseServer = require('./authServer').ResponseSSHServer; var sshResponseServer = require('./authServer').ResponseSSHServer;
var clone = require('clone'); var clone = require('clone');
@ -23,7 +21,7 @@ var path = require("path");
var gitCommand = "git"; var gitCommand = "git";
var gitVersion; var gitVersion;
var log = require("@node-red/util").log; const {log,exec} = require("@node-red/util");
function runGitCommand(args,cwd,env,emit) { function runGitCommand(args,cwd,env,emit) {
log.trace(gitCommand + JSON.stringify(args)); log.trace(gitCommand + JSON.stringify(args));

View File

@ -28,6 +28,7 @@ var Projects = require("./Project");
var settings; var settings;
var runtime; var runtime;
var log = require("@node-red/util").log; var log = require("@node-red/util").log;
const events = require("@node-red/util").events;
var projectsEnabled = false; var projectsEnabled = false;
var projectLogMessages = []; var projectLogMessages = [];
@ -355,11 +356,11 @@ function getActiveProject(user) {
function reloadActiveProject(action) { function reloadActiveProject(action) {
return runtime.nodes.stopFlows().then(function() { return runtime.nodes.stopFlows().then(function() {
return runtime.nodes.loadFlows(true).then(function() { return runtime.nodes.loadFlows(true).then(function() {
runtime.events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}}); events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}});
}).catch(function(err) { }).catch(function(err) {
// We're committed to the project change now, so notify editors // We're committed to the project change now, so notify editors
// that it has changed. // that it has changed.
runtime.events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}}); events.emit("runtime-event",{id:"project-update", payload:{ project: activeProject.name, action:action}});
throw err; throw err;
}); });
}); });

View File

@ -17,6 +17,8 @@
const log = require("./lib/log"); const log = require("./lib/log");
const i18n = require("./lib/i18n"); const i18n = require("./lib/i18n");
const util = require("./lib/util"); const util = require("./lib/util");
const events = require("./lib/events");
const exec = require("./lib/exec");
/** /**
* This module provides common utilities for the Node-RED runtime and editor * This module provides common utilities for the Node-RED runtime and editor
@ -54,4 +56,18 @@ module.exports = {
* @memberof @node-red/util * @memberof @node-red/util
*/ */
util: util, util: util,
/**
* Runtime events
* @mixes @node-red/util_event
* @memberof @node-red/util
*/
events: events,
/**
* Run system commands with event-log integration
* @mixes @node-red/util_exec
* @memberof @node-red/util
*/
exec: exec
} }

View File

@ -14,6 +14,11 @@
* limitations under the License. * limitations under the License.
**/ **/
/**
* Runtime events
* @mixin @node-red/util_events
*/
const events = new (require("events")).EventEmitter(); const events = new (require("events")).EventEmitter();
@ -45,14 +50,14 @@ module.exports = events;
/** /**
* Runtime events emitter * Runtime events emitter
* @mixin @node-red/runtime_events * @mixin @node-red/util_events
*/ */
/** /**
* Register an event listener for a runtime event * Register an event listener for a runtime event
* @name on * @name on
* @function * @function
* @memberof @node-red/runtime_events * @memberof @node-red/util_events
* @param {String} eventName - the name of the event to listen to * @param {String} eventName - the name of the event to listen to
* @param {Function} listener - the callback function for the event * @param {Function} listener - the callback function for the event
*/ */
@ -61,7 +66,7 @@ module.exports = events;
* Emit an event to all of its registered listeners * Emit an event to all of its registered listeners
* @name emit * @name emit
* @function * @function
* @memberof @node-red/runtime_events * @memberof @node-red/util_events
* @param {String} eventName - the name of the event to emit * @param {String} eventName - the name of the event to emit
* @param {any} ...args - the arguments to pass in the event * @param {any} ...args - the arguments to pass in the event
* @return {Boolean} - whether the event had listeners or not * @return {Boolean} - whether the event had listeners or not

View File

@ -1,4 +1,4 @@
/** /*!
* Copyright JS Foundation and other contributors, http://js.foundation * Copyright JS Foundation and other contributors, http://js.foundation
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -14,19 +14,41 @@
* limitations under the License. * limitations under the License.
**/ **/
const child_process = require('child_process'); /**
const { util } = require('@node-red/util'); * Run system commands with event-log integration
* @mixin @node-red/util_exec
*/
var events; const child_process = require('child_process');
const events = require("./events");
const util = require('./util');
function logLines(id,type,data) { function logLines(id,type,data) {
events.emit("event-log", {id:id,payload:{ts: Date.now(),data:data,type:type}}); events.emit("event-log", {id:id,payload:{ts: Date.now(),data:data,type:type}});
} }
module.exports = { module.exports = {
init: function(_runtime) { /**
events = _runtime.events; * Run a system command with stdout/err being emitted as 'event-log' events
}, * on the @node-red/util/events handler.
*
* The main arguments to this function are the same as passed to `child_process.spawn`
*
* @param {String} command - the command to run
* @param {Array} args - arguments for the command
* @param {Object} options - options to pass child_process.spawn
* @param {Boolean} emit - whether to emit events to the event-log for each line of stdout/err
* @return {Promise} A promise that resolves (rc=0) or rejects (rc!=0) when the command completes. The value
* of the promise is an object of the form:
*
* {
* code: <exit code>,
* stdout: <standard output from the command>,
* stderr: <standard error from the command>
* }
* @memberof @node-red/util_exec
*/
run: function(command,args,options,emit) { run: function(command,args,options,emit) {
var invocationId = util.generateId(); var invocationId = util.generateId();

View File

@ -1,4 +1,4 @@
/** /*!
* Copyright JS Foundation and other contributors, http://js.foundation * Copyright JS Foundation and other contributors, http://js.foundation
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -12,7 +12,6 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
* @ignore
**/ **/
/** /**
@ -91,7 +90,7 @@ var consoleLogger = function(msg) {
} catch(e){ } catch(e){
message = 'Exception trying to log: '+util.inspect(message); message = 'Exception trying to log: '+util.inspect(message);
} }
util.log("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+message); util.log("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+message);
} }
} }

View File

@ -121,6 +121,10 @@ module.exports = {
}, },
/** /**
* Stop the Node-RED application. * Stop the Node-RED application.
*
* Once called, Node-RED should not be restarted until the Node.JS process is
* restarted.
*
* @return {Promise} - resolves when complete * @return {Promise} - resolves when complete
* @memberof node-red * @memberof node-red
*/ */
@ -161,10 +165,10 @@ module.exports = {
/** /**
* Runtime events emitter * Runtime events emitter
* @see @node-red/runtime_events * @see @node-red/util_events
* @memberof node-red * @memberof node-red
*/ */
events: runtime.events, events: redUtil.events,
/** /**
* Runtime hooks engine * Runtime hooks engine

View File

@ -25,6 +25,7 @@ var NR_TEST_UTILS = require("nr-test-utils");
var installer = NR_TEST_UTILS.require("@node-red/registry/lib/installer"); var installer = NR_TEST_UTILS.require("@node-red/registry/lib/installer");
var registry = NR_TEST_UTILS.require("@node-red/registry/lib/index"); var registry = NR_TEST_UTILS.require("@node-red/registry/lib/index");
var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry"); var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry");
const { events, exec, log } = NR_TEST_UTILS.require("@node-red/util");
describe('nodes/registry/installer', function() { describe('nodes/registry/installer', function() {
@ -38,21 +39,15 @@ describe('nodes/registry/installer', function() {
_: function(msg) { return msg } _: function(msg) { return msg }
} }
var execResponse;
beforeEach(function() { beforeEach(function() {
installer.init({log:mockLog, settings:{}, events: new EventEmitter(), exec: { sinon.stub(exec,"run", () => execResponse || Promise.resolve(""))
run: function() { installer.init({})
return Promise.resolve("");
}
}});
}); });
function initInstaller(execResult) {
installer.init({log:mockLog, settings:{}, events: new EventEmitter(), exec: {
run: function() {
return execResult;
}
}});
}
afterEach(function() { afterEach(function() {
execResponse = null;
if (registry.addModule.restore) { if (registry.addModule.restore) {
registry.addModule.restore(); registry.addModule.restore();
} }
@ -72,7 +67,7 @@ describe('nodes/registry/installer', function() {
if (fs.statSync.restore) { if (fs.statSync.restore) {
fs.statSync.restore(); fs.statSync.restore();
} }
exec.run.restore();
}); });
describe("installs module", function() { describe("installs module", function() {
@ -108,7 +103,7 @@ describe('nodes/registry/installer', function() {
} }
var p = Promise.reject(res); var p = Promise.reject(res);
p.catch((err)=>{}); p.catch((err)=>{});
initInstaller(p) execResponse = p;
installer.installModule("this_wont_exist").catch(function(err) { installer.installModule("this_wont_exist").catch(function(err) {
err.should.have.property("code",404); err.should.have.property("code",404);
done(); done();
@ -122,7 +117,7 @@ describe('nodes/registry/installer', function() {
} }
var p = Promise.reject(res); var p = Promise.reject(res);
p.catch((err)=>{}); p.catch((err)=>{});
initInstaller(p) execResponse = p;
sinon.stub(typeRegistry,"getModuleInfo", function() { sinon.stub(typeRegistry,"getModuleInfo", function() {
return { return {
version: "0.1.1" version: "0.1.1"
@ -163,7 +158,7 @@ describe('nodes/registry/installer', function() {
} }
var p = Promise.reject(res); var p = Promise.reject(res);
p.catch((err)=>{}); p.catch((err)=>{});
initInstaller(p) execResponse = p;
installer.installModule("this_wont_exist").then(function() { installer.installModule("this_wont_exist").then(function() {
done(new Error("Unexpected success")); done(new Error("Unexpected success"));
}).catch(err => { }).catch(err => {
@ -181,7 +176,7 @@ describe('nodes/registry/installer', function() {
} }
var p = Promise.resolve(res); var p = Promise.resolve(res);
p.catch((err)=>{}); p.catch((err)=>{});
initInstaller(p) execResponse = p;
var addModule = sinon.stub(registry,"addModule",function(md) { var addModule = sinon.stub(registry,"addModule",function(md) {
return Promise.resolve(nodeInfo); return Promise.resolve(nodeInfo);
@ -226,7 +221,7 @@ describe('nodes/registry/installer', function() {
} }
var p = Promise.resolve(res); var p = Promise.resolve(res);
p.catch((err)=>{}); p.catch((err)=>{});
initInstaller(p) execResponse = p;
installer.installModule(resourcesDir).then(function(info) { installer.installModule(resourcesDir).then(function(info) {
info.should.eql(nodeInfo); info.should.eql(nodeInfo);
done(); done();
@ -242,7 +237,7 @@ describe('nodes/registry/installer', function() {
} }
var p = Promise.resolve(res); var p = Promise.resolve(res);
p.catch((err)=>{}); p.catch((err)=>{});
initInstaller(p) execResponse = p;
var addModule = sinon.stub(registry,"addModule",function(md) { var addModule = sinon.stub(registry,"addModule",function(md) {
return Promise.resolve(nodeInfo); return Promise.resolve(nodeInfo);
@ -280,7 +275,7 @@ describe('nodes/registry/installer', function() {
} }
var p = Promise.reject(res); var p = Promise.reject(res);
p.catch((err)=>{}); p.catch((err)=>{});
initInstaller(p) execResponse = p;
installer.uninstallModule("this_wont_exist").then(function() { installer.uninstallModule("this_wont_exist").then(function() {
done(new Error("Unexpected success")); done(new Error("Unexpected success"));
@ -304,7 +299,7 @@ describe('nodes/registry/installer', function() {
} }
var p = Promise.resolve(res); var p = Promise.resolve(res);
p.catch((err)=>{}); p.catch((err)=>{});
initInstaller(p) execResponse = p;
sinon.stub(fs,"statSync", function(fn) { return {}; }); sinon.stub(fs,"statSync", function(fn) { return {}; });

View File

@ -53,7 +53,7 @@ describe("red/nodes/registry/localfilesystem",function() {
} }
describe("#getNodeFiles",function() { describe("#getNodeFiles",function() {
it("Finds all the node files in the resources tree",function(done) { it("Finds all the node files in the resources tree",function(done) {
localfilesystem.init({settings:{coreNodesDir:resourcesDir}}); localfilesystem.init({coreNodesDir:resourcesDir});
var nodeList = localfilesystem.getNodeFiles(true); var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red"); nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red']; var nm = nodeList['node-red'];
@ -68,7 +68,7 @@ describe("red/nodes/registry/localfilesystem",function() {
done(); done();
}); });
it("Includes node files from settings",function(done) { it("Includes node files from settings",function(done) {
localfilesystem.init({settings:{nodesIncludes:['TestNode1.js'],coreNodesDir:resourcesDir}}); localfilesystem.init({nodesIncludes:['TestNode1.js'],coreNodesDir:resourcesDir});
var nodeList = localfilesystem.getNodeFiles(true); var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red"); nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red']; var nm = nodeList['node-red'];
@ -78,7 +78,7 @@ describe("red/nodes/registry/localfilesystem",function() {
done(); done();
}); });
it("Excludes node files from settings",function(done) { it("Excludes node files from settings",function(done) {
localfilesystem.init({settings:{nodesExcludes:['TestNode1.js'],coreNodesDir:resourcesDir}}); localfilesystem.init({nodesExcludes:['TestNode1.js'],coreNodesDir:resourcesDir});
var nodeList = localfilesystem.getNodeFiles(true); var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red"); nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red']; var nm = nodeList['node-red'];
@ -88,7 +88,7 @@ describe("red/nodes/registry/localfilesystem",function() {
done(); done();
}); });
it("Finds nodes in userDir/nodes",function(done) { it("Finds nodes in userDir/nodes",function(done) {
localfilesystem.init({settings:{userDir:userDir}}); localfilesystem.init({userDir:userDir});
var nodeList = localfilesystem.getNodeFiles(true); var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red"); nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red']; var nm = nodeList['node-red'];
@ -99,7 +99,7 @@ describe("red/nodes/registry/localfilesystem",function() {
}); });
it("Finds nodes in settings.nodesDir (string)",function(done) { it("Finds nodes in settings.nodesDir (string)",function(done) {
localfilesystem.init({settings:{nodesDir:userDir}}); localfilesystem.init({nodesDir:userDir});
var nodeList = localfilesystem.getNodeFiles(true); var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red"); nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red']; var nm = nodeList['node-red'];
@ -110,7 +110,7 @@ describe("red/nodes/registry/localfilesystem",function() {
}); });
it("Finds nodes in settings.nodesDir (string,relative path)",function(done) { it("Finds nodes in settings.nodesDir (string,relative path)",function(done) {
var relativeUserDir = path.join("test","unit","@node-red","registry","lib","resources","userDir"); var relativeUserDir = path.join("test","unit","@node-red","registry","lib","resources","userDir");
localfilesystem.init({settings:{nodesDir:relativeUserDir}}); localfilesystem.init({nodesDir:relativeUserDir});
var nodeList = localfilesystem.getNodeFiles(true); var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red"); nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red']; var nm = nodeList['node-red'];
@ -120,7 +120,7 @@ describe("red/nodes/registry/localfilesystem",function() {
done(); done();
}); });
it("Finds nodes in settings.nodesDir (array)",function(done) { it("Finds nodes in settings.nodesDir (array)",function(done) {
localfilesystem.init({settings:{nodesDir:[userDir]}}); localfilesystem.init({nodesDir:[userDir]});
var nodeList = localfilesystem.getNodeFiles(true); var nodeList = localfilesystem.getNodeFiles(true);
nodeList.should.have.a.property("node-red"); nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red']; var nm = nodeList['node-red'];
@ -139,7 +139,7 @@ describe("red/nodes/registry/localfilesystem",function() {
} }
return _join.apply(null,arguments); return _join.apply(null,arguments);
})); }));
localfilesystem.init({settings:{coreNodesDir:moduleDir}}); localfilesystem.init({coreNodesDir:moduleDir});
var nodeList = localfilesystem.getNodeFiles(); var nodeList = localfilesystem.getNodeFiles();
nodeList.should.have.a.property("node-red"); nodeList.should.have.a.property("node-red");
var nm = nodeList['node-red']; var nm = nodeList['node-red'];
@ -175,18 +175,7 @@ describe("red/nodes/registry/localfilesystem",function() {
it("scans icon files in the resources tree",function(done) { it("scans icon files in the resources tree",function(done) {
var count = 0; var count = 0;
localfilesystem.init({ localfilesystem.init({
coreNodesDir: resourcesDir
// events:{emit:function(eventName,dir){
// if (count === 0) {
// eventName.should.equal("node-icon-dir");
// dir.name.should.equal("node-red");
// dir.icons.should.be.an.Array();
// count = 1;
// } else if (count === 1) {
// done();
// }
// }},
settings:{coreNodesDir:resourcesDir}
}); });
var list = localfilesystem.getNodeFiles(true); var list = localfilesystem.getNodeFiles(true);
list.should.have.property("node-red"); list.should.have.property("node-red");
@ -201,22 +190,7 @@ describe("red/nodes/registry/localfilesystem",function() {
it("scans icons dir in library",function(done) { it("scans icons dir in library",function(done) {
var count = 0; var count = 0;
localfilesystem.init({ localfilesystem.init({
// userDir: userDir
// events:{emit:function(eventName,dir){
// eventName.should.equal("node-icon-dir");
// if (count === 0) {
// dir.name.should.equal("node-red");
// dir.icons.should.be.an.Array();
// count = 1;
// } else if (count === 1) {
// dir.name.should.equal("Library");
// dir.icons.should.be.an.Array();
// dir.icons.length.should.equal(1);
// dir.icons[0].should.be.equal("test_icon.png");
// done();
// }
// }},
settings:{userDir:userDir}
}); });
var list = localfilesystem.getNodeFiles(true); var list = localfilesystem.getNodeFiles(true);
list.should.have.property("node-red"); list.should.have.property("node-red");
@ -240,7 +214,7 @@ describe("red/nodes/registry/localfilesystem",function() {
} }
return _join.apply(null,arguments); return _join.apply(null,arguments);
})); }));
localfilesystem.init({settings:{coreNodesDir:moduleDir}}); localfilesystem.init({coreNodesDir:moduleDir});
var nodeModule = localfilesystem.getModuleFiles('TestNodeModule'); var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
nodeModule.should.have.a.property('TestNodeModule'); nodeModule.should.have.a.property('TestNodeModule');
nodeModule['TestNodeModule'].should.have.a.property('name','TestNodeModule'); nodeModule['TestNodeModule'].should.have.a.property('name','TestNodeModule');
@ -266,7 +240,7 @@ describe("red/nodes/registry/localfilesystem",function() {
} }
return _join.apply(null,arguments); return _join.apply(null,arguments);
})); }));
localfilesystem.init({settings:{coreNodesDir:moduleDir}}); localfilesystem.init({coreNodesDir:moduleDir});
/*jshint immed: false */ /*jshint immed: false */
(function(){ (function(){
localfilesystem.getModuleFiles('WontExistModule'); localfilesystem.getModuleFiles('WontExistModule');
@ -286,14 +260,7 @@ describe("red/nodes/registry/localfilesystem",function() {
return _join.apply(null,arguments); return _join.apply(null,arguments);
})); }));
localfilesystem.init({ localfilesystem.init({
coreNodesDir: moduleDir
// events:{emit:function(eventName,dir){
// eventName.should.equal("node-icon-dir");
// dir.name.should.equal("TestNodeModule");
// dir.icons.should.be.an.Array();
// done();
// }},
settings:{coreNodesDir:moduleDir}
}); });
var nodeModule = localfilesystem.getModuleFiles('TestNodeModule'); var nodeModule = localfilesystem.getModuleFiles('TestNodeModule');
nodeModule.should.have.property("TestNodeModule"); nodeModule.should.have.property("TestNodeModule");

View File

@ -21,9 +21,7 @@ var path = require("path");
var NR_TEST_UTILS = require("nr-test-utils"); var NR_TEST_UTILS = require("nr-test-utils");
var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry"); var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry");
var EventEmitter = require('events'); const { events } = NR_TEST_UTILS.require("@node-red/util");
var events = new EventEmitter();
describe("red/nodes/registry/registry",function() { describe("red/nodes/registry/registry",function() {
@ -84,7 +82,7 @@ describe("red/nodes/registry/registry",function() {
describe('#init/load', function() { describe('#init/load', function() {
it('loads initial config', function(done) { it('loads initial config', function(done) {
typeRegistry.init(settingsWithStorageAndInitialConfig,null,events); typeRegistry.init(settingsWithStorageAndInitialConfig,null);
typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.load(); typeRegistry.load();
typeRegistry.getNodeList().should.have.lengthOf(1); typeRegistry.getNodeList().should.have.lengthOf(1);
@ -121,7 +119,7 @@ describe("red/nodes/registry/registry",function() {
}} }}
}; };
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"}}}}'); 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,events); typeRegistry.init(legacySettings,null);
typeRegistry.load(); typeRegistry.load();
legacySettings.set.calledOnce.should.be.true(); legacySettings.set.calledOnce.should.be.true();
legacySettings.set.args[0][1].should.eql(expected); legacySettings.set.args[0][1].should.eql(expected);
@ -133,7 +131,7 @@ describe("red/nodes/registry/registry",function() {
describe.skip('#addNodeSet', function() { describe.skip('#addNodeSet', function() {
it('adds a node set for an unknown module', function() { it('adds a node set for an unknown module', function() {
typeRegistry.init(settings,null,events); typeRegistry.init(settings,null);
typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.getModuleList().should.eql({}); typeRegistry.getModuleList().should.eql({});
@ -162,7 +160,7 @@ describe("red/nodes/registry/registry",function() {
it('adds a node set to an existing module', function() { it('adds a node set to an existing module', function() {
typeRegistry.init(settings,null,events); typeRegistry.init(settings,null);
typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.getModuleList().should.eql({}); typeRegistry.getModuleList().should.eql({});
@ -191,7 +189,7 @@ describe("red/nodes/registry/registry",function() {
}); });
it('doesnt add node set types if node set has an error', function() { it('doesnt add node set types if node set has an error', function() {
typeRegistry.init(settings,null,events); typeRegistry.init(settings,null);
typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.getModuleList().should.eql({}); typeRegistry.getModuleList().should.eql({});
@ -207,7 +205,7 @@ describe("red/nodes/registry/registry",function() {
}); });
it('doesnt add node set if type already exists', function() { it('doesnt add node set if type already exists', function() {
typeRegistry.init(settings,null,events); typeRegistry.init(settings,null);
typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getNodeList().should.have.lengthOf(0);
typeRegistry.getModuleList().should.eql({}); typeRegistry.getModuleList().should.eql({});
@ -241,7 +239,7 @@ describe("red/nodes/registry/registry",function() {
describe("#enableNodeSet", function() { describe("#enableNodeSet", function() {
it('throws error if settings unavailable', function() { it('throws error if settings unavailable', function() {
typeRegistry.init(settings,null,events); typeRegistry.init(settings,null);
/*jshint immed: false */ /*jshint immed: false */
(function(){ (function(){
typeRegistry.enableNodeSet("test-module/test-name"); typeRegistry.enableNodeSet("test-module/test-name");
@ -249,7 +247,7 @@ describe("red/nodes/registry/registry",function() {
}); });
it('throws error if module unknown', function() { it('throws error if module unknown', function() {
typeRegistry.init(settingsWithStorageAndInitialConfig,null,events); typeRegistry.init(settingsWithStorageAndInitialConfig,null);
/*jshint immed: false */ /*jshint immed: false */
(function(){ (function(){
typeRegistry.enableNodeSet("test-module/unknown"); typeRegistry.enableNodeSet("test-module/unknown");
@ -260,7 +258,7 @@ describe("red/nodes/registry/registry",function() {
}); });
describe("#disableNodeSet", function() { describe("#disableNodeSet", function() {
it('throws error if settings unavailable', function() { it('throws error if settings unavailable', function() {
typeRegistry.init(settings,null,events); typeRegistry.init(settings,null);
/*jshint immed: false */ /*jshint immed: false */
(function(){ (function(){
typeRegistry.disableNodeSet("test-module/test-name"); typeRegistry.disableNodeSet("test-module/test-name");
@ -268,7 +266,7 @@ describe("red/nodes/registry/registry",function() {
}); });
it('throws error if module unknown', function() { it('throws error if module unknown', function() {
typeRegistry.init(settingsWithStorageAndInitialConfig,null,events); typeRegistry.init(settingsWithStorageAndInitialConfig,null);
/*jshint immed: false */ /*jshint immed: false */
(function(){ (function(){
typeRegistry.disableNodeSet("test-module/unknown"); typeRegistry.disableNodeSet("test-module/unknown");
@ -279,7 +277,7 @@ describe("red/nodes/registry/registry",function() {
describe('#getNodeConfig', function() { describe('#getNodeConfig', function() {
it('returns nothing for an unregistered type config', function(done) { it('returns nothing for an unregistered type config', function(done) {
typeRegistry.init(settings,null,events); typeRegistry.init(settings,null);
var config = typeRegistry.getNodeConfig("imaginary-shark"); var config = typeRegistry.getNodeConfig("imaginary-shark");
(config === null).should.be.true(); (config === null).should.be.true();
done(); done();
@ -288,7 +286,7 @@ describe("red/nodes/registry/registry",function() {
describe('#saveNodeList',function() { describe('#saveNodeList',function() {
it('rejects when settings unavailable',function(done) { it('rejects when settings unavailable',function(done) {
typeRegistry.init(stubSettings({},false,{}),null,events); 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.addModule({name: "test-module",version:"0.0.1",nodes: {"test-name":{module:"test-module",name:"test-name",types:[]}}});
typeRegistry.saveNodeList().catch(function(err) { typeRegistry.saveNodeList().catch(function(err) {
done(); done();
@ -296,7 +294,7 @@ describe("red/nodes/registry/registry",function() {
}); });
it('saves the list',function(done) { it('saves the list',function(done) {
var s = stubSettings({},true,{}); var s = stubSettings({},true,{});
typeRegistry.init(s,null,events); typeRegistry.init(s,null);
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":testNodeSet1, "test-name":testNodeSet1,
@ -325,7 +323,7 @@ describe("red/nodes/registry/registry",function() {
describe('#removeModule',function() { describe('#removeModule',function() {
it('throws error for unknown module', function() { it('throws error for unknown module', function() {
var s = stubSettings({},true,{}); var s = stubSettings({},true,{});
typeRegistry.init(s,null,events); typeRegistry.init(s,null);
/*jshint immed: false */ /*jshint immed: false */
(function(){ (function(){
typeRegistry.removeModule("test-module/unknown"); typeRegistry.removeModule("test-module/unknown");
@ -333,7 +331,7 @@ describe("red/nodes/registry/registry",function() {
}); });
it('throws error for unavaiable settings', function() { it('throws error for unavaiable settings', function() {
var s = stubSettings({},false,{}); var s = stubSettings({},false,{});
typeRegistry.init(s,null,events); typeRegistry.init(s,null);
/*jshint immed: false */ /*jshint immed: false */
(function(){ (function(){
typeRegistry.removeModule("test-module/unknown"); typeRegistry.removeModule("test-module/unknown");
@ -341,7 +339,7 @@ describe("red/nodes/registry/registry",function() {
}); });
it('removes a known module', function() { it('removes a known module', function() {
var s = stubSettings({},true,{}); var s = stubSettings({},true,{});
typeRegistry.init(s,null,events); typeRegistry.init(s,null);
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":testNodeSet1 "test-name":testNodeSet1
}}); }});
@ -360,7 +358,7 @@ describe("red/nodes/registry/registry",function() {
it('returns node config', function() { it('returns node config', function() {
typeRegistry.init(settings,{ typeRegistry.init(settings,{
getNodeHelp: function(config) { return "HE"+config.name+"LP" } getNodeHelp: function(config) { return "HE"+config.name+"LP" }
},events); });
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{ "test-name":{
@ -389,7 +387,7 @@ describe("red/nodes/registry/registry",function() {
}); });
describe('#getModuleInfo', function() { describe('#getModuleInfo', function() {
it('returns module info', function() { it('returns module info', function() {
typeRegistry.init(settings,{},events); typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{ "test-name":{
id: "test-module/test-name", id: "test-module/test-name",
@ -413,7 +411,7 @@ describe("red/nodes/registry/registry",function() {
}); });
describe('#getNodeInfo', function() { describe('#getNodeInfo', function() {
it('returns node info', function() { it('returns node info', function() {
typeRegistry.init(settings,{},events); typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{ "test-name":{
id: "test-module/test-name", id: "test-module/test-name",
@ -434,7 +432,7 @@ describe("red/nodes/registry/registry",function() {
}); });
describe('#getFullNodeInfo', function() { describe('#getFullNodeInfo', function() {
it('returns node info', function() { it('returns node info', function() {
typeRegistry.init(settings,{},events); typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{ "test-name":{
id: "test-module/test-name", id: "test-module/test-name",
@ -459,7 +457,7 @@ describe("red/nodes/registry/registry",function() {
}); });
describe('#getNodeList', function() { describe('#getNodeList', function() {
it("returns a filtered list", function() { it("returns a filtered list", function() {
typeRegistry.init(settings,{},events); typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{ "test-name":{
id: "test-module/test-name", id: "test-module/test-name",
@ -526,7 +524,7 @@ describe("red/nodes/registry/registry",function() {
it('returns a registered icon' , function() { it('returns a registered icon' , function() {
var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/'); var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/');
typeRegistry.init(settings,{},events); typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{ "test-name":{
id: "test-module/test-name", id: "test-module/test-name",
@ -558,7 +556,7 @@ describe("red/nodes/registry/registry",function() {
it('returns an icon list of registered node module', function() { it('returns an icon list of registered node module', function() {
var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/'); var testIcon = path.resolve(__dirname+'/resources/userDir/lib/icons/');
typeRegistry.init(settings,{},events); typeRegistry.init(settings,{});
typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: {
"test-name":{ "test-name":{
id: "test-module/test-name", id: "test-module/test-name",

View File

@ -19,6 +19,7 @@ var sinon = require("sinon");
var NR_TEST_UTILS = require("nr-test-utils"); var NR_TEST_UTILS = require("nr-test-utils");
var comms = NR_TEST_UTILS.require("@node-red/runtime/lib/api/comms"); 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("runtime-api/comms", function() {
describe("listens for events", function() { describe("listens for events", function() {
@ -30,21 +31,19 @@ describe("runtime-api/comms", function() {
} }
var eventHandlers = {}; var eventHandlers = {};
before(function(done) { before(function(done) {
sinon.stub(events,"removeListener", function() {})
sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler })
comms.init({ comms.init({
log: { log: {
trace: function(){} trace: function(){}
},
events: {
removeListener: function() {},
on: function(evt,handler) {
eventHandlers[evt] = handler;
}
} }
}) })
comms.addConnection({client: clientConnection}).then(done); comms.addConnection({client: clientConnection}).then(done);
}) })
after(function(done) { after(function(done) {
comms.removeConnection({client: clientConnection}).then(done); comms.removeConnection({client: clientConnection}).then(done);
events.removeListener.restore();
events.on.restore();
}) })
afterEach(function() { afterEach(function() {
messages = []; messages = [];
@ -98,18 +97,18 @@ describe("runtime-api/comms", function() {
} }
} }
before(function() { before(function() {
sinon.stub(events,"removeListener", function() {})
sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler })
comms.init({ comms.init({
log: { log: {
trace: function(){} trace: function(){}
},
events: {
removeListener: function() {},
on: function(evt,handler) {
eventHandlers[evt] = handler;
}
} }
}) })
}) })
after(function() {
events.removeListener.restore();
events.on.restore();
})
afterEach(function(done) { afterEach(function(done) {
comms.removeConnection({client: clientConnection1}).then(function() { comms.removeConnection({client: clientConnection1}).then(function() {
comms.removeConnection({client: clientConnection2}).then(done); comms.removeConnection({client: clientConnection2}).then(done);
@ -178,18 +177,18 @@ describe("runtime-api/comms", function() {
} }
var eventHandlers = {}; var eventHandlers = {};
before(function() { before(function() {
sinon.stub(events,"removeListener", function() {})
sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler })
comms.init({ comms.init({
log: { log: {
trace: function(){} trace: function(){}
},
events: {
removeListener: function() {},
on: function(evt,handler) {
eventHandlers[evt] = handler;
}
} }
}) })
}) })
after(function() {
events.removeListener.restore();
events.on.restore();
})
afterEach(function(done) { afterEach(function(done) {
messages = []; messages = [];
comms.removeConnection({client: clientConnection}).then(done); comms.removeConnection({client: clientConnection}).then(done);

View File

@ -22,7 +22,7 @@ var NR_TEST_UTILS = require("nr-test-utils");
var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows"); var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows");
var RedNode = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node"); var RedNode = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node");
var RED = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes"); var RED = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes");
var events = NR_TEST_UTILS.require("@node-red/runtime/lib/events"); var events = NR_TEST_UTILS.require("@node-red/util/lib/events");
var credentials = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/credentials"); var credentials = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/credentials");
var typeRegistry = NR_TEST_UTILS.require("@node-red/registry") var typeRegistry = NR_TEST_UTILS.require("@node-red/registry")
var Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Flow"); var Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Flow");

View File

@ -28,6 +28,7 @@ var settings = NR_TEST_UTILS.require("@node-red/runtime/lib/settings");
var util = NR_TEST_UTILS.require("@node-red/util"); var util = NR_TEST_UTILS.require("@node-red/util");
var log = NR_TEST_UTILS.require("@node-red/util").log; var log = NR_TEST_UTILS.require("@node-red/util").log;
var i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
describe("runtime", function() { describe("runtime", function() {
afterEach(function() { afterEach(function() {
@ -43,43 +44,45 @@ describe("runtime", function() {
delete process.env.NODE_RED_HOME; delete process.env.NODE_RED_HOME;
}); });
function mockUtil(metrics) { function mockUtil(metrics) {
sinon.stub(log,"log",function(){})
return { sinon.stub(log,"warn",function(){})
log:{ sinon.stub(log,"info",function(){})
log: sinon.stub(), sinon.stub(log,"trace",function(){})
warn: sinon.stub(), sinon.stub(log,"metric",function(){ return !!metrics })
info: sinon.stub(), sinon.stub(log,"_",function(){ return "abc"})
trace: sinon.stub(), sinon.stub(i18n,"registerMessageCatalog",function(){ return Promise.resolve()})
metric: sinon.stub().returns(!!metrics), }
_: function() { return "abc"} function unmockUtil() {
}, log.log.restore && log.log.restore();
i18n: { log.warn.restore && log.warn.restore();
registerMessageCatalog: function(){ log.info.restore && log.info.restore();
return Promise.resolve(); 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() { describe("init", 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() {}) sinon.stub(redNodes,"init",function() {})
mockUtil();
}); });
afterEach(function() { afterEach(function() {
log.init.restore(); log.init.restore();
settings.init.restore(); settings.init.restore();
redNodes.init.restore(); redNodes.init.restore();
unmockUtil();
}) })
it("initialises components", function() { it("initialises components", function() {
runtime.init({testSettings: true, httpAdminRoot:"/"},mockUtil()); runtime.init({testSettings: true, httpAdminRoot:"/"});
settings.init.called.should.be.true(); settings.init.called.should.be.true();
redNodes.init.called.should.be.true(); redNodes.init.called.should.be.true();
}); });
it("returns version", function() { it("returns version", function() {
runtime.init({testSettings: true, httpAdminRoot:"/"},mockUtil()); runtime.init({testSettings: true, httpAdminRoot:"/"});
return runtime.version().then(version => { return runtime.version().then(version => {
/^\d+\.\d+\.\d+(-.*)?$/.test(version).should.be.true(); /^\d+\.\d+\.\d+(-.*)?$/.test(version).should.be.true();
}); });
@ -98,7 +101,6 @@ describe("runtime", function() {
var redNodesLoadFlows; var redNodesLoadFlows;
var redNodesStartFlows; var redNodesStartFlows;
var redNodesLoadContextsPlugin; var redNodesLoadContextsPlugin;
var i18nRegisterMessageCatalog;
beforeEach(function() { beforeEach(function() {
storageInit = sinon.stub(storage,"init",function(settings) {return Promise.resolve();}); storageInit = sinon.stub(storage,"init",function(settings) {return Promise.resolve();});
@ -108,7 +110,7 @@ describe("runtime", function() {
redNodesLoadFlows = sinon.stub(redNodes,"loadFlows",function() {return Promise.resolve()}); redNodesLoadFlows = sinon.stub(redNodes,"loadFlows",function() {return Promise.resolve()});
redNodesStartFlows = sinon.stub(redNodes,"startFlows",function() {}); redNodesStartFlows = sinon.stub(redNodes,"startFlows",function() {});
redNodesLoadContextsPlugin = sinon.stub(redNodes,"loadContextsPlugin",function() {return Promise.resolve()}); redNodesLoadContextsPlugin = sinon.stub(redNodes,"loadContextsPlugin",function() {return Promise.resolve()});
i18nRegisterMessageCatalog = sinon.stub(util.i18n,"registerMessageCatalog",function() {return Promise.resolve()}); mockUtil();
}); });
afterEach(function() { afterEach(function() {
storageInit.restore(); storageInit.restore();
@ -119,7 +121,7 @@ describe("runtime", function() {
redNodesLoadFlows.restore(); redNodesLoadFlows.restore();
redNodesStartFlows.restore(); redNodesStartFlows.restore();
redNodesLoadContextsPlugin.restore(); redNodesLoadContextsPlugin.restore();
i18nRegisterMessageCatalog.restore(); unmockUtil();
}); });
it("reports errored/missing modules",function(done) { it("reports errored/missing modules",function(done) {
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function(cb) { redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function(cb) {
@ -128,8 +130,7 @@ describe("runtime", function() {
{ module:"module",enabled:true,loaded:false,types:["typeA","typeB"]} // missing { module:"module",enabled:true,loaded:false,types:["typeA","typeB"]} // missing
].filter(cb); ].filter(cb);
}); });
var util = mockUtil(); runtime.init({testSettings: true, httpAdminRoot:"/", load:function() { return Promise.resolve();}});
runtime.init({testSettings: true, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util);
// sinon.stub(console,"log"); // sinon.stub(console,"log");
runtime.start().then(function() { runtime.start().then(function() {
// console.log.restore(); // console.log.restore();
@ -139,9 +140,9 @@ describe("runtime", function() {
redNodesLoad.calledOnce.should.be.true(); redNodesLoad.calledOnce.should.be.true();
redNodesLoadFlows.calledOnce.should.be.true(); redNodesLoadFlows.calledOnce.should.be.true();
util.log.warn.calledWithMatch("Failed to register 1 node type"); log.warn.calledWithMatch("Failed to register 1 node type");
util.log.warn.calledWithMatch("Missing node modules"); log.warn.calledWithMatch("Missing node modules");
util.log.warn.calledWithMatch(" - module: typeA, typeB"); log.warn.calledWithMatch(" - module: typeA, typeB");
redNodesCleanModuleList.calledOnce.should.be.true(); redNodesCleanModuleList.calledOnce.should.be.true();
done(); done();
} catch(err) { } catch(err) {
@ -159,16 +160,15 @@ describe("runtime", function() {
].filter(cb); ].filter(cb);
}); });
var serverInstallModule = sinon.stub(redNodes,"installModule",function(name) { return Promise.resolve({nodes:[]});}); var serverInstallModule = sinon.stub(redNodes,"installModule",function(name) { return Promise.resolve({nodes:[]});});
var util = mockUtil(); runtime.init({testSettings: true, autoInstallModules:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}});
runtime.init({testSettings: true, autoInstallModules:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util);
sinon.stub(console,"log"); sinon.stub(console,"log");
runtime.start().then(function() { runtime.start().then(function() {
console.log.restore(); console.log.restore();
try { try {
util.log.warn.calledWithMatch("Failed to register 2 node types"); log.warn.calledWithMatch("Failed to register 2 node types");
util.log.warn.calledWithMatch("Missing node modules"); log.warn.calledWithMatch("Missing node modules");
util.log.warn.calledWithMatch(" - module: typeA, typeB"); log.warn.calledWithMatch(" - module: typeA, typeB");
util.log.warn.calledWithMatch(" - node-red: typeC, typeD"); log.warn.calledWithMatch(" - node-red: typeC, typeD");
redNodesCleanModuleList.calledOnce.should.be.false(); redNodesCleanModuleList.calledOnce.should.be.false();
serverInstallModule.calledOnce.should.be.true(); serverInstallModule.calledOnce.should.be.true();
serverInstallModule.calledWithMatch("module"); serverInstallModule.calledWithMatch("module");
@ -186,14 +186,13 @@ describe("runtime", function() {
{ err:"errored",name:"errName" } // error { err:"errored",name:"errName" } // error
].filter(cb); ].filter(cb);
}); });
var util = mockUtil(); runtime.init({testSettings: true, verbose:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}});
runtime.init({testSettings: true, verbose:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util);
sinon.stub(console,"log"); sinon.stub(console,"log");
runtime.start().then(function() { runtime.start().then(function() {
console.log.restore(); console.log.restore();
try { try {
util.log.warn.neverCalledWithMatch("Failed to register 1 node type"); log.warn.neverCalledWithMatch("Failed to register 1 node type");
util.log.warn.calledWithMatch("[errName] errored"); log.warn.calledWithMatch("[errName] errored");
done(); done();
} catch(err) { } catch(err) {
done(err); done(err);
@ -204,21 +203,21 @@ describe("runtime", function() {
it("reports runtime metrics",function(done) { it("reports runtime metrics",function(done) {
var stopFlows = sinon.stub(redNodes,"stopFlows",function() { return Promise.resolve();} ); var stopFlows = sinon.stub(redNodes,"stopFlows",function() { return Promise.resolve();} );
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function() {return []}); redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function() {return []});
var util = mockUtil(true); unmockUtil();
mockUtil(true);
runtime.init( runtime.init(
{testSettings: true, runtimeMetricInterval:200, httpAdminRoot:"/", load:function() { return Promise.resolve();}}, {testSettings: true, runtimeMetricInterval:200, httpAdminRoot:"/", load:function() { return Promise.resolve();}},
{}, {},
undefined, undefined);
util);
// sinon.stub(console,"log"); // sinon.stub(console,"log");
runtime.start().then(function() { runtime.start().then(function() {
// console.log.restore(); // console.log.restore();
setTimeout(function() { setTimeout(function() {
try { try {
util.log.log.args.should.have.lengthOf(3); log.log.args.should.have.lengthOf(3);
util.log.log.args[0][0].should.have.property("event","runtime.memory.rss"); log.log.args[0][0].should.have.property("event","runtime.memory.rss");
util.log.log.args[1][0].should.have.property("event","runtime.memory.heapTotal"); log.log.args[1][0].should.have.property("event","runtime.memory.heapTotal");
util.log.log.args[2][0].should.have.property("event","runtime.memory.heapUsed"); log.log.args[2][0].should.have.property("event","runtime.memory.heapUsed");
done(); done();
} catch(err) { } catch(err) {
done(err); done(err);

View File

@ -17,9 +17,9 @@ var should = require("should");
var NR_TEST_UTILS = require("nr-test-utils"); var NR_TEST_UTILS = require("nr-test-utils");
describe("runtime/events", function() { describe("@node-red/util/events", function() {
it('can be required without errors', function() { it('can be required without errors', function() {
NR_TEST_UTILS.require("@node-red/runtime/lib/events"); NR_TEST_UTILS.require("@node-red/util/lib/events");
}); });
it.skip('more tests needed', function(){}) it.skip('more tests needed', function(){})
}); });

View File

@ -16,30 +16,31 @@
var should = require("should"); var should = require("should");
var sinon = require("sinon"); var sinon = require("sinon");
var path = require("path"); var path = require("path");
var events = require("events"); var EventEmitter = require("events").EventEmitter;
var child_process = require('child_process'); var child_process = require('child_process');
var NR_TEST_UTILS = require("nr-test-utils"); var NR_TEST_UTILS = require("nr-test-utils");
var exec = NR_TEST_UTILS.require("@node-red/runtime/lib/exec"); 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() { describe("runtime/exec", function() {
var logEvents; var logEvents;
var mockProcess; var mockProcess;
const eventLogHandler = function(ev) {
logEvents.push(ev);
}
beforeEach(function() { beforeEach(function() {
var logEventHandler = new events.EventEmitter();
logEvents = [];
logEventHandler.on('event-log', function(ev) {
logEvents.push(ev);
});
exec.init({events:logEventHandler});
mockProcess = new events.EventEmitter(); logEvents = [];
mockProcess.stdout = new events.EventEmitter(); events.on("event-log", eventLogHandler);
mockProcess.stderr = new events.EventEmitter();
mockProcess = new EventEmitter();
mockProcess.stdout = new EventEmitter();
mockProcess.stderr = new EventEmitter();
sinon.stub(child_process,'spawn',function(command,args,options) { sinon.stub(child_process,'spawn',function(command,args,options) {
mockProcess._args = {command,args,options}; mockProcess._args = {command,args,options};
return mockProcess; return mockProcess;
@ -47,6 +48,7 @@ describe("runtime/exec", function() {
}); });
afterEach(function() { afterEach(function() {
events.removeListener("event-log", eventLogHandler);
if (child_process.spawn.restore) { if (child_process.spawn.restore) {
child_process.spawn.restore(); child_process.spawn.restore();
} }