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

@@ -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]');
});
});
});
});