Merge branch 'master' into runtime-api

This commit is contained in:
Nick O'Leary
2018-07-29 23:47:19 +01:00
147 changed files with 12297 additions and 2046 deletions

View File

@@ -27,12 +27,34 @@ util.inherits(injectNode, nodePage);
var payloadType = {
"flow": 1,
"global": 2,
"string": 3,
"str": 3,
"num": 4,
"bool": 5,
"json": 6,
"bin": 7,
"date": 8,
"env": 9,
};
var timeType = {
"none": 1,
"interval": 2,
"intervalBetweenTimes": 3,
"atASpecificTime": 4,
};
var timeType = {
"none": 1,
"interval": 2,
"intervalBetweenTimes": 3,
"atASpecificTime": 4,
};
var timeType = {
"none": 1,
"interval": 2,
"intervalBetweenTimes": 3,
"atASpecificTime": 4,
};
injectNode.prototype.setPayload = function(type, value) {
@@ -41,12 +63,27 @@ injectNode.prototype.setPayload = function(type, value) {
// Select a payload type.
var payloadTypeXPath = '//*[@class="red-ui-typedInput-options"]/a[' + payloadType[type] + ']';
browser.clickWithWait(payloadTypeXPath);
// Input a value.
browser.setValue('#node-input-payload', value);
if (value) {
// Input a value.
browser.setValue('//*[@class="red-ui-typedInput-input"]/input', value);
}
}
injectNode.prototype.setTopic = function(value) {
browser.setValue('#node-input-topic', value);
}
injectNode.prototype.setOnce = function(value) {
browser.clickWithWait('#node-input-once');
}
injectNode.prototype.setTimeType = function(type) {
var timeTypeXPath = '//*[@id="inject-time-type-select"]/option[' + timeType[type] + ']';
browser.clickWithWait(timeTypeXPath);
}
injectNode.prototype.setRepeat = function(sec) {
browser.setValue('#inject-time-interval-count', sec);
}
module.exports = injectNode;

View File

@@ -24,4 +24,23 @@ function debugNode(id) {
util.inherits(debugNode, nodePage);
var target = {
"msg": 1,
"full": 2
};
debugNode.prototype.setTarget = function(type, value) {
// Open a payload type list.
browser.clickWithWait('//*[contains(@class, "red-ui-typedInput-container")]/button');
// Select a payload type.
var xPath = '/html/body/div[11]/a[' + target[type] + ']';
browser.clickWithWait(xPath);
if (value) {
browser.clickWithWait('//*[contains(@class, "red-ui-typedInput-input")]/input');
browser.keys(['Control', 'a', 'Control']);
browser.keys(['Delete']);
browser.setValue('//*[contains(@class, "red-ui-typedInput-input")]/input', value);
}
}
module.exports = debugNode;

View File

@@ -0,0 +1,35 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var util = require("util");
var nodePage = require("../../node_page");
function functionNode(id) {
nodePage.call(this, id);
}
util.inherits(functionNode, nodePage);
functionNode.prototype.setCode = function(value) {
browser.click('#node-input-func-editor');
browser.keys(['Control', 'Home', 'Control']);
for (var i=0; i<value.length; i++) {
browser.keys([value.substr(i, 1)]);
}
}
module.exports = functionNode;

View File

@@ -0,0 +1,55 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var util = require("util");
var nodePage = require("../../node_page");
function templateNode(id) {
nodePage.call(this, id);
}
util.inherits(templateNode, nodePage);
var syntaxType = {
"mustache": 1,
"plain": 2
};
templateNode.prototype.setSyntax = function(type) {
// Open a method type list.
browser.clickWithWait('#node-input-syntax');
// Select a method type.
var syntaxTypeXPath = '//*[@id="node-input-syntax"]/option[' + syntaxType[type] + ']';
browser.clickWithWait(syntaxTypeXPath);
}
templateNode.prototype.setFormat = function(type) {
browser.selectByValue('#node-input-format', type);
}
templateNode.prototype.setTemplate = function(value) {
browser.click('#node-input-template-editor');
browser.keys(['Control', 'a', 'Control']); // call twice to release the keys.
// Need to add a character one by one since some words such as 'Control' are treated as a special word.
for (var i=0; i<value.length; i++) {
browser.keys([value.charAt(i)]);
}
browser.keys(['Control', 'Shift', 'End', 'Shift', 'Control']);
browser.keys(['Delete']);
}
module.exports = templateNode;

View File

@@ -0,0 +1,51 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var util = require("util");
var nodePage = require("../../node_page");
function httpinNode(id) {
nodePage.call(this, id);
}
function setMethod(type) {
browser.selectByValue('#node-input-method', type);
}
util.inherits(httpinNode, nodePage);
var methodType = {
"get": 1,
"post": 2,
"put": 3,
"delete": 4,
"patch": 5,
};
httpinNode.prototype.setMethod = function(type) {
// Open a method type list.
browser.clickWithWait('#node-input-method');
// Select a method type.
var methodTypeXPath = '//*[@id="node-input-method"]/option[' + methodType[type] + ']';
browser.clickWithWait(methodTypeXPath);
}
httpinNode.prototype.setUrl = function(value) {
browser.setValue('#node-input-url', value);
}
module.exports = httpinNode;

View File

@@ -0,0 +1,59 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var util = require("util");
var nodePage = require("../../node_page");
function httpRequestNode(id) {
nodePage.call(this, id);
}
util.inherits(httpRequestNode, nodePage);
var methodType = {
"get": 1,
"post": 2,
"put": 3,
"delete": 4,
"setByMsgMethod": 5,
};
var retType = {
"txt": 1,
"bin": 2,
"obj": 3,
};
httpRequestNode.prototype.setUrl = function(value) {
browser.setValue('#node-input-url', value);
}
httpRequestNode.prototype.setMethod = function(type) {
// Open a method type list.
browser.clickWithWait('#node-input-method');
// Select a method type.
var methodTypeXPath = '//*[@id="node-input-method"]/option[' + methodType[type] + ']';
browser.clickWithWait(methodTypeXPath);
}
httpRequestNode.prototype.setRet = function(type) {
browser.clickWithWait('#node-input-ret');
var retTypeXPath = '//*[@id="node-input-ret"]/option[' + retType[type] + ']';
browser.clickWithWait(retTypeXPath);
}
module.exports = httpRequestNode;

View File

@@ -0,0 +1,27 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var util = require("util");
var nodePage = require("../../node_page");
function httpResponseNode(id) {
nodePage.call(this, id);
}
util.inherits(httpResponseNode, nodePage);
module.exports = httpResponseNode;

View File

@@ -24,14 +24,58 @@ function changeNode(id) {
util.inherits(changeNode, nodePage);
var tType = {
"set": 1,
"change": 2,
"delete": 3,
"move": 4,
};
var totType = {
"msg": 1,
"flow": 2,
"global": 3,
"str": 4,
"num": 5,
"bool": 6,
"json": 7,
"bin": 8,
"date": 9,
"jsonata": 10,
};
var ptType = {
"msg": 1,
"flow": 2,
"global": 3,
};
function setT(rule, index) {
browser.selectByValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[1]/select', rule);
}
changeNode.prototype.ruleSet = function(to, index) {
// It is better to create a function whose input value is the object type in the future,
changeNode.prototype.ruleSet = function(p, pt, to, tot, index) {
index = index ? index : 1;
setT("set", index);
browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[2]/div[2]/div/input', to);
if (pt) {
browser.clickWithWait('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[1]/div/button[1]');
var num = 5 * index + 6;
var ptXPath = '/html/body/div[' + num + ']/a[' + ptType[pt] + ']';
browser.clickWithWait(ptXPath);
}
if (p) {
browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[1]/div/div/input', p);
}
if (tot) {
browser.clickWithWait('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[2]/div[2]/button[1]');
var num = 5 * index + 7;
var totXPath = '/html/body/div[' + num + ']/a[' + totType[tot] + ']';
browser.clickWithWait(totXPath);
}
if (to) {
browser.setValue('//*[@id="node-input-rule-container"]/li[' + index + ']/div/div[2]/div[2]/div/input' , to);
}
}
changeNode.prototype.ruleDelete = function(index) {

View File

@@ -0,0 +1,31 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var util = require("util");
var nodePage = require("../../node_page");
function htmlNode(id) {
nodePage.call(this, id);
}
util.inherits(htmlNode, nodePage);
htmlNode.prototype.setTag = function(value) {
browser.setValue('#node-input-tag', value);
}
module.exports = htmlNode;

View File

@@ -0,0 +1,44 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var util = require("util");
var nodePage = require("../../node_page");
function fileinNode(id) {
nodePage.call(this, id);
}
util.inherits(fileinNode, nodePage);
var formatType = {
"utf8": 1,
"lines": 2,
"": 3, // a single Buffer object
"stream": 4
};
fileinNode.prototype.setFilename = function(value) {
browser.setValue('#node-input-filename', value);
}
fileinNode.prototype.setFormat = function(type) {
browser.clickWithWait('#node-input-format');
var formatTypeXPath = '//*[@id="node-input-format"]/option[' + formatType[type] + ']';
browser.clickWithWait(formatTypeXPath);
}
module.exports = fileinNode;

View File

@@ -16,17 +16,33 @@
var injectNode = require('./core/core/20-inject_page');
var debugNode = require('./core/core/58-debug_page');
var templateNode = require('./core/core/80-template_page');
var functionNode = require('./core/core/80-function_page');
var httpinNode = require('./core/io/21-httpin_page');
var httpResponseNode = require('./core/io/21-httpresponse_page');
var changeNode = require('./core/logic/15-change_page');
var rangeNode = require('./core/logic/16-range_page');
var httpRequestNode = require('./core/io/21-httprequest_page');
var htmlNode = require('./core/parsers/70-HTML_page');
var fileinNode = require('./core/storage/50-filein_page');
var nodeCatalog = {
// input
"inject": injectNode,
"httpin": httpinNode,
// output
"debug": debugNode,
"httpResponse": httpResponseNode,
// function
"function": functionNode,
"template": templateNode,
"change": changeNode,
"range": rangeNode,
"httpRequest": httpRequestNode,
"html": htmlNode,
// storage
"filein": fileinNode,
}
function create(type, id) {

View File

@@ -0,0 +1,23 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
function pause(msec) {
browser.pause(msec);
}
module.exports = {
pause: pause,
};

View File

@@ -15,7 +15,7 @@
**/
function open() {
browser.clickWithWait('#red-ui-tab-debug');
browser.clickWithWait('#red-ui-tab-debug-link-button');
}
function getMessage(index) {

View File

@@ -17,11 +17,19 @@
var idMap = {
// input
"inject": "#palette_node_inject",
"httpin": "#palette_node_http_in",
// output
"debug": "#palette_node_debug",
"httpResponse": "#palette_node_http_response",
// function
"function": "#palette_node_function",
"template": "#palette_node_template",
"change": "#palette_node_change",
"range": "#palette_node_range",
"httpRequest": "#palette_node_http_request",
"html": "#palette_node_html",
// storage
"filein": "#palette_node_file_in",
};
function getId(type) {

View File

@@ -36,6 +36,7 @@ function addNode(type, x, y) {
}
function deleteAllNodes() {
browser.click('.innerCanvas');
browser.keys(['Control', 'a', 'a', 'Control']); // call twice to release the keys.
browser.keys(['Delete']);
}

View File

@@ -0,0 +1,584 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var helper = require("../../editor_helper");
var debugTab = require('../../pageobjects/workspace/debugTab_page');
var workspace = require('../../pageobjects/workspace/workspace_page');
var nodeWidth = 200;
var nodeHeight = 100;
var httpNodeRoot = "/api";
// https://cookbook.nodered.org/
describe('cookbook', function() {
beforeEach(function() {
workspace.deleteAllNodes();
});
before(function() {
helper.startServer();
});
after(function() {
helper.stopServer();
});
describe('HTTP endpoints', function () {
it('create an HTTP endpoint', function () {
var httpinNode = workspace.addNode("httpin");
var templateNode = workspace.addNode("template", nodeWidth);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 2);
httpinNode.edit();
httpinNode.setMethod("get");
httpinNode.setUrl("/hello");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("<html>\n<head></head>\n<body>\n<h1>Hello World!</h1>\n</body>\n</html>");
templateNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNode = workspace.addNode("inject", 0, nodeHeight);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth, nodeHeight);
var debugNode = workspace.addNode("debug", nodeWidth * 2, nodeHeight);
httpRequestNode.edit();
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello');
httpRequestNode.setMethod("get");
httpRequestNode.clickOk();
injectNode.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().indexOf('Hello World!').should.not.eql(-1);
});
it('handle query parameters passed to an HTTP endpoint', function () {
var httpinNode = workspace.addNode("httpin");
var templateNode = workspace.addNode("template", nodeWidth);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 2);
httpinNode.edit();
httpinNode.setMethod("get");
httpinNode.setUrl("/hello-query");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("<html>\n<head></head>\n<body>\n<h1>Hello {{req.query.name}}!</h1>\n</body>\n</html>");
templateNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNode = workspace.addNode("inject", 0, nodeHeight);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth, nodeHeight);
var debugNode = workspace.addNode("debug", nodeWidth * 2, nodeHeight);
httpRequestNode.edit();
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello-query?name=Nick');
httpRequestNode.setMethod("get");
httpRequestNode.clickOk();
injectNode.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().indexOf('Hello Nick!').should.not.eql(-1);
});
it('handle url parameters in an HTTP endpoint', function () {
var httpinNode = workspace.addNode("httpin");
var templateNode = workspace.addNode("template", nodeWidth * 2);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 3);
httpinNode.edit();
httpinNode.setMethod("get");
httpinNode.setUrl("/hello-param/:name");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("<html>\n<head></head>\n<body>\n<h1>Hello {{req.params.name}}!</h1>\n</body>\n</html>");
templateNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNode = workspace.addNode("inject", 0, nodeHeight);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth, nodeHeight);
var debugNode = workspace.addNode("debug", nodeWidth * 2, nodeHeight);
httpRequestNode.edit();
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello-param/Dave');
httpRequestNode.setMethod("get");
httpRequestNode.clickOk();
injectNode.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().indexOf('Hello Dave!').should.not.eql(-1);
});
it('access HTTP request headers', function () {
var httpinNode = workspace.addNode("httpin");
var templateNode = workspace.addNode("template", nodeWidth * 1.5);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 2.5);
httpinNode.edit();
httpinNode.setMethod("get");
httpinNode.setUrl("/hello-headers");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("<html>\n<head></head>\n<body>\n<h1>User agent: {{req.headers.user-agent}}</h1>\n</body>\n</html>");
templateNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNode = workspace.addNode("inject", 0, nodeHeight);
var changeNode = workspace.addNode("change", nodeWidth, nodeHeight);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth * 2, nodeHeight);
var debugNode = workspace.addNode("debug", nodeWidth * 3, nodeHeight);
changeNode.edit();
changeNode.ruleSet("headers", "msg", "{\"user-agent\":\"Mozilla/5.0 (Windows NT 10.0; Win64; x64)\"}", "json");
changeNode.clickOk();
httpRequestNode.edit();
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello-headers');
httpRequestNode.setMethod("get");
httpRequestNode.clickOk();
injectNode.connect(changeNode);
changeNode.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().indexOf('Mozilla').should.not.eql(-1);
});
it('include data captured in another flow', function () {
var injectNodeTimestamp = workspace.addNode("inject");
var changeNodeStore = workspace.addNode("change", nodeWidth);
var httpinNode = workspace.addNode("httpin", 0, nodeHeight);
var changeNodeCopy = workspace.addNode("change", nodeWidth * 2, nodeHeight);
var templateNode = workspace.addNode("template", nodeWidth * 3, nodeHeight);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 4, nodeHeight);
injectNodeTimestamp.edit();
injectNodeTimestamp.setPayload("date");
injectNodeTimestamp.clickOk();
changeNodeStore.edit();
changeNodeStore.ruleSet("timestamp", "flow", "payload", "msg");
changeNodeStore.clickOk();
injectNodeTimestamp.connect(changeNodeStore);
httpinNode.edit();
httpinNode.setMethod("get");
httpinNode.setUrl("/hello-data");
httpinNode.clickOk();
changeNodeCopy.edit();
changeNodeCopy.ruleSet("timestamp", "msg", "timestamp", "flow");
changeNodeCopy.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("<html>\n<head></head>\n<body>\n<h1>Time: {{ timestamp }}</h1>\n</body>\n</html>");
templateNode.clickOk();
httpinNode.connect(changeNodeCopy);
changeNodeCopy.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNodeCheck = workspace.addNode("inject", 0, nodeHeight * 2);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth, nodeHeight * 2);
var debugNode = workspace.addNode("debug", nodeWidth * 2, nodeHeight * 2);
httpRequestNode.edit();
httpRequestNode.setMethod("get");
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello-data');
httpRequestNode.clickOk();
injectNodeCheck.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNodeTimestamp.clickLeftButton();
injectNodeCheck.clickLeftButton();
var index = debugTab.getMessage().indexOf('Time: ') + 6;
debugTab.getMessage().substring(index, index + 13).should.within(1500000000000, 3000000000000);
});
it('serve JSON content', function () {
var httpinNode = workspace.addNode("httpin");
var templateNode = workspace.addNode("template", nodeWidth);
var changeNode = workspace.addNode("change", nodeWidth * 2);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 3);
httpinNode.edit();
httpinNode.setMethod("get");
httpinNode.setUrl("/hello-json");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("{ \"Hello\": \"World\" }");
templateNode.clickOk();
changeNode.edit();
changeNode.ruleSet("headers", "msg", "{}", "json", "1");
changeNode.addRule();
changeNode.ruleSet("headers.content-type", "msg", "application/json", "str", "2");
changeNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(changeNode);
changeNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNode = workspace.addNode("inject", 0, nodeHeight);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth, nodeHeight);
var debugNode = workspace.addNode("debug", nodeWidth * 2, nodeHeight);
httpRequestNode.edit();
httpRequestNode.setMethod("get");
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello-json');
httpRequestNode.clickOk();
debugNode.edit();
debugNode.setTarget("msg", "headers");
debugNode.clickOk();
injectNode.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
var message = debugTab.getMessage();
message[1].indexOf('application/json').should.not.eql(-1);
});
it('serve a local file', function () {
var httpinNode = workspace.addNode("httpin");
var fileinNode = workspace.addNode("filein", nodeWidth);
var changeNode = workspace.addNode("change", nodeWidth * 2, nodeHeight);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 3.5, nodeHeight);
httpinNode.edit();
httpinNode.setMethod("get");
httpinNode.setUrl("/hello-file");
httpinNode.clickOk();
fileinNode.edit();
fileinNode.setFilename("test/resources/file-in-node/test.txt");
fileinNode.setFormat("");
fileinNode.clickOk();
changeNode.edit();
changeNode.ruleSet("headers", "msg", "{}", "json");
changeNode.addRule();
changeNode.ruleSet("headers.content-type", "msg", "text/plain", "str", "2");
changeNode.clickOk();
httpinNode.connect(fileinNode);
fileinNode.connect(changeNode);
changeNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNode = workspace.addNode("inject", 0, nodeHeight * 2);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth, nodeHeight * 2);
var debugNode = workspace.addNode("debug", nodeWidth * 2, nodeHeight * 2);
httpRequestNode.edit();
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello-file');
httpRequestNode.setMethod("get");
httpRequestNode.clickOk();
injectNode.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().indexOf('Text file').should.not.eql(-1);
});
it('post raw data to a flow', function() {
var httpinNode = workspace.addNode("httpin");
var templateNode = workspace.addNode("template", nodeWidth * 2);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 3);
httpinNode.edit();
httpinNode.setMethod("post");
httpinNode.setUrl("/hello-raw");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("<html>\n<head></head>\n<body>\n<h1>Hello {{ payload }}!</h1>\n</body>\n</html>");
templateNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNode = workspace.addNode("inject", 0, nodeHeight);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth, nodeHeight);
var debugNode = workspace.addNode("debug", nodeWidth * 2, nodeHeight);
injectNode.edit()
injectNode.setPayload("str", "Nick");
injectNode.clickOk();
httpRequestNode.edit();
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello-raw');
httpRequestNode.setMethod("post");
httpRequestNode.clickOk();
injectNode.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().indexOf('Hello Nick!').should.not.eql(-1);
});
it('post form data to a flow', function () {
var httpinNode = workspace.addNode("httpin");
var templateNode = workspace.addNode("template", nodeWidth * 1.5);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 2.5);
httpinNode.edit();
httpinNode.setMethod("post");
httpinNode.setUrl("/hello-form");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("<html>\n<head></head>\n<body>\n<h1>Hello {{ payload.name }}!</h1>\n</body>\n</html>");
templateNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNode = workspace.addNode("inject", 0, nodeHeight);
var changeNode = workspace.addNode("change", nodeWidth, nodeHeight);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth * 2, nodeHeight);
var debugNode = workspace.addNode("debug", nodeWidth * 3, nodeHeight);
injectNode.edit()
injectNode.setPayload("str", "name=Nick");
injectNode.clickOk();
changeNode.edit();
changeNode.ruleSet("headers", "msg", "{\"content-type\":\"application/x-www-form-urlencoded\"}", "json");
changeNode.clickOk();
httpRequestNode.edit();
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello-form');
httpRequestNode.setMethod("post");
httpRequestNode.clickOk();
injectNode.connect(changeNode);
changeNode.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().indexOf('Hello Nick!').should.not.eql(-1);
});
it('post JSON data to a flow', function() {
var httpinNode = workspace.addNode("httpin");
var templateNode = workspace.addNode("template", nodeWidth * 2);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 3);
httpinNode.edit();
httpinNode.setMethod("post");
httpinNode.setUrl("/hello-json");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("<html>\n<head></head>\n<body>\n<h1>Hello {{ payload.name }}!</h1>\n</body>\n</html>");
templateNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation starts from here.
var injectNode = workspace.addNode("inject", 0, nodeHeight);
var changeNode = workspace.addNode("change", nodeWidth, nodeHeight);
var httpRequestNode = workspace.addNode("httpRequest", nodeWidth * 2, nodeHeight);
var debugNode = workspace.addNode("debug", nodeWidth * 3, nodeHeight);
injectNode.edit()
injectNode.setPayload("json", "{\"name\":\"Nick\"}");
injectNode.clickOk();
changeNode.edit();
changeNode.ruleSet("headers", "msg", "{\"content-type\":\"application/json\"}", "json");
changeNode.clickOk();
httpRequestNode.edit();
httpRequestNode.setUrl(helper.url() + httpNodeRoot + '/hello-json');
httpRequestNode.setMethod("post");
httpRequestNode.clickOk();
injectNode.connect(changeNode);
changeNode.connect(httpRequestNode);
httpRequestNode.connect(debugNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().indexOf('Hello Nick!').should.not.eql(-1);
});
it('work with cookies', function () {
this.timeout(60000);
var httpinNodeFormat = workspace.addNode("httpin");
var functionNodeFormat = workspace.addNode("function", nodeWidth * 1.5);
var templateNode = workspace.addNode("template", nodeWidth * 2.5);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 3.5);
var httpinNodeAdd = workspace.addNode("httpin", 0, nodeHeight);
var functionNodeAdd = workspace.addNode("function", nodeWidth * 1.5, nodeHeight);
var changeNode = workspace.addNode("change", nodeWidth * 2.5, nodeHeight * 1.5);
var httpinNodeClear = workspace.addNode("httpin", 0, nodeHeight * 2);
var functionNodeClear = workspace.addNode("function", nodeWidth * 1.5, nodeHeight * 2);
httpinNodeFormat.edit();
httpinNodeFormat.setMethod("get");
httpinNodeFormat.setUrl("/hello-cookie");
httpinNodeFormat.clickOk();
functionNodeFormat.edit();
functionNodeFormat.setCode("msg.payload = JSON.stringify(msg.req.cookies,null,4);");
functionNodeFormat.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("<html>\n<head></head>\n<body>\n<h1>Cookies</h1>\n<p></p><a href=\"hello-cookie/add\">Add a cookie</a> &bull; <a href=\"hello-cookie/clear\">Clear cookies</a></p>\n<pre>{{ payload }}</pre>\n</body>\n</html>");
templateNode.clickOk();
httpinNodeFormat.connect(functionNodeFormat);
functionNodeFormat.connect(templateNode);
templateNode.connect(httpResponseNode);
httpinNodeAdd.edit();
httpinNodeAdd.setMethod("get");
httpinNodeAdd.setUrl("/hello-cookie/add");
httpinNodeAdd.clickOk();
functionNodeAdd.edit();
functionNodeAdd.setCode("msg.cookies = { };\n msg.cookies[\"demo-\"+(Math.floor(Math.random()*1000))] = Date.now();");
functionNodeAdd.clickOk();
changeNode.edit();
changeNode.ruleSet("statusCode", "msg", "302", "num");
changeNode.addRule();
changeNode.ruleSet("headers", "msg", "{}", "json", "2");
changeNode.addRule();
changeNode.ruleSet("headers.location", "msg", httpNodeRoot + "/hello-cookie", "str", "3");
changeNode.clickOk();
httpinNodeAdd.connect(functionNodeAdd);
functionNodeAdd.connect(changeNode);
changeNode.connect(httpResponseNode);
httpinNodeClear.edit();
httpinNodeClear.setMethod("get");
httpinNodeClear.setUrl("/hello-cookie/clear");
httpinNodeClear.clickOk();
functionNodeClear.edit();
functionNodeClear.setCode("var cookieNames = Object.keys(msg.req.cookies).filter(function(cookieName) { return /^demo-/.test(cookieName);});\nmsg.cookies = {};\n\ncookieNames.forEach(function(cookieName) {\n msg.cookies[cookieName] = null;\n});\n\n");
functionNodeClear.clickOk();
httpinNodeClear.connect(functionNodeClear);
functionNodeClear.connect(changeNode);
workspace.deploy();
// This case cannot be checked since http request node does not transfer cookies when redirected.
});
});
});

View File

@@ -21,8 +21,11 @@ var fs = require('fs-extra');
var helper = require("../../editor_helper");
var debugTab = require('../../pageobjects/workspace/debugTab_page');
var workspace = require('../../pageobjects/workspace/workspace_page');
var specUtil = require('../../pageobjects/util/spec_util_page');
var nodeWidth = 200;
var nodeHeight = 100;
var httpNodeRoot = "/api";
// https://cookbook.nodered.org/
describe('cookbook', function() {
@@ -45,7 +48,7 @@ describe('cookbook', function() {
var debugNode = workspace.addNode("debug", nodeWidth * 2);
changeNode.edit();
changeNode.ruleSet("Hello World!");
changeNode.ruleSet("payload", "msg", "Hello World!");
changeNode.clickOk();
injectNode.connect(changeNode);
@@ -56,7 +59,7 @@ describe('cookbook', function() {
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.be.equal('"Hello World!"');
debugTab.getMessage().should.eql('"Hello World!"');
});
it('delete a message property', function() {
@@ -76,7 +79,7 @@ describe('cookbook', function() {
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.be.equal("undefined");
debugTab.getMessage().should.eql("undefined");
});
it('move a message property', function() {
@@ -100,7 +103,7 @@ describe('cookbook', function() {
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.be.equal('"Hello"');
debugTab.getMessage().should.eql('"Hello"');
});
it('map a property between different numeric ranges', function() {
@@ -135,11 +138,319 @@ describe('cookbook', function() {
debugTab.open();
debugTab.clearMessage();
injectNode1.clickLeftButton();
debugTab.getMessage(1).should.be.equal('0');
debugTab.getMessage(1).should.eql('0');
injectNode2.clickLeftButton();
debugTab.getMessage(2).should.be.equal('2.5024437927663734');
debugTab.getMessage(2).should.eql('2.5024437927663734');
injectNode3.clickLeftButton();
debugTab.getMessage(3).should.be.equal('5');
debugTab.getMessage(3).should.eql('5');
});
});
describe('flow control', function() {
it('trigger a flow whenever Node-RED starts', function() {
var injectNode = workspace.addNode("inject");
var debugNode = workspace.addNode("debug", nodeWidth * 2);
injectNode.edit();
injectNode.setPayload("str", "Started!")
injectNode.setOnce(true);
injectNode.clickOk();
injectNode.connect(debugNode);
debugTab.open();
debugTab.clearMessage();
workspace.deploy();
debugTab.getMessage().should.eql('"Started!"');
});
it('trigger a flow at regular intervals', function() {
var injectNode = workspace.addNode("inject");
var debugNode = workspace.addNode("debug", nodeWidth * 2);
injectNode.edit();
injectNode.setTimeType("interval");
injectNode.setRepeat(1);
injectNode.clickOk();
injectNode.connect(debugNode);
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
specUtil.pause(1000);
var t1 = Number(debugTab.getMessage(1));
t1.should.within(1500000000000, 3000000000000);
specUtil.pause(1000);
debugTab.getMessage(2).should.within(t1 + 1000, 3000000000000);
});
// skip this case since it needs up to one minite.
it.skip('trigger a flow at a specific time');
});
describe('HTTP requests', function() {
it('simple get request', function() {
var injectNode = workspace.addNode("inject");
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth);
var htmlNode = workspace.addNode("html", nodeWidth * 2);
var debugNode = workspace.addNode("debug", nodeWidth * 3);
httpRequetNode.edit();
httpRequetNode.setMethod("get");
httpRequetNode.setUrl(helper.url());
httpRequetNode.clickOk();
htmlNode.edit();
htmlNode.setTag("title");
htmlNode.clickOk();
injectNode.connect(httpRequetNode);
httpRequetNode.connect(htmlNode);
htmlNode.connect(debugNode);
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.eql('"Node-RED"');
});
it('set the URL of a request', function() {
var injectNode = workspace.addNode("inject");
var changeNode = workspace.addNode("change", nodeWidth * 1.5);
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2.5);
var debugNode = workspace.addNode("debug", nodeWidth * 3.5);
injectNode.edit();
injectNode.setPayload("str", helper.url());
injectNode.clickOk();
changeNode.edit();
changeNode.ruleSet("url", "msg", "payload", "msg");
changeNode.clickOk();
injectNode.connect(changeNode);
changeNode.connect(httpRequetNode);
httpRequetNode.connect(debugNode);
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.containEql('<title>Node-RED</title>');
});
it('set the URL of a request using a template', function() {
var injectNode = workspace.addNode("inject");
var changeNode = workspace.addNode("change", nodeWidth * 1.5);
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2.5);
var debugNode = workspace.addNode("debug", nodeWidth * 3.5);
injectNode.edit();
injectNode.setPayload("str", 'settings');
injectNode.clickOk();
changeNode.edit();
changeNode.ruleSet("query", "msg", "payload", "msg");
changeNode.clickOk();
httpRequetNode.edit();
httpRequetNode.setUrl(helper.url() + "/{{{query}}}");
httpRequetNode.clickOk();
injectNode.connect(changeNode);
changeNode.connect(httpRequetNode);
httpRequetNode.connect(debugNode);
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.containEql('httpNodeRoot');
});
it('set the query string parameters', function() {
var injectNode = workspace.addNode("inject");
var changeNode = workspace.addNode("change", nodeWidth);
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2);
var debugNode = workspace.addNode("debug", nodeWidth * 3);
injectNode.edit();
injectNode.setPayload("str", 'Nick');
injectNode.clickOk();
changeNode.edit();
changeNode.ruleSet("query", "msg", "payload", "msg");
changeNode.clickOk();
httpRequetNode.edit();
httpRequetNode.setUrl(helper.url() + httpNodeRoot + '/set-query?q={{{query}}}');
httpRequetNode.clickOk();
injectNode.connect(changeNode);
changeNode.connect(httpRequetNode);
httpRequetNode.connect(debugNode);
// The code for confirmation starts from here.
var httpinNode = workspace.addNode("httpin", 0, nodeHeight);
var templateNode = workspace.addNode("template", nodeWidth, nodeHeight);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 2, nodeHeight);
httpinNode.edit();
httpinNode.setMethod("get");
httpinNode.setUrl("/set-query");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("Hello {{req.query.q}}");
templateNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.eql('"Hello Nick"');
});
it('get a parsed JSON response', function() {
var injectNode = workspace.addNode("inject");
var changeNodeSetPost = workspace.addNode("change", nodeWidth);
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2);
var debugNode = workspace.addNode("debug", nodeWidth * 3);
injectNode.edit();
injectNode.setPayload("str", "json-response");
injectNode.clickOk();
changeNodeSetPost.edit();
changeNodeSetPost.ruleSet("post", "msg", "payload", "msg");
changeNodeSetPost.clickOk();
httpRequetNode.edit();
httpRequetNode.setMethod("get");
var url = helper.url() + httpNodeRoot + "/{{post}}";
httpRequetNode.setUrl(url);
httpRequetNode.setRet("obj");
httpRequetNode.clickOk();
debugNode.edit();
debugNode.setTarget("msg", "payload.title");
debugNode.clickOk();
injectNode.connect(changeNodeSetPost);
changeNodeSetPost.connect(httpRequetNode);
httpRequetNode.connect(debugNode);
// The code for confirmation starts from here.
var httpinNode = workspace.addNode("httpin", 0, nodeHeight);
var templateNode = workspace.addNode("template", nodeWidth * 1.5, nodeHeight);
var changeNodeSetHeader = workspace.addNode("change", nodeWidth * 2.5, nodeHeight);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 3.5, nodeHeight);
httpinNode.edit();
httpinNode.setMethod("get");
httpinNode.setUrl("/json-response");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("{\"title\": \"Hello\"}");
templateNode.clickOk();
changeNodeSetHeader.edit();
changeNodeSetHeader.ruleSet("headers", "msg", "{\"content-type\":\"application/json\"}", "json");
changeNodeSetHeader.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(changeNodeSetHeader);
changeNodeSetHeader.connect(httpResponseNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.eql('"Hello"');
});
it('get a binary response', function() {
var injectNode = workspace.addNode("inject");
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth);
var debugNode = workspace.addNode("debug", nodeWidth * 2);
httpRequetNode.edit();
httpRequetNode.setMethod("get");
httpRequetNode.setUrl(helper.url() + "/settings");
httpRequetNode.setRet("bin");
httpRequetNode.clickOk();
injectNode.connect(httpRequetNode);
httpRequetNode.connect(debugNode);
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.eql(['123', '34', '104', '116', '116', '112', '78', '111', '100', '101']);
});
it('set a request header', function() {
var injectNode = workspace.addNode("inject");
var functionNode = workspace.addNode("function", nodeWidth);
var httpRequetNode = workspace.addNode("httpRequest", nodeWidth * 2);
var debugNode = workspace.addNode("debug", nodeWidth * 3);
functionNode.edit();
functionNode.setCode("msg.payload = \"data to post\";");
functionNode.clickOk();
httpRequetNode.edit();
httpRequetNode.setMethod("post");
var url = helper.url() + httpNodeRoot + "/set-header";
httpRequetNode.setUrl(url);
httpRequetNode.clickOk();
injectNode.connect(functionNode);
functionNode.connect(httpRequetNode);
httpRequetNode.connect(debugNode);
// The code for confirmation starts from here.
var httpinNode = workspace.addNode("httpin", 0, nodeHeight);
var templateNode = workspace.addNode("template", nodeWidth * 1.5, nodeHeight);
var httpResponseNode = workspace.addNode("httpResponse", nodeWidth * 2.5, nodeHeight);
httpinNode.edit();
httpinNode.setMethod("post");
httpinNode.setUrl("/set-header");
httpinNode.clickOk();
templateNode.edit();
templateNode.setSyntax("mustache");
templateNode.setFormat("handlebars");
templateNode.setTemplate("{{ payload }}");
templateNode.clickOk();
httpinNode.connect(templateNode);
templateNode.connect(httpResponseNode);
// The code for confirmation ends here.
workspace.deploy();
debugTab.open();
debugTab.clearMessage();
injectNode.clickLeftButton();
debugTab.getMessage().should.eql('"data to post"');
});
});
});

View File

@@ -62,10 +62,11 @@ exports.config = {
//
browserName: 'chrome',
chromeOptions: {
// Runs tests without opening a broser.
args: ['--headless', '--disable-gpu', 'window-size=1920,1080'],
// Runs tests with opening a broser.
// args: ['--disable-gpu'],
args: process.env.NODE_RED_NON_HEADLESS
// Runs tests with opening a browser.
? ['--disable-gpu']
// Runs tests without opening a browser.
: ['--headless', '--disable-gpu', 'window-size=1920,1080']
},
}],
//
@@ -154,7 +155,7 @@ exports.config = {
// Options to be passed to Mocha.
// See the full list at http://mochajs.org/
mochaOpts: {
timeout: 20000,
timeout: 60000,
ui: 'bdd'
},
//

View File

@@ -16,22 +16,348 @@
var should = require("should");
var injectNode = require("../../../../nodes/core/core/20-inject.js");
var Context = require("../../../../red/runtime/nodes/context");
var helper = require("node-red-node-test-helper");
describe('inject node', function() {
before(function(done) {
beforeEach(function(done) {
helper.startServer(done);
});
after(function(done) {
helper.stopServer(done);
function initContext(done) {
Context.init({
contextStorage: {
memory0: {
module: "memory"
},
memory1: {
module: "memory"
}
}
});
Context.load().then(function () {
done();
});
}
afterEach(function(done) {
helper.unload().then(function () {
return Context.clean({allNodes: {}});
}).then(function () {
return Context.close();
}).then(function () {
helper.stopServer(done);
});
});
afterEach(function() {
helper.unload();
function basicTest(type, val, rval) {
it('inject value ('+type+')', function (done) {
var flow = [{id: "n1", type: "inject", topic: "t1", payload: val, payloadType: type, wires: [["n2"]], z: "flow"},
{id: "n2", type: "helper"}];
helper.load(injectNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
try {
msg.should.have.property("topic", "t1");
if (rval) {
msg.should.have.property("payload");
should.deepEqual(msg.payload, rval);
}
else {
msg.should.have.property("payload", val);
}
done();
} catch (err) {
done(err);
}
});
n1.receive({});
});
});
}
basicTest("num", 10);
basicTest("str", "10");
basicTest("bool", true);
var val_json = '{ "x":"vx", "y":"vy", "z":"vz" }';
basicTest("json", val_json, JSON.parse(val_json));
var val_buf = "[1,2,3,4,5]";
basicTest("bin", val_buf, Buffer.from(JSON.parse(val_buf)));
it('inject value of environment variable ', function (done) {
var flow = [{id: "n1", type: "inject", topic: "t1", payload: "NR_TEST", payloadType: "env", wires: [["n2"]], z: "flow"},
{id: "n2", type: "helper"}];
helper.load(injectNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
try {
msg.should.have.property("topic", "t1");
msg.should.have.property("payload", "foo");
done();
} catch (err) {
done(err);
}
});
process.env.NR_TEST = 'foo';
n1.receive({});
});
});
it('sets the value of flow context property', function (done) {
var flow = [{id: "n1", type: "inject", topic: "t1", payload: "flowValue", payloadType: "flow", wires: [["n2"]], z: "flow"},
{id: "n2", type: "helper"}];
helper.load(injectNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
try {
msg.should.have.property("topic", "t1");
msg.should.have.property("payload", "changeMe");
done();
} catch (err) {
done(err);
}
});
n1.context().flow.set("flowValue", "changeMe");
n1.receive({});
});
});
it('sets the value of persistable flow context property', function (done) {
var flow = [{id: "n1", type: "inject", topic: "t1", payload: "#:(memory0)::flowValue", payloadType: "flow", wires: [["n2"]], z: "flow"},
{id: "n2", type: "helper"}];
helper.load(injectNode, flow, function () {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
try {
msg.should.have.property("topic", "t1");
msg.should.have.property("payload", "changeMe");
done();
} catch (err) {
done(err);
}
});
n1.context().flow.set("flowValue", "changeMe", "memory0", function (err) {
n1.receive({});
});
});
});
});
it('sets the value of two persistable flow context property', function (done) {
var flow = [{id: "n0", z: "flow", type: "inject", topic: "t0", payload: "#:(memory0)::val", payloadType: "flow", wires: [["n2"]]},
{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "flow", wires: [["n2"]]},
{id: "n2", z: "flow", type: "helper"}];
helper.load(injectNode, flow, function () {
initContext(function () {
var n0 = helper.getNode("n0");
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function (msg) {
try {
msg.should.have.property("topic");
if (msg.topic === "t0") {
msg.should.have.property("payload", "foo");
}
else if (msg.topic === "t1") {
msg.should.have.property("payload", "bar");
}
else {
done(new Error("unexpected message"));
}
count++;
if (count === 2) {
done();
}
} catch (err) {
done(err);
}
});
var global = n0.context().flow;
global.set("val", "foo", "memory0", function (err) {
global.set("val", "bar", "memory1", function (err) {
n0.receive({});
n1.receive({});
});
});
});
});
});
it('sets the value of global context property', function (done) {
var flow = [{id: "n1", type: "inject", topic: "t1", payload: "globalValue", payloadType: "global", wires: [["n2"]]},
{id: "n2", type: "helper"}];
helper.load(injectNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
try {
msg.should.have.property("topic", "t1");
msg.should.have.property("payload", "changeMe");
done();
} catch (err) {
done(err);
}
});
n1.context().global.set("globalValue", "changeMe");
n1.receive({});
});
});
it('sets the value of persistable global context property', function (done) {
var flow = [{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "global", wires: [["n2"]]},
{id: "n2", z: "flow", type: "helper"}];
helper.load(injectNode, flow, function () {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
try {
msg.should.have.property("topic", "t1");
msg.should.have.property("payload", "foo");
done();
} catch (err) {
done(err);
}
});
var global = n1.context().global;
global.set("val", "foo", "memory1", function (err) {
n1.receive({});
});
});
});
});
it('sets the value of two persistable global context property', function (done) {
var flow = [{id: "n0", z: "flow", type: "inject", topic: "t0", payload: "#:(memory0)::val", payloadType: "global", wires: [["n2"]]},
{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "global", wires: [["n2"]]},
{id: "n2", z: "flow", type: "helper"}];
helper.load(injectNode, flow, function () {
initContext(function () {
var n0 = helper.getNode("n0");
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function (msg) {
try {
msg.should.have.property("topic");
if (msg.topic === "t0") {
msg.should.have.property("payload", "foo");
}
else if (msg.topic === "t1") {
msg.should.have.property("payload", "bar");
}
else {
done(new Error("unexpected message"));
}
count++;
if (count === 2) {
done();
}
} catch (err) {
done(err);
}
});
var global = n0.context().global;
global.set("val", "foo", "memory0", function (err) {
global.set("val", "bar", "memory1", function (err) {
n0.receive({});
n1.receive({});
});
});
});
});
});
it('sets the value of persistable flow & global context property', function (done) {
var flow = [{id: "n0", z: "flow", type: "inject", topic: "t0", payload: "#:(memory0)::val", payloadType: "flow", wires: [["n2"]]},
{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "global", wires: [["n2"]]},
{id: "n2", z: "flow", type: "helper"}];
helper.load(injectNode, flow, function () {
initContext(function () {
var n0 = helper.getNode("n0");
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function (msg) {
try {
msg.should.have.property("topic");
if (msg.topic === "t0") {
msg.should.have.property("payload", "foo");
}
else if (msg.topic === "t1") {
msg.should.have.property("payload", "bar");
}
else {
done(new Error("unexpected message"));
}
count++;
if (count === 2) {
done();
}
} catch (err) {
done(err);
}
});
var context = n0.context();
var flow = context.flow;
var global = context.global;
flow.set("val", "foo", "memory0", function (err) {
global.set("val", "bar", "memory1", function (err) {
n0.receive({});
n1.receive({});
});
});
});
});
});
it('sets the value of two persistable global context property', function (done) {
var flow = [{id: "n0", z: "flow", type: "inject", topic: "t0", payload: "#:(memory0)::val", payloadType: "global", wires: [["n2"]]},
{id: "n1", z: "flow", type: "inject", topic: "t1", payload: "#:(memory1)::val", payloadType: "global", wires: [["n2"]]},
{id: "n2", z: "flow", type: "helper"}];
helper.load(injectNode, flow, function () {
initContext(function () {
var n0 = helper.getNode("n0");
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function (msg) {
try {
msg.should.have.property("topic");
if (msg.topic === "t0") {
msg.should.have.property("payload", "foo");
}
else if (msg.topic === "t1") {
msg.should.have.property("payload", "bar");
}
else {
done(new Error("unexpected message"));
}
count++;
if (count === 2) {
done();
}
} catch (err) {
done(err);
}
});
var global = n0.context().global;
global.set("val", "foo", "memory0", function (err) {
global.set("val", "bar", "memory1", function (err) {
n0.receive({});
n1.receive({});
});
});
});
});
});
it('should inject once with default delay property', function(done) {
helper.load(injectNode, [{id:"n1", type:"inject", topic: "t1",
payload:"",payloadType:"date",

View File

@@ -411,7 +411,7 @@ describe('debug node', function() {
data:{
id:"n1",
msg:JSON.stringify({
__encoded__: true,
__enc__: true,
type: "array",
data: Array(1000).fill("X"),
length: 1001
@@ -438,7 +438,7 @@ describe('debug node', function() {
id:"n1",
msg:JSON.stringify({
foo:{
__encoded__: true,
__enc__: true,
type: "array",
data: Array(1000).fill("X"),
length: 1001
@@ -489,7 +489,7 @@ describe('debug node', function() {
foo:{
type: "Buffer",
data: Array(1000).fill(88),
__encoded__: true,
__enc__: true,
length: 1001
}
},null," "),

View File

@@ -1,21 +1,22 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var functionNode = require("../../../../nodes/core/core/80-function.js");
var Context = require("../../../../red/runtime/nodes/context");
var helper = require("node-red-node-test-helper");
describe('function node', function() {
@@ -28,10 +29,31 @@ describe('function node', function() {
helper.stopServer(done);
});
function initContext(done) {
Context.init({
contextStorage: {
memory1: {
module: "memory"
},
memory2: {
module: "memory"
}
}
});
Context.load().then(function () {
done();
});
}
afterEach(function() {
helper.unload();
helper.unload().then(function () {
return Context.clean({allNodes:{}});
}).then(function () {
return Context.close();
});
});
it('should be loaded', function(done) {
var flow = [{id:"n1", type:"function", name: "function" }];
helper.load(functionNode, flow, function() {
@@ -43,7 +65,7 @@ describe('function node', function() {
it('should send returned message', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -58,7 +80,7 @@ describe('function node', function() {
it('should send returned message using send()', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"node.send(msg);"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -73,7 +95,7 @@ describe('function node', function() {
it('should pass through _topic', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -89,8 +111,8 @@ describe('function node', function() {
it('should send to multiple outputs', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"],["n3"]],
func:"return [{payload: '1'},{payload: '2'}];"},
{id:"n2", type:"helper"}, {id:"n3", type:"helper"} ];
func:"return [{payload: '1'},{payload: '2'}];"},
{id:"n2", type:"helper"}, {id:"n3", type:"helper"} ];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -116,8 +138,8 @@ describe('function node', function() {
it('should send to multiple messages', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],
func:"return [[{payload: 1},{payload: 2}]];"},
{id:"n2", type:"helper"} ];
func:"return [[{payload: 1},{payload: 2}]];"},
{id:"n2", type:"helper"} ];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -140,7 +162,7 @@ describe('function node', function() {
it('should allow input to be discarded by returning null', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"return null"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -156,8 +178,8 @@ describe('function node', function() {
it('should handle null amongst valid messages', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"return [[msg,null,msg],null]"},
{id:"n2", type:"helper"},
{id:"n3", type:"helper"}];
{id:"n2", type:"helper"},
{id:"n3", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -181,7 +203,7 @@ describe('function node', function() {
it('should get keys in global context', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=global.keys();return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -197,7 +219,7 @@ describe('function node', function() {
function testNonObjectMessage(functionText,done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:functionText},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -290,7 +312,7 @@ describe('function node', function() {
it('should set node context', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.set('count','0');return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -304,9 +326,198 @@ describe('function node', function() {
});
});
it('should set persistable node context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.set('count','0','memory1');return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n1.context().get("count", "memory1", function (err, val) {
val.should.equal("0");
done();
});
}
catch (e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set two persistable node context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.set('count','0','memory1');context.set('count','1','memory2');return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n1.context().get("count", "memory1", function (err, val1) {
val1.should.equal("0");
n1.context().get("count", "memory2", function (err, val2) {
val2.should.equal("1");
done();
});
});
}
catch (e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set two persistable node context (single call, w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.set(['count1','count2'],['0','1'],'memory1');return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n1.context().get("count1", "memory1", function (err, val1) {
val1.should.equal("0");
n1.context().get("count2", "memory1", function (err, val2) {
val2.should.equal("1");
done();
});
});
}
catch (e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set persistable node context (w callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.set('count','0','memory1', function (err) { node.send(msg); });"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n1.context().get("count", "memory1", function (err, val) {
val.should.equal("0");
done();
});
}
catch (e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set two persistable node context (w callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.set('count','0','memory1', function (err) { context.set('count', '1', 'memory2', function (err) { node.send(msg); }); });"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n1.context().get("count", "memory1", function (err, val1) {
val1.should.equal("0");
n1.context().get("count", "memory1", function (err, val2) {
val2.should.equal("0");
done();
});
});
}
catch (e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set two persistable node context (single call, w callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.set(['count1','count2'],['0','1'],'memory1', function(err) { node.send(msg); });"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n1.context().get("count1", "memory1", function (err, val1) {
val1.should.equal("0");
n1.context().get("count2", "memory1", function (err, val2) {
val2.should.equal("1");
done();
});
});
}
catch (e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set default persistable node context', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.set('count','0');return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n1.context().get("count", "memory1", function (err, val) {
val.should.equal("0");
done();
});
}
catch (e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get node context', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=context.get('count');return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -320,9 +531,64 @@ describe('function node', function() {
});
});
function checkCallbackError(name, done) {
try {
helper.log().called.should.be.true();
var logEvents = helper.log().args.filter(function (evt) {
return evt[0].type == "function";
});
logEvents.should.have.length(1);
var msg = logEvents[0][0];
msg.should.have.property('level', helper.log().ERROR);
msg.should.have.property('id', name);
msg.should.have.property('type', 'function');
msg.should.have.property('msg', 'Error: Callback must be a function');
done();
}
catch (e) {
done(e);
}
}
it('should get persistable node context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=context.get('count','memory1');return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().set("count","0","memory1");
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', '0');
done();
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get persistable node context (w/ callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.get('count','memory1',function (err, val) { msg.payload=val; node.send(msg); });"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().set("count","0","memory1");
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', '0');
done();
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get keys in node context', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=context.keys();return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -336,9 +602,79 @@ describe('function node', function() {
});
});
it('should get keys in persistable node context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=context.keys('memory1');return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().set("count","0","memory1");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', ['count']);
done();
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get keys in persistable node context (w/ callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.keys('memory1', function(err, keys) { msg.payload=keys; node.send(msg); });"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().set("count","0","memory1");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', ['count']);
done();
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get keys in default persistable node context', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=context.keys();return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().set("count","0","memory1");
n1.context().set("number","1","memory2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', ['count']);
done();
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set flow context', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"flow.set('count','0');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -352,9 +688,115 @@ describe('function node', function() {
});
});
it('should set persistable flow context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"flow.set('count','0','memory1');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n2.context().flow.get("count", "memory1", function (err, val) {
val.should.equal("0");
done();
});
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set two persistable flow context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"flow.set('count','0','memory1');flow.set('count','1','memory2');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n2.context().flow.get("count", "memory1", function (err, val1) {
val1.should.equal("0");
n2.context().flow.get("count", "memory2", function (err, val2) {
val2.should.equal("1");
done();
});
});
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set persistable flow context (w/ callback)', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"flow.set('count','0','memory1', function (err) { node.send(msg); });"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n2.context().flow.get("count", "memory1", function (err, val) {
val.should.equal("0");
done();
});
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set two persistable flow context (w/ callback)', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"flow.set('count','0','memory1', function (err) { flow.set('count','1','memory2', function (err) { node.send(msg); }); });"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n2.context().flow.get("count", "memory1", function (err, val1) {
val1.should.equal("0");
n2.context().flow.get("count", "memory2", function (err, val2) {
val2.should.equal("1");
done();
});
});
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get flow context', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"msg.payload=flow.get('count');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -368,9 +810,45 @@ describe('function node', function() {
});
});
it('should get persistable flow context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"msg.payload=flow.get('count','memory1');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().flow.set("count","0","memory1");
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', '0');
done();
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get persistable flow context (w/ callback)', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"flow.get('count','memory1', function(err, val) { msg.payload=val; node.send(msg); });"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().flow.set("count","0","memory1");
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', '0');
done();
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get flow context', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"msg.payload=context.flow.get('count');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -386,7 +864,7 @@ describe('function node', function() {
it('should get keys in flow context', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"msg.payload=flow.keys();return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -400,9 +878,55 @@ describe('function node', function() {
});
});
it('should get keys in persistable flow context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"msg.payload=flow.keys('memory1');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().flow.set("count","0","memory1");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', ['count']);
done();
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get keys in persistable flow context (w/ callback)', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"flow.keys('memory1', function (err, val) { msg.payload=val; node.send(msg); });"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().flow.set("count","0","memory1");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', ['count']);
done();
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set global context', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"global.set('count','0');return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -416,9 +940,59 @@ describe('function node', function() {
});
});
it('should set persistable global context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"global.set('count','0','memory1');return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n2.context().global.get("count", "memory1", function(err, val) {
val.should.equal("0");
done();
});
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should set persistable global context (w/ callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"global.set('count','0','memory1', function (err) { node.send(msg); });"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
n2.context().global.get("count", "memory1", function(err, val) {
val.should.equal("0");
done();
});
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get global context', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=global.get('count');return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -432,9 +1006,45 @@ describe('function node', function() {
});
});
it('should get persistable global context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=global.get('count', 'memory1');return msg;"},
{id:"n2", type:"helper"}];
initContext(function () {
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().global.set("count","0", 'memory1');
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', '0');
done();
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get persistable global context (w/ callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"global.get('count', 'memory1', function (err, val) { msg.payload=val; node.send(msg); });"},
{id:"n2", type:"helper"}];
initContext(function () {
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().global.set("count","0", 'memory1');
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', '0');
done();
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get global context', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=context.global.get('count');return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -448,9 +1058,97 @@ describe('function node', function() {
});
});
it('should get persistable global context (w/o callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=context.global.get('count','memory1');return msg;"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().global.set("count","0", "memory1");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', '0');
done();
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should get persistable global context (w/ callback)', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"context.global.get('count','memory1', function (err, val) { msg.payload = val; node.send(msg); });"},
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().global.set("count","0", "memory1");
n2.on("input", function(msg) {
try {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', '0');
done();
}
catch(e) {
done(e);
}
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should handle error on get persistable context', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"msg.payload=context.get('count','memory1','callback');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().flow.set("count","0","memory1");
n1.receive({payload:"foo",topic: "bar"});
checkCallbackError('n1', done);
});
});
});
it('should handle error on set persistable context', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"msg.payload=context.set('count','0','memory1','callback');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.receive({payload:"foo",topic: "bar"});
checkCallbackError('n1', done);
});
});
});
it('should handle error on get keys in persistable context', function(done) {
var flow = [{id:"n1",type:"function",z:"flowA",wires:[["n2"]],func:"msg.payload=context.keys('memory1','callback');return msg;"},
{id:"n2", type:"helper",z:"flowA"}];
helper.load(functionNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context().flow.set("count","0","memory1");
n1.receive({payload:"foo",topic: "bar"});
checkCallbackError('n1', done);
});
});
});
it('should handle setTimeout()', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"setTimeout(function(){node.send(msg);},1000);"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -476,7 +1174,7 @@ describe('function node', function() {
it('should handle setInterval()', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"setInterval(function(){node.send(msg);},100);"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -495,7 +1193,7 @@ describe('function node', function() {
it('should handle clearInterval()', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"var id=setInterval(null,100);setTimeout(function(){clearInterval(id);node.send(msg);},1000);"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -510,7 +1208,7 @@ describe('function node', function() {
it('should allow accessing node.id', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload = node.id; return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -524,7 +1222,7 @@ describe('function node', function() {
it('should allow accessing node.name', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload = node.name; return msg;", "name":"name of node"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -538,7 +1236,7 @@ describe('function node', function() {
it('should use the same Date object from outside the sandbox', function(done) {
var flow = [{id:"n1",type:"function",wires:[["n2"]],func:"msg.payload=global.get('typeTest')(new Date());return msg;"},
{id:"n2", type:"helper"}];
{id:"n2", type:"helper"}];
helper.load(functionNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");

View File

@@ -16,6 +16,7 @@
var should = require("should");
var templateNode = require("../../../../nodes/core/core/80-template.js");
var Context = require("../../../../red/runtime/nodes/context");
var helper = require("node-red-node-test-helper");
describe('template node', function() {
@@ -28,8 +29,35 @@ describe('template node', function() {
helper.stopServer(done);
});
beforeEach(function(done) {
done();
});
function initContext(done) {
Context.init({
contextStorage: {
memory0: { // do not use (for excluding effect fallback)
module: "memory"
},
memory1: {
module: "memory"
},
memory2: {
module: "memory"
}
}
});
Context.load().then(function () {
done();
});
}
afterEach(function() {
helper.unload();
helper.unload().then(function () {
return Context.clean({allNodes:{}});
}).then(function () {
return Context.close();
});
});
@@ -116,7 +144,6 @@ describe('template node', function() {
});
});
it('should modify payload from flow context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow.value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
@@ -132,6 +159,44 @@ describe('template node', function() {
});
});
it('should modify payload from persistable flow context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow[memory1].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'payload=foo');
done();
});
n1.context().flow.set("value","foo","memory1",function (err) {
n1.receive({payload:"foo",topic: "bar"});
});
});
});
});
it('should modify payload from two persistable flow context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow[memory1].value}}/{{flow[memory2].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
initContext(function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'payload=foo/bar');
done();
});
n1.context().flow.set("value","foo","memory1",function (err) {
n1.context().flow.set("value","bar","memory2",function (err) {
n1.receive({payload:"foo",topic: "bar"});
});
});
});
});
});
it('should modify payload from global context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global.value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
@@ -147,6 +212,64 @@ describe('template node', function() {
});
});
it('should modify payload from persistable global context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global[memory1].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'payload=foo');
done();
});
n1.context().global.set("value","foo","memory1", function (err) {
n1.receive({payload:"foo",topic: "bar"});
});
});
});
});
it('should modify payload from two persistable global context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{global[memory1].value}}/{{global[memory2].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'payload=foo/bar');
done();
});
n1.context().global.set("value","foo","memory1", function (err) {
n1.context().global.set("value","bar","memory2", function (err) {
n1.receive({payload:"foo",topic: "bar"});
});
});
});
});
});
it('should modify payload from persistable flow & global context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", template:"payload={{flow[memory1].value}}/{{global[memory1].value}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'payload=foo/bar');
done();
});
n1.context().flow.set("value","foo","memory1", function (err) {
n1.context().global.set("value","bar","memory1", function (err) {
n1.receive({payload:"foo",topic: "bar"});
});
});
});
});
});
it('should handle missing node context', function(done) {
// this is artificial test because in flow there is missing z property (probably never happen in real usage)
var flow = [{id:"n1",type:"template", field:"payload", template:"payload={{flow.value}},{{global.value}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
@@ -206,6 +329,27 @@ describe('template node', function() {
});
});
it('should modify persistable flow context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"#:(memory1)::payload", fieldType:"flow", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
// mesage is intact
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
// result is in flow context
n2.context().flow.get("payload", "memory1", function (err, val) {
val.should.equal("payload=foo");
done();
});
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should modify global context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"payload", fieldType:"global", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
@@ -223,6 +367,27 @@ describe('template node', function() {
});
});
it('should modify persistable global context', function(done) {
var flow = [{id:"n1",z:"t1", type:"template", field:"#:(memory1)::payload", fieldType:"global", template:"payload={{payload}}",wires:[["n2"]]},{id:"n2",z:"t1",type:"helper"}];
helper.load(templateNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
// mesage is intact
msg.should.have.property('topic', 'bar');
msg.should.have.property('payload', 'foo');
// result is in global context
n2.context().global.get("payload", "memory1", function (err, val) {
val.should.equal("payload=foo");
done();
});
});
n1.receive({payload:"foo",topic: "bar"});
});
});
});
it('should handle if the field isn\'t set', function(done) {
var flow = [{id:"n1", type:"template", template: "payload={{payload}}",wires:[["n2"]]},{id:"n2",type:"helper"}];
helper.load(templateNode, flow, function() {
@@ -264,6 +429,7 @@ describe('template node', function() {
n1.receive({payload:{A:"abc"}});
});
});
it('should raise error if passed bad template', function(done) {
var flow = [{id:"n1", type:"template", field: "payload", template: "payload={{payload",wires:[["n2"]]},{id:"n2",type:"helper"}];
helper.load(templateNode, flow, function() {

View File

@@ -18,6 +18,7 @@ var should = require("should");
var sinon = require("sinon");
var helper = require("node-red-node-test-helper");
var triggerNode = require("../../../../nodes/core/core/89-trigger.js");
var Context = require("../../../../red/runtime/nodes/context");
var RED = require("../../../../red/red.js");
describe('trigger node', function() {
@@ -26,8 +27,31 @@ describe('trigger node', function() {
helper.startServer(done);
});
function initContext(done) {
Context.init({
contextStorage: {
memory0: {
module: "memory"
},
memory1: {
module: "memory"
},
memory2: {
module: "memory"
}
}
});
Context.load().then(function () {
done();
});
}
afterEach(function(done) {
helper.unload().then(function() {
helper.unload().then(function () {
return Context.clean({allNodes: {}});
}).then(function () {
return Context.close();
}).then(function () {
helper.stopServer(done);
});
});
@@ -75,6 +99,74 @@ describe('trigger node', function() {
});
});
function basicTest(type, val, rval) {
it('should output 1st value when triggered ('+type+')', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:val, op1type:type, op2:"", op2type:"null", duration:"20", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
process.env[val] = rval;
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
if (rval) {
msg.should.have.property("payload");
should.deepEqual(msg.payload, rval);
}
else {
msg.should.have.property("payload", val);
}
delete process.env[val];
done();
}
catch(err) { done(err); }
});
n1.emit("input", {payload:null});
});
});
it('should output 2st value when triggered ('+type+')', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", op1:"foo", op1type:"str", op2:val, op2type:type, duration:"20", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
process.env[val] = rval;
helper.load(triggerNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function(msg) {
try {
if (c === 0) {
msg.should.have.property("payload", "foo");
c++;
}
else {
if (rval) {
msg.should.have.property("payload");
should.deepEqual(msg.payload, rval);
}
else {
msg.should.have.property("payload", val);
}
delete process.env[val];
done();
}
}
catch(err) { done(err); }
});
n1.emit("input", {payload:null});
});
});
}
basicTest("num", 10);
basicTest("str", "10");
basicTest("bool", true);
var val_json = '{ "x":"vx", "y":"vy", "z":"vz" }';
basicTest("json", val_json, JSON.parse(val_json));
var val_buf = "[1,2,3,4,5]";
basicTest("bin", val_buf, Buffer.from(JSON.parse(val_buf)));
basicTest("env", "NR-TEST", "env-val");
it('should output 1 then 0 when triggered (default)', function(done) {
var flow = [{"id":"n1", "type":"trigger", "name":"triggerNode", duration:"20", wires:[["n2"]] },
{id:"n2", type:"helper"} ];
@@ -288,7 +380,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',
function(arg1, arg2, arg3, arg4) { return arg1; }
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"]] },
{id:"n2", type:"helper"} ];
@@ -312,7 +404,159 @@ describe('trigger node', function() {
});
n1.emit("input", {payload:null});
});
});
it('should be able to return things from persistable flow and global context variables', function (done) {
var flow = [{"id": "n1", "type": "trigger", "name": "triggerNode", "op1": "#:(memory1)::foo", "op1type": "flow",
"op2": "#:(memory1)::bar", "op2type": "global", "duration": "20", "wires": [["n2"]], "z": "flow" },
{"id": "n2", "type": "helper"}];
helper.load(triggerNode, flow, function () {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var c = 0;
n2.on("input", function (msg) {
try {
if (c === 0) {
msg.should.have.a.property("payload", "foo");
c += 1;
} else {
msg.should.have.a.property("payload", "bar");
done();
}
} catch (err) {
done(err);
}
});
var context = n1.context();
var flow = context.flow;
var global = context.global;
flow.set("foo", "foo", "memory1", function (err) {
global.set("bar", "bar", "memory1", function (err) {
n1.emit("input", { payload: null });
});
});
});
});
});
it('should be able to return things from multiple persistable global context variables', function (done) {
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
"duration": "20", "wires": [["n2"]],
"op1": "#:(memory1)::val", "op1type": "global",
"op2": "#:(memory2)::val", "op2type": "global"
},
{"id": "n2", "type": "helper"}];
helper.load(triggerNode, flow, function () {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function (msg) {
try {
if (count === 0) {
msg.should.have.a.property("payload", "foo");
}
else {
msg.should.have.a.property("payload", "bar");
}
count++;
if (count === 1) {
done();
}
}
catch (err) {
done(err);
}
});
var global = n1.context().global;
global.set("val", "foo", "memory1", function (err) {
global.set("val", "bar", "memory2", function (err) {
n1.emit("input", { payload: null });
});
});
});
});
});
it('should be able to return things from multiple persistable flow context variables', function (done) {
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
"duration": "20", "wires": [["n2"]],
"op1": "#:(memory1)::val", "op1type": "flow",
"op2": "#:(memory2)::val", "op2type": "flow"
},
{"id": "n2", "type": "helper"}];
helper.load(triggerNode, flow, function () {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function (msg) {
try {
if (count === 0) {
msg.should.have.a.property("payload", "foo");
}
else {
msg.should.have.a.property("payload", "bar");
}
count++;
if (count === 1) {
done();
}
}
catch (err) {
done(err);
}
});
var flow = n1.context().flow;
flow.set("val", "foo", "memory1", function (err) {
flow.set("val", "bar", "memory2", function (err) {
n1.emit("input", { payload: null });
});
});
});
});
});
it('should be able to return things from multiple persistable flow & global context variables', function (done) {
var flow = [{"id": "n1", "z": "flow", "type": "trigger",
"duration": "20", "wires": [["n2"]],
"op1": "#:(memory1)::val", "op1type": "flow",
"op2": "#:(memory2)::val", "op2type": "global"
},
{"id": "n2", "type": "helper"}];
helper.load(triggerNode, flow, function () {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function (msg) {
try {
if (count === 0) {
msg.should.have.a.property("payload", "foo");
}
else {
msg.should.have.a.property("payload", "bar");
}
count++;
if (count === 1) {
done();
}
}
catch (err) {
done(err);
}
});
var context = n1.context();
var flow = context.flow;
var global = context.flow;
flow.set("val", "foo", "memory1", function (err) {
global.set("val", "bar", "memory2", function (err) {
n1.emit("input", { payload: null });
});
});
});
});
});
it('should be able to not output anything on first trigger', function(done) {
@@ -386,7 +630,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',
function(arg1, arg2, arg3, arg4) { return arg1; }
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"]] },
{id:"n2", type:"helper"} ];
@@ -428,14 +672,12 @@ describe('trigger node', function() {
n2.on("input", function(msg) {
try {
if (c === 0) {
console.log(c,Date.now() - ss,msg);
msg.should.have.a.property("payload", "Hello");
c += 1;
}
else {
console.log(c,Date.now() - ss,msg);
msg.should.have.a.property("payload", "World");
(Date.now() - ss).should.be.greaterThan(150);
(Date.now() - ss).should.be.greaterThan(149);
done();
}
}

View File

@@ -0,0 +1,89 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var rpi = require("../../../../nodes/core/hardware/36-rpi-gpio.js");
var helper = require("node-red-node-test-helper");
var fs = require("fs");
describe('RPI GPIO Node', function() {
before(function(done) {
helper.startServer(done);
});
after(function(done) {
helper.stopServer(done);
});
afterEach(function() {
helper.unload();
});
var checkIgnore = function(done) {
setTimeout(function() {
try {
var logEvents = helper.log().args.filter(function(evt) {
return ((evt[0].level == 30) && (evt[0].msg.indexOf("rpi-gpio")===0));
});
logEvents[0][0].should.have.a.property('msg');
logEvents[0][0].msg.toString().should.startWith("rpi-gpio : rpi-gpio.errors.ignorenode");
done();
} catch(err) {
done(err);
}
},25);
}
it('should load Input node', function(done) {
var flow = [{id:"n1", type:"rpi-gpio in", name:"rpi-gpio in" }];
helper.load(rpi, flow, function() {
var n1 = helper.getNode("n1");
n1.should.have.property('name', 'rpi-gpio in');
try {
var cpuinfo = fs.readFileSync("/proc/cpuinfo").toString();
if (cpuinfo.indexOf(": BCM") === 1) {
done(); // It's ON a PI ... should really do more tests !
} else {
checkIgnore(done);
}
}
catch(e) {
checkIgnore(done);
}
});
});
it('should load Output node', function(done) {
var flow = [{id:"n1", type:"rpi-gpio out", name:"rpi-gpio out" }];
helper.load(rpi, flow, function() {
var n1 = helper.getNode("n1");
n1.should.have.property('name', 'rpi-gpio out');
try {
var cpuinfo = fs.readFileSync("/proc/cpuinfo").toString();
if (cpuinfo.indexOf(": BCM") === 1) {
done(); // It's ON a PI ... should really do more tests !
} else {
checkIgnore(done);
}
}
catch(e) {
checkIgnore(done);
}
});
});
});

View File

@@ -102,38 +102,13 @@ describe('HTTP Request Node', function() {
return "localhost:"+testSslPort+url;
}
function saveProxySetting() {
preEnvHttpProxyLowerCase = process.env.http_proxy;
preEnvHttpProxyUpperCase = process.env.HTTP_PROXY;
preEnvNoProxyLowerCase = process.env.no_proxy;
preEnvNoProxyUpperCase = process.env.NO_PROXY;
function deleteProxySetting() {
delete process.env.http_proxy;
delete process.env.HTTP_PROXY;
delete process.env.no_proxy;
delete process.env.NO_PROXY;
}
function restoreProxySetting() {
process.env.http_proxy = preEnvHttpProxyLowerCase;
process.env.HTTP_PROXY = preEnvHttpProxyUpperCase;
// On Windows, if environment variable of NO_PROXY that includes lower cases
// such as No_Proxy is replaced with NO_PROXY.
process.env.no_proxy = preEnvNoProxyLowerCase;
process.env.NO_PROXY = preEnvNoProxyUpperCase;
if (preEnvHttpProxyLowerCase == undefined){
delete process.env.http_proxy;
}
if (preEnvHttpProxyUpperCase == undefined){
delete process.env.HTTP_PROXY;
}
if (preEnvNoProxyLowerCase == undefined){
delete process.env.no_proxy;
}
if (preEnvNoProxyUpperCase == undefined){
delete process.env.NO_PROXY;
}
}
before(function(done) {
testApp = express();
testApp.use(bodyParser.raw({type:"*/*"}));
@@ -225,7 +200,35 @@ describe('HTTP Request Node', function() {
});
});
beforeEach(function() {
preEnvHttpProxyLowerCase = process.env.http_proxy;
preEnvHttpProxyUpperCase = process.env.HTTP_PROXY;
preEnvNoProxyLowerCase = process.env.no_proxy;
preEnvNoProxyUpperCase = process.env.NO_PROXY;
process.env.no_proxy = 'localhost';
process.env.NO_PROXY = 'localhost';
});
afterEach(function() {
process.env.http_proxy = preEnvHttpProxyLowerCase;
process.env.HTTP_PROXY = preEnvHttpProxyUpperCase;
// On Windows, if environment variable of NO_PROXY that includes lower cases
// such as No_Proxy is replaced with NO_PROXY.
process.env.no_proxy = preEnvNoProxyLowerCase;
process.env.NO_PROXY = preEnvNoProxyUpperCase;
if (preEnvHttpProxyLowerCase == undefined) {
delete process.env.http_proxy;
}
if (preEnvHttpProxyUpperCase == undefined) {
delete process.env.HTTP_PROXY;
}
if (preEnvNoProxyLowerCase == undefined) {
delete process.env.no_proxy;
}
if (preEnvNoProxyUpperCase == undefined) {
delete process.env.NO_PROXY;
}
helper.unload();
});
@@ -1060,13 +1063,12 @@ describe('HTTP Request Node', function() {
it('should use http_proxy', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
{id:"n2", type:"helper"}];
saveProxySetting();
deleteProxySetting();
process.env.http_proxy = "http://localhost:" + testProxyPort;
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
restoreProxySetting();
try {
msg.should.have.property('statusCode',200);
msg.payload.should.have.property('headers');
@@ -1083,13 +1085,12 @@ describe('HTTP Request Node', function() {
it('should use http_proxy when environment variable is invalid', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
{id:"n2", type:"helper"}];
saveProxySetting();
deleteProxySetting();
process.env.http_proxy = "invalidvalue";
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
restoreProxySetting();
try {
msg.should.have.property('statusCode',200);
msg.payload.should.have.property('headers');
@@ -1106,13 +1107,12 @@ describe('HTTP Request Node', function() {
it('should use HTTP_PROXY', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
{id:"n2", type:"helper"}];
saveProxySetting();
deleteProxySetting();
process.env.HTTP_PROXY = "http://localhost:" + testProxyPort;
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
restoreProxySetting();
try {
msg.should.have.property('statusCode',200);
msg.payload.should.have.property('headers');
@@ -1129,14 +1129,13 @@ describe('HTTP Request Node', function() {
it('should use no_proxy', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
{id:"n2", type:"helper"}];
saveProxySetting();
deleteProxySetting();
process.env.http_proxy = "http://localhost:" + testProxyPort;
process.env.no_proxy = "foo,localhost";
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
restoreProxySetting();
try {
msg.should.have.property('statusCode',200);
msg.payload.headers.should.not.have.property('x-testproxy-header','foobar');
@@ -1152,14 +1151,13 @@ describe('HTTP Request Node', function() {
it('should use NO_PROXY', function(done) {
var flow = [{id:"n1",type:"http request",wires:[["n2"]],method:"POST",ret:"obj",url:getTestURL('/postInspect')},
{id:"n2", type:"helper"}];
saveProxySetting();
deleteProxySetting();
process.env.HTTP_PROXY = "http://localhost:" + testProxyPort;
process.env.NO_PROXY = "foo,localhost";
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
restoreProxySetting();
try {
msg.should.have.property('statusCode',200);
msg.payload.headers.should.not.have.property('x-testproxy-header','foobar');
@@ -1198,13 +1196,12 @@ describe('HTTP Request Node', function() {
it('should authenticate on proxy server', function(done) {
var flow = [{id:"n1",type:"http request", wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/proxyAuthenticate')},
{id:"n2", type:"helper"}];
saveProxySetting();
deleteProxySetting();
process.env.http_proxy = "http://foouser:barpassword@localhost:" + testProxyPort;
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
restoreProxySetting();
try {
msg.should.have.property('statusCode',200);
msg.payload.should.have.property('user', 'foouser');
@@ -1223,13 +1220,12 @@ describe('HTTP Request Node', function() {
it('should output an error when proxy authentication was failed', function(done) {
var flow = [{id:"n1",type:"http request", wires:[["n2"]],method:"GET",ret:"obj",url:getTestURL('/proxyAuthenticate')},
{id:"n2", type:"helper"}];
saveProxySetting();
deleteProxySetting();
process.env.http_proxy = "http://xxxuser:barpassword@localhost:" + testProxyPort;
helper.load(httpRequestNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
restoreProxySetting();
try {
msg.should.have.property('statusCode',407);
msg.headers.should.have.property('proxy-authenticate', 'BASIC realm="test"');

View File

@@ -19,6 +19,7 @@ var should = require("should");
var stoppable = require('stoppable');
var helper = require("node-red-node-test-helper");
var tcpinNode = require("../../../../nodes/core/io/31-tcpin.js");
const RED = require("../../../../red/red.js");
describe('TCP Request Node', function() {
@@ -28,12 +29,12 @@ describe('TCP Request Node', function() {
function startServer(done) {
port += 1;
server = stoppable(net.createServer(function(c) {
c.on('data', function(data) {
var rdata = "ACK:"+data.toString();
c.write(rdata);
});
c.on('data', function(data) {
var rdata = "ACK:"+data.toString();
c.write(rdata);
});
c.on('error', function(err) {
startServer(done);
startServer(done);
});
})).listen(port, "127.0.0.1", function(err) {
done();
@@ -64,48 +65,108 @@ describe('TCP Request Node', function() {
done(err);
}
});
if((typeof val0) === 'object') {
n1.receive(val0);
} else {
n1.receive({payload:val0});
}
if((typeof val0) === 'object') {
n1.receive(val0);
} else {
n1.receive({payload:val0});
}
});
}
it('should send & recv data', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, "foo", "ACK:foo", done)
function testTCPMany(flow, values, result, done) {
helper.load(tcpinNode, flow, () => {
const n1 = helper.getNode("n1");
const n2 = helper.getNode("n2");
n2.on("input", msg => {
try {
msg.should.have.property('payload', Buffer(result));
done();
} catch(err) {
done(err);
}
});
values.forEach(value => {
n1.receive(typeof value === 'object' ? value : {payload: value});
});
});
}
describe('single message', function () {
it('should send & recv data', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, "foo", "ACK:foo", done)
});
it('should send & recv data when specified character received', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"char", splitc: "0", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, "foo0bar0", "ACK:foo0", done);
});
it('should send & recv data after fixed number of chars received', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"count", splitc: "7", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, "foo bar", "ACK:foo", done);
});
it('should send & receive, then keep connection', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, "foo", "ACK:foo", done);
});
it('should send & recv data to/from server:port from msg', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, {payload:"foo", host:"localhost", port:port}, "ACK:foo", done)
});
});
it('should send & recv data when specified character received', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"char", splitc: "0", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, "foo0bar0", "ACK:foo0", done);
});
describe('many messages', function () {
it('should send & recv data', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"time", splitc: "0", wires:[["n2"]] },
{id:"n2", type:"helper"}];
it('should send & recv data after fixed number of chars received', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"count", splitc: "7", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, "foo bar", "ACK:foo", done);
});
testTCPMany(flow, ['f', 'o', 'o'], 'ACK:foo', done);
});
it('should send & receive, then keep connection', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, "foo", "ACK:foo", done);
});
it('should send & recv data when specified character received', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"char", splitc: "0", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCPMany(flow, ["foo0","bar0"], "ACK:foo0", done);
});
it('should send & close', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, "foo", "ACK:foo", done);
});
it('should send & recv data after fixed number of chars received', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"count", splitc: "7", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCPMany(flow, ["fo", "ob", "ar"], "ACK:foo", done);
});
it('should send & recv data to/from server:port from msg', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCP(flow, {payload:"foo", host:"localhost", port:port}, "ACK:foo", done)
});
it('should send & receive, then keep connection', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCPMany(flow, ["foo", "bar", "baz"], "ACK:foobarbaz", done);
});
it('should send & recv data to/from server:port from msg', function(done) {
var flow = [{id:"n1", type:"tcp request", server:"", port:"", out:"time", splitc: "0", wires:[["n2"]] },
{id:"n2", type:"helper"}];
testTCPMany(flow, [
{payload:"f", host:"localhost", port:port},
{payload:"o", host:"localhost", port:port},
{payload:"o", host:"localhost", port:port}], "ACK:foo", done);
});
it('should limit the queue size', function (done) {
RED.settings.tcpMsgQueueSize = 10;
var flow = [{id:"n1", type:"tcp request", server:"localhost", port:port, out:"sit", splitc: "5", wires:[["n2"]] },
{id:"n2", type:"helper"}];
// create one more msg than is allowed
const msgs = new Array(RED.settings.tcpMsgQueueSize + 1).fill('x');
const expected = msgs.slice(0, -1);
testTCPMany(flow, msgs, "ACK:" + expected.join(''), done);
});
});
});

View File

@@ -19,6 +19,7 @@ var should = require("should");
var switchNode = require("../../../../nodes/core/logic/10-switch.js");
var helper = require("node-red-node-test-helper");
var RED = require("../../../../red/red.js");
var Context = require("../../../../red/runtime/nodes/context");
describe('switch Node', function() {
@@ -26,10 +27,31 @@ describe('switch Node', function() {
helper.startServer(done);
});
function initContext(done) {
Context.init({
contextStorage: {
memory0: {
module: "memory"
},
memory1: {
module: "memory"
}
}
});
Context.load().then(function () {
done();
});
}
afterEach(function(done) {
helper.unload();
RED.settings.nodeMessageBufferMaxLength = 0;
helper.stopServer(done);
helper.unload().then(function () {
return Context.clean({allNodes: {}});
}).then(function () {
return Context.close();
}).then(function () {
RED.settings.nodeMessageBufferMaxLength = 0;
helper.stopServer(done);
});
});
it('should be loaded with some defaults', function(done) {
@@ -125,7 +147,7 @@ describe('switch Node', function() {
helper.load(switchNode, flow, function() {
var switchNode1 = helper.getNode("switchNode1");
var helperNode1 = helper.getNode("helperNode1");
var sid = undefined;
var sid;
var count = 0;
if (modifier !== undefined) {
modifier(switchNode1);
@@ -293,6 +315,102 @@ describe('switch Node', function() {
genericSwitchTest("istype", "undefined", true, true, undefined, done);
});
it('should handle flow context', function (done) {
var flow = [{"id": "switchNode1", "type": "switch", "property": "foo", "propertyType": "flow",
"rules": [{"t": "eq", "v": "bar", "vt": "flow"}],
"checkall": "true", "outputs": "1", "wires": [["helperNode1"]], "z": "flow"},
{"id": "helperNode1", "type": "helper", "wires": []}];
helper.load(switchNode, flow, function () {
var switchNode1 = helper.getNode("switchNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function (msg) {
try {
msg.payload.should.equal("value");
done();
} catch (err) {
done(err);
}
});
switchNode1.context().flow.set("foo", "flowValue");
switchNode1.context().flow.set("bar", "flowValue");
switchNode1.receive({payload: "value"});
});
});
it('should handle persistable flow context', function (done) {
var flow = [{"id": "switchNode1", "type": "switch", "property": "#:(memory1)::foo", "propertyType": "flow",
"rules": [{"t": "eq", "v": "#:(memory1)::bar", "vt": "flow"}],
"checkall": "true", "outputs": "1", "wires": [["helperNode1"]], "z": "flow"},
{"id": "helperNode1", "type": "helper", "wires": []}];
helper.load(switchNode, flow, function () {
initContext(function () {
var switchNode1 = helper.getNode("switchNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function (msg) {
try {
msg.payload.should.equal("value");
done();
} catch (err) {
done(err);
}
});
switchNode1.context().flow.set("foo", "flowValue", "memory1", function (err) {
switchNode1.context().flow.set("bar", "flowValue", "memory1", function (err) {
switchNode1.receive({payload: "value"});
});
});
});
});
});
it('should handle global context', function (done) {
var flow = [{"id": "switchNode1", "type": "switch", "property": "foo", "propertyType": "global",
"rules": [{"t": "eq", "v": "bar", "vt": "global"}],
"checkall": "true", "outputs": "1", "wires": [["helperNode1"]]},
{"id": "helperNode1", "type": "helper", "wires": []}];
helper.load(switchNode, flow, function () {
var switchNode1 = helper.getNode("switchNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function (msg) {
try {
msg.payload.should.equal("value");
done();
} catch (err) {
done(err);
}
});
switchNode1.context().global.set("foo", "globalValue");
switchNode1.context().global.set("bar", "globalValue");
switchNode1.receive({payload: "value"});
});
});
it('should handle persistable global context', function (done) {
var flow = [{"id": "switchNode1", "type": "switch", "property": "#:(memory1)::foo", "propertyType": "global",
"rules": [{"t": "eq", "v": "#:(memory1)::bar", "vt": "global"}],
"checkall": "true", "outputs": "1", "wires": [["helperNode1"]]},
{"id": "helperNode1", "type": "helper", "wires": []}];
helper.load(switchNode, flow, function () {
initContext(function () {
var switchNode1 = helper.getNode("switchNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function (msg) {
try {
msg.payload.should.equal("foo");
done();
} catch (err) {
done(err);
}
});
switchNode1.context().global.set("foo", "globalValue", "memory1", function (err) {
switchNode1.context().global.set("bar", "globalValue", "memory1", function (err) {
switchNode1.receive({payload: "foo"});
});
});
});
});
});
it('should match regex with ignore-case flag set true', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"regex","v":"onetwothree","case":true}],checkall:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -333,6 +451,75 @@ describe('switch Node', function() {
singularSwitchTest(false, true, false, true, done);
});
it('should check if payload is empty (string)', function(done) {
singularSwitchTest("empty", true, true, "", done);
});
it('should check if payload is empty (array)', function(done) {
singularSwitchTest("empty", true, true, [], done);
});
it('should check if payload is empty (buffer)', function(done) {
singularSwitchTest("empty", true, true, Buffer.alloc(0), done);
});
it('should check if payload is empty (object)', function(done) {
singularSwitchTest("empty", true, true, {}, done);
});
it('should check if payload is empty (non-empty string)', function(done) {
singularSwitchTest("empty", true, false, "1", done);
});
it('should check if payload is empty (non-empty array)', function(done) {
singularSwitchTest("empty", true, false, [1], done);
});
it('should check if payload is empty (non-empty buffer)', function(done) {
singularSwitchTest("empty", true, false, Buffer.alloc(1), done);
});
it('should check if payload is empty (non-empty object)', function(done) {
singularSwitchTest("empty", true, false, {a:1}, done);
});
it('should check if payload is empty (null)', function(done) {
singularSwitchTest("empty", true, false, null, done);
});
it('should check if payload is empty (undefined)', function(done) {
singularSwitchTest("empty", true, false, undefined, done);
});
it('should check if payload is empty (0)', function(done) {
singularSwitchTest("empty", true, false, 0, done);
});
it('should check if payload is not empty (string)', function(done) {
singularSwitchTest("nempty", true, !true, "", done);
});
it('should check if payload is not empty (array)', function(done) {
singularSwitchTest("nempty", true, !true, [], done);
});
it('should check if payload is not empty (buffer)', function(done) {
singularSwitchTest("nempty", true, !true, Buffer.alloc(0), done);
});
it('should check if payload is not empty (object)', function(done) {
singularSwitchTest("nempty", true, !true, {}, done);
});
it('should check if payload is not empty (non-empty string)', function(done) {
singularSwitchTest("nempty", true, !false, "1", done);
});
it('should check if payload is not empty (non-empty array)', function(done) {
singularSwitchTest("nempty", true, !false, [1], done);
});
it('should check if payload is not empty (non-empty buffer)', function(done) {
singularSwitchTest("nempty", true, !false, Buffer.alloc(1), done);
});
it('should check if payload is not empty (non-empty object)', function(done) {
singularSwitchTest("nempty", true, !false, {a:1}, done);
});
it('should check if payload is not empty (null)', function(done) {
singularSwitchTest("nempty", true, false, null, done);
});
it('should check if payload is not empty (undefined)', function(done) {
singularSwitchTest("nempty", true, false, undefined, done);
});
it('should check if payload is not empty (0)', function(done) {
singularSwitchTest("nempty", true, false, 0, done);
});
it('should check input against a previous value', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{ "t": "gt", "v": "", "vt": "prev" }],checkall:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -460,7 +647,7 @@ describe('switch Node', function() {
} catch(err) {
done(err);
}
},100)
},500)
});
});
@@ -584,6 +771,53 @@ describe('switch Node', function() {
customFlowSwitchTest(flow, true, -5, done);
});
it('should handle flow and global contexts with JSONata expression', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"$abs($flowContext(\"payload\"))",propertyType:"jsonata",rules:[{"t":"btwn","v":"$flowContext(\"vt\")","vt":"jsonata","v2":"$globalContext(\"v2t\")","v2t":"jsonata"}],checkall:true,outputs:1,wires:[["helperNode1"]],z:"flow"},
{id:"helperNode1", type:"helper", wires:[],z:"flow"},
{id:"flow",type:"tab"}];
helper.load(switchNode, flow, function() {
var switchNode1 = helper.getNode("switchNode1");
var helperNode1 = helper.getNode("helperNode1");
switchNode1.context().flow.set("payload",-5);
switchNode1.context().flow.set("vt",4);
switchNode1.context().global.set("v2t",6);
helperNode1.on("input", function(msg) {
try {
should.equal(msg.payload,"pass");
done();
} catch(err) {
done(err);
}
});
switchNode1.receive({payload:"pass"});
});
});
it('should handle persistable flow and global contexts with JSONata expression', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"$abs($flowContext(\"payload\",\"memory1\"))",propertyType:"jsonata",rules:[{"t":"btwn","v":"$flowContext(\"vt\",\"memory1\")","vt":"jsonata","v2":"$globalContext(\"v2t\",\"memory1\")","v2t":"jsonata"}],checkall:true,outputs:1,wires:[["helperNode1"]],z:"flow"},
{id:"helperNode1", type:"helper", wires:[],z:"flow"},
{id:"flow",type:"tab"}];
helper.load(switchNode, flow, function() {
initContext(function () {
var switchNode1 = helper.getNode("switchNode1");
var helperNode1 = helper.getNode("helperNode1");
switchNode1.context().flow.set(["payload","vt"],[-7,6],"memory1",function(){
switchNode1.context().global.set("v2t",8,"memory1",function(){
helperNode1.on("input", function(msg) {
try {
should.equal(msg.payload,"pass");
done();
} catch(err) {
done(err);
}
});
switchNode1.receive({payload:"pass"});
});
});
});
});
});
it('should take head of message sequence (no repair)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"head","v":3}],checkall:false,repair:false,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -599,7 +833,7 @@ describe('switch Node', function() {
it('should take head of message sequence (w. context)', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"head","v":"count",vt:"global"}],checkall:false,repair:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [0, 1, 2], true,
customFlowSequenceSwitchTest(flow, [0, 1, 2, 3, 4], [0, 1, 2], true,
function(node) {
node.context().global.set("count", 3);
}, done);
@@ -642,7 +876,7 @@ describe('switch Node', function() {
{id:"helperNode1", type:"helper", wires:[]}];
customFlowSwitchTest(flow, true, 9, done);
});
it('should be able to use $I in JSONata expression', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"payload",rules:[{"t":"jsonata_exp","v":"$I % 2 = 1",vt:"jsonata"}],checkall:true,repair:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -666,9 +900,11 @@ describe('switch Node', function() {
var vals = new Array(port_count);
var recv_count = 0;
for (var id in outs) {
var out = outs[id];
vals[out.port] = out.vals;
recv_count += out.vals.length;
if (outs.hasOwnProperty(id)) {
var out = outs[id];
vals[out.port] = out.vals;
recv_count += out.vals.length;
}
}
var count = 0;
function check_msg(msg, ix, vf) {
@@ -676,7 +912,7 @@ describe('switch Node', function() {
msg.should.have.property("payload");
var payload = msg.payload;
msg.should.have.property("parts");
vf(payload).should.be.ok;
vf(payload).should.be.ok();
var parts = msg.parts;
var evals = vals[ix];
parts.should.have.property("id");
@@ -703,8 +939,8 @@ describe('switch Node', function() {
}
var index = parts.index;
var eindex = counts[ix];
var eval = evals[eindex];
payload.should.equal(eval);
var value = evals[eindex];
payload.should.equal(value);
counts[ix]++;
count++;
if (count === recv_count) {
@@ -716,18 +952,22 @@ describe('switch Node', function() {
}
}
for (var id in outs) {
(function() {
var node = helper.getNode(id);
var port = outs[id].port;
var vf = outs[id].vf;
node.on("input", function(msg) {
check_msg(msg, port, vf);
});
})();
if (outs.hasOwnProperty(id)) {
(function() {
var node = helper.getNode(id);
var port = outs[id].port;
var vf = outs[id].vf;
node.on("input", function(msg) {
check_msg(msg, port, vf);
});
})();
}
}
for(var i in seq_in) {
n1.receive({payload:seq_in[i], xindex:i,
parts:{index:i, count:seq_in.length, id:222}});
if (seq_in.hasOwnProperty(i)) {
n1.receive({payload:seq_in[i], xindex:i,
parts:{index:i, count:seq_in.length, id:222}});
}
}
});
}
@@ -786,9 +1026,9 @@ describe('switch Node', function() {
var data = [ 1, -2, 2, 0, -1 ];
var outs = {
"n2" : { port:0, vals:[1, 2, 0],
vf:function(x) { return(x > 0); } },
vf:function(x) { return(x >= 0); } },
"n3" : { port:1, vals:[-2, 0, -1],
vf:function(x) { return(x < 0); } },
vf:function(x) { return(x <= 0); } },
"n4" : { port:2, vals:[],
vf:function(x) { return(false); } },
};
@@ -821,4 +1061,24 @@ describe('switch Node', function() {
n1.receive({payload:1, parts:{index:0, count:4, id:222}});
});
});
it('should handle invalid jsonata expression', function(done) {
var flow = [{id:"switchNode1",type:"switch",name:"switchNode",property:"$invalidExpression(payload)",propertyType:"jsonata",rules:[{"t":"btwn","v":"$sqrt(16)","vt":"jsonata","v2":"$sqrt(36)","v2t":"jsonata"}],checkall:true,outputs:1,wires:[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(switchNode, flow, function() {
var n1 = helper.getNode("switchNode1");
setTimeout(function() {
var logEvents = helper.log().args.filter(function (evt) {
return evt[0].type == "switch";
});
var evt = logEvents[0][0];
evt.should.have.property('id', "switchNode1");
evt.should.have.property('type', "switch");
done();
}, 150);
n1.receive({payload:1});
});
});
});

View File

@@ -15,8 +15,10 @@
**/
var should = require("should");
var sinon = require("sinon");
var changeNode = require("../../../../nodes/core/logic/15-change.js");
var Context = require("../../../../red/runtime/nodes/context");
var helper = require("node-red-node-test-helper");
describe('change Node', function() {
@@ -25,9 +27,30 @@ describe('change Node', function() {
helper.startServer(done);
});
function initContext(done) {
Context.init({
contextStorage: {
memory0: {
module: "memory"
},
memory1: {
module: "memory"
}
}
});
Context.load().then(function () {
done();
});
}
afterEach(function(done) {
helper.unload();
helper.stopServer(done);
helper.unload().then(function () {
return Context.clean({allNodes: {}});
}).then(function () {
return Context.close();
}).then(function () {
helper.stopServer(done);
});
});
it('should load node with defaults', function(done) {
@@ -95,6 +118,30 @@ describe('change Node', function() {
});
});
it('sets the value of persistable global context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t":"set","p":"#:(memory1)::globalValue","pt":"global","to":"changed","tot":"str"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
changeNode1.context().global.get("globalValue", "memory1", function (err, val) {
val.should.equal("changed");
done();
});
} catch(err) {
done(err);
}
});
changeNode1.context().global.set("globalValue","changeMe","memory1", function (err) {
changeNode1.receive({payload:""});
});
});
});
});
it('sets the value and type of the message property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "set", "p": "payload", "pt": "msg", "to": "12345", "tot": "num" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -299,6 +346,28 @@ describe('change Node', function() {
});
});
it('changes the value to persistable flow context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"set","p":"payload","to":"#:(memory1)::flowValue","tot":"flow"}],"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.payload.should.eql("Hello World!");
done();
} catch(err) {
done(err);
}
});
changeNode1.context().flow.set("flowValue","Hello World!","memory1",function(err) {
changeNode1.receive({payload:""});
});
});
});
});
it('changes the value to global context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"set","p":"payload","to":"globalValue","tot":"global"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -318,6 +387,28 @@ describe('change Node', function() {
});
});
it('changes the value to persistable global context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"set","p":"payload","to":"#:(memory1)::globalValue","tot":"global"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.payload.should.eql("Hello World!");
done();
} catch(err) {
done(err);
}
});
changeNode1.context().global.set("globalValue","Hello World!","memory1", function (err) {
changeNode1.receive({payload:""});
});
});
});
});
it('changes the value to a number', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"set","p":"payload","to":"123","tot":"num"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -454,6 +545,120 @@ describe('change Node', function() {
});
});
it('reports invalid jsonata expression', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"set","p":"payload","to":"$invalid(payload)","tot":"jsonata"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
sinon.spy(changeNode1,"error");
helperNode1.on("input", function(msg) {
done("Invalid jsonata expression passed message through");
});
changeNode1.receive({payload:"Hello World!"});
setTimeout(function() {
try {
changeNode1.error.called.should.be.true();
done();
} catch(err) {
done(err);
}
},50);
});
});
it('changes the value using flow context with jsonata', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"set","p":"payload","to":"$flowContext(\"foo\")","tot":"jsonata"}],"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"},{"id":"flow","type":"tab"}];
helper.load(changeNode, flow, function() {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
changeNode1.context().flow.set("foo","bar");
helperNode1.on("input", function(msg) {
try {
msg.payload.should.eql("bar");
done();
} catch(err) {
done(err);
}
});
changeNode1.receive({payload:"Hello World!"});
});
});
it('changes the value using global context with jsonata', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"set","p":"payload","to":"$globalContext(\"foo\")","tot":"jsonata"}],"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"},{"id":"flow","type":"tab"}];
helper.load(changeNode, flow, function() {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
changeNode1.context().global.set("foo","bar");
helperNode1.on("input", function(msg) {
try {
msg.payload.should.eql("bar");
done();
} catch(err) {
done(err);
}
});
changeNode1.receive({payload:"Hello World!"});
});
});
it('changes the value using persistable flow context with jsonata', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"set","p":"payload","to":"$flowContext(\"foo\",\"memory1\")","tot":"jsonata"}],"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"},{"id":"flow","type":"tab"}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.payload.should.eql("bar");
done();
} catch(err) {
done(err);
}
});
changeNode1.context().flow.set("foo","bar","memory1",function(err){
if(err){
done(err);
}else{
changeNode1.context().flow.set("foo","error!");
changeNode1.receive({payload:"Hello World!"});
}
});
});
});
});
it('changes the value using persistable global context with jsonata', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"set","p":"payload","to":"$globalContext(\"foo\",\"memory1\")","tot":"jsonata"}],"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"},{"id":"flow","type":"tab"}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.payload.should.eql("bar");
done();
} catch(err) {
done(err);
}
});
changeNode1.context().global.set("foo","bar","memory1",function(err){
if(err){
done(err);
}else{
changeNode1.context().global.set("foo","error!");
changeNode1.receive({payload:"Hello World!"});
}
});
});
});
});
});
describe('#change', function() {
it('changes the value of the message property', function(done) {
@@ -693,6 +898,28 @@ describe('change Node', function() {
});
});
it('changes the value using persistable flow context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"change","p":"payload","from":"#:(memory1)::topic","to":"123","fromt":"flow","tot":"str"}],"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.payload.should.equal("abc123abc");
done();
} catch(err) {
done(err);
}
});
changeNode1.context().flow.set("topic","ABC","memory1", function (err) {
changeNode1.receive({payload:"abcABCabc"});
});
});
});
});
it('changes the value using global context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"change","p":"payload","from":"topic","to":"123","fromt":"global","tot":"str"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -712,6 +939,28 @@ describe('change Node', function() {
});
});
it('changes the value using persistable global context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"change","p":"payload","from":"#:(memory1)::topic","to":"123","fromt":"global","tot":"str"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.payload.should.equal("abc123abc");
done();
} catch(err) {
done(err);
}
});
changeNode1.context().global.set("topic","ABC","memory1",function (err) {
changeNode1.receive({payload:"abcABCabc"});
});
});
});
});
it('changes the number using global context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"change","p":"payload","from":"topic","to":"ABC","fromt":"global","tot":"str"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -731,6 +980,28 @@ describe('change Node', function() {
});
});
it('changes the number using persistable global context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"change","p":"payload","from":"#:(memory1)::topic","to":"ABC","fromt":"global","tot":"str"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.payload.should.equal("ABC");
done();
} catch(err) {
done(err);
}
});
changeNode1.context().global.set("topic",123,"memory1",function (err) {
changeNode1.receive({payload:123});
});
});
});
});
it('changes the value using number - string payload', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"change","p":"payload","from":"123","to":"456","fromt":"num","tot":"str"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -822,6 +1093,30 @@ describe('change Node', function() {
});
});
it('changes the value of the persistable global context', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "change", "p": "#:(memory1)::payload", "pt": "global", "from": "Hello", "fromt": "str", "to": "Goodbye", "tot": "str" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
helperNode1.context().global.get("payload","memory1", function (err, val) {
val.should.equal("Goodbye World!");
done();
});
} catch(err) {
done(err);
}
});
changeNode1.context().global.set("payload","Hello World!","memory1",function (err) {
changeNode1.receive({payload:""});
});
});
});
});
it('changes the value and doesnt change type of the flow context for partial match', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "change", "p": "payload", "pt": "flow", "from": "123", "fromt": "str", "to": "456", "tot": "num" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"}];
@@ -842,6 +1137,31 @@ describe('change Node', function() {
});
});
it('changes the value and doesnt change type of the persistable flow context for partial match', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "change", "p": "#:(memory1)::payload", "pt": "flow", "from": "123", "fromt": "str", "to": "456", "tot": "num" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
helperNode1.context().flow.get("payload","memory1",function (err, val) {
val.should.equal("Change456Me");
val.should.be.a.String();
done();
});
} catch(err) {
done(err);
}
});
changeNode1.context().flow.set("payload","Change123Me","memory1",function (err) {
changeNode1.receive({payload:""});
});
});
});
});
it('changes the value and type of the flow context if a complete match', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "change", "p": "payload", "pt": "flow", "from": "123", "fromt": "str", "to": "456", "tot": "num" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"}];
@@ -862,6 +1182,31 @@ describe('change Node', function() {
});
});
it('changes the value and type of the persistable flow context if a complete match', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "change", "p": "#:(memory1)::payload", "pt": "flow", "from": "123", "fromt": "str", "to": "456", "tot": "num" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
helperNode1.context().flow.get("payload","memory1",function (err, val) {
val.should.be.a.Number();
val.should.equal(456);
done();
});
} catch(err) {
done(err);
}
});
changeNode1.context().flow.set("payload","123","memory1",function (err) {
changeNode1.receive({payload:""});
});
});
});
});
it('changes the value using number - number flow context', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "change", "p": "payload", "pt": "flow", "from": "123", "fromt": "num", "to": "abc", "tot": "str" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"}];
@@ -881,6 +1226,30 @@ describe('change Node', function() {
});
});
it('changes the value using number - number persistable flow context', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "change", "p": "#:(memory1)::payload", "pt": "flow", "from": "123", "fromt": "num", "to": "abc", "tot": "str" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
helperNode1.context().flow.get("payload","memory1",function (err, val) {
val.should.equal("abc");
done();
});
} catch(err) {
done(err);
}
});
changeNode1.context().flow.set("payload",123,"memory1",function (err) {
changeNode1.receive({payload:""});
});
});
});
});
it('changes the value using boolean - boolean flow context', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "change", "p": "payload", "pt": "flow", "from": "true", "fromt": "bool", "to": "abc", "tot": "str" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"}];
@@ -900,6 +1269,49 @@ describe('change Node', function() {
});
});
it('changes the value using boolean - boolean persistable flow context', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "change", "p": "#:(memory1)::payload", "pt": "flow", "from": "true", "fromt": "bool", "to": "abc", "tot": "str" }],"reg":false,"name":"changeNode","wires":[["helperNode1"]],"z":"flow"},
{id:"helperNode1", type:"helper", wires:[],"z":"flow"}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
helperNode1.context().flow.get("payload","memory1",function (err, val) {
val.should.equal("abc");
done();
});
} catch(err) {
done(err);
}
});
changeNode1.context().flow.set("payload",true,"memory1",function (err) {
changeNode1.receive({payload:""});
});
});
});
});
it('reports invalid fromValue', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{"t":"change","p":"payload","from":"null","fromt":"msg","to":"abc","tot":"str"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
var changeNode1 = helper.getNode("changeNode1");
setTimeout(function() {
var logEvents = helper.log().args.filter(function (evt) {
return evt[0].type == "change";
});
logEvents.should.have.length(1);
var msg = logEvents[0][0];
msg.should.have.property('level', helper.log().ERROR);
msg.should.have.property('id', 'changeNode1');
done();
},25);
changeNode1.receive({payload:"",null:null});
});
});
describe('env var', function() {
before(function() {
process.env.NR_TEST_A = 'foo';
@@ -966,6 +1378,30 @@ describe('change Node', function() {
});
});
it('deletes the value of persistable global context property', function(done) {
var flow = [{"id":"changeNode1","type":"change",rules:[{ "t": "delete", "p": "#:(memory1)::globalValue", "pt": "global"}],"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
changeNode1.context().global.get("globalValue","memory1",function(err,val) {
should.equal(undefined);
done();
});
} catch(err) {
done(err);
}
});
changeNode1.context().global.set("globalValue","Hello World!","memory1",function (err) {
changeNode1.receive({payload:""});
});
});
});
});
it('deletes the value of a multi-level message property', function(done) {
var flow = [{"id":"changeNode1","type":"change","action":"delete","property":"foo.bar","from":"","to":"","reg":false,"name":"changeNode","wires":[["helperNode1"]]},
{id:"helperNode1", type:"helper", wires:[]}];
@@ -1133,6 +1569,7 @@ describe('change Node', function() {
});
});
});
it('applies multiple rules in order', function(done) {
var flow = [{"id":"changeNode1","type":"change","wires":[["helperNode1"]],
rules:[
@@ -1157,5 +1594,101 @@ describe('change Node', function() {
});
});
});
it('can access two persistable flow context property', function(done) {
var flow = [{"id":"changeNode1", "z":"t1", "type":"change",
"wires":[["helperNode1"]],
rules:[
{"t":"set", "p":"val0", "to":"#:(memory0)::val", "tot":"flow"},
{"t":"set", "p":"val1", "to":"#:(memory1)::val", "tot":"flow"}
]},
{id:"helperNode1", "z":"t1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.should.have.property("val0", "foo");
msg.should.have.property("val1", "bar");
done();
} catch(err) {
done(err);
}
});
var flow = changeNode1.context().flow;
flow.set("val", "foo", "memory0", function (err) {
flow.set("val", "bar", "memory1", function (err) {
changeNode1.receive({payload:""});
});
});
});
});
});
it('can access two persistable global context property', function(done) {
var flow = [{"id":"changeNode1", "z":"t1", "type":"change",
"wires":[["helperNode1"]],
rules:[
{"t":"set", "p":"val0", "to":"#:(memory0)::val", "tot":"global"},
{"t":"set", "p":"val1", "to":"#:(memory1)::val", "tot":"global"}
]},
{id:"helperNode1", "z":"t1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.should.have.property("val0", "foo");
msg.should.have.property("val1", "bar");
done();
} catch(err) {
done(err);
}
});
var global = changeNode1.context().global;
global.set("val", "foo", "memory0", function (err) {
global.set("val", "bar", "memory1", function (err) {
changeNode1.receive({payload:""});
});
});
});
});
});
it('can access persistable global & flow context property', function(done) {
var flow = [{"id":"changeNode1", "z":"t1", "type":"change",
"wires":[["helperNode1"]],
rules:[
{"t":"set", "p":"val0", "to":"#:(memory0)::val", "tot":"flow"},
{"t":"set", "p":"val1", "to":"#:(memory1)::val", "tot":"global"}
]},
{id:"helperNode1", "z":"t1", type:"helper", wires:[]}];
helper.load(changeNode, flow, function() {
initContext(function () {
var changeNode1 = helper.getNode("changeNode1");
var helperNode1 = helper.getNode("helperNode1");
helperNode1.on("input", function(msg) {
try {
msg.should.have.property("val0", "foo");
msg.should.have.property("val1", "bar");
done();
} catch(err) {
done(err);
}
});
var context = changeNode1.context();
var flow = context.flow;
var global = context.global;
flow.set("val", "foo", "memory0", function (err) {
global.set("val", "bar", "memory1", function (err) {
changeNode1.receive({payload:""});
});
});
});
});
});
});
});

View File

@@ -19,6 +19,9 @@ var splitNode = require("../../../../nodes/core/logic/17-split.js");
var joinNode = require("../../../../nodes/core/logic/17-split.js");
var helper = require("node-red-node-test-helper");
var RED = require("../../../../red/red.js");
var Context = require("../../../../red/runtime/nodes/context");
var TimeoutForErrorCase = 20;
describe('SPLIT node', function() {
@@ -264,21 +267,156 @@ describe('SPLIT node', function() {
});
});
it('should handle invalid spltType (not an array)', function (done) {
var flow = [{ id: "sn1", type: "split", splt: "1", spltType: "bin", wires: [["sn2"]] },
{ id: "sn2", type: "helper" }];
helper.load(splitNode, flow, function () {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
setTimeout(function () {
done();
}, TimeoutForErrorCase);
sn2.on("input", function (msg) {
done(new Error("This path does not go through."));
});
sn1.receive({ payload: "123" });
});
});
it('should handle invalid splt length', function (done) {
var flow = [{ id: "sn1", type: "split", splt: 0, spltType: "len", wires: [["sn2"]] },
{ id: "sn2", type: "helper" }];
helper.load(splitNode, flow, function () {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
setTimeout(function () {
done();
}, TimeoutForErrorCase);
sn2.on("input", function (msg) {
done(new Error("This path does not go through."));
});
sn1.receive({ payload: "123" });
});
});
it('should handle invalid array splt length', function (done) {
var flow = [{ id: "sn1", type: "split", arraySplt: 0, arraySpltType: "len", wires: [["sn2"]] },
{ id: "sn2", type: "helper" }];
helper.load(splitNode, flow, function () {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
setTimeout(function () {
done();
}, TimeoutForErrorCase);
sn2.on("input", function (msg) {
done(new Error("This path does not go through."));
});
sn1.receive({ payload: "123" });
});
});
it('should ceil count value when msg.payload type is string', function (done) {
var flow = [{ id: "sn1", type: "split", splt: "2", spltType: "len", wires: [["sn2"]] },
{ id: "sn2", type: "helper" }];
helper.load(splitNode, flow, function () {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
sn2.on("input", function (msg) {
msg.should.have.property("parts");
msg.parts.should.have.property("count", 2);
msg.parts.should.have.property("index");
if (msg.parts.index === 0) { msg.payload.length.should.equal(2); }
if (msg.parts.index === 1) { msg.payload.length.should.equal(1); done(); }
});
sn1.receive({ payload: "123" });
});
});
it('should handle spltBufferString value of undefined', function (done) {
var flow = [{ id: "sn1", type: "split", wires: [["sn2"]], splt: "[52]", spltType: "bin" },
{ id: "sn2", type: "helper" }];
helper.load(splitNode, flow, function () {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
sn2.on("input", function (msg) {
try {
msg.should.have.property("parts");
msg.parts.should.have.property("index");
if (msg.parts.index === 0) { msg.payload.toString().should.equal("123"); done(); }
} catch (err) {
done(err);
}
});
sn1.receive({ payload: "123" });
});
});
it('should ceil count value when msg.payload type is Buffer', function (done) {
var flow = [{ id: "sn1", type: "split", splt: "2", spltType: "len", wires: [["sn2"]] },
{ id: "sn2", type: "helper" }];
helper.load(splitNode, flow, function () {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
sn2.on("input", function (msg) {
msg.should.have.property("parts");
msg.parts.should.have.property("count", 2);
msg.parts.should.have.property("index");
if (msg.parts.index === 0) { msg.payload.length.should.equal(2); }
if (msg.parts.index === 1) { msg.payload.length.should.equal(1); done(); }
});
var b = new Buffer.from("123");
sn1.receive({ payload: b });
});
});
it('should set msg.parts.ch when node.spltType is str', function (done) {
var flow = [{ id: "sn1", type: "split", splt: "2", spltType: "str", stream: false, wires: [["sn2"]] },
{ id: "sn2", type: "helper" }];
helper.load(splitNode, flow, function () {
var sn1 = helper.getNode("sn1");
var sn2 = helper.getNode("sn2");
sn2.on("input", function (msg) {
msg.should.have.property("parts");
msg.parts.should.have.property("count", 2);
msg.parts.should.have.property("index");
if (msg.parts.index === 0) { msg.payload.length.should.equal(2); }
if (msg.parts.index === 1) { msg.payload.length.should.equal(1); done(); }
});
var b = new Buffer.from("123");
sn1.receive({ payload: b });
});
});
});
describe('JOIN node', function() {
before(function(done) {
beforeEach(function(done) {
helper.startServer(done);
});
after(function(done) {
helper.stopServer(done);
});
function initContext(done) {
Context.init({
contextStorage: {
memory: {
module: "memory"
}
}
});
Context.load().then(function () {
done();
});
}
afterEach(function() {
helper.unload();
RED.settings.nodeMessageBufferMaxLength = 0;
afterEach(function(done) {
helper.unload().then(function(){
return Context.clean({allNodes:{}});
}).then(function(){
return Context.close();
}).then(function(){
RED.settings.nodeMessageBufferMaxLength = 0;
helper.stopServer(done);
});
});
it('should be loaded', function(done) {
@@ -696,6 +834,57 @@ describe('JOIN node', function() {
});
});
it('should manually join things into an array, send when told complete', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:1, mode:"custom", build:"array"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array();
msg.payload.length.should.equal(3);
msg.payload[0].should.equal(1);
msg.payload[1].should.equal(2);
msg.payload[2].should.equal(3);
done();
}
catch(e) { done(e); }
});
n1.receive({payload:1, topic:"A"});
n1.receive({payload:2, topic:"B"});
n1.receive({payload:3, topic:"C"});
n1.receive({complete:true});
});
});
it('should manually join things into an object, send when told complete', function(done) {
var flow = [{id:"n1", type:"join", wires:[["n2"]], timeout:1, mode:"custom", build:"object"},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Object();
Object.keys(msg.payload).length.should.equal(3);
msg.payload.A.should.equal(1);
msg.payload.B.should.equal(2);
msg.payload.C.should.equal(3);
done();
}
catch(e) { done(e); }
});
n1.receive({payload:1, topic:"A"});
n1.receive({payload:2, topic:"B"});
n1.receive({payload:3, topic:"C"});
n1.receive({complete:true});
});
});
it('should join split strings back into a word', function(done) {
var flow = [{id:"n1", type:"join", mode:"auto", wires:[["n2"]]},
{id:"n2", type:"helper"}];
@@ -739,7 +928,7 @@ describe('JOIN node', function() {
});
});
it('should redece messages', function(done) {
it('should reduce messages', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$A+payload",
@@ -767,7 +956,137 @@ describe('JOIN node', function() {
});
});
it('should redece messages using $I', function(done) {
it('should reduce messages - count only in last part', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$A+payload",
reduceInit:"0",
reduceInitType:"num",
reduceFixup:undefined,
wires:[["n2"]]},
{id:"n2", type:"helper"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.equal(10);
done();
}
catch(e) { done(e); }
});
n1.receive({payload:3, parts:{index:2, id:222}});
n1.receive({payload:2, parts:{index:1, id:222}});
n1.receive({payload:4, parts:{index:3, count:4,id:222}});
n1.receive({payload:1, parts:{index:0, id:222}});
});
});
function checkInitTypes(itype, ival, rval, initializer, checker, done) {
var flow = [{id:"n1", z:"f0", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$A",
reduceInit:ival,
reduceInitType:itype,
reduceFixup:undefined,
wires:[["n2"]]},
{id:"n2", type:"helper"}];
if (!initializer) {
initializer = (node, cb) => {
cb();
};
}
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
initializer(n1, function () {
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
checker(msg.payload, rval);
done();
}
catch(e) { done(e); }
});
n1.receive({payload:3, parts:{index:2, count:4, id:222}});
n1.receive({payload:2, parts:{index:1, count:4, id:222}});
n1.receive({payload:4, parts:{index:3, count:4, id:222}});
n1.receive({payload:1, parts:{index:0, count:4, id:222}});
});
});
}
function checkInitTypesSimple(itype, val, done) {
checkInitTypes(itype, val, val, undefined, should.equal, done);
}
function checkInitTypesComplex(itype, ival, rval, done) {
checkInitTypes(itype, ival, rval, undefined, should.deepEqual, done);
}
it('should reduce messages with init types (str)', function(done) {
checkInitTypesSimple('str', "xyz", done);
});
it('should reduce messages with init types (num)', function(done) {
checkInitTypesSimple('num', 10, done);
});
it('should reduce messages with init types (bool)', function(done) {
checkInitTypesSimple('bool', true, done);
});
it('should reduce messages with init types (json)', function(done) {
var ival = '{"x":"vx", "y":"vy", "z":"vz"}';
var rval = JSON.parse(ival);
checkInitTypesComplex('json', ival, rval, done);
});
it('should reduce messages with init types (bin)', function(done) {
var ival = "[1,2,3]";
var rval = Buffer.from(JSON.parse(ival));
checkInitTypesComplex('bin', ival, rval, done);
});
it('should reduce messages with init types (JSONata)', function(done) {
var ival = "1+2+3";
var rval = 6;
checkInitTypesComplex('jsonata', ival, rval, done);
});
it('should reduce messages with init types (env)', function(done) {
function init(node, cb) {
process.env.NR_XYZ = "nr_xyz";
cb();
}
function fin(err) {
delete process.env.NR_XYZ;
done(err);
}
checkInitTypes('env', "NR_XYZ", "nr_xyz", init, should.equal, fin);
});
it('should reduce messages with init types (flow.name)', function(done) {
function init(node, cb) {
var context = node.context();
context.flow.set("foo", "bar");
cb();
}
checkInitTypes('flow', "foo", "bar", init, should.equal, done);
});
it('should reduce messages with init types (global.name)', function(done) {
function init(node, cb) {
var context = node.context();
context.global.set("foo", "bar");
cb();
}
checkInitTypes('global', "foo", "bar", init, should.equal, done);
});
it('should reduce messages using $I', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$A+$I",
@@ -795,7 +1114,7 @@ describe('JOIN node', function() {
});
});
it('should redece messages with fixup', function(done) {
it('should reduce messages with fixup', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$A+payload",
@@ -824,7 +1143,7 @@ describe('JOIN node', function() {
});
});
it('should redece messages (left)', function(done) {
it('should reduce messages (left)', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"'(' & $A & '+' & payload & ')'",
@@ -853,7 +1172,7 @@ describe('JOIN node', function() {
});
});
it('should redece messages (right)', function(done) {
it('should reduce messages (right)', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:true,
reduceExp:"'(' & $A & '+' & payload & ')'",
@@ -882,7 +1201,7 @@ describe('JOIN node', function() {
});
});
it('should redece messages with array result', function(done) {
it('should reduce messages with array result', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$append($A,[payload])",
@@ -942,7 +1261,7 @@ describe('JOIN node', function() {
evt.should.have.property('type', "join");
evt.should.have.property('msg', "join.too-many");
done();
}, 150);
}, TimeoutForErrorCase);
n1.receive({payload:3, parts:{index:2, count:4, id:222}});
n1.receive({payload:2, parts:{index:1, count:4, id:222}});
n1.receive({payload:4, parts:{index:3, count:4, id:222}});
@@ -950,4 +1269,320 @@ describe('JOIN node', function() {
});
});
it('should reduce messages with flow context', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$A+(payload*$flowContext(\"two\"))",
reduceInit:"$flowContext(\"one\")",
reduceInitType:"jsonata",
reduceFixup:"$A*$flowContext(\"three\")",
wires:[["n2"]],z:"flow"},
{id:"n2", type:"helper",z:"flow"},
{id:"flow", type:"tab"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.equal(((((1+1*2)+2*2)+3*2)+4*2)*3);
done();
}
catch(e) { done(e); }
});
n1.context().flow.set("one",1);
n1.context().flow.set("two",2);
n1.context().flow.set("three",3);
n1.receive({payload:3, parts:{index:2, count:4, id:222}});
n1.receive({payload:2, parts:{index:1, count:4, id:222}});
n1.receive({payload:4, parts:{index:3, count:4, id:222}});
n1.receive({payload:1, parts:{index:0, count:4, id:222}});
});
});
it('should reduce messages with global context', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$A+(payload/$globalContext(\"two\"))",
reduceInit:"$globalContext(\"one\")",
reduceInitType:"jsonata",
reduceFixup:"$A*$globalContext(\"three\")",
wires:[["n2"]],z:"flow"},
{id:"n2", type:"helper",z:"flow"},
{id:"flow", type:"tab"}];
helper.load(joinNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.equal(((((1+1/2)+2/2)+3/2)+4/2)*3);
done();
}
catch(e) { done(e); }
});
n1.context().global.set("one",1);
n1.context().global.set("two",2);
n1.context().global.set("three",3);
n1.receive({payload:3, parts:{index:2, count:4, id:222}});
n1.receive({payload:2, parts:{index:1, count:4, id:222}});
n1.receive({payload:4, parts:{index:3, count:4, id:222}});
n1.receive({payload:1, parts:{index:0, count:4, id:222}});
});
});
it('should reduce messages with persistable flow context', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$A+(payload*$flowContext(\"two\",\"memory\"))",
reduceInit:"$flowContext(\"one\",\"memory\")",
reduceInitType:"jsonata",
reduceFixup:"$A*$flowContext(\"three\",\"memory\")",
wires:[["n2"]],z:"flow"},
{id:"n2", type:"helper",z:"flow"},
{id:"flow", type:"tab"}];
helper.load(joinNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
try {
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.equal(((((1+1*2)+2*2)+3*2)+4*2)*3);
done();
}
catch(e) { done(e); }
});
n1.context().flow.set(["one","two","three"],[1,2,3],"memory",function(err){
if(err){
done(err);
} else{
n1.receive({payload:3, parts:{index:2, count:4, id:222}});
n1.receive({payload:2, parts:{index:1, count:4, id:222}});
n1.receive({payload:4, parts:{index:3, count:4, id:222}});
n1.receive({payload:1, parts:{index:0, count:4, id:222}});
}
});
}catch(err) {
done(err);
}
});
});
});
it('should reduce messages with persistable global context', function(done) {
var flow = [{id:"n1", type:"join", mode:"reduce",
reduceRight:false,
reduceExp:"$A+(payload/$globalContext(\"two\",\"memory\"))",
reduceInit:"$globalContext(\"one\",\"memory\")",
reduceInitType:"jsonata",
reduceFixup:"$A*$globalContext(\"three\",\"memory\")",
wires:[["n2"]],z:"flow"},
{id:"n2", type:"helper",z:"flow"},
{id:"flow", type:"tab"}];
helper.load(joinNode, flow, function() {
initContext(function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function(msg) {
try {
msg.should.have.property("payload");
msg.payload.should.equal(((((1+1/2)+2/2)+3/2)+4/2)*3);
done();
}
catch(e) { done(e); }
});
n1.context().global.set(["one","two","three"],[1,2,3],"memory",function(err){
if(err){
done(err);
} else{
n1.receive({payload:3, parts:{index:2, count:4, id:222}});
n1.receive({payload:2, parts:{index:1, count:4, id:222}});
n1.receive({payload:4, parts:{index:3, count:4, id:222}});
n1.receive({payload:1, parts:{index:0, count:4, id:222}});
}
});
});
});
});
it('should handle invalid JSONata reduce expression - syntax error"', function (done) {
var flow = [{
id: "n1", type: "join", mode: "reduce",
reduceRight: false,
reduceExp: "invalid expr",
reduceInit: "0",
reduceInitType: "num",
reduceFixup: undefined,
wires: [["n2"]]
},
{ id: "n2", type: "helper" }];
helper.load(joinNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
setTimeout(function () {
done();
}, TimeoutForErrorCase);
n2.on("input", function (msg) {
done(new Error("This path does not go through."));
});
n1.receive({ payload: "A", parts: { id: 1, type: "string", ch: ",", index: 0, count: 1 } });
});
});
it('should handle invalid JSONata reduce expression - runtime error"', function (done) {
var flow = [{
id: "n1", type: "join", mode: "reduce",
reduceRight: false,
reduceExp: "$uknown()",
reduceInit: "0",
reduceInitType: "num",
reduceFixup: undefined,
wires: [["n2"]]
},
{ id: "n2", type: "helper" }];
helper.load(joinNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
setTimeout(function () {
done();
}, TimeoutForErrorCase);
n2.on("input", function (msg) {
done(new Error("This path does not go through."));
});
n1.receive({ payload: "A", parts: { id: 1, type: "string", ch: ",", index: 0, count: 1 } });
});
});
it('should handle invalid JSONata fixup expression - syntax err"', function (done) {
var flow = [{
id: "n1", type: "join", mode: "reduce",
reduceRight: false,
reduceExp: "$A",
reduceInit: "0",
reduceInitType: "num",
reduceFixup: "invalid expr",
wires: [["n2"]]
},
{ id: "n2", type: "helper" }];
helper.load(joinNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
setTimeout(function () {
done();
}, TimeoutForErrorCase);
n2.on("input", function (msg) {
done(new Error("This path does not go through."));
});
n1.receive({ payload: "A", parts: { id: 1, type: "string", ch: ",", index: 0, count: 1 } });
});
});
it('should handle invalid JSONata fixup expression - runtime err"', function (done) {
var flow = [{
id: "n1", type: "join", mode: "reduce",
reduceRight: false,
reduceExp: "$A",
reduceInit: "0",
reduceInitType: "num",
reduceFixup: "$unknown()",
wires: [["n2"]]
},
{ id: "n2", type: "helper" }];
helper.load(joinNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
setTimeout(function () {
done();
}, TimeoutForErrorCase);
n2.on("input", function (msg) {
done(new Error("This path does not go through."));
});
n1.receive({ payload: "A", parts: { id: 1, type: "string", ch: ",", index: 0, count: 1 } });
});
});
it('should concat payload when group.type is array', function (done) {
var flow = [{ id: "n1", type: "join", wires: [["n2"]], build: "array", mode: "auto" },
{ id: "n2", type: "helper" }];
helper.load(joinNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
try {
msg.should.have.property("payload");
msg.payload.should.be.an.Array();
msg.payload[0].should.equal("ab");
msg.payload[1].should.equal("cd");
msg.payload[2].should.equal("ef");
done();
}
catch (e) { done(e); }
});
n1.receive({ payload: "ab", parts: { id: 1, type: "array", ch: ",", index: 0, count: 3, len:2}});
n1.receive({ payload: "cd", parts: { id: 1, type: "array", ch: ",", index: 1, count: 3, len:2}});
n1.receive({ payload: "ef", parts: { id: 1, type: "array", ch: ",", index: 2, count: 3, len:2}});
});
});
it('should concat payload when group.type is buffer and group.joinChar is undefined', function (done) {
var flow = [{ id: "n1", type: "join", wires: [["n2"]], joiner: ",", build: "buffer", mode: "auto" },
{ id: "n2", type: "helper" }];
helper.load(joinNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
try {
msg.should.have.property("payload");
Buffer.isBuffer(msg.payload).should.be.true();
msg.payload.toString().should.equal("ABC");
done();
}
catch (e) { done(e); }
});
n1.receive({ payload: Buffer.from("A"), parts: { id: 1, type: "buffer", index: 0, count: 3 } });
n1.receive({ payload: Buffer.from("B"), parts: { id: 1, type: "buffer", index: 1, count: 3 } });
n1.receive({ payload: Buffer.from("C"), parts: { id: 1, type: "buffer", index: 2, count: 3 } });
});
});
it('should concat payload when group.type is string and group.joinChar is not string', function (done) {
var flow = [{ id: "n1", type: "join", wires: [["n2"]], joiner: ",", build: "buffer", mode: "auto" },
{ id: "n2", type: "helper" }];
helper.load(joinNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
try {
msg.should.have.property("payload");
msg.payload.toString().should.equal("A0B0C");
done();
}
catch (e) { done(e); }
});
n1.receive({ payload: Buffer.from("A"), parts: { id: 1, type: "string", ch: Buffer.from("0"), index: 0, count: 3 } });
n1.receive({ payload: Buffer.from("B"), parts: { id: 1, type: "string", ch: Buffer.from("0"), index: 1, count: 3 } });
n1.receive({ payload: Buffer.from("C"), parts: { id: 1, type: "string", ch: Buffer.from("0"), index: 2, count: 3 } });
});
});
it('should handle msg.parts property when mode is auto and parts or id are missing', function (done) {
var flow = [{ id: "n1", type: "join", wires: [["n2"]], joiner: "[44]", joinerType: "bin", build: "string", mode: "auto" },
{ id: "n2", type: "helper" }];
helper.load(joinNode, flow, function () {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n2.on("input", function (msg) {
done(new Error("This path does not go through."));
});
n1.receive({ payload: "A", parts: { type: "string", ch: ",", index: 0, count: 2 } });
n1.receive({ payload: "B", parts: { type: "string", ch: ",", index: 1, count: 2 } });
setTimeout(function () {
done();
}, TimeoutForErrorCase);
});
});
});

View File

@@ -18,20 +18,32 @@ var should = require("should");
var sortNode = require("../../../../nodes/core/logic/18-sort.js");
var helper = require("node-red-node-test-helper");
var RED = require("../../../../red/red.js");
var Context = require("../../../../red/runtime/nodes/context");
describe('SORT node', function() {
before(function(done) {
beforeEach(function(done) {
helper.startServer(done);
});
after(function(done) {
helper.stopServer(done);
});
function initContext(done) {
Context.init({
contextStorage: {
memory: {
module: "memory"
}
}
});
Context.load().then(function () {
done();
});
}
afterEach(function() {
helper.unload();
RED.settings.nodeMessageBufferMaxLength = 0;
afterEach(function(done) {
helper.unload().then(function(){
RED.settings.nodeMessageBufferMaxLength = 0;
helper.stopServer(done);
});
});
it('should be loaded', function(done) {
@@ -48,8 +60,8 @@ describe('SORT node', function() {
var sort = flow[0];
sort.target = target;
sort.targetType = "msg";
sort.msgKey = key;
sort.msgKeyType = key_type;
sort.msgKey = key;
sort.msgKeyType = key_type;
helper.load(sortNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
@@ -214,8 +226,6 @@ describe('SORT node', function() {
});
})();
return;
(function() {
var flow = [{id:"n1", type:"sort", order:"descending", as_num:false, wires:[["n2"]]},
{id:"n2", type:"helper"}];
@@ -229,6 +239,134 @@ describe('SORT node', function() {
});
})();
it('should sort payload by context (exp, not number, ascending)', function(done) {
var flow = [{id:"n1", type:"sort", target:"data", targetType:"msg", msgKey:"$flowContext($)", msgKeyType:"jsonata", order:"ascending", as_num:false, wires:[["n2"]],z:"flow"},
{id:"n2", type:"helper",z:"flow"},
{id:"flow", type:"tab"}];
var data_in = [ "first", "second", "third", "fourth" ];
var data_out = [ "second", "third", "first", "fourth" ];
helper.load(sortNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context()["flow"].set("first","3");
n1.context()["flow"].set("second","1");
n1.context()["flow"].set("third","2");
n1.context()["flow"].set("fourth","4");
n2.on("input", function(msg) {
msg.should.have.property("data");
var data = msg["data"];
data.length.should.equal(data_out.length);
for(var i = 0; i < data_out.length; i++) {
data[i].should.equal(data_out[i]);
}
done();
});
var msg = {};
msg["data"] = data_in;
n1.receive(msg);
});
});
it('should sort message group by context (exp, not number, ascending)', function(done) {
var flow = [{id:"n1", type:"sort", target:"data", targetType:"msg", msgKey:"$globalContext(payload)", msgKeyType:"jsonata", order:"ascending", as_num:false, wires:[["n2"]],z:"flow"},
{id:"n2", type:"helper",z:"flow"},
{id:"flow", type:"tab"}];
var data_in = [ "first", "second", "third", "fourth" ];
var data_out = [ "second", "fourth", "third", "first" ];
helper.load(sortNode, flow, function() {
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n1.context()["global"].set("first","4");
n1.context()["global"].set("second","1");
n1.context()["global"].set("third","3");
n1.context()["global"].set("fourth","2");
n2.on("input", function(msg) {
msg.should.have.property("payload");
msg.should.have.property("parts");
msg.parts.should.have.property("count", data_out.length);
var data = msg["payload"];
var index = data_out.indexOf(data);
msg.parts.should.have.property("index", index);
count++;
if (count === data_out.length) {
done();
}
});
var len = data_in.length;
for(var i = 0; i < len; i++) {
var parts = { id: "X", index: i, count: len };
var msg = {parts: parts};
msg["payload"] = data_in[i];
n1.receive(msg);
}
});
});
it('should sort payload by persistable context (exp, not number, descending)', function(done) {
var flow = [{id:"n1", type:"sort", target:"data", targetType:"msg", msgKey:"$globalContext($,\"memory\")", msgKeyType:"jsonata", order:"descending", as_num:false, wires:[["n2"]],z:"flow"},
{id:"n2", type:"helper",z:"flow"},
{id:"flow", type:"tab"}];
var data_in = [ "first", "second", "third", "fourth" ];
var data_out = [ "fourth", "first", "third", "second" ];
helper.load(sortNode, flow, function() {
initContext(function(){
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
n1.context()["global"].set(["first","second","third","fourth"],["3","1","2","4"],"memory",function(){
n2.on("input", function(msg) {
msg.should.have.property("data");
var data = msg["data"];
data.length.should.equal(data_out.length);
for(var i = 0; i < data_out.length; i++) {
data[i].should.equal(data_out[i]);
}
done();
});
var msg = {};
msg["data"] = data_in;
n1.receive(msg);
});
});
});
});
it('should sort message group by persistable context (exp, not number, descending)', function(done) {
var flow = [{id:"n1", type:"sort", target:"data", targetType:"msg", msgKey:"$flowContext(payload,\"memory\")", msgKeyType:"jsonata", order:"descending", as_num:false, wires:[["n2"]],z:"flow"},
{id:"n2", type:"helper",z:"flow"},
{id:"flow", type:"tab"}];
var data_in = [ "first", "second", "third", "fourth" ];
var data_out = [ "first", "third", "fourth", "second" ];
helper.load(sortNode, flow, function() {
initContext(function(){
var n1 = helper.getNode("n1");
var n2 = helper.getNode("n2");
var count = 0;
n1.context()["flow"].set(["first","second","third","fourth"],["4","1","3","2"],"memory",function(){
n2.on("input", function(msg) {
msg.should.have.property("payload");
msg.should.have.property("parts");
msg.parts.should.have.property("count", data_out.length);
var data = msg["payload"];
var index = data_out.indexOf(data);
msg.parts.should.have.property("index", index);
count++;
if (count === data_out.length) {
done();
}
});
var len = data_in.length;
for(var i = 0; i < len; i++) {
var parts = { id: "X", index: i, count: len };
var msg = {parts: parts};
msg["payload"] = data_in[i];
n1.receive(msg);
}
});
});
});
});
it('should handle JSONata script error', function(done) {
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:false, target:"payload", targetType:"seq", seqKey:"$unknown()", seqKeyType:"jsonata", wires:[["n2"]]},
{id:"n2", type:"helper"}];
@@ -251,8 +389,6 @@ describe('SORT node', function() {
});
});
return;
it('should handle too many pending messages', function(done) {
var flow = [{id:"n1", type:"sort", order:"ascending", as_num:false, target:"payload", targetType:"seq", seqKey:"payload", seqKeyType:"msg", wires:[["n2"]]},
{id:"n2", type:"helper"}];

View File

@@ -247,4 +247,85 @@ describe('JSON node', function() {
});
});
});
it('should pass an object if provided a valid JSON string and schema', function(done) {
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
{id:"jn2", type:"helper"}];
helper.load(jsonNode, flow, function() {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
jn2.on("input", function(msg) {
should.equal(msg.payload.number, 3);
should.equal(msg.payload.string, "allo");
done();
});
var jsonString = '{"number": 3, "string": "allo"}';
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
jn1.receive({payload:jsonString, schema:schema});
});
});
it('should pass a string if provided a valid object and schema', function(done) {
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
{id:"jn2", type:"helper"}];
helper.load(jsonNode, flow, function() {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
jn2.on("input", function(msg) {
should.equal(msg.payload, '{"number":3,"string":"allo"}');
done();
});
var obj = {"number": 3, "string": "allo"};
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
jn1.receive({payload:obj, schema:schema});
});
});
it('should log an error if passed an invalid object and valid schema', function(done) {
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
{id:"jn2", type:"helper"}];
helper.load(jsonNode, flow, function() {
try {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
var schema = {title: "testSchema", type: "object", properties: {number: {type: "number"}, string: {type: "string" }}};
var obj = {"number": "foo", "string": 3};
jn1.receive({payload:obj, schema:schema});
var logEvents = helper.log().args.filter(function(evt) {
return evt[0].type == "json";
});
logEvents.should.have.length(1);
logEvents[0][0].should.have.a.property('msg');
logEvents[0][0].msg.should.equal("json.errors.schema-error: data.number should be number, data.string should be string");
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
done();
} catch(err) {
done(err);
}
});
});
it('should log an error if passed a valid object and invalid schema', function(done) {
var flow = [{id:"jn1",type:"json",wires:[["jn2"]]},
{id:"jn2", type:"helper"}];
helper.load(jsonNode, flow, function() {
try {
var jn1 = helper.getNode("jn1");
var jn2 = helper.getNode("jn2");
var schema = "garbage";
var obj = {"number": "foo", "string": 3};
jn1.receive({payload:obj, schema:schema});
var logEvents = helper.log().args.filter(function(evt) {
return evt[0].type == "json";
});
logEvents.should.have.length(1);
logEvents[0][0].should.have.a.property('msg');
logEvents[0][0].msg.should.equal("json.errors.schema-error-compile");
logEvents[0][0].should.have.a.property('level',helper.log().ERROR);
done();
} catch(err) {
done(err);
}
});
});
});

View File

@@ -46,82 +46,173 @@ describe('file Nodes', function() {
it('should be loaded', function(done) {
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":true}];
helper.load(fileNode, flow, function() {
var fileNode1 = helper.getNode("fileNode1");
fileNode1.should.have.property('name', 'fileNode');
done();
try {
var fileNode1 = helper.getNode("fileNode1");
fileNode1.should.have.property('name', 'fileNode');
done();
}
catch (e) {
done(e);
}
});
});
it('should write to a file', function(done) {
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":true}];
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":true, wires: [["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
helper.load(fileNode, flow, function() {
var n1 = helper.getNode("fileNode1");
n1.emit("input", {payload:"test"});
setTimeout(function() {
var f = fs.readFileSync(fileToTest);
f.should.have.length(4);
fs.unlinkSync(fileToTest);
done();
},wait);
var n2 = helper.getNode("helperNode1");
n2.on("input", function(msg) {
try {
var f = fs.readFileSync(fileToTest);
f.should.have.length(4);
fs.unlinkSync(fileToTest);
msg.should.have.property("payload", "test");
done();
}
catch (e) {
done(e);
}
});
n1.receive({payload:"test"});
});
});
it('should append to a file and add newline', function(done) {
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":false}];
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":true, "overwriteFile":false, wires: [["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
try {
fs.unlinkSync(fileToTest);
}catch(err) {}
} catch(err) {
}
helper.load(fileNode, flow, function() {
var n1 = helper.getNode("fileNode1");
n1.emit("input", {payload:"test2"}); // string
var n2 = helper.getNode("helperNode1");
var count = 0;
var data = ["test2", true, 999, [2]];
n2.on("input", function (msg) {
try {
msg.should.have.property("payload");
data.should.containDeep([msg.payload]);
if (count === 3) {
var f = fs.readFileSync(fileToTest).toString();
if (os.type() !== "Windows_NT") {
f.should.have.length(19);
f.should.equal("test2\ntrue\n999\n[2]\n");
}
else {
f.should.have.length(23);
f.should.equal("test2\r\ntrue\r\n999\r\n[2]\r\n");
}
done();
}
count++;
}
catch (e) {
done(e);
}
});
n1.receive({payload:"test2"}); // string
setTimeout(function() {
n1.emit("input", {payload:true}); // boolean
n1.receive({payload:true}); // boolean
},30);
setTimeout(function() {
n1.emit("input", {payload:999}); // number
n1.receive({payload:999}); // number
},60);
setTimeout(function() {
n1.emit("input", {payload:[2]}); // object (array)
n1.receive({payload:[2]}); // object (array)
},90);
setTimeout(function() {
var f = fs.readFileSync(fileToTest).toString();
if (os.type() !== "Windows_NT") {
f.should.have.length(19);
f.should.equal("test2\ntrue\n999\n[2]\n");
}
else {
f.should.have.length(23);
f.should.equal("test2\r\ntrue\r\n999\r\n[2]\r\n");
}
done();
},wait);
});
});
it('should append to a file after it has been deleted ', function(done) {
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":false}];
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":false, wires: [["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
try {
fs.unlinkSync(fileToTest);
} catch(err) {}
} catch(err) {
}
helper.load(fileNode, flow, function() {
var n1 = helper.getNode("fileNode1");
var n2 = helper.getNode("helperNode1");
var data = ["one", "two", "three", "four"];
var count = 0;
n2.on("input", function (msg) {
try {
msg.should.have.property("payload");
data.should.containDeep([msg.payload]);
try {
if (count === 1) {
// Check they got appended as expected
var f = fs.readFileSync(fileToTest).toString();
f.should.equal("onetwo");
// Delete the file
fs.unlinkSync(fileToTest);
setTimeout(function() {
// Send two more messages to the file
n1.receive({payload:"three"});
n1.receive({payload:"four"});
}, wait);
}
if (count === 3) {
var f = fs.readFileSync(fileToTest).toString();
f.should.equal("threefour");
fs.unlinkSync(fileToTest);
done();
}
} catch(err) {
done(err);
}
count++;
}
catch (e) {
done(e);
}
});
// Send two messages to the file
n1.emit("input", {payload:"one"});
n1.emit("input", {payload:"two"});
setTimeout(function() {
n1.receive({payload:"one"});
n1.receive({payload:"two"});
});
});
it('should append to a file after it has been recreated ', function(done) {
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":false, wires: [["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
try {
fs.unlinkSync(fileToTest);
} catch(err) {
}
helper.load(fileNode, flow, function() {
var n1 = helper.getNode("fileNode1");
var n2 = helper.getNode("helperNode1");
var data = ["one", "two", "three", "four"];
var count = 0;
n2.on("input", function (msg) {
try {
// Check they got appended as expected
var f = fs.readFileSync(fileToTest).toString();
f.should.equal("onetwo");
msg.should.have.property("payload");
data.should.containDeep([msg.payload]);
if (count == 1) {
// Check they got appended as expected
var f = fs.readFileSync(fileToTest).toString();
f.should.equal("onetwo");
// Delete the file
fs.unlinkSync(fileToTest);
// Send two more messages to the file
n1.emit("input", {payload:"three"});
n1.emit("input", {payload:"four"});
setTimeout(function() {
if (os.type() === "Windows_NT") {
var dummyFile = path.join(resourcesDir,"50-file-test-dummy.txt");
fs.rename(fileToTest, dummyFile, function() {
recreateTest(n1, dummyFile);
});
} else {
recreateTest(n1, fileToTest);
}
}
if (count == 3) {
// Check the file was updated
try {
var f = fs.readFileSync(fileToTest).toString();
@@ -131,42 +222,16 @@ describe('file Nodes', function() {
} catch(err) {
done(err);
}
},wait);
} catch(err) {
done(err);
}
},wait);
});
});
it('should append to a file after it has been recreated ', function(done) {
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":false}];
try {
fs.unlinkSync(fileToTest);
} catch(err) {}
helper.load(fileNode, flow, function() {
var n1 = helper.getNode("fileNode1");
// Send two messages to the file
n1.emit("input", {payload:"one"});
n1.emit("input", {payload:"two"});
setTimeout(function() {
try {
// Check they got appended as expected
var f = fs.readFileSync(fileToTest).toString();
f.should.equal("onetwo");
if (os.type() === "Windows_NT") {
var dummyFile = path.join(resourcesDir,"50-file-test-dummy.txt");
fs.rename(fileToTest, dummyFile, function() {
recreateTest(n1, dummyFile);
});
} else {
recreateTest(n1, fileToTest);
}
} catch(err) {
done(err);
}
},wait);
count++;
});
// Send two messages to the file
n1.receive({payload:"one"});
n1.receive({payload:"two"});
});
function recreateTest(n1, fileToDelete) {
@@ -177,50 +242,52 @@ describe('file Nodes', function() {
fs.writeFileSync(fileToTest,"");
// Send two more messages to the file
n1.emit("input", {payload:"three"});
n1.emit("input", {payload:"four"});
setTimeout(function() {
// Check the file was updated
try {
var f = fs.readFileSync(fileToTest).toString();
f.should.equal("threefour");
fs.unlinkSync(fileToTest);
done();
} catch(err) {
done(err);
}
},wait);
n1.receive({payload:"three"});
n1.receive({payload:"four"});
}
});
it('should use msg.filename if filename not set in node', function(done) {
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "appendNewline":true, "overwriteFile":true}];
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "appendNewline":true, "overwriteFile":true, wires: [["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
helper.load(fileNode, flow, function() {
var n1 = helper.getNode("fileNode1");
n1.emit("input", {payload:"fine", filename:fileToTest});
setTimeout(function() {
var f = fs.readFileSync(fileToTest).toString();
if (os.type() !== "Windows_NT") {
f.should.have.length(5);
f.should.equal("fine\n");
}
else {
f.should.have.length(6);
f.should.equal("fine\r\n");
}
done();
},wait);
var n2 = helper.getNode("helperNode1");
n2.on("input", function (msg) {
try {
msg.should.have.property("payload", "fine");
msg.should.have.property("filename", fileToTest);
var f = fs.readFileSync(fileToTest).toString();
if (os.type() !== "Windows_NT") {
f.should.have.length(5);
f.should.equal("fine\n");
}
else {
f.should.have.length(6);
f.should.equal("fine\r\n");
}
done();
}
catch (e) {
done(e);
}
});
n1.receive({payload:"fine", filename:fileToTest});
});
});
it('should be able to delete the file', function(done) {
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":"delete"}];
var flow = [{id:"fileNode1", type:"file", name: "fileNode", "filename":fileToTest, "appendNewline":false, "overwriteFile":"delete", wires: [["helperNode1"]]},
{id:"helperNode1", type:"helper"}];
helper.load(fileNode, flow, function() {
var n1 = helper.getNode("fileNode1");
n1.emit("input", {payload:"fine"});
setTimeout(function() {
var n2 = helper.getNode("helperNode1");
n2.on("input", function (msg) {
try {
var f = fs.readFileSync(fileToTest).toString();
f.should.not.equal("fine");
@@ -230,7 +297,9 @@ describe('file Nodes', function() {
e.code.should.equal("ENOENT");
done();
}
},wait);
});
n1.receive({payload:"fine"});
});
});
@@ -394,6 +463,11 @@ describe('file Nodes', function() {
});
it('should try to create a new directory if asked to do so (append)', function(done) {
// fs.writeFileSync of afterEach failed on Windows.
if (os.type() === "Windows_NT") {
done();
return;
}
// 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", function(arg1,arg2,arg3,arg4) { arg2(null); });

View File

@@ -0,0 +1,231 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var request = require('supertest');
var express = require('express');
var bodyParser = require('body-parser');
var sinon = require('sinon');
var when = require('when');
var context = require("../../../../red/api/admin/context");
var Context = require("../../../../red/runtime/nodes/context");
var Util = require("../../../../red/runtime/util");
describe("api/admin/context", function() {
var app = undefined;
before(function (done) {
var node_context = undefined;
app = express();
app.use(bodyParser.json());
app.get("/context/:scope(global)", context.get);
app.get("/context/:scope(global)/*", context.get);
app.get("/context/:scope(node|flow)/:id", context.get);
app.get("/context/:scope(node|flow)/:id/*", context.get);
context.init({
settings: {
},
log:{warn:function(){},_:function(){},audit:function(){}},
nodes: {
listContextStores: Context.listStores,
getContext: Context.get,
getNode: function(id) {
if (id === 'NID') {
return {
id: 'NID',
context: function () {
return node_context;
}
};
}
return null;
}
},
util: Util
});
Context.init({
contextStorage: {
memory0: {
module: "memory"
},
memory1: {
module: "memory"
}
}
});
Context.load().then(function () {
var ctx = Context.get("NID", "FID");
node_context = ctx;
ctx.set("foo", "n_v00", "memory0");
ctx.set("bar", "n_v01", "memory0");
ctx.set("baz", "n_v10", "memory1");
ctx.set("bar", "n_v11", "memory1");
ctx.flow.set("foo", "f_v00", "memory0");
ctx.flow.set("bar", "f_v01", "memory0");
ctx.flow.set("baz", "f_v10", "memory1");
ctx.flow.set("bar", "f_v11", "memory1");
ctx.global.set("foo", "g_v00", "memory0");
ctx.global.set("bar", "g_v01", "memory0");
ctx.global.set("baz", "g_v10", "memory1");
ctx.global.set("bar", "g_v11", "memory1");
done();
});
});
after(function () {
Context.clean({allNodes:{}});
Context.close();
});
function check_mem(body, mem, name, val) {
var mem0 = body[mem];
mem0.should.have.property(name);
mem0[name].should.deepEqual(val);
}
function check_scope(scope, prefix, id) {
describe('# '+scope, function () {
var xid = id ? ("/"+id) : "";
it('should return '+scope+' contexts', function (done) {
request(app)
.get('/context/'+scope+xid)
.set('Accept', 'application/json')
.expect(200)
.end(function (err, res) {
if (err) {
return done(err);
}
var body = res.body;
body.should.have.key('memory0', 'memory1');
check_mem(body, 'memory0',
'foo', {msg:prefix+'_v00', format:'string[5]'});
check_mem(body, 'memory0',
'bar', {msg:prefix+'_v01', format:'string[5]'});
check_mem(body, 'memory1',
'baz', {msg:prefix+'_v10', format:'string[5]'});
check_mem(body, 'memory1',
'bar', {msg:prefix+'_v11', format:'string[5]'});
done();
});
});
it('should return a value from default '+scope+' context', function (done) {
request(app)
.get('/context/'+scope+xid+'/foo')
.set('Accept', 'application/json')
.expect(200)
.end(function (err, res) {
if (err) {
return done(err);
}
var body = res.body;
body.should.deepEqual({msg: prefix+'_v00', format: 'string[5]'});
done();
});
});
it('should return a value from specified '+scope+' context', function (done) {
request(app)
.get('/context/'+scope+xid+'/bar?store=memory1')
.set('Accept', 'application/json')
.expect(200)
.end(function (err, res) {
if (err) {
return done(err);
}
var body = res.body;
body.should.deepEqual({msg: prefix+'_v11', format: 'string[5]', store: 'memory1'});
done();
});
});
it('should return specified '+scope+' store', function (done) {
request(app)
.get('/context/'+scope+xid+'?store=memory1')
.set('Accept', 'application/json')
.expect(200)
.end(function (err, res) {
if (err) {
return done(err);
}
var body = res.body;
body.should.deepEqual({
memory1: {
baz: { msg: prefix+'_v10', format: 'string[5]' },
bar: { msg: prefix+'_v11', format: 'string[5]' }
}
});
done();
});
});
it('should return undefined for unknown key of default '+scope+' store', function (done) {
request(app)
.get('/context/'+scope+xid+'/unknown')
.set('Accept', 'application/json')
.expect(200)
.end(function (err, res) {
if (err) {
return done(err);
}
var body = res.body;
body.should.deepEqual({msg:'(undefined)', format:'undefined'});
done();
});
});
it('should cause error for unknown '+scope+' store', function (done) {
request(app)
.get('/context/'+scope+xid+'?store=unknown')
.set('Accept', 'application/json')
.expect(200)
.end(function (err, res) {
if (err) {
return done();
}
done("unexpected");
});
});
});
}
check_scope("global", "g", undefined);
check_scope("node", "n", "NID");
check_scope("flow", "f", "FID");
describe("# errors", function () {
it('should cause error for unknown scope', function (done) {
request(app)
.get('/context/scope')
.set('Accept', 'application/json')
.expect(200)
.end(function (err, res) {
if (err) {
return done();
}
done("unexpected");
});
});
});
});

View File

@@ -20,8 +20,7 @@ var express = require('express');
var sinon = require('sinon');
var locales = require("../../../../red/api/editor/locales");
var i18n = require("../../../../red/util/i18n");
var i18n = require("../../../../red/util").i18n;
describe("api/editor/locales", function() {
beforeEach(function() {
@@ -31,18 +30,39 @@ describe("api/editor/locales", function() {
describe('get named resource catalog',function() {
var app;
before(function() {
// bit of a mess of internal workings
// locales.init({
// i18n: {
// i: {
// language: function() { return 'en-US'},
// changeLanguage: function(lang,callback) {
// if (callback) {
// callback();
// }
// },
// getResourceBundle: function(lang, namespace) {
// return {namespace:namespace, lang:lang};
// }
// },
// }
// });
locales.init({});
sinon.stub(i18n.i,'lng',function() { return 'en-US'});
sinon.stub(i18n.i,'setLng',function(lang,callback) { if (callback) {callback();}});
sinon.stub(i18n,'catalog',function(namespace, lang) {return {namespace:namespace, lang:lang};});
// bit of a mess of internal workings
sinon.stub(i18n.i,'changeLanguage',function(lang,callback) { if (callback) {callback();}});
if (i18n.i.getResourceBundle) {
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
i18n.i.getResourceBundle = function(lang, namespace) {return {namespace:namespace, lang:lang};};
i18n.i.getResourceBundle.restore = function() { delete i18n.i.getResourceBundle };
}
app = express();
app.get(/locales\/(.+)\/?$/,locales.get);
});
after(function() {
i18n.i.lng.restore();
i18n.i.setLng.restore();
i18n.catalog.restore();
i18n.i.changeLanguage.restore();
i18n.i.getResourceBundle.restore();
})
it('returns with default language', function(done) {
request(app)

View File

@@ -0,0 +1,20 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
describe("runtime-api/context", function() {
});

View File

@@ -165,7 +165,7 @@ describe('nodes/registry/installer', function() {
});
});
it("rejects when non-existant path is provided", function(done) {
this.timeout(10000);
this.timeout(20000);
var resourcesDir = path.resolve(path.join(__dirname,"resources","local","TestNodeModule","node_modules","NonExistant"));
installer.installModule(resourcesDir).then(function() {
done(new Error("Unexpected success"));

View File

@@ -89,6 +89,8 @@ describe("runtime", function() {
var redNodesGetNodeList;
var redNodesLoadFlows;
var redNodesStartFlows;
var redNodesLoadContextsPlugin;
beforeEach(function() {
storageInit = sinon.stub(storage,"init",function(settings) {return Promise.resolve();});
redNodesInit = sinon.stub(redNodes,"init", function() {});
@@ -96,6 +98,7 @@ describe("runtime", function() {
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()});
});
afterEach(function() {
storageInit.restore();
@@ -105,6 +108,7 @@ describe("runtime", function() {
redNodesCleanModuleList.restore();
redNodesLoadFlows.restore();
redNodesStartFlows.restore();
redNodesLoadContextsPlugin.restore();
});
it("reports errored/missing modules",function(done) {
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function(cb) {
@@ -187,7 +191,7 @@ describe("runtime", function() {
});
it("reports runtime metrics",function(done) {
var stopFlows = sinon.stub(redNodes,"stopFlows",function() {} );
var stopFlows = sinon.stub(redNodes,"stopFlows",function() { return Promise.resolve();} );
redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function() {return []});
var util = mockUtil(true);
runtime.init({testSettings: true, runtimeMetricInterval:200, httpAdminRoot:"/", load:function() { return Promise.resolve();}},util);
@@ -214,10 +218,19 @@ describe("runtime", function() {
});
it("stops components", function() {
var stopFlows = sinon.stub(redNodes,"stopFlows",function() {} );
runtime.stop();
stopFlows.called.should.be.true();
stopFlows.restore();
it("stops components", function(done) {
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();
stopFlows.restore();
closeContextsPlugin.restore();
done();
}).catch(function(err){
stopFlows.restore();
closeContextsPlugin.restore();
return done(err)
});
});
});

View File

@@ -0,0 +1,897 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var sinon = require('sinon');
var path = require("path");
var Context = require("../../../../../red/runtime/nodes/context/index");
describe('context', function() {
describe('local memory',function() {
beforeEach(function() {
Context.init({});
Context.load();
});
afterEach(function() {
Context.clean({allNodes:{}});
return Context.close();
});
it('stores local property',function() {
var context1 = Context.get("1","flowA");
should.not.exist(context1.get("foo"));
context1.set("foo","test");
context1.get("foo").should.equal("test");
});
it('stores local property - creates parent properties',function() {
var context1 = Context.get("1","flowA");
context1.set("foo.bar","test");
context1.get("foo").should.eql({bar:"test"});
});
it('deletes local property',function() {
var context1 = Context.get("1","flowA");
context1.set("foo.abc.bar1","test1");
context1.set("foo.abc.bar2","test2");
context1.get("foo.abc").should.eql({bar1:"test1",bar2:"test2"});
context1.set("foo.abc.bar1",undefined);
context1.get("foo.abc").should.eql({bar2:"test2"});
context1.set("foo.abc",undefined);
should.not.exist(context1.get("foo.abc"));
context1.set("foo",undefined);
should.not.exist(context1.get("foo"));
});
it('stores flow property',function() {
var context1 = Context.get("1","flowA");
should.not.exist(context1.flow.get("foo"));
context1.flow.set("foo","test");
context1.flow.get("foo").should.equal("test");
});
it('stores global property',function() {
var context1 = Context.get("1","flowA");
should.not.exist(context1.global.get("foo"));
context1.global.set("foo","test");
context1.global.get("foo").should.equal("test");
});
it('keeps local context local', function() {
var context1 = Context.get("1","flowA");
var context2 = Context.get("2","flowA");
should.not.exist(context1.get("foo"));
should.not.exist(context2.get("foo"));
context1.set("foo","test");
context1.get("foo").should.equal("test");
should.not.exist(context2.get("foo"));
});
it('flow context accessible to all flow nodes', function() {
var context1 = Context.get("1","flowA");
var context2 = Context.get("2","flowA");
should.not.exist(context1.flow.get("foo"));
should.not.exist(context2.flow.get("foo"));
context1.flow.set("foo","test");
context1.flow.get("foo").should.equal("test");
context2.flow.get("foo").should.equal("test");
});
it('flow context not shared to nodes on other flows', function() {
var context1 = Context.get("1","flowA");
var context2 = Context.get("2","flowB");
should.not.exist(context1.flow.get("foo"));
should.not.exist(context2.flow.get("foo"));
context1.flow.set("foo","test");
context1.flow.get("foo").should.equal("test");
should.not.exist(context2.flow.get("foo"));
});
it('global context shared to all nodes', function() {
var context1 = Context.get("1","flowA");
var context2 = Context.get("2","flowB");
should.not.exist(context1.global.get("foo"));
should.not.exist(context2.global.get("foo"));
context1.global.set("foo","test");
context1.global.get("foo").should.equal("test");
context2.global.get("foo").should.equal("test");
});
it('deletes context',function() {
var context = Context.get("1","flowA");
should.not.exist(context.get("foo"));
context.set("foo","abc");
context.get("foo").should.equal("abc");
return Context.delete("1","flowA").then(function(){
context = Context.get("1","flowA");
should.not.exist(context.get("foo"));
});
});
it('enumerates context keys - sync', function() {
var context = Context.get("1","flowA");
var keys = context.keys();
keys.should.be.an.Array();
keys.should.be.empty();
context.set("foo","bar");
keys = context.keys();
keys.should.have.length(1);
keys[0].should.equal("foo");
context.set("abc.def","bar");
keys = context.keys();
keys.should.have.length(2);
keys[1].should.equal("abc");
});
it('enumerates context keys - async', function(done) {
var context = Context.get("1","flowA");
var keys = context.keys(function(err,keys) {
keys.should.be.an.Array();
keys.should.be.empty();
context.set("foo","bar");
keys = context.keys(function(err,keys) {
keys.should.have.length(1);
keys[0].should.equal("foo");
context.set("abc.def","bar");
keys = context.keys(function(err,keys) {
keys.should.have.length(2);
keys[1].should.equal("abc");
done();
});
});
});
});
it('should enumerate only context keys when GlobalContext was given - sync', function() {
Context.init({functionGlobalContext: {foo:"bar"}});
Context.load().then(function(){
var context = Context.get("1","flowA");
context.global.set("foo2","bar2");
var keys = context.global.keys();
keys.should.have.length(2);
keys[0].should.equal("foo");
keys[1].should.equal("foo2");
});
});
it('should enumerate only context keys when GlobalContext was given - async', function(done) {
Context.init({functionGlobalContext: {foo:"bar"}});
Context.load().then(function(){
var context = Context.get("1","flowA");
context.global.set("foo2","bar2");
context.global.keys(function(err,keys) {
keys.should.have.length(2);
keys[0].should.equal("foo");
keys[1].should.equal("foo2");
done();
});
}).catch(done);
});
it('returns functionGlobalContext value if store value undefined', function() {
Context.init({functionGlobalContext: {foo:"bar"}});
Context.load().then(function(){
var context = Context.get("1","flowA");
var v = context.global.get('foo');
v.should.equal('bar');
});
})
});
describe('external context storage',function() {
var resourcesDir = path.resolve(path.join(__dirname,"..","resources","context"));
var sandbox = sinon.sandbox.create();
var stubGet = sandbox.stub();
var stubSet = sandbox.stub();
var stubKeys = sandbox.stub();
var stubDelete = sandbox.stub().returns(Promise.resolve());
var stubClean = sandbox.stub().returns(Promise.resolve());
var stubOpen = sandbox.stub().returns(Promise.resolve());
var stubClose = sandbox.stub().returns(Promise.resolve());
var stubGet2 = sandbox.stub();
var stubSet2 = sandbox.stub();
var stubKeys2 = sandbox.stub();
var stubDelete2 = sandbox.stub().returns(Promise.resolve());
var stubClean2 = sandbox.stub().returns(Promise.resolve());
var stubOpen2 = sandbox.stub().returns(Promise.resolve());
var stubClose2 = sandbox.stub().returns(Promise.resolve());
var testPlugin = function(config){
function Test(){}
Test.prototype.get = stubGet;
Test.prototype.set = stubSet;
Test.prototype.keys = stubKeys;
Test.prototype.delete = stubDelete;
Test.prototype.clean = stubClean;
Test.prototype.open = stubOpen;
Test.prototype.close = stubClose;
return new Test(config);
};
var testPlugin2 = function(config){
function Test2(){}
Test2.prototype.get = stubGet2;
Test2.prototype.set = stubSet2;
Test2.prototype.keys = stubKeys2;
Test2.prototype.delete = stubDelete2;
Test2.prototype.clean = stubClean2;
Test2.prototype.open = stubOpen2;
Test2.prototype.close = stubClose2;
return new Test2(config);
};
var contextStorage={
test:{
module: testPlugin,
config:{}
}
};
var contextDefaultStorage={
default: {
module: testPlugin2,
config:{}
},
test:{
module: testPlugin,
config:{}
}
};
var contextAlias={
default: "test",
test:{
module: testPlugin,
config:{}
}
};
var memoryStorage ={
memory:{
module: "memory"
}
};
afterEach(function() {
sandbox.reset();
return Context.clean({allNodes:{}}).then(function(){
return Context.close();
});
});
describe('load modules',function(){
it('should call open()', function() {
Context.init({contextStorage:contextDefaultStorage});
Context.load().then(function(){
stubOpen.called.should.be.true();
stubOpen2.called.should.be.true();
});
});
it('should load memory module', function() {
Context.init({contextStorage:{memory:{module:"memory"}}});
Context.load();
});
it('should load localfilesystem module', function() {
Context.init({contextStorage:{file:{module:"localfilesystem",config:{dir:resourcesDir}}}});
Context.load();
});
it('should ignore reserved storage name `_`', function(done) {
Context.init({contextStorage:{_:{module:testPlugin}}});
Context.load().then(function(){
var context = Context.get("1","flow");
var cb = function(){}
context.set("foo","bar","_",cb);
context.get("foo","_",cb);
context.keys("_",cb);
stubSet.called.should.be.false();
stubGet.called.should.be.false();
stubKeys.called.should.be.false();
done();
}).catch(done);
});
it('should fail when using invalid store name', function(done) {
Context.init({contextStorage:{'Invalid name':{module:testPlugin}}});
Context.load().then(function(){
done("An error was not thrown");
}).catch(function(){
done();
});
});
it('should fail when using invalid sign character', function (done) {
Context.init({ contextStorage:{'abc-123':{module:testPlugin}}});
Context.load().then(function () {
done("An error was not thrown");
}).catch(function () {
done();
});
});
it('should fail when using invalid default context', function(done) {
Context.init({contextStorage:{default:"noexist"}});
Context.load().then(function(){
done("An error was not thrown");
}).catch(function(){
done();
});
});
it('should fail for the storage with no module', function(done) {
Context.init({ contextStorage: { test: {}}});
Context.load().then(function(){
done("An error was not thrown");
}).catch(function(){
done();
});
});
it('should fail to load non-existent module', function(done) {
Context.init({contextStorage:{ file:{module:"nonexistent"} }});
Context.load().then(function(){
done("An error was not thrown");
}).catch(function(){
done();
});
});
it('should fail to load invalid module', function (done) {
Context.init({contextStorage: {
test: {
module: function (config) {
throw new Error("invalid plugin was loaded.");
}
}
}});
Context.load().then(function () {
done("An error was not thrown");
}).catch(function () {
done();
});
});
});
describe('close modules',function(){
it('should call close()', function(done) {
Context.init({contextStorage:contextDefaultStorage});
Context.load().then(function(){
return Context.close().then(function(){
stubClose.called.should.be.true();
stubClose2.called.should.be.true();
done();
});
}).catch(done);
});
});
describe('store context',function() {
it('should store local property to external context storage',function(done) {
Context.init({contextStorage:contextStorage});
var cb = function(){done("An error occurred")}
Context.load().then(function(){
var context = Context.get("1","flow");
context.set("foo","bar","test",cb);
context.get("foo","test",cb);
context.keys("test",cb);
stubSet.calledWithExactly("1:flow","foo","bar",cb).should.be.true();
stubGet.calledWith("1:flow","foo").should.be.true();
stubKeys.calledWithExactly("1:flow",cb).should.be.true();
done();
}).catch(done);
});
it('should store flow property to external context storage',function(done) {
Context.init({contextStorage:contextStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
var cb = function(){done("An error occurred")}
context.flow.set("foo","bar","test",cb);
context.flow.get("foo","test",cb);
context.flow.keys("test",cb);
stubSet.calledWithExactly("flow","foo","bar",cb).should.be.true();
stubGet.calledWith("flow","foo").should.be.true();
stubKeys.calledWithExactly("flow",cb).should.be.true();
done();
}).catch(done);
});
it('should store global property to external context storage',function(done) {
Context.init({contextStorage:contextStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
var cb = function(){done("An error occurred")}
context.global.set("foo","bar","test",cb);
context.global.get("foo","test",cb);
context.global.keys("test",cb);
stubSet.calledWithExactly("global","foo","bar",cb).should.be.true();
stubGet.calledWith("global","foo").should.be.true();
stubKeys.calledWith("global").should.be.true();
done();
}).catch(done);
});
it('should store data to the default context when non-existent context storage was specified', function(done) {
Context.init({contextStorage:contextDefaultStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
var cb = function(){done("An error occurred")}
context.set("foo","bar","nonexist",cb);
context.get("foo","nonexist",cb);
context.keys("nonexist",cb);
stubGet.called.should.be.false();
stubSet.called.should.be.false();
stubKeys.called.should.be.false();
stubSet2.calledWithExactly("1:flow","foo","bar",cb).should.be.true();
stubGet2.calledWith("1:flow","foo").should.be.true();
stubKeys2.calledWithExactly("1:flow",cb).should.be.true();
done();
}).catch(done);
});
it('should use the default context', function(done) {
Context.init({contextStorage:contextDefaultStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
var cb = function(){done("An error occurred")}
context.set("foo","bar","default",cb);
context.get("foo","default",cb);
context.keys("default",cb);
stubGet.called.should.be.false();
stubSet.called.should.be.false();
stubKeys.called.should.be.false();
stubSet2.calledWithExactly("1:flow","foo","bar",cb).should.be.true();
stubGet2.calledWith("1:flow","foo").should.be.true();
stubKeys2.calledWithExactly("1:flow",cb).should.be.true();
done();
}).catch(done);
});
it('should use the alias of default context', function(done) {
Context.init({contextStorage:contextDefaultStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
var cb = function(){done("An error occurred")}
context.set("foo","alias",cb);
context.get("foo",cb);
context.keys(cb);
stubGet.called.should.be.false();
stubSet.called.should.be.false();
stubKeys.called.should.be.false();
stubSet2.calledWithExactly("1:flow","foo","alias",cb).should.be.true();
stubGet2.calledWith("1:flow","foo").should.be.true();
stubKeys2.calledWithExactly("1:flow",cb).should.be.true();
done();
}).catch(done);
});
it('should use default as the alias of other context', function(done) {
Context.init({contextStorage:contextAlias});
Context.load().then(function(){
var context = Context.get("1","flow");
var cb = function(){done("An error occurred")}
context.set("foo","alias",cb);
context.get("foo",cb);
context.keys(cb);
stubSet.calledWithExactly("1:flow","foo","alias",cb).should.be.true();
stubGet.calledWith("1:flow","foo").should.be.true();
stubKeys.calledWithExactly("1:flow",cb).should.be.true();
done();
}).catch(done);
});
it('should not throw an error using undefined storage for local context', function(done) {
Context.init({contextStorage:contextStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
var cb = function(){done("An error occurred")}
context.get("local","nonexist",cb);
done()
}).catch(done);
});
it('should throw an error using undefined storage for flow context', function(done) {
Context.init({contextStorage:contextStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
var cb = function(){done("An error occurred")}
context.flow.get("flow","nonexist",cb);
done();
}).catch(done);
});
it('should return functionGlobalContext value as a default - synchronous', function(done) {
var fGC = { "foo": 456 };
Context.init({contextStorage:memoryStorage, functionGlobalContext:fGC });
Context.load().then(function() {
var context = Context.get("1","flow");
// Get foo - should be value from fGC
var v = context.global.get("foo");
v.should.equal(456);
// Update foo - should not touch fGC object
context.global.set("foo","new value");
fGC.foo.should.equal(456);
// Get foo - should be the updated value
v = context.global.get("foo");
v.should.equal("new value");
done();
}).catch(done);
})
it('should return functionGlobalContext value as a default - async', function(done) {
var fGC = { "foo": 456 };
Context.init({contextStorage:memoryStorage, functionGlobalContext:fGC });
Context.load().then(function() {
var context = Context.get("1","flow");
// Get foo - should be value from fGC
context.global.get("foo", function(err, v) {
if (err) {
done(err)
} else {
v.should.equal(456);
// Update foo - should not touch fGC object
context.global.set("foo","new value", function(err) {
if (err) {
done(err)
} else {
fGC.foo.should.equal(456);
// Get foo - should be the updated value
context.global.get("foo", function(err, v) {
if (err) {
done(err)
} else {
v.should.equal("new value");
done();
}
});
}
});
}
});
}).catch(done);
})
it('should return multiple values if key is an array', function(done) {
Context.init({contextStorage:memoryStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
context.set("foo1","bar1","memory");
context.set("foo2","bar2","memory");
context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err) {
done(err);
} else {
foo1.should.be.equal("bar1");
foo2.should.be.equal("bar2");
should.not.exist(foo3);
done();
}
});
}).catch(function(err){ done(err); });
});
it('should return multiple functionGlobalContext values if key is an array', function(done) {
var fGC = { "foo1": 456, "foo2": 789 };
Context.init({contextStorage:memoryStorage, functionGlobalContext:fGC });
Context.load().then(function(){
var context = Context.get("1","flow");
context.global.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err) {
done(err);
} else {
foo1.should.be.equal(456);
foo2.should.be.equal(789);
should.not.exist(foo3);
done();
}
});
}).catch(function(err){ done(err); });
});
it('should return an error if an error occurs in getting multiple store values', function(done) {
Context.init({contextStorage:contextStorage});
stubGet.onFirstCall().callsArgWith(2, "error2", "bar1");
Context.load().then(function(){
var context = Context.get("1","flow");
context.global.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err === "error2") {
done();
} else {
done("An error occurred");
}
});
}).catch(function(err){ done(err); });
});
it('should return a first error if some errors occur in getting multiple store values', function(done) {
Context.init({contextStorage:contextStorage});
stubGet.onFirstCall().callsArgWith(2, "error1");
stubGet.onSecondCall().callsArgWith(2, null, "bar2");
stubGet.onThirdCall().callsArgWith(2, "error3");
Context.load().then(function(){
var context = Context.get("1","flow");
context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err === "error1") {
done();
} else {
done("An error occurred");
}
});
}).catch(function(err){ done(err); });
});
it('should store multiple properties if key and value are arrays', function(done) {
Context.init({contextStorage:memoryStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
context.set(["foo1","foo2","foo3"], ["bar1","bar2","bar3"], "memory", function(err){
if (err) {
done(err);
} else {
context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err) {
done(err);
} else {
foo1.should.be.equal("bar1");
foo2.should.be.equal("bar2");
foo3.should.be.equal("bar3");
done();
}
});
}
});
});
});
it('should deletes multiple properties', function(done) {
Context.init({contextStorage:memoryStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
context.set(["foo1","foo2","foo3"], ["bar1","bar2","bar3"], "memory", function(err){
if (err) {
done(err);
} else {
context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err) {
done(err);
} else {
foo1.should.be.equal("bar1");
foo2.should.be.equal("bar2");
foo3.should.be.equal("bar3");
context.set(["foo1","foo2","foo3"], new Array(3), "memory", function(err){
if (err) {
done(err);
} else {
context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err) {
done(err);
} else {
should.not.exist(foo1);
should.not.exist(foo2);
should.not.exist(foo3);
done();
}
});
}
});
}
});
}
});
});
});
it('should use null for missing values if the value array is shorter than the key array', function(done) {
Context.init({contextStorage:memoryStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
context.set(["foo1","foo2","foo3"], ["bar1","bar2"], "memory", function(err){
if (err) {
done(err);
} else {
context.keys(function(err, keys){
keys.should.have.length(3);
keys.should.eql(["foo1","foo2","foo3"]);
context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err) {
done(err);
} else {
foo1.should.be.equal("bar1");
foo2.should.be.equal("bar2");
should(foo3).be.null();
done();
}
});
});
}
});
});
});
it('should use null for missing values if the value is not array', function(done) {
Context.init({contextStorage:memoryStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
context.set(["foo1","foo2","foo3"], "bar1", "memory", function(err){
if (err) {
done(err);
} else {
context.keys(function(err, keys){
keys.should.have.length(3);
keys.should.eql(["foo1","foo2","foo3"]);
context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err) {
done(err);
} else {
foo1.should.be.equal("bar1");
should(foo2).be.null();
should(foo3).be.null();
done();
}
});
});
}
});
});
});
it('should ignore the extra values if the value array is longer than the key array', function(done) {
Context.init({contextStorage:memoryStorage});
Context.load().then(function(){
var context = Context.get("1","flow");
context.set(["foo1","foo2","foo3"], ["bar1","bar2","bar3","ignored"], "memory", function(err){
if (err) {
done(err);
} else {
context.keys(function(err, keys){
keys.should.have.length(3);
keys.should.eql(["foo1","foo2","foo3"]);
context.get(["foo1","foo2","foo3"], "memory", function(err,foo1,foo2,foo3){
if (err) {
done(err);
} else {
foo1.should.be.equal("bar1");
foo2.should.be.equal("bar2");
foo3.should.be.equal("bar3");
done();
}
});
});
}
});
});
});
it('should return an error if an error occurs in storing multiple values', function(done) {
Context.init({contextStorage:contextStorage});
stubSet.onFirstCall().callsArgWith(3, "error2");
Context.load().then(function(){
var context = Context.get("1","flow");
context.set(["foo1","foo2","foo3"], ["bar1","bar2","bar3"], "memory", function(err){
if (err === "error2") {
done();
} else {
done("An error occurred");
}
});
}).catch(function(err){ done(err); });
});
it('should throw an error if callback of context.get is not a function', function (done) {
Context.init({ contextStorage: memoryStorage });
Context.load().then(function () {
var context = Context.get("1", "flow");
context.get("foo", "memory", "callback");
done("should throw an error.");
}).catch(function () {
done();
});
});
it('should not throw an error if callback of context.get is not specified', function (done) {
Context.init({ contextStorage: memoryStorage });
Context.load().then(function () {
var context = Context.get("1", "flow");
context.get("foo", "memory");
done();
}).catch(done);
});
it('should throw an error if callback of context.set is not a function', function (done) {
Context.init({ contextStorage: memoryStorage });
Context.load().then(function () {
var context = Context.get("1", "flow");
context.set("foo", "bar", "memory", "callback");
done("should throw an error.");
}).catch(function () {
done();
});
});
it('should not throw an error if callback of context.set is not specified', function (done) {
Context.init({ contextStorage: memoryStorage });
Context.load().then(function () {
var context = Context.get("1", "flow");
context.set("foo", "bar", "memory");
done();
}).catch(done);
});
it('should throw an error if callback of context.keys is not a function', function (done) {
Context.init({ contextStorage: memoryStorage });
Context.load().then(function () {
var context = Context.get("1", "flow");
context.keys("memory", "callback");
done("should throw an error.");
}).catch(function () {
done();
});
});
it('should not throw an error if callback of context.keys is not specified', function (done) {
Context.init({ contextStorage: memoryStorage });
Context.load().then(function () {
var context = Context.get("1", "flow");
context.keys("memory");
done();
}).catch(done);
});
});
describe('listStores', function () {
it('should list context storages', function (done) {
Context.init({ contextStorage: contextDefaultStorage });
Context.load().then(function () {
var list = Context.listStores();
list.default.should.equal("default");
list.stores.should.eql(["default", "test"]);
done();
}).catch(done);
});
it('should list context storages without default storage', function (done) {
Context.init({ contextStorage: contextStorage });
Context.load().then(function () {
var list = Context.listStores();
list.default.should.equal("test");
list.stores.should.eql(["test"]);
done();
}).catch(done);
});
});
describe('delete context',function(){
it('should not call delete() when external context storage is used', function(done) {
Context.init({contextStorage:contextDefaultStorage});
Context.load().then(function(){
Context.get("flowA");
return Context.delete("flowA").then(function(){
stubDelete.called.should.be.false();
stubDelete2.called.should.be.false();
done();
});
}).catch(done);
});
});
describe('clean context',function(){
it('should call clean()', function(done) {
Context.init({contextStorage:contextDefaultStorage});
Context.load().then(function(){
return Context.clean({allNodes:{}}).then(function(){
stubClean.calledWithExactly([]).should.be.true();
stubClean2.calledWithExactly([]).should.be.true();
done();
});
}).catch(done);
});
});
});
});

View File

@@ -0,0 +1,774 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require('should');
var fs = require('fs-extra');
var path = require("path");
var LocalFileSystem = require('../../../../../red/runtime/nodes/context/localfilesystem');
var resourcesDir = path.resolve(path.join(__dirname,"..","resources","context"));
describe('localfilesystem',function() {
var context;
before(function() {
return fs.remove(resourcesDir);
});
beforeEach(function() {
context = LocalFileSystem({dir: resourcesDir, cache: false});
return context.open();
});
afterEach(function() {
return context.clean([]).then(function(){
return context.close().then(function(){
return fs.remove(resourcesDir);
});
});
});
describe('#get/set',function() {
it('should store property',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo","test",function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.equal("test");
done();
});
});
});
});
it('should store property - creates parent properties',function(done) {
context.set("nodeX","foo.bar","test",function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.eql({bar:"test"});
done();
});
});
});
it('should store local scope property', function (done) {
context.set("abc:def", "foo.bar", "test", function (err) {
context.get("abc:def", "foo", function (err, value) {
value.should.be.eql({ bar: "test" });
done();
});
});
});
it('should delete property',function(done) {
context.set("nodeX","foo.abc.bar1","test1",function(err){
context.set("nodeX","foo.abc.bar2","test2",function(err){
context.get("nodeX","foo.abc",function(err, value){
value.should.be.eql({bar1:"test1",bar2:"test2"});
context.set("nodeX","foo.abc.bar1",undefined,function(err){
context.get("nodeX","foo.abc",function(err, value){
value.should.be.eql({bar2:"test2"});
context.set("nodeX","foo.abc",undefined,function(err){
context.get("nodeX","foo.abc",function(err, value){
should.not.exist(value);
context.set("nodeX","foo",undefined,function(err){
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
done();
});
});
});
});
});
});
});
});
});
});
it('should not shared context with other scope', function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.get("nodeY","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo","testX",function(err){
context.set("nodeY","foo","testY",function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.equal("testX");
context.get("nodeY","foo",function(err, value){
value.should.be.equal("testY");
done();
});
});
});
});
});
});
});
it('should store string',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo","bar",function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.String();
value.should.be.equal("bar");
context.set("nodeX","foo","1",function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.String();
value.should.be.equal("1");
done();
});
});
});
});
});
});
it('should store number',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo",1,function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.Number();
value.should.be.equal(1);
done();
});
});
});
});
it('should store null',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo",null,function(err){
context.get("nodeX","foo",function(err, value){
should(value).be.null();
done();
});
});
});
});
it('should store boolean',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo",true,function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.Boolean().and.true();
context.set("nodeX","foo",false,function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.Boolean().and.false();
done();
});
});
});
});
});
});
it('should store object',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo",{obj:"bar"},function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.Object();
value.should.eql({obj:"bar"});
done();
});
});
});
});
it('should store array',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo",["a","b","c"],function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.Array();
value.should.eql(["a","b","c"]);
context.get("nodeX","foo[1]",function(err, value){
value.should.be.String();
value.should.equal("b");
done();
});
});
});
});
});
it('should store array of arrays',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo",[["a","b","c"],[1,2,3,4],[true,false]],function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.Array();
value.should.have.length(3);
value[0].should.have.length(3);
value[1].should.have.length(4);
value[2].should.have.length(2);
context.get("nodeX","foo[1]",function(err, value){
value.should.be.Array();
value.should.have.length(4);
value.should.be.eql([1,2,3,4]);
done();
});
});
});
});
});
it('should store array of objects',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo",[{obj:"bar1"},{obj:"bar2"},{obj:"bar3"}],function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.Array();
value.should.have.length(3);
value[0].should.be.Object();
value[1].should.be.Object();
value[2].should.be.Object();
context.get("nodeX","foo[1]",function(err, value){
value.should.be.Object();
value.should.be.eql({obj:"bar2"});
done();
});
});
});
});
});
it('should set/get multiple values', function(done) {
context.set("nodeX",["one","two","three"],["test1","test2","test3"], function(err) {
context.get("nodeX",["one","two"], function() {
Array.prototype.slice.apply(arguments).should.eql([undefined,"test1","test2"])
done();
});
});
})
it('should set/get multiple values - get unknown', function(done) {
context.set("nodeX",["one","two","three"],["test1","test2","test3"], function(err) {
context.get("nodeX",["one","two","unknown"], function() {
Array.prototype.slice.apply(arguments).should.eql([undefined,"test1","test2",undefined])
done();
});
});
})
it('should set/get multiple values - single value providd', function(done) {
context.set("nodeX",["one","two","three"],"test1", function(err) {
context.get("nodeX",["one","two"], function() {
Array.prototype.slice.apply(arguments).should.eql([undefined,"test1",null])
done();
});
});
})
it('should throw error if bad key included in multiple keys - get', function(done) {
context.set("nodeX",["one","two","three"],["test1","test2","test3"], function(err) {
context.get("nodeX",["one",".foo","three"], function(err) {
should.exist(err);
done();
});
});
})
it('should throw error if bad key included in multiple keys - set', function(done) {
context.set("nodeX",["one",".foo","three"],["test1","test2","test3"], function(err) {
should.exist(err);
// Check 'one' didn't get set as a result
context.get("nodeX","one",function(err,one) {
should.not.exist(one);
done();
})
});
})
it('should throw an error when getting a value with invalid key', function (done) {
context.set("nodeX","foo","bar",function(err) {
context.get("nodeX"," ",function(err,value) {
should.exist(err);
done();
});
});
});
it('should throw an error when setting a value with invalid key',function (done) {
context.set("nodeX"," ","bar",function (err) {
should.exist(err);
done();
});
});
it('should throw an error when callback of get() is not a function',function (done) {
try {
context.get("nodeX","foo","callback");
done("should throw an error.");
} catch (err) {
done();
}
});
it('should throw an error when callback of get() is not specified',function (done) {
try {
context.get("nodeX","foo");
done("should throw an error.");
} catch (err) {
done();
}
});
it('should throw an error when callback of set() is not a function',function (done) {
try {
context.set("nodeX","foo","bar","callback");
done("should throw an error.");
} catch (err) {
done();
}
});
it('should not throw an error when callback of set() is not specified', function (done) {
try {
context.set("nodeX"," ","bar");
done();
} catch (err) {
done("should not throw an error.");
}
});
it('should handle empty context file', function (done) {
fs.outputFile(path.join(resourcesDir,"contexts","nodeX","flow.json"),"",function(){
context.get("nodeX", "foo", function (err, value) {
should.not.exist(value);
context.set("nodeX", "foo", "test", function (err) {
context.get("nodeX", "foo", function (err, value) {
value.should.be.equal("test");
done();
});
});
});
});
});
it('should throw an error when reading corrupt context file', function (done) {
fs.outputFile(path.join(resourcesDir, "contexts", "nodeX", "flow.json"),"{abc",function(){
context.get("nodeX", "foo", function (err, value) {
should.exist(err);
done();
});
});
});
});
describe('#keys',function() {
it('should enumerate context keys', function(done) {
context.keys("nodeX",function(err, value){
value.should.be.an.Array();
value.should.be.empty();
context.set("nodeX","foo","bar",function(err){
context.keys("nodeX",function(err, value){
value.should.have.length(1);
value[0].should.equal("foo");
context.set("nodeX","abc.def","bar",function(err){
context.keys("nodeX",function(err, value){
value.should.have.length(2);
value[1].should.equal("abc");
done();
});
});
});
});
});
});
it('should enumerate context keys in each scopes', function(done) {
context.keys("nodeX",function(err, value){
value.should.be.an.Array();
value.should.be.empty();
context.keys("nodeY",function(err, value){
value.should.be.an.Array();
value.should.be.empty();
context.set("nodeX","foo","bar",function(err){
context.set("nodeY","hoge","piyo",function(err){
context.keys("nodeX",function(err, value){
value.should.have.length(1);
value[0].should.equal("foo");
context.keys("nodeY",function(err, value){
value.should.have.length(1);
value[0].should.equal("hoge");
done();
});
});
});
});
});
});
});
it('should throw an error when callback of keys() is not a function', function (done) {
try {
context.keys("nodeX", "callback");
done("should throw an error.");
} catch (err) {
done();
}
});
it('should throw an error when callback of keys() is not specified', function (done) {
try {
context.keys("nodeX");
done("should throw an error.");
} catch (err) {
done();
}
});
});
describe('#delete',function() {
it('should delete context',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.get("nodeY","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo","testX",function(err){
context.set("nodeY","foo","testY",function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.equal("testX");
context.get("nodeY","foo",function(err, value){
value.should.be.equal("testY");
context.delete("nodeX").then(function(){
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.get("nodeY","foo",function(err, value){
value.should.be.equal("testY");
done();
});
});
}).catch(done);
});
});
});
});
});
});
});
});
describe('#clean',function() {
it('should clean unnecessary context',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.get("nodeY","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo","testX",function(err){
context.set("nodeY","foo","testY",function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.equal("testX");
context.get("nodeY","foo",function(err, value){
value.should.be.equal("testY");
context.clean([]).then(function(){
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.get("nodeY","foo",function(err, value){
should.not.exist(value);
done();
});
});
});
});
});
});
});
});
});
});
it('should not clean active context',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.get("nodeY","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo","testX",function(err){
context.set("nodeY","foo","testY",function(err){
context.get("nodeX","foo",function(err, value){
value.should.be.equal("testX");
context.get("nodeY","foo",function(err, value){
value.should.be.equal("testY");
context.clean(["nodeX"]).then(function(){
context.get("nodeX","foo",function(err, value){
value.should.be.equal("testX");
context.get("nodeY","foo",function(err, value){
should.not.exist(value);
done();
});
});
});
});
});
});
});
});
});
});
});
describe('#if cache is enabled',function() {
afterEach(function() {
return context.clean([]).then(function(){
return context.close().then(function(){
return fs.remove(resourcesDir);
});
});
});
it('should load contexts into the cache',function() {
var globalData = {key:"global"};
var flowData = {key:"flow"};
var nodeData = {key:"node"};
return Promise.all([
fs.outputFile(path.join(resourcesDir,"contexts","global","global.json"), JSON.stringify(globalData,null,4), "utf8"),
fs.outputFile(path.join(resourcesDir,"contexts","flow","flow.json"), JSON.stringify(flowData,null,4), "utf8"),
fs.outputFile(path.join(resourcesDir,"contexts","flow","node.json"), JSON.stringify(nodeData,null,4), "utf8")
]).then(function(){
context = LocalFileSystem({dir: resourcesDir, cache: true});
return context.open();
}).then(function(){
return Promise.all([
fs.remove(path.join(resourcesDir,"contexts","global","global.json")),
fs.remove(path.join(resourcesDir,"contexts","flow","flow.json")),
fs.remove(path.join(resourcesDir,"contexts","flow","node.json"))
]);
}).then(function(){
context.get("global","key").should.be.equal("global");
context.get("flow","key").should.be.equal("flow");
context.get("node:flow","key").should.be.equal("node");
});
});
it('should store property to the cache',function() {
context = LocalFileSystem({dir: resourcesDir, cache: true});
return context.open().then(function(){
return new Promise(function(resolve, reject){
context.set("global","foo","bar",function(err){
if(err){
reject(err);
} else {
resolve();
}
});
});
}).then(function(){
return fs.remove(path.join(resourcesDir,"contexts","global","global.json"));
}).then(function(){
context.get("global","foo").should.be.equal("bar");
})
});
it('should enumerate context keys in the cache',function() {
var globalData = {foo:"bar"};
fs.outputFile(path.join(resourcesDir,"contexts","global","global.json"), JSON.stringify(globalData,null,4), "utf8").then(function(){
context = LocalFileSystem({dir: resourcesDir, cache: true});
return context.open()
}).then(function(){
return fs.remove(path.join(resourcesDir,"contexts","global","global.json"));
}).then(function(){
var keys = context.keys("global");
keys.should.have.length(1);
keys[0].should.equal("foo");
return new Promise(function(resolve, reject){
context.set("global","foo2","bar2",function(err){
if(err){
reject(err);
} else {
resolve();
}
});
});
}).then(function(){
return fs.remove(path.join(resourcesDir,"contexts","global","global.json"));
}).then(function(){
var keys = context.keys("global");
keys.should.have.length(2);
keys[1].should.equal("foo2");
})
});
it('should delete context in the cache',function() {
context = LocalFileSystem({dir: resourcesDir, cache: true});
return context.open().then(function(){
return new Promise(function(resolve, reject){
context.set("global","foo","bar",function(err){
if(err){
reject(err);
} else {
resolve();
}
});
});
}).then(function(){
context.get("global","foo").should.be.equal("bar");
return context.delete("global");
}).then(function(){
should.not.exist(context.get("global","foo"))
})
});
it('should clean unnecessary context in the cache',function() {
var flowAData = {key:"flowA"};
var flowBData = {key:"flowB"};
return Promise.all([
fs.outputFile(path.join(resourcesDir,"contexts","flowA","flow.json"), JSON.stringify(flowAData,null,4), "utf8"),
fs.outputFile(path.join(resourcesDir,"contexts","flowB","flow.json"), JSON.stringify(flowBData,null,4), "utf8")
]).then(function(){
context = LocalFileSystem({dir: resourcesDir, cache: true});
return context.open();
}).then(function(){
context.get("flowA","key").should.be.equal("flowA");
context.get("flowB","key").should.be.equal("flowB");
return context.clean(["flowA"]);
}).then(function(){
context.get("flowA","key").should.be.equal("flowA");
should.not.exist(context.get("flowB","key"));
});
});
});
describe('Configuration', function () {
it('should change a base directory', function (done) {
var differentBaseContext = LocalFileSystem({
base: "contexts2",
dir: resourcesDir,
cache: false
});
differentBaseContext.open().then(function () {
differentBaseContext.set("node2", "foo2", "bar2", function (err) {
differentBaseContext.get("node2", "foo2", function (err, value) {
value.should.be.equal("bar2");
context.get("node2", "foo2", function(err, value) {
should.not.exist(value);
done();
});
});
});
});
});
it('should use userDir', function (done) {
var userDirContext = LocalFileSystem({
base: "contexts2",
cache: false,
settings: {
userDir: resourcesDir
}
});
userDirContext.open().then(function () {
userDirContext.set("node2", "foo2", "bar2", function (err) {
userDirContext.get("node2", "foo2", function (err, value) {
value.should.be.equal("bar2");
context.get("node2", "foo2", function (err, value) {
should.not.exist(value);
done();
});
});
});
});
});
it('should use NODE_RED_HOME', function (done) {
var oldNRH = process.env.NODE_RED_HOME;
process.env.NODE_RED_HOME = resourcesDir;
fs.mkdirSync(resourcesDir);
fs.writeFileSync(path.join(resourcesDir,".config.json"),"");
var nrHomeContext = LocalFileSystem({
base: "contexts2",
cache: false
});
try {
nrHomeContext.open().then(function () {
nrHomeContext.set("node2", "foo2", "bar2", function (err) {
nrHomeContext.get("node2", "foo2", function (err, value) {
value.should.be.equal("bar2");
context.get("node2", "foo2", function (err, value) {
should.not.exist(value);
done();
});
});
});
});
} finally {
process.env.NODE_RED_HOME = oldNRH;
}
});
it('should use HOME_PATH', function (done) {
var oldNRH = process.env.NODE_RED_HOME;
var oldHOMEPATH = process.env.HOMEPATH;
process.env.NODE_RED_HOME = resourcesDir;
process.env.HOMEPATH = resourcesDir;
var homePath = path.join(resourcesDir, ".node-red");
fs.outputFile(path.join(homePath, ".config.json"),"",function(){
var homeContext = LocalFileSystem({
base: "contexts2",
cache: false
});
try {
homeContext.open().then(function () {
homeContext.set("node2", "foo2", "bar2", function (err) {
homeContext.get("node2", "foo2", function (err, value) {
value.should.be.equal("bar2");
context.get("node2", "foo2", function (err, value) {
should.not.exist(value);
done();
});
});
});
});
} finally {
process.env.NODE_RED_HOME = oldNRH;
process.env.HOMEPATH = oldHOMEPATH;
}
});
});
it('should use HOME_PATH', function (done) {
var oldNRH = process.env.NODE_RED_HOME;
var oldHOMEPATH = process.env.HOMEPATH;
var oldHOME = process.env.HOME;
process.env.NODE_RED_HOME = resourcesDir;
process.env.HOMEPATH = resourcesDir;
process.env.HOME = resourcesDir;
var homeContext = LocalFileSystem({
base: "contexts2",
cache: false
});
try {
homeContext.open().then(function () {
homeContext.set("node2", "foo2", "bar2", function (err) {
homeContext.get("node2", "foo2", function (err, value) {
value.should.be.equal("bar2");
context.get("node2", "foo2", function (err, value) {
should.not.exist(value);
done();
});
});
});
});
} finally {
process.env.NODE_RED_HOME = oldNRH;
process.env.HOMEPATH = oldHOMEPATH;
process.env.HOME = oldHOME;
}
});
});
});

View File

@@ -0,0 +1,319 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require('should');
var Memory = require('../../../../../red/runtime/nodes/context/memory');
describe('memory',function() {
var context;
beforeEach(function() {
context = Memory({});
return context.open();
});
afterEach(function() {
return context.clean([]).then(function(){
return context.close();
});
});
describe('#get/set',function() {
describe('sync',function() {
it('should store property',function() {
should.not.exist(context.get("nodeX","foo"));
context.set("nodeX","foo","test");
context.get("nodeX","foo").should.equal("test");
});
it('should store property - creates parent properties',function() {
context.set("nodeX","foo.bar","test");
context.get("nodeX","foo").should.eql({bar:"test"});
});
it('should delete property',function() {
context.set("nodeX","foo.abc.bar1","test1");
context.set("nodeX","foo.abc.bar2","test2");
context.get("nodeX","foo.abc").should.eql({bar1:"test1",bar2:"test2"});
context.set("nodeX","foo.abc.bar1",undefined);
context.get("nodeX","foo.abc").should.eql({bar2:"test2"});
context.set("nodeX","foo.abc",undefined);
should.not.exist(context.get("nodeX","foo.abc"));
context.set("nodeX","foo",undefined);
should.not.exist(context.get("nodeX","foo"));
});
it('should not shared context with other scope', function() {
should.not.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","testX");
context.set("nodeY","foo","testY");
context.get("nodeX","foo").should.equal("testX");
context.get("nodeY","foo").should.equal("testY");
});
it('should throw the error if the error occurs', function() {
try{
context.set("nodeX",".foo","test");
should.fail("Error was not thrown");
}catch(err){
should.exist(err);
try{
context.get("nodeX",".foo");
should.fail("Error was not thrown");
}catch(err){
should.exist(err);
}
}
});
it('should get multiple values - all known', function() {
context.set("nodeX","one","test1");
context.set("nodeX","two","test2");
context.set("nodeX","three","test3");
context.set("nodeX","four","test4");
var values = context.get("nodeX",["one","two","four"]);
values.should.eql(["test1","test2","test4"])
})
it('should get multiple values - include unknown', function() {
context.set("nodeX","one","test1");
context.set("nodeX","two","test2");
context.set("nodeX","three","test3");
context.set("nodeX","four","test4");
var values = context.get("nodeX",["one","unknown"]);
values.should.eql(["test1",undefined])
})
it('should throw error if bad key included in multiple keys', function() {
context.set("nodeX","one","test1");
context.set("nodeX","two","test2");
context.set("nodeX","three","test3");
context.set("nodeX","four","test4");
try{
var values = context.get("nodeX",["one",".foo","three"]);
should.fail("Error was not thrown");
}catch(err){
should.exist(err);
}
})
});
describe('async',function() {
it('should store property',function(done) {
context.get("nodeX","foo",function(err, value){
should.not.exist(value);
context.set("nodeX","foo","test",function(err){
context.get("nodeX","foo",function(err, value){
value.should.equal("test");
done();
});
});
});
});
it('should pass the error to callback if the error occurs',function(done) {
context.set("nodeX",".foo","test",function(err, value){
should.exist(err);
context.get("nodeX",".foo",function(err){
should.exist(err);
done();
});
});
});
it('should get multiple values - all known', function(done) {
context.set("nodeX","one","test1");
context.set("nodeX","two","test2");
context.set("nodeX","three","test3");
context.set("nodeX","four","test4");
context.get("nodeX",["one","two","four"],function() {
Array.prototype.slice.apply(arguments).should.eql([undefined,"test1","test2","test4"])
done();
});
})
it('should get multiple values - include unknown', function(done) {
context.set("nodeX","one","test1");
context.set("nodeX","two","test2");
context.set("nodeX","three","test3");
context.set("nodeX","four","test4");
context.get("nodeX",["one","unknown"],function() {
Array.prototype.slice.apply(arguments).should.eql([undefined,"test1",undefined])
done();
});
})
it('should throw error if bad key included in multiple keys', function(done) {
context.set("nodeX","one","test1");
context.set("nodeX","two","test2");
context.set("nodeX","three","test3");
context.set("nodeX","four","test4");
context.get("nodeX",["one",".foo","three"], function(err) {
should.exist(err);
done();
});
})
});
});
describe('#keys',function() {
describe('sync',function() {
it('should enumerate context keys', function() {
var keys = context.keys("nodeX");
keys.should.be.an.Array();
keys.should.be.empty();
context.set("nodeX","foo","bar");
keys = context.keys("nodeX");
keys.should.have.length(1);
keys[0].should.equal("foo");
context.set("nodeX","abc.def","bar");
keys = context.keys("nodeX");
keys.should.have.length(2);
keys[1].should.equal("abc");
});
it('should enumerate context keys in each scopes', function() {
var keysX = context.keys("nodeX");
keysX.should.be.an.Array();
keysX.should.be.empty();
var keysY = context.keys("nodeY");
keysY.should.be.an.Array();
keysY.should.be.empty();
context.set("nodeX","foo","bar");
context.set("nodeY","hoge","piyo");
keysX = context.keys("nodeX");
keysX.should.have.length(1);
keysX[0].should.equal("foo");
keysY = context.keys("nodeY");
keysY.should.have.length(1);
keysY[0].should.equal("hoge");
});
it('should enumerate global context keys', function () {
var keys = context.keys("global");
keys.should.be.an.Array();
keys.should.be.empty();
context.set("global", "foo", "bar");
keys = context.keys("global");
keys.should.have.length(1);
keys[0].should.equal("foo");
context.set("global", "abc.def", "bar");
keys = context.keys("global");
keys.should.have.length(2);
keys[1].should.equal("abc");
});
it('should not return specific keys as global context keys', function () {
var keys = context.keys("global");
context.set("global", "set", "bar");
context.set("global", "get", "bar");
context.set("global", "keys", "bar");
keys = context.keys("global");
keys.should.have.length(0);
});
});
describe('async',function() {
it('should enumerate context keys', function(done) {
context.keys("nodeX", function(err, keys) {
keys.should.be.an.Array();
keys.should.be.empty();
context.set("nodeX", "foo", "bar", function(err) {
context.keys("nodeX", function(err, keys) {
keys.should.have.length(1);
keys[0].should.equal("foo");
context.set("nodeX","abc.def","bar",function(err){
context.keys("nodeX",function(err, keys){
keys.should.have.length(2);
keys[1].should.equal("abc");
done();
});
});
});
});
});
});
});
});
describe('#delete',function() {
it('should delete context',function() {
should.not.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","abc");
context.set("nodeY","foo","abc");
context.get("nodeX","foo").should.equal("abc");
context.get("nodeY","foo").should.equal("abc");
return context.delete("nodeX").then(function(){
should.not.exist(context.get("nodeX","foo"));
should.exist(context.get("nodeY","foo"));
});
});
});
describe('#clean',function() {
it('should clean unnecessary context',function() {
should.not.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","abc");
context.set("nodeY","foo","abc");
context.get("nodeX","foo").should.equal("abc");
context.get("nodeY","foo").should.equal("abc");
return context.clean([]).then(function(){
should.not.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
});
});
it('should not clean active context',function() {
should.not.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","abc");
context.set("nodeY","foo","abc");
context.get("nodeX","foo").should.equal("abc");
context.get("nodeY","foo").should.equal("abc");
return context.clean(["nodeX"]).then(function(){
should.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
});
});
it('should not clean global context', function () {
context.set("global", "foo", "abc");
context.get("global", "foo").should.equal("abc");
return context.clean(["global"]).then(function () {
should.exist(context.get("global", "foo"));
});
});
});
});

View File

@@ -1,144 +0,0 @@
/**
* Copyright JS Foundation and other contributors, http://js.foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
**/
var should = require("should");
var sinon = require('sinon');
var Context = require("../../../../red/runtime/nodes/context");
describe('context', function() {
beforeEach(function() {
Context.init({});
});
afterEach(function() {
Context.clean({allNodes:{}});
});
it('stores local property',function() {
var context1 = Context.get("1","flowA");
should.not.exist(context1.get("foo"));
context1.set("foo","test");
context1.get("foo").should.eql("test");
});
it('stores local property - creates parent properties',function() {
var context1 = Context.get("1","flowA");
context1.set("foo.bar","test");
context1.get("foo").should.eql({bar:"test"});
});
it('deletes local property',function() {
var context1 = Context.get("1","flowA");
context1.set("foo.abc.bar1","test1");
context1.set("foo.abc.bar2","test2");
context1.get("foo.abc").should.eql({bar1:"test1",bar2:"test2"});
context1.set("foo.abc.bar1",undefined);
context1.get("foo.abc").should.eql({bar2:"test2"});
context1.set("foo.abc",undefined);
should.not.exist(context1.get("foo.abc"));
context1.set("foo",undefined);
should.not.exist(context1.get("foo"));
});
it('stores flow property',function() {
var context1 = Context.get("1","flowA");
should.not.exist(context1.flow.get("foo"));
context1.flow.set("foo","test");
context1.flow.get("foo").should.eql("test");
});
it('stores global property',function() {
var context1 = Context.get("1","flowA");
should.not.exist(context1.global.get("foo"));
context1.global.set("foo","test");
context1.global.get("foo").should.eql("test");
});
it('keeps local context local', function() {
var context1 = Context.get("1","flowA");
var context2 = Context.get("2","flowA");
should.not.exist(context1.get("foo"));
should.not.exist(context2.get("foo"));
context1.set("foo","test");
context1.get("foo").should.eql("test");
should.not.exist(context2.get("foo"));
});
it('flow context accessible to all flow nodes', function() {
var context1 = Context.get("1","flowA");
var context2 = Context.get("2","flowA");
should.not.exist(context1.flow.get("foo"));
should.not.exist(context2.flow.get("foo"));
context1.flow.set("foo","test");
context1.flow.get("foo").should.eql("test");
context2.flow.get("foo").should.eql("test");
});
it('flow context not shared to nodes on other flows', function() {
var context1 = Context.get("1","flowA");
var context2 = Context.get("2","flowB");
should.not.exist(context1.flow.get("foo"));
should.not.exist(context2.flow.get("foo"));
context1.flow.set("foo","test");
context1.flow.get("foo").should.eql("test");
should.not.exist(context2.flow.get("foo"));
});
it('global context shared to all nodes', function() {
var context1 = Context.get("1","flowA");
var context2 = Context.get("2","flowB");
should.not.exist(context1.global.get("foo"));
should.not.exist(context2.global.get("foo"));
context1.global.set("foo","test");
context1.global.get("foo").should.eql("test");
context2.global.get("foo").should.eql("test");
});
it('deletes context',function() {
var context = Context.get("1","flowA");
should.not.exist(context.get("foo"));
context.set("foo","abc");
context.get("foo").should.eql("abc");
Context.delete("1","flowA");
context = Context.get("1","flowA");
should.not.exist(context.get("foo"));
})
it('enumerates context keys', function() {
var context = Context.get("1","flowA");
var keys = context.keys();
keys.should.be.an.Array();
keys.should.be.empty();
context.set("foo","bar");
keys = context.keys();
keys.should.have.length(1);
keys[0].should.eql("foo");
context.set("abc.def","bar");
keys = context.keys();
keys.should.have.length(2);
keys[1].should.eql("abc");
})
});

View File

@@ -287,7 +287,7 @@ describe("storage/localfilesystem/projects/ssh", function() {
});
it('should generate sshkey file with size data', function(done) {
this.timeout(10000);
this.timeout(20000);
var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
var username = 'test';
var options = {
@@ -311,7 +311,7 @@ describe("storage/localfilesystem/projects/ssh", function() {
});
it('should generate sshkey file with password & size data', function(done) {
this.timeout(10000);
this.timeout(20000);
var sshkeyDirPath = path.join(userDir, 'projects', '.sshkeys');
var username = 'test';
var options = {

View File

@@ -141,7 +141,15 @@ describe("red/util", function() {
cloned.res.should.equal(msg.res);
});
});
describe('getObjectProperty', function() {
it('gets a property beginning with "msg."', function() {
// getMessageProperty strips off `msg.` prefixes.
// getObjectProperty does not
var obj = { msg: { a: "foo"}, a: "bar"};
var v = util.getObjectProperty(obj,"msg.a");
v.should.eql("foo");
})
});
describe('getMessageProperty', function() {
it('retrieves a simple property', function() {
var v = util.getMessageProperty({a:"foo"},"msg.a");
@@ -169,7 +177,16 @@ describe("red/util", function() {
});
});
describe('setObjectProperty', function() {
it('set a property beginning with "msg."', function() {
// setMessageProperty strips off `msg.` prefixes.
// setObjectProperty does not
var obj = {};
util.setObjectProperty(obj,"msg.a","bar");
obj.should.have.property("msg");
obj.msg.should.have.property("a","bar");
})
});
describe('setMessageProperty', function() {
it('sets a property', function() {
var msg = {a:"foo"};
@@ -191,6 +208,11 @@ describe("red/util", function() {
util.setMessageProperty(msg,"msg.a.b.c","bar",false);
should.not.exist(msg.a.b);
})
it('does not create missing parent properties with array', function () {
var msg = {a:{}};
util.setMessageProperty(msg, "msg.a.b[1].c", "bar", false);
should.not.exist(msg.a.b);
})
it('deletes property if value is undefined', function() {
var msg = {a:{b:{c:"foo"}}};
util.setMessageProperty(msg,"msg.a.b.c",undefined);
@@ -227,6 +249,11 @@ describe("red/util", function() {
msg.a[2].should.be.instanceOf(Array);
msg.a[2][2].should.eql("bar");
});
it('does not create missing array elements - mid property', function () {
var msg = {a:[]};
util.setMessageProperty(msg, "msg.a[1][1]", "bar", false);
msg.a.should.empty();
});
it('does not create missing array elements - final property', function() {
var msg = {a:{}};
util.setMessageProperty(msg,"msg.a.b[2]","bar",false);
@@ -275,10 +302,23 @@ describe("red/util", function() {
var result = util.evaluateNodeProperty('','date');
(Date.now() - result).should.be.approximately(0,50);
});
it('returns bin', function () {
var result = util.evaluateNodeProperty('[1, 2]','bin');
result[0].should.eql(1);
result[1].should.eql(2);
});
it('returns msg property',function() {
var result = util.evaluateNodeProperty('foo.bar','msg',{},{foo:{bar:"123"}});
result.should.eql("123");
});
it('throws an error if callback is not defined', function (done) {
try {
util.evaluateNodeProperty(' ','msg',{},{foo:{bar:"123"}});
done("should throw an error");
} catch (err) {
done();
}
});
it('returns flow property',function() {
var result = util.evaluateNodeProperty('foo.bar','flow',{
context:function() { return {
@@ -307,6 +347,14 @@ describe("red/util", function() {
},{});
result.should.eql("123");
});
it('returns jsonata result', function () {
var result = util.evaluateNodeProperty('$abs(-1)','jsonata',{},{});
result.should.eql(1);
});
it('returns null', function() {
var result = util.evaluateNodeProperty(null,'null');
(result === null).should.be.true();
})
describe('environment variable', function() {
before(function() {
process.env.NR_TEST_A = "foo";
@@ -444,6 +492,12 @@ describe("red/util", function() {
var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
result.should.eql("bar");
});
it('accesses environment variable from an expression', function() {
process.env.UTIL_ENV = 'foo';
var expr = util.prepareJSONataExpression('$env("UTIL_ENV")',{});
var result = util.evaluateJSONataExpression(expr,{});
result.should.eql('foo');
});
it('handles non-existant flow context variable', function() {
var expr = util.prepareJSONataExpression('$flowContext("nonExistant")',{context:function() { return {flow:{get: function(key) { return {'foo':'bar'}[key]}}}}});
var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
@@ -454,7 +508,267 @@ describe("red/util", function() {
var result = util.evaluateJSONataExpression(expr,{payload:"hello"});
should.not.exist(result);
});
it('handles async flow context access', function(done) {
var expr = util.prepareJSONataExpression('$flowContext("foo")',{context:function() { return {flow:{get: function(key,store,callback) { setTimeout(()=>{callback(null,{'foo':'bar'}[key])},10)}}}}});
util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value) {
try {
should.not.exist(err);
value.should.eql("bar");
done();
} catch(err2) {
done(err2);
}
});
})
it('handles async global context access', function(done) {
var expr = util.prepareJSONataExpression('$globalContext("foo")',{context:function() { return {global:{get: function(key,store,callback) { setTimeout(()=>{callback(null,{'foo':'bar'}[key])},10)}}}}});
util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value) {
try {
should.not.exist(err);
value.should.eql("bar");
done();
} catch(err2) {
done(err2);
}
});
})
it('handles persistable store in flow context access', function(done) {
var storeName;
var expr = util.prepareJSONataExpression('$flowContext("foo", "flowStoreName")',{context:function() { return {flow:{get: function(key,store,callback) { storeName = store;setTimeout(()=>{callback(null,{'foo':'bar'}[key])},10)}}}}});
util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value) {
try {
should.not.exist(err);
value.should.eql("bar");
storeName.should.equal("flowStoreName");
done();
} catch(err2) {
done(err2);
}
});
})
it('handles persistable store in global context access', function(done) {
var storeName;
var expr = util.prepareJSONataExpression('$globalContext("foo", "globalStoreName")',{context:function() { return {global:{get: function(key,store,callback) { storeName = store;setTimeout(()=>{callback(null,{'foo':'bar'}[key])},10)}}}}});
util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value) {
try {
should.not.exist(err);
value.should.eql("bar");
storeName.should.equal("globalStoreName");
done();
} catch(err2) {
done(err2);
}
});
})
it('callbacks with error when invalid expression was specified', function (done) {
var expr = util.prepareJSONataExpression('$abc(1)',{});
var result = util.evaluateJSONataExpression(expr,{payload:"hello"},function(err,value){
should.exist(err);
done();
});
});
});
describe('encodeObject', function () {
it('encodes Error with message', function() {
var err = new Error("encode error");
err.name = 'encodeError';
var msg = {msg:err};
var result = util.encodeObject(msg);
result.format.should.eql("error");
var resultJson = JSON.parse(result.msg);
resultJson.name.should.eql('encodeError');
resultJson.message.should.eql('encode error');
});
it('encodes Error without message', function() {
var err = new Error();
err.name = 'encodeError';
err.toString = function(){return 'error message';}
var msg = {msg:err};
var result = util.encodeObject(msg);
result.format.should.eql("error");
var resultJson = JSON.parse(result.msg);
resultJson.name.should.eql('encodeError');
resultJson.message.should.eql('error message');
});
it('encodes Buffer', function() {
var msg = {msg:Buffer.from("abc")};
var result = util.encodeObject(msg,{maxLength:4});
result.format.should.eql("buffer[3]");
result.msg[0].should.eql('6');
result.msg[1].should.eql('1');
result.msg[2].should.eql('6');
result.msg[3].should.eql('2');
});
it('encodes function', function() {
var msg = {msg:function(){}};
var result = util.encodeObject(msg);
result.format.should.eql("function");
result.msg.should.eql('[function]');
});
it('encodes boolean', function() {
var msg = {msg:true};
var result = util.encodeObject(msg);
result.format.should.eql("boolean");
result.msg.should.eql('true');
});
it('encodes number', function() {
var msg = {msg:123};
var result = util.encodeObject(msg);
result.format.should.eql("number");
result.msg.should.eql('123');
});
it('encodes 0', function() {
var msg = {msg:0};
var result = util.encodeObject(msg);
result.format.should.eql("number");
result.msg.should.eql('0');
});
it('encodes null', function() {
var msg = {msg:null};
var result = util.encodeObject(msg);
result.format.should.eql("null");
result.msg.should.eql('(undefined)');
});
it('encodes undefined', function() {
var msg = {msg:undefined};
var result = util.encodeObject(msg);
result.format.should.eql("undefined");
result.msg.should.eql('(undefined)');
});
it('encodes string', function() {
var msg = {msg:'1234567890'};
var result = util.encodeObject(msg,{maxLength:6});
result.format.should.eql("string[10]");
result.msg.should.eql('123456...');
});
describe('encode object', function() {
it('object', function() {
var msg = { msg:{"foo":"bar"} };
var result = util.encodeObject(msg);
result.format.should.eql("Object");
var resultJson = JSON.parse(result.msg);
resultJson.foo.should.eql('bar');
});
it('object whose name includes error', function() {
function MyErrorObj(){
this.name = 'my error obj';
this.message = 'my error message';
};
var msg = { msg:new MyErrorObj() };
var result = util.encodeObject(msg);
result.format.should.eql("MyErrorObj");
var resultJson = JSON.parse(result.msg);
resultJson.name.should.eql('my error obj');
resultJson.message.should.eql('my error message');
});
it('constructor of IncomingMessage', function() {
function IncomingMessage(){};
var msg = { msg:new IncomingMessage() };
var result = util.encodeObject(msg);
result.format.should.eql("Object");
var resultJson = JSON.parse(result.msg);
resultJson.should.empty();
});
it('_req key in msg', function() {
function Socket(){};
var msg = { msg:{"_req":123} };
var result = util.encodeObject(msg);
result.format.should.eql("Object");
var resultJson = JSON.parse(result.msg);
resultJson._req.__enc__.should.eql(true);
resultJson._req.type.should.eql('internal');
});
it('_res key in msg', function() {
function Socket(){};
var msg = { msg:{"_res":123} };
var result = util.encodeObject(msg);
result.format.should.eql("Object");
var resultJson = JSON.parse(result.msg);
resultJson._res.__enc__.should.eql(true);
resultJson._res.type.should.eql('internal');
});
it('array of error', function() {
var msg = { msg:[new Error("encode error")] };
var result = util.encodeObject(msg);
result.format.should.eql("array[1]");
var resultJson = JSON.parse(result.msg);
resultJson[0].should.eql('Error: encode error');
});
it('long array in msg', function() {
var msg = {msg:{array:[1,2,3,4]}};
var result = util.encodeObject(msg,{maxLength:2});
result.format.should.eql("Object");
var resultJson = JSON.parse(result.msg);
resultJson.array.__enc__.should.eql(true);
resultJson.array.data[0].should.eql(1);
resultJson.array.data[1].should.eql(2);
resultJson.array.length.should.eql(4);
});
it('array of string', function() {
var msg = { msg:["abcde","12345"] };
var result = util.encodeObject(msg,{maxLength:3});
result.format.should.eql("array[2]");
var resultJson = JSON.parse(result.msg);
resultJson[0].should.eql('abc...');
resultJson[1].should.eql('123...');
});
it('array of function', function() {
var msg = { msg:[function(){}] };
var result = util.encodeObject(msg);
result.format.should.eql("array[1]");
var resultJson = JSON.parse(result.msg);
resultJson[0].__enc__.should.eql(true);
resultJson[0].type.should.eql('function');
});
it('array of number', function() {
var msg = { msg:[1,2,3] };
var result = util.encodeObject(msg,{maxLength:2});
result.format.should.eql("array[3]");
var resultJson = JSON.parse(result.msg);
resultJson.__enc__.should.eql(true);
resultJson.data[0].should.eql(1);
resultJson.data[1].should.eql(2);
resultJson.data.length.should.eql(2);
resultJson.length.should.eql(3);
});
it('array of special number', function() {
var msg = { msg:[NaN,Infinity,-Infinity] };
var result = util.encodeObject(msg);
result.format.should.eql("array[3]");
var resultJson = JSON.parse(result.msg);
resultJson[0].__enc__.should.eql(true);
resultJson[0].type.should.eql('number');
resultJson[0].data.should.eql('NaN');
resultJson[1].data.should.eql('Infinity');
resultJson[2].data.should.eql('-Infinity');
});
it('constructor of Buffer in msg', function() {
var msg = { msg:{buffer:new Buffer([1,2,3,4])} };
var result = util.encodeObject(msg,{maxLength:2});
result.format.should.eql("Object");
var resultJson = JSON.parse(result.msg);
resultJson.buffer.__enc__.should.eql(true);
resultJson.buffer.length.should.eql(4);
resultJson.buffer.data[0].should.eql(1);
resultJson.buffer.data[1].should.eql(2);
});
it('constructor of ServerResponse', function() {
function ServerResponse(){};
var msg = { msg: new ServerResponse() };
var result = util.encodeObject(msg);
result.format.should.eql("Object");
var resultJson = JSON.parse(result.msg);
resultJson.should.eql('[internal]');
});
it('constructor of Socket in msg', function() {
function Socket(){};
var msg = { msg: { socket: new Socket() } };
var result = util.encodeObject(msg);
result.format.should.eql("Object");
var resultJson = JSON.parse(result.msg);
resultJson.socket.should.eql('[internal]');
});
});
});
});

View File

@@ -0,0 +1 @@
Text file