Compare commits

..

15 Commits

Author SHA1 Message Date
Nick O'Leary
b0955705be Update to 1.3.2 2021-04-13 13:34:16 +01:00
Nick O'Leary
a4a624d537 Update changelog 2021-04-13 13:33:41 +01:00
Nick O'Leary
6a8cf1b768 Fix variable reference error in editableList
Fixes #2933
2021-04-13 13:24:54 +01:00
Kazuhito Yokoi
39274b0c5d Add Japanese translations for Node-RED v1.3.1 (#2930) 2021-04-12 14:15:07 +01:00
Dave Conway-Jones
55c2430671 Merge branch 'master' of https://github.com/node-red/node-red 2021-04-12 12:16:32 +01:00
Dave Conway-Jones
023486e175 File out node - fix timing of msg.send to be after close., and...
allow msg.encoding to set encoding if desired.
To close #2921
2021-04-12 12:16:23 +01:00
Nick O'Leary
8227643741 Merge branch 'pr_2920' 2021-04-12 12:08:32 +01:00
Nick O'Leary
e44131f97a Update function node help reference to node properties 2021-04-12 12:08:07 +01:00
Nick O'Leary
5028377d45 Fix MQTT Broker TLS config row layout
Fixes #2927
2021-04-12 11:48:10 +01:00
Nick O'Leary
51aaf1b150 Handle package.json without dependencies section 2021-04-12 10:34:43 +01:00
Nick O'Leary
13406e76de Ensure theme login image is passed through to api response
Fixes #2929
2021-04-12 10:06:35 +01:00
Dave Conway-Jones
4672d98e8a split node - add comment to info re $N being number of messages arriving 2021-04-12 09:47:18 +01:00
Dave Conway-Jones
858b3d640a fix CSV parsing with other than , separator
(and joining as well...
and add tests
to close #2925
2021-04-10 22:17:31 +01:00
Nick O'Leary
6087002562 Fix handling of user-provided keymap
Fixes #2926
2021-04-10 21:34:26 +01:00
Kristian Heljas
ad788fbed1 Function node: describe node.outputCount in help text 2021-04-08 21:09:44 +03:00
90 changed files with 529 additions and 1462 deletions

View File

@@ -13,6 +13,9 @@ matrix:
- node_js: "12"
script:
- ./node_modules/.bin/grunt no-coverage
- node_js: "16"
- node_js: "10"
script:
- ./node_modules/.bin/grunt no-coverage
#- node_js: "8"
# script:
# - ./node_modules/.bin/grunt no-coverage

View File

@@ -1,3 +1,23 @@
### 1.3.2: Maintenance Release
Runtime
- Handle package.json without dependencies section
Editor
- Fix variable reference error in editableList Fixes #2933
- Fix handling of user-provided keymap Fixes #2926
- Ensure theme login image is passed through to api response Fixes #2929
- Add Japanese translations for Node-RED v1.3.1 (#2930) @kazuhitoyokoi
Nodes
- CSV: Fix CSV parsing with other than , separator
- File out: Fix timing of msg.send to be after close
- Function: describe `node.outputCount` in help text
- MQTT: Fix MQTT Broker TLS config row layout Fixes #2927
- Split: add comment to info re $N being number of messages arriving
### 1.3.1: Maintenance Release

View File

@@ -208,9 +208,7 @@ module.exports = function(grunt) {
"node_modules/marked/marked.min.js",
"node_modules/dompurify/dist/purify.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/d3/d3.v3.min.js",
"node_modules/i18next/i18next.min.js",
"node_modules/i18next-http-backend/i18nextHttpBackend.min.js",
"node_modules/jquery-i18next/jquery-i18next.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/i18next/i18next.min.js",
"node_modules/jsonata/jsonata-es5.min.js",
"packages/node_modules/@node-red/editor-client/src/vendor/jsonata/formatter.js",
"packages/node_modules/@node-red/editor-client/src/vendor/ace/ace.js",

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "2.0.0-beta.1",
"version": "1.3.2",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -41,11 +41,11 @@
"denque": "1.5.0",
"express": "4.17.1",
"express-session": "1.17.1",
"fs-extra": "9.1.0",
"fs-extra": "8.1.0",
"fs.notify": "0.0.4",
"hash-sum": "2.0.0",
"https-proxy-agent": "5.0.0",
"i18next": "20.2.1",
"i18next": "15.1.2",
"iconv-lite": "0.6.2",
"is-utf8": "0.2.1",
"js-yaml": "3.14.0",
@@ -60,6 +60,9 @@
"multer": "1.4.2",
"mustache": "4.2.0",
"node-red-admin": "^0.2.6",
"node-red-node-rbe": "^0.5.0",
"node-red-node-sentiment": "^0.1.6",
"node-red-node-tail": "^0.3.0",
"nopt": "5.0.0",
"oauth2orize": "1.11.0",
"on-headers": "1.0.2",
@@ -68,14 +71,14 @@
"passport-oauth2-client-password": "0.1.2",
"raw-body": "2.4.1",
"request": "2.88.0",
"semver": "7.3.5",
"semver": "6.3.0",
"tar": "6.1.0",
"uglify-js": "3.13.3",
"ws": "6.2.1",
"xml2js": "0.4.23"
},
"optionalDependencies": {
"bcrypt": "5.0.1"
"bcrypt": "3.0.8"
},
"devDependencies": {
"dompurify": "2.2.7",
@@ -84,14 +87,14 @@
"grunt-cli": "~1.4.2",
"grunt-concurrent": "3.0.0",
"grunt-contrib-clean": "~2.0.0",
"grunt-contrib-compress": "2.0.0",
"grunt-contrib-compress": "1.6.0",
"grunt-contrib-concat": "~1.0.1",
"grunt-contrib-copy": "~1.0.0",
"grunt-contrib-jshint": "3.0.0",
"grunt-contrib-uglify": "5.0.1",
"grunt-contrib-jshint": "~2.1.0",
"grunt-contrib-uglify": "~4.0.1",
"grunt-contrib-watch": "~1.1.0",
"grunt-jsdoc": "2.4.1",
"grunt-jsdoc-to-markdown": "6.0.0",
"grunt-jsdoc-to-markdown": "5.0.0",
"grunt-jsonlint": "2.1.3",
"grunt-mkdir": "~1.1.0",
"grunt-npm-command": "~0.1.2",
@@ -99,21 +102,19 @@
"grunt-simple-mocha": "~0.4.1",
"grunt-simple-nyc": "^3.0.1",
"http-proxy": "1.18.1",
"i18next-http-backend": "1.2.1",
"jquery-i18next": "1.2.1",
"jsdoc-nr-template": "github:node-red/jsdoc-nr-template",
"marked": "2.0.1",
"minami": "1.2.3",
"mocha": "8.3.2",
"mocha": "^5.2.0",
"node-red-node-test-helper": "^0.2.7",
"node-sass": "^5.0.0",
"nodemon": "2.0.7",
"should": "13.2.3",
"sinon": "10.0.1",
"sinon": "1.17.7",
"stoppable": "^1.1.0",
"supertest": "6.1.3"
"supertest": "5.0.0"
},
"engines": {
"node": ">=12"
"node": ">=8"
}
}

View File

@@ -90,7 +90,7 @@ function getToken(req,res,next) {
return server.token()(req,res,next);
}
function login(req,res) {
async function login(req,res) {
var response = {};
if (settings.adminAuth) {
var mergedAdminAuth = Object.assign({}, settings.adminAuth, settings.adminAuth.module);
@@ -116,8 +116,9 @@ function login(req,res) {
response.prompts[0].image = theme.serveFile('/login/',mergedAdminAuth.strategy.image);
}
}
if (theme.context().login && theme.context().login.image) {
response.image = theme.context().login.image;
let themeContext = await theme.context();
if (themeContext.login && themeContext.login.image) {
response.image = themeContext.login.image;
}
}
res.json(response);

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-api",
"version": "2.0.0-beta.1",
"version": "1.3.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/util": "2.0.0-beta.1",
"@node-red/editor-client": "2.0.0-beta.1",
"@node-red/util": "1.3.2",
"@node-red/editor-client": "1.3.2",
"bcryptjs": "2.4.3",
"body-parser": "1.19.0",
"clone": "2.1.2",
@@ -35,6 +35,6 @@
"ws": "6.2.1"
},
"optionalDependencies": {
"bcrypt": "5.0.1"
"bcrypt": "3.0.6"
}
}

View File

@@ -524,8 +524,8 @@
"title": "パレットの管理",
"palette": "パレット",
"times": {
"seconds": "秒前",
"minutes": "分前",
"seconds": "秒前",
"minutes": "分前",
"minutesV": "__count__ 分前",
"hoursV": "__count__ 時間前",
"hoursV_plural": "__count__ 時間前",

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/editor-client",
"version": "2.0.0-beta.1",
"version": "1.3.2",
"license": "Apache-2.0",
"repository": {
"type": "git",

View File

@@ -18,66 +18,53 @@ RED.i18n = (function() {
var apiRootUrl;
function detectLanguage() {
return navigator.language
}
return {
init: function(options, done) {
apiRootUrl = options.apiRootUrl||"";
var preferredLanguage = localStorage.getItem("editor-language");
var opts = {
backend: {
loadPath: apiRootUrl+'locales/__ns__?lng=__lng__',
resGetPath: apiRootUrl+'locales/__ns__?lng=__lng__',
dynamicLoad: false,
load:'current',
ns: {
namespaces: ["editor","node-red","jsonata","infotips"],
defaultNs: "editor"
},
lng: 'en-US',
// debug: true,
preload:['en-US'],
ns: ["editor","node-red","jsonata","infotips"],
defaultNS: "editor",
fallbackLng: ['en-US'],
returnObjects: true,
interpolation: {
unescapeSuffix: 'HTML',
escapeValue: false,
prefix: '__',
suffix: '__'
}
useCookie: false,
returnObjectTrees: true
};
if (preferredLanguage) {
opts.lng = preferredLanguage;
}
i18next.use(i18nextHttpBackend).init(opts,function() {
i18n.init(opts,function() {
done();
});
jqueryI18next.init(i18next, $, { handleName: 'i18n' });
RED["_"] = function() {
var v = i18next.t.apply(i18next,arguments);
var v = i18n.t.apply(null,arguments);
if (typeof v === 'string') {
return v;
} else {
return arguments[0];
}
}
},
lang: function() {
// Gets the active message catalog language. This is based on what
// locale the editor is using and what languages are available.
//
var preferredLangs = [localStorage.getItem("editor-language")|| detectLanguage()].concat(i18next.languages);
var preferredLangs = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var knownLangs = RED.settings.theme("languages")||["en-US"];
for (var i=0;i<preferredLangs.length;i++) {
if (knownLangs.indexOf(preferredLangs[i]) > -1) {
return preferredLangs[i]
}
}
return 'en-US'
return 'end-US'
},
loadNodeCatalog: function(namespace,done) {
var languageList = [localStorage.getItem("editor-language")|| detectLanguage()].concat(i18next.languages);
var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var toLoad = languageList.length;
languageList.forEach(function(lang) {
$.ajax({
@@ -87,7 +74,7 @@ RED.i18n = (function() {
cache: false,
url: apiRootUrl+'nodes/'+namespace+'/messages?lng='+lang,
success: function(data) {
i18next.addResourceBundle(lang,namespace,data);
i18n.addResourceBundle(lang,namespace,data);
toLoad--;
if (toLoad === 0) {
done();
@@ -99,7 +86,7 @@ RED.i18n = (function() {
},
loadNodeCatalogs: function(done) {
var languageList = [localStorage.getItem("editor-language")|| detectLanguage()].concat(i18next.languages);
var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var toLoad = languageList.length;
languageList.forEach(function(lang) {
@@ -112,7 +99,7 @@ RED.i18n = (function() {
success: function(data) {
var namespaces = Object.keys(data);
namespaces.forEach(function(ns) {
i18next.addResourceBundle(lang,ns,data[ns]);
i18n.addResourceBundle(lang,ns,data[ns]);
});
toLoad--;
if (toLoad === 0) {
@@ -124,7 +111,7 @@ RED.i18n = (function() {
},
loadPluginCatalogs: function(done) {
var languageList = [localStorage.getItem("editor-language")|| detectLanguage()].concat(i18next.languages);
var languageList = i18n.functions.toLanguages(localStorage.getItem("editor-language")||i18n.detectLanguage());
var toLoad = languageList.length;
languageList.forEach(function(lang) {
@@ -137,7 +124,7 @@ RED.i18n = (function() {
success: function(data) {
var namespaces = Object.keys(data);
namespaces.forEach(function(ns) {
i18next.addResourceBundle(lang,ns,data[ns]);
i18n.addResourceBundle(lang,ns,data[ns]);
});
toLoad--;
if (toLoad === 0) {
@@ -146,7 +133,6 @@ RED.i18n = (function() {
}
});
})
},
detectLanguage: detectLanguage
}
}
})();

View File

@@ -36,7 +36,7 @@ var RED = (function() {
}
function loadPlugins(done) {
loader.reportProgress(RED._("event.loadPlugins",{count:""}), 17)
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
var lang = localStorage.getItem("editor-language")||i18n.detectLanguage();
$.ajax({
headers: {
@@ -176,7 +176,7 @@ var RED = (function() {
function loadNodes() {
loader.reportProgress(RED._("event.loadNodes",{count:""}), 30)
var lang = localStorage.getItem("editor-language")||RED.i18n.detectLanguage();
var lang = localStorage.getItem("editor-language")||i18n.detectLanguage();
$.ajax({
headers: {

View File

@@ -71,7 +71,7 @@
var buttons = this.options.buttons || [];
if (this.options.addButton !== false) {
var addLabel, addTittle;
var addLabel, addTitle;
if (typeof this.options.addButton === 'string') {
addLabel = this.options.addButton
} else {
@@ -102,7 +102,7 @@
button.click(evt);
}
});
if (button.title) {
element.attr("title", button.title);
}
@@ -113,7 +113,7 @@
element.append($("<span></span>").text(" " + button.label));
}
});
if (this.element.css("position") === "absolute") {
["top","left","bottom","right"].forEach(function(s) {
var v = that.element.css(s);

View File

@@ -119,7 +119,7 @@ RED.keyboard = (function() {
} else {
mergedKeymap[action] = [{
scope: themeKeymap[action].scope || "*",
key: [themeKeymap[action].key],
key: themeKeymap[action].key,
user: false
}]
if (mergedKeymap[action][0].scope === "workspace") {

View File

@@ -233,7 +233,7 @@ RED.sidebar.help = (function() {
var div = $('<div>',{class:"red-ui-info-outline-item"});
RED.utils.createNodeIcon(n).appendTo(div);
var contentDiv = $('<div>',{class:"red-ui-search-result-description"}).appendTo(div);
$('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).text(n.name||n._def.paletteLabel||n.type).appendTo(contentDiv);
$('<div>',{class:"red-ui-search-result-node-label red-ui-info-outline-item-label"}).text(n.name||n.type).appendTo(contentDiv);
return div;
}
@@ -248,8 +248,7 @@ RED.sidebar.help = (function() {
title = subflowNode.name || nodeType;
} else {
helpText = RED.nodes.getNodeHelp(nodeType)||('<span class="red-ui-help-info-none">'+RED._("sidebar.info.none")+'</span>');
var _def = RED.nodes.registry.getNodeType(nodeType);
title = (_def && _def.paletteLabel)?_def.paletteLabel:nodeType;
title = nodeType;
}
setInfoText(title, helpText, helpSection);

File diff suppressed because one or more lines are too long

View File

@@ -302,7 +302,7 @@ module.exports = function(RED) {
}
});
if (moduleErrors) {
throw new Error("Function node failed to load external modules");
throw new Error(RED._("function.error.externalModuleLoadError"));
}
}

View File

@@ -78,11 +78,8 @@
<option value="day" data-i18n="delay.label.units.day.singular"></option>
</select>
</div>
<div class="form-row" id="rate-override">
<label></label><input style="width:30px; vertical-align:baseline;" type="checkbox" id="node-input-allowrate"><label style="width: 250px;" for="node-input-allowrate" data-i18n="delay.allowrate"></label>
</div>
<div class="form-row" id="rate-details-drop">
<label></label><input style="width:30px;; vertical-align:baseline;" type="checkbox" id="node-input-drop"><label style="width: 250px;" for="node-input-drop" data-i18n="delay.dropmsg"></label>
<label></label><input style="width: 30px;" type="checkbox" id="node-input-drop"><label style="width: 250px;" for="node-input-drop" data-i18n="delay.dropmsg"></label>
</div>
<div class="form-row" id="rate-details-per-topic">
<label></label>
@@ -113,8 +110,7 @@
randomFirst: {value:"1", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
randomLast: {value:"5", required:true, validate:function(v) { return RED.validators.number(v) && (v >= 0); }},
randomUnits: {value: "seconds"},
drop: {value:false},
allowrate: {value:false}
drop: {value:false}
},
inputs:1,
outputs:1,

View File

@@ -20,20 +20,6 @@ module.exports = function(RED) {
var MILLIS_TO_NANOS = 1000000;
var SECONDS_TO_NANOS = 1000000000;
var _maxKeptMsgsCount;
function maxKeptMsgsCount(node) {
if (_maxKeptMsgsCount === undefined) {
var name = "nodeMessageBufferMaxLength";
if (RED.settings.hasOwnProperty(name)) {
_maxKeptMsgsCount = RED.settings[name];
}
else {
_maxKeptMsgsCount = 0;
}
}
return _maxKeptMsgsCount;
}
function DelayNode(n) {
RED.nodes.createNode(this,n);
@@ -92,9 +78,6 @@ module.exports = function(RED) {
this.randomID = -1;
this.lastSent = null;
this.drop = n.drop;
this.droppedMsgs = 0;
this.allowrate = n.allowrate|| false;
this.fixedrate = this.rate;
var node = this;
function ourTimeout(handler, delay, clearHandler) {
@@ -105,19 +88,6 @@ module.exports = function(RED) {
};
}
var sendMsgFromBuffer = function() {
if (node.buffer.length === 0) {
clearInterval(node.intervalID);
node.intervalID = -1;
}
if (node.buffer.length > 0) {
const msgInfo = node.buffer.shift();
msgInfo.send(msgInfo.msg);
msgInfo.done();
}
node.reportDepth();
}
var clearDelayList = function(s) {
for (var i=0; i<node.idList.length; i++ ) { node.idList[i].clear(); }
node.idList = [];
@@ -142,28 +112,21 @@ module.exports = function(RED) {
}
}
var loggerId = setInterval(function () {
if (node.droppedMsgs !== 0) {
node.debug("node.droppedMsgs = " + node.droppedMsgs);
node.droppedMsgs = 0;
}
}, 15 * 1000);
node.on("close", function() { clearInterval(loggerId); });
if (node.pauseType === "delay") {
node.on("input", function(msg, send, done) {
var id = ourTimeout(function() {
node.idList.splice(node.idList.indexOf(id),1);
if (node.idList.length === 0) { node.status({}); }
send(msg);
done();
}, node.timeout, () => done());
if (Object.keys(msg).length === 2 && msg.hasOwnProperty("flush")) { id.clear(); }
else { node.idList.push(id); }
if (msg.hasOwnProperty("reset")) { clearDelayList(true); }
if (msg.hasOwnProperty("flush")) { flushDelayList(); done(); }
if ((node.timeout > 1000) && (node.idList.length !== 0)) {
node.status({fill:"blue",shape:"dot",text:" "});
else {
var id = ourTimeout(function() {
node.idList.splice(node.idList.indexOf(id),1);
if (node.idList.length === 0) { node.status({}); }
send(msg);
done();
}, node.timeout, () => done());
node.idList.push(id);
if ((node.timeout > 1000) && (node.idList.length !== 0)) {
node.status({fill:"blue",shape:"dot",text:" "});
}
if (msg.hasOwnProperty("reset")) { clearDelayList(true); }
}
});
node.on("close", function() { clearDelayList(); });
@@ -182,11 +145,11 @@ module.exports = function(RED) {
done();
}, delayvar, () => done());
node.idList.push(id);
if (msg.hasOwnProperty("reset")) { clearDelayList(true); }
if (msg.hasOwnProperty("flush")) { flushDelayList(); done(); }
if ((delayvar >= 0) && (node.idList.length !== 0)) {
node.status({fill:"blue",shape:"dot",text:delayvar/1000+"s"});
}
if (msg.hasOwnProperty("reset")) { clearDelayList(true); }
if (msg.hasOwnProperty("flush")) { flushDelayList(); }
});
node.on("close", function() { clearDelayList(); });
}
@@ -199,37 +162,32 @@ module.exports = function(RED) {
}
delete node.lastSent;
node.buffer = [];
node.rate = node.fixedrate;
node.status({text:"reset"});
done();
return;
}
if (!node.drop) {
var m = RED.util.cloneMessage(msg);
delete m.flush;
if (node.intervalID !== -1) {
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate)) && node.rate !== msg.rate) {
node.rate = msg.rate;
clearInterval(node.intervalID);
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
}
var max_msgs = maxKeptMsgsCount(node);
if ((max_msgs > 0) && (node.buffer.length >= max_msgs)) {
node.buffer = [];
node.error(RED._("delay.errors.too-many"), msg);
} else {
node.buffer.push({msg: m, send: send, done: done});
node.reportDepth();
}
node.buffer.push({msg: m, send: send, done: done});
node.reportDepth();
}
else {
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
node.rate = msg.rate;
}
send(m);
node.reportDepth();
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
node.intervalID = setInterval(function() {
if (node.buffer.length === 0) {
clearInterval(node.intervalID);
node.intervalID = -1;
}
if (node.buffer.length > 0) {
const msgInfo = node.buffer.shift();
msgInfo.send(msgInfo.msg);
msgInfo.done();
}
node.reportDepth();
}, node.rate);
done();
}
if (msg.hasOwnProperty("flush")) {
@@ -243,40 +201,17 @@ module.exports = function(RED) {
}
}
else {
if (maxKeptMsgsCount(node) > 0) {
if (node.intervalID === -1) {
node.send(msg);
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
} else {
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate)) && node.rate !== msg.rate) {
node.rate = msg.rate;
clearInterval(node.intervalID);
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
}
if (node.buffer.length < _maxKeptMsgsCount) {
var m = RED.util.cloneMessage(msg);
node.buffer.push({msg: m, send: send, done: done});
} else {
node.trace("dropped due to buffer overflow. msg._msgid = " + msg._msgid);
node.droppedMsgs++;
}
}
} else {
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate))) {
node.rate = msg.rate;
}
var timeSinceLast;
if (node.lastSent) {
timeSinceLast = process.hrtime(node.lastSent);
}
if (!node.lastSent) { // ensuring that we always send the first message
node.lastSent = process.hrtime();
send(msg);
}
else if ( ( (timeSinceLast[0] * SECONDS_TO_NANOS) + timeSinceLast[1] ) > (node.rate * MILLIS_TO_NANOS) ) {
node.lastSent = process.hrtime();
send(msg);
}
var timeSinceLast;
if (node.lastSent) {
timeSinceLast = process.hrtime(node.lastSent);
}
if (!node.lastSent) { // ensuring that we always send the first message
node.lastSent = process.hrtime();
send(msg);
}
else if ( ( (timeSinceLast[0] * SECONDS_TO_NANOS) + timeSinceLast[1] ) > (node.rate * MILLIS_TO_NANOS) ) {
node.lastSent = process.hrtime();
send(msg);
}
done();
}
@@ -310,11 +245,6 @@ module.exports = function(RED) {
var hit;
node.on("input", function(msg, send, done) {
if (node.allowrate && msg.hasOwnProperty("rate") && !isNaN(parseFloat(msg.rate)) && node.rate !== msg.rate) {
node.rate = msg.rate;
clearInterval(node.intervalID);
node.intervalID = setInterval(sendMsgFromBuffer, node.rate);
}
if (!msg.hasOwnProperty("topic")) { msg.topic = "_none_"; }
hit = false;
for (var b in node.buffer) { // check if already in queue
@@ -335,7 +265,6 @@ module.exports = function(RED) {
msgInfo.done();
}
node.buffer = [];
node.rate = node.fixedrate;
node.status({text:"reset"});
done();
}
@@ -368,13 +297,12 @@ module.exports = function(RED) {
node.status({});
done();
}, wait, () => done());
if (Object.keys(msg).length === 2 && msg.hasOwnProperty("flush")) { id.clear(); }
else { node.idList.push(id); }
if (msg.hasOwnProperty("reset")) { clearDelayList(true); }
if (msg.hasOwnProperty("flush")) { flushDelayList(); done(); }
node.idList.push(id);
if ((node.timeout >= 1000) && (node.idList.length !== 0)) {
node.status({fill:"blue",shape:"dot",text:parseInt(wait/10)/100+"s"});
}
if (msg.hasOwnProperty("reset")) { clearDelayList(true); }
if (msg.hasOwnProperty("flush")) { flushDelayList(); }
});
node.on("close", function() { clearDelayList(); });
}

View File

@@ -1,93 +0,0 @@
<script type="text/html" data-template-name="rbe">
<div class="form-row">
<label for="node-input-func"><i class="fa fa-wrench"></i> <span data-i18n="rbe.label.func"></span></label>
<select type="text" id="node-input-func" style="width:70%;">
<option value="rbe" data-i18n="rbe.opts.rbe"></option>
<option value="rbei" data-i18n="rbe.opts.rbei"></option>
<option value="deadbandEq" data-i18n="rbe.opts.deadbandEq"></option>
<option value="deadband" data-i18n="rbe.opts.deadband"></option>
<option value="narrowbandEq" data-i18n="rbe.opts.narrowbandEq"></option>
<option value="narrowband" data-i18n="rbe.opts.narrowband"></option>
</select>
</div>
<div class="form-row" id="node-bandgap">
<label for="node-input-gap">&nbsp;</label>
<input type="text" id="node-input-gap" data-i18n="[placeholder]rbe.placeholder.bandgap" style="width:95px;">
<select type="text" id="node-input-inout" style="width:54%;">
<option value="out" data-i18n="rbe.opts.out"></option>
<option value="in" data-i18n="rbe.opts.in"></option>
</select>
</div>
<div class="form-row" id="node-startvalue">
<label for="node-input-start"><i class="fa fa-thumb-tack"></i> <span data-i18n="rbe.label.start"></span></label>
<input type="text" id="node-input-start" data-i18n="[placeholder]rbe.placeholder.start" style="width:70%;">
</div>
<div class="form-row">
<label for="node-input-property"><i class="fa fa-ellipsis-h"></i> <span data-i18n="node-red:common.label.property"></span></label>
<input type="text" id="node-input-property" style="width:70%;"/>
</div>
<div class="form-row">
<label> </label>
<input type="checkbox" id="node-input-septopics" style="display:inline-block; width:20px; vertical-align:baseline;">
<span data-i18n="rbe.label.septopics"></span> <input type="text" id="node-input-topi" style="width:27%;"/>
</div>
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> <span data-i18n="rbe.label.name"></span></label>
<input type="text" id="node-input-name" data-i18n="[placeholder]rbe.label.name" style="width:70%;">
</div>
</script>
<script type="text/javascript">
RED.nodes.registerType("rbe", {
color:"#E2D96E",
category: 'function',
defaults: {
name: {value:""},
func: {value:"rbe"},
gap: {value:"",validate:RED.validators.regex(/^(\d*[.]*\d*|)(%|)$/)},
start: {value:""},
inout: {value:"out"},
septopics: {value:true},
property: {value:"payload",required:true},
topi: {value:"topic",required:true}
},
inputs:1,
outputs:1,
icon: "rbe.png",
paletteLabel: "filter",
label: function() {
var ll = (this.func||"").replace("Eq","").replace("rbei",this._("rbe.rbe")).replace("rbe",this._("rbe.rbe"))||this._("rbe.rbe");
return this.name||ll||this._("rbe.rbe");
},
labelStyle: function() {
return this.name?"node_label_italic":"";
},
oneditprepare: function() {
if (this.property === undefined) {
$("#node-input-property").val("payload");
}
if (this.septopics === undefined) {
$("#node-input-septopics").prop('checked', true);
}
$("#node-input-property").typedInput({default:'msg',types:['msg']});
$("#node-input-topi").typedInput({default:'msg',types:['msg']});
//$( "#node-input-gap" ).spinner({min:0});
if ($("#node-input-inout").val() === null) {
$("#node-input-inout").val("out");
}
$("#node-input-func").on("change",function() {
if (($("#node-input-func").val() === "rbe")||($("#node-input-func").val() === "rbei")) {
$("#node-bandgap").hide();
} else {
$("#node-bandgap").show();
}
if (($("#node-input-func").val() === "narrowband")||($("#node-input-func").val() === "narrowbandEq")) {
$("#node-startvalue").show();
} else {
$("#node-startvalue").hide();
}
});
}
});
</script>

View File

@@ -1,97 +0,0 @@
module.exports = function(RED) {
"use strict";
function RbeNode(n) {
RED.nodes.createNode(this,n);
this.func = n.func || "rbe";
this.gap = n.gap || "0";
this.start = n.start || '';
this.inout = n.inout || "out";
this.pc = false;
if (this.gap.substr(-1) === "%") {
this.pc = true;
this.gap = parseFloat(this.gap);
}
this.g = this.gap;
this.property = n.property || "payload";
this.topi = n.topi || "topic";
this.septopics = true;
if (n.septopics !== undefined && n.septopics === false) {
this.septopics = false;
}
var node = this;
node.previous = {};
this.on("input",function(msg) {
var topic;
try {
topic = RED.util.getMessageProperty(msg,node.topi);
}
catch(e) { }
if (msg.hasOwnProperty("reset")) {
if (node.septopics && topic && (typeof topic === "string") && (topic !== "")) {
delete node.previous[msg.topic];
}
else { node.previous = {}; }
}
var value = RED.util.getMessageProperty(msg,node.property);
if (value !== undefined) {
var t = "_no_topic";
if (node.septopics) { t = topic || t; }
if ((this.func === "rbe") || (this.func === "rbei")) {
var doSend = (this.func !== "rbei") || (node.previous.hasOwnProperty(t)) || false;
if (typeof(value) === "object") {
if (typeof(node.previous[t]) !== "object") { node.previous[t] = {}; }
if (!RED.util.compareObjects(value, node.previous[t])) {
node.previous[t] = RED.util.cloneMessage(value);
if (doSend) { node.send(msg); }
}
}
else {
if (value !== node.previous[t]) {
node.previous[t] = RED.util.cloneMessage(value);
if (doSend) { node.send(msg); }
}
}
}
else {
var n = parseFloat(value);
if (!isNaN(n)) {
if ((typeof node.previous[t] === 'undefined') && (this.func === "narrowband")) {
if (node.start === '') { node.previous[t] = n; }
else { node.previous[t] = node.start; }
}
if (node.pc) { node.gap = Math.abs(node.previous[t] * node.g / 100) || 0; }
else { node.gap = Number(node.gap); }
if ((node.previous[t] === undefined) && (node.func === "narrowbandEq")) { node.previous[t] = n; }
if (node.previous[t] === undefined) { node.previous[t] = n - node.gap - 1; }
if (Math.abs(n - node.previous[t]) === node.gap) {
if ((this.func === "deadbandEq")||(this.func === "narrowband")) {
if (node.inout === "out") { node.previous[t] = n; }
node.send(msg);
}
}
else if (Math.abs(n - node.previous[t]) > node.gap) {
if (this.func === "deadband" || this.func === "deadbandEq") {
if (node.inout === "out") { node.previous[t] = n; }
node.send(msg);
}
}
else if (Math.abs(n - node.previous[t]) < node.gap) {
if ((this.func === "narrowband")||(this.func === "narrowbandEq")) {
if (node.inout === "out") { node.previous[t] = n; }
node.send(msg);
}
}
if (node.inout === "in") { node.previous[t] = n; }
}
else {
node.warn(RED._("rbe.warn.nonumber"));
}
}
} // ignore msg with no payload property.
});
}
RED.nodes.registerType("rbe",RbeNode);
}

View File

@@ -186,8 +186,8 @@
<input type="text" id="node-config-input-port" data-i18n="[placeholder]mqtt.label.port" style="width:55px">
</div>
<div class="form-row" style="height: 34px;">
<input type="checkbox" id="node-config-input-usetls" style="height: 34px; margin: 0 0 0 104px; display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-usetls" style="width: 80px; line-height: 34px;"><span data-i18n="mqtt.label.use-tls"></span></label>
<input type="checkbox" id="node-config-input-usetls" style="height: 34px; margin: 0 5px 0 104px; display: inline-block; width: auto; vertical-align: top;">
<label for="node-config-input-usetls" style="width: 100px; line-height: 34px;"><span data-i18n="mqtt.label.use-tls"></span></label>
<span id="node-config-row-tls" class="hide"><input style="width: 320px;" type="text" id="node-config-input-tls"></span>
</div>
<div class="form-row">

View File

@@ -38,10 +38,11 @@ module.exports = function(RED) {
if (this.hdrout === true) { this.hdrout = "all"; }
var tmpwarn = true;
var node = this;
var re = new RegExp(',(?=(?:(?:[^"]*"){2})*[^"]*$)','g');
var re = new RegExp(node.sep+'(?=(?:(?:[^"]*"){2})*[^"]*$)','g');
// pass in an array of column names to be trimed, de-quoted and retrimed
var clean = function(col) {
// pass in an array of column names to be trimmed, de-quoted and retrimmed
var clean = function(col,sep) {
if (sep) { re = new RegExp(sep+'(?=(?:(?:[^"]*"){2})*[^"]*$)','g'); }
col = col.trim().split(re) || [""];
col = col.map(x => x.replace(/"/g,'').trim());
if ((col.length === 1) && (col[0] === "")) { node.goodtmpl = false; }
@@ -67,7 +68,7 @@ module.exports = function(RED) {
if (node.hdrout !== "none" && node.hdrSent === false) {
if ((template.length === 1) && (template[0] === '')) {
if (msg.hasOwnProperty("columns")) {
template = clean(msg.columns || "");
template = clean(msg.columns || "",",");
}
else {
template = Object.keys(msg.payload[0]);
@@ -93,7 +94,7 @@ module.exports = function(RED) {
}
else {
if ((template.length === 1) && (template[0] === '') && (msg.hasOwnProperty("columns"))) {
template = clean(msg.columns || "");
template = clean(msg.columns || "",",");
}
if ((template.length === 1) && (template[0] === '')) {
/* istanbul ignore else */

View File

@@ -201,7 +201,7 @@
defaults: {
name: {value:""},
mode: {value:"auto"},
build: { value:"object"},
build: { value:"string"},
property: { value:"payload", validate:RED.validators.typedInput("propertyType")},
propertyType: { value:"msg"},
key: {value:"topic"},

View File

@@ -219,6 +219,10 @@
value: "none",
label: label
}).text(label).appendTo(encSel);
$("<option/>", {
value: "setbymsg",
label: node._("file.encoding.setbymsg")
}).text(label).appendTo(encSel);
encodings.forEach(function(item) {
if(Array.isArray(item)) {
var group = $("<optgroup/>", {

View File

@@ -61,11 +61,13 @@ module.exports = function(RED) {
if (filename === "") {
node.warn(RED._("file.errors.nofilename"));
done();
} else if (node.overwriteFile === "delete") {
}
else if (node.overwriteFile === "delete") {
fs.unlink(filename, function (err) {
if (err) {
node.error(RED._("file.errors.deletefail",{error:err.toString()}),msg);
} else {
}
else {
if (RED.settings.verbose) {
node.log(RED._("file.status.deletedfile",{file:filename}));
}
@@ -73,12 +75,14 @@ module.exports = function(RED) {
}
done();
});
} else if (msg.hasOwnProperty("payload") && (typeof msg.payload !== "undefined")) {
}
else if (msg.hasOwnProperty("payload") && (typeof msg.payload !== "undefined")) {
var dir = path.dirname(filename);
if (node.createDir) {
try {
fs.ensureDirSync(dir);
} catch(err) {
}
catch(err) {
node.error(RED._("file.errors.createfail",{error:err.toString()}),msg);
done();
return;
@@ -92,7 +96,11 @@ module.exports = function(RED) {
if (typeof data === "boolean") { data = data.toString(); }
if (typeof data === "number") { data = data.toString(); }
if ((node.appendNewline) && (!Buffer.isBuffer(data))) { data += os.EOL; }
var buf = encode(data, node.encoding);
var buf;
if (node.encoding === "setbymsg") {
buf = encode(data, msg.encoding || "none");
}
else { buf = encode(data, node.encoding); }
if (node.overwriteFile === "true") {
var wstream = fs.createWriteStream(filename, { encoding:'binary', flags:'w', autoClose:true });
node.wstream = wstream;
@@ -101,10 +109,11 @@ module.exports = function(RED) {
done();
});
wstream.on("open", function() {
wstream.end(buf, function() {
wstream.once("close", function() {
nodeSend(msg);
done();
});
wstream.end(buf);
})
return;
}
@@ -126,7 +135,8 @@ module.exports = function(RED) {
delete node.wstream;
delete node.wstreamIno;
}
} catch(err) {
}
catch(err) {
// File does not exist
recreateStream = true;
node.wstream.end();
@@ -154,14 +164,16 @@ module.exports = function(RED) {
nodeSend(msg);
done();
});
} else {
}
else {
// Dynamic filename - write and close the stream
node.wstream.end(buf, function() {
node.wstream.once("close", function() {
nodeSend(msg);
delete node.wstream;
delete node.wstreamIno;
done();
});
node.wstream.end(buf);
}
}
}
@@ -276,7 +288,6 @@ module.exports = function(RED) {
ch = "\n";
type = "string";
}
var hwm;
var getout = false;
var rs = fs.createReadStream(filename)
@@ -340,16 +351,17 @@ module.exports = function(RED) {
nodeSend(msg);
}
else if (node.format === "lines") {
var m = { payload: spare,
topic:msg.topic,
parts: {
index: count,
count: count+1,
ch: ch,
type: type,
id: msg._msgid
}
};
var m = {
payload: spare,
topic:msg.topic,
parts: {
index: count,
count: count+1,
ch: ch,
type: type,
id: msg._msgid
}
};
nodeSend(m);
}
else if (getout) { // last chunk same size as high water mark - have to send empty extra packet.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 252 B

View File

@@ -1,40 +0,0 @@
<script type="text/html" data-help-name="rbe">
<p>Report by Exception (RBE) - Daten-Weiterleitung nur bei Änderung der Nutzdaten (Payload).
Der Node kann auch blockieren oder weiterleiten, wenn die Wertänderung eine Grenze überschreitet (Totband- und Nahband-Modus).</p>
<h3>Eingangsdaten</h3>
<dl class="message-properties">
<dt>payload
<span class="property-type">number | string | (object)</span>
</dt>
<dd>Der RBE-Modus mit Prüfung auf Wertänderung akzeptiert Zahlen (numbers), Zeichenfolgen (string) und einfache Objekte (object).
Bei den anderen wertvergleichenden Modies müssen analysierbare (parseable) Zahlenwerte übergeben werden.</dd>
<dt class="optional">topic <span class="property-type">string</span>
</dt>
<dd>Wenn vorgegeben erfolgt die Auswertung separat für jedes Topic</dd>
<dt class="optional">reset<span class="property-type">any</span></dt>
<dd>Wenn gesetzt wird/werden der/die gespeicherte(n) Wert(e) rückgesetzt</dd>
</dl>
<h3>Ausgangsdaten</h3>
<dl class="message-properties">
<dt>payload
<span class="property-type">wie Eingangsdaten</span>
</dt>
<dd>Wenn Bedingung erfüllt, sind die Ausgangsdaten gleich den Eingangsdaten</dd>
</dl>
<h3>Details</h3>
<p>Im <i>RBE</i>-Modus mit Prüfung auf Wertänderung blockiert dieser Node die Datenweitergabe bis
<code>msg.payload</code> (oder die eingestellte Eigenschaft) verändert ist gegenüber dessen vorherigen Wert.
Wenn benötigt, wird der Anfangswert ignoriert, sodass beim Start nichts gesendet wird.</p>
<p>In den <i>Totband</i>-Modies werden die Eingangswerte geblockt,
<i>bis</i> die Wertänderung größer oder größer-gleich ist als &plusmn; des Bandes um den voherigen Wert.</p>
<p>In den <i>Nahband</i>-Modies werden die Eingangswerte geblockt,
<i>wenn</i> die Wertänderung größer oder größer-gleich ist als &plusmn; des Bandes um den voherigen Wert.
Dies ist beispielsweise nützlich, um Ausreißer eines fehlerhaften Sensors zu ignorieren.</p>
<p>In den Totband und Nahband-Modies müssen die Eingangswerte analysierbare (parseable) Zahlenwerte sein und
beide unterstützen auch % (prozentuale Angabe), d.h. der Node sendet nur, wenn der Eingangswert mehr als x% vom vorherigen Wert abweicht.</p>
<p>Die Totband- und Nahband-Modies erlauben den Vergleich entweder gegen den letzten gültigen Ausgangswert,
dieses zum Ignorieren von Werten außerhalb des gültigen Bereichs, oder gegen den des vorherigen Eingangswertes,
welches den Sollwert rücksetzt, was einen allmähligen Drift (Totband) oder einen eine schrittweise Veränderung (Nahband) ermöglicht.</p>
<p><b>Hinweis</b>: Dieser Node arbeitet auf per-<code>msg.topic</code>-Basis.
Dies bedeutet, dass ein einzelner rbe-Node mehrere verschiedene Topics parallel bearbeiten kann.</p>
</script>

View File

@@ -363,7 +363,7 @@
"keepalive": "Keep-Alive",
"cleansession": "Bereinigte Sitzung (clean session) verwenden",
"cleanstart": "Verwende bereinigten Start",
"use-tls": "Sichere Verbindung (SSL/TLS) verwenden",
"use-tls": "TLS",
"tls-config": "TLS-Konfiguration",
"verify-server-cert": "Server-Zertifikat überprüfen",
"compatmode": "MQTT 3.1 unterstützen",
@@ -1000,32 +1000,5 @@
"too-many": "Zu viele anstehende Nachrichten im <span style=\"background-color:Gainsboro\">batch</span>-Node",
"unexpected": "Unerwarteter Modus",
"no-parts": "Keine parts-Eigenschaft in Nachricht"
},
"rbe": {
"rbe": "filter",
"label": {
"func": "Modus",
"init": "Sende Anfangswert",
"start": "Startwert",
"name": "Name",
"septopics": "Modus für jedes msg.topic separat anwenden"
},
"placeholder":{
"bandgap": "z.B. 10 oder 5%",
"start": "Leer lassen, um erste empfangenen Daten zu nutzen"
},
"opts": {
"rbe": "Blockieren bis Wertänderung",
"rbei": "Blockieren bis Wertänderung (Anfangswert ignorieren)",
"deadband": "Blockieren bis Wertänderung ist größer als",
"deadbandEq": "Blockieren bis Wertänderung ist größer-gleich",
"narrowband": "Blockieren wenn Wertänderung ist größer als",
"narrowbandEq": "Blockieren wenn Wertänderung ist größer-gleich",
"in": "verglichen mit letzten Eingangswert",
"out": "verglichen mit letzten gültigen Ausgangswert"
},
"warn": {
"nonumber": "Keine Zahl gefunden in den Nutzdaten (Payload)"
}
}
}

View File

@@ -52,10 +52,11 @@
pass <code>msg</code> as a second argument to <code>node.error</code>:</p>
<pre>node.error("Error",msg);</pre>
<h4>Accessing Node Information</h4>
<p>In the function block, id and name of the node can be referenced using the following properties:</p>
<p>The following properties are available to access information about the node:</p>
<ul>
<li><code>node.id</code> - id of the node</li>
<li><code>node.name</code> - name of the node</li>
<li><code>node.outputCount</code> - number of node outputs</li>
</ul>
<h4>Using environment variables</h4>
<p>Environment variables can be accessed using <code>env.get("MY_ENV_VAR")</code>.</p>

View File

@@ -22,12 +22,6 @@
<dd>Sets the delay, in milliseconds, to be applied to the message. This
option only applies if the node is configured to allow the message to
override the configured default delay interval.</dd>
<dt class="optional">rate <span class="property-type">number</span></dt>
<dd>Sets the rate value in milliseconds between messages.
This node overwrites the existing rate value defined in the node configuration
when it receives the message which contains <code>msg.rate</code> value in milliSeconds.
This option only applies if the node is configured to allow the message to
override the configured default rate interval.</dd>
<dt class="optional">reset</dt>
<dd>If the received message has this property set to any value, all
outstanding messages held by the node are cleared without being sent.</dd>
@@ -38,17 +32,15 @@
<h3>Details</h3>
<p>When configured to delay messages, the delay interval can be a fixed value,
a random value within a range or dynamically set for each message.
Each message is delayed independently of any other message, based on
Each message is delayed independently of any other message, based on
the time of its arrival.
</p>
<p>When configured to rate limit messages, their delivery is spread across
the configured time period. The status shows the number of messages currently in the queue.
It can optionally discard intermediate messages as they arrive.</p>
</p>
<p> If set to allow override of the rate, the new rate will be applied immediately,
and will remain in effect until changed again, the node is reset, or the flow is restarted.</p>
<p>The rate limiting can be applied to all messages, or group them according to
their <code>msg.topic</code> value. When grouping, intermediate messages are
their <code>msg.topic</code> value. When grouping, intermerdiate messages are
automatically dropped. At each time interval, the node can either release
the most recent message for all topics, or release the most recent message
for the next topic.

View File

@@ -1,41 +0,0 @@
<script type="text/html" data-help-name="rbe">
<p>Report by Exception (RBE) node - only passes on data if the payload has changed.
It can also block unless, or ignore if the value changes by a specified amount (Dead- and Narrowband mode).</p>
<h3>Inputs</h3>
<dl class="message-properties">
<dt>payload
<span class="property-type">number | string | (object)</span>
</dt>
<dd>RBE mode will accept numbers, strings, and simple objects.
Other modes must provide a parseable number.</dd>
<dt class="optional">topic <span class="property-type">string</span>
</dt>
<dd>if specified the function will work on a per topic basis. This property can be set by configuration.</dd>
<dt class="optional">reset<span class="property-type">any</span></dt>
<dd>if set clears the stored value for the specified msg.topic, or
all topics if msg.topic is not specified.</dd>
</dl>
<h3>Outputs</h3>
<dl class="message-properties">
<dt>payload
<span class="property-type">as per input</span>
</dt>
<dd>If triggered the output will be the same as the input.</dd>
</dl>
<h3>Details</h3>
<p>In RBE mode this node will block until the <code>msg.payload</code>,
(or selected property) value is different to the previous one.
If required it can ignore the intial value, so as not to send anything at start.</p>
<p>The <a href="https://en.wikipedia.org/wiki/Deadband" target="_blank">Deadband</a> modes will block the incoming value
<i>unless</i> its change is greater or greater-equal than &plusmn; the band gap away from a previous value.</p>
<p>The Narrowband modes will block the incoming value,
<i>if</i> its change is greater or greater-equal than &plusmn; the band gap away from the previous value.
It is useful for ignoring outliers from a faulty sensor for example.</p>
<p>Both in Deadband and Narrowband modes the incoming value must contain a parseable number and
both also supports % - only sends if/unless the input differs by more than x% of the original value.</p>
<p>Both Deadband and Narrowband allow comparison against either the previous valid output value, thus
ignoring any values out of range, or the previous input value, which resets the set point, thus allowing
gradual drift (deadband), or a step change (narrowband).</p>
<p><b>Note:</b> This works on a per <code>msg.topic</code> basis, though this can be changed to another property if desired.
This means that a single rbe node can handle multiple different topics at the same time.</p>
</script>

View File

@@ -227,6 +227,7 @@
"error": {
"externalModuleNotAllowed": "Function node not allowed to load external modules",
"moduleNotAllowed": "Module __module__ not allowed",
"externalModuleLoadError": "Function node failed to load external modules",
"moduleLoadError": "Failed to load module __module__: __error__",
"moduleNameError": "Invalid module variable name: __name__",
"moduleNameReserved": "Reserved variable name: __name__",
@@ -276,7 +277,6 @@
"rate": "Rate",
"msgper": "msg(s) per",
"dropmsg": "drop intermediate messages",
"allowrate": "allow msg.rate (in ms) to override rate",
"label": {
"delay": "delay",
"variable": "variable",
@@ -302,8 +302,9 @@
}
}
},
"errors": {
"too-many" : "too many pending messages in delay node"
"error": {
"buffer": "buffer exceeded 1000 messages",
"buffer1": "buffer exceeded 10000 messages"
}
},
"trigger": {
@@ -877,6 +878,7 @@
},
"encoding": {
"none": "default",
"setbymsg": "set by msg.encoding",
"native": "Native",
"unicode": "Unicode",
"japanese": "Japanese",
@@ -1001,32 +1003,5 @@
"too-many" : "too many pending messages in batch node",
"unexpected" : "unexpected mode",
"no-parts" : "no parts property in message"
},
"rbe": {
"rbe": "filter",
"label": {
"func": "Mode",
"init": "Send initial value",
"start": "Start value",
"name": "Name",
"septopics": "Apply mode separately for each "
},
"placeholder":{
"bandgap": "e.g. 10 or 5%",
"start": "leave blank to use first data received"
},
"opts": {
"rbe": "block unless value changes",
"rbei": "block unless value changes (ignore initial value)",
"deadband": "block unless value change is greater than",
"deadbandEq": "block unless value change is greater or equal to",
"narrowband": "block if value change is greater than",
"narrowbandEq": "block if value change is greater or equal to",
"in": "compared to last input value",
"out": "compared to last valid output value"
},
"warn": {
"nonumber": "no number found in payload"
}
}
}

View File

@@ -91,7 +91,7 @@
</ul>
</dd>
<dt class="optional">complete</dt>
<dd>If set, the node will append the payload, and then send the output message in its current state.
<dd>If set, the node will append the payload, and then send the output message in its current state.
If you don't wish to append the payload, delete it from the msg.</dd>
</dl>
<h3>Details</h3>
@@ -150,6 +150,7 @@
<p>By default, the reduce expression is applied in order, from the first
to the last message of the sequence. It can optionally be applied in
reverse order.</p>
<p>$N is the number of messages that arrive - even if they are identical.</p>
</dl>
<p><b>Example:</b> the following settings, given a sequence of numeric values,
calculates the average value:

View File

@@ -21,6 +21,8 @@
<dl class="message-properties">
<dt class="optional">filename <span class="property-type">string</span></dt>
<dd>If not configured in the node, this optional property sets the name of the file to be updated.</dd>
<dt class="optional">encoding <span class="property-type">string</span></dt>
<dd>If encoding is configured to be set by msg, then this optional property can set the encoding.</dt>
</dl>
<h3>Output</h3>
<p>On completion of write, input message is sent to output port.</p>

View File

@@ -44,10 +44,11 @@
<p>catchードを用いてエラー処理が可能ですcatchードで処理させるためには<code>msg</code><code>node.error</code>:</p>
<pre>node.error("エラー",msg);</pre>
<h4>ノード情報の参照</h4>
<p>コード中ではードのIDおよび名前を以下のプロパティで参照できます:</p>
<p>ノードに関する情報を参照するための以下のプロパティを利用できます:</p>
<ul>
<li><code>node.id</code> - ID</li>
<li><code>node.name</code> - </li>
<li><code>node.outputCount</code> - </li>
</ul>
<h4>環境変数の利用</h4>
<p>環境変数は<code>env.get("MY_ENV_VAR")</code></p>

View File

@@ -20,8 +20,6 @@
<dl class="message-properties">
<dt class="optional">delay <span class="property-type">数値</span></dt>
<dd>メッセージの遅延時間をミリ秒単位で設定しますこれはノードの設定でデフォルトの遅延時間を上書きできるようノードを設定した場合にのみ適用します</dd>
<dt class="optional">rate <span class="property-type">数値</span></dt>
<dd>メッセージ間の流量値をミリ秒単位で設定します本ノードは<code>msg.rate</code></dd>
<dt class="optional">reset</dt>
<dd>受信メッセージでこのプロパティを任意の値に設定するとノードが保持する全ての未送信メッセージをクリアします</dd>
<dt class="optional">flush</dt>
@@ -30,6 +28,5 @@
<h3>詳細</h3>
<p>メッセージを遅延させるように設定する場合遅延時間は固定値範囲内の乱数値メッセージ毎の動的な指定値のいずれかを指定できます</p>
<p>流量制御する場合メッセージは指定した時間間隔内に分散して送信しますキューに残っているメッセージ数はノードのステータスに表示されます受け取った中間メッセージを破棄することも可能です</p>
<p>流量値を上書きできるように設定されている場合新しい流量値はすぐに適用されますこの流量値は再度変更されるまで本ノードがリセットされるまでまたはフローが再実行されるまで有効です</p>
<p>流量制御は全てのメッセージに適用することも<code>msg.topic</code></p>
</script>

View File

@@ -1,31 +0,0 @@
<!-- Source revision: https://github.com/node-red/node-red-nodes/commit/467907776088422882076f46d85e25601449564d -->
<script type="text/html" data-help-name="rbe">
<p>Report by Exception(例外データの報告)ノード - ペイロードの値が変化した場合だけデータを送信</p>
<p>値が指定した量変化するまでブロックすることもできます- 不感帯(deadband)モード</p>
<h3>入力</h3> <dl class="message-properties">
<dt>payload
<span class="property-type">数値 | 文字列 | (オブジェクト)</span>
</dt>
<dd>RBEモードでは数値文字列シンプルなオブジェクトを受け付けます他のモードではパース可能な数値を指定します</dd>
<dt class="optional">topic <span class="property-type">文字列</span>
</dt>
<dd>指定するとトピックごとに動作します</dd>
<dt class="optional">reset<span class="property-type">任意</span></dt>
<dd>値を設定すると保存した値をクリアしますmsg.topicを指定した場合は対応する値指定しなければ全てのトピックが対象となります</dd>
</dl>
<h3>出力</h3>
<dl class="message-properties">
<dt>payload
<span class="property-type">入力と同じ</span>
</dt>
<dd>トリガー条件を満たした場合入力を出力として送信</dd>
</dl>
<h3>詳細</h3>
<p>RBEモードでは<code>msg.payload</code></p>
<p>不感帯モードでは入力データはパース可能な数値でなければなりません以前の入力値に対する差分が指定値より大きな場合にのみメッセージを出力します</p>
<p>不感帯モードでは%による指定もサポートしています入力と前の値の差分がX%より大きな場合に出力を行います</p>
<p>狭帯域(narrowband)モードでは前の値に対する差分が一定値より大きな場合に入力ペイロードをブロックしますこのモードは故障したセンサから発生する外れ値を無視する時などに有用です</p>
<p>不感帯モードと狭帯域モードでは以前の有効出力値もしくは以前の入力値との比較ができます有効出力値を用いると範囲外の値を無視することが入力値を用いると設定点がリセットされるため漸次的変化(不感帯モード)もしくは段階的変化(狭帯域モード)が可能です</p>
<p><b>:</b> <code>msg.topic</code>rbe</p>
</script>

View File

@@ -227,6 +227,7 @@
"error": {
"externalModuleNotAllowed": "Functionードは、外部モジュールを読み込みできません",
"moduleNotAllowed": "モジュール __module__ は利用できません",
"externalModuleLoadError": "Functionードは、外部モジュールの読み込みに失敗しました",
"moduleLoadError": "モジュール __module__ の読み込みに失敗しました: __error__",
"moduleNameError": "モジュール変数名が不正です: __name__",
"moduleNameReserved": "予約された変数名です: __name__",
@@ -276,7 +277,6 @@
"rate": "流量",
"msgper": "メッセージ/",
"dropmsg": "中間メッセージを削除",
"allowrate": "msg.rate(ミリ秒単位)で流量値を上書き",
"label": {
"delay": "delay",
"variable": "variable",
@@ -302,8 +302,9 @@
}
}
},
"errors": {
"too-many": "delayード内で保持しているメッセージが多すぎます"
"error": {
"buffer": "バッファ上限の1000メッセージを超えました",
"buffer1": "バッファ上限の10000メッセージを超えました"
}
},
"trigger": {
@@ -875,6 +876,7 @@
},
"encoding": {
"none": "デフォルト",
"setbymsg": "msg.encodingで設定",
"native": "ネイティブ",
"unicode": "UNICODE",
"japanese": "日本",
@@ -999,30 +1001,5 @@
"too-many": "batchード内で保持しているメッセージが多すぎます",
"unexpected": "想定外のモード",
"no-parts": "メッセージにpartsプロパティがありません"
},
"rbe": {
"label": {
"func": "動作",
"init": "初期値を送付",
"start": "初期値",
"name": "名前"
},
"placeholder": {
"bandgap": "例:10、5%",
"start": "最初に受け取った値を用いる場合は空欄"
},
"opts": {
"rbe": "値が変化した時のみメッセージを中継",
"rbei": "値が変化した時のみメッセージを中継(初期値を無視)",
"deadband": "値が指定した変化量を超える時のみメッセージを中継",
"deadbandEq": "値が指定した変化量以上の時のみメッセージを中継",
"narrowband": "値が指定した変化量を超えない時のみメッセージを中継",
"narrowbandEq": "値が指定した変化量以上でない時のみメッセージを中継",
"in": "最後の入力値と比較",
"out": "最後の出力値と比較"
},
"warn": {
"nonumber": "ペイロードに数値が含まれていません"
}
}
}

View File

@@ -20,6 +20,8 @@
<dl class="message-properties">
<dt class="optional">filename <span class="property-type">文字列</span></dt>
<dd>対象ファイル名をノードに設定していない場合このプロパティでファイルを指定できます</dd>
<dt class="optional">encoding <span class="property-type">文字列</span></dt>
<dd>エンコーディングをmsgで設定する構成にした際はこの任意のプロパティでエンコーディングを設定できます</dt>
</dl>
<h3>出力</h3>
<p>書き込みの完了時入力メッセージを出力端子に送出します</p>

View File

@@ -272,6 +272,10 @@
"singular": "일"
}
}
},
"error": {
"buffer": "버퍼 상한의 1000메세지를 넘었습니다",
"buffer1": "버퍼 상한의 10000메세지를 넘었습니다"
}
},
"trigger": {
@@ -329,7 +333,7 @@
"port": "포트",
"keepalive": "킵 얼라이브 시간",
"cleansession": "세션 초기화",
"use-tls": "SSL/TLS접속을 사용",
"use-tls": "사용TLS",
"tls-config": "TLS설정",
"verify-server-cert": "서버인증서를 확인",
"compatmode": "구 MQTT 3.1서포트"

View File

@@ -352,7 +352,7 @@
"port": "Порт",
"keepalive": "Keep-alive время (сек)",
"cleansession": "Использовать чистую сессию",
"use-tls": "Включить безопасное (SSL/TLS) соединение",
"use-tls": "TLS",
"tls-config":"Конфигурация TLS",
"verify-server-cert":"Проверить сертификат сервера",
"compatmode": "Использовать устаревшую поддержку MQTT 3.1"

View File

@@ -290,6 +290,10 @@
"singular": "天"
}
}
},
"error": {
"buffer": "缓冲了超过 1000 条信息",
"buffer1": "缓冲了超过 10000 条信息"
}
},
"trigger": {
@@ -349,7 +353,7 @@
"port": "端口",
"keepalive": "Keepalive计时(秒)",
"cleansession": "使用新的会话",
"use-tls": "使用安全连接 (SSL/TLS)",
"use-tls": "使用 TLS",
"tls-config": "TLS 设置",
"verify-server-cert": "验证服务器证书",
"compatmode": "使用旧式MQTT 3.1支持"

View File

@@ -353,7 +353,7 @@
"port": "埠",
"keepalive": "Keepalive計時(秒)",
"cleansession": "使用新的會話",
"use-tls": "使用安全連接 (SSL/TLS)",
"use-tls": "使用 TLS",
"tls-config": "TLS 設置",
"verify-server-cert": "驗證伺服器憑證",
"compatmode": "使用舊式MQTT 3.1支援"

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/nodes",
"version": "2.0.0-beta.1",
"version": "1.3.2",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -24,7 +24,7 @@
"cors": "2.8.5",
"cron": "1.7.2",
"denque": "1.5.0",
"fs-extra": "9.1.0",
"fs-extra": "8.1.0",
"fs.notify": "0.0.4",
"hash-sum": "2.0.0",
"https-proxy-agent": "5.0.0",

View File

@@ -472,7 +472,7 @@ function getPackageList() {
try {
var userPackage = path.join(settings.userDir,"package.json");
var pkg = JSON.parse(fs.readFileSync(userPackage,"utf-8"));
return pkg.dependencies;
return pkg.dependencies || {};
} catch(err) {
log.error(err);
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/registry",
"version": "2.0.0-beta.1",
"version": "1.3.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,8 +16,8 @@
}
],
"dependencies": {
"@node-red/util": "2.0.0-beta.1",
"semver": "7.3.5",
"@node-red/util": "1.3.2",
"semver": "6.3.0",
"tar": "6.1.0",
"uglify-js": "3.13.3"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/runtime",
"version": "2.0.0-beta.1",
"version": "1.3.2",
"license": "Apache-2.0",
"main": "./lib/index.js",
"repository": {
@@ -16,12 +16,12 @@
}
],
"dependencies": {
"@node-red/registry": "2.0.0-beta.1",
"@node-red/util": "2.0.0-beta.1",
"@node-red/registry": "1.3.2",
"@node-red/util": "1.3.2",
"async-mutex": "0.3.1",
"clone": "2.1.2",
"express": "4.17.1",
"fs-extra": "9.1.0",
"fs-extra": "8.1.0",
"json-stringify-safe": "5.0.1"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@node-red/util",
"version": "2.0.0-beta.1",
"version": "1.3.2",
"license": "Apache-2.0",
"repository": {
"type": "git",
@@ -16,7 +16,7 @@
],
"dependencies": {
"clone": "2.1.2",
"i18next": "20.2.1",
"i18next": "15.1.2",
"json-stringify-safe": "5.0.1",
"jsonata": "1.8.4",
"lodash.clonedeep": "^4.5.0",

View File

@@ -1,6 +1,6 @@
{
"name": "node-red",
"version": "2.0.0-beta.1",
"version": "1.3.2",
"description": "Low-code programming for event-driven applications",
"homepage": "http://nodered.org",
"license": "Apache-2.0",
@@ -31,22 +31,24 @@
"flow"
],
"dependencies": {
"@node-red/editor-api": "2.0.0-beta.1",
"@node-red/runtime": "2.0.0-beta.1",
"@node-red/util": "2.0.0-beta.1",
"@node-red/nodes": "2.0.0-beta.1",
"@node-red/editor-api": "1.3.2",
"@node-red/runtime": "1.3.2",
"@node-red/util": "1.3.2",
"@node-red/nodes": "1.3.2",
"basic-auth": "2.0.1",
"bcryptjs": "2.4.3",
"express": "4.17.1",
"fs-extra": "9.1.0",
"fs-extra": "8.1.0",
"node-red-admin": "^0.2.6",
"node-red-node-rbe": "^0.5.0",
"node-red-node-tail": "^0.3.0",
"nopt": "5.0.0",
"semver": "7.3.5"
"semver": "6.3.0"
},
"optionalDependencies": {
"bcrypt": "5.0.1"
"bcrypt": "3.0.6"
},
"engines": {
"node": ">=12"
"node": ">=8"
}
}

View File

@@ -18,7 +18,6 @@ var should = require("should");
var delayNode = require("nr-test-utils").require("@node-red/nodes/core/function/89-delay.js");
var helper = require("node-red-node-test-helper");
var RED = require("nr-test-utils").require("node-red/lib/red");
var GRACE_PERCENTAGE=10;
@@ -36,7 +35,6 @@ describe('delay Node', function() {
});
afterEach(function(done) {
RED.settings.nodeMessageBufferMaxLength = 0;
helper.unload();
helper.stopServer(done);
});
@@ -152,7 +150,6 @@ describe('delay Node', function() {
* We send a message, take a timestamp then when the message is received by the helper node, we take another timestamp.
* Then check if the message has been delayed by the expected amount.
*/
it('delays the message in seconds', function(done) {
genericDelayTest(0.5, "seconds", done);
});
@@ -179,14 +176,14 @@ describe('delay Node', function() {
* @param nbUnit - the multiple of the unit, aLimit Message for nbUnit Seconds
* @param runtimeInMillis - when to terminate run and count messages received
*/
function genericRateLimitSECONDSTest(aLimit, nbUnit, runtimeInMillis, rateValue, done) {
function genericRateLimitSECONDSTest(aLimit, nbUnit, runtimeInMillis, done) {
var flow = [{"id":"delayNode1","type":"delay","nbRateUnits":nbUnit,"name":"delayNode","pauseType":"rate","timeout":5,"timeoutUnits":"seconds","rate":aLimit,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":false,"wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(delayNode, flow, function() {
var delayNode1 = helper.getNode("delayNode1");
var helperNode1 = helper.getNode("helperNode1");
var receivedMessagesStack = [];
var rate = 1000 / aLimit * nbUnit;
var rate = 1000/aLimit;
var receiveTimestamp;
@@ -204,7 +201,7 @@ describe('delay Node', function() {
var i = 0;
for (; i < possibleMaxMessageCount + 1; i++) {
delayNode1.receive({ payload: i, rate: rateValue });
delayNode1.receive({payload:i});
}
setTimeout(function() {
@@ -227,22 +224,17 @@ describe('delay Node', function() {
}
it('limits the message rate to 1 per second', function(done) {
genericRateLimitSECONDSTest(1, 1, 1500, null, done);
genericRateLimitSECONDSTest(1, 1, 1500, done);
});
it('limits the message rate to 1 per 2 seconds', function(done) {
this.timeout(6000);
genericRateLimitSECONDSTest(1, 2, 3000, null, done);
genericRateLimitSECONDSTest(1, 2, 3000, done);
});
it('limits the message rate to 2 per seconds, 2 seconds', function(done) {
this.timeout(6000);
genericRateLimitSECONDSTest(2, 1, 2100, null, done);
});
it('limits the message rate using msg.rate', function (done) {
RED.settings.nodeMessageBufferMaxLength = 3;
genericRateLimitSECONDSTest(1, 1, 1500, 2000, done);
genericRateLimitSECONDSTest(2, 1, 2100, done);
});
/**
@@ -251,7 +243,7 @@ describe('delay Node', function() {
* @param nbUnit - the multiple of the unit, aLimit Message for nbUnit Seconds
* @param runtimeInMillis - when to terminate run and count messages received
*/
function dropRateLimitSECONDSTest(aLimit, nbUnit, runtimeInMillis, rateValue, done) {
function dropRateLimitSECONDSTest(aLimit, nbUnit, runtimeInMillis, done) {
var flow = [{"id":"delayNode1","type":"delay","name":"delayNode","pauseType":"rate","timeout":5,"nbRateUnits":nbUnit,"timeoutUnits":"seconds","rate":aLimit,"rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(delayNode, flow, function() {
@@ -277,7 +269,7 @@ describe('delay Node', function() {
var possibleMaxMessageCount = Math.ceil(aLimit * (runtimeInMillis / 1000) + aLimit); // +aLimit as at the start of the 2nd period, we're allowing the 3rd burst
var i = 0;
delayNode1.receive({ payload: i, rate: rateValue });
delayNode1.receive({payload:i});
i++;
for (; i < possibleMaxMessageCount + 1; i++) {
setTimeout(function() {
@@ -314,23 +306,17 @@ describe('delay Node', function() {
it('limits the message rate to 1 per second, 4 seconds, with drop', function(done) {
this.timeout(6000);
dropRateLimitSECONDSTest(1, 1, 4000, null, done);
dropRateLimitSECONDSTest(1, 1, 4000, done);
});
it('limits the message rate to 1 per 2 seconds, 4 seconds, with drop', function(done) {
this.timeout(6000);
dropRateLimitSECONDSTest(1, 2, 4500, null, done);
dropRateLimitSECONDSTest(1, 2, 4500, done);
});
it('limits the message rate to 2 per second, 5 seconds, with drop', function(done) {
this.timeout(6000);
dropRateLimitSECONDSTest(2, 1, 5000, null, done);
});
it('limits the message rate with drop using msg.rate', function (done) {
this.timeout(6000);
RED.settings.nodeMessageBufferMaxLength = 3;
dropRateLimitSECONDSTest(2, 1, 5000, 1000, done);
dropRateLimitSECONDSTest(2, 1, 5000, done);
});
/**
@@ -733,7 +719,7 @@ describe('delay Node', function() {
setImmediate( function() { delayNode1.receive({reset:true}); }); // reset the queue
});
});
/* Messaging API support */
function mapiDoneTestHelper(done, pauseType, drop, msgAndTimings) {
const completeNode = require("nr-test-utils").require("@node-red/nodes/core/common/24-complete.js");
@@ -761,7 +747,7 @@ describe('delay Node', function() {
}
});
}
it('calls done when queued message is emitted (type: delay)', function(done) {
mapiDoneTestHelper(done, "delay", false, [{msg:{payload:1}, avr:1000, var:100}]);
});

View File

@@ -483,7 +483,7 @@ describe('trigger node', function() {
});
it('should be able to return things from flow and global context variables', function(done) {
var spy = sinon.stub(RED.util, 'evaluateNodeProperty').callsFake(
var spy = sinon.stub(RED.util, 'evaluateNodeProperty',
function(arg1, arg2, arg3, arg4, arg5) { if (arg5) { arg5(null, arg1) } else { return arg1; } }
);
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"foo", op1type:"flow", op2:"bar", op2type:"global", duration:"20", wires:[["n2"]] },
@@ -742,7 +742,7 @@ describe('trigger node', function() {
it('should be able to extend the delay', function(done) {
this.timeout(5000); // add extra time for flake
var spy = sinon.stub(RED.util, 'evaluateNodeProperty').callsFake(
var spy = sinon.stub(RED.util, 'evaluateNodeProperty',
function(arg1, arg2, arg3, arg4, arg5) { if (arg5) { arg5(null, arg1) } else { return arg1; } }
);
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", extend:"true", op1type:"flow", op1:"foo", op2:"bar", op2type:"global", duration:"100", wires:[["n2"]] },

View File

@@ -53,7 +53,7 @@ describe('exec node', function() {
it('should exec a simple command', function(done) {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:false, append:"", oldrc:"false"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec').callsFake(
var spy = sinon.stub(child_process, 'exec',
function(arg1, arg2, arg3, arg4) {
// arg3(error,stdout,stderr);
arg3(null,arg1,arg1.toUpperCase());
@@ -137,7 +137,7 @@ describe('exec node', function() {
it('should exec a simple command with extra parameters', function(done) {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:"payload", append:"more", oldrc:"false"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec').callsFake(
var spy = sinon.stub(child_process, 'exec',
function(arg1, arg2, arg3, arg4) {
//console.log(arg1);
// arg3(error,stdout,stderr);
@@ -193,7 +193,7 @@ describe('exec node', function() {
it('should be able to return a binary buffer', function(done) {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:true, append:"more", oldrc:"false"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec').callsFake(
var spy = sinon.stub(child_process, 'exec',
function(arg1, arg2, arg3, arg4) {
//console.log(arg1);
// arg3(error,stdout,stderr);
@@ -325,7 +325,7 @@ describe('exec node', function() {
it('should return the rc for a failing command', function(done) {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"error", addpay:false, append:"", oldrc:"false"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec').callsFake(
var spy = sinon.stub(child_process, 'exec',
function(arg1, arg2, arg3, arg4) {
//console.log(arg1);
// arg3(error,stdout,stderr);
@@ -388,7 +388,7 @@ describe('exec node', function() {
it('should preserve existing properties on msg object', function(done) {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"echo", addpay:false, append:"", oldrc:"false"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec').callsFake(
var spy = sinon.stub(child_process, 'exec',
function(arg1, arg2, arg3, arg4) {
// arg3(error,stdout,stderr);
arg3(null,arg1,arg1.toUpperCase());
@@ -455,7 +455,7 @@ describe('exec node', function() {
it('should preserve existing properties on msg object for a failing command', function(done) {
var flow = [{id:"n1",type:"exec",wires:[["n2"],["n3"],["n4"]],command:"error", addpay:false, append:"", oldrc:"false"},
{id:"n2", type:"helper"},{id:"n3", type:"helper"},{id:"n4", type:"helper"}];
var spy = sinon.stub(child_process, 'exec').callsFake(
var spy = sinon.stub(child_process, 'exec',
function(arg1, arg2, arg3, arg4) {
// arg3(error,stdout,stderr);
arg3({code: 1},arg1,arg1.toUpperCase());

View File

@@ -1,538 +0,0 @@
var should = require("should");
var helper = require("node-red-node-test-helper");
var testNode = require("nr-test-utils").require("@node-red/nodes/core/function/rbe.js");
describe('rbe node', function() {
"use strict";
beforeEach(function(done) {
helper.startServer(done);
});
afterEach(function(done) {
helper.unload().then(function() {
helper.stopServer(done);
});
});
it("should be loaded with correct defaults", function(done) {
var flow = [{"id":"n1", "type":"rbe", "name":"rbe1", "wires":[[]]}];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
n1.should.have.property("name", "rbe1");
n1.should.have.property("func", "rbe");
n1.should.have.property("gap", "0");
done();
});
});
it('should only send output if payload changes - with multiple topics (rbe)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"rbe", gap:"0", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
if (c === 0) {
msg.should.have.a.property("payload", "a");
c+=1;
}
else if (c === 1) {
msg.should.have.a.property("payload", 2);
c+=1;
}
else if (c == 2) {
msg.should.have.a.property("payload");
msg.payload.should.have.a.property("b",1);
msg.payload.should.have.a.property("c",2);
c+=1;
}
else if (c == 3) {
msg.should.have.a.property("payload",true);
c+=1;
}
else if (c == 4) {
msg.should.have.a.property("payload",false);
c+=1;
}
else if (c == 5) {
msg.should.have.a.property("payload",true);
c+=1;
}
else if (c == 6) {
msg.should.have.a.property("topic","a");
msg.should.have.a.property("payload",1);
c+=1;
}
else if (c == 7) {
msg.should.have.a.property("topic","b");
msg.should.have.a.property("payload",1);
c+=1;
}
else {
c += 1;
msg.should.have.a.property("topic","c");
msg.should.have.a.property("payload",1);
done();
}
});
n1.emit("input", {payload:"a"});
n1.emit("input", {payload:"a"});
n1.emit("input", {payload:"a"});
n1.emit("input", {payload:2});
n1.emit("input", {payload:2});
n1.emit("input", {payload:{b:1,c:2}});
n1.emit("input", {payload:{c:2,b:1}});
n1.emit("input", {payload:{c:2,b:1}});
n1.emit("input", {payload:true});
n1.emit("input", {payload:false});
n1.emit("input", {payload:false});
n1.emit("input", {payload:true});
n1.emit("input", {topic:"a",payload:1});
n1.emit("input", {topic:"b",payload:1});
n1.emit("input", {topic:"b",payload:1});
n1.emit("input", {topic:"a",payload:1});
n1.emit("input", {topic:"c",payload:1});
});
});
it('should ignore multiple topics if told to (rbe)', function(done) {
var flow = [{id:"n1", type:"rbe", func:"rbe", gap:"0", septopics:false, wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
if (c === 0) {
msg.should.have.a.property("payload", "a");
c+=1;
}
else if (c === 1) {
msg.should.have.a.property("payload", 2);
c+=1;
}
else if (c == 2) {
msg.should.have.a.property("payload");
msg.payload.should.have.a.property("b",1);
msg.payload.should.have.a.property("c",2);
c+=1;
}
else if (c == 3) {
msg.should.have.a.property("payload",true);
c+=1;
}
else if (c == 4) {
msg.should.have.a.property("payload",false);
c+=1;
}
else if (c == 5) {
msg.should.have.a.property("payload",true);
c+=1;
}
else if (c == 6) {
msg.should.have.a.property("topic","a");
msg.should.have.a.property("payload",1);
c+=1;
}
else {
msg.should.have.a.property("topic","a");
msg.should.have.a.property("payload",2);
done();
}
});
n1.emit("input", {topic:"a",payload:"a"});
n1.emit("input", {topic:"b",payload:"a"});
n1.emit("input", {topic:"c",payload:"a"});
n1.emit("input", {topic:"a",payload:2});
n1.emit("input", {topic:"b",payload:2});
n1.emit("input", {payload:{b:1,c:2}});
n1.emit("input", {payload:{c:2,b:1}});
n1.emit("input", {payload:{c:2,b:1}});
n1.emit("input", {topic:"a",payload:true});
n1.emit("input", {topic:"b",payload:false});
n1.emit("input", {topic:"c",payload:false});
n1.emit("input", {topic:"d",payload:true});
n1.emit("input", {topic:"a",payload:1});
n1.emit("input", {topic:"b",payload:1});
n1.emit("input", {topic:"c",payload:1});
n1.emit("input", {topic:"d",payload:1});
n1.emit("input", {topic:"a",payload:2});
});
});
it('should only send output if another chosen property changes - foo (rbe)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"rbe", gap:"0", property:"foo", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
if (c === 0) {
msg.should.have.a.property("foo", "a");
c+=1;
}
else if (c === 1) {
msg.should.have.a.property("foo", "b");
c+=1;
}
else {
msg.should.have.a.property("foo");
msg.foo.should.have.a.property("b",1);
msg.foo.should.have.a.property("c",2);
done();
}
});
n1.emit("input", {foo:"a"});
n1.emit("input", {payload:"a"});
n1.emit("input", {foo:"a"});
n1.emit("input", {payload:"a"});
n1.emit("input", {foo:"a"});
n1.emit("input", {foo:"b"});
n1.emit("input", {foo:{b:1,c:2}});
n1.emit("input", {foo:{c:2,b:1}});
n1.emit("input", {payload:{c:2,b:1}});
});
});
it('should only send output if payload changes - ignoring first value (rbei)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"rbei", gap:"0", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
if (c === 0) {
msg.should.have.a.property("payload", "b");
msg.should.have.a.property("topic", "a");
c+=1;
}
else if (c === 1) {
msg.should.have.a.property("payload", "b");
msg.should.have.a.property("topic", "b");
c+=1;
}
else if (c === 2) {
msg.should.have.a.property("payload", "c");
msg.should.have.a.property("topic", "a");
c+=1;
}
else {
msg.should.have.a.property("payload", "c");
msg.should.have.a.property("topic", "b");
done();
}
});
n1.emit("input", {payload:"a", topic:"a"});
n1.emit("input", {payload:"a", topic:"b"});
n1.emit("input", {payload:"a", topic:"a"});
n1.emit("input", {payload:"b", topic:"a"});
n1.emit("input", {payload:"b", topic:"b"});
n1.emit("input", {payload:"c", topic:"a"});
n1.emit("input", {payload:"c", topic:"b"});
});
});
it('should send output if queue is reset (rbe)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"rbe", gap:"0", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
if (c === 0) {
msg.should.have.a.property("payload", "a");
c+=1;
}
else if (c === 1) {
msg.should.have.a.property("payload", "b");
c+=1;
}
else if (c === 2) {
msg.should.have.a.property("payload", "a");
c+=1;
}
else if (c === 3) {
msg.should.have.a.property("payload", "b");
c+=1;
}
else if (c === 4) {
msg.should.have.a.property("payload", "b");
c+=1;
}
else if (c === 5) {
msg.should.have.a.property("payload", "b");
c+=1;
}
else if (c === 6) {
msg.should.have.a.property("payload", "a");
c+=1;
}
else {
msg.should.have.a.property("payload", "c");
done();
}
});
n1.emit("input", {topic:"a", payload:"a"});
n1.emit("input", {topic:"a", payload:"a"});
n1.emit("input", {topic:"b", payload:"b"});
n1.emit("input", {reset:true}); // reset all
n1.emit("input", {topic:"a", payload:"a"});
n1.emit("input", {topic:"b", payload:"b"});
n1.emit("input", {topic:"b", payload:"b"});
n1.emit("input", {topic:"b", reset:""}); // reset b
n1.emit("input", {topic:"b", payload:"b"});
n1.emit("input", {topic:"a", payload:"a"});
n1.emit("input", {reset:""}); // reset all
n1.emit("input", {topic:"b", payload:"b"});
n1.emit("input", {topic:"a", payload:"a"});
n1.emit("input", {topic:"c"}); // don't reset a non topic
n1.emit("input", {topic:"b", payload:"b"});
n1.emit("input", {topic:"a", payload:"a"});
n1.emit("input", {topic:"c", payload:"c"});
});
});
it('should only send output if x away from original value (deadbandEq)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"deadbandEq", gap:"10", inout:"out", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
c = c + 1;
if (c === 1) {
msg.should.have.a.property("payload", 0);
}
else if (c === 2) {
msg.should.have.a.property("payload", 10);
}
else if (c == 3) {
msg.should.have.a.property("payload", 20);
done();
}
});
n1.emit("input", {payload:0});
n1.emit("input", {payload:2});
n1.emit("input", {payload:4});
n1.emit("input", {payload:6});
n1.emit("input", {payload:8});
n1.emit("input", {payload:10});
n1.emit("input", {payload:15});
n1.emit("input", {payload:20});
});
});
it('should only send output if more than x away from original value (deadband)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"deadband", gap:"10", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
c = c + 1;
//console.log(c,msg);
if (c === 1) {
msg.should.have.a.property("payload", 0);
}
else if (c === 2) {
msg.should.have.a.property("payload", 20);
}
else {
msg.should.have.a.property("payload", "5 deg");
done();
}
});
n1.emit("input", {payload:0});
n1.emit("input", {payload:2});
n1.emit("input", {payload:4});
n1.emit("input", {payload:"6 deg"});
n1.emit("input", {payload:8});
n1.emit("input", {payload:20});
n1.emit("input", {payload:15});
n1.emit("input", {payload:"5 deg"});
});
});
it('should only send output if more than x% away from original value (deadband)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"deadband", gap:"10%", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
c = c + 1;
if (c === 1) {
msg.should.have.a.property("payload", 100);
}
else if (c === 2) {
msg.should.have.a.property("payload", 111);
}
else if (c === 3) {
msg.should.have.a.property("payload", 135);
done();
}
});
n1.emit("input", {payload:100});
n1.emit("input", {payload:95});
n1.emit("input", {payload:105});
n1.emit("input", {payload:111});
n1.emit("input", {payload:120});
n1.emit("input", {payload:135});
});
});
it('should warn if no number found in deadband mode', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"deadband", gap:"10", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
c += 1;
});
setTimeout( function() {
c.should.equal(0);
helper.log().called.should.be.true;
var logEvents = helper.log().args.filter(function (evt) {
return evt[0].type == "rbe";
});
logEvents.should.have.length(1);
var msg = logEvents[0][0];
msg.should.have.property('level', helper.log().WARN);
msg.should.have.property('id', 'n1');
msg.should.have.property('type', 'rbe');
msg.should.have.property('msg', 'rbe.warn.nonumber');
done();
},50);
n1.emit("input", {payload:"banana"});
});
});
it('should not send output if x away or greater from original value (narrowbandEq)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"narrowbandEq", gap:"10", inout:"out", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
c = c + 1;
//console.log(c,msg);
if (c === 1) {
msg.should.have.a.property("payload", 0);
}
else if (c === 2) {
msg.should.have.a.property("payload", 5);
}
else if (c === 3) {
msg.should.have.a.property("payload", 10);
done();
}
});
n1.emit("input", {payload:0});
n1.emit("input", {payload:10});
n1.emit("input", {payload:5});
n1.emit("input", {payload:15});
n1.emit("input", {payload:10});
n1.emit("input", {payload:20});
n1.emit("input", {payload:25});
});
});
it('should not send output if more than x away from original value (narrowband)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"narrowband", gap:"10", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
if (c === 0) {
msg.should.have.a.property("payload", 0);
}
else if (c === 1) {
msg.should.have.a.property("payload","6 deg");
}
else {
msg.should.have.a.property("payload", "5 deg");
done();
}
c += 1;
});
n1.emit("input", {payload:0});
n1.emit("input", {payload:20});
n1.emit("input", {payload:40});
n1.emit("input", {payload:"6 deg"});
n1.emit("input", {payload:18});
n1.emit("input", {payload:20});
n1.emit("input", {payload:50});
n1.emit("input", {payload:"5 deg"});
});
});
it('should send output if gap is 0 and input doesnt change (narrowband)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"narrowband", gap:"0", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
if (c === 0) {
msg.should.have.a.property("payload", 1);
}
else if (c === 4) {
msg.should.have.a.property("payload",1);
done();
}
c += 1;
});
n1.emit("input", {payload:1});
n1.emit("input", {payload:1});
n1.emit("input", {payload:1});
n1.emit("input", {payload:1});
n1.emit("input", {payload:0});
n1.emit("input", {payload:1});
});
});
it('should not send output if more than x away from original value (narrowband in step mode)', function(done) {
var flow = [{"id":"n1", "type":"rbe", func:"narrowband", gap:"10", inout:"in", start:"500", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(testNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
if (c === 0) {
msg.should.have.a.property("payload", 55);
}
else if (c === 1) {
msg.should.have.a.property("payload", 205);
done();
}
c += 1;
});
n1.emit("input", {payload:50});
n1.emit("input", {payload:55});
n1.emit("input", {payload:200});
n1.emit("input", {payload:205});
});
});
});

View File

@@ -170,6 +170,24 @@ describe('CSV node', function() {
n1.emit("input", {payload:testString});
});
});
it('should allow passing in a template as first line of CSV (not comma)', function(done) {
var flow = [ { id:"n1", type:"csv", temp:"", hdrin:true, sep:";", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(csvNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
msg.should.have.property('payload', { a: 1, "b b":2, "c;c":3, "d, d": 4 });
msg.should.have.property('columns', 'a,b b,c;c,"d, d"');
check_parts(msg, 0, 1);
done();
});
var testString = 'a;b b;"c;c";" d, d "'+"\n"+"1;2;3;4"+String.fromCharCode(10);
n1.emit("input", {payload:testString});
});
});
it('should leave numbers starting with 0, e and + as strings (except 0.)', function(done) {
var flow = [ { id:"n1", type:"csv", temp:"a,b,c,d,e,f,g", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
@@ -609,6 +627,24 @@ describe('CSV node', function() {
});
});
it('should convert a simple object back to a tsv using a tab as a separator', function(done) {
var flow = [ { id:"n1", type:"csv", temp:"", sep:"\t", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
helper.load(csvNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('payload', '1\tfoo\t"ba""r"\tdi,ng\n');
done();
}
catch(e) { done(e); }
});
var testJson = { d:1, b:"foo", c:"ba\"r", a:"di,ng" };
n1.emit("input", {payload:testJson});
});
});
it('should handle a template with spaces in the property names', function(done) {
var flow = [ { id:"n1", type:"csv", temp:"a,b o,c p,,e", wires:[["n2"]] },
{id:"n2", type:"helper"} ];

View File

@@ -391,7 +391,7 @@ describe('file Nodes', function() {
it('should fail to write to a ro file', function(done) {
// Stub file write so we can make writes fail
var spy = sinon.stub(fs, 'createWriteStream').callsFake(function(arg1,arg2) {
var spy = sinon.stub(fs, 'createWriteStream', function(arg1,arg2) {
var ws = {};
ws.on = function(e,d) { throw("Stub error message"); }
ws.write = function(e,d) { }
@@ -421,7 +421,7 @@ describe('file Nodes', function() {
it('should fail to append to a ro file', function(done) {
// Stub file write so we can make writes fail
var spy = sinon.stub(fs, 'createWriteStream').callsFake(function(arg1,arg2) {
var spy = sinon.stub(fs, 'createWriteStream', function(arg1,arg2) {
var ws = {};
ws.on = function(e,d) { throw("Stub error message"); }
ws.write = function(e,d) { }
@@ -451,7 +451,7 @@ describe('file Nodes', function() {
it('should cope with failing to delete a file', function(done) {
// Stub file write so we can make writes fail
var spy = sinon.stub(fs, 'unlink').callsFake(function(arg,arg2) { arg2(new Error("Stub error message")); });
var spy = sinon.stub(fs, 'unlink', function(arg,arg2) { arg2(new Error("Stub error message")); });
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":"delete"}];
helper.load(fileNode, flow, function() {
@@ -477,7 +477,7 @@ describe('file Nodes', function() {
it('should fail to create a new directory if not asked to do so (append)', function(done) {
// Stub file write so we can make writes fail
var fileToTest2 = path.join(resourcesDir,"file-out-node","50-file-test-file.txt");
//var spy = sinon.stub(fs, 'appendFile').callsFake(function(arg,arg2,arg3,arg4){ arg4(new Error("Stub error message")); });
//var spy = sinon.stub(fs, 'appendFile', function(arg,arg2,arg3,arg4){ arg4(new Error("Stub error message")); });
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest2, "appendNewline":true, "overwriteFile":false}];
helper.load(fileNode, flow, function() {
@@ -508,7 +508,7 @@ describe('file Nodes', function() {
}
// Stub file write so we can make writes fail
var fileToTest2 = path.join(resourcesDir,"file-out-node","50-file-test-file.txt");
var spy = sinon.stub(fs, "ensureDir").callsFake(function(arg1,arg2,arg3,arg4) { arg2(null); });
var spy = sinon.stub(fs, "ensureDir", function(arg1,arg2,arg3,arg4) { arg2(null); });
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest2, "appendNewline":true, "overwriteFile":false, "createDir":true}];
helper.load(fileNode, flow, function() {
var n1 = helper.getNode("fileNode1");
@@ -531,7 +531,7 @@ describe('file Nodes', function() {
it('should fail to create a new directory if not asked to do so (overwrite)', function(done) {
// Stub file write so we can make writes fail
var fileToTest2 = path.join(resourcesDir,"file-out-node","50-file-test-file.txt");
//var spy = sinon.stub(fs, 'appendFile').callsFake(function(arg,arg2,arg3,arg4){ arg4(new Error("Stub error message")); });
//var spy = sinon.stub(fs, 'appendFile', function(arg,arg2,arg3,arg4){ arg4(new Error("Stub error message")); });
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest2, "appendNewline":false, "overwriteFile":true}];
helper.load(fileNode, flow, function() {
@@ -557,7 +557,7 @@ describe('file Nodes', function() {
it('should try to create a new directory if asked to do so (overwrite)', function(done) {
// Stub file write so we can make writes fail
var fileToTest2 = path.join(resourcesDir,"file-out-node","50-file-test-file.txt");
var spy = sinon.stub(fs, "ensureDir").callsFake(function(arg1,arg2,arg3,arg4) { arg2(null); });
var spy = sinon.stub(fs, "ensureDir", function(arg1,arg2,arg3,arg4) { arg2(null); });
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest2, "appendNewline":true, "overwriteFile":true, "createDir":true}];
helper.load(fileNode, flow, function() {

View File

@@ -45,35 +45,35 @@ describe("api/admin/index", function() {
};
before(function() {
mockList.forEach(function(m) {
sinon.stub(m,"init").callsFake(function(){});
sinon.stub(m,"init",function(){});
});
sinon.stub(auth,"needsPermission").callsFake(function(permission) {
sinon.stub(auth,"needsPermission", function(permission) {
return function(req,res,next) {
permissionChecks[permission] = (permissionChecks[permission]||0)+1;
next();
};
});
sinon.stub(flows,"get").callsFake(stubApp);
sinon.stub(flows,"post").callsFake(stubApp);
sinon.stub(flows,"get",stubApp);
sinon.stub(flows,"post",stubApp);
sinon.stub(flow,"get").callsFake(stubApp);
sinon.stub(flow,"post").callsFake(stubApp);
sinon.stub(flow,"delete").callsFake(stubApp);
sinon.stub(flow,"put").callsFake(stubApp);
sinon.stub(flow,"get",stubApp);
sinon.stub(flow,"post",stubApp);
sinon.stub(flow,"delete",stubApp);
sinon.stub(flow,"put",stubApp);
sinon.stub(nodes,"getAll").callsFake(stubApp);
sinon.stub(nodes,"post").callsFake(stubApp);
sinon.stub(nodes,"getModule").callsFake(stubApp);
sinon.stub(nodes,"putModule").callsFake(stubApp);
sinon.stub(nodes,"delete").callsFake(stubApp);
sinon.stub(nodes,"getSet").callsFake(stubApp);
sinon.stub(nodes,"putSet").callsFake(stubApp);
sinon.stub(nodes,"getModuleCatalog").callsFake(stubApp);
sinon.stub(nodes,"getModuleCatalogs").callsFake(stubApp);
sinon.stub(nodes,"getAll",stubApp);
sinon.stub(nodes,"post",stubApp);
sinon.stub(nodes,"getModule",stubApp);
sinon.stub(nodes,"putModule",stubApp);
sinon.stub(nodes,"delete",stubApp);
sinon.stub(nodes,"getSet",stubApp);
sinon.stub(nodes,"putSet",stubApp);
sinon.stub(nodes,"getModuleCatalog",stubApp);
sinon.stub(nodes,"getModuleCatalogs",stubApp);
sinon.stub(context,"get").callsFake(stubApp);
sinon.stub(context,"delete").callsFake(stubApp);
sinon.stub(context,"get",stubApp);
sinon.stub(context,"delete",stubApp);
});
after(function() {
mockList.forEach(function(m) {

View File

@@ -41,7 +41,7 @@ describe("api/admin/nodes", function() {
app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,nodes.putSet);
app.get("/getIcons",nodes.getIcons);
app.delete(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,nodes.delete);
sinon.stub(apiUtil,"determineLangFromHeaders").callsFake(function() {
sinon.stub(apiUtil,"determineLangFromHeaders", function() {
return "en-US";
});
});

View File

@@ -29,7 +29,7 @@ var theme = NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/theme");
describe("api/editor/settings", function() {
before(function() {
sinon.stub(theme,"settings").callsFake(function() { return { existing: 123, test: 456 };});
sinon.stub(theme,"settings",function() { return { existing: 123, test: 456 };});
app = express();
app.use(bodyParser.json());
app.get("/settings",info.runtimeSettings);

View File

@@ -58,7 +58,7 @@ describe("api/auth/index",function() {
describe("revoke", function() {
it("revokes a token", function(done) {
var revokeToken = sinon.stub(Tokens,"revoke").callsFake(function() {
var revokeToken = sinon.stub(Tokens,"revoke",function() {
return Promise.resolve();
});
@@ -79,8 +79,8 @@ describe("api/auth/index",function() {
describe("login", function() {
beforeEach(function() {
sinon.stub(Tokens,"init").callsFake(function(){});
sinon.stub(Users,"init").callsFake(function(){});
sinon.stub(Tokens,"init",function(){});
sinon.stub(Users,"init",function(){});
});
afterEach(function() {
Tokens.init.restore();
@@ -119,8 +119,8 @@ describe("api/auth/index",function() {
});
describe("needsPermission", function() {
beforeEach(function() {
sinon.stub(Tokens,"init").callsFake(function(){});
sinon.stub(Users,"init").callsFake(function(){});
sinon.stub(Tokens,"init",function(){});
sinon.stub(Users,"init",function(){});
});
afterEach(function() {
Tokens.init.restore();
@@ -135,7 +135,7 @@ describe("api/auth/index",function() {
it('no-ops if adminAuth not set', function(done) {
sinon.stub(passport,"authenticate").callsFake(function(scopes,opts) {
sinon.stub(passport,"authenticate",function(scopes,opts) {
return function(req,res,next) {
}
});
@@ -147,12 +147,12 @@ describe("api/auth/index",function() {
})
});
it('skips auth if req.user undefined', function(done) {
sinon.stub(passport,"authenticate").callsFake(function(scopes,opts) {
sinon.stub(passport,"authenticate",function(scopes,opts) {
return function(req,res,next) {
next();
}
});
sinon.stub(Permissions,"hasPermission").callsFake(function(perm) { return true });
sinon.stub(Permissions,"hasPermission",function(perm) { return true });
auth.init({adminAuth:{}});
var func = auth.needsPermission("foo");
func({user:null},{},function() {
@@ -167,12 +167,12 @@ describe("api/auth/index",function() {
});
it('passes for valid user permission', function(done) {
sinon.stub(passport,"authenticate").callsFake(function(scopes,opts) {
sinon.stub(passport,"authenticate",function(scopes,opts) {
return function(req,res,next) {
next();
}
});
sinon.stub(Permissions,"hasPermission").callsFake(function(perm) { return true });
sinon.stub(Permissions,"hasPermission",function(perm) { return true });
auth.init({adminAuth:{}});
var func = auth.needsPermission("foo");
func({user:true,authInfo: { scope: "read"}},{},function() {
@@ -189,12 +189,12 @@ describe("api/auth/index",function() {
});
it('rejects for invalid user permission', function(done) {
sinon.stub(passport,"authenticate").callsFake(function(scopes,opts) {
sinon.stub(passport,"authenticate",function(scopes,opts) {
return function(req,res,next) {
next();
}
});
sinon.stub(Permissions,"hasPermission").callsFake(function(perm) { return false });
sinon.stub(Permissions,"hasPermission",function(perm) { return false });
auth.init({adminAuth:{}});
var func = auth.needsPermission("foo");
func({user:true,authInfo: { scope: "read"}},{

View File

@@ -35,7 +35,7 @@ describe("api/auth/strategies", function() {
});
it('Handles authentication failure',function(done) {
userAuthentication = sinon.stub(Users,"authenticate").callsFake(function(username,password) {
userAuthentication = sinon.stub(Users,"authenticate",function(username,password) {
return Promise.resolve(null);
});
@@ -51,7 +51,7 @@ describe("api/auth/strategies", function() {
});
it('Handles scope overreach',function(done) {
userAuthentication = sinon.stub(Users,"authenticate").callsFake(function(username,password) {
userAuthentication = sinon.stub(Users,"authenticate",function(username,password) {
return Promise.resolve({username:"user",permissions:"read"});
});
@@ -67,11 +67,11 @@ describe("api/auth/strategies", function() {
});
it('Creates new token on authentication success',function(done) {
userAuthentication = sinon.stub(Users,"authenticate").callsFake(function(username,password) {
userAuthentication = sinon.stub(Users,"authenticate",function(username,password) {
return Promise.resolve({username:"user",permissions:"*"});
});
var tokenDetails = {};
var tokenCreate = sinon.stub(Tokens,"create").callsFake(function(username,client,scope) {
var tokenCreate = sinon.stub(Tokens,"create",function(username,client,scope) {
tokenDetails.username = username;
tokenDetails.client = client;
tokenDetails.scope = scope;
@@ -98,7 +98,7 @@ describe("api/auth/strategies", function() {
describe("Anonymous Strategy", function() {
it('Succeeds if anon user enabled',function(done) {
var userDefault = sinon.stub(Users,"default").callsFake(function() {
var userDefault = sinon.stub(Users,"default",function() {
return Promise.resolve("anon");
});
strategies.anonymousStrategy._success = strategies.anonymousStrategy.success;
@@ -111,7 +111,7 @@ describe("api/auth/strategies", function() {
strategies.anonymousStrategy.authenticate({});
});
it('Fails if anon user not enabled',function(done) {
var userDefault = sinon.stub(Users,"default").callsFake(function() {
var userDefault = sinon.stub(Users,"default",function() {
return Promise.resolve(null);
});
strategies.anonymousStrategy._fail = strategies.anonymousStrategy.fail;
@@ -130,10 +130,10 @@ describe("api/auth/strategies", function() {
describe("Tokens Strategy", function() {
it('Succeeds if tokens user enabled custom header',function(done) {
var userTokens = sinon.stub(Users,"tokens").callsFake(function(token) {
var userTokens = sinon.stub(Users,"tokens",function(token) {
return Promise.resolve("tokens-"+token);
});
var userTokenHeader = sinon.stub(Users,"tokenHeader").callsFake(function(token) {
var userTokenHeader = sinon.stub(Users,"tokenHeader",function(token) {
return "x-test-token";
});
strategies.tokensStrategy._success = strategies.tokensStrategy.success;
@@ -146,10 +146,10 @@ describe("api/auth/strategies", function() {
strategies.tokensStrategy.authenticate({headers:{"x-test-token":"1234"}});
});
it('Succeeds if tokens user enabled default header',function(done) {
var userTokens = sinon.stub(Users,"tokens").callsFake(function(token) {
var userTokens = sinon.stub(Users,"tokens",function(token) {
return Promise.resolve("tokens-"+token);
});
var userTokenHeader = sinon.stub(Users,"tokenHeader").callsFake(function(token) {
var userTokenHeader = sinon.stub(Users,"tokenHeader",function(token) {
return "authorization";
});
strategies.tokensStrategy._success = strategies.tokensStrategy.success;
@@ -162,10 +162,10 @@ describe("api/auth/strategies", function() {
strategies.tokensStrategy.authenticate({headers:{"authorization":"Bearer 1234"}});
});
it('Fails if tokens user not enabled',function(done) {
var userTokens = sinon.stub(Users,"tokens").callsFake(function() {
var userTokens = sinon.stub(Users,"tokens",function() {
return Promise.resolve(null);
});
var userTokenHeader = sinon.stub(Users,"tokenHeader").callsFake(function(token) {
var userTokenHeader = sinon.stub(Users,"tokenHeader",function(token) {
return "authorization";
});
strategies.tokensStrategy._fail = strategies.tokensStrategy.fail;
@@ -185,7 +185,7 @@ describe("api/auth/strategies", function() {
describe("Bearer Strategy", function() {
it('Rejects invalid token',function(done) {
var getToken = sinon.stub(Tokens,"get").callsFake(function(token) {
var getToken = sinon.stub(Tokens,"get",function(token) {
return Promise.resolve(null);
});
@@ -202,10 +202,10 @@ describe("api/auth/strategies", function() {
});
});
it('Accepts valid token',function(done) {
var getToken = sinon.stub(Tokens,"get").callsFake(function(token) {
var getToken = sinon.stub(Tokens,"get",function(token) {
return Promise.resolve({user:"user",scope:"scope"});
});
var getUser = sinon.stub(Users,"get").callsFake(function(username) {
var getUser = sinon.stub(Users,"get",function(username) {
return Promise.resolve("aUser");
});
@@ -224,10 +224,10 @@ describe("api/auth/strategies", function() {
});
});
it('Fail if no user for token',function(done) {
var getToken = sinon.stub(Tokens,"get").callsFake(function(token) {
var getToken = sinon.stub(Tokens,"get",function(token) {
return Promise.resolve({user:"user",scope:"scope"});
});
var getUser = sinon.stub(Users,"get").callsFake(function(username) {
var getUser = sinon.stub(Users,"get",function(username) {
return Promise.resolve(null);
});
@@ -250,7 +250,7 @@ describe("api/auth/strategies", function() {
describe("Client Password Strategy", function() {
it('Accepts valid client',function(done) {
var testClient = {id:"node-red-editor",secret:"not_available"};
var getClient = sinon.stub(Clients,"get").callsFake(function(client) {
var getClient = sinon.stub(Clients,"get",function(client) {
return Promise.resolve(testClient);
});
@@ -268,7 +268,7 @@ describe("api/auth/strategies", function() {
});
it('Rejects invalid client secret',function(done) {
var testClient = {id:"node-red-editor",secret:"not_available"};
var getClient = sinon.stub(Clients,"get").callsFake(function(client) {
var getClient = sinon.stub(Clients,"get",function(client) {
return Promise.resolve(testClient);
});
@@ -285,7 +285,7 @@ describe("api/auth/strategies", function() {
});
});
it('Rejects invalid client id',function(done) {
var getClient = sinon.stub(Clients,"get").callsFake(function(client) {
var getClient = sinon.stub(Clients,"get",function(client) {
return Promise.resolve(null);
});
strategies.clientPasswordStrategy("invalid_id","invalid_secret",function(err,client) {
@@ -303,7 +303,7 @@ describe("api/auth/strategies", function() {
var userAuthentication;
it('Blocks after 5 failures',function(done) {
userAuthentication = sinon.stub(Users,"authenticate").callsFake(function(username,password) {
userAuthentication = sinon.stub(Users,"authenticate",function(username,password) {
return Promise.resolve(null);
});
for (var z=0; z<5; z++) {

View File

@@ -58,7 +58,7 @@ describe("api/editor/comms", function() {
var url;
var port;
before(function(done) {
sinon.stub(Users,"default").callsFake(function() { return Promise.resolve(null);});
sinon.stub(Users,"default",function() { return Promise.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {}, {comms: mockComms});
server.listen(listenPort, address);
@@ -126,7 +126,7 @@ describe("api/editor/comms", function() {
var url;
var port;
before(function(done) {
sinon.stub(Users,"default").callsFake(function() { return Promise.resolve(null);});
sinon.stub(Users,"default",function() { return Promise.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {disableEditor:true}, {comms: mockComms});
server.listen(listenPort, address);
@@ -164,7 +164,7 @@ describe("api/editor/comms", function() {
var url;
var port;
before(function(done) {
sinon.stub(Users,"default").callsFake(function() { return Promise.resolve(null);});
sinon.stub(Users,"default",function() { return Promise.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {httpAdminRoot:"/adminPath"}, {comms: mockComms});
server.listen(listenPort, address);
@@ -202,7 +202,7 @@ describe("api/editor/comms", function() {
var url;
var port;
before(function(done) {
sinon.stub(Users,"default").callsFake(function() { return Promise.resolve(null);});
sinon.stub(Users,"default",function() { return Promise.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {httpAdminRoot:"/adminPath/"}, {comms: mockComms});
server.listen(listenPort, address);
@@ -240,7 +240,7 @@ describe("api/editor/comms", function() {
var url;
var port;
before(function(done) {
sinon.stub(Users,"default").callsFake(function() { return Promise.resolve(null);});
sinon.stub(Users,"default",function() { return Promise.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {httpAdminRoot:"adminPath"}, {comms: mockComms});
server.listen(listenPort, address);
@@ -278,7 +278,7 @@ describe("api/editor/comms", function() {
var url;
var port;
before(function(done) {
sinon.stub(Users,"default").callsFake(function() { return Promise.resolve(null);});
sinon.stub(Users,"default",function() { return Promise.resolve(null);});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {webSocketKeepAliveTime: 100}, {comms: mockComms});
server.listen(listenPort, address);
@@ -344,22 +344,22 @@ describe("api/editor/comms", function() {
var getToken;
var getUserToken;
before(function(done) {
getDefaultUser = sinon.stub(Users,"default").callsFake(function() { return Promise.resolve(null);});
getUser = sinon.stub(Users,"get").callsFake(function(username) {
getDefaultUser = sinon.stub(Users,"default",function() { return Promise.resolve(null);});
getUser = sinon.stub(Users,"get", function(username) {
if (username == "fred") {
return Promise.resolve({permissions:"read"});
} else {
return Promise.resolve(null);
}
});
getUserToken = sinon.stub(Users,"tokens").callsFake(function(token) {
getUserToken = sinon.stub(Users,"tokens", function(token) {
if (token == "abcde") {
return Promise.resolve({user:"wilma", permissions:"*"})
} else {
return Promise.resolve(null);
}
});
getToken = sinon.stub(Tokens,"get").callsFake(function(token) {
getToken = sinon.stub(Tokens,"get",function(token) {
if (token == "1234") {
return Promise.resolve({user:"fred",scope:["*"]});
} else if (token == "5678") {
@@ -483,7 +483,7 @@ describe("api/editor/comms", function() {
var port;
var getDefaultUser;
before(function(done) {
getDefaultUser = sinon.stub(Users,"default").callsFake(function() { return Promise.resolve({permissions:"read"});});
getDefaultUser = sinon.stub(Users,"default",function() { return Promise.resolve({permissions:"read"});});
server = stoppable(http.createServer(function(req,res){app(req,res)}));
comms.init(server, {adminAuth:{}}, {comms: mockComms});
server.listen(listenPort, address);

View File

@@ -32,8 +32,8 @@ describe("api/editor/index", function() {
var app;
describe("disabled the editor", function() {
beforeEach(function() {
sinon.stub(comms,'init').callsFake(function(){});
sinon.stub(info,'init').callsFake(function(){});
sinon.stub(comms,'init', function(){});
sinon.stub(info,'init', function(){});
});
afterEach(function() {
comms.init.restore();
@@ -54,13 +54,13 @@ describe("api/editor/index", function() {
var errors = [];
var session_data = {};
before(function() {
sinon.stub(auth,'needsPermission').callsFake(function(permission) {
sinon.stub(auth,'needsPermission',function(permission) {
return function(req,res,next) { next(); }
});
mockList.forEach(function(m) {
sinon.stub(NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/"+m),"init").callsFake(function(){});
sinon.stub(NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/"+m),"init",function(){});
});
sinon.stub(NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/theme"),"app").callsFake(function(){ return express()});
sinon.stub(NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/theme"),"app",function(){ return express()});
});
after(function() {
mockList.forEach(function(m) {
@@ -72,7 +72,7 @@ describe("api/editor/index", function() {
});
before(function() {
sinon.stub(log,"error").callsFake(function(err) { errors.push(err)})
sinon.stub(log,"error",function(err) { errors.push(err)})
app = editorApi.init({},{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false,exportNodeSettings:function(){}},{
isStarted: () => Promise.resolve(isStarted)
});

View File

@@ -50,9 +50,9 @@ describe("api/editor/locales", function() {
locales.init({});
// bit of a mess of internal workings
sinon.stub(i18n.i,'changeLanguage').callsFake(function(lang,callback) { if (callback) {callback();}});
sinon.stub(i18n.i,'changeLanguage',function(lang,callback) { if (callback) {callback();}});
if (i18n.i.getResourceBundle) {
sinon.stub(i18n.i,'getResourceBundle').callsFake(function(lang, namespace) {return {namespace:namespace, lang:lang};});
sinon.stub(i18n.i,'getResourceBundle',function(lang, namespace) {return {namespace:namespace, lang:lang};});
} else {
// If i18n.init has not been called, then getResourceBundle isn't
// defined - so hardcode a stub
@@ -121,7 +121,7 @@ describe("api/editor/locales", function() {
// var app;
// before(function() {
// // bit of a mess of internal workings
// sinon.stub(i18n,'catalog').callsFake(function(namespace, lang) {
// sinon.stub(i18n,'catalog',function(namespace, lang) {
// return {
// "node-red": "should not return",
// "test-module-a-id": "test-module-a-catalog",

View File

@@ -29,7 +29,7 @@ var theme = NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/theme");
describe("api/editor/settings", function() {
before(function() {
sinon.stub(theme,"settings").callsFake(function() { return { existing: 123, test: 456 };});
sinon.stub(theme,"settings",function() { return { existing: 123, test: 456 };});
app = express();
app.use(bodyParser.json());
app.get("/settings/user",function(req,res,next) {req.user = "fred"; next()}, info.userSettings);

View File

@@ -27,7 +27,7 @@ var theme = NR_TEST_UTILS.require("@node-red/editor-api/lib/editor/theme");
describe("api/editor/theme", function () {
beforeEach(function () {
sinon.stub(fs, "statSync").callsFake(function () { return true; });
sinon.stub(fs, "statSync", function () { return true; });
});
afterEach(function () {
theme.init({settings: {}});

View File

@@ -31,18 +31,18 @@ var apiAdmin = NR_TEST_UTILS.require("@node-red/editor-api/lib/admin");
describe("api/index", function() {
var beforeEach = function() {
sinon.stub(apiAuth,"init").callsFake(function(){});
sinon.stub(apiEditor,"init").callsFake(function(){
sinon.stub(apiAuth,"init",function(){});
sinon.stub(apiEditor,"init",function(){
var app = express();
app.get("/editor",function(req,res) { res.status(200).end(); });
return app;
});
sinon.stub(apiAdmin,"init").callsFake(function(){
sinon.stub(apiAdmin,"init",function(){
var app = express();
app.get("/admin",function(req,res) { res.status(200).end(); });
return app;
});
sinon.stub(apiAuth,"login").callsFake(function(req,res){
sinon.stub(apiAuth,"login",function(req,res){
res.status(200).end();
});
};
@@ -115,7 +115,7 @@ describe("api/index", function() {
describe('initialises api with authentication enabled', function(done) {
it('enables an oauth/openID based authentication mechanism',function(done) {
const stub = sinon.stub(apiAuth, 'genericStrategy').callsFake(function(){});
const stub = sinon.stub(apiAuth, 'genericStrategy', function(){});
const adminAuth = { type: 'strategy', strategy: {} }
api.init({ httpAdminRoot: true, adminAuth },{},{},{});
should(stub.called).be.ok();
@@ -159,7 +159,7 @@ describe("api/index", function() {
describe('editor start', function (done) {
it('cannot be started when editor is disabled', function (done) {
const stub = sinon.stub(apiEditor, 'start').callsFake(function () {
const stub = sinon.stub(apiEditor, 'start', function () {
return Promise.resolve(true);
});
api.init({ httpAdminRoot: true, disableEditor: true }, {}, {}, {});

View File

@@ -33,8 +33,8 @@ describe("api/util", function() {
var app;
before(function() {
app = express();
sinon.stub(log,'error').callsFake(function(msg) {loggedError = msg;});
sinon.stub(log,'audit').callsFake(function(event) {loggedEvent = event;});
sinon.stub(log,'error',function(msg) {loggedError = msg;});
sinon.stub(log,'audit',function(event) {loggedEvent = event;});
app.get("/tooLarge", function(req,res) {
var err = new Error();
err.message = "request entity too large";

View File

@@ -44,7 +44,7 @@ describe("externalModules api", function() {
})
describe("checkFlowDependencies", function() {
beforeEach(function() {
sinon.stub(exec,"run").callsFake(async function(cmd, args, options) {
sinon.stub(exec,"run", async function(cmd, args, options) {
let error;
if (args[1] === "moduleNotFound") {
error = new Error();

View File

@@ -49,10 +49,10 @@ describe('red/registry/index', function() {
describe('#addModule', function() {
it('loads the module and returns its info', function(done) {
stubs.push(sinon.stub(loader,"addModule").callsFake(function(module) {
stubs.push(sinon.stub(loader,"addModule",function(module) {
return Promise.resolve();
}));
stubs.push(sinon.stub(typeRegistry,"getModuleInfo").callsFake(function(module) {
stubs.push(sinon.stub(typeRegistry,"getModuleInfo", function(module) {
return "info";
}));
registry.addModule("foo").then(function(info) {
@@ -61,10 +61,10 @@ describe('red/registry/index', function() {
}).catch(function(err) { done(err); });
});
it('rejects if loader rejects', function(done) {
stubs.push(sinon.stub(loader,"addModule").callsFake(function(module) {
stubs.push(sinon.stub(loader,"addModule",function(module) {
return Promise.reject("error");
}));
stubs.push(sinon.stub(typeRegistry,"getModuleInfo").callsFake(function(module) {
stubs.push(sinon.stub(typeRegistry,"getModuleInfo", function(module) {
return "info";
}));
registry.addModule("foo").then(function(info) {
@@ -78,10 +78,10 @@ describe('red/registry/index', function() {
describe('#enableNode',function() {
it('enables a node set',function(done) {
stubs.push(sinon.stub(typeRegistry,"enableNodeSet").callsFake(function() {
stubs.push(sinon.stub(typeRegistry,"enableNodeSet",function() {
return Promise.resolve();
}));
stubs.push(sinon.stub(typeRegistry,"getNodeInfo").callsFake(function() {
stubs.push(sinon.stub(typeRegistry,"getNodeInfo", function() {
return {id:"node-set",loaded:true};
}));
registry.enableNode("node-set").then(function(ns) {
@@ -92,7 +92,7 @@ describe('red/registry/index', function() {
});
it('rejects if node unknown',function() {
stubs.push(sinon.stub(typeRegistry,"enableNodeSet").callsFake(function() {
stubs.push(sinon.stub(typeRegistry,"enableNodeSet",function() {
throw new Error('failure');
}));
/*jshint immed: false */
@@ -102,15 +102,15 @@ describe('red/registry/index', function() {
});
it('triggers a node load',function(done) {
stubs.push(sinon.stub(typeRegistry,"enableNodeSet").callsFake(function() {
stubs.push(sinon.stub(typeRegistry,"enableNodeSet",function() {
return Promise.resolve();
}));
var calls = 0;
stubs.push(sinon.stub(typeRegistry,"getNodeInfo").callsFake(function() {
stubs.push(sinon.stub(typeRegistry,"getNodeInfo", function() {
// loaded=false on first call, true on subsequent
return {id:"node-set",loaded:(calls++>0)};
}));
stubs.push(sinon.stub(loader,"loadNodeSet").callsFake(function(){return Promise.resolve();}));
stubs.push(sinon.stub(loader,"loadNodeSet",function(){return Promise.resolve();}));
stubs.push(sinon.stub(typeRegistry,"getFullNodeInfo"));
registry.enableNode("node-set").then(function(ns) {

View File

@@ -42,7 +42,7 @@ describe('nodes/registry/installer', function() {
var execResponse;
beforeEach(function() {
sinon.stub(exec,"run").callsFake(() => execResponse || Promise.resolve(""))
sinon.stub(exec,"run", () => execResponse || Promise.resolve(""))
installer.init({})
});
@@ -118,7 +118,7 @@ describe('nodes/registry/installer', function() {
var p = Promise.reject(res);
p.catch((err)=>{});
execResponse = p;
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
sinon.stub(typeRegistry,"getModuleInfo", function() {
return {
version: "0.1.1"
}
@@ -129,7 +129,7 @@ describe('nodes/registry/installer', function() {
}).catch(done);
});
it("rejects when update requested to existing version", function(done) {
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
sinon.stub(typeRegistry,"getModuleInfo", function() {
return {
user: true,
version: "0.1.1"
@@ -141,7 +141,7 @@ describe('nodes/registry/installer', function() {
}).catch(done);
});
it("rejects when update requested to existing version and url", function(done) {
sinon.stub(typeRegistry,"getModuleInfo").callsFake(function() {
sinon.stub(typeRegistry,"getModuleInfo", function() {
return {
user: true,
version: "0.1.1"
@@ -180,7 +180,7 @@ describe('nodes/registry/installer', function() {
p.catch((err)=>{});
execResponse = p;
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
var addModule = sinon.stub(registry,"addModule",function(md) {
return Promise.resolve(nodeInfo);
});
@@ -211,7 +211,7 @@ describe('nodes/registry/installer', function() {
});
it("succeeds when path is valid node-red module", function(done) {
var nodeInfo = {nodes:{module:"foo",types:["a"]}};
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
var addModule = sinon.stub(registry,"addModule",function(md) {
return Promise.resolve(nodeInfo);
});
var resourcesDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule","node_modules","TestNodeModule"));
@@ -241,7 +241,7 @@ describe('nodes/registry/installer', function() {
p.catch((err)=>{});
execResponse = p;
var addModule = sinon.stub(registry,"addModule").callsFake(function(md) {
var addModule = sinon.stub(registry,"addModule",function(md) {
return Promise.resolve(nodeInfo);
});
@@ -267,7 +267,7 @@ describe('nodes/registry/installer', function() {
it("rejects with generic error", function(done) {
var nodeInfo = [{module:"foo",types:["a"]}];
var removeModule = sinon.stub(registry,"removeModule").callsFake(function(md) {
var removeModule = sinon.stub(registry,"removeModule",function(md) {
return Promise.resolve(nodeInfo);
});
var res = {
@@ -288,10 +288,10 @@ describe('nodes/registry/installer', function() {
});
it("succeeds when module is found", function(done) {
var nodeInfo = [{module:"foo",types:["a"]}];
var removeModule = sinon.stub(typeRegistry,"removeModule").callsFake(function(md) {
var removeModule = sinon.stub(typeRegistry,"removeModule",function(md) {
return nodeInfo;
});
var getModuleInfo = sinon.stub(registry,"getModuleInfo").callsFake(function(md) {
var getModuleInfo = sinon.stub(registry,"getModuleInfo",function(md) {
return {nodes:[]};
});
var res = {
@@ -303,7 +303,7 @@ describe('nodes/registry/installer', function() {
p.catch((err)=>{});
execResponse = p;
sinon.stub(fs,"statSync").callsFake(function(fn) { return {}; });
sinon.stub(fs,"statSync", function(fn) { return {}; });
installer.uninstallModule("this_wont_exist").then(function(info) {
info.should.eql(nodeInfo);

View File

@@ -46,8 +46,8 @@ describe("red/nodes/registry/loader",function() {
describe("#load",function() {
it("load empty set without settings available", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return {};}));
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};}));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return false;}}});
loader.load(true).then(function() {
localfilesystem.getNodeFiles.called.should.be.true();
@@ -57,8 +57,8 @@ describe("red/nodes/registry/loader",function() {
})
});
it("load empty set with settings available triggers registery save", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return {};}));
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){ return {};}));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return {};}));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load(true).then(function() {
registry.saveNodeList.called.should.be.true();
@@ -69,7 +69,7 @@ describe("red/nodes/registry/loader",function() {
});
it("load core node files scanned by lfs - single node single file", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){
var result = {};
result["node-red"] = {
"name": "node-red",
@@ -85,10 +85,10 @@ describe("red/nodes/registry/loader",function() {
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return }));
stubs.push(sinon.stub(registry,"addModule", function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
@@ -126,7 +126,7 @@ describe("red/nodes/registry/loader",function() {
});
it("load core node files scanned by lfs - ignore html if disableEditor true", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){
var result = {};
result["node-red"] = {
"name": "node-red",
@@ -142,10 +142,10 @@ describe("red/nodes/registry/loader",function() {
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return }));
stubs.push(sinon.stub(registry,"addModule", function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{disableEditor: true, available:function(){return true;}}});
@@ -190,7 +190,7 @@ describe("red/nodes/registry/loader",function() {
});
it("load core node files scanned by lfs - multiple nodes single file", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){
var result = {};
result["node-red"] = {
"name": "node-red",
@@ -206,10 +206,10 @@ describe("red/nodes/registry/loader",function() {
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return }));
stubs.push(sinon.stub(registry,"addModule", function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.load().then(function(result) {
@@ -250,7 +250,7 @@ describe("red/nodes/registry/loader",function() {
it("load core node files scanned by lfs - node with promise", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){
var result = {};
result["node-red"] = {
"name": "node-red",
@@ -266,10 +266,10 @@ describe("red/nodes/registry/loader",function() {
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return }));
stubs.push(sinon.stub(registry,"addModule", function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
@@ -308,7 +308,7 @@ describe("red/nodes/registry/loader",function() {
it("load core node files scanned by lfs - node with rejecting promise", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){
var result = {};
result["node-red"] = {
"name": "node-red",
@@ -324,10 +324,10 @@ describe("red/nodes/registry/loader",function() {
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return }));
stubs.push(sinon.stub(registry,"addModule", function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
@@ -362,7 +362,7 @@ describe("red/nodes/registry/loader",function() {
});
it("load core node files scanned by lfs - missing file", function(done) {
stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){
var result = {};
result["node-red"] = {
"name": "node-red",
@@ -378,10 +378,10 @@ describe("red/nodes/registry/loader",function() {
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return }));
stubs.push(sinon.stub(registry,"addModule", function(){ return }));
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
@@ -416,7 +416,7 @@ describe("red/nodes/registry/loader",function() {
// it("load core node files scanned by lfs - missing html file", function(done) {
// // This is now an okay situation
// stubs.push(sinon.stub(localfilesystem,"getNodeFiles").callsFake(function(){
// stubs.push(sinon.stub(localfilesystem,"getNodeFiles", function(){
// var result = {};
// result["node-red"] = {
// "name": "node-red",
@@ -432,10 +432,10 @@ describe("red/nodes/registry/loader",function() {
// return result;
// }));
//
// stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return }));
// stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
// stubs.push(sinon.stub(registry,"saveNodeList", function(){ return }));
// stubs.push(sinon.stub(registry,"addModule", function(){ return }));
// // This module isn't already loaded
// stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
// stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
//
// stubs.push(sinon.stub(nodes,"registerType"));
// loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
@@ -481,7 +481,7 @@ describe("red/nodes/registry/loader",function() {
});
it("returns rejected error if module already loaded", function(done) {
stubs.push(sinon.stub(registry,"getModuleInfo").callsFake(function(){return{}}));
stubs.push(sinon.stub(registry,"getModuleInfo",function(){return{}}));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.addModule("test-module").catch(function(err) {
@@ -490,8 +490,8 @@ describe("red/nodes/registry/loader",function() {
});
});
it("returns rejected error if module not found", function(done) {
stubs.push(sinon.stub(registry,"getModuleInfo").callsFake(function(){return null}));
stubs.push(sinon.stub(localfilesystem,"getModuleFiles").callsFake(function() {
stubs.push(sinon.stub(registry,"getModuleInfo",function(){return null}));
stubs.push(sinon.stub(localfilesystem,"getModuleFiles",function() {
throw new Error("failure");
}));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
@@ -504,9 +504,9 @@ describe("red/nodes/registry/loader",function() {
it("loads module by name", function(done) {
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getModuleInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(localfilesystem,"getModuleFiles").callsFake(function(){
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(registry,"getModuleInfo",function(){ return null; }));
stubs.push(sinon.stub(localfilesystem,"getModuleFiles", function(){
var result = {};
result["TestNodeModule"] = {
"name": "TestNodeModule",
@@ -523,8 +523,8 @@ describe("red/nodes/registry/loader",function() {
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return "a node list" }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" }));
stubs.push(sinon.stub(registry,"addModule", function(){ return }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({nodes:nodes,log:{info:function(){},_:function(){}},settings:{available:function(){return true;}}});
loader.addModule("TestNodeModule").then(function(result) {
@@ -560,9 +560,9 @@ describe("red/nodes/registry/loader",function() {
it("skips module that fails version check", function(done) {
// This module isn't already loaded
stubs.push(sinon.stub(registry,"getNodeInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(registry,"getModuleInfo").callsFake(function(){ return null; }));
stubs.push(sinon.stub(localfilesystem,"getModuleFiles").callsFake(function(){
stubs.push(sinon.stub(registry,"getNodeInfo", function(){ return null; }));
stubs.push(sinon.stub(registry,"getModuleInfo",function(){ return null; }));
stubs.push(sinon.stub(localfilesystem,"getModuleFiles", function(){
var result = {};
result["TestNodeModule"] = {
"name": "TestNodeModule",
@@ -580,8 +580,8 @@ describe("red/nodes/registry/loader",function() {
return result;
}));
stubs.push(sinon.stub(registry,"saveNodeList").callsFake(function(){ return "a node list" }));
stubs.push(sinon.stub(registry,"addModule").callsFake(function(){ return }));
stubs.push(sinon.stub(registry,"saveNodeList", function(){ return "a node list" }));
stubs.push(sinon.stub(registry,"addModule", function(){ return }));
stubs.push(sinon.stub(nodes,"registerType"));
loader.init({log:{"_":function(){},warn:function(){}},nodes:nodes,version: function() { return "0.12.0"}, settings:{available:function(){return true;}}});
loader.addModule("TestNodeModule").then(function(result) {
@@ -643,7 +643,7 @@ describe("red/nodes/registry/loader",function() {
},"en").should.eql("foo");
});
it("loads help, caching result", function() {
stubs.push(sinon.stub(fs,"readFileSync").callsFake(function(path) {
stubs.push(sinon.stub(fs,"readFileSync", function(path) {
return 'bar';
}))
var node = {
@@ -660,7 +660,7 @@ describe("red/nodes/registry/loader",function() {
fs.readFileSync.calledOnce.should.be.true();
});
it("loads help, defaulting to en-US content", function() {
stubs.push(sinon.stub(fs,"readFileSync").callsFake(function(path) {
stubs.push(sinon.stub(fs,"readFileSync", function(path) {
throw new Error("not found");
}))
var node = {
@@ -677,7 +677,7 @@ describe("red/nodes/registry/loader",function() {
fs.readFileSync.calledOnce.should.be.true();
});
it("loads help, defaulting to en-US content for extra nodes", function() {
stubs.push(sinon.stub(fs,"readFileSync").callsFake(function(path) {
stubs.push(sinon.stub(fs,"readFileSync", function(path) {
if (path.indexOf("en-US") >= 0) {
return 'bar';
}
@@ -698,7 +698,7 @@ describe("red/nodes/registry/loader",function() {
fs.readFileSync.calledTwice.should.be.true();
});
it("fails to load en-US help content", function() {
stubs.push(sinon.stub(fs,"readFileSync").callsFake(function(path) {
stubs.push(sinon.stub(fs,"readFileSync", function(path) {
throw new Error("not found");
}));
var node = {

View File

@@ -30,7 +30,7 @@ var i18n = NR_TEST_UTILS.require("@node-red/util").i18n;
describe("red/nodes/registry/localfilesystem",function() {
beforeEach(function() {
stubs.push(sinon.stub(i18n,"registerMessageCatalog").callsFake(function() { return Promise.resolve(); }));
stubs.push(sinon.stub(i18n,"registerMessageCatalog", function() { return Promise.resolve(); }));
})
var stubs = [];
@@ -131,7 +131,7 @@ describe("red/nodes/registry/localfilesystem",function() {
});
it("Finds nodes module path",function(done) {
var _join = path.join;
stubs.push(sinon.stub(path,"join").callsFake(function() {
stubs.push(sinon.stub(path,"join",function() {
if (arguments[0] == resourcesDir) {
// This stops the module tree scan from going any higher
// up the tree than resourcesDir.
@@ -206,7 +206,7 @@ describe("red/nodes/registry/localfilesystem",function() {
describe("#getModuleFiles",function() {
it("gets a nodes module files",function(done) {
var _join = path.join;
stubs.push(sinon.stub(path,"join").callsFake(function() {
stubs.push(sinon.stub(path,"join",function() {
if (arguments[0] == resourcesDir) {
// This stops the module tree scan from going any higher
// up the tree than resourcesDir.
@@ -232,7 +232,7 @@ describe("red/nodes/registry/localfilesystem",function() {
});
it("throws an error if a node isn't found",function(done) {
var _join = path.join;
stubs.push(sinon.stub(path,"join").callsFake(function() {
stubs.push(sinon.stub(path,"join",function() {
if (arguments[0] == resourcesDir) {
// This stops the module tree scan from going any higher
// up the tree than resourcesDir.
@@ -251,7 +251,7 @@ describe("red/nodes/registry/localfilesystem",function() {
it.skip("finds icon path directory");
it("scans icon files with a module file",function(done) {
var _join = path.join;
stubs.push(sinon.stub(path,"join").callsFake(function() {
stubs.push(sinon.stub(path,"join",function() {
if (arguments[0] == resourcesDir) {
// This stops the module tree scan from going any higher
// up the tree than resourcesDir.

View File

@@ -37,8 +37,8 @@ describe("red/nodes/registry/plugins",function() {
}
}
events.on("registry:plugin-added",handleEvent);
sinon.stub(registry,"getModule").callsFake(moduleId => modules[moduleId]);
sinon.stub(registry,"getModuleList").callsFake(() => modules)
sinon.stub(registry,"getModule", moduleId => modules[moduleId]);
sinon.stub(registry,"getModuleList", () => modules)
});
afterEach(function() {
events.removeListener("registry:plugin-added",handleEvent);

View File

@@ -31,8 +31,8 @@ describe("runtime-api/comms", function() {
}
var eventHandlers = {};
before(function(done) {
sinon.stub(events,"removeListener").callsFake(function() {})
sinon.stub(events,"on").callsFake(function(evt,handler) { eventHandlers[evt] = handler })
sinon.stub(events,"removeListener", function() {})
sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler })
comms.init({
log: {
trace: function(){}
@@ -97,8 +97,8 @@ describe("runtime-api/comms", function() {
}
}
before(function() {
sinon.stub(events,"removeListener").callsFake(function() {})
sinon.stub(events,"on").callsFake(function(evt,handler) { eventHandlers[evt] = handler })
sinon.stub(events,"removeListener", function() {})
sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler })
comms.init({
log: {
trace: function(){}
@@ -177,8 +177,8 @@ describe("runtime-api/comms", function() {
}
var eventHandlers = {};
before(function() {
sinon.stub(events,"removeListener").callsFake(function() {})
sinon.stub(events,"on").callsFake(function(evt,handler) { eventHandlers[evt] = handler })
sinon.stub(events,"removeListener", function() {})
sinon.stub(events,"on", function(evt,handler) { eventHandlers[evt] = handler })
comms.init({
log: {
trace: function(){}

View File

@@ -24,7 +24,7 @@ var index = NR_TEST_UTILS.require("@node-red/runtime/lib/api/index");
describe("runtime-api/index", function() {
before(function() {
["comms","flows","nodes","settings","library","projects"].forEach(n => {
sinon.stub(NR_TEST_UTILS.require(`@node-red/runtime/lib/api/${n}`),"init").callsFake(()=>{});
sinon.stub(NR_TEST_UTILS.require(`@node-red/runtime/lib/api/${n}`),"init",()=>{});
})
});
after(function() {

View File

@@ -217,7 +217,7 @@ describe("api/admin/nodes", function() {
app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,nodes.putSet);
app.get("/getIcons",nodes.getIcons);
app.delete("/nodes/:id",nodes.delete);
sinon.stub(apiUtil,"determineLangFromHeaders").callsFake(function() {
sinon.stub(apiUtil,"determineLangFromHeaders", function() {
return "en-US";
});
});

View File

@@ -173,7 +173,7 @@ describe('Flow', function() {
util.inherits(TestDoneNode,Node);
before(function() {
getType = sinon.stub(typeRegistry,"get").callsFake(function(type) {
getType = sinon.stub(typeRegistry,"get",function(type) {
if (type=="test") {
return TestNode;
} else if (type=="testError"){

View File

@@ -202,7 +202,7 @@ describe('Subflow', function() {
util.inherits(TestEnvNode,Node);
before(function() {
getType = sinon.stub(typeRegistry,"get").callsFake(function(type) {
getType = sinon.stub(typeRegistry,"get",function(type) {
if (type=="test") {
return TestNode;
} else if (type=="testError"){

View File

@@ -51,10 +51,10 @@ describe('flows/index', function() {
before(function() {
getType = sinon.stub(typeRegistry,"get").callsFake(function(type) {
getType = sinon.stub(typeRegistry,"get",function(type) {
return type.indexOf('missing') === -1;
});
checkFlowDependencies = sinon.stub(typeRegistry, "checkFlowDependencies").callsFake(async function(flow) {
checkFlowDependencies = sinon.stub(typeRegistry, "checkFlowDependencies", async function(flow) {
if (flow[0].id === "node-with-missing-modules") {
throw new Error("Missing module");
}
@@ -69,20 +69,20 @@ describe('flows/index', function() {
beforeEach(function() {
eventsOn = sinon.spy(events,"on");
credentialsClean = sinon.stub(credentials,"clean").callsFake(function(conf) {
credentialsClean = sinon.stub(credentials,"clean",function(conf) {
conf.forEach(function(n) {
delete n.credentials;
});
return Promise.resolve();
});
credentialsLoad = sinon.stub(credentials,"load").callsFake(function(creds) {
credentialsLoad = sinon.stub(credentials,"load",function(creds) {
if (creds && creds.hasOwnProperty("$") && creds['$'] === "fail") {
return Promise.reject("creds error");
}
return Promise.resolve();
});
credentialsAdd = sinon.stub(credentials,"add").callsFake(async function(id, conf){})
flowCreate = sinon.stub(Flow,"create").callsFake(function(parent, global, flow) {
credentialsAdd = sinon.stub(credentials,"add", async function(id, conf){})
flowCreate = sinon.stub(Flow,"create",function(parent, global, flow) {
var id;
if (typeof flow === 'undefined') {
flow = global;
@@ -551,7 +551,7 @@ describe('flows/index', function() {
describe('#checkTypeInUse', function() {
before(function() {
sinon.stub(typeRegistry,"getNodeInfo").callsFake(function(id) {
sinon.stub(typeRegistry,"getNodeInfo",function(id) {
if (id === 'unused-module') {
return {types:['one','two','three']}
} else {

View File

@@ -26,7 +26,7 @@ describe('flows/util', function() {
var getType;
before(function() {
getType = sinon.stub(typeRegistry,"get").callsFake(function(type) {
getType = sinon.stub(typeRegistry,"get",function(type) {
return type!=='missing';
});
});

View File

@@ -44,13 +44,13 @@ describe("runtime", function() {
delete process.env.NODE_RED_HOME;
});
function mockUtil(metrics) {
sinon.stub(log,"log").callsFake(function(){})
sinon.stub(log,"warn").callsFake(function(){})
sinon.stub(log,"info").callsFake(function(){})
sinon.stub(log,"trace").callsFake(function(){})
sinon.stub(log,"metric").callsFake(function(){ return !!metrics })
sinon.stub(log,"_").callsFake(function(){ return "abc"})
sinon.stub(i18n,"registerMessageCatalog").callsFake(function(){ return Promise.resolve()})
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();
@@ -63,9 +63,9 @@ describe("runtime", function() {
}
describe("init", function() {
beforeEach(function() {
sinon.stub(log,"init").callsFake(function() {});
sinon.stub(settings,"init").callsFake(function() {});
sinon.stub(redNodes,"init").callsFake(function() {})
sinon.stub(log,"init",function() {});
sinon.stub(settings,"init",function() {});
sinon.stub(redNodes,"init",function() {})
mockUtil();
});
afterEach(function() {
@@ -103,13 +103,13 @@ describe("runtime", function() {
var redNodesLoadContextsPlugin;
beforeEach(function() {
storageInit = sinon.stub(storage,"init").callsFake(function(settings) {return Promise.resolve();});
redNodesInit = sinon.stub(redNodes,"init").callsFake(function() {});
redNodesLoad = sinon.stub(redNodes,"load").callsFake(function() {return Promise.resolve()});
redNodesCleanModuleList = sinon.stub(redNodes,"cleanModuleList").callsFake(function(){});
redNodesLoadFlows = sinon.stub(redNodes,"loadFlows").callsFake(function() {return Promise.resolve()});
redNodesStartFlows = sinon.stub(redNodes,"startFlows").callsFake(function() {});
redNodesLoadContextsPlugin = sinon.stub(redNodes,"loadContextsPlugin").callsFake(function() {return Promise.resolve()});
storageInit = sinon.stub(storage,"init",function(settings) {return Promise.resolve();});
redNodesInit = sinon.stub(redNodes,"init", function() {});
redNodesLoad = sinon.stub(redNodes,"load", function() {return Promise.resolve()});
redNodesCleanModuleList = sinon.stub(redNodes,"cleanModuleList",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()});
mockUtil();
});
afterEach(function() {
@@ -124,7 +124,7 @@ describe("runtime", function() {
unmockUtil();
});
it("reports errored/missing modules",function(done) {
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList").callsFake(function(cb) {
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function(cb) {
return [
{ err:"errored",name:"errName" }, // error
{ module:"module",enabled:true,loaded:false,types:["typeA","typeB"]} // missing
@@ -151,7 +151,7 @@ describe("runtime", function() {
}).catch(err=>{done(err)});
});
it("initiates load of missing modules",function(done) {
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList").callsFake(function(cb) {
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function(cb) {
return [
{ err:"errored",name:"errName" }, // error
{ err:"errored",name:"errName" }, // error
@@ -159,7 +159,7 @@ describe("runtime", function() {
{ module:"node-red",enabled:true,loaded:false,types:["typeC","typeD"]} // missing
].filter(cb);
});
var serverInstallModule = sinon.stub(redNodes,"installModule").callsFake(function(name) { return Promise.resolve({nodes:[]});});
var serverInstallModule = sinon.stub(redNodes,"installModule",function(name) { return Promise.resolve({nodes:[]});});
runtime.init({testSettings: true, autoInstallModules:true, httpAdminRoot:"/", load:function() { return Promise.resolve();}});
sinon.stub(console,"log");
runtime.start().then(function() {
@@ -181,7 +181,7 @@ describe("runtime", function() {
}).catch(err=>{done(err)});
});
it("reports errored modules when verbose is enabled",function(done) {
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList").callsFake(function(cb) {
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function(cb) {
return [
{ err:"errored",name:"errName" } // error
].filter(cb);
@@ -201,8 +201,8 @@ describe("runtime", function() {
});
it("reports runtime metrics",function(done) {
var stopFlows = sinon.stub(redNodes,"stopFlows").callsFake(function() { return Promise.resolve();} );
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList").callsFake(function() {return []});
var stopFlows = sinon.stub(redNodes,"stopFlows",function() { return Promise.resolve();} );
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function() {return []});
unmockUtil();
mockUtil(true);
runtime.init(
@@ -233,8 +233,8 @@ describe("runtime", function() {
});
it("stops components", function(done) {
var stopFlows = sinon.stub(redNodes,"stopFlows").callsFake(function() { return Promise.resolve();} );
var closeContextsPlugin = sinon.stub(redNodes,"closeContextsPlugin").callsFake(function() { return Promise.resolve();} );
var stopFlows = sinon.stub(redNodes,"stopFlows",function() { return Promise.resolve();} );
var closeContextsPlugin = sinon.stub(redNodes,"closeContextsPlugin",function() { return Promise.resolve();} );
runtime.stop().then(function(){
stopFlows.called.should.be.true();
closeContextsPlugin.called.should.be.true();

View File

@@ -65,7 +65,7 @@ describe("runtime/library/examples", function() {
}
}
});
sinon.stub(fs,"readFile").callsFake(function(path,opts,callback) {
sinon.stub(fs,"readFile", function(path,opts,callback) {
if (path === "/tmp/test-module/abc") {
callback(null,"Example flow result");
} else if (path === "/tmp/@scope/test-module/abc") {

View File

@@ -37,14 +37,14 @@ var mockLog = {
describe("runtime/library", function() {
before(function() {
sinon.stub(localLibrary,"getEntry").callsFake(function(type,path) {
sinon.stub(localLibrary,"getEntry",function(type,path) {
return Promise.resolve({
library: "local",
type:type,
path:path
})
});
sinon.stub(localLibrary,"saveEntry").callsFake(function(type, path, meta, body) {
sinon.stub(localLibrary,"saveEntry",function(type, path, meta, body) {
return Promise.resolve({
library: "local",
type:type,
@@ -53,7 +53,7 @@ describe("runtime/library", function() {
body:body
})
});
sinon.stub(examplesLibrary,"getEntry").callsFake(function(type,path) {
sinon.stub(examplesLibrary,"getEntry",function(type,path) {
return Promise.resolve({
library: "_examples_",
type:type,

View File

@@ -151,7 +151,7 @@ describe('Node', function() {
it('handles thrown errors', function(done) {
var n = new RedNode({id:'123',type:'abc'});
sinon.stub(n,"error").callsFake(function(err,msg) {});
sinon.stub(n,"error",function(err,msg) {});
var message = {payload:"hello world"};
n.on('input',function(msg) {
throw new Error("test error");
@@ -271,7 +271,7 @@ describe('Node', function() {
});
it('logs error if callback provides error', function(done) {
var n = new RedNode({id:'123',type:'abc'});
sinon.stub(n,"error").callsFake(function(err,msg) {});
sinon.stub(n,"error",function(err,msg) {});
var message = {payload:"hello world"};
n.on('input',function(msg, nodeSend, nodeDone) {
@@ -723,7 +723,7 @@ describe('Node', function() {
it('produces a metric message', function(done) {
var n = new RedNode({id:'123',type:'abc'});
var loginfo = {};
sinon.stub(Log, 'log').callsFake(function(msg) {
sinon.stub(Log, 'log', function(msg) {
loginfo = msg;
});
var msg = {payload:"foo", _msgid:"987654321"};
@@ -739,7 +739,7 @@ describe('Node', function() {
it('returns metric value if eventname undefined', function(done) {
var n = new RedNode({id:'123',type:'abc'});
var loginfo = {};
sinon.stub(Log, 'log').callsFake(function(msg) {
sinon.stub(Log, 'log', function(msg) {
loginfo = msg;
});
var msg = {payload:"foo", _msgid:"987654321"};
@@ -751,7 +751,7 @@ describe('Node', function() {
it('returns not defined if eventname defined', function(done) {
var n = new RedNode({id:'123',type:'abc'});
var loginfo = {};
sinon.stub(Log, 'log').callsFake(function(msg) {
sinon.stub(Log, 'log', function(msg) {
loginfo = msg;
});
var msg = {payload:"foo", _msgid:"987654321"};

View File

@@ -320,7 +320,7 @@ describe('context', function() {
describe('external context storage',function() {
var resourcesDir = path.resolve(path.join(__dirname,"..","resources","context"));
var sandbox = sinon.createSandbox();
var sandbox = sinon.sandbox.create();
var stubGet = sandbox.stub();
var stubSet = sandbox.stub();
var stubKeys = sandbox.stub();

View File

@@ -177,15 +177,15 @@ describe("red/nodes/index", function() {
var userDir = path.join(__dirname,".testUserHome");
before(function(done) {
sinon.stub(log,"log").callsFake(function(){});
sinon.stub(log,"log",function(){});
fs.remove(userDir,function(err) {
fs.mkdir(userDir,function() {
sinon.stub(index, 'load').callsFake(function() {
sinon.stub(index, 'load', function() {
return new Promise(function(resolve,reject){
resolve([]);
});
});
sinon.stub(localfilesystem, 'getCredentials').callsFake(function() {
sinon.stub(localfilesystem, 'getCredentials', function() {
return new Promise(function(resolve,reject) {
resolve({"tab1":{"b":1,"c":2}});
});
@@ -271,7 +271,7 @@ describe("red/nodes/index", function() {
var randomNodeInfo = {id:"5678",types:["random"]};
beforeEach(function() {
sinon.stub(registry,"getNodeInfo").callsFake(function(id) {
sinon.stub(registry,"getNodeInfo",function(id) {
if (id == "test") {
return {id:"1234",types:["test"]};
} else if (id == "doesnotexist") {
@@ -280,7 +280,7 @@ describe("red/nodes/index", function() {
return randomNodeInfo;
}
});
sinon.stub(registry,"disableNode").callsFake(function(id) {
sinon.stub(registry,"disableNode",function(id) {
return Promise.resolve(randomNodeInfo);
});
});
@@ -343,7 +343,7 @@ describe("red/nodes/index", function() {
};
before(function() {
sinon.stub(registry,"getNodeInfo").callsFake(function(id) {
sinon.stub(registry,"getNodeInfo",function(id) {
if (id == "node-red/foo") {
return {id:"1234",types:["test"]};
} else if (id == "doesnotexist") {
@@ -352,7 +352,7 @@ describe("red/nodes/index", function() {
return randomNodeInfo;
}
});
sinon.stub(registry,"getModuleInfo").callsFake(function(module) {
sinon.stub(registry,"getModuleInfo",function(module) {
if (module == "node-red") {
return {nodes:[{name:"foo"}]};
} else if (module == "doesnotexist") {
@@ -361,7 +361,7 @@ describe("red/nodes/index", function() {
return randomModuleInfo;
}
});
sinon.stub(registry,"removeModule").callsFake(function(id) {
sinon.stub(registry,"removeModule",function(id) {
return randomModuleInfo;
});
});

View File

@@ -313,7 +313,7 @@ describe('storage/localfilesystem', function() {
var flowFile = 'test.json';
var flowFilePath = path.join(userDir,flowFile);
localfilesystem.init({userDir:userDir, flowFile:flowFilePath,getUserSettings: () => {{}}}, mockRuntime).then(function() {
sinon.stub(fs,"fsync").callsFake(function(fd, cb) {
sinon.stub(fs,"fsync", function(fd, cb) {
cb(new Error());
});
sinon.spy(log,"warn");

View File

@@ -34,7 +34,7 @@ describe("localfilesystem/projects/ssh/keygen", function() {
var command;
var args;
var opts;
sinon.stub(child_process,"spawn").callsFake(function(_command,_args,_opts) {
sinon.stub(child_process,"spawn", function(_command,_args,_opts) {
_command = command;
_args = args;
_opts = opts;

View File

@@ -41,7 +41,7 @@ describe("runtime/exec", function() {
mockProcess = new EventEmitter();
mockProcess.stdout = new EventEmitter();
mockProcess.stderr = new EventEmitter();
sinon.stub(child_process,'spawn').callsFake(function(command,args,options) {
sinon.stub(child_process,'spawn',function(command,args,options) {
mockProcess._args = {command,args,options};
return mockProcess;
});

View File

@@ -24,7 +24,7 @@ var log = NR_TEST_UTILS.require("@node-red/util").log;
describe("@node-red/util/log", function() {
beforeEach(function () {
var spy = sinon.stub(util, 'log').callsFake(function(arg){});
var spy = sinon.stub(util, 'log', function(arg){});
var settings = {logging: { console: { level: 'metric', metrics: true } } };
log.init(settings);
});

View File

@@ -33,9 +33,9 @@ describe("red/red", function() {
// describe("check build", function() {
// beforeEach(function() {
// sinon.stub(runtime,"init").callsFake(function() {});
// sinon.stub(api,"init").callsFake(function() {});
// // sinon.stub(RED,"version").callsFake(function() { return "version";});
// sinon.stub(runtime,"init",function() {});
// sinon.stub(api,"init",function() {});
// // sinon.stub(RED,"version",function() { return "version";});
// });
// afterEach(function() {
// runtime.init.restore();
@@ -44,7 +44,7 @@ describe("red/red", function() {
// // RED.version.restore();
// });
// it.skip('warns if build has not been run',function() {
// sinon.stub(fs,"statSync").callsFake(function() { throw new Error();});
// sinon.stub(fs,"statSync",function() { throw new Error();});
//
// /*jshint immed: false */
// (function() {
@@ -52,7 +52,7 @@ describe("red/red", function() {
// }).should.throw("Node-RED not built");
// });
// it('passed if build has been run',function() {
// sinon.stub(fs,"statSync").callsFake(function() { });
// sinon.stub(fs,"statSync",function() { });
// RED.init({},{});
// });
// });