mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Add open/close API for context
This commit is contained in:
		| @@ -90,6 +90,7 @@ function start() { | ||||
|         }) | ||||
|         .then(function() { return storage.init(runtime)}) | ||||
|         .then(function() { return settings.load(storage)}) | ||||
|         .then(function() { return redNodes.loadContextsPlugin()}) | ||||
|         .then(function() { | ||||
|  | ||||
|             if (log.metric()) { | ||||
| @@ -109,8 +110,6 @@ function start() { | ||||
|                 events.emit("runtime-event",{id:"runtime-unsupported-version",payload:{type:"error",text:"notification.errors.unsupportedVersion"},retain:true}); | ||||
|             } | ||||
|             log.info(os.type()+" "+os.release()+" "+os.arch()+" "+os.endianness()); | ||||
|             log.info("Loading external context plugins"); | ||||
|             redNodes.loadContextsPlugin(); | ||||
|             return redNodes.load().then(function() { | ||||
|  | ||||
|                 var i; | ||||
| @@ -231,7 +230,9 @@ function stop() { | ||||
|         clearTimeout(reinstallTimeout); | ||||
|     } | ||||
|     started = false; | ||||
|     return redNodes.stopFlows(); | ||||
|     return redNodes.stopFlows().then(function(){ | ||||
|         return redNodes.closeContextsPlugin(); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| var runtime = module.exports = { | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
| var clone = require("clone"); | ||||
| var util = require("../../util"); | ||||
| var log = require("../../log"); | ||||
| var when = require("when"); | ||||
|  | ||||
| var settings; | ||||
| var contexts = {}; | ||||
| @@ -30,8 +31,10 @@ function init(_settings) { | ||||
|  | ||||
|     // init memory plugin | ||||
|     var memory = require("./memory"); | ||||
|     var seed = settings.functionGlobalContext || {}; | ||||
|     externalContexts["_"] = memory(); | ||||
|     globalContext = createContext("global",settings.functionGlobalContext || {}); | ||||
|     externalContexts["_"].setGlobalContext(seed); | ||||
|     globalContext = createContext("global",seed); | ||||
| } | ||||
|  | ||||
| function load() { | ||||
| @@ -39,6 +42,7 @@ function load() { | ||||
|     var plugins = settings.contextStorage; | ||||
|     var isAlias = false; | ||||
|     if (plugins) { | ||||
|         var promises = []; | ||||
|         noContextStorage = false; | ||||
|         for(var pluginName in plugins){ | ||||
|             if(pluginName === "_"){ | ||||
| @@ -56,25 +60,32 @@ function load() { | ||||
|                     try{ | ||||
|                         plugin = require("./"+plugins[pluginName].module); | ||||
|                     }catch(err){ | ||||
|                         throw new Error(log._("context.error-module-not-loaded", {module:plugins[pluginName].module})); | ||||
|                         return when.reject(new Error(log._("context.error-module-not-loaded", {module:plugins[pluginName].module}))); | ||||
|                     } | ||||
|                 } else { | ||||
|                     plugin = plugins[pluginName].module; | ||||
|                 } | ||||
|                 externalContexts[pluginName] = plugin(config); | ||||
|             }else{ | ||||
|                 throw new Error(log._("context.error-module-not-defined", {storage:pluginName})); | ||||
|                 return when.reject(new Error(log._("context.error-module-not-defined", {storage:pluginName}))); | ||||
|             } | ||||
|         } | ||||
|         if(isAlias){ | ||||
|             if(externalContexts.hasOwnProperty(plugins["default"])){ | ||||
|                 externalContexts["default"] =  externalContexts[plugins["default"]]; | ||||
|             }else{ | ||||
|                 throw new Error(log._("context.error-invalid-default-module", {storage:plugins["default"]})); | ||||
|                 return when.reject(new Error(log._("context.error-invalid-default-module", {storage:plugins["default"]}))); | ||||
|             } | ||||
|         } | ||||
|         for(var plugin in externalContexts){ | ||||
|             if(externalContexts.hasOwnProperty(plugin)){ | ||||
|                 promises.push(externalContexts[plugin].open()); | ||||
|             } | ||||
|         } | ||||
|         return when.all(promises); | ||||
|     } else { | ||||
|         noContextStorage = true; | ||||
|         return externalContexts["_"].open(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -157,9 +168,6 @@ function createContext(id,seed) { | ||||
|         var context = getContextStorage(storageName); | ||||
|         return context.keys(scope); | ||||
|     }; | ||||
|     if(id === "global"){ | ||||
|         externalContexts["_"].setGlobalContext(seed); | ||||
|     } | ||||
|     return obj; | ||||
| } | ||||
|  | ||||
| @@ -210,10 +218,21 @@ function clean(flowConfig) { | ||||
|     } | ||||
| } | ||||
|  | ||||
| function close() { | ||||
|     var promises = []; | ||||
|     for(var plugin in externalContexts){ | ||||
|         if(externalContexts.hasOwnProperty(plugin)){ | ||||
|             promises.push(externalContexts[plugin].close()); | ||||
|         } | ||||
|     } | ||||
|     return when.all(promises); | ||||
| } | ||||
|  | ||||
| module.exports = { | ||||
|     init: init, | ||||
|     load: load, | ||||
|     get: getContext, | ||||
|     delete: deleteContext, | ||||
|     clean:clean | ||||
|     clean: clean, | ||||
|     close: close | ||||
| }; | ||||
|   | ||||
| @@ -17,11 +17,10 @@ | ||||
| var JsonDB = require('node-json-db'); | ||||
| var fs = require('fs-extra'); | ||||
| var path = require("path"); | ||||
| var when = require("when"); | ||||
|  | ||||
| function createStorage(storageBaseDir, scope) { | ||||
|     var i = scope.indexOf(":") | ||||
|      | ||||
|     if(i === -1){ | ||||
|     if(scope.indexOf(":") === -1){ | ||||
|         if(scope === "global"){ | ||||
|             return new JsonDB(path.join(storageBaseDir,"global",scope), true, true);  | ||||
|         }else{ // scope:flow | ||||
| @@ -69,6 +68,14 @@ function LocalFileSystem(config){ | ||||
|     this.storages = {}; | ||||
| } | ||||
|  | ||||
| LocalFileSystem.prototype.open = function(){ | ||||
|     return when.resolve(); | ||||
| } | ||||
|  | ||||
| LocalFileSystem.prototype.close = function(){ | ||||
|     return when.resolve(); | ||||
| } | ||||
|  | ||||
| LocalFileSystem.prototype.get = function (scope, key) { | ||||
|     if(!this.storages[scope]){ | ||||
|         return undefined; | ||||
|   | ||||
| @@ -15,11 +15,20 @@ | ||||
|  **/ | ||||
|  | ||||
| var util = require("../../util"); | ||||
| var when = require("when"); | ||||
|  | ||||
| function Memory(config){ | ||||
|     this.data = {}; | ||||
| } | ||||
|  | ||||
| Memory.prototype.open = function(){ | ||||
|     return when.resolve(); | ||||
| }; | ||||
|  | ||||
| Memory.prototype.close = function(){ | ||||
|     return when.resolve(); | ||||
| }; | ||||
|  | ||||
| Memory.prototype.get = function(scope, key) { | ||||
|     if(!this.data[scope]){ | ||||
|         return undefined; | ||||
| @@ -49,14 +58,7 @@ Memory.prototype.keys = function(scope){ | ||||
|  | ||||
| Memory.prototype.delete = function(scope){ | ||||
|     delete this.data[scope]; | ||||
| }; | ||||
|  | ||||
| Memory.prototype.open = function(){ | ||||
|     return true; | ||||
| }; | ||||
|  | ||||
| Memory.prototype.close = function(){ | ||||
|     delete this.data; | ||||
| }; | ||||
|  | ||||
| Memory.prototype.setGlobalContext= function(seed){ | ||||
|   | ||||
| @@ -219,5 +219,6 @@ module.exports = { | ||||
|     getCredentialKeyType: credentials.getKeyType, | ||||
|  | ||||
|     // Contexts | ||||
|     loadContextsPlugin: context.load | ||||
|     loadContextsPlugin: context.load, | ||||
|     closeContextsPlugin: context.close | ||||
| }; | ||||
|   | ||||
| @@ -92,7 +92,7 @@ describe("runtime", function() { | ||||
|             redNodesCleanModuleList = sinon.stub(redNodes,"cleanModuleList",function(){}); | ||||
|             redNodesLoadFlows = sinon.stub(redNodes,"loadFlows",function() {return when.resolve()}); | ||||
|             redNodesStartFlows = sinon.stub(redNodes,"startFlows",function() {}); | ||||
|             redNodesLoadContextsPlugin = sinon.stub(redNodes,"loadContextsPlugin",function() {}); | ||||
|             redNodesLoadContextsPlugin = sinon.stub(redNodes,"loadContextsPlugin",function() {return when.resolve()}); | ||||
|         }); | ||||
|         afterEach(function() { | ||||
|             storageInit.restore(); | ||||
| @@ -186,7 +186,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 when.resolve();} ); | ||||
|             redNodesGetNodeList = sinon.stub(redNodes,"getNodeList", function() {return []}); | ||||
|             logMetric.restore(); | ||||
|             logMetric = sinon.stub(log,"metric",function() { return true; }); | ||||
| @@ -217,10 +217,18 @@ 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 when.resolve();} ); | ||||
|         var closeContextsPlugin = sinon.stub(redNodes,"closeContextsPlugin",function() { return when.resolve();} ); | ||||
|         runtime.stop().then(function(){ | ||||
|             stopFlows.called.should.be.true(); | ||||
|             closeContextsPlugin.called.should.be.true(); | ||||
|             done(); | ||||
|         }).catch(function(err){ | ||||
|             return done(err) | ||||
|         }).finally(function(){ | ||||
|             stopFlows.restore(); | ||||
|             closeContextsPlugin.restore(); | ||||
|         }); | ||||
|     }); | ||||
| }); | ||||
|   | ||||
| @@ -16,18 +16,18 @@ | ||||
|  | ||||
| var should = require("should"); | ||||
| var sinon = require('sinon'); | ||||
| var path = require('path'); | ||||
| var fs = require('fs-extra'); | ||||
| var rewire = require("rewire"); | ||||
| var Context = require("../../../../../red/runtime/nodes/context/index"); | ||||
|  | ||||
| describe('context', function() { | ||||
|     describe('localmemory',function() { | ||||
|     describe('local memory',function() { | ||||
|         beforeEach(function() { | ||||
|             Context.init({}); | ||||
|             return Context.load(); | ||||
|         }); | ||||
|         afterEach(function() { | ||||
|             Context.clean({allNodes:{}}); | ||||
|             return Context.close(); | ||||
|         }); | ||||
|         it('stores local property',function() { | ||||
|             var context1 = Context.get("1","flowA"); | ||||
| @@ -140,57 +140,261 @@ describe('context', function() { | ||||
|             keys.should.have.length(2); | ||||
|             keys[1].should.eql("abc"); | ||||
|         }); | ||||
|  | ||||
|         it('should store data on memory when contextStorage is not defined', function() { | ||||
|             var context =  Context.get("1","flow"); | ||||
|             context.set("#nonexist.key1", "val1"); | ||||
|             context.get("#nonexist.key1").should.eql("val1"); | ||||
|             context.flow.set("#nonexist.key2", "val2"); | ||||
|             context.flow.get("#nonexist.key2").should.eql("val2"); | ||||
|             context.global.set("#nonexist.key1", "val3"); | ||||
|             context.global.get("#nonexist.key1").should.eql("val3"); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('external context storage',function() { | ||||
|         var testDir = path.join(__dirname,".testUserHome"); | ||||
|         var context; | ||||
|         var stubGet = sinon.stub(); | ||||
|         var stubSet = sinon.stub(); | ||||
|         var stubKeys = sinon.stub(); | ||||
|         var stubDelete = sinon.stub(); | ||||
|         var contextStorage={ | ||||
|             test:{ | ||||
|                 module: function(config){ | ||||
|                     function Test(){} | ||||
|                     Test.prototype.get = stubGet; | ||||
|                     Test.prototype.set = stubSet; | ||||
|                     Test.prototype.keys = stubKeys; | ||||
|                     Test.prototype.delete = stubDelete; | ||||
|                     return new Test(config); | ||||
|                 }, | ||||
|                 config:{} | ||||
|             } | ||||
|         }; | ||||
|         describe('load modules',function(){ | ||||
|             afterEach(function() { | ||||
|                 Context.clean({allNodes:{}}); | ||||
|                 return Context.close(); | ||||
|             }); | ||||
|  | ||||
|         afterEach(function(done) { | ||||
|             stubGet.reset(); | ||||
|             stubSet.reset(); | ||||
|             stubKeys.reset(); | ||||
|             stubDelete.reset(); | ||||
|             Context.clean({allNodes:{}}); | ||||
|             fs.remove(testDir,done); | ||||
|             it('should load memory module', function() { | ||||
|                 Context.init({contextStorage:{memory:{module:"memory"}}}); | ||||
|                 return Context.load(); | ||||
|             }); | ||||
|             it('should load localfilesystem module', function() { | ||||
|                 Context.init({contextStorage:{file:{module:"localfilesystem"}}}); | ||||
|                 return Context.load(); | ||||
|             }); | ||||
|             it('should accept special storage name', function() { | ||||
|                 Context.init({ | ||||
|                     contextStorage:{ | ||||
|                         "#%&":{module:"memory"}, | ||||
|                         \u3042:{module:"memory"}, | ||||
|                         1:{module:"memory"}, | ||||
|                     } | ||||
|                 }); | ||||
|                 return Context.load().then(function(){ | ||||
|                     var context = Context.get("1","flow"); | ||||
|                     context.set("##%&.sign","sign1"); | ||||
|                     context.get("##%&.sign").should.eql("sign1"); | ||||
|                     context.set("#\u3042.file2","file2"); | ||||
|                     context.get("#\u3042.file2").should.eql("file2"); | ||||
|                     context.set("#1.num","num3"); | ||||
|                     context.get("#1.num").should.eql("num3"); | ||||
|                 }); | ||||
|             }); | ||||
|             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(); | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         function initializeContext() { | ||||
|             Context.init({contextStorage:contextStorage}); | ||||
|             Context.load(); | ||||
|             context =  Context.get("1","flow"); | ||||
|         } | ||||
|  | ||||
|         describe('key name',function() { | ||||
|             var memoryStorage = { | ||||
|                 memory: { | ||||
|                     module: "memory" | ||||
|         describe('store data',function() { | ||||
|             var sandbox = sinon.sandbox.create(); | ||||
|             var stubGet = sandbox.stub(); | ||||
|             var stubSet = sandbox.stub(); | ||||
|             var stubKeys = sandbox.stub(); | ||||
|             var stubDelete = sandbox.stub(); | ||||
|             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(); | ||||
|             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.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.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:{} | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             afterEach(function() { | ||||
|                 sandbox.reset(); | ||||
|                 Context.clean({allNodes:{}}); | ||||
|                 return Context.close(); | ||||
|             }); | ||||
|      | ||||
|             it('should store local property to external context storage',function() { | ||||
|                 Context.init({contextStorage:contextStorage}); | ||||
|                 return Context.load().then(function(){ | ||||
|                     var context =  Context.get("1","flow"); | ||||
|                     should.not.exist(context.get("#test.foo")); | ||||
|                     context.set("#test.foo","test"); | ||||
|                     context.get("#test.foo"); | ||||
|                     context.keys("#test"); | ||||
|                     stubSet.calledWithExactly("1:flow","foo","test").should.be.true(); | ||||
|                     stubGet.calledWithExactly("1:flow","foo").should.be.true(); | ||||
|                     stubKeys.calledWithExactly("1:flow").should.be.true(); | ||||
|                 }); | ||||
|             }); | ||||
|             it('should store flow property to external context storage',function() { | ||||
|                 Context.init({contextStorage:contextStorage}); | ||||
|                 return Context.load().then(function(){ | ||||
|                     var context =  Context.get("1","flow"); | ||||
|                     should.not.exist(context.flow.get("#test.foo")); | ||||
|                     context.flow.set("#test.foo","test"); | ||||
|                     context.flow.get("#test.foo"); | ||||
|                     context.flow.keys("#test"); | ||||
|                     stubSet.calledWithExactly("flow","foo","test").should.be.true(); | ||||
|                     stubGet.calledWithExactly("flow","foo").should.be.true(); | ||||
|                     stubKeys.calledWithExactly("flow").should.be.true(); | ||||
|                 }); | ||||
|             }); | ||||
|             it('should store global property to external context storage',function() { | ||||
|                 Context.init({contextStorage:contextStorage}); | ||||
|                 return Context.load().then(function(){ | ||||
|                     var context =  Context.get("1","flow"); | ||||
|                     should.not.exist(context.global.get("#test.foo")); | ||||
|                     context.global.set("#test.foo","test"); | ||||
|                     context.global.get("#test.foo"); | ||||
|                     context.global.keys("#test"); | ||||
|                     stubSet.calledWithExactly("global","foo","test").should.be.true(); | ||||
|                     stubGet.calledWithExactly("global","foo").should.be.true(); | ||||
|                     stubKeys.calledWithExactly("global").should.be.true(); | ||||
|                 }); | ||||
|             }); | ||||
|             it('should store data to the default context when non-existent context storage was specified', function() { | ||||
|                 Context.init({contextStorage:contextDefaultStorage}); | ||||
|                 return Context.load().then(function(){ | ||||
|                     var context =  Context.get("1","flow"); | ||||
|                     should.not.exist(context.get("#nonexist.foo")); | ||||
|                     context.set("#nonexist.foo","test"); | ||||
|                     context.get("#nonexist.foo"); | ||||
|                     context.keys("#nonexist"); | ||||
|                     stubGet.called.should.be.false(); | ||||
|                     stubSet.called.should.be.false(); | ||||
|                     stubKeys.called.should.be.false(); | ||||
|                     stubSet2.calledWithExactly("1:flow","foo","test").should.be.true(); | ||||
|                     stubGet2.calledWithExactly("1:flow","foo").should.be.true(); | ||||
|                     stubKeys2.calledWithExactly("1:flow").should.be.true(); | ||||
|                 }); | ||||
|             }); | ||||
|             it('should use the default context', function() { | ||||
|                 Context.init({contextStorage:contextDefaultStorage}); | ||||
|                 return Context.load().then(function(){ | ||||
|                     var context =  Context.get("1","flow"); | ||||
|                     should.not.exist(context.get("#default.foo")); | ||||
|                     context.set("#default.foo","default"); | ||||
|                     context.get("#default.foo"); | ||||
|                     context.keys("#default"); | ||||
|                     stubGet.called.should.be.false(); | ||||
|                     stubSet.called.should.be.false(); | ||||
|                     stubKeys.called.should.be.false(); | ||||
|                     stubSet2.calledWithExactly("1:flow","foo","default").should.be.true(); | ||||
|                     stubGet2.calledWithExactly("1:flow","foo").should.be.true(); | ||||
|                     stubKeys2.calledWithExactly("1:flow").should.be.true(); | ||||
|                 }); | ||||
|             }); | ||||
|             it('should use the alias of default context', function() { | ||||
|                 Context.init({contextStorage:contextDefaultStorage}); | ||||
|                 return Context.load().then(function(){ | ||||
|                     var context =  Context.get("1","flow"); | ||||
|                     should.not.exist(context.get("#.foo")); | ||||
|                     context.set("#.foo","alias"); | ||||
|                     context.get("#.foo"); | ||||
|                     context.keys("#"); | ||||
|                     stubGet.called.should.be.false(); | ||||
|                     stubSet.called.should.be.false(); | ||||
|                     stubKeys.called.should.be.false(); | ||||
|                     stubSet2.calledWithExactly("1:flow","foo","alias").should.be.true(); | ||||
|                     stubGet2.calledWithExactly("1:flow","foo").should.be.true(); | ||||
|                     stubKeys2.calledWithExactly("1:flow").should.be.true(); | ||||
|                 }); | ||||
|             }); | ||||
|             it('should 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"); | ||||
|                     context.get("#nonexist.local"); | ||||
|                     should.fail(null, null, "An error was not thrown using undefined storage for local context"); | ||||
|                 }).catch(function(err) { | ||||
|                     if (err.name === "ContextError") { | ||||
|                         done(); | ||||
|                     } else { | ||||
|                         done(err); | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|             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"); | ||||
|                     context.flow.set("#nonexist.flow"); | ||||
|                     should.fail(null, null, "An error was not thrown using undefined storage for flow context"); | ||||
|                 }).catch(function(err) { | ||||
|                     if (err.name === "ContextError") { | ||||
|                         done(); | ||||
|                     } else { | ||||
|                         done(err); | ||||
|                     } | ||||
|                 }); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('key name',function() { | ||||
|             beforeEach(function() { | ||||
|                 Context.init({contextStorage:memoryStorage}); | ||||
|                 Context.load(); | ||||
|                 context =  Context.get("1","flow"); | ||||
|                 Context.init({contextStorage:{memory:{module:"memory"}}}); | ||||
|                 return Context.load().then(function(){ | ||||
|                     context =  Context.get("1","flow"); | ||||
|                 }); | ||||
|             }); | ||||
|             afterEach(function() { | ||||
|                 Context.clean({allNodes:{}}); | ||||
|                 return Context.close(); | ||||
|             }); | ||||
|             it('should work correctly with the valid key name',function() { | ||||
|                 context.set("#memory.azAZ09#_","valid"); | ||||
| @@ -222,192 +426,6 @@ describe('context', function() { | ||||
|                 }).should.throw(); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('if external context storage exists',function() { | ||||
|             var contextDefaultStorage={ | ||||
|                 default: "test", | ||||
|                 test:{ | ||||
|                     module: function(config){ | ||||
|                         function Test(){} | ||||
|                         Test.prototype.get = stubGet; | ||||
|                         Test.prototype.set = stubSet; | ||||
|                         Test.prototype.keys = stubKeys; | ||||
|                         Test.prototype.delete = stubDelete; | ||||
|                         return new Test(config); | ||||
|                     }, | ||||
|                     config:{} | ||||
|                 } | ||||
|             }; | ||||
|  | ||||
|             it('should store local property to external context storage',function() { | ||||
|                 initializeContext(); | ||||
|                 should.not.exist(context.get("#test.foo")); | ||||
|                 context.set("#test.foo","test"); | ||||
|                 context.get("#test.foo"); | ||||
|                 context.keys("#test"); | ||||
|                 stubGet.called.should.be.true(); | ||||
|                 stubSet.called.should.be.true(); | ||||
|                 stubKeys.called.should.be.true(); | ||||
|             }); | ||||
|             it('should store flow property to external context storage',function() { | ||||
|                 initializeContext(); | ||||
|                 should.not.exist(context.flow.get("#test.foo")); | ||||
|                 context.flow.set("#test.foo","test"); | ||||
|                 context.flow.get("#test.foo"); | ||||
|                 context.flow.keys("#test"); | ||||
|                 stubGet.called.should.be.true(); | ||||
|                 stubSet.called.should.be.true(); | ||||
|                 stubKeys.called.should.be.true(); | ||||
|             }); | ||||
|             it('should store global property to external context storage',function() { | ||||
|                 initializeContext(); | ||||
|                 should.not.exist(context.global.get("#test.foo")); | ||||
|                 context.global.set("#test.foo","test"); | ||||
|                 context.global.get("#test.foo"); | ||||
|                 context.global.keys("#test"); | ||||
|                 stubGet.called.should.be.true(); | ||||
|                 stubSet.called.should.be.true(); | ||||
|                 stubKeys.called.should.be.true(); | ||||
|             }); | ||||
|             it('should store data when non-existent context storage was specified', function() { | ||||
|                 Context.init({contextStorage:contextDefaultStorage}); | ||||
|                 Context.load(); | ||||
|                 context =  Context.get("1","flow"); | ||||
|                 should.not.exist(context.get("#nonexist.foo")); | ||||
|                 context.set("#nonexist.foo","test"); | ||||
|                 context.get("#nonexist.foo"); | ||||
|                 context.keys("#nonexist"); | ||||
|                 stubGet.called.should.be.true(); | ||||
|                 stubSet.called.should.be.true(); | ||||
|                 stubKeys.called.should.be.true(); | ||||
|             }); | ||||
|             it('should use the default context', function() { | ||||
|                 Context.init({contextStorage:contextDefaultStorage}); | ||||
|                 Context.load(); | ||||
|                 context =  Context.get("1","flow"); | ||||
|                 should.not.exist(context.get("#default.foo")); | ||||
|                 context.set("#default.foo","default"); | ||||
|                 context.get("#default.foo"); | ||||
|                 context.keys("#default"); | ||||
|                 stubGet.called.should.be.true(); | ||||
|                 stubSet.called.should.be.true(); | ||||
|                 stubKeys.called.should.be.true(); | ||||
|             }); | ||||
|             it('should use the alias of default context', function() { | ||||
|                 Context.init({contextStorage:contextDefaultStorage}); | ||||
|                 Context.load(); | ||||
|                 context =  Context.get("1","flow"); | ||||
|                 should.not.exist(context.get("#.foo")); | ||||
|                 context.set("#.foo","alias"); | ||||
|                 context.get("#.foo"); | ||||
|                 context.keys("#"); | ||||
|                 stubGet.called.should.be.true(); | ||||
|                 stubSet.called.should.be.true(); | ||||
|                 stubKeys.called.should.be.true(); | ||||
|             }); | ||||
|             it('should load memory module', function(done) { | ||||
|                 Context.init({ contextStorage: { _: {}}}); | ||||
|                 try { | ||||
|                     Context.load(); | ||||
|                     context.set("#_.foo","mem1"); | ||||
|                     context.get("#_.foo").should.eql("mem1"); | ||||
|                     var keys = context.keys("#_"); | ||||
|                     keys.should.have.length(1); | ||||
|                     keys[0].should.eql("foo"); | ||||
|                     done(); | ||||
|                 } catch (err) { | ||||
|                     done(err); | ||||
|                 } | ||||
|             }); | ||||
|             it('should load localfilesystem module', function(done) { | ||||
|                 Context.init({contextStorage:{ file:{module:"localfilesystem"} }}); | ||||
|                 try { | ||||
|                     Context.load(); | ||||
|                     done(); | ||||
|                 } catch (err) { | ||||
|                     done(err); | ||||
|                 } | ||||
|             }); | ||||
|             it('should accept special storage name', function(done) { | ||||
|                 Context.init({ | ||||
|                     contextStorage:{ | ||||
|                         "#%&":{module:"memory"}, | ||||
|                         \u3042:{module:"memory"}, | ||||
|                         1:{module:"memory"}, | ||||
|                     } | ||||
|                 }); | ||||
|                 try { | ||||
|                     Context.load(); | ||||
|                     context.set("##%&.sign","sign1"); | ||||
|                     context.get("##%&.sign").should.eql("sign1"); | ||||
|                     context.set("#\u3042.file2","file2"); | ||||
|                     context.get("#\u3042.file2").should.eql("file2"); | ||||
|                     context.set("#1.num","num3"); | ||||
|                     context.get("#1.num").should.eql("num3"); | ||||
|                     done(); | ||||
|                 } catch (err) { | ||||
|                     done(err); | ||||
|                 } | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|         describe('if external context storage does not exist',function() { | ||||
|             it('should throw an error using undefined storage for local context', function(done) { | ||||
|                 initializeContext(); | ||||
|                 try { | ||||
|                     context.get("#nonexist.local"); | ||||
|                     should.fail(null, null, "An error was not thrown using undefined storage for local context"); | ||||
|                 } catch (err) { | ||||
|                     if (err.name === "ContextError") { | ||||
|                         done(); | ||||
|                     } else { | ||||
|                         done(err); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|             it('should throw an error using undefined storage for flow context', function(done) { | ||||
|                 initializeContext(); | ||||
|                 try { | ||||
|                     context.flow.set("#nonexist.flow"); | ||||
|                     should.fail(null, null, "An error was not thrown using undefined storage for flow context"); | ||||
|                 } catch (err) { | ||||
|                     if (err.name === "ContextError") { | ||||
|                         done(); | ||||
|                     } else { | ||||
|                         done(err); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|             it('should fail when using invalid default context', function() { | ||||
|                 Context.init({contextStorage:{default:"noexist"}}); | ||||
|                 (function() { | ||||
|                     Context.load(); | ||||
|                 }).should.throw(); | ||||
|             }); | ||||
|             it('should store data on memory when contextStorage is not defined', function() { | ||||
|                 Context.init({}); | ||||
|                 Context.load(); | ||||
|                 context =  Context.get("1","flow"); | ||||
|                 context.set("#nonexist.key1", "val1"); | ||||
|                 context.get("#nonexist.key1").should.eql("val1"); | ||||
|                 context.flow.set("#nonexist.key2", "val2"); | ||||
|                 context.flow.get("#nonexist.key2").should.eql("val2"); | ||||
|                 context.global.set("#nonexist.key1", "val3"); | ||||
|                 context.global.get("#nonexist.key1").should.eql("val3"); | ||||
|             }); | ||||
|             it('should fail for the storage with no module', function() { | ||||
|                 Context.init({ contextStorage: { test: {}}}); | ||||
|                 (function() { | ||||
|                     Context.load(); | ||||
|                 }).should.throw(); | ||||
|             }); | ||||
|             it('should fail to load non-existent module', function() { | ||||
|                 Context.init({contextStorage:{ file:{module:"nonexistent"} }}); | ||||
|                 (function() { | ||||
|                     Context.load(); | ||||
|                 }).should.throw(); | ||||
|             }); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     describe('#parseKey()', function() { | ||||
|   | ||||
| @@ -17,6 +17,7 @@ | ||||
| var should = require('should'); | ||||
| var fs = require('fs-extra'); | ||||
| var path = require("path"); | ||||
| var when = require("when"); | ||||
| var LocalFileSystem = require('../../../../../red/runtime/nodes/context/localfilesystem'); | ||||
|  | ||||
| var resourcesDir = path.resolve(path.join(__dirname,"..","resources","context")); | ||||
| @@ -26,11 +27,12 @@ describe('localfilesystem',function() { | ||||
|  | ||||
|     beforeEach(function() { | ||||
|         context = LocalFileSystem({dir: resourcesDir}); | ||||
|         return context.open(); | ||||
|     }); | ||||
|  | ||||
|     afterEach(function(done) { | ||||
|         fs.remove(resourcesDir).then(function(result){ | ||||
|             return done(result); | ||||
|     afterEach(function() { | ||||
|         return context.close().then(function(){ | ||||
|             return fs.remove(resourcesDir); | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user