1
0
mirror of https://github.com/node-red/node-red.git synced 2023-10-10 13:36:53 +02:00

Add clean to context plugin

and don't delete local context unless the context is deleted by a user
This commit is contained in:
HirokiUchikawa 2018-05-30 15:23:34 +09:00
parent 7185bcd51f
commit f262348497
8 changed files with 260 additions and 107 deletions

View File

@ -105,12 +105,12 @@ Node.prototype.close = function(removed) {
if (promises.length > 0) {
return when.settle(promises).then(function() {
if (this._context) {
context.delete(this._alias||this.id,this.z);
return context.delete(this._alias||this.id,this.z);
}
});
} else {
if (this._context) {
context.delete(this._alias||this.id,this.z);
return context.delete(this._alias||this.id,this.z);
}
return;
}

View File

@ -70,6 +70,11 @@ function load() {
return when.reject(new Error(log._("context.error-module-not-defined", {storage:pluginName})));
}
}
for(var plugin in externalContexts){
if(externalContexts.hasOwnProperty(plugin)){
promises.push(externalContexts[plugin].open());
}
}
if(isAlias){
if(externalContexts.hasOwnProperty(plugins["default"])){
externalContexts["default"] = externalContexts[plugins["default"]];
@ -77,11 +82,6 @@ function load() {
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;
@ -191,31 +191,35 @@ function getContext(localId,flowId) {
}
function deleteContext(id,flowId) {
var contextId = id;
if (flowId) {
contextId = id+":"+flowId;
if(noContextStorage){
var promises = [];
var contextId = id;
if (flowId) {
contextId = id+":"+flowId;
}
delete contexts[contextId];
return externalContexts["_"].delete(contextId);
}else{
return when.resolve();
}
for(var plugin in externalContexts){
externalContexts[plugin].delete(contextId);
}
delete contexts[contextId];
}
function clean(flowConfig) {
var activeIds = {};
var contextId;
var node;
var promises = [];
for(var plugin in externalContexts){
if(externalContexts.hasOwnProperty(plugin)){
promises.push(externalContexts[plugin].clean(Object.keys(flowConfig.allNodes)));
}
}
for (var id in contexts) {
if (contexts.hasOwnProperty(id)) {
var idParts = id.split(":");
if (!flowConfig.allNodes.hasOwnProperty(idParts[0])) {
for(var plugin in externalContexts){
externalContexts[plugin].delete(id);
}
delete contexts[id];
}
}
}
return when.all(promises);
}
function close() {

View File

@ -78,7 +78,7 @@ LocalFileSystem.prototype.close = function(){
LocalFileSystem.prototype.get = function (scope, key) {
if(!this.storages[scope]){
return undefined;
this.storages[scope] = createStorage(this.storageBaseDir ,scope);
}
try{
this.storages[scope].reload();
@ -105,28 +105,38 @@ LocalFileSystem.prototype.set = function(scope, key, value) {
LocalFileSystem.prototype.keys = function(scope) {
if(!this.storages[scope]){
return [];
this.storages[scope] = createStorage(this.storageBaseDir ,scope);
}
return Object.keys(this.storages[scope].getData("/"));
}
LocalFileSystem.prototype.delete = function(scope){
var self = this;
if(this.storages[scope]){
var promise;
this.storages[scope].delete("/");
if(scope.indexOf(":") === -1){
fs.removeSync(path.dirname(this.storages[scope].filename));
}else{
try{
fs.statSync(this.storages[scope].filename);
fs.unlinkSync(this.storages[scope].filename);
}catch(err){
console.log("deleted");
}
}
delete this.storages[scope];
return fs.remove(this.storages[scope].filename).then(function(){
delete self.storages[scope];
return when.resolve();
});
}else{
return when.resolve();
}
}
LocalFileSystem.prototype.clean = function(activeNodes){
var self = this;
return fs.readdir(self.storageBaseDir).then(function(dirs){
return when.all(dirs.reduce(function(result, item){
if(item !== "global" && !activeNodes.includes(item)){
result.push(fs.remove(path.join(self.storageBaseDir,item)));
delete self.storages[item];
}
return result;
},[]));
});
}
module.exports = function(config){
return new LocalFileSystem(config);
};

View File

@ -58,9 +58,21 @@ Memory.prototype.keys = function(scope){
Memory.prototype.delete = function(scope){
delete this.data[scope];
return Promise.resolve();
};
Memory.prototype.clean = function(activeNodes){
for(var id in this.data){
if(this.data.hasOwnProperty(id) && id !== "global"){
var idParts = id.split(":");
if(!activeNodes.includes(idParts[0])){
delete this.data[id];
}
}
}
return Promise.resolve();
}
Memory.prototype.setGlobalContext= function(seed){
this.data["global"] = seed;
};

View File

@ -160,11 +160,12 @@ function setFlows(_config,type,muteLog,forceStart) {
activeFlowConfig = newFlowConfig;
if (forceStart || started) {
return stop(type,diff,muteLog).then(function() {
context.clean(activeFlowConfig);
start(type,diff,muteLog).then(function() {
events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true});
return context.clean(activeFlowConfig).then(function() {
start(type,diff,muteLog).then(function() {
events.emit("runtime-event",{id:"runtime-deploy",payload:{revision:flowRevision},retain: true});
});
return flowRevision;
});
return flowRevision;
}).catch(function(err) {
})
} else {

View File

@ -118,9 +118,10 @@ describe('context', function() {
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"));
return Context.delete("1","flowA").then(function(){
context = Context.get("1","flowA");
should.not.exist(context.get("foo"));
});
});
it('enumerates context keys', function() {
@ -153,12 +154,75 @@ describe('context', function() {
});
describe('external context storage',function() {
describe('load modules',function(){
afterEach(function() {
Context.clean({allNodes:{}});
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:{}
}
};
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});
return 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"}}});
return Context.load();
@ -185,6 +249,18 @@ describe('context', function() {
context.get("#1.num").should.eql("num3");
});
});
it('should ignore reserved storage name `_`', function() {
Context.init({contextStorage:{_:{module:testPlugin}}});
return Context.load().then(function(){
var context = Context.get("1","flow");
context.set("#_.foo","bar");
context.get("#_.foo");
context.keys("#_");
stubSet.called.should.be.false();
stubGet.called.should.be.false();
stubKeys.called.should.be.false();
});
});
it('should fail when using invalid default context', function(done) {
Context.init({contextStorage:{default:"noexist"}});
Context.load().then(function(){
@ -211,63 +287,19 @@ describe('context', function() {
});
});
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();
describe('close modules',function(){
it('should call close()', function() {
Context.init({contextStorage:contextDefaultStorage});
return Context.load().then(function(){
return Context.close().then(function(){
stubClose.called.should.be.true();
stubClose2.called.should.be.true();
});
});
});
});
describe('store context',function() {
it('should store local property to external context storage',function() {
Context.init({contextStorage:contextStorage});
return Context.load().then(function(){
@ -385,6 +417,31 @@ describe('context', function() {
});
});
describe('delete context',function(){
it('should not call delete()', function() {
Context.init({contextStorage:contextDefaultStorage});
return Context.load().then(function(){
Context.get("flowA");
return Context.delete("flowA").then(function(){
stubDelete.called.should.be.false();
stubDelete2.called.should.be.false();
});
});
});
});
describe('clean context',function(){
it('should call clean()', function() {
Context.init({contextStorage:contextDefaultStorage});
return Context.load().then(function(){
return Context.clean({allNodes:{}}).then(function(){
stubClean.calledWithExactly([]).should.be.true();
stubClean2.calledWithExactly([]).should.be.true();
});
});
});
});
describe('key name',function() {
beforeEach(function() {
Context.init({contextStorage:{memory:{module:"memory"}}});

View File

@ -31,8 +31,10 @@ describe('localfilesystem',function() {
});
afterEach(function() {
return context.close().then(function(){
return fs.remove(resourcesDir);
return context.clean([]).then(function(){
return context.close().then(function(){
return fs.remove(resourcesDir);
});
});
});
@ -118,9 +120,39 @@ describe('localfilesystem',function() {
context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("abc");
context.delete("nodeX");
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.exist(context.get("nodeY","foo"));
should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","abc");
context.set("nodeY","foo","abc");
context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("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.eql("abc");
context.get("nodeY","foo").should.eql("abc");
return context.clean(["nodeX"]).then(function(){
should.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
});
});
});
});

View File

@ -22,6 +22,13 @@ describe('memory',function() {
beforeEach(function() {
context = Memory({});
return context.open();
});
afterEach(function() {
return context.clean([]).then(function(){
return context.close();
});
});
describe('#get/set',function() {
@ -120,9 +127,39 @@ describe('memory',function() {
context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("abc");
context.delete("nodeX");
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.exist(context.get("nodeY","foo"));
should.not.exist(context.get("nodeY","foo"));
context.set("nodeX","foo","abc");
context.set("nodeY","foo","abc");
context.get("nodeX","foo").should.eql("abc");
context.get("nodeY","foo").should.eql("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.eql("abc");
context.get("nodeY","foo").should.eql("abc");
return context.clean(["nodeX"]).then(function(){
should.exist(context.get("nodeX","foo"));
should.not.exist(context.get("nodeY","foo"));
});
});
});