From 9be1013bb71006ea649a36905970e6802882c4fd Mon Sep 17 00:00:00 2001 From: Jack Foltz Date: Tue, 24 Jul 2018 19:39:55 -0400 Subject: [PATCH] Update all tests and add some new ones --- test/api.js | 162 ++++++++++++++++++++++++++++++------------------------- test/testUtil.js | 110 ++++++++++++++++--------------------- 2 files changed, 134 insertions(+), 138 deletions(-) diff --git a/test/api.js b/test/api.js index 1192e5c..d636ebe 100644 --- a/test/api.js +++ b/test/api.js @@ -14,107 +14,123 @@ var server = app.server; var util = require('./testUtil.js'); -before(function (done) { - async.series([ - function (cb) { - util.resetDatabase(cb); - }, - function(cb) { - util.createInvites([{ - code: 'TestCode1', - scope: ['test.perm'] - }, { - code: 'TestCode2' - }, { - code: 'TestCode3', - exp: new Date() - } - ], cb); - } - ], function (err) { - if (err) console.log(err); - done(); - }); -}); +before(util.resetDatabase); -describe('Users', function () { - describe('/POST register', function () { - it('SHOULD register valid user, valid invite', function (done) { - util.verifySuccessfulRegister({ - username: 'TestUser1', - password: 'TestPassword', - invite: 'TestCode1' - }, done); +describe('Users', function() { + describe('/POST register', function() { + describe('0 Well Formed Requests', function() { + beforeEach((done) => { + async.series([ + util.resetDatabase, + util.createTestInvite + ], done); + }); + + it('MUST register a valid user with a valid invite', function(done) { + util.verifySuccessfulRegister({username: 'user', password: 'pass', invite: 'code'}, done); + }); + + it('MUST register a username with unicode symbols and a valid invite', function(done) { + util.verifySuccessfulRegister({username: 'ᴮᴵᴳᴮᴵᴿᴰ', password: 'pass', invite: 'code'}, done); + }) }); - it('SHOULD register another valid user, valid invite', function(done) { - util.verifySuccessfulRegister({ - username: 'TestUser2', - password: 'TestPassword', - invite: 'TestCode2' - }, done); + + describe('1 Invalid Invites', function() { + beforeEach(util.resetDatabase); + + const verifyRejectedInvite = function(invite, message, done) { + const user = {username: 'user', password: 'pass', invite: invite && invite.code ? invite.code : 'code'}; + const create = invite ? util.createInvite : (invite, cb) => cb(); + async.series([ + (cb) => create(invite, cb), + (cb) => util.verifyFailedRegister(user, message, 401, cb) + ], done); + }; + + it('MUST NOT register a nonexistant invite', function(done) { + verifyRejectedInvite(null, 'Invalid invite code.', done); + }); + + it('MUST NOT register a used invite', function(done) { + verifyRejectedInvite({used: new Date()}, 'Invite already used.', done); + }); + + it('MUST NOT register an expired invite', function(done) { + verifyRejectedInvite({exp: new Date()}, 'Invite expired.', done); + }) }); - it('SHOULD NOT register invalid user, valid invite', function (done) { - util.verifyFailedUserRegister({ - username: 'TestUser1', - password: 'TestPassword', - invite: 'TestCode2' - }, done); - }); - it('SHOULD NOT register valid user, nonexistant invite', function (done) { - util.verifyFailedInviteRegister({ - username: 'TestUser3', - password: 'TestPassword', - invite: 'bogus' - }, done); - }); + describe('2 Invalid Usernames', function() { + beforeEach((done) => { + async.series([ + util.resetDatabase, + (cb) => util.createTestInvites(3, cb) + ], done); + }); - it('SHOULD NOT register valid user, used invite', function (done) { - util.verifyFailedInviteRegister({ - username: 'TestUser3', - password: 'TestPassword', - invite: 'TestCode1' - }, done); - }); + it('MUST NOT register a duplicate username', function(done) { + const user0 = {username: 'user', password: 'pass', invite: 'code0'}; + const user1 = {username: 'user', password: 'diff', invite: 'code1'}; + async.series([ + (cb) => util.verifySuccessfulRegister(user0, cb), + (cb) => util.verifyFailedRegister(user1, 'Username in use.', 401, cb) + ], done); + }); - it('SHOULD NOT register valid user, expired invite', function (done) { - util.verifyFailedInviteRegister({ - username: 'TestUser3', - password: 'TestPassword', - invite: 'TestCode3' - }, done); - }) + it('MUST NOT register a username with a duplicate canonical name', function(done) { + const user0 = {username: 'bigbird', password: 'pass', invite: 'code0'}; + const user1 = {username: 'ᴮᴵᴳᴮᴵᴿᴰ', password: 'diff', invite: 'code1'}; + async.series([ + (cb) => util.verifySuccessfulRegister(user0, cb), + (cb) => util.verifyFailedRegister(user1, 'Username in use.', 401, cb) + ], done); + }); + + it('MUST NOT register a username containing whitespace', function(done) { + const users = [ + {username: 'user name', password: 'pass', invite: 'code0'}, + {username: 'user name', password: 'pass', invite: 'code1'}, + {username: 'user name', password: 'pass', invite: 'code2'} + ]; + const failMsg = 'Username contains invalid characters.'; + async.each(users, (user, cb) => util.verifyFailedRegister(user, failMsg, 401, cb), done); + }); + + it('MUST NOT register a username containing HTML', function(done) { + const user = {username: 'user', password: 'pass', invite: 'code0'}; + util.verifyFailedRegister(user, 'Username contains invalid characters.', 401, done); + }); + }); }); - describe('/POST login', function () { - it('SHOULD accept valid user, valid password', function (done) { + describe('/POST login', function() { + it('SHOULD accept valid user, valid password', function(done) { util.verifySuccessfulLogin({ username: 'TestUser1', password: 'TestPassword' }, done); }); - it('SHOULD NOT accept valid user, invalid password', function (done) { + it('SHOULD NOT accept valid user, invalid password', function(done) { util.verifyFailedPasswordLogin({ username: 'TestUser1', password: 'bogus' }, done); }); - it('SHOULD NOT accept invalid user, any password', function (done) { + it('SHOULD NOT accept invalid user, any password', function(done) { util.verifyFailedUsernameLogin({ username: 'BogusTestUser', password: 'bogus' }, done); }); }); - }); -describe('Uploads', function () { - describe('/POST upload', function () { +describe('Uploads', function() { + describe('/POST upload', function() { it('SHOULD accept logged in valid upload', function(done) { util.verifySuccessfulUpload({ username: 'TestUser2', @@ -142,8 +158,8 @@ describe('Uploads', function () { }); }); -after(function () { - server.close(function () { +after(function() { + server.close(function() { process.exit(); }); }); diff --git a/test/testUtil.js b/test/testUtil.js index 8db20a7..2ce1c9e 100644 --- a/test/testUtil.js +++ b/test/testUtil.js @@ -20,82 +20,62 @@ chai.use(http); //---------------- DATABASE UTIL ----------------// -var resetDatabase = function(callback) { - db.once('open', function() { - async.each([ - User, Invite, Upload, - ], function(schema, cb) { - schema.remove({}, function(err) { - cb(err); - }); - }, function(err) { - if (err) console.log(err); - callback(); - }); - }); +var resetDatabase = function(cb) { + async.each( + [User, Invite, Upload], + (schema, cb) => schema.remove({}, cb), + cb); }; -var createInvites = function(invites, callback) { - async.each(invites, function(invite, cb) { - if (!invite.scope) { - invite.scope = ['test.perm', 'file.upload']; - } - if (!invite.exp) { - var date = new Date(); - date.setDate(date.getDate() + 7); - invite.exp = date; - } - - invite.issuer = 'Mocha'; - invite.issued = new Date(); - - Invite.create(invite, function(err) { - cb(err); - }); - }, function(err) { - if (err) console.log(err); - callback(); - }) +const createInvite = function(invite, done) { + if (!invite.code) invite.code = 'code'; + if (!invite.scope) invite.scope = ['test.perm', 'file.upload']; + if (!invite.issuer) invite.issuer = 'Mocha'; + if (!invite.issued) invite.issued = new Date(); + Invite.create(invite, done); }; +const createInvites = function(invites, done) { + async.each(invites, createInvite, done); +}; + +var createTestInvite = function(done) { + createInvite({code: 'code'}, done); +}; + +var createTestInvites = function(n, done) { + const codes = Array.from(new Array(n), (val, index) => 'code' + index); + async.each(codes, (code, cb) => createInvite({code: code}, cb), done); +}; //---------------- REGISTER UTIL ----------------// -var register = function(user, cb) { +const register = function(user, cb) { chai.request(server) .post('/api/auth/register') .send(user) .end(cb); }; -var verifySuccessfulRegister = function(user, done) { - register(user, function (err, res) { +const verifySuccessfulRegister = function(user, done) { + register(user, function(err, res) { res.should.have.status(200); + res.body.should.be.a('object'); + res.body.should.have.property('message').eql('Registration successful.'); done(); }); }; -var verifyFailedUserRegister = function(user, done) { - register(user, function (err, res) { - res.should.have.status(401); +const verifyFailedRegister = function(user, message, status, done) { + register(user, function(err, res) { + res.should.have.status(status); res.body.should.be.a('object'); - res.body.should.have.property('message').eql('Invalid username.'); - done(); - }); -}; - -var verifyFailedInviteRegister = function(user, done) { - register(user, function (err, res) { - res.should.have.status(401); - res.body.should.be.a('object'); - res.body.should.have.property('message').eql('Invalid invite code.'); + res.body.should.have.property('message').eql(message); done(); }) }; - - //---------------- LOGIN UTIL ----------------// var login = function(user, cb) { @@ -106,14 +86,14 @@ var login = function(user, cb) { }; var verifySuccessfulLogin = function(user, done) { - login(user, function (err, res) { + login(user, function(err, res) { res.should.have.status(200); done(); }); }; var verifyFailedUsernameLogin = function(user, done) { - login(user, function (err, res) { + login(user, function(err, res) { res.should.have.status(401); res.body.should.be.a('object'); res.body.should.have.property('message').eql('Invalid username.'); @@ -122,7 +102,7 @@ var verifyFailedUsernameLogin = function(user, done) { }; var verifyFailedPasswordLogin = function(user, done) { - login(user, function (err, res) { + login(user, function(err, res) { res.should.have.status(401); res.body.should.be.a('object'); res.body.should.have.property('message').eql('Invalid password.'); @@ -131,7 +111,6 @@ var verifyFailedPasswordLogin = function(user, done) { }; - //---------------- UPLOAD UTIL ----------------// var upload = function(token, file, cb) { @@ -186,7 +165,7 @@ var verifyFailedPermissionUpload = function(user, done) { var verifyFailedAuthUpload = function(done) { async.parallel([ function(cb) { - upload('bogus', 'test/test.png', function (err, res) { + upload('bogus', 'test/test.png', function(err, res) { res.should.have.status(401); res.body.should.be.a('object'); res.body.should.have.property('message').eql('UnauthorizedError: jwt malformed'); @@ -204,11 +183,11 @@ var verifyFailedAuthUpload = function(done) { '8JwmEFxO3zRf66tWo', 'test/test.png', function(err, res) { - res.should.have.status(401); - res.body.should.be.a('object'); - res.body.should.have.property('message').eql('UnauthorizedError: invalid signature'); - cb(); - }) + res.should.have.status(401); + res.body.should.be.a('object'); + res.body.should.have.property('message').eql('UnauthorizedError: invalid signature'); + cb(); + }) } ], function(err, res) { if (err) console.log(err); @@ -217,16 +196,17 @@ var verifyFailedAuthUpload = function(done) { }; - module.exports = { resetDatabase: resetDatabase, + createInvite: createInvite, createInvites: createInvites, + createTestInvite: createTestInvite, + createTestInvites: createTestInvites, register: register, verifySuccessfulRegister: verifySuccessfulRegister, - verifyFailedUserRegister: verifyFailedUserRegister, - verifyFailedInviteRegister: verifyFailedInviteRegister, + verifyFailedRegister: verifyFailedRegister, login: login, verifySuccessfulLogin: verifySuccessfulLogin,