mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Reorganise red/api layout to better componentise
This commit is contained in:
279
test/red/api/admin/flow_spec.js
Normal file
279
test/red/api/admin/flow_spec.js
Normal file
@@ -0,0 +1,279 @@
|
||||
/**
|
||||
* 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 flow = require("../../../../red/api/admin/flow");
|
||||
|
||||
describe("flow api", function() {
|
||||
|
||||
var app;
|
||||
|
||||
before(function() {
|
||||
app = express();
|
||||
app.use(bodyParser.json());
|
||||
app.get("/flow/:id",flow.get);
|
||||
app.post("/flow",flow.post);
|
||||
app.put("/flow/:id",flow.put);
|
||||
app.delete("/flow/:id",flow.delete);
|
||||
});
|
||||
|
||||
describe("get", function() {
|
||||
before(function() {
|
||||
flow.init({
|
||||
settings:{},
|
||||
nodes: {
|
||||
getFlow: function(id) {
|
||||
if (id === '123') {
|
||||
return {id:'123'}
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
},
|
||||
log:{ audit: sinon.stub() }
|
||||
});
|
||||
})
|
||||
it('gets a known flow', function(done) {
|
||||
request(app)
|
||||
.get('/flow/123')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.has.a.property('id','123');
|
||||
done();
|
||||
});
|
||||
})
|
||||
it('404s an unknown flow', function(done) {
|
||||
request(app)
|
||||
.get('/flow/456')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(404)
|
||||
.end(done);
|
||||
})
|
||||
});
|
||||
|
||||
describe("add", function() {
|
||||
before(function() {
|
||||
flow.init({
|
||||
settings:{},
|
||||
nodes: {
|
||||
addFlow: function(f) {
|
||||
if (f.id === "123") {
|
||||
return when.resolve('123')
|
||||
} else {
|
||||
return when.reject(new Error("test error"));
|
||||
}
|
||||
}
|
||||
},
|
||||
log:{ audit: sinon.stub() }
|
||||
});
|
||||
})
|
||||
it('adds a new flow', function(done) {
|
||||
request(app)
|
||||
.post('/flow')
|
||||
.set('Accept', 'application/json')
|
||||
.send({id:'123'})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.has.a.property('id','123');
|
||||
done();
|
||||
});
|
||||
})
|
||||
it('400 an invalid flow', function(done) {
|
||||
request(app)
|
||||
.post('/flow')
|
||||
.set('Accept', 'application/json')
|
||||
.send({id:'error'})
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.has.a.property('error','unexpected_error');
|
||||
res.body.should.has.a.property('message','Error: test error');
|
||||
|
||||
done();
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
describe("update", function() {
|
||||
var nodes;
|
||||
before(function() {
|
||||
nodes = {
|
||||
updateFlow: function(id,f) {
|
||||
var err;
|
||||
if (id === "123") {
|
||||
return when.resolve()
|
||||
} else if (id === "unknown") {
|
||||
err = new Error();
|
||||
err.code = 404;
|
||||
throw err;
|
||||
} else if (id === "unexpected") {
|
||||
err = new Error();
|
||||
err.code = 500;
|
||||
throw err;
|
||||
} else {
|
||||
return when.reject(new Error("test error"));
|
||||
}
|
||||
}
|
||||
};
|
||||
flow.init({
|
||||
settings:{},
|
||||
nodes: nodes,
|
||||
log:{ audit: sinon.stub() }
|
||||
});
|
||||
})
|
||||
|
||||
it('updates an existing flow', function(done) {
|
||||
sinon.spy(nodes,"updateFlow");
|
||||
request(app)
|
||||
.put('/flow/123')
|
||||
.set('Accept', 'application/json')
|
||||
.send({id:'123'})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.has.a.property('id','123');
|
||||
nodes.updateFlow.calledOnce.should.be.true();
|
||||
nodes.updateFlow.lastCall.args[0].should.eql('123');
|
||||
nodes.updateFlow.lastCall.args[1].should.eql({id:'123'});
|
||||
nodes.updateFlow.restore();
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
it('404s on an unknown flow', function(done) {
|
||||
request(app)
|
||||
.put('/flow/unknown')
|
||||
.set('Accept', 'application/json')
|
||||
.send({id:'123'})
|
||||
.expect(404)
|
||||
.end(done);
|
||||
})
|
||||
|
||||
it('400 on async update error', function(done) {
|
||||
request(app)
|
||||
.put('/flow/async_error')
|
||||
.set('Accept', 'application/json')
|
||||
.send({id:'123'})
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.has.a.property('error','unexpected_error');
|
||||
res.body.should.has.a.property('message','Error: test error');
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
it('400 on sync update error', function(done) {
|
||||
request(app)
|
||||
.put('/flow/unexpected')
|
||||
.set('Accept', 'application/json')
|
||||
.send({id:'123'})
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.has.a.property('error',500);
|
||||
res.body.should.has.a.property('message','Error');
|
||||
done();
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
describe("delete", function() {
|
||||
var nodes;
|
||||
before(function() {
|
||||
nodes = {
|
||||
removeFlow: function(id) {
|
||||
var err;
|
||||
if (id === "123") {
|
||||
return when.resolve()
|
||||
} else if (id === "unknown") {
|
||||
err = new Error();
|
||||
err.code = 404;
|
||||
throw err;
|
||||
} else if (id === "unexpected") {
|
||||
err = new Error();
|
||||
err.code = 500;
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
};
|
||||
flow.init({
|
||||
settings:{},
|
||||
nodes: nodes,
|
||||
log:{ audit: sinon.stub() }
|
||||
});
|
||||
})
|
||||
|
||||
it('updates an existing flow', function(done) {
|
||||
sinon.spy(nodes,"removeFlow");
|
||||
request(app)
|
||||
.delete('/flow/123')
|
||||
.expect(204)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
nodes.removeFlow.calledOnce.should.be.true();
|
||||
nodes.removeFlow.lastCall.args[0].should.eql('123');
|
||||
nodes.removeFlow.restore();
|
||||
done();
|
||||
});
|
||||
})
|
||||
|
||||
it('404s on an unknown flow', function(done) {
|
||||
request(app)
|
||||
.delete('/flow/unknown')
|
||||
.expect(404)
|
||||
.end(done);
|
||||
})
|
||||
|
||||
it('400 on remove error', function(done) {
|
||||
request(app)
|
||||
.delete('/flow/unexpected')
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.has.a.property('error',500);
|
||||
res.body.should.has.a.property('message','Error');
|
||||
done();
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
});
|
282
test/red/api/admin/flows_spec.js
Normal file
282
test/red/api/admin/flows_spec.js
Normal file
@@ -0,0 +1,282 @@
|
||||
/**
|
||||
* 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 flows = require("../../../../red/api/admin/flows");
|
||||
|
||||
describe("flows api", function() {
|
||||
|
||||
var app;
|
||||
|
||||
before(function() {
|
||||
app = express();
|
||||
app.use(bodyParser.json());
|
||||
app.get("/flows",flows.get);
|
||||
app.post("/flows",flows.post);
|
||||
});
|
||||
|
||||
it('returns flow - v1', function(done) {
|
||||
flows.init({
|
||||
settings: {},
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
getFlows: function() { return {rev:"123",flows:[1,2,3]}; }
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
try {
|
||||
res.body.should.have.lengthOf(3);
|
||||
done();
|
||||
} catch(e) {
|
||||
return done(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
it('returns flow - v2', function(done) {
|
||||
flows.init({
|
||||
settings: {},
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
getFlows: function() { return {rev:"123",flows:[1,2,3]}; }
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.set('Node-RED-API-Version','v2')
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
try {
|
||||
res.body.should.have.a.property('rev','123');
|
||||
res.body.should.have.a.property('flows');
|
||||
res.body.flows.should.have.lengthOf(3);
|
||||
done();
|
||||
} catch(e) {
|
||||
return done(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
it('returns flow - bad version', function(done) {
|
||||
request(app)
|
||||
.get('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.set('Node-RED-API-Version','xxx')
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
try {
|
||||
res.body.should.have.a.property('code','invalid_api_version');
|
||||
done();
|
||||
} catch(e) {
|
||||
return done(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
it('sets flows - default - v1', function(done) {
|
||||
var setFlows = sinon.spy(function() { return when.resolve();});
|
||||
flows.init({
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
setFlows: setFlows
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(204)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
setFlows.calledOnce.should.be.true();
|
||||
setFlows.lastCall.args[1].should.eql('full');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('sets flows - non-default - v1', function(done) {
|
||||
var setFlows = sinon.spy(function() { return when.resolve();});
|
||||
flows.init({
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
setFlows: setFlows
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.set('Node-RED-Deployment-Type','nodes')
|
||||
.expect(204)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
setFlows.calledOnce.should.be.true();
|
||||
setFlows.lastCall.args[1].should.eql('nodes');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('set flows - rejects mismatched revision - v2', function(done) {
|
||||
var setFlows = sinon.spy(function() { return when.resolve();});
|
||||
var getFlows = sinon.spy(function() { return {rev:123,flows:[1,2,3]}});
|
||||
flows.init({
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
setFlows: setFlows,
|
||||
getFlows: getFlows
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.set('Node-RED-API-Version','v2')
|
||||
.send({rev:456,flows:[4,5,6]})
|
||||
.expect(409)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property("code","version_mismatch");
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('set flows - rev provided - v2', function(done) {
|
||||
var setFlows = sinon.spy(function() { return when.resolve(456);});
|
||||
var getFlows = sinon.spy(function() { return {rev:123,flows:[1,2,3]}});
|
||||
flows.init({
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
setFlows: setFlows,
|
||||
getFlows: getFlows
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.set('Node-RED-API-Version','v2')
|
||||
.send({rev:123,flows:[4,5,6]})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property("rev",456);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('set flows - no rev provided - v2', function(done) {
|
||||
var setFlows = sinon.spy(function() { return when.resolve(456);});
|
||||
var getFlows = sinon.spy(function() { return {rev:123,flows:[1,2,3]}});
|
||||
flows.init({
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
setFlows: setFlows,
|
||||
getFlows: getFlows
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.set('Node-RED-API-Version','v2')
|
||||
.send({flows:[4,5,6]})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property("rev",456);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('sets flow - bad version', function(done) {
|
||||
request(app)
|
||||
.post('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.set('Node-RED-API-Version','xxx')
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
try {
|
||||
res.body.should.have.a.property('code','invalid_api_version');
|
||||
done();
|
||||
} catch(e) {
|
||||
return done(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
it('reloads flows', function(done) {
|
||||
var loadFlows = sinon.spy(function() { return when.resolve(); });
|
||||
flows.init({
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
loadFlows: loadFlows
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.set('Node-RED-Deployment-Type','reload')
|
||||
.expect(204)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
loadFlows.called.should.be.true();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns error when set fails', function(done) {
|
||||
flows.init({
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
setFlows: function() { return when.reject(new Error("expected error")); }
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/flows')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(500)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property("message","expected error");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
299
test/red/api/admin/index_spec.js
Normal file
299
test/red/api/admin/index_spec.js
Normal file
@@ -0,0 +1,299 @@
|
||||
/**
|
||||
* 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 request = require("supertest");
|
||||
var express = require("express");
|
||||
var adminApi = require("../../../../red/api/admin");
|
||||
var auth = require("../../../../red/api/auth");
|
||||
|
||||
var nodes = require("../../../../red/api/admin/nodes");
|
||||
var flows = require("../../../../red/api/admin/flows");
|
||||
var flow = require("../../../../red/api/admin/flow");
|
||||
var info = require("../../../../red/api/admin/info");
|
||||
|
||||
/**
|
||||
* Ensure all API routes are correctly mounted, with the expected permissions checks
|
||||
*/
|
||||
describe("api/admin/index", function() {
|
||||
describe("Ensure all API routes are correctly mounted, with the expected permissions checks", function() {
|
||||
var app;
|
||||
var mockList = [
|
||||
flows,flow,info,nodes
|
||||
]
|
||||
var permissionChecks = {};
|
||||
var lastRequest;
|
||||
var stubApp = function(req,res,next) {
|
||||
lastRequest = req;
|
||||
res.status(200).end();
|
||||
};
|
||||
before(function() {
|
||||
mockList.forEach(function(m) {
|
||||
sinon.stub(m,"init",function(){});
|
||||
});
|
||||
sinon.stub(auth,"needsPermission", function(permission) {
|
||||
return function(req,res,next) {
|
||||
permissionChecks[permission] = (permissionChecks[permission]||0)+1;
|
||||
next();
|
||||
}
|
||||
});
|
||||
|
||||
sinon.stub(flows,"get",stubApp);
|
||||
sinon.stub(flows,"post",stubApp);
|
||||
|
||||
sinon.stub(flow,"get",stubApp);
|
||||
sinon.stub(flow,"post",stubApp);
|
||||
sinon.stub(flow,"delete",stubApp);
|
||||
sinon.stub(flow,"put",stubApp);
|
||||
|
||||
sinon.stub(nodes,"getAll",stubApp);
|
||||
sinon.stub(nodes,"post",stubApp);
|
||||
sinon.stub(nodes,"getModule",stubApp);
|
||||
sinon.stub(nodes,"putModule",stubApp);
|
||||
sinon.stub(nodes,"delete",stubApp);
|
||||
sinon.stub(nodes,"getSet",stubApp);
|
||||
sinon.stub(nodes,"putSet",stubApp);
|
||||
|
||||
sinon.stub(info,"settings",stubApp);
|
||||
|
||||
});
|
||||
after(function() {
|
||||
mockList.forEach(function(m) {
|
||||
m.init.restore();
|
||||
});
|
||||
auth.needsPermission.restore();
|
||||
|
||||
flows.get.restore();
|
||||
flows.post.restore();
|
||||
flow.get.restore();
|
||||
flow.post.restore();
|
||||
flow.delete.restore();
|
||||
flow.put.restore();
|
||||
nodes.getAll.restore();
|
||||
nodes.post.restore();
|
||||
nodes.getModule.restore();
|
||||
nodes.putModule.restore();
|
||||
nodes.delete.restore();
|
||||
nodes.getSet.restore();
|
||||
nodes.putSet.restore();
|
||||
|
||||
info.settings.restore();
|
||||
});
|
||||
|
||||
before(function() {
|
||||
app = adminApi.init({});
|
||||
});
|
||||
beforeEach(function() {
|
||||
permissionChecks = {};
|
||||
})
|
||||
it('GET /flows', function(done) {
|
||||
request(app).get("/flows").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('flows.read',1);
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('POST /flows', function(done) {
|
||||
request(app).post("/flows").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('flows.write',1);
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('GET /flow/1234', function(done) {
|
||||
request(app).get("/flow/1234").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('flows.read',1);
|
||||
lastRequest.params.should.have.property('id','1234')
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('POST /flow', function(done) {
|
||||
request(app).post("/flow").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('flows.write',1);
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('DELETE /flow/1234', function(done) {
|
||||
request(app).del("/flow/1234").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('flows.write',1);
|
||||
lastRequest.params.should.have.property('id','1234')
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('PUT /flow/1234', function(done) {
|
||||
request(app).put("/flow/1234").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('flows.write',1);
|
||||
lastRequest.params.should.have.property('id','1234')
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('GET /nodes', function(done) {
|
||||
request(app).get("/nodes").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.read',1);
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('POST /nodes', function(done) {
|
||||
request(app).post("/nodes").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.write',1);
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('GET /nodes/module', function(done) {
|
||||
request(app).get("/nodes/module").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.read',1);
|
||||
lastRequest.params.should.have.property(0,'module')
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('GET /nodes/@scope/module', function(done) {
|
||||
request(app).get("/nodes/@scope/module").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.read',1);
|
||||
lastRequest.params.should.have.property(0,'@scope/module')
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('PUT /nodes/module', function(done) {
|
||||
request(app).put("/nodes/module").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.write',1);
|
||||
lastRequest.params.should.have.property(0,'module')
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('PUT /nodes/@scope/module', function(done) {
|
||||
request(app).put("/nodes/@scope/module").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.write',1);
|
||||
lastRequest.params.should.have.property(0,'@scope/module')
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('DELETE /nodes/module', function(done) {
|
||||
request(app).del("/nodes/module").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.write',1);
|
||||
lastRequest.params.should.have.property(0,'module')
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('DELETE /nodes/@scope/module', function(done) {
|
||||
request(app).del("/nodes/@scope/module").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.write',1);
|
||||
lastRequest.params.should.have.property(0,'@scope/module')
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('GET /nodes/module/set', function(done) {
|
||||
request(app).get("/nodes/module/set").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.read',1);
|
||||
lastRequest.params.should.have.property(0,'module')
|
||||
lastRequest.params.should.have.property(2,'set')
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('GET /nodes/@scope/module/set', function(done) {
|
||||
request(app).get("/nodes/@scope/module/set").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.read',1);
|
||||
lastRequest.params.should.have.property(0,'@scope/module')
|
||||
lastRequest.params.should.have.property(2,'set')
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('PUT /nodes/module/set', function(done) {
|
||||
request(app).put("/nodes/module/set").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.write',1);
|
||||
lastRequest.params.should.have.property(0,'module')
|
||||
lastRequest.params.should.have.property(2,'set')
|
||||
done();
|
||||
})
|
||||
});
|
||||
it('PUT /nodes/@scope/module/set', function(done) {
|
||||
request(app).put("/nodes/@scope/module/set").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('nodes.write',1);
|
||||
lastRequest.params.should.have.property(0,'@scope/module')
|
||||
lastRequest.params.should.have.property(2,'set')
|
||||
done();
|
||||
})
|
||||
});
|
||||
|
||||
it('GET /settings', function(done) {
|
||||
request(app).get("/settings").expect(200).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
permissionChecks.should.have.property('settings.read',1);
|
||||
done();
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
102
test/red/api/admin/info_spec.js
Normal file
102
test/red/api/admin/info_spec.js
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* 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 sinon = require('sinon');
|
||||
var when = require('when');
|
||||
|
||||
var app = express();
|
||||
var info = require("../../../../red/api/admin/info");
|
||||
var theme = require("../../../../red/api/editor/theme");
|
||||
|
||||
describe("info api", function() {
|
||||
describe("settings handler", function() {
|
||||
before(function() {
|
||||
sinon.stub(theme,"settings",function() { return { test: 456 };});
|
||||
app = express();
|
||||
app.get("/settings",info.settings);
|
||||
});
|
||||
|
||||
after(function() {
|
||||
theme.settings.restore();
|
||||
});
|
||||
|
||||
it('returns the filtered settings', function(done) {
|
||||
info.init({
|
||||
settings: {
|
||||
foo: 123,
|
||||
httpNodeRoot: "testHttpNodeRoot",
|
||||
version: "testVersion",
|
||||
paletteCategories :["red","blue","green"],
|
||||
exportNodeSettings: function(obj) {
|
||||
obj.testNodeSetting = "helloWorld";
|
||||
}
|
||||
},
|
||||
nodes: {
|
||||
paletteEditorEnabled: function() { return true; }
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get("/settings")
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property("httpNodeRoot","testHttpNodeRoot");
|
||||
res.body.should.have.property("version","testVersion");
|
||||
res.body.should.have.property("paletteCategories",["red","blue","green"]);
|
||||
res.body.should.have.property("editorTheme",{test:456});
|
||||
res.body.should.have.property("testNodeSetting","helloWorld");
|
||||
res.body.should.not.have.property("foo",123);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('overrides palette editable if runtime says it is disabled', function(done) {
|
||||
info.init({
|
||||
settings: {
|
||||
httpNodeRoot: "testHttpNodeRoot",
|
||||
version: "testVersion",
|
||||
paletteCategories :["red","blue","green"],
|
||||
exportNodeSettings: function() {}
|
||||
},
|
||||
nodes: {
|
||||
paletteEditorEnabled: function() { return false; }
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get("/settings")
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property("httpNodeRoot","testHttpNodeRoot");
|
||||
res.body.should.have.property("version","testVersion");
|
||||
res.body.should.have.property("paletteCategories",["red","blue","green"]);
|
||||
res.body.should.have.property("editorTheme");
|
||||
res.body.editorTheme.should.have.property("test",456);
|
||||
|
||||
res.body.editorTheme.should.have.property("palette",{editable:false});
|
||||
done();
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
});
|
814
test/red/api/admin/nodes_spec.js
Normal file
814
test/red/api/admin/nodes_spec.js
Normal file
@@ -0,0 +1,814 @@
|
||||
/**
|
||||
* 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 nodes = require("../../../../red/api/admin/nodes");
|
||||
var apiUtil = require("../../../../red/api/util");
|
||||
|
||||
describe("nodes api", function() {
|
||||
|
||||
var app;
|
||||
function initNodes(runtime) {
|
||||
runtime.log = {
|
||||
audit:function(e){},//console.log(e)},
|
||||
_:function(){},
|
||||
info: function(){},
|
||||
warn: function(){}
|
||||
}
|
||||
runtime.events = {
|
||||
emit: function(){}
|
||||
}
|
||||
nodes.init(runtime);
|
||||
|
||||
}
|
||||
|
||||
before(function() {
|
||||
app = express();
|
||||
app.use(bodyParser.json());
|
||||
app.get("/nodes",nodes.getAll);
|
||||
app.post("/nodes",nodes.post);
|
||||
app.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,nodes.getModule);
|
||||
app.get(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,nodes.getSet);
|
||||
app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,nodes.putModule);
|
||||
app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,nodes.putSet);
|
||||
app.delete("/nodes/:id",nodes.delete);
|
||||
sinon.stub(apiUtil,"determineLangFromHeaders", function() {
|
||||
return "en-US";
|
||||
});
|
||||
});
|
||||
after(function() {
|
||||
apiUtil.determineLangFromHeaders.restore();
|
||||
})
|
||||
|
||||
describe('get nodes', function() {
|
||||
it('returns node list', function(done) {
|
||||
initNodes({
|
||||
nodes:{
|
||||
getNodeList: function() {
|
||||
return [1,2,3];
|
||||
}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get('/nodes')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.be.an.Array();
|
||||
res.body.should.have.lengthOf(3);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns node configs', function(done) {
|
||||
initNodes({
|
||||
nodes:{
|
||||
getNodeConfigs: function() {
|
||||
return "<script></script>";
|
||||
}
|
||||
},
|
||||
i18n: {
|
||||
determineLangFromHeaders: function(){}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get('/nodes')
|
||||
.set('Accept', 'text/html')
|
||||
.expect(200)
|
||||
.expect("<script></script>")
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns node module info', function(done) {
|
||||
initNodes({
|
||||
nodes:{
|
||||
getModuleInfo: function(id) {
|
||||
return {"node-red":{name:"node-red"}}[id];
|
||||
}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get('/nodes/node-red')
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("name","node-red");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 404 for unknown module', function(done) {
|
||||
initNodes({
|
||||
nodes:{
|
||||
getModuleInfo: function(id) {
|
||||
return {"node-red":{name:"node-red"}}[id];
|
||||
}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get('/nodes/node-blue')
|
||||
.expect(404)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns individual node info', function(done) {
|
||||
initNodes({
|
||||
nodes:{
|
||||
getNodeInfo: function(id) {
|
||||
return {"node-red/123":{id:"node-red/123"}}[id];
|
||||
}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get('/nodes/node-red/123')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("id","node-red/123");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns individual node configs', function(done) {
|
||||
initNodes({
|
||||
nodes:{
|
||||
getNodeConfig: function(id) {
|
||||
return {"node-red/123":"<script></script>"}[id];
|
||||
}
|
||||
},
|
||||
i18n: {
|
||||
determineLangFromHeaders: function(){}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get('/nodes/node-red/123')
|
||||
.set('Accept', 'text/html')
|
||||
.expect(200)
|
||||
.expect("<script></script>")
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 404 for unknown node', function(done) {
|
||||
initNodes({
|
||||
nodes:{
|
||||
getNodeInfo: function(id) {
|
||||
return {"node-red/123":{id:"node-red/123"}}[id];
|
||||
}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.get('/nodes/node-red/456')
|
||||
.set('Accept', 'application/json')
|
||||
.expect(404)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('install', function() {
|
||||
|
||||
it('returns 400 if settings are unavailable', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return false}}
|
||||
});
|
||||
request(app)
|
||||
.post('/nodes')
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 400 if request is invalid', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}}
|
||||
});
|
||||
request(app)
|
||||
.post('/nodes')
|
||||
.send({})
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('by module', function() {
|
||||
it('installs the module and returns module info', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function(id) { return null; },
|
||||
installModule: function() {
|
||||
return when.resolve({
|
||||
name:"foo",
|
||||
nodes:[{id:"123"}]
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/nodes')
|
||||
.send({module: 'foo'})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("name","foo");
|
||||
res.body.should.have.property("nodes");
|
||||
res.body.nodes[0].should.have.property("id","123");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails the install if already installed', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function(id) { return {nodes:{id:"123"}}; },
|
||||
installModule: function() {
|
||||
return when.resolve({id:"123"});
|
||||
}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/nodes')
|
||||
.send({module: 'foo'})
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails the install if module error', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function(id) { return null },
|
||||
installModule: function() {
|
||||
return when.reject(new Error("test error"));
|
||||
}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/nodes')
|
||||
.send({module: 'foo'})
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("message","Error: test error");
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('fails the install if module not found', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function(id) { return null },
|
||||
installModule: function() {
|
||||
var err = new Error("test error");
|
||||
err.code = 404;
|
||||
return when.reject(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.post('/nodes')
|
||||
.send({module: 'foo'})
|
||||
.expect(404)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
describe('delete', function() {
|
||||
it('returns 400 if settings are unavailable', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return false}}
|
||||
});
|
||||
|
||||
request(app)
|
||||
.del('/nodes/123')
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('by module', function() {
|
||||
it('uninstalls the module', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function(id) { return {nodes:[{id:"123"}]} },
|
||||
getNodeInfo: function() { return null },
|
||||
uninstallModule: function() { return when.resolve({id:"123"});}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.del('/nodes/foo')
|
||||
.expect(204)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails the uninstall if the module is not installed', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function(id) { return null },
|
||||
getNodeInfo: function() { return null }
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.del('/nodes/foo')
|
||||
.expect(404)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('fails the uninstall if the module is not installed', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function(id) { return {nodes:[{id:"123"}]} },
|
||||
getNodeInfo: function() { return null },
|
||||
uninstallModule: function() { return when.reject(new Error("test error"));}
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.del('/nodes/foo')
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("message","Error: test error");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('enable/disable', function() {
|
||||
it('returns 400 if settings are unavailable', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return false}}
|
||||
});
|
||||
request(app)
|
||||
.put('/nodes/123')
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 400 for invalid node payload', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}}
|
||||
});
|
||||
request(app)
|
||||
.put('/nodes/node-red/foo')
|
||||
.send({})
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("message","Invalid request");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 400 for invalid module payload', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}}
|
||||
});
|
||||
request(app)
|
||||
.put('/nodes/foo')
|
||||
.send({})
|
||||
.expect(400)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("message","Invalid request");
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 404 for unknown node', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getNodeInfo: function() { return null }
|
||||
}
|
||||
});
|
||||
|
||||
request(app)
|
||||
.put('/nodes/node-red/foo')
|
||||
.send({enabled:false})
|
||||
.expect(404)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('returns 404 for unknown module', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function(id) { return null }
|
||||
}
|
||||
});
|
||||
|
||||
request(app)
|
||||
.put('/nodes/node-blue')
|
||||
.send({enabled:false})
|
||||
.expect(404)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('enables disabled node', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getNodeInfo: function() { return {id:"123",enabled: false} },
|
||||
enableNode: function() { return when.resolve({id:"123",enabled: true,types:['a']}); }
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.put('/nodes/node-red/foo')
|
||||
.send({enabled:true})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("id","123");
|
||||
res.body.should.have.property("enabled",true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('disables enabled node', function(done) {
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getNodeInfo: function() { return {id:"123",enabled: true} },
|
||||
disableNode: function() { return when.resolve({id:"123",enabled: false,types:['a']}); }
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.put('/nodes/node-red/foo')
|
||||
.send({enabled:false})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("id","123");
|
||||
res.body.should.have.property("enabled",false);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('no-ops if already in the right state', function() {
|
||||
function run(state,done) {
|
||||
var enableNode = sinon.spy(function() { return when.resolve({id:"123",enabled: true,types:['a']}) });
|
||||
var disableNode = sinon.spy(function() { return when.resolve({id:"123",enabled: false,types:['a']}) });
|
||||
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getNodeInfo: function() { return {id:"123",enabled: state} },
|
||||
enableNode: enableNode,
|
||||
disableNode: disableNode
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.put('/nodes/node-red/foo')
|
||||
.send({enabled:state})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
var enableNodeCalled = enableNode.called;
|
||||
var disableNodeCalled = disableNode.called;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
enableNodeCalled.should.be.false();
|
||||
disableNodeCalled.should.be.false();
|
||||
res.body.should.have.property("id","123");
|
||||
res.body.should.have.property("enabled",state);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
it('already enabled', function(done) {
|
||||
run(true,done);
|
||||
});
|
||||
it('already disabled', function(done) {
|
||||
run(false,done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('does not no-op if err on node', function() {
|
||||
function run(state,done) {
|
||||
var enableNode = sinon.spy(function() { return when.resolve({id:"123",enabled: true,types:['a']}) });
|
||||
var disableNode = sinon.spy(function() { return when.resolve({id:"123",enabled: false,types:['a']}) });
|
||||
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getNodeInfo: function() { return {id:"123",enabled: state, err:"foo"} },
|
||||
enableNode: enableNode,
|
||||
disableNode: disableNode
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.put('/nodes/node-red/foo')
|
||||
.send({enabled:state})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
var enableNodeCalled = enableNode.called;
|
||||
var disableNodeCalled = disableNode.called;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
enableNodeCalled.should.be.equal(state);
|
||||
disableNodeCalled.should.be.equal(!state);
|
||||
res.body.should.have.property("id","123");
|
||||
res.body.should.have.property("enabled",state);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
it('already enabled', function(done) {
|
||||
run(true,done);
|
||||
});
|
||||
it('already disabled', function(done) {
|
||||
run(false,done);
|
||||
});
|
||||
});
|
||||
|
||||
it('enables disabled module', function(done) {
|
||||
var n1 = {id:"123",enabled:false,types:['a']};
|
||||
var n2 = {id:"456",enabled:false,types:['b']};
|
||||
var enableNode = sinon.stub();
|
||||
enableNode.onFirstCall().returns((function() {
|
||||
n1.enabled = true;
|
||||
return when.resolve(n1);
|
||||
})());
|
||||
enableNode.onSecondCall().returns((function() {
|
||||
n2.enabled = true;
|
||||
return when.resolve(n2);
|
||||
})());
|
||||
enableNode.returns(null);
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} },
|
||||
enableNode: enableNode
|
||||
}
|
||||
});
|
||||
|
||||
request(app)
|
||||
.put('/nodes/node-red')
|
||||
.send({enabled:true})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("name","node-red");
|
||||
res.body.should.have.property("nodes");
|
||||
res.body.nodes[0].should.have.property("enabled",true);
|
||||
res.body.nodes[1].should.have.property("enabled",true);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('disables enabled module', function(done) {
|
||||
var n1 = {id:"123",enabled:true,types:['a']};
|
||||
var n2 = {id:"456",enabled:true,types:['b']};
|
||||
var disableNode = sinon.stub();
|
||||
disableNode.onFirstCall().returns((function() {
|
||||
n1.enabled = false;
|
||||
return when.resolve(n1);
|
||||
})());
|
||||
disableNode.onSecondCall().returns((function() {
|
||||
n2.enabled = false;
|
||||
return when.resolve(n2);
|
||||
})());
|
||||
disableNode.returns(null);
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function() { return {name:"node-red", nodes:[n1, n2]} },
|
||||
disableNode: disableNode
|
||||
}
|
||||
});
|
||||
|
||||
request(app)
|
||||
.put('/nodes/node-red')
|
||||
.send({enabled:false})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
res.body.should.have.property("name","node-red");
|
||||
res.body.should.have.property("nodes");
|
||||
res.body.nodes[0].should.have.property("enabled",false);
|
||||
res.body.nodes[1].should.have.property("enabled",false);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('no-ops if a node in module already in the right state', function() {
|
||||
function run(state,done) {
|
||||
var node = {id:"123",enabled:state,types:['a']};
|
||||
var enableNode = sinon.spy(function(id) {
|
||||
node.enabled = true;
|
||||
return when.resolve(node);
|
||||
});
|
||||
var disableNode = sinon.spy(function(id) {
|
||||
node.enabled = false;
|
||||
return when.resolve(node);
|
||||
});
|
||||
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function() { return {name:"node-red", nodes:[node]}; },
|
||||
enableNode: enableNode,
|
||||
disableNode: disableNode
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
.put('/nodes/node-red')
|
||||
.send({enabled:state})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
var enableNodeCalled = enableNode.called;
|
||||
var disableNodeCalled = disableNode.called;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
enableNodeCalled.should.be.false();
|
||||
disableNodeCalled.should.be.false();
|
||||
res.body.should.have.property("name","node-red");
|
||||
res.body.should.have.property("nodes");
|
||||
res.body.nodes[0].should.have.property("enabled",state);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
it('already enabled', function(done) {
|
||||
run(true,done);
|
||||
});
|
||||
it('already disabled', function(done) {
|
||||
run(false,done);
|
||||
});
|
||||
});
|
||||
|
||||
describe('does not no-op if err on a node in module', function() {
|
||||
function run(state,done) {
|
||||
var node = {id:"123",enabled:state,types:['a'],err:"foo"};
|
||||
var enableNode = sinon.spy(function(id) {
|
||||
node.enabled = true;
|
||||
return when.resolve(node);
|
||||
});
|
||||
var disableNode = sinon.spy(function(id) {
|
||||
node.enabled = false;
|
||||
return when.resolve(node);
|
||||
});
|
||||
|
||||
initNodes({
|
||||
settings:{available:function(){return true}},
|
||||
nodes:{
|
||||
getModuleInfo: function() { return {name:"node-red", nodes:[node]}; },
|
||||
enableNode: enableNode,
|
||||
disableNode: disableNode
|
||||
}
|
||||
});
|
||||
|
||||
request(app)
|
||||
.put('/nodes/node-red')
|
||||
.send({enabled:state})
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
var enableNodeCalled = enableNode.called;
|
||||
var disableNodeCalled = disableNode.called;
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
enableNodeCalled.should.be.equal(state);
|
||||
disableNodeCalled.should.be.equal(!state);
|
||||
res.body.should.have.property("name","node-red");
|
||||
res.body.should.have.property("nodes");
|
||||
res.body.nodes[0].should.have.property("enabled",state);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
it('already enabled', function(done) {
|
||||
run(true,done);
|
||||
});
|
||||
it('already disabled', function(done) {
|
||||
run(false,done);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
});
|
Reference in New Issue
Block a user