From fc4edde6e6fa30badb738de487e8d3bb39a2caec Mon Sep 17 00:00:00 2001 From: Nick O'Leary Date: Sat, 28 Apr 2018 15:57:32 +0100 Subject: [PATCH] Add runtime-api tests --- red/red.js | 4 +- red/runtime-api/flows.js | 17 +- red/runtime-api/projects.js | 3 +- test/red/runtime-api/flows_spec.js | 622 ++++++++------ test/red/runtime-api/nodes_spec.js | 162 +++- test/red/runtime-api/projects_spec.js | 1094 ++++++++++++++++++++++++- test/red/runtime-api/settings_spec.js | 29 +- 7 files changed, 1666 insertions(+), 265 deletions(-) diff --git a/red/red.js b/red/red.js index 5e9da6402..46a4fc23a 100644 --- a/red/red.js +++ b/red/red.js @@ -71,7 +71,7 @@ module.exports = { if (userSettings.httpAdminRoot !== false) { runtime.init(userSettings,redUtil,api); runtimeAPI.init(runtime,redUtil); - api.init(httpServer,userSettings,runtime.storage,runtimeAPI,redUtil); + api.init(httpServer,userSettings,runtime.storage,runtimeAPI); apiEnabled = true; server = runtime.adminApi.server; @@ -106,7 +106,7 @@ module.exports = { }) }, nodes: runtime.nodes, - get log() { return redUtil.log }, + log: redUtil.log, settings:runtime.settings, util: runtime.util, version: runtime.version, diff --git a/red/runtime-api/flows.js b/red/runtime-api/flows.js index 30a6e83ef..7df55ccb0 100644 --- a/red/runtime-api/flows.js +++ b/red/runtime-api/flows.js @@ -49,7 +49,6 @@ var api = module.exports = { getFlows: function(opts) { return new Promise(function(resolve,reject) { runtime.log.audit({event: "flows.get"}/*,req*/); - var version = opts.version||"v1"; return resolve(runtime.nodes.getFlows()); }); }, @@ -61,7 +60,6 @@ var api = module.exports = { * @memberof RED.flows */ setFlows: function(opts) { - var err; return new Promise(function(resolve,reject) { var flows = opts.flows; @@ -75,6 +73,7 @@ var api = module.exports = { if (flows.hasOwnProperty('rev')) { var currentVersion = runtime.nodes.getFlows().rev; if (currentVersion !== flows.rev) { + var err; err = new Error(); err.code = "version_mismatch"; err.status = 409; @@ -193,18 +192,22 @@ var api = module.exports = { var id = opts.id; try { runtime.nodes.removeFlow(id).then(function() { - log.audit({event: "flow.remove",id:id}); + runtime.log.audit({event: "flow.remove",id:id}); return resolve(); - }) + }).catch(function(err) { + runtime.log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()}); + err.status = 400; + return reject(err); + }); } catch(err) { if (err.code === 404) { - log.audit({event: "flow.remove",id:id,error:"not_found"}); + runtime.log.audit({event: "flow.remove",id:id,error:"not_found"}); // TODO: this swap around of .code and .status isn't ideal err.status = 404; err.code = "not_found"; return reject(err); } else { - log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()}); + runtime.log.audit({event: "flow.remove",id:id,error:err.code||"unexpected_error",message:err.toString()}); err.status = 400; return reject(err); } @@ -228,7 +231,7 @@ var api = module.exports = { if (!credentials) { return resolve({}); } - var definition = runtime.nodes.getCredentialDefinition(opts.type); + var definition = runtime.nodes.getCredentialDefinition(opts.type) || {}; var sendCredentials = {}; for (var cred in definition) { diff --git a/red/runtime-api/projects.js b/red/runtime-api/projects.js index 849adfd45..79b447d52 100644 --- a/red/runtime-api/projects.js +++ b/red/runtime-api/projects.js @@ -27,6 +27,7 @@ var api = module.exports = { available: function(opts) { return Promise.resolve(!!runtime.storage.projects); }, + /** * List projects known to the runtime * @param {Object} opts @@ -50,8 +51,6 @@ var api = module.exports = { }) }, - - /** * Create a new project * @param {Object} opts diff --git a/test/red/runtime-api/flows_spec.js b/test/red/runtime-api/flows_spec.js index 502eaddca..9b060ba23 100644 --- a/test/red/runtime-api/flows_spec.js +++ b/test/red/runtime-api/flows_spec.js @@ -14,278 +14,400 @@ * limitations under the License. **/ -describe("runtime-api/flows", function() { - it.skip('more tests needed', function(){}) -}); - - -/* 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 sinon = require("sinon"); -var flows = require("../../../../red/api/admin/flows"); +var flows = require("../../../red/runtime-api/flows") -describe("api/admin/flows", function() { +var mockLog = () => ({ + log: sinon.stub(), + debug: sinon.stub(), + trace: sinon.stub(), + warn: sinon.stub(), + info: sinon.stub(), + metric: sinon.stub(), + audit: sinon.stub(), + _: function() { return "abc"} +}) - 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); +describe("runtime-api/flows", function() { + describe("getFlows", function() { + it("returns the current flow configuration", function(done) { + flows.init({ + log: mockLog(), + nodes: { + getFlows: function() { return [1,2,3] } } }); - }); - 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'); + flows.getFlows({}).then(function(result) { + result.should.eql([1,2,3]); 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 - } + }).catch(done); }); - 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); + describe("setFlows", function() { + var setFlows; + var loadFlows; + var reloadError = false; + beforeEach(function() { + setFlows = sinon.spy(function(flows,type) { + if (flows[0] === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; } - res.body.should.have.property("code","version_mismatch"); + return Promise.resolve("newRev"); + }); + loadFlows = sinon.spy(function() { + if (!reloadError) { + return Promise.resolve("newLoadRev"); + } else { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } + }) + flows.init({ + log: mockLog(), + nodes: { + getFlows: function() { return {rev:"currentRev",flows:[]} }, + setFlows: setFlows, + loadFlows: loadFlows + } + }) + + }) + it("defaults to full deploy", function(done) { + flows.setFlows({ + flows: {flows:[4,5,6]} + }).then(function(result) { + result.should.eql({rev:"newRev"}); + setFlows.called.should.be.true(); + setFlows.lastCall.args[0].should.eql([4,5,6]); + setFlows.lastCall.args[1].should.eql("full"); 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 - } + }).catch(done); }); - 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); + it("passes through other deploy types", function(done) { + flows.setFlows({ + deploymentType: "nodes", + flows: {flows:[4,5,6]} + }).then(function(result) { + result.should.eql({rev:"newRev"}); + setFlows.called.should.be.true(); + setFlows.lastCall.args[0].should.eql([4,5,6]); + setFlows.lastCall.args[1].should.eql("nodes"); 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 - } + }).catch(done); }); - 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); - } + it("triggers a flow reload", function(done) { + flows.setFlows({ + deploymentType: "reload" + }).then(function(result) { + result.should.eql({rev:"newLoadRev"}); + setFlows.called.should.be.false(); loadFlows.called.should.be.true(); done(); - }); + }).catch(done); + }); + it("allows update when revision matches", function(done) { + flows.setFlows({ + deploymentType: "nodes", + flows: {flows:[4,5,6],rev:"currentRev"} + }).then(function(result) { + result.should.eql({rev:"newRev"}); + setFlows.called.should.be.true(); + setFlows.lastCall.args[0].should.eql([4,5,6]); + setFlows.lastCall.args[1].should.eql("nodes"); + done(); + }).catch(done); + }); + it("rejects update when revision does not match", function(done) { + flows.setFlows({ + deploymentType: "nodes", + flows: {flows:[4,5,6],rev:"notTheCurrentRev"} + }).then(function(result) { + done(new Error("Did not reject rev mismatch")); + }).catch(function(err) { + err.should.have.property('code','version_mismatch'); + err.should.have.property('status',409); + done(); + }).catch(done); + }); + it("rejects when reload fails",function(done) { + reloadError = true; + flows.setFlows({ + deploymentType: "reload" + }).then(function(result) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + done(); + }).catch(done); + }); + it("rejects when update fails",function(done) { + flows.setFlows({ + deploymentType: "full", + flows: {flows:["error",5,6]} + }).then(function(result) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + done(); + }).catch(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); + describe("addFlow", function() { + var addFlow; + beforeEach(function() { + addFlow = sinon.spy(function(flow) { + if (flow === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; } - res.body.should.have.property("message","expected error"); - done(); + return Promise.resolve("newId"); }); + flows.init({ + log: mockLog(), + nodes: { + addFlow: addFlow + } + }); + }) + it("adds a flow", function(done) { + flows.addFlow({flow:{a:"123"}}).then(function(id) { + addFlow.called.should.be.true(); + addFlow.lastCall.args[0].should.eql({a:"123"}); + id.should.eql("newId"); + done() + }).catch(done); + }); + it("rejects when add fails", function(done) { + flows.addFlow({flow:"error"}).then(function(id) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + done(); + }).catch(done); + }); + }); + describe("getFlow", function() { + var getFlow; + beforeEach(function() { + getFlow = sinon.spy(function(flow) { + if (flow === "unknown") { + return null; + } + return [1,2,3]; + }); + flows.init({ + log: mockLog(), + nodes: { + getFlow: getFlow + } + }); + }) + it("gets a flow", function(done) { + flows.getFlow({id:"123"}).then(function(flow) { + flow.should.eql([1,2,3]); + done() + }).catch(done); + }); + it("rejects when flow not found", function(done) { + flows.getFlow({id:"unknown"}).then(function(flow) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','not_found'); + err.should.have.property('status',404); + done(); + }).catch(done); + }); + }); + + describe("updateFlow", function() { + var updateFlow; + beforeEach(function() { + updateFlow = sinon.spy(function(id,flow) { + if (id === "unknown") { + var err = new Error(); + // TODO: quirk of internal api - uses .code for .status + err.code = 404; + throw err; + } else if (id === "error") { + var err = new Error(); + // TODO: quirk of internal api - uses .code for .status + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } + return Promise.resolve(); + }); + flows.init({ + log: mockLog(), + nodes: { + updateFlow: updateFlow + } + }); + }) + it("updates a flow", function(done) { + flows.updateFlow({id:"123",flow:[1,2,3]}).then(function(id) { + id.should.eql("123"); + updateFlow.called.should.be.true(); + updateFlow.lastCall.args[0].should.eql("123"); + updateFlow.lastCall.args[1].should.eql([1,2,3]); + done() + }).catch(done); + }); + it("rejects when flow not found", function(done) { + flows.updateFlow({id:"unknown"}).then(function(flow) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','not_found'); + err.should.have.property('status',404); + done(); + }).catch(done); + }); + it("rejects when update fails", function(done) { + flows.updateFlow({id:"error"}).then(function(flow) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + + describe("deleteFlow", function() { + var removeFlow; + beforeEach(function() { + removeFlow = sinon.spy(function(flow) { + if (flow === "unknown") { + var err = new Error(); + // TODO: quirk of internal api - uses .code for .status + err.code = 404; + throw err; + } else if (flow === "error") { + var err = new Error(); + // TODO: quirk of internal api - uses .code for .status + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } + return Promise.resolve(); + }); + flows.init({ + log: mockLog(), + nodes: { + removeFlow: removeFlow + } + }); + }) + it("deletes a flow", function(done) { + flows.deleteFlow({id:"123"}).then(function() { + removeFlow.called.should.be.true(); + removeFlow.lastCall.args[0].should.eql("123"); + done() + }).catch(done); + }); + it("rejects when flow not found", function(done) { + flows.deleteFlow({id:"unknown"}).then(function(flow) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','not_found'); + err.should.have.property('status',404); + done(); + }).catch(done); + }); + it("rejects when delete fails", function(done) { + flows.deleteFlow({id:"error"}).then(function(flow) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("getNodeCredentials", function() { + beforeEach(function() { + flows.init({ + log: mockLog(), + nodes: { + getCredentials: function(id) { + if (id === "unknown") { + return undefined; + } else if (id === "known") { + return { + username: "abc", + password: "123" + } + } else if (id === "known2") { + return { + username: "abc", + password: "" + } + } else { + return {}; + } + }, + getCredentialDefinition: function(type) { + if (type === "node") { + return { + username: {type:"text"}, + password: {type:"password"} + } + } else { + return null; + } + } + } + }); + }) + it("returns an empty object for an unknown node", function(done) { + flows.getNodeCredentials({id:"unknown", type:"node"}).then(function(result) { + result.should.eql({}); + done(); + }).catch(done); + }); + it("gets the filtered credentials for a known node with password", function(done) { + flows.getNodeCredentials({id:"known", type:"node"}).then(function(result) { + result.should.eql({ + username: "abc", + has_password: true + }); + done(); + }).catch(done); + }); + it("gets the filtered credentials for a known node without password", function(done) { + flows.getNodeCredentials({id:"known2", type:"node"}).then(function(result) { + result.should.eql({ + username: "abc", + has_password: false + }); + done(); + }).catch(done); + }); + it("gets the empty credentials for a known node without a registered definition", function(done) { + flows.getNodeCredentials({id:"known2", type:"unknown-type"}).then(function(result) { + result.should.eql({}); + done(); + }).catch(done); + }); }); }); - -*/ diff --git a/test/red/runtime-api/nodes_spec.js b/test/red/runtime-api/nodes_spec.js index 80237816e..432bad07e 100644 --- a/test/red/runtime-api/nodes_spec.js +++ b/test/red/runtime-api/nodes_spec.js @@ -14,8 +14,168 @@ * limitations under the License. **/ +var should = require("should"); +var sinon = require("sinon"); + +var nodes = require("../../../red/runtime-api/nodes") + +var mockLog = () => ({ + log: sinon.stub(), + debug: sinon.stub(), + trace: sinon.stub(), + warn: sinon.stub(), + info: sinon.stub(), + metric: sinon.stub(), + audit: sinon.stub(), + _: function() { return "abc"} +}) + describe("runtime-api/nodes", function() { - it.skip('more tests needed', function(){}) + describe("getNodeInfo", function() { + beforeEach(function() { + nodes.init({ + log: mockLog(), + nodes: { + getNodeInfo: function(id) { + if (id === "known") { + return {id:"known"}; + } else { + return null; + } + } + } + }); + }) + it("returns node info", function(done) { + nodes.getNodeInfo({id:"known"}).then(function(result) { + result.should.eql({id:"known"}); + done(); + }).catch(done); + }); + it("returns 404 if node not known", function(done) { + nodes.getNodeInfo({id:"unknown"}).then(function(result) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','not_found'); + err.should.have.property('status',404); + done(); + }).catch(done); + }); + }); + describe("getNodeList", function() { + beforeEach(function() { + nodes.init({ + log: mockLog(), + nodes: { + getNodeList: function() { + return [1,2,3]; + } + } + }); + }) + it("returns node list", function(done) { + nodes.getNodeList({}).then(function(result) { + result.should.eql([1,2,3]); + done(); + }).catch(done); + }); + }); + + describe("getNodeConfig", function() { + beforeEach(function() { + nodes.init({ + log: mockLog(), + nodes: { + getNodeConfig: function(id,lang) { + if (id === "known") { + return id+lang; + } else { + return null; + } + } + } + }); + }) + it("returns node config", function(done) { + nodes.getNodeConfig({id:"known",lang:'lang'}).then(function(result) { + result.should.eql("knownlang"); + done(); + }).catch(done); + }); + it("returns 404 if node not known", function(done) { + nodes.getNodeConfig({id:"unknown",lang:'lang'}).then(function(result) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','not_found'); + err.should.have.property('status',404); + done(); + }).catch(done); + }); + }); + + describe("getNodeConfigs", function() { + beforeEach(function() { + nodes.init({ + log: mockLog(), + nodes: { + getNodeConfigs: function(lang) { + return lang; + } + } + }); + }) + it("returns all node configs", function(done) { + nodes.getNodeConfigs({lang:'lang'}).then(function(result) { + result.should.eql("lang"); + done(); + }).catch(done); + }); + }); + + describe("getModuleInfo", function() { + beforeEach(function() { + nodes.init({ + log: mockLog(), + nodes: { + getModuleInfo: function(id) { + if (id === "known") { + return {module:"known"}; + } else { + return null; + } + } + } + }); + }) + it("returns node info", function(done) { + nodes.getModuleInfo({module:"known"}).then(function(result) { + result.should.eql({module:"known"}); + done(); + }).catch(done); + }); + it("returns 404 if node not known", function(done) { + nodes.getModuleInfo({module:"unknown"}).then(function(result) { + done(new Error("Did not return internal error")); + }).catch(function(err) { + err.should.have.property('code','not_found'); + err.should.have.property('status',404); + done(); + }).catch(done); + }); + }); + + describe.skip("addModule", function() {}); + describe.skip("removeModule", function() {}); + describe.skip("setModuleState", function() {}); + describe.skip("setNodeSetState", function() {}); + + describe.skip("getModuleCatalogs", function() {}); + describe.skip("getModuleCatalog", function() {}); + + describe.skip("getIconList", function() {}); + describe.skip("getIcon", function() {}); + + }); /* diff --git a/test/red/runtime-api/projects_spec.js b/test/red/runtime-api/projects_spec.js index b84d7d883..407eb849d 100644 --- a/test/red/runtime-api/projects_spec.js +++ b/test/red/runtime-api/projects_spec.js @@ -14,6 +14,1096 @@ * limitations under the License. **/ -describe("runtime-api/projects", function() { - it.skip('more tests needed', function(){}) +var should = require("should"); +var sinon = require("sinon"); + +var projects = require("../../../red/runtime-api/projects") + +var mockLog = () => ({ + log: sinon.stub(), + debug: sinon.stub(), + trace: sinon.stub(), + warn: sinon.stub(), + info: sinon.stub(), + metric: sinon.stub(), + audit: sinon.stub(), + _: function() { return "abc"} +}) + +describe("runtime-api/settings", function() { + describe("available", function() { + it("resolves true if projects available", function(done) { + projects.init({ + storage: { + projects: {} + } + }); + projects.available().then(function(result) { + result.should.be.true(); + done(); + }).catch(done); + }) + it("resolves false if projects unavailable", function(done) { + projects.init({ + storage: { + } + }); + projects.available().then(function(result) { + result.should.be.false(); + done(); + }).catch(done); + }) + + }); + describe("listProjects", function() { + var runtime = {storage: {projects: { + listProjects: sinon.spy(function(user) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve([1,2,3]); + } + }), + getActiveProject: function(user) { + if (user === "noActive") { + return null; + } + return {name:"aProject"}; + } + }}}; + before(function() { + projects.init(runtime); + }) + it("lists the projects, without an active project", function(done) { + projects.listProjects({user:"noActive"}).then(function(result) { + result.should.have.property('projects',[1,2,3]); + result.should.not.have.property('active'); + done(); + }).catch(done); + }); + it("lists the projects, with an active project", function(done) { + projects.listProjects({user:"foo"}).then(function(result) { + result.should.have.property('projects',[1,2,3]); + result.should.have.property('active','aProject'); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.listProjects({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + err.should.have.property('status',400); + done(); + }).catch(done); + }); + + }); + describe("createProject", function() { + var runtime = {storage: {projects: { + createProject: sinon.spy(function(user,project) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve(project); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("create project", function(done) { + projects.createProject({user:"known",project:{a:1}}).then(function(result) { + result.should.eql({a:1}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.createProject({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + describe("initialiseProject", function() { + var runtime = {storage: {projects: { + initialiseProject: sinon.spy(function(user,id,project) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({id,project}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("intialise project", function(done) { + projects.initialiseProject({user:"known",id:123, project:{a:1}}).then(function(result) { + result.should.eql({id:123, project:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.initialiseProject({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("getActiveProject", function() { + var runtime = {storage: {projects: { + getActiveProject: sinon.spy(function(user) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve("123"); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("returns active project", function(done) { + projects.getActiveProject({user:"known"}).then(function(result) { + result.should.eql("123"); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getActiveProject({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("setActiveProject", function() { + var activeProject; + var runtime; + beforeEach(function() { + runtime = {storage: {projects: { + getActiveProject: sinon.spy(function() { return activeProject;}), + setActiveProject: sinon.spy(function(user,id) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id}); + } + }) + }}}; + projects.init(runtime); + }) + it("sets project if current project is unset", function(done) { + activeProject = null; + projects.setActiveProject({user:"known",id:123}).then(function(result) { + result.should.eql({user:"known",id:123}); + done(); + }).catch(done); + }); + it("sets project if current project is different", function(done) { + activeProject = {name:456}; + projects.setActiveProject({user:"known",id:123}).then(function(result) { + result.should.eql({user:"known",id:123}); + done(); + }).catch(done); + }); + it("no-ops if current project is same", function(done) { + activeProject = {name:123}; + projects.setActiveProject({user:"known",id:123}).then(function(result) { + (result === undefined).should.be.true(); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.setActiveProject({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("getProject", function() { + var runtime = {storage: {projects: { + getProject: sinon.spy(function(user,id) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("returns project", function(done) { + projects.getProject({user:"known",id:123}).then(function(result) { + result.should.eql({user:"known",id:123}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getProject({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + describe("updateProject", function() { + var runtime = {storage: {projects: { + updateProject: sinon.spy(function(user,id,project) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,project}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("updates project", function(done) { + projects.updateProject({user:"known",id:123,project:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,project:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.updateProject({user:"error",id:123,project:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("deleteProject", function() { + var runtime = {storage: {projects: { + deleteProject: sinon.spy(function(user,id) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("deletes project", function(done) { + projects.deleteProject({user:"known",id:123}).then(function(result) { + result.should.eql({user:"known",id:123}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.deleteProject({user:"error",id:123}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("getStatus", function() { + var runtime = {storage: {projects: { + getStatus: sinon.spy(function(user,id,remote) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,remote}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("gets status", function(done) { + projects.getStatus({user:"known",id:123,remote:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,remote:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getStatus({user:"error",id:123,project:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + describe("getBranches", function() { + var runtime = {storage: {projects: { + getBranches: sinon.spy(function(user,id,remote) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,remote}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("gets branches", function(done) { + projects.getBranches({user:"known",id:123,remote:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,remote:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getBranches({user:"error",id:123,remote:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + describe("getBranchStatus", function() { + var runtime = {storage: {projects: { + getBranchStatus: sinon.spy(function(user,id,branch) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,branch}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("gets branch status", function(done) { + projects.getBranchStatus({user:"known",id:123,branch:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,branch:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getBranchStatus({user:"error",id:123,branch:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("setBranch", function() { + var runtime = {storage: {projects: { + setBranch: sinon.spy(function(user,id,branch,create) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,branch,create}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("commits", function(done) { + projects.setBranch({user:"known",id:123,branch:{a:1},create:true}).then(function(result) { + result.should.eql({user:"known",id:123,branch:{a:1},create:true}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.setBranch({user:"error",id:123,branch:{a:1},create:true}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("deleteBranch", function() { + var runtime = {storage: {projects: { + deleteBranch: sinon.spy(function(user,id,branch,something,force) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,branch,force}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("commits", function(done) { + projects.deleteBranch({user:"known",id:123,branch:{a:1},force:true}).then(function(result) { + result.should.eql({user:"known",id:123,branch:{a:1},force:true}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.deleteBranch({user:"error",id:123,branch:{a:1},force:true}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("commit", function() { + var runtime = {storage: {projects: { + commit: sinon.spy(function(user,id,message) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,message}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("commits", function(done) { + projects.commit({user:"known",id:123,message:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,message:{message:{a:1}}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.commit({user:"error",id:123,message:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + describe("getCommit", function() { + var runtime = {storage: {projects: { + getCommit: sinon.spy(function(user,id,sha) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,sha}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("gets commit", function(done) { + projects.getCommit({user:"known",id:123,sha:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,sha:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getCommit({user:"error",id:123,sha:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("getCommits", function() { + var runtime = {storage: {projects: { + getCommits: sinon.spy(function(user,id,options) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,options}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("gets commits with default limit/before", function(done) { + projects.getCommits({user:"known",id:123}).then(function(result) { + result.should.eql({user:"known",id:123,options:{limit:20,before:undefined}}); + done(); + }).catch(done); + }); + it("gets commits with provided limit/before", function(done) { + projects.getCommits({user:"known",id:123,limit:10,before:456}).then(function(result) { + result.should.eql({user:"known",id:123,options:{limit:10,before:456}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getCommits({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("abortMerge", function() { + var runtime = {storage: {projects: { + abortMerge: sinon.spy(function(user,id) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("aborts merge", function(done) { + projects.abortMerge({user:"known",id:123}).then(function(result) { + result.should.eql({user:"known",id:123}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.abortMerge({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("resolveMerge", function() { + var runtime = {storage: {projects: { + resolveMerge: sinon.spy(function(user,id,path,resolution) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,path,resolution}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("resolves merge", function(done) { + projects.resolveMerge({user:"known",id:123,path:"/abc",resolution:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,path:"/abc",resolution:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.resolveMerge({user:"error",id:123,path:"/abc",resolution:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("getFiles", function() { + var runtime = {storage: {projects: { + getFiles: sinon.spy(function(user,id) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("gets files", function(done) { + projects.getFiles({user:"known",id:123}).then(function(result) { + result.should.eql({user:"known",id:123}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getFiles({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("getFile", function() { + var runtime = {storage: {projects: { + getFile: sinon.spy(function(user,id,path,tree) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,path,tree}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("gets file", function(done) { + projects.getFile({user:"known",id:123,path:"/abc",tree:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,path:"/abc",tree:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getFile({user:"error",id:123,path:"/abc",tree:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("stageFile", function() { + var runtime = {storage: {projects: { + stageFile: sinon.spy(function(user,id,path) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,path}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("stages a file", function(done) { + projects.stageFile({user:"known",id:123,path:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,path:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.stageFile({user:"error",id:123,path:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + describe("unstageFile", function() { + var runtime = {storage: {projects: { + unstageFile: sinon.spy(function(user,id,path) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,path}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("unstages a file", function(done) { + projects.unstageFile({user:"known",id:123,path:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,path:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.unstageFile({user:"error",id:123,path:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("revertFile", function() { + var runtime = {storage: {projects: { + revertFile: sinon.spy(function(user,id,path) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,path}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("reverts a file", function(done) { + projects.revertFile({user:"known",id:123,path:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,path:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.revertFile({user:"error",id:123,path:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("getFileDiff", function() { + var runtime = {storage: {projects: { + getFileDiff: sinon.spy(function(user,id,path,type) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,path,type}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("gets file diff", function(done) { + projects.getFileDiff({user:"known",id:123,path:{a:1},type:"abc"}).then(function(result) { + result.should.eql({user:"known",id:123,path:{a:1},type:"abc"}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getFileDiff({user:"error",id:123,path:{a:1},type:"abc"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("getRemotes", function() { + var runtime = {storage: {projects: { + getRemotes: sinon.spy(function(user,id) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("gets remotes", function(done) { + projects.getRemotes({user:"known",id:123}).then(function(result) { + result.should.eql({user:"known",id:123}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.getRemotes({user:"error"}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("addRemote", function() { + var runtime = {storage: {projects: { + addRemote: sinon.spy(function(user,id,remote) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,remote}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("adds a remote", function(done) { + projects.addRemote({user:"known",id:123,remote:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,remote:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.addRemote({user:"error",id:123,remote:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("removeRemote", function() { + var runtime = {storage: {projects: { + removeRemote: sinon.spy(function(user,id,remote) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,remote}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("removes a remote", function(done) { + projects.removeRemote({user:"known",id:123,remote:{a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,remote:{a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.removeRemote({user:"error",id:123,remote:{a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + describe("updateRemote", function() { + var runtime = {storage: {projects: { + updateRemote: sinon.spy(function(user,id,name,remote) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,name,remote}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("updates a remote", function(done) { + projects.updateRemote({user:"known",id:123,remote:{name:"abc",a:1}}).then(function(result) { + result.should.eql({user:"known",id:123,name:"abc",remote:{name:"abc",a:1}}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.updateRemote({user:"error",id:123,remote:{name:"abc",a:1}}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + describe("pull", function() { + var runtime = {storage: {projects: { + pull: sinon.spy(function(user,id,remote,track,allowUnrelatedHistories) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,remote,track,allowUnrelatedHistories}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("pulls", function(done) { + projects.pull({user:"known",id:123,remote:"abc",track:false,allowUnrelatedHistories:true}).then(function(result) { + result.should.eql({user:"known",id:123,remote:"abc",track:false,allowUnrelatedHistories:true}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.pull({user:"error",id:123,remote:"abc",track:false,allowUnrelatedHistories:true}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + describe("push", function() { + var runtime = {storage: {projects: { + push: sinon.spy(function(user,id,remote,track) { + if (user === "error") { + var err = new Error("error"); + err.code = "error"; + var p = Promise.reject(err); + p.catch(()=>{}); + return p; + } else { + return Promise.resolve({user,id,remote,track}); + } + }) + }}}; + before(function() { + projects.init(runtime); + }) + it("pulls", function(done) { + projects.push({user:"known",id:123,remote:"abc",track:false}).then(function(result) { + result.should.eql({user:"known",id:123,remote:"abc",track:false}); + done(); + }).catch(done); + }); + it("rejects with internal error", function(done) { + projects.push({user:"error",id:123,remote:"abc",track:false}).then(function(result) { + done(new Error("Did not reject internal error")); + }).catch(function(err) { + err.should.have.property('code','error'); + // err.should.have.property('status',400); + done(); + }).catch(done); + }); + }); + + }); diff --git a/test/red/runtime-api/settings_spec.js b/test/red/runtime-api/settings_spec.js index 668ae96a3..534f615d6 100644 --- a/test/red/runtime-api/settings_spec.js +++ b/test/red/runtime-api/settings_spec.js @@ -14,9 +14,36 @@ * limitations under the License. **/ + +var should = require("should"); +var sinon = require("sinon"); + +var settings = require("../../../red/runtime-api/settings") + +var mockLog = () => ({ + log: sinon.stub(), + debug: sinon.stub(), + trace: sinon.stub(), + warn: sinon.stub(), + info: sinon.stub(), + metric: sinon.stub(), + audit: sinon.stub(), + _: function() { return "abc"} +}) + describe("runtime-api/settings", function() { - it.skip('more tests needed', function(){}) + describe.skip("getRuntimeSettings", function() {}); + describe.skip("getUserSettings", function() {}); + describe.skip("updateUserSettings", function() {}); + describe.skip("getUserKeys", function() {}); + describe.skip("getUserKey", function() {}); + describe.skip("generateUserKey", function() {}); + describe.skip("removeUserKey", function() {}); + }); + + + /* it('returns the filtered settings', function(done) { info.init({