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:
@@ -33,7 +33,7 @@ var RED = require("../../red/red.js");
|
||||
var redNodes = require("../../red/runtime/nodes");
|
||||
var flows = require("../../red/runtime/nodes/flows");
|
||||
var credentials = require("../../red/runtime/nodes/credentials");
|
||||
var comms = require("../../red/api/comms.js");
|
||||
var comms = require("../../red/api/editor/comms.js");
|
||||
var log = require("../../red/runtime/log.js");
|
||||
var context = require("../../red/runtime/nodes/context.js");
|
||||
var events = require("../../red/runtime/events.js");
|
||||
|
@@ -21,7 +21,7 @@ var bodyParser = require('body-parser');
|
||||
var sinon = require('sinon');
|
||||
var when = require('when');
|
||||
|
||||
var flow = require("../../../red/api/flow");
|
||||
var flow = require("../../../../red/api/admin/flow");
|
||||
|
||||
describe("flow api", function() {
|
||||
|
@@ -21,7 +21,7 @@ var bodyParser = require('body-parser');
|
||||
var sinon = require('sinon');
|
||||
var when = require('when');
|
||||
|
||||
var flows = require("../../../red/api/flows");
|
||||
var flows = require("../../../../red/api/admin/flows");
|
||||
|
||||
describe("flows api", function() {
|
||||
|
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();
|
||||
})
|
||||
});
|
||||
});
|
||||
});
|
@@ -21,8 +21,8 @@ var sinon = require('sinon');
|
||||
var when = require('when');
|
||||
|
||||
var app = express();
|
||||
var info = require("../../../red/api/info");
|
||||
var theme = require("../../../red/api/theme");
|
||||
var info = require("../../../../red/api/admin/info");
|
||||
var theme = require("../../../../red/api/editor/theme");
|
||||
|
||||
describe("info api", function() {
|
||||
describe("settings handler", function() {
|
@@ -21,8 +21,8 @@ var bodyParser = require('body-parser');
|
||||
var sinon = require('sinon');
|
||||
var when = require('when');
|
||||
|
||||
var nodes = require("../../../red/api/nodes");
|
||||
var locales = require("../../../red/api/locales");
|
||||
var nodes = require("../../../../red/api/admin/nodes");
|
||||
var apiUtil = require("../../../../red/api/util");
|
||||
|
||||
describe("nodes api", function() {
|
||||
|
||||
@@ -51,11 +51,13 @@ describe("nodes api", function() {
|
||||
app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)$/,nodes.putModule);
|
||||
app.put(/\/nodes\/((@[^\/]+\/)?[^\/]+)\/([^\/]+)$/,nodes.putSet);
|
||||
app.delete("/nodes/:id",nodes.delete);
|
||||
sinon.stub(locales,"determineLangFromHeaders", function() {
|
||||
sinon.stub(apiUtil,"determineLangFromHeaders", function() {
|
||||
return "en-US";
|
||||
});
|
||||
});
|
||||
|
||||
after(function() {
|
||||
apiUtil.determineLangFromHeaders.restore();
|
||||
})
|
||||
|
||||
describe('get nodes', function() {
|
||||
it('returns node list', function(done) {
|
@@ -23,14 +23,14 @@ var express = require('express');
|
||||
var app = express();
|
||||
var WebSocket = require('ws');
|
||||
|
||||
var comms = require("../../../red/api/comms");
|
||||
var Users = require("../../../red/api/auth/users");
|
||||
var Tokens = require("../../../red/api/auth/tokens");
|
||||
var comms = require("../../../../red/api/editor/comms");
|
||||
var Users = require("../../../../red/api/auth/users");
|
||||
var Tokens = require("../../../../red/api/auth/tokens");
|
||||
|
||||
var address = '127.0.0.1';
|
||||
var listenPort = 0; // use ephemeral port
|
||||
|
||||
describe("api/comms", function() {
|
||||
describe("api/editor/comms", function() {
|
||||
describe("with default keepalive", function() {
|
||||
var server;
|
||||
var url;
|
||||
@@ -327,7 +327,7 @@ describe("api/comms", function() {
|
||||
ws.on('message', function(data) {
|
||||
var msg = JSON.parse(data);
|
||||
msg.should.have.property('topic','hb');
|
||||
msg.should.have.property('data').be.a.Number;
|
||||
msg.should.have.property('data').be.a.Number();
|
||||
count++;
|
||||
if (count == 3) {
|
||||
ws.close();
|
@@ -20,9 +20,9 @@ var express = require('express');
|
||||
var sinon = require('sinon');
|
||||
var when = require('when');
|
||||
|
||||
var credentials = require("../../../red/api/credentials");
|
||||
var credentials = require("../../../../red/api/editor/credentials");
|
||||
|
||||
describe('credentials api', function() {
|
||||
describe('api/editor/credentials', function() {
|
||||
var app;
|
||||
|
||||
before(function() {
|
109
test/red/api/editor/index_spec.js
Normal file
109
test/red/api/editor/index_spec.js
Normal file
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* 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 editorApi = require("../../../../red/api/editor");
|
||||
var comms = require("../../../../red/api/editor/comms");
|
||||
|
||||
|
||||
describe("api/editor/index", function() {
|
||||
var app;
|
||||
describe("disabled the editor", function() {
|
||||
beforeEach(function() {
|
||||
sinon.stub(comms,'init', function(){});
|
||||
});
|
||||
afterEach(function() {
|
||||
comms.init.restore();
|
||||
});
|
||||
it("disables the editor", function() {
|
||||
var editorApp = editorApi.init({},{
|
||||
settings:{disableEditor:true}
|
||||
});
|
||||
should.not.exist(editorApp);
|
||||
comms.init.called.should.be.false();
|
||||
});
|
||||
});
|
||||
describe("enables the editor", function() {
|
||||
var mockList = [
|
||||
'library','theme','locales','credentials','comms'
|
||||
]
|
||||
var isStarted = true;
|
||||
var errors = [];
|
||||
before(function() {
|
||||
mockList.forEach(function(m) {
|
||||
sinon.stub(require("../../../../red/api/editor/"+m),"init",function(){});
|
||||
});
|
||||
sinon.stub(require("../../../../red/api/editor/theme"),"app",function(){ return express()});
|
||||
});
|
||||
after(function() {
|
||||
mockList.forEach(function(m) {
|
||||
require("../../../../red/api/editor/"+m).init.restore();
|
||||
})
|
||||
require("../../../../red/api/editor/theme").app.restore();
|
||||
});
|
||||
|
||||
before(function() {
|
||||
app = editorApi.init({},{
|
||||
log:{audit:function(){},error:function(msg){errors.push(msg)}},
|
||||
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false},
|
||||
events:{on:function(){},removeListener:function(){}},
|
||||
isStarted: function() { return isStarted; }
|
||||
});
|
||||
});
|
||||
it('serves the editor', function(done) {
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
// Index page should probably mention Node-RED somewhere
|
||||
res.text.indexOf("Node-RED").should.not.eql(-1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('serves icons', function(done) {
|
||||
request(app)
|
||||
.get("/icons/inject.png")
|
||||
.expect("Content-Type", /image\/png/)
|
||||
.expect(200,done)
|
||||
});
|
||||
it('handles page not there', function(done) {
|
||||
request(app)
|
||||
.get("/foo")
|
||||
.expect(404,done)
|
||||
});
|
||||
it('warns if runtime not started', function(done) {
|
||||
isStarted = false;
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(503)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.text.should.eql("Not started");
|
||||
errors.should.have.lengthOf(1);
|
||||
errors[0].should.eql("Node-RED runtime not started");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -22,10 +22,10 @@ var bodyParser = require('body-parser');
|
||||
var when = require('when');
|
||||
|
||||
var app;
|
||||
var library = require("../../../red/api/library");
|
||||
var auth = require("../../../red/api/auth");
|
||||
var library = require("../../../../red/api/editor/library");
|
||||
var auth = require("../../../../red/api/auth");
|
||||
|
||||
describe("library api", function() {
|
||||
describe("api/editor/library", function() {
|
||||
|
||||
function initLibrary(_flows,_libraryEntries,_examples) {
|
||||
var flows = _flows;
|
122
test/red/api/editor/locales_spec.js
Normal file
122
test/red/api/editor/locales_spec.js
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* 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 locales = require("../../../../red/api/editor/locales");
|
||||
|
||||
describe("api/editor/locales", function() {
|
||||
beforeEach(function() {
|
||||
})
|
||||
afterEach(function() {
|
||||
})
|
||||
describe('get named resource catalog',function() {
|
||||
var app;
|
||||
before(function() {
|
||||
// bit of a mess of internal workings
|
||||
locales.init({
|
||||
i18n: {
|
||||
i: {
|
||||
lng: function() { return 'en-US'},
|
||||
setLng: function(lang,callback) {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
},
|
||||
catalog: function(namespace, lang) {
|
||||
return {namespace:namespace, lang:lang};
|
||||
}
|
||||
}
|
||||
});
|
||||
app = express();
|
||||
app.get(/locales\/(.+)\/?$/,locales.get);
|
||||
});
|
||||
it('returns with default language', function(done) {
|
||||
request(app)
|
||||
.get("/locales/message-catalog")
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property('namespace','message-catalog');
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('returns with selected language', function(done) {
|
||||
request(app)
|
||||
.get("/locales/message-catalog?lng=fr-FR")
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property('namespace','message-catalog');
|
||||
res.body.should.have.property('lang','fr-FR');
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('get all node resource catalogs',function() {
|
||||
var app;
|
||||
before(function() {
|
||||
// bit of a mess of internal workings
|
||||
locales.init({
|
||||
i18n: {
|
||||
catalog: function(namespace, lang) {
|
||||
return {
|
||||
"node-red": "should not return",
|
||||
"test-module-a-id": "test-module-a-catalog",
|
||||
"test-module-b-id": "test-module-b-catalog",
|
||||
"test-module-c-id": "test-module-c-catalog"
|
||||
}[namespace]
|
||||
}
|
||||
},
|
||||
nodes: {
|
||||
getNodeList: function() {
|
||||
return [
|
||||
{module:"node-red",id:"node-red-id"},
|
||||
{module:"test-module-a",id:"test-module-a-id"},
|
||||
{module:"test-module-b",id:"test-module-b-id"}
|
||||
];
|
||||
}
|
||||
}
|
||||
});
|
||||
app = express();
|
||||
app.get("/locales/nodes",locales.getAllNodes);
|
||||
});
|
||||
it('returns with the node catalogs', function(done) {
|
||||
request(app)
|
||||
.get("/locales/nodes")
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.eql({
|
||||
'test-module-a-id': 'test-module-a-catalog',
|
||||
'test-module-b-id': 'test-module-b-catalog'
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
@@ -15,7 +15,6 @@
|
||||
**/
|
||||
|
||||
var should = require("should");
|
||||
var request = require('supertest');
|
||||
var express = require('express');
|
||||
var sinon = require('sinon');
|
||||
var when = require('when');
|
||||
@@ -23,9 +22,9 @@ var fs = require("fs");
|
||||
|
||||
var app = express();
|
||||
|
||||
var theme = require("../../../red/api/theme");
|
||||
var theme = require("../../../../red/api/editor/theme");
|
||||
|
||||
describe("theme handler", function() {
|
||||
describe("api/editor/theme", function() {
|
||||
beforeEach(function() {
|
||||
sinon.stub(fs,"statSync",function() { return true; });
|
||||
});
|
@@ -22,10 +22,10 @@ var path = require("path");
|
||||
|
||||
var EventEmitter = require('events').EventEmitter;
|
||||
var events = new EventEmitter();
|
||||
var ui = require("../../../red/api/ui");
|
||||
var ui = require("../../../../red/api/editor/ui");
|
||||
|
||||
|
||||
describe("ui api", function() {
|
||||
describe("api/editor/ui", function() {
|
||||
var app;
|
||||
|
||||
before(function() {
|
||||
@@ -33,7 +33,7 @@ describe("ui api", function() {
|
||||
events:events,
|
||||
nodes: {
|
||||
getNodeIconPath: function(module,icon) {
|
||||
return path.resolve(__dirname+'/../../../public/icons/arrow-in.png');
|
||||
return path.resolve(__dirname+'/../../../../public/icons/arrow-in.png');
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -91,7 +91,7 @@ describe("ui api", function() {
|
||||
}
|
||||
}
|
||||
it('returns the requested icon', function(done) {
|
||||
var defaultIcon = fs.readFileSync(path.resolve(__dirname+'/../../../public/icons/arrow-in.png'));
|
||||
var defaultIcon = fs.readFileSync(path.resolve(__dirname+'/../../../../public/icons/arrow-in.png'));
|
||||
request(app)
|
||||
.get("/icons/module/icon.png")
|
||||
.expect("Content-Type", /image\/png/)
|
@@ -23,164 +23,83 @@ var fs = require("fs");
|
||||
var path = require("path");
|
||||
var api = require("../../../red/api");
|
||||
|
||||
describe("api index", function() {
|
||||
var app;
|
||||
var apiUtil = require("../../../red/api/util");
|
||||
var apiAuth = require("../../../red/api/auth");
|
||||
var apiEditor = require("../../../red/api/editor");
|
||||
var apiAdmin = require("../../../red/api/admin");
|
||||
|
||||
describe("disables editor", function() {
|
||||
|
||||
describe("api/index", function() {
|
||||
var beforeEach = function() {
|
||||
sinon.stub(apiUtil,"init",function(){});
|
||||
sinon.stub(apiAuth,"init",function(){});
|
||||
sinon.stub(apiEditor,"init",function(){
|
||||
var app = express();
|
||||
app.get("/editor",function(req,res) { res.status(200).end(); });
|
||||
return app;
|
||||
});
|
||||
sinon.stub(apiAdmin,"init",function(){
|
||||
var app = express();
|
||||
app.get("/admin",function(req,res) { res.status(200).end(); });
|
||||
return app;
|
||||
});
|
||||
sinon.stub(apiAuth,"login",function(req,res){
|
||||
res.status(200).end();
|
||||
});
|
||||
};
|
||||
var afterEach = function() {
|
||||
apiUtil.init.restore();
|
||||
apiAuth.init.restore();
|
||||
apiAuth.login.restore();
|
||||
apiEditor.init.restore();
|
||||
apiAdmin.init.restore();
|
||||
};
|
||||
|
||||
beforeEach(beforeEach);
|
||||
afterEach(afterEach);
|
||||
|
||||
it("does not setup admin api if httpAdminRoot is false", function(done) {
|
||||
api.init({},{
|
||||
settings: { httpAdminRoot: false }
|
||||
});
|
||||
should.not.exist(api.adminApp);
|
||||
done();
|
||||
});
|
||||
describe('initalises admin api without adminAuth', function(done) {
|
||||
before(function() {
|
||||
beforeEach();
|
||||
api.init({},{
|
||||
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:true, exportNodeSettings: function() {}},
|
||||
events: {on:function(){},removeListener: function(){}},
|
||||
log: {info:function(){},_:function(){}},
|
||||
nodes: {paletteEditorEnabled: function(){return true}}
|
||||
settings: { }
|
||||
});
|
||||
app = api.adminApp;
|
||||
});
|
||||
|
||||
it('does not serve the editor', function(done) {
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(404,done)
|
||||
});
|
||||
it('does not serve icons', function(done) {
|
||||
request(app)
|
||||
.get("/icons/default.png")
|
||||
.expect(404,done)
|
||||
});
|
||||
it('serves settings', function(done) {
|
||||
request(app)
|
||||
.get("/settings")
|
||||
.expect(200,done)
|
||||
});
|
||||
after(afterEach);
|
||||
it('exposes the editor',function() {
|
||||
request(api.adminApp).get("/editor").expect(200).end(done);
|
||||
})
|
||||
it('exposes the admin api',function() {
|
||||
request(api.adminApp).get("/admin").expect(200).end(done);
|
||||
})
|
||||
it('exposes the auth api',function(done) {
|
||||
request(api.adminApp).get("/auth/login").expect(200).end(done);
|
||||
})
|
||||
});
|
||||
|
||||
describe("can serve auth", function() {
|
||||
var mockList = [
|
||||
'ui','nodes','flows','library','info','locales','credentials'
|
||||
]
|
||||
before(function() {
|
||||
mockList.forEach(function(m) {
|
||||
sinon.stub(require("../../../red/api/"+m),"init",function(){});
|
||||
});
|
||||
});
|
||||
after(function() {
|
||||
mockList.forEach(function(m) {
|
||||
require("../../../red/api/"+m).init.restore();
|
||||
})
|
||||
});
|
||||
describe('initalises admin api without editor', function(done) {
|
||||
before(function() {
|
||||
beforeEach();
|
||||
api.init({},{
|
||||
settings:{httpNodeRoot:true, httpAdminRoot: true, adminAuth:{type: "credentials",users:[],default:{permissions:"read"}}},
|
||||
storage:{getSessions:function(){return when.resolve({})}},
|
||||
events:{on:function(){},removeListener:function(){}}
|
||||
});
|
||||
app = api.adminApp;
|
||||
});
|
||||
|
||||
it('it now serves auth', function(done) {
|
||||
request(app)
|
||||
.get("/auth/login")
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) { return done(err); }
|
||||
res.body.type.should.equal("credentials");
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("editor warns if runtime not started", function() {
|
||||
var mockList = [
|
||||
'nodes','flows','library','info','theme','locales','credentials'
|
||||
]
|
||||
before(function() {
|
||||
mockList.forEach(function(m) {
|
||||
sinon.stub(require("../../../red/api/"+m),"init",function(){});
|
||||
settings: { disableEditor: true }
|
||||
});
|
||||
});
|
||||
after(function() {
|
||||
mockList.forEach(function(m) {
|
||||
require("../../../red/api/"+m).init.restore();
|
||||
})
|
||||
});
|
||||
|
||||
it('serves the editor', function(done) {
|
||||
var errorLog = sinon.spy();
|
||||
api.init({},{
|
||||
log:{audit:function(){},error:errorLog},
|
||||
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false},
|
||||
events:{on:function(){},removeListener:function(){}},
|
||||
isStarted: function() { return false; } // <-----
|
||||
});
|
||||
app = api.adminApp;
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(503)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.text.should.eql("Not started");
|
||||
errorLog.calledOnce.should.be.true();
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("enables editor", function() {
|
||||
|
||||
var mockList = [
|
||||
'nodes','flows','library','info','theme','locales','credentials'
|
||||
]
|
||||
before(function() {
|
||||
mockList.forEach(function(m) {
|
||||
sinon.stub(require("../../../red/api/"+m),"init",function(){});
|
||||
});
|
||||
});
|
||||
after(function() {
|
||||
mockList.forEach(function(m) {
|
||||
require("../../../red/api/"+m).init.restore();
|
||||
})
|
||||
});
|
||||
|
||||
before(function() {
|
||||
api.init({},{
|
||||
log:{audit:function(){}},
|
||||
settings:{httpNodeRoot:true, httpAdminRoot: true,disableEditor:false},
|
||||
events:{on:function(){},removeListener:function(){}},
|
||||
isStarted: function() { return true; }
|
||||
});
|
||||
app = api.adminApp;
|
||||
});
|
||||
it('serves the editor', function(done) {
|
||||
request(app)
|
||||
.get("/")
|
||||
.expect(200)
|
||||
.end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
// Index page should probably mention Node-RED somewhere
|
||||
res.text.indexOf("Node-RED").should.not.eql(-1);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('serves icons', function(done) {
|
||||
request(app)
|
||||
.get("/icons/inject.png")
|
||||
.expect("Content-Type", /image\/png/)
|
||||
.expect(200,done)
|
||||
});
|
||||
it('serves settings', function(done) {
|
||||
request(app)
|
||||
.get("/settings")
|
||||
.expect(200,done)
|
||||
});
|
||||
it('handles page not there', function(done) {
|
||||
request(app)
|
||||
.get("/foo")
|
||||
.expect(404,done)
|
||||
});
|
||||
after(afterEach);
|
||||
it('does not expose the editor',function() {
|
||||
request(api.adminApp).get("/editor").expect(404).end(done);
|
||||
})
|
||||
it('exposes the admin api',function() {
|
||||
request(api.adminApp).get("/admin").expect(200).end(done);
|
||||
})
|
||||
it('exposes the auth api',function(done) {
|
||||
request(api.adminApp).get("/auth/login").expect(200).end(done)
|
||||
})
|
||||
});
|
||||
});
|
||||
|
@@ -1,19 +0,0 @@
|
||||
/**
|
||||
* 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.
|
||||
**/
|
||||
|
||||
describe("locales api", function() {
|
||||
it.skip("works",function() {});
|
||||
});
|
107
test/red/api/util_spec.js
Normal file
107
test/red/api/util_spec.js
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* 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 apiUtil = require("../../../red/api/util");
|
||||
|
||||
describe("api/util", function() {
|
||||
describe("errorHandler", function() {
|
||||
var loggedError = null;
|
||||
var loggedEvent = null;
|
||||
var app;
|
||||
before(function() {
|
||||
app = express();
|
||||
apiUtil.init({
|
||||
log:{
|
||||
error: function(msg) {
|
||||
loggedError = msg;
|
||||
},
|
||||
audit: function(event) {
|
||||
loggedEvent = event;
|
||||
}
|
||||
},
|
||||
i18n:{}
|
||||
})
|
||||
app.get("/tooLarge", function(req,res) {
|
||||
var err = new Error();
|
||||
err.message = "request entity too large";
|
||||
throw err;
|
||||
},apiUtil.errorHandler)
|
||||
app.get("/stack", function(req,res) {
|
||||
var err = new Error();
|
||||
err.message = "stacktrace";
|
||||
throw err;
|
||||
},apiUtil.errorHandler)
|
||||
});
|
||||
beforeEach(function() {
|
||||
loggedError = null;
|
||||
loggedEvent = null;
|
||||
})
|
||||
it("logs an error for request entity too large", function(done) {
|
||||
request(app).get("/tooLarge").expect(400).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property("error","unexpected_error");
|
||||
res.body.should.have.property("message","Error: request entity too large");
|
||||
|
||||
loggedError.should.have.property("message","request entity too large");
|
||||
|
||||
loggedEvent.should.have.property("event","api.error");
|
||||
loggedEvent.should.have.property("error","unexpected_error");
|
||||
loggedEvent.should.have.property("message","Error: request entity too large");
|
||||
done();
|
||||
});
|
||||
})
|
||||
it("logs an error plus stack for other errors", function(done) {
|
||||
request(app).get("/stack").expect(400).end(function(err,res) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
res.body.should.have.property("error","unexpected_error");
|
||||
res.body.should.have.property("message","Error: stacktrace");
|
||||
|
||||
/Error: stacktrace\s*at.*util_spec.js/m.test(loggedError).should.be.true();
|
||||
|
||||
loggedEvent.should.have.property("event","api.error");
|
||||
loggedEvent.should.have.property("error","unexpected_error");
|
||||
loggedEvent.should.have.property("message","Error: stacktrace");
|
||||
|
||||
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
describe('determineLangFromHeaders', function() {
|
||||
before(function() {
|
||||
apiUtil.init({
|
||||
log:{},
|
||||
i18n:{defaultLang:"en-US"}
|
||||
});
|
||||
})
|
||||
it('returns the default lang if non provided', function() {
|
||||
apiUtil.determineLangFromHeaders(null).should.eql("en-US");
|
||||
})
|
||||
it('returns the first language accepted', function() {
|
||||
apiUtil.determineLangFromHeaders(['fr-FR','en-GB']).should.eql("fr-FR");
|
||||
})
|
||||
})
|
||||
});
|
Reference in New Issue
Block a user