diff --git a/API.md b/API.md index f349ea8fe..692a34723 100644 --- a/API.md +++ b/API.md @@ -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/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/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/editor-client | the client-side resources of the Node-RED editor application diff --git a/Gruntfile.js b/Gruntfile.js index b01763ab0..2bdc2e3aa 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -461,7 +461,8 @@ module.exports = function(grunt) { 'packages/node_modules/@node-red/runtime/lib/hooks.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/auth/index.js' + 'packages/node_modules/@node-red/editor-api/lib/auth/index.js', + 'packages/node_modules/@node-red/registry/lib/index.js' ], options: { destination: 'docs', diff --git a/packages/node_modules/@node-red/registry/lib/index.js b/packages/node_modules/@node-red/registry/lib/index.js index 2805534a2..ebcde8cea 100644 --- a/packages/node_modules/@node-red/registry/lib/index.js +++ b/packages/node_modules/@node-red/registry/lib/index.js @@ -1,4 +1,4 @@ -/** +/*! * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -29,16 +29,27 @@ var loader = require("./loader"); var installer = require("./installer"); 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) { - settings = runtime.settings; - installer.init(runtime); + installer.init(runtime.settings); + // 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); - registry.init(settings,loader,runtime.events); + registry.init(runtime.settings,loader); 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() { registry.load(); return installer.checkPrereq().then(loader.load); @@ -66,34 +77,221 @@ module.exports = { init:init, load:load, 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, + /** + * 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 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, + + + /** + * Get a list of all nodes in the registry. + * + * @return {Object} the node list + * @function + * @memberof @node-red/registry + */ 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, + + /** + * Get a list of all moduless in the registry. + * + * @return {Object} the module list + * @function + * @memberof @node-red/registry + */ 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, + + /** + * 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, + + /** + * 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, + + + /** + * Get the full list of all icons available. + * + * @return {String} the icon list + * @function + * @memberof @node-red/registry + */ 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, + + /** + * 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, + + /** + * 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} 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, + + /** + * Removes a module from the registry. + * + * @param {String} module - the name of the module to remove + * @return {Promise} 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, + /** + * 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} A promise that resolves with the module information once it has been installed + * @function + * @memberof @node-red/registry + */ installModule: installer.installModule, + + + /** + * Uninstalls a module using npm + * + * @param {String} module - the name of the module to uninstall + * @return {Promise} A promise that resolves when the module has been removed + * @function + * @memberof @node-red/registry + */ 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, + /** + * 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, + /** + * 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, + + + /** + * 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, deprecated: require("./deprecated") diff --git a/packages/node_modules/@node-red/registry/lib/installer.js b/packages/node_modules/@node-red/registry/lib/installer.js index 03f9eb11c..9735aa8a1 100644 --- a/packages/node_modules/@node-red/registry/lib/installer.js +++ b/packages/node_modules/@node-red/registry/lib/installer.js @@ -22,11 +22,7 @@ var tar = require("tar"); var registry = require("./registry"); var library = require("./library"); -var log; -var exec; - -var events; - +const {exec,log,events} = require("@node-red/util"); var child_process = require('child_process'); var npmCommand = process.platform === 'win32' ? 'npm.cmd' : 'npm'; var paletteEditorEnabled = false; @@ -37,11 +33,8 @@ const slashRe = process.platform === "win32" ? /\\|[/]/ : /[/]/; const pkgurlRe = /^(https?|git(|\+https?|\+ssh|\+file)):\/\//; const localtgzRe = /^([a-zA-Z]:|\/).+tgz$/; -function init(runtime) { - events = runtime.events; - settings = runtime.settings; - log = runtime.log; - exec = runtime.exec; +function init(_settings) { + settings = _settings; } var activePromise = Promise.resolve(); diff --git a/packages/node_modules/@node-red/registry/lib/library.js b/packages/node_modules/@node-red/registry/lib/library.js index a8ca8a775..90b0fda82 100644 --- a/packages/node_modules/@node-red/registry/lib/library.js +++ b/packages/node_modules/@node-red/registry/lib/library.js @@ -14,7 +14,7 @@ * limitations under the License. **/ -var fs = require('fs'); +var fs = require('fs-extra'); var fspath = require('path'); var runtime; @@ -22,38 +22,34 @@ var runtime; var exampleRoots = {}; var exampleFlows = null; -function getFlowsFromPath(path) { - return new Promise(function(resolve,reject) { - var result = {}; - fs.readdir(path,function(err,files) { - var promises = []; - var validFiles = []; - files.forEach(function(file) { - var fullPath = fspath.join(path,file); - var stats = fs.lstatSync(fullPath); - if (stats.isDirectory()) { - validFiles.push(file); - promises.push(getFlowsFromPath(fullPath)); - } else if (/\.json$/.test(file)){ - validFiles.push(file); - promises.push(Promise.resolve(file.split(".")[0])) - } - }) - var i=0; - Promise.all(promises).then(function(results) { - results.forEach(function(r) { - if (typeof r === 'string') { - result.f = result.f||[]; - result.f.push(r); - } else { - result.d = result.d||{}; - result.d[validFiles[i]] = r; - } - i++; - }) - resolve(result); - }) - }); +async function getFlowsFromPath(path) { + var result = {}; + var validFiles = []; + return fs.readdir(path).then(files => { + var promises = []; + files.forEach(function(file) { + var fullPath = fspath.join(path,file); + var stats = fs.lstatSync(fullPath); + if (stats.isDirectory()) { + validFiles.push(file); + promises.push(getFlowsFromPath(fullPath)); + } else if (/\.json$/.test(file)){ + validFiles.push(file); + promises.push(Promise.resolve(file.split(".")[0])) + } + }) + return Promise.all(promises) + }).then(results => { + results.forEach(function(r,i) { + if (typeof r === 'string') { + result.f = result.f||[]; + result.f.push(r); + } else { + result.d = result.d||{}; + result.d[validFiles[i]] = r; + } + }) + return result; }) } diff --git a/packages/node_modules/@node-red/registry/lib/loader.js b/packages/node_modules/@node-red/registry/lib/loader.js index 3a960c73c..18d202420 100644 --- a/packages/node_modules/@node-red/registry/lib/loader.js +++ b/packages/node_modules/@node-red/registry/lib/loader.js @@ -22,15 +22,14 @@ var localfilesystem = require("./localfilesystem"); var registry = require("./registry"); var registryUtil = require("./util") var i18n = require("@node-red/util").i18n; +var log = require("@node-red/util").log; var settings; -var runtime; function init(_runtime) { - runtime = _runtime; - settings = runtime.settings; - localfilesystem.init(runtime); - registryUtil.init(runtime); + settings = _runtime.settings; + localfilesystem.init(settings); + registryUtil.init(_runtime); } function load(disableNodePathScan) { @@ -38,7 +37,7 @@ function load(disableNodePathScan) { // We should expose that as an option at some point, although the // performance gains are minimal. //return loadNodeFiles(registry.getModuleList()); - runtime.log.info(runtime.log._("server.loading")); + log.info(log._("server.loading")); var nodeFiles = localfilesystem.getNodeFiles(disableNodePathScan); return loadNodeFiles(nodeFiles); @@ -51,9 +50,9 @@ function loadNodeFiles(nodeFiles) { /* istanbul ignore else */ if (nodeFiles.hasOwnProperty(module)) { 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 - 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"; continue; } diff --git a/packages/node_modules/@node-red/registry/lib/localfilesystem.js b/packages/node_modules/@node-red/registry/lib/localfilesystem.js index d5bef63cd..7aea3f57b 100644 --- a/packages/node_modules/@node-red/registry/lib/localfilesystem.js +++ b/packages/node_modules/@node-red/registry/lib/localfilesystem.js @@ -16,9 +16,6 @@ var fs = require("fs"); var path = require("path"); - -var log; - var log = require("@node-red/util").log; var i18n = require("@node-red/util").i18n; @@ -26,8 +23,8 @@ var settings; var disableNodePathScan = false; var iconFileExtensions = [".png", ".gif", ".svg"]; -function init(runtime) { - settings = runtime.settings; +function init(_settings) { + settings = _settings; } function isIncluded(name) { diff --git a/packages/node_modules/@node-red/registry/lib/registry.js b/packages/node_modules/@node-red/registry/lib/registry.js index 89f04eacc..a91735071 100644 --- a/packages/node_modules/@node-red/registry/lib/registry.js +++ b/packages/node_modules/@node-red/registry/lib/registry.js @@ -19,8 +19,7 @@ var path = require("path"); var fs = require("fs"); var library = require("./library"); - -var events; +const {events} = require("@node-red/util") var settings; var loader; @@ -31,10 +30,9 @@ var nodeConstructors = {}; var nodeTypeToId = {}; var moduleNodes = {}; -function init(_settings,_loader, _events) { +function init(_settings,_loader) { settings = _settings; loader = _loader; - events = _events; moduleNodes = {}; nodeTypeToId = {}; nodeConstructors = {}; diff --git a/packages/node_modules/@node-red/registry/lib/util.js b/packages/node_modules/@node-red/registry/lib/util.js index 5a6d3da38..dbb6c6fc7 100644 --- a/packages/node_modules/@node-red/registry/lib/util.js +++ b/packages/node_modules/@node-red/registry/lib/util.js @@ -14,9 +14,8 @@ * limitations under the License. **/ -var path = require("path"); -var i18n = require("@node-red/util").i18n; -var registry; +const path = require("path"); +const {events,i18n,log} = require("@node-red/util"); var runtime; function copyObjectProperties(src,dst,copyList,blockList) { @@ -40,7 +39,7 @@ function copyObjectProperties(src,dst,copyList,blockList) { } } function requireModule(name) { - var moduleInfo = registry.getModuleInfo(name); + var moduleInfo = require("./index").getModuleInfo(name); if (moduleInfo && moduleInfo.path) { var relPath = path.relative(__dirname, moduleInfo.path); return require(relPath); @@ -56,14 +55,14 @@ function createNodeApi(node) { nodes: {}, log: {}, settings: {}, - events: runtime.events, + events: events, hooks: runtime.hooks, util: runtime.util, version: runtime.version, require: requireModule, comms: { publish: function(topic,data,retain) { - runtime.events.emit("comms",{ + events.emit("comms",{ topic: topic, data: data, retain: retain @@ -83,7 +82,7 @@ function createNodeApi(node) { red.nodes.registerType = function(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"]); if (runtime.adminApi) { red.auth = runtime.adminApi.auth; @@ -108,7 +107,6 @@ function createNodeApi(node) { module.exports = { init: function(_runtime) { runtime = _runtime; - registry = require("@node-red/registry/lib"); }, createNodeApi: createNodeApi } diff --git a/packages/node_modules/@node-red/runtime/lib/api/comms.js b/packages/node_modules/@node-red/runtime/lib/api/comms.js index 42e727412..90f1603cd 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/comms.js +++ b/packages/node_modules/@node-red/runtime/lib/api/comms.js @@ -33,6 +33,7 @@ var runtime; var retained = {}; var connections = []; +const events = require("@node-red/util").events; function handleCommsEvent(event) { publish(event.topic,event.data,event.retain); @@ -88,14 +89,14 @@ var api = module.exports = { runtime = _runtime; connections = []; retained = {}; - runtime.events.removeListener("node-status",handleStatusEvent); - runtime.events.on("node-status",handleStatusEvent); - runtime.events.removeListener("runtime-event",handleRuntimeEvent); - runtime.events.on("runtime-event",handleRuntimeEvent); - runtime.events.removeListener("comms",handleCommsEvent); - runtime.events.on("comms",handleCommsEvent); - runtime.events.removeListener("event-log",handleEventLog); - runtime.events.on("event-log",handleEventLog); + events.removeListener("node-status",handleStatusEvent); + events.on("node-status",handleStatusEvent); + events.removeListener("runtime-event",handleRuntimeEvent); + events.on("runtime-event",handleRuntimeEvent); + events.removeListener("comms",handleCommsEvent); + events.on("comms",handleCommsEvent); + events.removeListener("event-log",handleEventLog); + events.on("event-log",handleEventLog); }, /** diff --git a/packages/node_modules/@node-red/runtime/lib/api/nodes.js b/packages/node_modules/@node-red/runtime/lib/api/nodes.js index 6a05b4c17..9ac83c814 100644 --- a/packages/node_modules/@node-red/runtime/lib/api/nodes.js +++ b/packages/node_modules/@node-red/runtime/lib/api/nodes.js @@ -376,16 +376,18 @@ var api = module.exports = { var lang = opts.lang; var prevLang = runtime.i18n.i.language; // Trigger a load from disk of the language if it is not the default - return runtime.i18n.i.changeLanguage(lang, function(){ - var nodeList = runtime.nodes.getNodeList(); - var result = {}; - nodeList.forEach(function(n) { - if (n.module !== "node-red") { - result[n.id] = runtime.i18n.i.getResourceBundle(lang, n.id)||{}; - } + return new Promise( (resolve,reject) => { + runtime.i18n.i.changeLanguage(lang, function(){ + var nodeList = runtime.nodes.getNodeList(); + var result = {}; + nodeList.forEach(function(n) { + 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; }); }, diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js index a7e00bfbc..a4791e084 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/Flow.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/Flow.js @@ -16,8 +16,8 @@ var clone = require("clone"); var redUtil = require("@node-red/util").util; +const events = require("@node-red/util").events; var flowUtil = require("./util"); -var events = require("../events"); const context = require('../nodes/context'); const hooks = require("../hooks"); @@ -679,7 +679,6 @@ module.exports = { asyncMessageDelivery = !runtime.settings.runtimeSyncDelivery Log = runtime.log; Subflow = require("./Subflow"); - Subflow.init(runtime); }, create: function(parent,global,conf) { return new Flow(parent,global,conf); diff --git a/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js b/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js index 78ec9ee75..da15ecfe4 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/Subflow.js @@ -18,16 +18,11 @@ const clone = require("clone"); const Flow = require('./Flow').Flow; const context = require('../nodes/context'); const util = require("util"); -const events = require("../events"); - const redUtil = require("@node-red/util").util; +const events = require("@node-red/util").events; const flowUtil = require("./util"); - - const credentials = require("../nodes/credentials"); -var Log; - /** * Create deep copy of object */ @@ -509,8 +504,6 @@ function createSubflow(parent,globalFlow,subflowDef,subflowInstance) { } module.exports = { - init: function(runtime) { - Log = runtime.log; - }, + init: function(runtime) {}, create: createSubflow } diff --git a/packages/node_modules/@node-red/runtime/lib/flows/index.js b/packages/node_modules/@node-red/runtime/lib/flows/index.js index a207b8f05..350115f81 100644 --- a/packages/node_modules/@node-red/runtime/lib/flows/index.js +++ b/packages/node_modules/@node-red/runtime/lib/flows/index.js @@ -25,9 +25,8 @@ var context = require("../nodes/context") var credentials = require("../nodes/credentials"); var flowUtil = require("./util"); var log; -var events = require("../events"); +const events = require("@node-red/util").events; var redUtil = require("@node-red/util").util; -const hooks = require("../hooks"); var storage = null; var settings = null; @@ -712,7 +711,7 @@ module.exports = { */ load: load, loadFlows: load, - + get:getNode, eachNode: eachNode, diff --git a/packages/node_modules/@node-red/runtime/lib/index.js b/packages/node_modules/@node-red/runtime/lib/index.js index 89b0dcfd6..dd1594467 100644 --- a/packages/node_modules/@node-red/runtime/lib/index.js +++ b/packages/node_modules/@node-red/runtime/lib/index.js @@ -20,19 +20,15 @@ var redNodes = require("./nodes"); var flows = require("./flows"); var storage = require("./storage"); var library = require("./library"); -var events = require("./events"); var hooks = require("./hooks"); var settings = require("./settings"); -var exec = require("./exec"); var express = require("express"); var path = require('path'); var fs = require("fs"); var os = require("os"); -var redUtil = require("@node-red/util"); -var log = redUtil.log; -var i18n = redUtil.i18n; +const {log,i18n,events,exec,util} = require("@node-red/util"); var runtimeMetricInterval = null; @@ -65,7 +61,7 @@ var server; * better abstracted. * @memberof @node-red/runtime */ -function init(userSettings,httpServer,_adminApi,__util) { +function init(userSettings,httpServer,_adminApi) { server = httpServer; userSettings.version = getVersion(); settings.init(userSettings); @@ -79,14 +75,6 @@ function init(userSettings,httpServer,_adminApi,__util) { redNodes.init(runtime); library.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; @@ -246,6 +234,10 @@ function reportMetrics() { /** * 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. * @memberof @node-red/runtime */ @@ -266,17 +258,17 @@ function stop() { // This is the internal api var runtime = { version: getVersion, - get log() { return log }, - get i18n() { return i18n }, + log: log, + i18n: i18n, + events: events, settings: settings, storage: storage, - events: events, hooks: hooks, nodes: redNodes, flows: flows, library: library, exec: exec, - util: require("@node-red/util").util, + util: util, get adminApi() { return adminApi }, get adminApp() { return adminApp }, get nodeApp() { return nodeApp }, diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/index.js b/packages/node_modules/@node-red/runtime/lib/nodes/index.js index be31df2f7..858274be2 100644 --- a/packages/node_modules/@node-red/runtime/lib/nodes/index.js +++ b/packages/node_modules/@node-red/runtime/lib/nodes/index.js @@ -28,7 +28,7 @@ var context = require("./context"); var Node = require("./Node"); var log; -var events = require("../events"); +const events = require("@node-red/util").events; var settings; diff --git a/packages/node_modules/@node-red/runtime/lib/storage/index.js b/packages/node_modules/@node-red/runtime/lib/storage/index.js index e7f09c20f..f5e07e254 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/index.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/index.js @@ -17,7 +17,7 @@ var Path = require('path'); var crypto = require('crypto'); -var log = require("@node-red/util").log; // TODO: separate module +var log = require("@node-red/util").log; var runtime; var storageModule; diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js index 55bb9d078..d87001f1f 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/Project.js @@ -26,6 +26,7 @@ var sshKeys = require("./ssh"); var settings; var runtime; var log = require("@node-red/util").log; +const events = require("@node-red/util").events; var projectsDir; @@ -532,7 +533,7 @@ Project.prototype.status = function(user, includeRemote) { result.merging = true; if (!self.merging) { self.merging = true; - runtime.events.emit("runtime-event",{ + events.emit("runtime-event",{ id:"runtime-state", payload:{ type:"warning", @@ -556,7 +557,7 @@ Project.prototype.status = function(user, includeRemote) { } if (result.commits.total === 0 && Object.keys(result.files).length === 0) { if (!self.empty) { - runtime.events.emit("runtime-event",{ + events.emit("runtime-event",{ id:"runtime-state", payload:{ type:"warning", @@ -570,9 +571,9 @@ Project.prototype.status = function(user, includeRemote) { } else { if (self.empty) { if (self.paths.flowFile) { - runtime.events.emit("runtime-event",{id:"runtime-state",retain:true}); + events.emit("runtime-event",{id:"runtime-state",retain:true}); } else { - runtime.events.emit("runtime-event",{ + events.emit("runtime-event",{ id:"runtime-state", payload:{ type:"warning", diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/index.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/index.js index dbcb5fb61..e1ded4337 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/index.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/git/index.js @@ -14,8 +14,6 @@ * limitations under the License. **/ -var exec = require("../../../../exec"); - var authResponseServer = require('./authServer').ResponseServer; var sshResponseServer = require('./authServer').ResponseSSHServer; var clone = require('clone'); @@ -23,7 +21,7 @@ var path = require("path"); var gitCommand = "git"; var gitVersion; -var log = require("@node-red/util").log; +const {log,exec} = require("@node-red/util"); function runGitCommand(args,cwd,env,emit) { log.trace(gitCommand + JSON.stringify(args)); diff --git a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js index 80a3f31e4..3bbeb823b 100644 --- a/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js +++ b/packages/node_modules/@node-red/runtime/lib/storage/localfilesystem/projects/index.js @@ -28,6 +28,7 @@ var Projects = require("./Project"); var settings; var runtime; var log = require("@node-red/util").log; +const events = require("@node-red/util").events; var projectsEnabled = false; var projectLogMessages = []; @@ -355,11 +356,11 @@ function getActiveProject(user) { function reloadActiveProject(action) { return runtime.nodes.stopFlows().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) { // We're committed to the project change now, so notify editors // 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; }); }); diff --git a/packages/node_modules/@node-red/util/index.js b/packages/node_modules/@node-red/util/index.js index 66ac91bd3..29e1a480c 100644 --- a/packages/node_modules/@node-red/util/index.js +++ b/packages/node_modules/@node-red/util/index.js @@ -17,6 +17,8 @@ const log = require("./lib/log"); const i18n = require("./lib/i18n"); 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 @@ -54,4 +56,18 @@ module.exports = { * @memberof @node-red/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 } diff --git a/packages/node_modules/@node-red/runtime/lib/events.js b/packages/node_modules/@node-red/util/lib/events.js similarity index 92% rename from packages/node_modules/@node-red/runtime/lib/events.js rename to packages/node_modules/@node-red/util/lib/events.js index 8e6935222..df45b4d16 100644 --- a/packages/node_modules/@node-red/runtime/lib/events.js +++ b/packages/node_modules/@node-red/util/lib/events.js @@ -14,6 +14,11 @@ * limitations under the License. **/ + /** + * Runtime events + * @mixin @node-red/util_events + */ + const events = new (require("events")).EventEmitter(); @@ -45,14 +50,14 @@ module.exports = events; /** * Runtime events emitter - * @mixin @node-red/runtime_events + * @mixin @node-red/util_events */ /** * Register an event listener for a runtime event * @name on * @function - * @memberof @node-red/runtime_events + * @memberof @node-red/util_events * @param {String} eventName - the name of the event to listen to * @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 * @name emit * @function - * @memberof @node-red/runtime_events + * @memberof @node-red/util_events * @param {String} eventName - the name of the event to emit * @param {any} ...args - the arguments to pass in the event * @return {Boolean} - whether the event had listeners or not diff --git a/packages/node_modules/@node-red/runtime/lib/exec.js b/packages/node_modules/@node-red/util/lib/exec.js similarity index 67% rename from packages/node_modules/@node-red/runtime/lib/exec.js rename to packages/node_modules/@node-red/util/lib/exec.js index 0ef3c069c..c7197ef65 100644 --- a/packages/node_modules/@node-red/runtime/lib/exec.js +++ b/packages/node_modules/@node-red/util/lib/exec.js @@ -1,4 +1,4 @@ -/** +/*! * Copyright JS Foundation and other contributors, http://js.foundation * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -14,19 +14,41 @@ * 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) { events.emit("event-log", {id:id,payload:{ts: Date.now(),data:data,type:type}}); } 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: , + * stdout: , + * stderr: + * } + + * @memberof @node-red/util_exec + */ run: function(command,args,options,emit) { var invocationId = util.generateId(); diff --git a/packages/node_modules/@node-red/util/lib/log.js b/packages/node_modules/@node-red/util/lib/log.js index 8d7b84966..341019080 100644 --- a/packages/node_modules/@node-red/util/lib/log.js +++ b/packages/node_modules/@node-red/util/lib/log.js @@ -1,4 +1,4 @@ -/** +/*! * Copyright JS Foundation and other contributors, http://js.foundation * * 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. * See the License for the specific language governing permissions and * limitations under the License. - * @ignore **/ /** @@ -91,7 +90,7 @@ var consoleLogger = function(msg) { } catch(e){ message = 'Exception trying to log: '+util.inspect(message); } - + util.log("["+levelNames[msg.level]+"] "+(msg.type?"["+msg.type+":"+(msg.name||msg.id)+"] ":"")+message); } } diff --git a/packages/node_modules/node-red/lib/red.js b/packages/node_modules/node-red/lib/red.js index 86fa513d1..e46e40e26 100644 --- a/packages/node_modules/node-red/lib/red.js +++ b/packages/node_modules/node-red/lib/red.js @@ -121,6 +121,10 @@ module.exports = { }, /** * 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 * @memberof node-red */ @@ -161,10 +165,10 @@ module.exports = { /** * Runtime events emitter - * @see @node-red/runtime_events + * @see @node-red/util_events * @memberof node-red */ - events: runtime.events, + events: redUtil.events, /** * Runtime hooks engine diff --git a/test/unit/@node-red/registry/lib/installer_spec.js b/test/unit/@node-red/registry/lib/installer_spec.js index b344dbbea..e0e7380f6 100644 --- a/test/unit/@node-red/registry/lib/installer_spec.js +++ b/test/unit/@node-red/registry/lib/installer_spec.js @@ -25,6 +25,7 @@ var NR_TEST_UTILS = require("nr-test-utils"); var installer = NR_TEST_UTILS.require("@node-red/registry/lib/installer"); var registry = NR_TEST_UTILS.require("@node-red/registry/lib/index"); 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() { @@ -38,21 +39,15 @@ describe('nodes/registry/installer', function() { _: function(msg) { return msg } } + var execResponse; + beforeEach(function() { - installer.init({log:mockLog, settings:{}, events: new EventEmitter(), exec: { - run: function() { - return Promise.resolve(""); - } - }}); + sinon.stub(exec,"run", () => execResponse || Promise.resolve("")) + installer.init({}) }); - function initInstaller(execResult) { - installer.init({log:mockLog, settings:{}, events: new EventEmitter(), exec: { - run: function() { - return execResult; - } - }}); - } + afterEach(function() { + execResponse = null; if (registry.addModule.restore) { registry.addModule.restore(); } @@ -72,7 +67,7 @@ describe('nodes/registry/installer', function() { if (fs.statSync.restore) { fs.statSync.restore(); } - + exec.run.restore(); }); describe("installs module", function() { @@ -108,7 +103,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.reject(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; installer.installModule("this_wont_exist").catch(function(err) { err.should.have.property("code",404); done(); @@ -122,7 +117,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.reject(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; sinon.stub(typeRegistry,"getModuleInfo", function() { return { version: "0.1.1" @@ -163,7 +158,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.reject(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; installer.installModule("this_wont_exist").then(function() { done(new Error("Unexpected success")); }).catch(err => { @@ -181,7 +176,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.resolve(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; var addModule = sinon.stub(registry,"addModule",function(md) { return Promise.resolve(nodeInfo); @@ -226,7 +221,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.resolve(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; installer.installModule(resourcesDir).then(function(info) { info.should.eql(nodeInfo); done(); @@ -242,7 +237,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.resolve(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; var addModule = sinon.stub(registry,"addModule",function(md) { return Promise.resolve(nodeInfo); @@ -280,7 +275,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.reject(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; installer.uninstallModule("this_wont_exist").then(function() { done(new Error("Unexpected success")); @@ -304,7 +299,7 @@ describe('nodes/registry/installer', function() { } var p = Promise.resolve(res); p.catch((err)=>{}); - initInstaller(p) + execResponse = p; sinon.stub(fs,"statSync", function(fn) { return {}; }); diff --git a/test/unit/@node-red/registry/lib/localfilesystem_spec.js b/test/unit/@node-red/registry/lib/localfilesystem_spec.js index d86a08adb..5cb3c180d 100644 --- a/test/unit/@node-red/registry/lib/localfilesystem_spec.js +++ b/test/unit/@node-red/registry/lib/localfilesystem_spec.js @@ -53,7 +53,7 @@ describe("red/nodes/registry/localfilesystem",function() { } describe("#getNodeFiles",function() { 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); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -68,7 +68,7 @@ describe("red/nodes/registry/localfilesystem",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); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -78,7 +78,7 @@ describe("red/nodes/registry/localfilesystem",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); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -88,7 +88,7 @@ describe("red/nodes/registry/localfilesystem",function() { done(); }); it("Finds nodes in userDir/nodes",function(done) { - localfilesystem.init({settings:{userDir:userDir}}); + localfilesystem.init({userDir:userDir}); var nodeList = localfilesystem.getNodeFiles(true); nodeList.should.have.a.property("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) { - localfilesystem.init({settings:{nodesDir:userDir}}); + localfilesystem.init({nodesDir:userDir}); var nodeList = localfilesystem.getNodeFiles(true); nodeList.should.have.a.property("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) { 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); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -120,7 +120,7 @@ describe("red/nodes/registry/localfilesystem",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); nodeList.should.have.a.property("node-red"); var nm = nodeList['node-red']; @@ -139,7 +139,7 @@ describe("red/nodes/registry/localfilesystem",function() { } return _join.apply(null,arguments); })); - localfilesystem.init({settings:{coreNodesDir:moduleDir}}); + localfilesystem.init({coreNodesDir:moduleDir}); var nodeList = localfilesystem.getNodeFiles(); nodeList.should.have.a.property("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) { var count = 0; localfilesystem.init({ - - // 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} + coreNodesDir: resourcesDir }); var list = localfilesystem.getNodeFiles(true); list.should.have.property("node-red"); @@ -201,22 +190,7 @@ describe("red/nodes/registry/localfilesystem",function() { it("scans icons dir in library",function(done) { var count = 0; localfilesystem.init({ - // - // 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} + userDir: userDir }); var list = localfilesystem.getNodeFiles(true); list.should.have.property("node-red"); @@ -240,7 +214,7 @@ describe("red/nodes/registry/localfilesystem",function() { } return _join.apply(null,arguments); })); - localfilesystem.init({settings:{coreNodesDir:moduleDir}}); + localfilesystem.init({coreNodesDir:moduleDir}); var nodeModule = localfilesystem.getModuleFiles('TestNodeModule'); nodeModule.should.have.a.property('TestNodeModule'); nodeModule['TestNodeModule'].should.have.a.property('name','TestNodeModule'); @@ -266,7 +240,7 @@ describe("red/nodes/registry/localfilesystem",function() { } return _join.apply(null,arguments); })); - localfilesystem.init({settings:{coreNodesDir:moduleDir}}); + localfilesystem.init({coreNodesDir:moduleDir}); /*jshint immed: false */ (function(){ localfilesystem.getModuleFiles('WontExistModule'); @@ -286,14 +260,7 @@ describe("red/nodes/registry/localfilesystem",function() { return _join.apply(null,arguments); })); localfilesystem.init({ - - // 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} + coreNodesDir: moduleDir }); var nodeModule = localfilesystem.getModuleFiles('TestNodeModule'); nodeModule.should.have.property("TestNodeModule"); diff --git a/test/unit/@node-red/registry/lib/registry_spec.js b/test/unit/@node-red/registry/lib/registry_spec.js index d493ed688..60b48938d 100644 --- a/test/unit/@node-red/registry/lib/registry_spec.js +++ b/test/unit/@node-red/registry/lib/registry_spec.js @@ -21,9 +21,7 @@ var path = require("path"); var NR_TEST_UTILS = require("nr-test-utils"); var typeRegistry = NR_TEST_UTILS.require("@node-red/registry/lib/registry"); -var EventEmitter = require('events'); - -var events = new EventEmitter(); +const { events } = NR_TEST_UTILS.require("@node-red/util"); describe("red/nodes/registry/registry",function() { @@ -84,7 +82,7 @@ describe("red/nodes/registry/registry",function() { describe('#init/load', function() { it('loads initial config', function(done) { - typeRegistry.init(settingsWithStorageAndInitialConfig,null,events); + typeRegistry.init(settingsWithStorageAndInitialConfig,null); typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.load(); 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"}}}}'); - typeRegistry.init(legacySettings,null,events); + typeRegistry.init(legacySettings,null); typeRegistry.load(); legacySettings.set.calledOnce.should.be.true(); legacySettings.set.args[0][1].should.eql(expected); @@ -133,7 +131,7 @@ describe("red/nodes/registry/registry",function() { describe.skip('#addNodeSet', 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.getModuleList().should.eql({}); @@ -162,7 +160,7 @@ describe("red/nodes/registry/registry",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.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() { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); typeRegistry.getNodeList().should.have.lengthOf(0); typeRegistry.getModuleList().should.eql({}); @@ -207,7 +205,7 @@ describe("red/nodes/registry/registry",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.getModuleList().should.eql({}); @@ -241,7 +239,7 @@ describe("red/nodes/registry/registry",function() { describe("#enableNodeSet", function() { it('throws error if settings unavailable', function() { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); /*jshint immed: false */ (function(){ typeRegistry.enableNodeSet("test-module/test-name"); @@ -249,7 +247,7 @@ describe("red/nodes/registry/registry",function() { }); it('throws error if module unknown', function() { - typeRegistry.init(settingsWithStorageAndInitialConfig,null,events); + typeRegistry.init(settingsWithStorageAndInitialConfig,null); /*jshint immed: false */ (function(){ typeRegistry.enableNodeSet("test-module/unknown"); @@ -260,7 +258,7 @@ describe("red/nodes/registry/registry",function() { }); describe("#disableNodeSet", function() { it('throws error if settings unavailable', function() { - typeRegistry.init(settings,null,events); + typeRegistry.init(settings,null); /*jshint immed: false */ (function(){ typeRegistry.disableNodeSet("test-module/test-name"); @@ -268,7 +266,7 @@ describe("red/nodes/registry/registry",function() { }); it('throws error if module unknown', function() { - typeRegistry.init(settingsWithStorageAndInitialConfig,null,events); + typeRegistry.init(settingsWithStorageAndInitialConfig,null); /*jshint immed: false */ (function(){ typeRegistry.disableNodeSet("test-module/unknown"); @@ -279,7 +277,7 @@ describe("red/nodes/registry/registry",function() { describe('#getNodeConfig', function() { 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"); (config === null).should.be.true(); done(); @@ -288,7 +286,7 @@ describe("red/nodes/registry/registry",function() { describe('#saveNodeList',function() { 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.saveNodeList().catch(function(err) { done(); @@ -296,7 +294,7 @@ describe("red/nodes/registry/registry",function() { }); it('saves the list',function(done) { var s = stubSettings({},true,{}); - typeRegistry.init(s,null,events); + typeRegistry.init(s,null); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":testNodeSet1, @@ -325,7 +323,7 @@ describe("red/nodes/registry/registry",function() { describe('#removeModule',function() { it('throws error for unknown module', function() { var s = stubSettings({},true,{}); - typeRegistry.init(s,null,events); + typeRegistry.init(s,null); /*jshint immed: false */ (function(){ typeRegistry.removeModule("test-module/unknown"); @@ -333,7 +331,7 @@ describe("red/nodes/registry/registry",function() { }); it('throws error for unavaiable settings', function() { var s = stubSettings({},false,{}); - typeRegistry.init(s,null,events); + typeRegistry.init(s,null); /*jshint immed: false */ (function(){ typeRegistry.removeModule("test-module/unknown"); @@ -341,7 +339,7 @@ describe("red/nodes/registry/registry",function() { }); it('removes a known module', function() { var s = stubSettings({},true,{}); - typeRegistry.init(s,null,events); + typeRegistry.init(s,null); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":testNodeSet1 }}); @@ -360,7 +358,7 @@ describe("red/nodes/registry/registry",function() { it('returns node config', function() { typeRegistry.init(settings,{ getNodeHelp: function(config) { return "HE"+config.name+"LP" } - },events); + }); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ @@ -389,7 +387,7 @@ describe("red/nodes/registry/registry",function() { }); describe('#getModuleInfo', function() { it('returns module info', function() { - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", @@ -413,7 +411,7 @@ describe("red/nodes/registry/registry",function() { }); describe('#getNodeInfo', function() { it('returns node info', function() { - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", @@ -434,7 +432,7 @@ describe("red/nodes/registry/registry",function() { }); describe('#getFullNodeInfo', function() { it('returns node info', function() { - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", @@ -459,7 +457,7 @@ describe("red/nodes/registry/registry",function() { }); describe('#getNodeList', function() { it("returns a filtered list", function() { - typeRegistry.init(settings,{},events); + typeRegistry.init(settings,{}); typeRegistry.addModule({name: "test-module",version:"0.0.1",nodes: { "test-name":{ id: "test-module/test-name", @@ -526,7 +524,7 @@ describe("red/nodes/registry/registry",function() { it('returns a registered icon' , function() { 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: { "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() { 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: { "test-name":{ id: "test-module/test-name", diff --git a/test/unit/@node-red/runtime/lib/api/comms_spec.js b/test/unit/@node-red/runtime/lib/api/comms_spec.js index e1359cb7d..2f2e35a54 100644 --- a/test/unit/@node-red/runtime/lib/api/comms_spec.js +++ b/test/unit/@node-red/runtime/lib/api/comms_spec.js @@ -19,6 +19,7 @@ var sinon = require("sinon"); var NR_TEST_UTILS = require("nr-test-utils"); var comms = NR_TEST_UTILS.require("@node-red/runtime/lib/api/comms"); +var events = NR_TEST_UTILS.require("@node-red/util/lib/events"); describe("runtime-api/comms", function() { describe("listens for events", function() { @@ -30,21 +31,19 @@ describe("runtime-api/comms", function() { } var eventHandlers = {}; before(function(done) { + sinon.stub(events,"removeListener", function() {}) + sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler }) comms.init({ log: { trace: function(){} - }, - events: { - removeListener: function() {}, - on: function(evt,handler) { - eventHandlers[evt] = handler; - } } }) comms.addConnection({client: clientConnection}).then(done); }) after(function(done) { comms.removeConnection({client: clientConnection}).then(done); + events.removeListener.restore(); + events.on.restore(); }) afterEach(function() { messages = []; @@ -98,18 +97,18 @@ describe("runtime-api/comms", function() { } } before(function() { + sinon.stub(events,"removeListener", function() {}) + sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler }) comms.init({ log: { trace: function(){} - }, - events: { - removeListener: function() {}, - on: function(evt,handler) { - eventHandlers[evt] = handler; - } } }) }) + after(function() { + events.removeListener.restore(); + events.on.restore(); + }) afterEach(function(done) { comms.removeConnection({client: clientConnection1}).then(function() { comms.removeConnection({client: clientConnection2}).then(done); @@ -178,18 +177,18 @@ describe("runtime-api/comms", function() { } var eventHandlers = {}; before(function() { + sinon.stub(events,"removeListener", function() {}) + sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler }) comms.init({ log: { trace: function(){} - }, - events: { - removeListener: function() {}, - on: function(evt,handler) { - eventHandlers[evt] = handler; - } } }) }) + after(function() { + events.removeListener.restore(); + events.on.restore(); + }) afterEach(function(done) { messages = []; comms.removeConnection({client: clientConnection}).then(done); diff --git a/test/unit/@node-red/runtime/lib/flows/index_spec.js b/test/unit/@node-red/runtime/lib/flows/index_spec.js index 6f6066100..e230d2407 100644 --- a/test/unit/@node-red/runtime/lib/flows/index_spec.js +++ b/test/unit/@node-red/runtime/lib/flows/index_spec.js @@ -22,7 +22,7 @@ var NR_TEST_UTILS = require("nr-test-utils"); var flows = NR_TEST_UTILS.require("@node-red/runtime/lib/flows"); var RedNode = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes/Node"); var RED = NR_TEST_UTILS.require("@node-red/runtime/lib/nodes"); -var events = NR_TEST_UTILS.require("@node-red/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 typeRegistry = NR_TEST_UTILS.require("@node-red/registry") var Flow = NR_TEST_UTILS.require("@node-red/runtime/lib/flows/Flow"); diff --git a/test/unit/@node-red/runtime/lib/index_spec.js b/test/unit/@node-red/runtime/lib/index_spec.js index f6a506de1..60bdc286b 100644 --- a/test/unit/@node-red/runtime/lib/index_spec.js +++ b/test/unit/@node-red/runtime/lib/index_spec.js @@ -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 log = NR_TEST_UTILS.require("@node-red/util").log; +var i18n = NR_TEST_UTILS.require("@node-red/util").i18n; describe("runtime", function() { afterEach(function() { @@ -43,43 +44,45 @@ describe("runtime", function() { delete process.env.NODE_RED_HOME; }); function mockUtil(metrics) { - - return { - log:{ - log: sinon.stub(), - warn: sinon.stub(), - info: sinon.stub(), - trace: sinon.stub(), - metric: sinon.stub().returns(!!metrics), - _: function() { return "abc"} - }, - i18n: { - registerMessageCatalog: function(){ - return Promise.resolve(); - } - } - } + sinon.stub(log,"log",function(){}) + sinon.stub(log,"warn",function(){}) + sinon.stub(log,"info",function(){}) + sinon.stub(log,"trace",function(){}) + sinon.stub(log,"metric",function(){ return !!metrics }) + sinon.stub(log,"_",function(){ return "abc"}) + sinon.stub(i18n,"registerMessageCatalog",function(){ return Promise.resolve()}) + } + function unmockUtil() { + log.log.restore && log.log.restore(); + log.warn.restore && log.warn.restore(); + log.info.restore && log.info.restore(); + log.trace.restore && log.trace.restore(); + log.metric.restore && log.metric.restore(); + log._.restore && log._.restore(); + i18n.registerMessageCatalog.restore && i18n.registerMessageCatalog.restore(); } describe("init", function() { beforeEach(function() { sinon.stub(log,"init",function() {}); sinon.stub(settings,"init",function() {}); sinon.stub(redNodes,"init",function() {}) + mockUtil(); }); afterEach(function() { log.init.restore(); settings.init.restore(); redNodes.init.restore(); + unmockUtil(); }) it("initialises components", function() { - runtime.init({testSettings: true, httpAdminRoot:"/"},mockUtil()); + runtime.init({testSettings: true, httpAdminRoot:"/"}); settings.init.called.should.be.true(); redNodes.init.called.should.be.true(); }); it("returns version", function() { - runtime.init({testSettings: true, httpAdminRoot:"/"},mockUtil()); + runtime.init({testSettings: true, httpAdminRoot:"/"}); return runtime.version().then(version => { /^\d+\.\d+\.\d+(-.*)?$/.test(version).should.be.true(); }); @@ -98,7 +101,6 @@ describe("runtime", function() { var redNodesLoadFlows; var redNodesStartFlows; var redNodesLoadContextsPlugin; - var i18nRegisterMessageCatalog; beforeEach(function() { 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()}); redNodesStartFlows = sinon.stub(redNodes,"startFlows",function() {}); redNodesLoadContextsPlugin = sinon.stub(redNodes,"loadContextsPlugin",function() {return Promise.resolve()}); - i18nRegisterMessageCatalog = sinon.stub(util.i18n,"registerMessageCatalog",function() {return Promise.resolve()}); + mockUtil(); }); afterEach(function() { storageInit.restore(); @@ -119,7 +121,7 @@ describe("runtime", function() { redNodesLoadFlows.restore(); redNodesStartFlows.restore(); redNodesLoadContextsPlugin.restore(); - i18nRegisterMessageCatalog.restore(); + unmockUtil(); }); it("reports errored/missing modules",function(done) { redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function(cb) { @@ -128,8 +130,7 @@ describe("runtime", function() { { module:"module",enabled:true,loaded:false,types:["typeA","typeB"]} // missing ].filter(cb); }); - var util = mockUtil(); - runtime.init({testSettings: true, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util); + runtime.init({testSettings: true, httpAdminRoot:"/", load:function() { return Promise.resolve();}}); // sinon.stub(console,"log"); runtime.start().then(function() { // console.log.restore(); @@ -139,9 +140,9 @@ describe("runtime", function() { redNodesLoad.calledOnce.should.be.true(); redNodesLoadFlows.calledOnce.should.be.true(); - util.log.warn.calledWithMatch("Failed to register 1 node type"); - util.log.warn.calledWithMatch("Missing node modules"); - util.log.warn.calledWithMatch(" - module: typeA, typeB"); + log.warn.calledWithMatch("Failed to register 1 node type"); + log.warn.calledWithMatch("Missing node modules"); + log.warn.calledWithMatch(" - module: typeA, typeB"); redNodesCleanModuleList.calledOnce.should.be.true(); done(); } catch(err) { @@ -159,16 +160,15 @@ describe("runtime", function() { ].filter(cb); }); 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();}},util); + runtime.init({testSettings: true, autoInstallModules:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}}); sinon.stub(console,"log"); runtime.start().then(function() { console.log.restore(); try { - util.log.warn.calledWithMatch("Failed to register 2 node types"); - util.log.warn.calledWithMatch("Missing node modules"); - util.log.warn.calledWithMatch(" - module: typeA, typeB"); - util.log.warn.calledWithMatch(" - node-red: typeC, typeD"); + log.warn.calledWithMatch("Failed to register 2 node types"); + log.warn.calledWithMatch("Missing node modules"); + log.warn.calledWithMatch(" - module: typeA, typeB"); + log.warn.calledWithMatch(" - node-red: typeC, typeD"); redNodesCleanModuleList.calledOnce.should.be.false(); serverInstallModule.calledOnce.should.be.true(); serverInstallModule.calledWithMatch("module"); @@ -186,14 +186,13 @@ describe("runtime", function() { { err:"errored",name:"errName" } // error ].filter(cb); }); - var util = mockUtil(); - runtime.init({testSettings: true, verbose:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util); + runtime.init({testSettings: true, verbose:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}}); sinon.stub(console,"log"); runtime.start().then(function() { console.log.restore(); try { - util.log.warn.neverCalledWithMatch("Failed to register 1 node type"); - util.log.warn.calledWithMatch("[errName] errored"); + log.warn.neverCalledWithMatch("Failed to register 1 node type"); + log.warn.calledWithMatch("[errName] errored"); done(); } catch(err) { done(err); @@ -204,21 +203,21 @@ describe("runtime", function() { it("reports runtime metrics",function(done) { var stopFlows = sinon.stub(redNodes,"stopFlows",function() { return Promise.resolve();} ); redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function() {return []}); - var util = mockUtil(true); + unmockUtil(); + mockUtil(true); runtime.init( {testSettings: true, runtimeMetricInterval:200, httpAdminRoot:"/", load:function() { return Promise.resolve();}}, {}, - undefined, - util); + undefined); // sinon.stub(console,"log"); runtime.start().then(function() { // console.log.restore(); setTimeout(function() { try { - util.log.log.args.should.have.lengthOf(3); - util.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"); - util.log.log.args[2][0].should.have.property("event","runtime.memory.heapUsed"); + log.log.args.should.have.lengthOf(3); + log.log.args[0][0].should.have.property("event","runtime.memory.rss"); + log.log.args[1][0].should.have.property("event","runtime.memory.heapTotal"); + log.log.args[2][0].should.have.property("event","runtime.memory.heapUsed"); done(); } catch(err) { done(err); diff --git a/test/unit/@node-red/runtime/lib/events_spec.js b/test/unit/@node-red/util/lib/events_spec.js similarity index 88% rename from test/unit/@node-red/runtime/lib/events_spec.js rename to test/unit/@node-red/util/lib/events_spec.js index 09b47693d..09f5d2ae0 100644 --- a/test/unit/@node-red/runtime/lib/events_spec.js +++ b/test/unit/@node-red/util/lib/events_spec.js @@ -17,9 +17,9 @@ var should = require("should"); 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() { - NR_TEST_UTILS.require("@node-red/runtime/lib/events"); + NR_TEST_UTILS.require("@node-red/util/lib/events"); }); it.skip('more tests needed', function(){}) }); diff --git a/test/unit/@node-red/runtime/lib/exec_spec.js b/test/unit/@node-red/util/lib/exec_spec.js similarity index 90% rename from test/unit/@node-red/runtime/lib/exec_spec.js rename to test/unit/@node-red/util/lib/exec_spec.js index 1e37b7cc1..887938d16 100644 --- a/test/unit/@node-red/runtime/lib/exec_spec.js +++ b/test/unit/@node-red/util/lib/exec_spec.js @@ -16,30 +16,31 @@ var should = require("should"); var sinon = require("sinon"); var path = require("path"); -var events = require("events"); +var EventEmitter = require("events").EventEmitter; var child_process = require('child_process'); 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() { var logEvents; var mockProcess; + const eventLogHandler = function(ev) { + logEvents.push(ev); + } 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(); - mockProcess.stdout = new events.EventEmitter(); - mockProcess.stderr = new events.EventEmitter(); + logEvents = []; + events.on("event-log", eventLogHandler); + + mockProcess = new EventEmitter(); + mockProcess.stdout = new EventEmitter(); + mockProcess.stderr = new EventEmitter(); sinon.stub(child_process,'spawn',function(command,args,options) { mockProcess._args = {command,args,options}; return mockProcess; @@ -47,6 +48,7 @@ describe("runtime/exec", function() { }); afterEach(function() { + events.removeListener("event-log", eventLogHandler); if (child_process.spawn.restore) { child_process.spawn.restore(); }