Installing a module returns module info

Removing a module checks module exists and checks type is not in use
This commit is contained in:
Anna Thomas 2014-11-21 15:15:24 +00:00
parent 4c9d53388c
commit dd5821ee1b
4 changed files with 145 additions and 64 deletions

View File

@ -34,6 +34,7 @@ module.exports = {
res.send(redNodes.getNodeConfigs()); res.send(redNodes.getNodeConfigs());
} }
}, },
post: function(req,res) { post: function(req,res) {
if (!settings.available()) { if (!settings.available()) {
res.send(400,new Error("Settings unavailable").toString()); res.send(400,new Error("Settings unavailable").toString());
@ -55,7 +56,7 @@ module.exports = {
return; return;
} }
promise.then(function(info) { promise.then(function(info) {
res.json(info); res.json(redNodes.getModuleInfo(node.module));
}).otherwise(function(err) { }).otherwise(function(err) {
if (err.code === 404) { if (err.code === 404) {
res.send(404); res.send(404);

View File

@ -55,20 +55,21 @@ function checkTypeInUse(id) {
var nodeInfo = registry.getNodeInfo(id); var nodeInfo = registry.getNodeInfo(id);
if (!nodeInfo) { if (!nodeInfo) {
throw new Error("Unrecognised id: "+id); throw new Error("Unrecognised id: "+id);
} } else {
var inUse = {}; var inUse = {};
flows.each(function(n) { flows.each(function(n) {
inUse[n.type] = (inUse[n.type]||0)+1; inUse[n.type] = (inUse[n.type]||0)+1;
}); });
var nodesInUse = []; var nodesInUse = [];
nodeInfo.types.forEach(function(t) { nodeInfo.types.forEach(function(t) {
if (inUse[t]) { if (inUse[t]) {
nodesInUse.push(t); nodesInUse.push(t);
}
});
if (nodesInUse.length > 0) {
var msg = nodesInUse.join(", ");
throw new Error("Type in use: "+msg);
} }
});
if (nodesInUse.length > 0) {
var msg = nodesInUse.join(", ");
throw new Error("Type in use: "+msg);
} }
} }
@ -79,13 +80,16 @@ function removeNode(id) {
function removeModule(module) { function removeModule(module) {
var info = registry.getNodeModuleInfo(module); var info = registry.getNodeModuleInfo(module);
for (var i=0;i<info.nodes.length;i++) { if (!info) {
checkTypeInUse(info.nodes[i]); throw new Error("Unrecognised module: "+module);
} else {
for (var i=0;i<info.nodes.length;i++) {
checkTypeInUse(module+"/"+info.nodes[i]);
}
return registry.removeModule(module);
} }
return registry.removeModule(module);
} }
function disableNode(id) { function disableNode(id) {
checkTypeInUse(id); checkTypeInUse(id);
return registry.disableNode(id); return registry.disableNode(id);

View File

@ -203,13 +203,21 @@ describe("nodes api", function() {
}); });
describe('by module', function() { describe('by module', function() {
it('installs the module and returns node info', function(done) { it('installs the module and returns module info', function(done) {
var settingsAvailable = sinon.stub(settings,'available', function() { var settingsAvailable = sinon.stub(settings,'available', function() {
return true; return true;
}); });
var getNodeModuleInfo = sinon.stub(redNodes,'getNodeModuleInfo',function(id) { var getNodeModuleInfo = sinon.stub(redNodes,'getNodeModuleInfo',function(id) {
return null; return null;
}); });
var getModuleInfo = sinon.stub(redNodes,'getModuleInfo',function(module) {
if (module === "foo") {
return {
name:"foo",
nodes:[{id:123}]
};
}
});
var installModule = sinon.stub(server,'installModule', function() { var installModule = sinon.stub(server,'installModule', function() {
return when.resolve({id:"123"}); return when.resolve({id:"123"});
}); });
@ -221,11 +229,14 @@ describe("nodes api", function() {
.end(function(err,res) { .end(function(err,res) {
settingsAvailable.restore(); settingsAvailable.restore();
getNodeModuleInfo.restore(); getNodeModuleInfo.restore();
getModuleInfo.restore();
installModule.restore(); installModule.restore();
if (err) { if (err) {
throw err; throw err;
} }
res.body.should.have.property("id","123"); res.body.should.have.property("name","foo");
res.body.should.have.property("nodes");
res.body.nodes[0].should.have.property("id","123");
done(); done();
}); });
}); });

View File

@ -23,7 +23,7 @@ var sinon = require('sinon');
var index = require("../../../red/nodes/index"); var index = require("../../../red/nodes/index");
describe("red/nodes/index", function() { describe("red/nodes/index", function() {
afterEach(function() { afterEach(function() {
index.clearRegistry(); index.clearRegistry();
}); });
@ -44,7 +44,7 @@ describe("red/nodes/index", function() {
return when(true); return when(true);
} }
}; };
var settings = { var settings = {
available: function() { return false } available: function() { return false }
}; };
@ -56,13 +56,13 @@ describe("red/nodes/index", function() {
// do nothing // do nothing
}); });
} }
it('nodes are initialised with credentials',function(done) { it('nodes are initialised with credentials',function(done) {
index.init(settings, storage); index.init(settings, storage);
index.registerType('test', TestNode); index.registerType('test', TestNode);
index.loadFlows().then(function() { index.loadFlows().then(function() {
var testnode = new TestNode({id:'tab1',type:'test',name:'barney'}); var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});
testnode.credentials.should.have.property('b',1); testnode.credentials.should.have.property('b',1);
testnode.credentials.should.have.property('c',2); testnode.credentials.should.have.property('c',2);
done(); done();
@ -71,8 +71,8 @@ describe("red/nodes/index", function() {
}); });
}); });
it('flows should be initialised',function(done) { it('flows should be initialised',function(done) {
index.init(settings, storage); index.init(settings, storage);
index.loadFlows().then(function() { index.loadFlows().then(function() {
should.deepEqual(testFlows, index.getFlows()); should.deepEqual(testFlows, index.getFlows());
@ -82,7 +82,7 @@ describe("red/nodes/index", function() {
}); });
}); });
describe("registerType should register credentials definition", function() { describe("registerType should register credentials definition", function() {
var http = require('http'); var http = require('http');
var express = require('express'); var express = require('express');
@ -91,7 +91,7 @@ describe("red/nodes/index", function() {
var credentials = require("../../../red/nodes/credentials"); var credentials = require("../../../red/nodes/credentials");
var localfilesystem = require("../../../red/storage/localfilesystem"); var localfilesystem = require("../../../red/storage/localfilesystem");
var RED = require("../../../red/red.js"); var RED = require("../../../red/red.js");
var userDir = path.join(__dirname,".testUserHome"); var userDir = path.join(__dirname,".testUserHome");
before(function(done) { before(function(done) {
fs.remove(userDir,function(err) { fs.remove(userDir,function(err) {
@ -109,7 +109,7 @@ describe("red/nodes/index", function() {
RED.init(http.createServer(function(req,res){app(req,res)}), RED.init(http.createServer(function(req,res){app(req,res)}),
{userDir: userDir}); {userDir: userDir});
server.start().then(function () { server.start().then(function () {
done(); done();
}); });
}); });
}); });
@ -121,24 +121,24 @@ describe("red/nodes/index", function() {
index.load.restore(); index.load.restore();
localfilesystem.getCredentials.restore(); localfilesystem.getCredentials.restore();
}); });
it(': definition defined',function(done) { it(': definition defined',function(done) {
index.registerType('test', TestNode, { index.registerType('test', TestNode, {
credentials: { credentials: {
foo: {type:"test"} foo: {type:"test"}
} }
}); });
var testnode = new TestNode({id:'tab1',type:'test',name:'barney'}); var testnode = new TestNode({id:'tab1',type:'test',name:'barney'});
credentials.getDefinition("test").should.have.property('foo'); credentials.getDefinition("test").should.have.property('foo');
done(); done();
}); });
}); });
describe('allows nodes to be added/remove/enabled/disabled from the registry', function() { describe('allows nodes to be added/removed/enabled/disabled from the registry', function() {
var registry = require("../../../red/nodes/registry"); var registry = require("../../../red/nodes/registry");
var randomNodeInfo = {id:"5678",types:["random"]}; var randomNodeInfo = {id:"5678",types:["random"]};
before(function() { before(function() {
sinon.stub(registry,"getNodeInfo",function(id) { sinon.stub(registry,"getNodeInfo",function(id) {
if (id == "test") { if (id == "test") {
@ -162,9 +162,9 @@ describe("red/nodes/index", function() {
registry.disableNode.restore(); registry.disableNode.restore();
}); });
it(': allows an unused node type to be removed',function(done) { it(': allows an unused node type to be removed',function(done) {
index.init(settings, storage); index.init(settings, storage);
index.registerType('test', TestNode); index.registerType('test', TestNode);
index.loadFlows().then(function() { index.loadFlows().then(function() {
var info = index.removeNode("5678"); var info = index.removeNode("5678");
registry.removeNode.calledOnce.should.be.true; registry.removeNode.calledOnce.should.be.true;
@ -175,10 +175,10 @@ describe("red/nodes/index", function() {
done(err); done(err);
}); });
}); });
it(': allows an unused node type to be disabled',function(done) { it(': allows an unused node type to be disabled',function(done) {
index.init(settings, storage); index.init(settings, storage);
index.registerType('test', TestNode); index.registerType('test', TestNode);
index.loadFlows().then(function() { index.loadFlows().then(function() {
var info = index.disableNode("5678"); var info = index.disableNode("5678");
registry.disableNode.calledOnce.should.be.true; registry.disableNode.calledOnce.should.be.true;
@ -190,66 +190,131 @@ describe("red/nodes/index", function() {
}); });
}); });
it(': prevents removing a node type that is in use',function(done) { it(': prevents removing a node type that is in use',function(done) {
index.init(settings, storage); index.init(settings, storage);
index.registerType('test', TestNode); index.registerType('test', TestNode);
index.loadFlows().then(function() { index.loadFlows().then(function() {
/*jshint immed: false */ /*jshint immed: false */
(function() { (function() {
index.removeNode("test"); index.removeNode("test");
}).should.throw(); }).should.throw();
done(); done();
}).otherwise(function(err) { }).otherwise(function(err) {
done(err); done(err);
}); });
}); });
it(': prevents disabling a node type that is in use',function(done) { it(': prevents disabling a node type that is in use',function(done) {
index.init(settings, storage); index.init(settings, storage);
index.registerType('test', TestNode); index.registerType('test', TestNode);
index.loadFlows().then(function() { index.loadFlows().then(function() {
/*jshint immed: false */ /*jshint immed: false */
(function() { (function() {
index.disabledNode("test"); index.disabledNode("test");
}).should.throw(); }).should.throw();
done(); done();
}).otherwise(function(err) { }).otherwise(function(err) {
done(err); done(err);
}); });
}); });
it(': prevents removing a node type that is unknown',function(done) { it(': prevents removing a node type that is unknown',function(done) {
index.init(settings, storage); index.init(settings, storage);
index.registerType('test', TestNode); index.registerType('test', TestNode);
index.loadFlows().then(function() { index.loadFlows().then(function() {
/*jshint immed: false */ /*jshint immed: false */
(function() { (function() {
index.removeNode("doesnotexist"); index.removeNode("doesnotexist");
}).should.throw(); }).should.throw();
done(); done();
}).otherwise(function(err) { }).otherwise(function(err) {
done(err); done(err);
}); });
}); });
it(': prevents disabling a node type that is unknown',function(done) { it(': prevents disabling a node type that is unknown',function(done) {
index.init(settings, storage); index.init(settings, storage);
index.registerType('test', TestNode); index.registerType('test', TestNode);
index.loadFlows().then(function() { index.loadFlows().then(function() {
/*jshint immed: false */ /*jshint immed: false */
(function() { (function() {
index.disableNode("doesnotexist"); index.disableNode("doesnotexist");
}).should.throw(); }).should.throw();
done();
}).otherwise(function(err) {
done(err);
});
});
});
describe('allows modules to be removed from the registry', function() {
var registry = require("../../../red/nodes/registry");
var randomNodeInfo = {id:"5678",types:["random"]};
var randomModuleInfo = {
name:"random",
nodes: [randomNodeInfo]
};
before(function() {
sinon.stub(registry,"getNodeInfo",function(id) {
if (id == "node-red/foo") {
return {id:"1234",types:["test"]};
} else if (id == "doesnotexist") {
return null;
} else {
return randomNodeInfo;
}
});
sinon.stub(registry,"getNodeModuleInfo",function(module) {
if (module == "node-red") {
return {name:"node-red",nodes:["foo"]};
} else if (module == "doesnotexist") {
return null;
} else {
return randomModuleInfo.nodes;
}
});
sinon.stub(registry,"removeModule",function(id) {
return randomModuleInfo;
});
});
after(function() {
registry.getNodeInfo.restore();
registry.getNodeModuleInfo.restore();
registry.removeModule.restore();
});
it(': prevents removing a module that is in use',function(done) {
index.init(settings, storage);
index.registerType('test', TestNode);
index.loadFlows().then(function() {
/*jshint immed: false */
(function() {
index.removeModule("node-red");
}).should.throw();
done();
}).otherwise(function(err) {
done(err);
});
});
it(': prevents removing a module that is unknown',function(done) {
index.init(settings, storage);
index.registerType('test', TestNode);
index.loadFlows().then(function() {
/*jshint immed: false */
(function() {
index.removeModule("doesnotexist");
}).should.throw();
done(); done();
}).otherwise(function(err) { }).otherwise(function(err) {
done(err); done(err);
}); });
}); });
}); });
}); });