Skip to content

Commit e7eb02f

Browse files
committed
Add unit tests for refactored API modules
1 parent 72f9471 commit e7eb02f

16 files changed

Lines changed: 1352 additions & 318 deletions

red/api/flows.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ var express = require('express');
1717
var fs = require("fs");
1818
var events = require("../events");
1919
var path = require("path");
20+
var util = require("util");
2021

2122
var redNodes = require("../nodes");
2223
var settings = require("../settings");

red/api/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,8 @@ function init(adminApp) {
6060
adminApp.get("/library/flows",library.getAll);
6161
adminApp.get(new RegExp("/library/flows\/(.*)"),library.get);
6262

63+
64+
// Error Handler
6365
adminApp.use(errorHandler);
6466
}
6567

red/api/library.js

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -20,48 +20,49 @@ var redApp = null;
2020
var storage = require("../storage");
2121

2222
function createLibrary(type) {
23-
24-
redApp.get(new RegExp("/library/"+type+"($|\/(.*))"),function(req,res) {
25-
var path = req.params[1]||"";
26-
storage.getLibraryEntry(type,path).then(function(result) {
27-
if (typeof result === "string") {
28-
res.writeHead(200, {'Content-Type': 'text/plain'});
29-
res.write(result);
30-
res.end();
31-
} else {
32-
res.json(result);
33-
}
34-
}).otherwise(function(err) {
35-
if (err) {
36-
util.log("[red] Error loading library entry '"+path+"' : "+err);
37-
if (err.message.indexOf('forbidden') === 0) {
38-
res.send(403);
39-
return;
23+
if (redApp) {
24+
redApp.get(new RegExp("/library/"+type+"($|\/(.*))"),function(req,res) {
25+
var path = req.params[1]||"";
26+
storage.getLibraryEntry(type,path).then(function(result) {
27+
if (typeof result === "string") {
28+
res.writeHead(200, {'Content-Type': 'text/plain'});
29+
res.write(result);
30+
res.end();
31+
} else {
32+
res.json(result);
4033
}
41-
}
42-
res.send(404);
43-
});
44-
});
45-
46-
redApp.post(new RegExp("/library/"+type+"\/(.*)"),function(req,res) {
47-
var path = req.params[0];
48-
var fullBody = '';
49-
req.on('data', function(chunk) {
50-
fullBody += chunk.toString();
51-
});
52-
req.on('end', function() {
53-
storage.saveLibraryEntry(type,path,req.query,fullBody).then(function() {
54-
res.send(204);
55-
}).otherwise(function(err) {
56-
util.log("[red] Error saving library entry '"+path+"' : "+err);
34+
}).otherwise(function(err) {
35+
if (err) {
36+
util.log("[red] Error loading library entry '"+path+"' : "+err);
5737
if (err.message.indexOf('forbidden') === 0) {
5838
res.send(403);
5939
return;
6040
}
61-
res.send(500);
62-
});
41+
}
42+
res.send(404);
43+
});
6344
});
64-
});
45+
46+
redApp.post(new RegExp("/library/"+type+"\/(.*)"),function(req,res) {
47+
var path = req.params[0];
48+
var fullBody = '';
49+
req.on('data', function(chunk) {
50+
fullBody += chunk.toString();
51+
});
52+
req.on('end', function() {
53+
storage.saveLibraryEntry(type,path,req.query,fullBody).then(function() {
54+
res.send(204);
55+
}).otherwise(function(err) {
56+
util.log("[red] Error saving library entry '"+path+"' : "+err);
57+
if (err.message.indexOf('forbidden') === 0) {
58+
res.send(403);
59+
return;
60+
}
61+
res.send(500);
62+
});
63+
});
64+
});
65+
}
6566
}
6667
module.exports = {
6768
init: function(app) {

red/api/nodes.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ module.exports = {
5555
return;
5656
}
5757
promise.then(function(info) {
58-
res.json(info);
58+
res.json(info);
5959
}).otherwise(function(err) {
6060
if (err.code === 404) {
6161
res.send(404);
@@ -90,7 +90,6 @@ module.exports = {
9090
promise.then(function(removedNodes) {
9191
res.json(removedNodes);
9292
}).otherwise(function(err) {
93-
console.log(err.stack);
9493
res.send(400,err.toString());
9594
});
9695
} catch(err) {

red/api/ui.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ events.on("node-icon-dir",function(dir) {
3232
module.exports = {
3333
ensureSlash: function(req,res,next) {
3434
if (req.originalUrl.slice(-1) != "/") {
35-
res.redirect(req.originalUrl+"/");
35+
res.redirect(301,req.originalUrl+"/");
3636
} else {
3737
next();
3838
}

red/server.js

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
var express = require('express');
1818
var util = require('util');
1919
var when = require('when');
20-
var exec = require('child_process').exec;
20+
var child_process = require('child_process');
2121

2222
var redNodes = require("./nodes");
2323
var comms = require("./comms");
@@ -28,7 +28,7 @@ var nodeApp = null;
2828
var server = null;
2929
var settings = null;
3030

31-
function createServer(_server,_settings) {
31+
function init(_server,_settings) {
3232
server = _server;
3333
settings = _settings;
3434

@@ -37,7 +37,6 @@ function createServer(_server,_settings) {
3737
nodeApp = express();
3838
app = express();
3939

40-
4140
if (settings.httpAdminRoot !== false) {
4241
require("./api").init(app);
4342
}
@@ -147,7 +146,7 @@ function installModule(module) {
147146
return;
148147
}
149148
util.log("[red] Installing module: "+module);
150-
var child = exec('npm install --production '+module, function(err, stdin, stdout) {
149+
var child = child_process.exec('npm install --production '+module, function(err, stdin, stdout) {
151150
if (err) {
152151
var lookFor404 = new RegExp(" 404 .*"+module+"$","m");
153152
if (lookFor404.test(stdout)) {
@@ -171,14 +170,14 @@ function installModule(module) {
171170
}
172171

173172
function uninstallModule(module) {
174-
var list = redNodes.removeModule(module);
175173
return when.promise(function(resolve,reject) {
176174
if (/[\s;]/.test(module)) {
177175
reject(new Error("Invalid module name"));
178176
return;
179177
}
178+
var list = redNodes.removeModule(module);
180179
util.log("[red] Removing module: "+module);
181-
var child = exec('npm remove '+module, function(err, stdin, stdout) {
180+
var child = child_process.exec('npm remove '+module, function(err, stdin, stdout) {
182181
if (err) {
183182
util.log("[red] Removal of module "+module+" failed:");
184183
util.log("------------------------------------------");
@@ -202,7 +201,7 @@ function stop() {
202201
}
203202

204203
module.exports = {
205-
init: createServer,
204+
init: init,
206205
start: start,
207206
stop: stop,
208207

red/settings.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,17 @@ var persistentSettings = {
7575
},
7676

7777
reset: function() {
78+
for (var i in userSettings) {
79+
if (userSettings.hasOwnProperty(i)) {
80+
delete persistentSettings[i];
81+
}
82+
}
7883
userSettings = null;
7984
globalSettings = null;
8085
storage = null;
86+
87+
88+
8189
}
8290
}
8391

test/red/api/flows_spec.js

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* Copyright 2014 IBM Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
17+
var should = require("should");
18+
var request = require('supertest');
19+
var express = require('express');
20+
var sinon = require('sinon');
21+
var when = require('when');
22+
23+
var app = express();
24+
var redNodes = require("../../../red/nodes");
25+
26+
var flows = require("../../../red/api/flows");
27+
28+
describe("flows api", function() {
29+
30+
var app;
31+
32+
before(function() {
33+
app = express();
34+
app.use(express.json());
35+
app.get("/flows",flows.get);
36+
app.post("/flows",flows.post);
37+
});
38+
39+
it('returns flow', function(done) {
40+
var getFlows = sinon.stub(redNodes,'getFlows', function() {
41+
return [1,2,3];
42+
});
43+
request(app)
44+
.get('/flows')
45+
.set('Accept', 'application/json')
46+
.expect(200)
47+
.end(function(err,res) {
48+
getFlows.restore();
49+
if (err) {
50+
throw err;
51+
}
52+
res.body.should.be.an.Array.and.have.lengthOf(3);
53+
done();
54+
});
55+
});
56+
57+
it('sets flows', function(done) {
58+
var setFlows = sinon.stub(redNodes,'setFlows', function() {
59+
return when.resolve();
60+
});
61+
request(app)
62+
.post('/flows')
63+
.set('Accept', 'application/json')
64+
.expect(204)
65+
.end(function(err,res) {
66+
setFlows.restore();
67+
if (err) {
68+
throw err;
69+
}
70+
done();
71+
});
72+
});
73+
it('returns error when set fails', function(done) {
74+
var setFlows = sinon.stub(redNodes,'setFlows', function() {
75+
return when.reject(new Error("test error"));
76+
});
77+
request(app)
78+
.post('/flows')
79+
.set('Accept', 'application/json')
80+
.expect(500)
81+
.end(function(err,res) {
82+
setFlows.restore();
83+
if (err) {
84+
throw err;
85+
}
86+
res.text.should.eql("test error");
87+
done();
88+
});
89+
});
90+
91+
});

test/red/api/index_spec.js

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/**
2+
* Copyright 2014 IBM Corp.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
**/
16+
17+
var should = require("should");
18+
var request = require("supertest");
19+
var express = require("express");
20+
var fs = require("fs");
21+
var path = require("path");
22+
23+
var settings = require("../../../red/settings");
24+
var api = require("../../../red/api");
25+
26+
27+
describe("api index", function() {
28+
var app;
29+
30+
describe("disables editor", function() {
31+
before(function() {
32+
settings.init({disableEditor:true});
33+
app = express();
34+
api.init(app);
35+
});
36+
after(function() {
37+
settings.reset();
38+
});
39+
40+
it('does not serve the editor', function(done) {
41+
request(app)
42+
.get("/")
43+
.expect(404,done)
44+
});
45+
it('does not serve icons', function(done) {
46+
request(app)
47+
.get("/icons/default.png")
48+
.expect(404,done)
49+
});
50+
it('does not serve settings', function(done) {
51+
request(app)
52+
.get("/settings")
53+
.expect(404,done)
54+
});
55+
56+
});
57+
58+
describe("enables editor", function() {
59+
before(function() {
60+
settings.init({disableEditor:false});
61+
app = express();
62+
api.init(app);
63+
});
64+
after(function() {
65+
settings.reset();
66+
});
67+
68+
it('serves the editor', function(done) {
69+
request(app)
70+
.get("/")
71+
.expect(200)
72+
.end(function(err,res) {
73+
if (err) {
74+
return done(err);
75+
}
76+
// Index page should probably mention Node-RED somewhere
77+
res.text.indexOf("Node-RED").should.not.eql(-1);
78+
done();
79+
});
80+
});
81+
it('serves icons', function(done) {
82+
request(app)
83+
.get("/icons/inject.png")
84+
.expect("Content-Type", /image\/png/)
85+
.expect(200,done)
86+
});
87+
it('serves settings', function(done) {
88+
request(app)
89+
.get("/settings")
90+
.expect(200,done)
91+
});
92+
});
93+
});

0 commit comments

Comments
 (0)