mirror of
https://github.com/node-red/node-red.git
synced 2025-03-01 10:36:34 +00:00
Add v2 /flows api and deploy-overwrite protection
This commit is contained in:
@@ -34,12 +34,12 @@ describe("flows api", function() {
|
||||
app.post("/flows",flows.post);
|
||||
});
|
||||
|
||||
it('returns flow', function(done) {
|
||||
it('returns flow - v1', function(done) {
|
||||
flows.init({
|
||||
settings: {},
|
||||
log:{warn:function(){},_:function(){},audit:function(){}},
|
||||
nodes:{
|
||||
getFlows: function() { return [1,2,3]; }
|
||||
getFlows: function() { return {rev:"123",flows:[1,2,3]}; }
|
||||
}
|
||||
});
|
||||
request(app)
|
||||
@@ -50,13 +50,60 @@ describe("flows api", function() {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.be.an.Array;
|
||||
res.body.should.have.lengthOf(3);
|
||||
done();
|
||||
try {
|
||||
res.body.should.have.lengthOf(3);
|
||||
done();
|
||||
} catch(e) {
|
||||
return done(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('sets flows - default', function(done) {
|
||||
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('error','bad_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(){}},
|
||||
@@ -77,7 +124,7 @@ describe("flows api", function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('sets flows - non-default', function(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(){}},
|
||||
@@ -100,6 +147,96 @@ describe("flows api", function() {
|
||||
});
|
||||
});
|
||||
|
||||
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("error","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('error','bad_api_version');
|
||||
done();
|
||||
} catch(e) {
|
||||
return done(e);
|
||||
}
|
||||
});
|
||||
});
|
||||
it('reloads flows', function(done) {
|
||||
var loadFlows = sinon.spy(function() { return when.resolve(); });
|
||||
flows.init({
|
||||
|
@@ -116,22 +116,31 @@ describe('flows/index', function() {
|
||||
flows.setFlows(originalConfig).then(function() {
|
||||
credentialsClean.called.should.be.true;
|
||||
storage.hasOwnProperty('conf').should.be.true;
|
||||
flows.getFlows().should.eql(originalConfig);
|
||||
flows.getFlows().flows.should.eql(originalConfig);
|
||||
done();
|
||||
});
|
||||
|
||||
});
|
||||
it('sets the full flow for type load', function(done) {
|
||||
it('loads the full flow for type load', function(done) {
|
||||
var originalConfig = [
|
||||
{id:"t1-1",x:10,y:10,z:"t1",type:"test",wires:[]},
|
||||
{id:"t1",type:"tab"}
|
||||
];
|
||||
flows.init({settings:{},storage:storage});
|
||||
var loadStorage = {
|
||||
saveFlows: function(conf) {
|
||||
loadStorage.conf = conf;
|
||||
return when.resolve(456);
|
||||
},
|
||||
getFlows: function() {
|
||||
return when.resolve({flows:originalConfig,rev:123})
|
||||
}
|
||||
}
|
||||
flows.init({settings:{},storage:loadStorage});
|
||||
flows.setFlows(originalConfig,"load").then(function() {
|
||||
credentialsClean.called.should.be.false;
|
||||
// 'load' type does not trigger a save
|
||||
storage.hasOwnProperty('conf').should.be.false;
|
||||
flows.getFlows().should.eql(originalConfig);
|
||||
loadStorage.hasOwnProperty('conf').should.be.false;
|
||||
flows.getFlows().flows.should.eql(originalConfig);
|
||||
done();
|
||||
});
|
||||
|
||||
@@ -147,10 +156,10 @@ describe('flows/index', function() {
|
||||
credentialsClean.called.should.be.true;
|
||||
storage.hasOwnProperty('conf').should.be.true;
|
||||
var cleanedFlows = flows.getFlows();
|
||||
storage.conf.flows.should.eql(cleanedFlows);
|
||||
cleanedFlows.should.not.eql(originalConfig);
|
||||
cleanedFlows[0].credentials = {"a":1};
|
||||
cleanedFlows.should.eql(originalConfig);
|
||||
storage.conf.flows.should.eql(cleanedFlows.flows);
|
||||
cleanedFlows.flows.should.not.eql(originalConfig);
|
||||
cleanedFlows.flows[0].credentials = {"a":1};
|
||||
cleanedFlows.flows.should.eql(originalConfig);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -170,7 +179,7 @@ describe('flows/index', function() {
|
||||
|
||||
events.once('nodes-started',function() {
|
||||
flows.setFlows(newConfig,"nodes").then(function() {
|
||||
flows.getFlows().should.eql(newConfig);
|
||||
flows.getFlows().flows.should.eql(newConfig);
|
||||
flowCreate.flows['t1'].update.called.should.be.true;
|
||||
flowCreate.flows['t2'].start.called.should.be.true;
|
||||
flowCreate.flows['_GLOBAL_'].update.called.should.be.true;
|
||||
@@ -199,7 +208,7 @@ describe('flows/index', function() {
|
||||
|
||||
events.once('nodes-started',function() {
|
||||
flows.setFlows(newConfig,"nodes").then(function() {
|
||||
flows.getFlows().should.eql(newConfig);
|
||||
flows.getFlows().flows.should.eql(newConfig);
|
||||
flowCreate.flows['t1'].update.called.should.be.true;
|
||||
flowCreate.flows['t2'].start.called.should.be.true;
|
||||
flowCreate.flows['_GLOBAL_'].update.called.should.be.true;
|
||||
@@ -229,7 +238,7 @@ describe('flows/index', function() {
|
||||
credentialsLoad.called.should.be.true;
|
||||
// 'load' type does not trigger a save
|
||||
storage.hasOwnProperty('conf').should.be.false;
|
||||
flows.getFlows().should.eql(originalConfig);
|
||||
flows.getFlows().flows.should.eql(originalConfig);
|
||||
done();
|
||||
});
|
||||
});
|
||||
@@ -535,7 +544,7 @@ describe('flows/index', function() {
|
||||
{id:"t2-3",z:"t1",type:"test"}
|
||||
]
|
||||
}).then(function(id) {
|
||||
flows.getFlows().should.have.lengthOf(6);
|
||||
flows.getFlows().flows.should.have.lengthOf(6);
|
||||
var createdFlows = Object.keys(flowCreate.flows);
|
||||
createdFlows.should.have.lengthOf(3);
|
||||
createdFlows[2].should.eql(id);
|
||||
|
@@ -39,13 +39,14 @@ describe("red/nodes/index", function() {
|
||||
});
|
||||
|
||||
var testFlows = [{"type":"test","id":"tab1","label":"Sheet 1"}];
|
||||
var testCredentials = {"tab1":{"b":1,"c":2}};
|
||||
var storage = {
|
||||
getFlows: function() {
|
||||
return when({flows:testFlows,credentials:{"tab1":{"b":1,"c":2}}});
|
||||
return when({red:123,flows:testFlows,credentials:testCredentials});
|
||||
},
|
||||
saveFlows: function(conf) {
|
||||
should.deepEqual(testFlows, conf.flows);
|
||||
return when();
|
||||
return when.resolve(123);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -84,7 +85,9 @@ describe("red/nodes/index", function() {
|
||||
it('flows should be initialised',function(done) {
|
||||
index.init(runtime);
|
||||
index.loadFlows().then(function() {
|
||||
should.deepEqual(testFlows, index.getFlows());
|
||||
console.log(testFlows);
|
||||
console.log(index.getFlows());
|
||||
should.deepEqual(testFlows, index.getFlows().flows);
|
||||
done();
|
||||
}).otherwise(function(err) {
|
||||
done(err);
|
||||
@@ -173,8 +176,8 @@ describe("red/nodes/index", function() {
|
||||
index.registerType('test', TestNode);
|
||||
index.loadFlows().then(function() {
|
||||
var info = index.disableNode("5678");
|
||||
registry.disableNode.calledOnce.should.be.true;
|
||||
registry.disableNode.calledWith("5678").should.be.true;
|
||||
registry.disableNode.calledOnce.should.be.true();
|
||||
registry.disableNode.calledWith("5678").should.be.true();
|
||||
info.should.eql(randomNodeInfo);
|
||||
done();
|
||||
}).otherwise(function(err) {
|
||||
|
@@ -79,6 +79,7 @@ describe("red/storage/index", function() {
|
||||
},
|
||||
saveFlows : function (flows) {
|
||||
flows.should.be.true;
|
||||
return when.resolve("");
|
||||
},
|
||||
getCredentials : function() {
|
||||
calledFlagGetCredentials = true;
|
||||
|
Reference in New Issue
Block a user