mirror of
				https://github.com/node-red/node-red.git
				synced 2025-03-01 10:36:34 +00:00 
			
		
		
		
	Installing a module returns module info
Removing a module checks module exists and checks type is not in use
This commit is contained in:
		| @@ -34,6 +34,7 @@ module.exports = { | ||||
|             res.send(redNodes.getNodeConfigs()); | ||||
|         } | ||||
|     }, | ||||
|  | ||||
|     post: function(req,res) { | ||||
|         if (!settings.available()) { | ||||
|             res.send(400,new Error("Settings unavailable").toString()); | ||||
| @@ -55,7 +56,7 @@ module.exports = { | ||||
|             return; | ||||
|         } | ||||
|         promise.then(function(info) { | ||||
|             res.json(info); | ||||
|             res.json(redNodes.getModuleInfo(node.module)); | ||||
|         }).otherwise(function(err) { | ||||
|             if (err.code === 404) { | ||||
|                 res.send(404); | ||||
|   | ||||
| @@ -55,20 +55,21 @@ function checkTypeInUse(id) { | ||||
|     var nodeInfo = registry.getNodeInfo(id); | ||||
|     if (!nodeInfo) { | ||||
|         throw new Error("Unrecognised id: "+id); | ||||
|     } | ||||
|     var inUse = {}; | ||||
|     flows.each(function(n) { | ||||
|         inUse[n.type] = (inUse[n.type]||0)+1; | ||||
|     }); | ||||
|     var nodesInUse = []; | ||||
|     nodeInfo.types.forEach(function(t) { | ||||
|         if (inUse[t]) { | ||||
|             nodesInUse.push(t); | ||||
|     } else { | ||||
|         var inUse = {}; | ||||
|         flows.each(function(n) { | ||||
|             inUse[n.type] = (inUse[n.type]||0)+1; | ||||
|         }); | ||||
|         var nodesInUse = []; | ||||
|         nodeInfo.types.forEach(function(t) { | ||||
|             if (inUse[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) { | ||||
|     var info = registry.getNodeModuleInfo(module); | ||||
|     for (var i=0;i<info.nodes.length;i++) { | ||||
|         checkTypeInUse(info.nodes[i]); | ||||
|     if (!info) { | ||||
|         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) { | ||||
|     checkTypeInUse(id); | ||||
|     return registry.disableNode(id); | ||||
|   | ||||
| @@ -203,13 +203,21 @@ describe("nodes api", 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() { | ||||
|                     return true; | ||||
|                 }); | ||||
|                 var getNodeModuleInfo = sinon.stub(redNodes,'getNodeModuleInfo',function(id) { | ||||
|                     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() { | ||||
|                     return when.resolve({id:"123"}); | ||||
|                 }); | ||||
| @@ -221,11 +229,14 @@ describe("nodes api", function() { | ||||
|                     .end(function(err,res) { | ||||
|                         settingsAvailable.restore(); | ||||
|                         getNodeModuleInfo.restore(); | ||||
|                         getModuleInfo.restore(); | ||||
|                         installModule.restore(); | ||||
|                         if (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(); | ||||
|                     }); | ||||
|             }); | ||||
|   | ||||
| @@ -23,7 +23,7 @@ var sinon = require('sinon'); | ||||
| var index = require("../../../red/nodes/index"); | ||||
|  | ||||
| describe("red/nodes/index", function() { | ||||
|          | ||||
|  | ||||
|     afterEach(function() { | ||||
|         index.clearRegistry(); | ||||
|     }); | ||||
| @@ -44,7 +44,7 @@ describe("red/nodes/index", function() { | ||||
|                 return when(true); | ||||
|             } | ||||
|     }; | ||||
|      | ||||
|  | ||||
|     var settings = { | ||||
|         available: function() { return false } | ||||
|     }; | ||||
| @@ -56,13 +56,13 @@ describe("red/nodes/index", function() { | ||||
|             // do nothing | ||||
|         }); | ||||
|     } | ||||
|      | ||||
|    it('nodes are initialised with credentials',function(done) {       | ||||
|  | ||||
|    it('nodes are initialised with credentials',function(done) { | ||||
|  | ||||
|         index.init(settings, storage); | ||||
|         index.registerType('test', TestNode);             | ||||
|         index.registerType('test', TestNode); | ||||
|         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('c',2); | ||||
|             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.loadFlows().then(function() { | ||||
|             should.deepEqual(testFlows, index.getFlows()); | ||||
| @@ -82,7 +82,7 @@ describe("red/nodes/index", function() { | ||||
|         }); | ||||
|  | ||||
|     }); | ||||
|     | ||||
|  | ||||
|    describe("registerType should register credentials definition", function() { | ||||
|        var http = require('http'); | ||||
|        var express = require('express'); | ||||
| @@ -91,7 +91,7 @@ describe("red/nodes/index", function() { | ||||
|        var credentials = require("../../../red/nodes/credentials"); | ||||
|        var localfilesystem = require("../../../red/storage/localfilesystem"); | ||||
|        var RED = require("../../../red/red.js"); | ||||
|         | ||||
|  | ||||
|        var userDir = path.join(__dirname,".testUserHome"); | ||||
|        before(function(done) { | ||||
|            fs.remove(userDir,function(err) { | ||||
| @@ -109,7 +109,7 @@ describe("red/nodes/index", function() { | ||||
|                    RED.init(http.createServer(function(req,res){app(req,res)}), | ||||
|                             {userDir: userDir}); | ||||
|                    server.start().then(function () { | ||||
|                        done();  | ||||
|                        done(); | ||||
|                     }); | ||||
|                }); | ||||
|            }); | ||||
| @@ -121,24 +121,24 @@ describe("red/nodes/index", function() { | ||||
|            index.load.restore(); | ||||
|            localfilesystem.getCredentials.restore(); | ||||
|        }); | ||||
|         | ||||
|        it(': definition defined',function(done) {       | ||||
|  | ||||
|        it(': definition defined',function(done) { | ||||
|            index.registerType('test', TestNode, { | ||||
|                credentials: { | ||||
|                    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'); | ||||
|            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 randomNodeInfo = {id:"5678",types:["random"]}; | ||||
|         | ||||
|  | ||||
|        before(function() { | ||||
|            sinon.stub(registry,"getNodeInfo",function(id) { | ||||
|                if (id == "test") { | ||||
| @@ -162,9 +162,9 @@ describe("red/nodes/index", function() { | ||||
|            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.registerType('test', TestNode);             | ||||
|             index.registerType('test', TestNode); | ||||
|             index.loadFlows().then(function() { | ||||
|                 var info = index.removeNode("5678"); | ||||
|                 registry.removeNode.calledOnce.should.be.true; | ||||
| @@ -175,10 +175,10 @@ describe("red/nodes/index", function() { | ||||
|                 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.registerType('test', TestNode);             | ||||
|             index.registerType('test', TestNode); | ||||
|             index.loadFlows().then(function() { | ||||
|                 var info = index.disableNode("5678"); | ||||
|                 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.registerType('test', TestNode);             | ||||
|             index.registerType('test', TestNode); | ||||
|             index.loadFlows().then(function() { | ||||
|                 /*jshint immed: false */ | ||||
|                 (function() { | ||||
|                     index.removeNode("test"); | ||||
|                 }).should.throw();     | ||||
|                  | ||||
|                 }).should.throw(); | ||||
|  | ||||
|                 done(); | ||||
|             }).otherwise(function(err) { | ||||
|                 done(err); | ||||
|             }); | ||||
|        }); | ||||
|         | ||||
|  | ||||
|        it(': prevents disabling a node type that is in use',function(done) { | ||||
|             index.init(settings, storage); | ||||
|             index.registerType('test', TestNode);             | ||||
|             index.registerType('test', TestNode); | ||||
|             index.loadFlows().then(function() { | ||||
|                 /*jshint immed: false */ | ||||
|                 (function() { | ||||
|                     index.disabledNode("test"); | ||||
|                 }).should.throw();     | ||||
|                  | ||||
|                 }).should.throw(); | ||||
|  | ||||
|                 done(); | ||||
|             }).otherwise(function(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.registerType('test', TestNode);             | ||||
|             index.registerType('test', TestNode); | ||||
|             index.loadFlows().then(function() { | ||||
|                 /*jshint immed: false */ | ||||
|                 (function() { | ||||
|                     index.removeNode("doesnotexist"); | ||||
|                 }).should.throw();     | ||||
|                  | ||||
|                 }).should.throw(); | ||||
|  | ||||
|                 done(); | ||||
|             }).otherwise(function(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.registerType('test', TestNode);             | ||||
|             index.registerType('test', TestNode); | ||||
|             index.loadFlows().then(function() { | ||||
|                 /*jshint immed: false */ | ||||
|                 (function() { | ||||
|                     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(); | ||||
|             }).otherwise(function(err) { | ||||
|                 done(err); | ||||
|             }); | ||||
|         }); | ||||
|  | ||||
|     }); | ||||
|     | ||||
|     | ||||
| }); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user