diff --git a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
index 1fff8b87e..a4a2a5485 100755
--- a/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
+++ b/packages/node_modules/@node-red/editor-client/locales/en-US/editor.json
@@ -901,6 +901,7 @@
"editor-tab": {
"properties": "Properties",
"description": "Description",
- "appearance": "Appearance"
+ "appearance": "Appearance",
+ "env": "Env Var"
}
}
diff --git a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json
index 23c957426..2d412cb0d 100755
--- a/packages/node_modules/@node-red/editor-client/locales/ja/editor.json
+++ b/packages/node_modules/@node-red/editor-client/locales/ja/editor.json
@@ -901,6 +901,7 @@
"editor-tab": {
"properties": "プロパティ",
"description": "説明",
- "appearance": "外観"
+ "appearance": "外観",
+ "env": "環境変数"
}
}
diff --git a/packages/node_modules/@node-red/editor-client/src/js/nodes.js b/packages/node_modules/@node-red/editor-client/src/js/nodes.js
index d9ef6ab44..0965cbdb9 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/nodes.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/nodes.js
@@ -358,7 +358,10 @@ RED.nodes = (function() {
}
subflows[sf.id] = sf;
RED.nodes.registerType("subflow:"+sf.id, {
- defaults:{name:{value:""}},
+ defaults:{
+ name:{value:""},
+ env:{value:[]}
+ },
icon: function() { return sf.icon||"subflow.png" },
category: sf.category || "subflows",
inputs: sf.in.length,
@@ -535,6 +538,7 @@ RED.nodes = (function() {
node.category = n.category;
node.in = [];
node.out = [];
+ node.env = n.env;
n.in.forEach(function(p) {
var nIn = {x:p.x,y:p.y,wires:[]};
@@ -1018,6 +1022,7 @@ RED.nodes = (function() {
node.name = n.name;
node.outputs = subflow.out.length;
node.inputs = subflow.in.length;
+ node.env = n.env;
} else {
if (!node._def) {
if (node.x && node.y) {
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js
index 443f3844e..c69b4e216 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/editor.js
@@ -540,7 +540,113 @@ RED.editor = (function() {
return label;
}
- function buildEditForm(container,formId,type,ns) {
+ function buildEnvForm(container, node) {
+ var env_container = $('#node-input-env-container');
+ env_container
+ .css('min-height','250px').css('min-width','450px')
+ .editableList({
+ addItem: function(container, i, opt) {
+ var row = $('
', {class:"editor-tray-content"}).appendTo(editorContent).hide(),
iconClass: "fa fa-cog"
};
- buildEditForm(nodePropertiesTab.content,"dialog-form",type,ns);
+ buildEditForm(nodePropertiesTab.content,"dialog-form",type,ns,node);
editorTabs.addTab(nodePropertiesTab);
if (!node._def.defaults || !node._def.defaults.hasOwnProperty('info')) {
@@ -1986,6 +2107,14 @@ RED.editor = (function() {
changed = true;
}
+ var old_env = editing_node.env;
+ var new_env = convEnv($("#node-input-env-container").editableList("items"));
+ if (!isSameEnv(old_env, new_env)) {
+ editing_node.env = new_env;
+ changes.env = editing_node.env;
+ changed = true;
+ }
+
RED.palette.refresh();
if (changed) {
@@ -2063,7 +2192,7 @@ RED.editor = (function() {
content: $('
', {class:"editor-tray-content"}).appendTo(editorContent).hide(),
iconClass: "fa fa-cog"
};
- buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template");
+ buildEditForm(nodePropertiesTab.content,"dialog-form","subflow-template", undefined, editing_node);
editorTabs.addTab(nodePropertiesTab);
var descriptionTab = {
diff --git a/packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js b/packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js
index 2acbd88b5..3cfd51a5d 100644
--- a/packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js
+++ b/packages/node_modules/@node-red/editor-client/src/js/ui/subflow.js
@@ -17,10 +17,16 @@
RED.subflow = (function() {
- var _subflowEditTemplate = '';
+ var _subflowEditTemplate = '';
var _subflowTemplateEditTemplate = '';
diff --git a/packages/node_modules/@node-red/nodes/core/core/80-function.js b/packages/node_modules/@node-red/nodes/core/core/80-function.js
index 0e1efbdcd..e8454d79e 100644
--- a/packages/node_modules/@node-red/nodes/core/core/80-function.js
+++ b/packages/node_modules/@node-red/nodes/core/core/80-function.js
@@ -158,9 +158,7 @@ module.exports = function(RED) {
},
env: {
get: function(envVar) {
- // For now, just return the env var. This will eventually
- // also return project settings and subflow instance properties
- return process.env[envVar]
+ return node.getenv(envVar);
}
},
setTimeout: function () {
diff --git a/packages/node_modules/@node-red/nodes/core/logic/15-change.js b/packages/node_modules/@node-red/nodes/core/logic/15-change.js
index 3faf5c7aa..8d100233e 100644
--- a/packages/node_modules/@node-red/nodes/core/logic/15-change.js
+++ b/packages/node_modules/@node-red/nodes/core/logic/15-change.js
@@ -94,7 +94,7 @@ module.exports = function(RED) {
this.error(RED._("change.errors.invalid-expr",{error:e.message}));
}
} else if (rule.tot === 'env') {
- rule.to = RED.util.evaluateNodeProperty(rule.to,'env');
+ rule.to = RED.util.evaluateNodeProperty(rule.to,'env',node);
}
}
diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/Node.js b/packages/node_modules/@node-red/runtime/lib/nodes/Node.js
index a0825f7b1..02562ca99 100644
--- a/packages/node_modules/@node-red/runtime/lib/nodes/Node.js
+++ b/packages/node_modules/@node-red/runtime/lib/nodes/Node.js
@@ -34,6 +34,9 @@ function Node(n) {
if (n._alias) {
this._alias = n._alias;
}
+ if (n.env) {
+ this.env = n.env;
+ }
if (n._flow) {
// Make this a non-enumerable property as it may cause
// circular references. Any existing code that tries to JSON serialise
@@ -236,6 +239,22 @@ Node.prototype.receive = function(msg) {
}
};
+Node.prototype.getenv = function(name) {
+ var flow = this._flow;
+ if (flow) {
+ var val = flow.getSetting(name);
+ return val;
+ }
+ return undefined;
+};
+
+Node.prototype.setenv = function(name, val) {
+ var flow = this._flow;
+ if (flow) {
+ flow.setSetting(name, val);
+ }
+};
+
function log_helper(self, level, msg) {
var o = {
level: level,
diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js
index 20399f19d..8af2185ff 100644
--- a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js
+++ b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Flow.js
@@ -461,6 +461,10 @@ class Flow {
}
console.log("==================")
}
+
+ getenv(name) {
+ return process.env[name];
+ }
}
/**
diff --git a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Subflow.js b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Subflow.js
index cf393868e..883a47af0 100644
--- a/packages/node_modules/@node-red/runtime/lib/nodes/flows/Subflow.js
+++ b/packages/node_modules/@node-red/runtime/lib/nodes/flows/Subflow.js
@@ -22,6 +22,35 @@ const flowUtil = require("./util");
var Log;
+
+/**
+ * Convert env var definition of subflow template and instance to env var dic
+ * @param {Hash} env1 env var definition of template
+ * @param {Hash} env2 env var definition of instance
+ * @return {Hash} env var dic
+ */
+function env2Dic(env0, env1) {
+ var dic = {};
+ function add(env) {
+ for(var i = 0; i < env.length; i++) {
+ var item = env[i];
+ var name = item.name;
+ var info = Object.assign({}, item.info);
+ info.name = name;
+ dic[name] = item;
+ dic[name+"_type"] = { value: item.type };
+ dic[name+"_info"] = { value: info };
+ }
+ }
+ if (env0) {
+ add(env0);
+ }
+ if (env1) {
+ add(env1);
+ }
+ return dic;
+}
+
/**
* This class represents a subflow - which is handled as a special type of Flow
*/
@@ -104,12 +133,14 @@ class Subflow extends Flow {
var self = this;
// Create a subflow node to accept inbound messages and route appropriately
var Node = require("../Node");
+ var env = env2Dic(this.subflowDef.env, this.subflowInstance.env);
var subflowInstanceConfig = {
id: this.subflowInstance.id,
type: this.subflowInstance.type,
z: this.subflowInstance.z,
name: this.subflowInstance.name,
wires: [],
+ env: env,
_flow: this
}
if (this.subflowDef.in) {
@@ -164,7 +195,7 @@ class Subflow extends Flow {
self.node._updateWires(subflowInstanceConfig.wires);
}
}
- }
+ };
// Wire the subflow outputs
if (this.subflowDef.out) {
@@ -172,7 +203,7 @@ class Subflow extends Flow {
for (var i=0;i');
expr._legacyMode = /(^|[^a-zA-Z0-9_'"])msg([^a-zA-Z0-9_'"]|$)/.test(value);
diff --git a/test/nodes/subflow/subflow_spec.js b/test/nodes/subflow/subflow_spec.js
new file mode 100644
index 000000000..86b7e33e0
--- /dev/null
+++ b/test/nodes/subflow/subflow_spec.js
@@ -0,0 +1,408 @@
+/**
+* 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("nr-test-utils").require("@node-red/nodes/core/core/80-function.js");
+var helper = require("node-red-node-test-helper");
+
+// Notice:
+// - nodes should have x, y, z property when defining subflow.
+
+describe('subflow', function() {
+
+ before(function(done) {
+ helper.startServer(done);
+ });
+
+ after(function(done) {
+ helper.stopServer(done);
+ });
+
+ afterEach(function() {
+ helper.unload();
+ });
+
+ it('should define subflow', function(done) {
+ var flow = [
+ {id:"t1", type:"tab"},
+ {id:"n1", z:"t1", type:"subflow:s1", wires:[["n2"]]},
+ {id:"n2", z:"t1", type:"helper", wires:[]},
+ // Subflow
+ {id:"s1", type:"subflow", name:"Subflow", info:"",
+ in:[{wires:[ {id:"s1-n1"} ]}],
+ out:[{wires:[ {id:"s1-n1", port:0} ]}]},
+ {id:"s1-n1", z:"s1", type:"function",
+ func:"return msg;", wires:[]}
+ ];
+ helper.load(functionNode, flow, function() {
+ done();
+ });
+ });
+
+ it('should pass data to/from subflow', function(done) {
+ var flow = [
+ {id:"t0", type:"tab", label:"", disabled:false, info:""},
+ {id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
+ {id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
+ // Subflow
+ {id:"s1", type:"subflow", name:"Subflow", info:"",
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1", port:0} ]
+ }]
+ },
+ {id:"s1-n1", x:10, y:10, z:"s1", type:"function",
+ func:"msg.payload = msg.payload+'bar'; return msg;", wires:[]}
+ ];
+ helper.load(functionNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ msg.should.have.property("payload", "foobar");
+ done();
+ });
+ n1.receive({payload:"foo"});
+ });
+ });
+
+ it('should pass data to/from nested subflow', function(done) {
+ var flow = [
+ {id:"t0", type:"tab", label:"", disabled:false, info:""},
+ {id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
+ {id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
+ // Subflow1
+ {id:"s1", type:"subflow", name:"Subflow1", info:"",
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n2", port:0} ]
+ }]
+ },
+ {id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
+ wires:[["s1-n2"]]},
+ {id:"s1-n2", x:10, y:10, z:"s1", type:"function",
+ func:"msg.payload = msg.payload+'baz'; return msg;", wires:[]},
+ // Subflow2
+ {id:"s2", type:"subflow", name:"Subflow2", info:"",
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s2-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s2-n1", port:0} ]
+ }]
+ },
+ {id:"s2-n1", x:10, y:10, z:"s2", type:"function",
+ func:"msg.payload=msg.payload+'bar'; return msg;", wires:[]}
+ ];
+ helper.load(functionNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ msg.should.have.property("payload", "foobarbaz");
+ done();
+ });
+ n1.receive({payload:"foo"});
+ });
+ });
+
+ it('should access env var of subflow template', function(done) {
+ var flow = [
+ {id:"t0", type:"tab", label:"", disabled:false, info:""},
+ {id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
+ {id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
+ // Subflow
+ {id:"s1", type:"subflow", name:"Subflow", info:"",
+ env: [
+ {name: "K", type: "T", value: "V",
+ info: {
+ name: "K",
+ label: "",
+ value: "V",
+ type: "T",
+ target_type: "env var",
+ "target": "K"
+ }}
+ ],
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1", port:0} ]
+ }]
+ },
+ {id:"s1-n1", x:10, y:10, z:"s1", type:"function",
+ func:"msg.V = env.get('K'); msg.T = env.get('K_type'); msg.I = env.get('K_info'); return msg;",
+ wires:[]}
+ ];
+ helper.load(functionNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ try {
+ msg.should.have.property("V", "V");
+ msg.should.have.property("T", "T");
+ msg.should.have.property("I");
+ done();
+ }
+ catch (e) {
+ console.log(e);
+ done(e);
+ }
+ });
+ n1.receive({payload:"foo"});
+ });
+ });
+
+ it('should access env var of subflow instance', function(done) {
+ var flow = [
+ {id:"t0", type:"tab", label:"", disabled:false, info:""},
+ {id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
+ env: [
+ {name: "K", type: "T", value: "V",
+ info: {
+ name: "K",
+ label: "",
+ value: "V",
+ type: "T",
+ target_type: "env var",
+ "target": "K"
+ }}
+ ],
+ wires:[["n2"]]},
+ {id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
+ // Subflow
+ {id:"s1", type:"subflow", name:"Subflow", info:"",
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1", port:0} ]
+ }]
+ },
+ {id:"s1-n1", x:10, y:10, z:"s1", type:"function",
+ func:"msg.V = env.get('K'); msg.T = env.get('K_type'); msg.I = env.get('K_info'); return msg;",
+ wires:[]}
+ ];
+ helper.load(functionNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ try {
+ msg.should.have.property("V", "V");
+ msg.should.have.property("T", "T");
+ msg.should.have.property("I");
+ done();
+ }
+ catch (e) {
+ console.log(e);
+ done(e);
+ }
+ });
+ n1.receive({payload:"foo"});
+ });
+ });
+
+ it('should overwrite env var of subflow template by env var of subflow instance', function(done) {
+ var flow = [
+ {id:"t0", type:"tab", label:"", disabled:false, info:""},
+ {id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
+ env: [
+ {name: "K", type: "T", value: "V",
+ info: {
+ name: "K",
+ label: "",
+ value: "V",
+ type: "T",
+ target_type: "env var",
+ "target": "K"
+ }}
+ ],
+ wires:[["n2"]]},
+ {id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
+ // Subflow
+ {id:"s1", type:"subflow", name:"Subflow", info:"",
+ env: [
+ {name: "K", type: "TT", value: "TV",
+ info: {
+ name: "K",
+ label: "",
+ value: "TV",
+ type: "TT",
+ target_type: "env var",
+ "target": "K"
+ }}
+ ],
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1", port:0} ]
+ }]
+ },
+ {id:"s1-n1", x:10, y:10, z:"s1", type:"function",
+ func:"msg.V = env.get('K'); msg.T = env.get('K_type'); msg.I = env.get('K_info'); return msg;",
+ wires:[]}
+ ];
+ helper.load(functionNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ try {
+ msg.should.have.property("V", "V");
+ msg.should.have.property("T", "T");
+ msg.should.have.property("I");
+ done();
+ }
+ catch (e) {
+ console.log(e);
+ done(e);
+ }
+ });
+ n1.receive({payload:"foo"});
+ });
+ });
+
+ it('should access env var of parent subflow template', function(done) {
+ var flow = [
+ {id:"t0", type:"tab", label:"", disabled:false, info:""},
+ {id:"n1", x:10, y:10, z:"t0", type:"subflow:s1", wires:[["n2"]]},
+ {id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
+ // Subflow1
+ {id:"s1", type:"subflow", name:"Subflow1", info:"",
+ env: [
+ {name: "K", type: "T", value: "V",
+ info: {
+ name: "K",
+ label: "",
+ value: "V",
+ type: "T",
+ target_type: "env var",
+ "target": "K"
+ }}
+ ],
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n2", port:0} ]
+ }]
+ },
+ {id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
+ wires:[["s1-n2"]]},
+ {id:"s1-n2", x:10, y:10, z:"s1", type:"function",
+ func:"return msg;", wires:[]},
+ // Subflow2
+ {id:"s2", type:"subflow", name:"Subflow2", info:"",
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s2-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s2-n1", port:0} ]
+ }]
+ },
+ {id:"s2-n1", x:10, y:10, z:"s2", type:"function",
+ func:"msg.V = env.get('K'); return msg;",
+ wires:[]}
+ ];
+ helper.load(functionNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ msg.should.have.property("V", "V");
+ done();
+ });
+ n1.receive({payload:"foo"});
+ });
+ });
+
+ it('should access env var of parent subflow instance', function(done) {
+ var flow = [
+ {id:"t0", type:"tab", label:"", disabled:false, info:""},
+ {id:"n1", x:10, y:10, z:"t0", type:"subflow:s1",
+ env: [
+ {name: "K", type: "T", value: "V",
+ info: {
+ name: "K",
+ label: "",
+ value: "V",
+ type: "T",
+ target_type: "env var",
+ "target": "K"
+ }}
+ ],
+ wires:[["n2"]]},
+ {id:"n2", x:10, y:10, z:"t0", type:"helper", wires:[]},
+ // Subflow1
+ {id:"s1", type:"subflow", name:"Subflow1", info:"",
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s1-n2", port:0} ]
+ }]
+ },
+ {id:"s1-n1", x:10, y:10, z:"s1", type:"subflow:s2",
+ wires:[["s1-n2"]]},
+ {id:"s1-n2", x:10, y:10, z:"s1", type:"function",
+ func:"return msg;", wires:[]},
+ // Subflow2
+ {id:"s2", type:"subflow", name:"Subflow2", info:"",
+ in:[{
+ x:10, y:10,
+ wires:[ {id:"s2-n1"} ]
+ }],
+ out:[{
+ x:10, y:10,
+ wires:[ {id:"s2-n1", port:0} ]
+ }]
+ },
+ {id:"s2-n1", x:10, y:10, z:"s2", type:"function",
+ func:"msg.V = env.get('K'); return msg;",
+ wires:[]}
+ ];
+ helper.load(functionNode, flow, function() {
+ var n1 = helper.getNode("n1");
+ var n2 = helper.getNode("n2");
+ n2.on("input", function(msg) {
+ msg.should.have.property("V", "V");
+ done();
+ });
+ n1.receive({payload:"foo"});
+ });
+ });
+
+});
diff --git a/test/unit/@node-red/runtime/lib/nodes/flows/Subflow_spec.js b/test/unit/@node-red/runtime/lib/nodes/flows/Subflow_spec.js
index 732c406f7..bb4c7f372 100644
--- a/test/unit/@node-red/runtime/lib/nodes/flows/Subflow_spec.js
+++ b/test/unit/@node-red/runtime/lib/nodes/flows/Subflow_spec.js
@@ -67,10 +67,12 @@ describe('Subflow', function() {
this.foo = n.foo;
this.handled = 0;
this.stopped = false;
+ this.received = null;
currentNodes[node.id] = node;
this.on('input',function(msg) {
// console.log(this.id,msg.payload);
node.handled++;
+ node.received = msg.payload;
node.send(msg);
});
this.on('close',function() {
@@ -170,6 +172,34 @@ describe('Subflow', function() {
}
util.inherits(TestAsyncNode,Node);
+ var TestEnvNode = function(n) {
+ Node.call(this,n);
+ this._index = createCount++;
+ this.scope = n.scope;
+ this.foo = n.foo;
+ var node = this;
+ this.stopped = false;
+ this.received = null;
+ currentNodes[node.id] = node;
+ this.on('input',function(msg) {
+ var val = node.getenv("__KEY__");
+ node.received = val;
+ node.send({payload: val});
+ });
+ this.on('close',function() {
+ node.stopped = true;
+ stoppedNodes[node.id] = node;
+ delete currentNodes[node.id];
+ });
+ this.__updateWires = this.updateWires;
+ this.updateWires = function(newWires) {
+ rewiredNodes[node.id] = node;
+ node.newWires = newWires;
+ node.__updateWires(newWires);
+ };
+ }
+ util.inherits(TestEnvNode,Node);
+
before(function() {
getType = sinon.stub(typeRegistry,"get",function(type) {
if (type=="test") {
@@ -178,6 +208,8 @@ describe('Subflow', function() {
return TestErrorNode;
} else if (type=="testStatus"){
return TestStatusNode;
+ } else if (type=="testEnv"){
+ return TestEnvNode;
} else {
return TestAsyncNode;
}
@@ -533,4 +565,128 @@ describe('Subflow', function() {
});
+ describe("#env var", function() {
+ it("can access process env var", function(done) {
+ var config = flowUtils.parseConfig([
+ {id:"t1",type:"tab"},
+ {id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
+ {id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
+ {id:"3",x:10,y:10,z:"t1",type:"test",foo:"t1.3",wires:[]},
+ {id:"sf1",type:"subflow",name:"Subflow 2",info:"",
+ "in":[ {wires:[{id:"sf1-1"}]} ],
+ "out":[ {wires:[{id:"sf1-2",port:0}]} ]},
+ {id:"sf1-1",type:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
+ {id:"sf1-2",type:"testEnv",z:"sf1",foo:"sf1-cn",x:166,y:99,wires:[[]]}
+ ]);
+ var flow = Flow.create({
+ getSetting: k=> process.env[k],
+ handleError: (a,b,c) => { console.log(a,b,c); }
+ },config,config.flows["t1"]);
+
+ flow.start();
+
+ process.env["__KEY__"] = "__VAL__";
+
+ currentNodes["1"].receive({payload: "test"});
+ currentNodes["3"].should.have.a.property("received", "__VAL__");
+
+ flow.stop().then(function() {
+ done();
+ });
+ });
+
+ it("can access subflow env var", function(done) {
+ var config = flowUtils.parseConfig([
+ {id:"t1",type:"tab"},
+ {id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
+ {id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
+ {id:"3",x:10,y:10,z:"t1",type:"test",foo:"t1.3",wires:[]},
+ {id:"sf1",type:"subflow",name:"Subflow 2",info:"",
+ "in":[ {wires:[{id:"sf1-1"}]} ],
+ "out":[ {wires:[{id:"sf1-2",port:0}]} ]},
+ {id:"sf1-1",type:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
+ {id:"sf1-2",type:"testEnv",z:"sf1",foo:"sf1.2",x:166,y:99,wires:[[]]}
+ ]);
+ var flow = Flow.create({
+ getSetting: k=> process.env[k],
+ handleError: (a,b,c) => { console.log(a,b,c); }
+ },config,config.flows["t1"]);
+
+ flow.start();
+
+ var testenv_node = null;
+ for (var n in currentNodes) {
+ var node = currentNodes[n];
+ if (node.type === "testEnv") {
+ testenv_node = node;
+ break;
+ }
+ }
+ process.env["__KEY__"] = "__VAL0__";
+ testenv_node.setenv("__KEY__", "__VAL1__");
+
+ currentNodes["1"].receive({payload: "test"});
+ currentNodes["3"].should.have.a.property("received", "__VAL1__");
+
+ flow.stop().then(function() {
+ done();
+ });
+ });
+
+ it("can access nested subflow env var", function(done) {
+ var config = flowUtils.parseConfig([
+ {id:"t1",type:"tab"},
+ {id:"1",x:10,y:10,z:"t1",type:"test",foo:"t1.1",wires:["2"]},
+ {id:"2",x:10,y:10,z:"t1",type:"subflow:sf1",wires:["3"]},
+ {id:"3",x:10,y:10,z:"t1",type:"test",foo:"t1.3",wires:[]},
+ {id:"sf1",type:"subflow",name:"Subflow 1",info:"",
+ in:[{wires:[{id:"sf1-1"}]}],
+ out:[{wires:[{id:"sf1-2",port:0}]}]},
+ {id:"sf2",type:"subflow",name:"Subflow 2",info:"",
+ in:[{wires:[{id:"sf2-1"}]}],
+ out:[{wires:[{id:"sf2-2",port:0}]}]},
+ {id:"sf1-1",type:"test",z:"sf1",foo:"sf1.1",x:166,y:99,wires:[["sf1-2"]]},
+ {id:"sf1-2",type:"subflow:sf2",z:"sf1",x:166,y:99,wires:[[]]},
+ {id:"sf2-1",type:"test",z:"sf2",foo:"sf2.1",x:166,y:99,wires:[["sf2-2"]]},
+ {id:"sf2-2",type:"testEnv",z:"sf2",foo:"sf2.2",x:166,y:99,wires:[[]]},
+ ]);
+ var flow = Flow.create({
+ getSetting: k=> process.env[k],
+ handleError: (a,b,c) => { console.log(a,b,c); }
+ },config,config.flows["t1"]);
+
+ flow.start();
+
+ var node_sf1_1 = null;
+ var node_sf2_1 = null;
+ var testenv_node = null;
+ for (var n in currentNodes) {
+ var node = currentNodes[n];
+ if (node.foo === "sf1.1") {
+ node_sf1_1 = node;
+ }
+ if (node.foo === "sf2.1") {
+ node_sf2_1 = node;
+ }
+ }
+
+ process.env["__KEY__"] = "__VAL0__";
+ currentNodes["1"].receive({payload: "test"});
+ currentNodes["3"].should.have.a.property("received", "__VAL0__");
+
+ node_sf1_1.setenv("__KEY__", "__VAL1__");
+ currentNodes["1"].receive({payload: "test"});
+ currentNodes["3"].should.have.a.property("received", "__VAL1__");
+
+ node_sf2_1.setenv("__KEY__", "__VAL2__");
+ currentNodes["1"].receive({payload: "test"});
+ currentNodes["3"].should.have.a.property("received", "__VAL2__");
+
+ flow.stop().then(function() {
+ done();
+ });
+ });
+
+ });
+
});