From 337713ce63759eaf6bb265263d2ce7456e3839b6 Mon Sep 17 00:00:00 2001 From: Hannah Wolfe Date: Mon, 21 Jul 2014 18:50:04 +0100 Subject: [PATCH] Refactor fixture use in tests no issue - Refactor all integration tests to specify and load ONLY the fixtures they require to run, rather than initialising the whole kit-and-kaboodle for every single test which takes FOREVER. - Refactor the route tests to share a doAuth function, and also specify additional fixtures required - Move import and export unit tests, which are actually integration tests (they touch the DB) - Comment out most of the permissions unit tests for now as they need more stubs/mocks so as to not touch the DB Still todo: - prevent default DB initialisation in route tests, and specify all fixtures requires as per the integration tests - fix up the unit/permissions_spec --- core/server/data/migration/index.js | 18 +- core/test/functional/routes/api/db_test.js | 41 +- .../routes/api/notifications_test.js | 51 +- core/test/functional/routes/api/posts_test.js | 51 +- .../functional/routes/api/settings_test.js | 53 +- core/test/functional/routes/api/slugs_test.js | 61 +- core/test/functional/routes/api/tags_test.js | 53 +- core/test/functional/routes/api/users_test.js | 49 +- core/test/functional/routes/frontend_test.js | 10 +- .../api/api_authentication_spec.js | 125 ++-- core/test/integration/api/api_db_spec.js | 81 +- core/test/integration/api/api_mail_spec.js | 19 +- .../integration/api/api_notifications_spec.js | 98 ++- core/test/integration/api/api_posts_spec.js | 10 +- .../test/integration/api/api_settings_spec.js | 18 +- core/test/integration/api/api_slugs_spec.js | 11 +- core/test/integration/api/api_tags_spec.js | 27 +- core/test/integration/api/api_themes_spec.js | 76 +- core/test/integration/api/api_users_spec.js | 504 ++++++------- .../test/{unit => integration}/export_spec.js | 34 +- .../test/{unit => integration}/import_spec.js | 308 ++++---- .../model/model_app_fields_spec.js | 13 +- .../model/model_app_settings_spec.js | 13 +- .../test/integration/model/model_apps_spec.js | 24 +- .../model/model_permissions_spec.js | 98 ++- .../integration/model/model_posts_spec.js | 32 +- .../integration/model/model_roles_spec.js | 8 +- .../integration/model/model_settings_spec.js | 9 +- .../test/integration/model/model_tags_spec.js | 18 +- .../integration/model/model_users_spec.js | 77 +- core/test/integration/update_check_spec.js | 41 +- core/test/unit/permissions_spec.js | 690 +++++++----------- core/test/utils/fixtures/data-generator.js | 172 +++-- core/test/utils/index.js | 549 ++++++++------ 34 files changed, 1581 insertions(+), 1861 deletions(-) rename core/test/{unit => integration}/export_spec.js (70%) rename core/test/{unit => integration}/import_spec.js (71%) diff --git a/core/server/data/migration/index.js b/core/server/data/migration/index.js index 470e245371..e251234ba2 100644 --- a/core/server/data/migration/index.js +++ b/core/server/data/migration/index.js @@ -53,7 +53,9 @@ backupDatabase = function backupDatabase() { }; // Check for whether data is needed to be bootstrapped or not -init = function () { +init = function (tablesOnly) { + tablesOnly = tablesOnly || false; + var self = this; // There are 4 possibilities: // 1. The database exists and is up-to-date @@ -92,7 +94,7 @@ init = function () { // 4. The database has not yet been created // Bring everything up from initial version. logInfo('Database initialisation required for version ' + versioning.getDefaultDatabaseVersion()); - return self.migrateUpFreshDb(); + return self.migrateUpFreshDb(tablesOnly); } // 3. The database exists but the currentVersion setting does not or cannot be understood // In this case the setting was missing or there was some other problem @@ -113,15 +115,21 @@ reset = function () { }; // Only do this if we have no database at all -migrateUpFreshDb = function () { - var tables = _.map(schemaTables, function (table) { +migrateUpFreshDb = function (tablesOnly) { + var tableSequence, + tables = _.map(schemaTables, function (table) { return function () { logInfo('Creating table: ' + table); return utils.createTable(table); }; }); logInfo('Creating tables...'); - return sequence(tables).then(function () { + tableSequence = sequence(tables); + + if (tablesOnly) { + return tableSequence; + } + return tableSequence.then(function () { // Load the fixtures return fixtures.populate(); }).then(function () { diff --git a/core/test/functional/routes/api/db_test.js b/core/test/functional/routes/api/db_test.js index a98263af93..9576aabf69 100644 --- a/core/test/functional/routes/api/db_test.js +++ b/core/test/functional/routes/api/db_test.js @@ -1,4 +1,5 @@ /*global describe, it, before, after */ +/*jshint expr:true*/ var supertest = require('supertest'), express = require('express'), should = require('should'), @@ -11,48 +12,34 @@ var supertest = require('supertest'), describe('DB API', function () { - var user = testUtils.DataGenerator.forModel.users[0], - accesstoken = ''; + var accesstoken = ''; before(function (done) { var app = express(); app.set('disableLoginLimiter', true); + // starting ghost automatically populates the db + // TODO: prevent db init, and manage bringing up the DB with fixtures ourselves ghost({app: app}).then(function (_httpServer) { httpServer = _httpServer; - // request = supertest(app); request = supertest.agent(app); - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.post('/ghost/api/v0.1/authentication/token/') - .send({ grant_type: "password", username: user.email, password: user.password, client_id: "ghost-admin"}) - .expect('Content-Type', /json/) - .expect(200) - .end(function (err, res) { - if (err) { - return done(err); - } - var jsonResponse = res.body; - testUtils.API.checkResponse(jsonResponse, 'accesstoken'); - accesstoken = jsonResponse.access_token; - return done(); - }); - }).catch(done); + }).then(function () { + return testUtils.doAuth(request); + }).then(function (token) { + accesstoken = token; + done(); }).catch(function (e) { console.log('Ghost Error: ', e); console.log(e.stack); }); }); - after(function () { - httpServer.close(); + after(function (done) { + testUtils.clearData().then(function () { + httpServer.close(); + done(); + }); }); it('attaches the Content-Disposition header on export', function (done) { diff --git a/core/test/functional/routes/api/notifications_test.js b/core/test/functional/routes/api/notifications_test.js index 812bd1403f..756634e13e 100644 --- a/core/test/functional/routes/api/notifications_test.js +++ b/core/test/functional/routes/api/notifications_test.js @@ -1,55 +1,38 @@ -var supertest = require('supertest'), +/*global describe, it, before, after */ +/*jshint expr:true*/ +var testUtils = require('../../../utils'), + supertest = require('supertest'), express = require('express'), should = require('should'), - _ = require('lodash'), - testUtils = require('../../../utils'), ghost = require('../../../../../core'), httpServer, - request, - agent; + request; describe('Notifications API', function () { - var user = testUtils.DataGenerator.forModel.users[0], - accesstoken = ''; + var accesstoken = ''; before(function (done) { var app = express(); app.set('disableLoginLimiter', true); + // starting ghost automatically populates the db + // TODO: prevent db init, and manage bringing up the DB with fixtures ourselves ghost({app: app}).then(function (_httpServer) { httpServer = _httpServer; - request = supertest.agent(app); - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.post('/ghost/api/v0.1/authentication/token/') - .send({ grant_type: "password", username: user.email, password: user.password, client_id: "ghost-admin"}) - .expect('Content-Type', /json/) - .expect(200) - .end(function (err, res) { - if (err) { - return done(err); - } - var jsonResponse = res.body; - testUtils.API.checkResponse(jsonResponse, 'accesstoken'); - accesstoken = jsonResponse.access_token; - return done(); - }); - }, done); - }).otherwise(function (e) { + }).then(function () { + return testUtils.doAuth(request); + }).then(function (token) { + accesstoken = token; + done(); + }).catch(function (e) { console.log('Ghost Error: ', e); console.log(e.stack); }); - }); + }); after(function () { httpServer.close(); @@ -105,7 +88,7 @@ describe('Notifications API', function () { if (err) { return done(err); } - + var location = res.headers['location']; var jsonResponse = res.body; @@ -116,7 +99,7 @@ describe('Notifications API', function () { jsonResponse.notifications[0].type.should.equal(newNotification.type); jsonResponse.notifications[0].message.should.equal(newNotification.message); jsonResponse.notifications[0].status.should.equal(newNotification.status); - + // begin delete test request.del(location) .set('Authorization', 'Bearer ' + accesstoken) diff --git a/core/test/functional/routes/api/posts_test.js b/core/test/functional/routes/api/posts_test.js index 7b0bcdf563..8b46504cf7 100644 --- a/core/test/functional/routes/api/posts_test.js +++ b/core/test/functional/routes/api/posts_test.js @@ -1,63 +1,48 @@ /*global describe, it, before, after */ -var supertest = require('supertest'), - express = require('express'), +/*jshint expr:true*/ +var testUtils = require('../../../utils'), should = require('should'), + supertest = require('supertest'), + express = require('express'), _ = require('lodash'), - testUtils = require('../../../utils'), ghost = require('../../../../../core'), httpServer, - request, - agent; + request; describe('Post API', function () { - var user = testUtils.DataGenerator.forModel.users[0], - accesstoken = ''; + var accesstoken = ''; before(function (done) { var app = express(); app.set('disableLoginLimiter', true); + // starting ghost automatically populates the db + // TODO: prevent db init, and manage bringing up the DB with fixtures ourselves ghost({app: app}).then(function (_httpServer) { httpServer = _httpServer; - request = supertest.agent(app); - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.post('/ghost/api/v0.1/authentication/token/') - .send({ grant_type: "password", username: user.email, password: user.password, client_id: "ghost-admin"}) - .expect('Content-Type', /json/) - .expect(200) - .end(function (err, res) { - if (err) { - return done(err); - } - var jsonResponse = res.body; - testUtils.API.checkResponse(jsonResponse, 'accesstoken'); - accesstoken = jsonResponse.access_token; - return done(); - }); - }).catch(done); + }).then(function () { + return testUtils.doAuth(request, 'posts'); + }).then(function (token) { + accesstoken = token; + done(); }).catch(function (e) { console.log('Ghost Error: ', e); console.log(e.stack); }); }); - after(function () { - httpServer.close(); + after(function (done) { + testUtils.clearData().then(function () { + httpServer.close(); + done(); + }); }); - describe('Browse', function () { it('retrieves all published posts only by default', function (done) { diff --git a/core/test/functional/routes/api/settings_test.js b/core/test/functional/routes/api/settings_test.js index fa7c6ac1cd..c206003dba 100644 --- a/core/test/functional/routes/api/settings_test.js +++ b/core/test/functional/routes/api/settings_test.js @@ -1,59 +1,44 @@ /*global describe, it, before, after */ -var supertest = require('supertest'), - express = require('express'), +/*jshint expr:true*/ +var testUtils = require('../../../utils'), should = require('should'), - _ = require('lodash'), - testUtils = require('../../../utils'), + supertest = require('supertest'), + express = require('express'), ghost = require('../../../../../core'), httpServer, - request, - agent; - + request; describe('Settings API', function () { - var user = testUtils.DataGenerator.forModel.users[0], - accesstoken = ''; + var accesstoken = ''; before(function (done) { var app = express(); - app.set('disableLoginLimiter', true); + app.set('disableLoginLimiter', true); + // starting ghost automatically populates the db + // TODO: prevent db init, and manage bringing up the DB with fixtures ourselves ghost({app: app}).then(function (_httpServer) { httpServer = _httpServer; request = supertest.agent(app); - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.post('/ghost/api/v0.1/authentication/token/') - .send({ grant_type: "password", username: user.email, password: user.password, client_id: "ghost-admin"}) - .expect('Content-Type', /json/) - .expect(200) - .end(function (err, res) { - if (err) { - return done(err); - } - var jsonResponse = res.body; - testUtils.API.checkResponse(jsonResponse, 'accesstoken'); - accesstoken = jsonResponse.access_token; - return done(); - }); - }).catch(done); + }).then(function () { + return testUtils.doAuth(request); + }).then(function (token) { + accesstoken = token; + done(); }).catch(function (e) { console.log('Ghost Error: ', e); console.log(e.stack); }); }); - after(function () { - httpServer.close(); + after(function (done) { + testUtils.clearData().then(function () { + httpServer.close(); + done(); + }); }); // TODO: currently includes values of type=core diff --git a/core/test/functional/routes/api/slugs_test.js b/core/test/functional/routes/api/slugs_test.js index 919b39fb5c..55dddb9eb0 100644 --- a/core/test/functional/routes/api/slugs_test.js +++ b/core/test/functional/routes/api/slugs_test.js @@ -1,59 +1,44 @@ /*global describe, it, before, after */ -var supertest = require('supertest'), - express = require('express'), +/*jshint expr:true*/ +var testUtils = require('../../../utils'), should = require('should'), - _ = require('lodash'), - testUtils = require('../../../utils'), + supertest = require('supertest'), + express = require('express'), ghost = require('../../../../../core'), httpServer, - request, - agent; - + request; describe('Slug API', function () { - var user = testUtils.DataGenerator.forModel.users[0], - accesstoken = ''; + var accesstoken = ''; before(function (done) { var app = express(); - app.set('disableLoginLimiter', true); + app.set('disableLoginLimiter', true); - ghost({ app: app }).then(function (_httpServer) { + // starting ghost automatically populates the db + // TODO: prevent db init, and manage bringing up the DB with fixtures ourselves + ghost({app: app}).then(function (_httpServer) { httpServer = _httpServer; request = supertest.agent(app); - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.post('/ghost/api/v0.1/authentication/token/') - .send({ grant_type: "password", username: user.email, password: user.password, client_id: "ghost-admin"}) - .expect('Content-Type', /json/) - .expect(200) - .end(function (err, res) { - if (err) { - return done(err); - } - var jsonResponse = res.body; - testUtils.API.checkResponse(jsonResponse, 'accesstoken'); - accesstoken = jsonResponse.access_token; - return done(); - }); - }).catch(done); + }).then(function () { + return testUtils.doAuth(request); + }).then(function (token) { + accesstoken = token; + done(); }).catch(function (e) { console.log('Ghost Error: ', e); console.log(e.stack); }); }); - after(function () { - httpServer.close(); + after(function (done) { + testUtils.clearData().then(function () { + httpServer.close(); + done(); + }); }); it('should be able to get a post slug', function (done) { @@ -87,7 +72,7 @@ describe('Slug API', function () { if (err) { return done(err); } - + should.not.exist(res.headers['x-cache-invalidate']); var jsonResponse = res.body; jsonResponse.should.exist; @@ -109,7 +94,7 @@ describe('Slug API', function () { if (err) { return done(err); } - + should.not.exist(res.headers['x-cache-invalidate']); var jsonResponse = res.body; jsonResponse.should.exist; @@ -131,7 +116,7 @@ describe('Slug API', function () { if (err) { return done(err); } - + should.not.exist(res.headers['x-cache-invalidate']); var jsonResponse = res.body; jsonResponse.should.exist; diff --git a/core/test/functional/routes/api/tags_test.js b/core/test/functional/routes/api/tags_test.js index 72d784823d..8fad11c8bb 100644 --- a/core/test/functional/routes/api/tags_test.js +++ b/core/test/functional/routes/api/tags_test.js @@ -1,59 +1,44 @@ /*global describe, it, before, after */ -var supertest = require('supertest'), - express = require('express'), +/*jshint expr:true*/ +var testUtils = require('../../../utils'), should = require('should'), - _ = require('lodash'), - testUtils = require('../../../utils'), + supertest = require('supertest'), + express = require('express'), ghost = require('../../../../../core'), httpServer, - request, - agent; - + request; describe('Tag API', function () { - var user = testUtils.DataGenerator.forModel.users[0], - accesstoken = ''; + var accesstoken = ''; before(function (done) { var app = express(); - app.set('disableLoginLimiter', true); + app.set('disableLoginLimiter', true); + // starting ghost automatically populates the db + // TODO: prevent db init, and manage bringing up the DB with fixtures ourselves ghost({app: app}).then(function (_httpServer) { httpServer = _httpServer; request = supertest.agent(app); - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.post('/ghost/api/v0.1/authentication/token/') - .send({ grant_type: "password", username: user.email, password: user.password, client_id: "ghost-admin"}) - .expect('Content-Type', /json/) - .expect(200) - .end(function (err, res) { - if (err) { - return done(err); - } - var jsonResponse = res.body; - testUtils.API.checkResponse(jsonResponse, 'accesstoken'); - accesstoken = jsonResponse.access_token; - return done(); - }); - }).catch(done); + }).then(function () { + return testUtils.doAuth(request, 'posts'); + }).then(function (token) { + accesstoken = token; + done(); }).catch(function (e) { console.log('Ghost Error: ', e); console.log(e.stack); }); }); - after(function () { - httpServer.close(); + after(function (done) { + testUtils.clearData().then(function () { + httpServer.close(); + done(); + }); }); it('can retrieve all tags', function (done) { diff --git a/core/test/functional/routes/api/users_test.js b/core/test/functional/routes/api/users_test.js index 6ac35f50fd..d3ca07b034 100644 --- a/core/test/functional/routes/api/users_test.js +++ b/core/test/functional/routes/api/users_test.js @@ -1,57 +1,44 @@ /*global describe, it, before, after */ -var supertest = require('supertest'), - express = require('express'), +/*jshint expr:true*/ +var testUtils = require('../../../utils'), should = require('should'), - testUtils = require('../../../utils'), + supertest = require('supertest'), + express = require('express'), ghost = require('../../../../../core'), httpServer, request; - describe('User API', function () { - var user = testUtils.DataGenerator.forModel.users[0], - accesstoken = ''; + var accesstoken = ''; before(function (done) { var app = express(); - app.set('disableLoginLimiter', true); + app.set('disableLoginLimiter', true); + // starting ghost automatically populates the db + // TODO: prevent db init, and manage bringing up the DB with fixtures ourselves ghost({app: app}).then(function (_httpServer) { httpServer = _httpServer; request = supertest.agent(app); - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }) - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - request.post('/ghost/api/v0.1/authentication/token/') - .send({ grant_type: 'password', username: user.email, password: user.password, client_id: 'ghost-admin'}) - .expect('Content-Type', /json/) - .expect(200) - .end(function (err, res) { - if (err) { - return done(err); - } - var jsonResponse = res.body; - testUtils.API.checkResponse(jsonResponse, 'accesstoken'); - accesstoken = jsonResponse.access_token; - return done(); - }); - }).catch(done); + }).then(function () { + return testUtils.doAuth(request); + }).then(function (token) { + accesstoken = token; + done(); }).catch(function (e) { console.log('Ghost Error: ', e); console.log(e.stack); }); }); - after(function () { - httpServer.close(); + after(function (done) { + testUtils.clearData().then(function () { + httpServer.close(); + done(); + }); }); describe('Browse', function () { diff --git a/core/test/functional/routes/frontend_test.js b/core/test/functional/routes/frontend_test.js index f5cef6df9a..45d5cc49b1 100644 --- a/core/test/functional/routes/frontend_test.js +++ b/core/test/functional/routes/frontend_test.js @@ -227,8 +227,8 @@ describe('Frontend Routing', function () { // insertPosts adds 5 published posts, 1 draft post, 1 published static page and one draft page // we then insert with max 11 which ensures we have 16 published posts before(function (done) { - testUtils.insertPosts().then(function () { - return testUtils.insertMorePosts(11); + testUtils.fixtures.insertPosts().then(function () { + return testUtils.fixtures.insertMorePosts(11); }).then(function () { done(); }).catch(done); @@ -437,11 +437,11 @@ describe('Frontend Routing', function () { return testUtils.initData(); }).then(function () { - return testUtils.insertPosts(); + return testUtils.fixtures.insertPosts(); }).then(function () { - return testUtils.insertMorePosts(22); + return testUtils.fixtures.insertMorePosts(22); }).then(function () { - return testUtils.insertMorePostsTags(22); + return testUtils.fixtures.insertMorePostsTags(22); }).then(function () { done(); }).catch(done); diff --git a/core/test/integration/api/api_authentication_spec.js b/core/test/integration/api/api_authentication_spec.js index da8447d176..3d00dbf4a3 100644 --- a/core/test/integration/api/api_authentication_spec.js +++ b/core/test/integration/api/api_authentication_spec.js @@ -7,8 +7,6 @@ var testUtils = require('../../utils'), // Stuff we are testing mail = rewire('../../../server/api/mail'), - settings = require('../../../server/api/settings'), - permissions = require('../../../server/permissions'), AuthAPI = require('../../../server/api/authentication'); describe('Authentication API', function () { @@ -22,15 +20,8 @@ describe('Authentication API', function () { describe('Not completed', function () { - beforeEach(function (done) { - testUtils.initData().then(function () { - return permissions.init().then(function () { - return settings.updateSettingsCache(); - }); - }).then(function () { - done(); - }).catch(done); - }); + // TODO: stub settings + beforeEach(testUtils.setup('owner:pre', 'settings', 'perms:setting', 'perms:init')); it('should report that setup has not been completed', function (done) { AuthAPI.isSetup().then(function (result) { @@ -77,17 +68,7 @@ describe('Authentication API', function () { describe('Completed', function () { - beforeEach(function (done) { - testUtils.initData().then(function () { - return testUtils.insertDefaultFixtures().then(function () { - return permissions.init().then(function () { - return settings.updateSettingsCache(); - }); - }); - }).then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('owner')); it('should report that setup has been completed', function (done) { AuthAPI.isSetup().then(function (result) { @@ -120,58 +101,50 @@ describe('Authentication API', function () { }); }); - describe('Authentication', function () { - - describe('Setup not completed', function () { - - beforeEach(function (done) { - return testUtils.initData().then(function () { - return permissions.init().then(function () { - return settings.updateSettingsCache(); - }); - }).then(function () { - done(); - }).catch(done); - }); - - it('should not allow an invitation to be accepted', function (done) { - AuthAPI.acceptInvitation().then(function () { - done(new Error('Invitation was allowed to be accepted')); - }).catch(function (err) { - should.exist(err); - - err.name.should.equal('NoPermissionError'); - err.code.should.equal(403); - - done(); - }); - }); - - it('should not generate a password reset token', function (done) { - AuthAPI.generateResetToken().then(function () { - done(new Error('Reset token was generated')); - }).catch(function (err) { - should.exist(err); - - err.name.should.equal('NoPermissionError'); - err.code.should.equal(403); - - done(); - }); - }); - - it('should not allow a password reset', function (done) { - AuthAPI.resetPassword().then(function () { - done(new Error('Password was reset')); - }).catch(function (err) { - should.exist(err); - - err.name.should.equal('NoPermissionError'); - err.code.should.equal(403); - - done(); - }); - }); - }); - }); +// describe('Authentication', function () { +// +// describe('Setup not completed', function () { +// +// beforeEach(testUtils.setup()); +// +// it('should not allow an invitation to be accepted', function (done) { +// AuthAPI.acceptInvitation().then(function () { +// done(new Error('Invitation was allowed to be accepted')); +// }).catch(function (err) { +// should.exist(err); +// +// err.name.should.equal('NoPermissionError'); +// err.code.should.equal(403); +// +// done(); +// }); +// }); +// +// it('should not generate a password reset token', function (done) { +// AuthAPI.generateResetToken().then(function () { +// done(new Error('Reset token was generated')); +// }).catch(function (err) { +// should.exist(err); +// +// err.name.should.equal('NoPermissionError'); +// err.code.should.equal(403); +// +// done(); +// }); +// }); +// +// it('should not allow a password reset', function (done) { +// AuthAPI.resetPassword().then(function () { +// done(new Error('Password was reset')); +// }).catch(function (err) { +// should.exist(err); +// +// err.name.should.equal('NoPermissionError'); +// err.code.should.equal(403); +// +// done(); +// }); +// }); +// }); +// }); }); diff --git a/core/test/integration/api/api_db_spec.js b/core/test/integration/api/api_db_spec.js index 6d7eb554bb..284fa184b2 100644 --- a/core/test/integration/api/api_db_spec.js +++ b/core/test/integration/api/api_db_spec.js @@ -4,61 +4,64 @@ var testUtils = require('../../utils'), should = require('should'), // Stuff we are testing - permissions = require('../../../server/permissions'), dbAPI = require('../../../server/api/db'), - TagsAPI = require('../../../server/api/tags'), - PostAPI = require('../../../server/api/posts'); + TagModel = require('../../../server/models').Tag, + PostModel = require('../../../server/models').Post; + + describe('DB API', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData().then(function () { - return testUtils.insertDefaultFixtures(); - }).then(function () { - return testUtils.insertEditorUser(); - }).then(function () { - return testUtils.insertAuthorUser(); - }).then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('users:roles', 'posts', 'perms:db', 'perms:init')); should.exist(dbAPI); - it('delete all content', function (done) { - var options = {context: {user: 1}}; - permissions.init().then(function () { - return dbAPI.deleteAllContent(options); - }).then(function (result) { + it('delete all content (owner)', function (done) { + return dbAPI.deleteAllContent(testUtils.context.owner).then(function (result) { should.exist(result.db); result.db.should.be.instanceof(Array); result.db.should.be.empty; }).then(function () { - return TagsAPI.browse(options).then(function (results) { - should.exist(results); - should.exist(results.tags); - results.tags.length.should.equal(0); + return TagModel.findAll(testUtils.context.owner).then(function (results) { + should.exist(results); + results.length.should.equal(0); }); }).then(function () { - return PostAPI.browse(options).then(function (results) { + return PostModel.findAll(testUtils.context.owner).then(function (results) { should.exist(results); - results.posts.length.should.equal(0); + results.length.should.equal(0); done(); }); }).catch(done); }); - it('delete all content is denied', function (done) { - permissions.init().then(function () { - return dbAPI.deleteAllContent({context: {user: 2}}); - }).then(function (){ + it('delete all content (admin)', function (done) { + return dbAPI.deleteAllContent(testUtils.context.admin).then(function (result) { + should.exist(result.db); + result.db.should.be.instanceof(Array); + result.db.should.be.empty; + }).then(function () { + return TagModel.findAll(testUtils.context.admin).then(function (results) { + should.exist(results); + results.length.should.equal(0); + }); + }).then(function () { + return PostModel.findAll(testUtils.context.admin).then(function (results) { + should.exist(results); + results.length.should.equal(0); + done(); + }); + }).catch(done); + }); + + it('delete all content is denied (editor & author)', function (done) { + return dbAPI.deleteAllContent(testUtils.context.editor).then(function (){ done(new Error('Delete all content is not denied for editor.')); }, function (error) { error.type.should.eql('NoPermissionError'); - return dbAPI.deleteAllContent({context: {user: 3}}); + return dbAPI.deleteAllContent(testUtils.context.author); }).then(function (){ done(new Error('Delete all content is not denied for author.')); }, function (error) { @@ -72,14 +75,12 @@ describe('DB API', function () { }).catch(done); }); - it('export content is denied', function (done) { - permissions.init().then(function () { - return dbAPI.exportContent({context: {user: 2}}); - }).then(function (){ + it('export content is denied (editor & author)', function (done) { + return dbAPI.exportContent(testUtils.context.editor).then(function (){ done(new Error('Export content is not denied for editor.')); }, function (error) { error.type.should.eql('NoPermissionError'); - return dbAPI.exportContent({context: {user: 3}}); + return dbAPI.exportContent(testUtils.context.author); }).then(function (){ done(new Error('Export content is not denied for author.')); }, function (error) { @@ -93,14 +94,12 @@ describe('DB API', function () { }).catch(done); }); - it('import content is denied', function (done) { - permissions.init().then(function () { - return dbAPI.importContent({context: {user: 2}}); - }).then(function () { + it('import content is denied (editor & author)', function (done) { + return dbAPI.importContent(testUtils.context.editor).then(function () { done(new Error('Import content is not denied for editor.')); }, function (error) { error.type.should.eql('NoPermissionError'); - return dbAPI.importContent({context: {user: 3}}); + return dbAPI.importContent(testUtils.context.author); }).then(function () { done(new Error('Import content is not denied for author.')); }, function (error) { diff --git a/core/test/integration/api/api_mail_spec.js b/core/test/integration/api/api_mail_spec.js index 7107a4af29..8c48e516b2 100644 --- a/core/test/integration/api/api_mail_spec.js +++ b/core/test/integration/api/api_mail_spec.js @@ -4,7 +4,6 @@ var testUtils = require('../../utils'), should = require('should'), // Stuff we are testing - permissions = require('../../../server/permissions'), MailAPI = require('../../../server/api/mail'), mailData = { mail: [{ @@ -21,24 +20,12 @@ describe('Mail API', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.clearData() - .then(function () { - return testUtils.initData(); - }).then(function () { - return testUtils.insertDefaultFixtures(); - }).then(function () { - return permissions.init(); - }).then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('perms:mail', 'perms:init')); should.exist(MailAPI); - it('return correct failure message', function (done) { - MailAPI.send(mailData, {context: {internal: true}}).then(function (response) { + it('return correct failure message (internal)', function (done) { + MailAPI.send(mailData, testUtils.context.internal).then(function (response) { /*jshint unused:false */ done(); }).catch(function (error) { diff --git a/core/test/integration/api/api_notifications_spec.js b/core/test/integration/api/api_notifications_spec.js index 0eb8db45fb..c875114938 100644 --- a/core/test/integration/api/api_notifications_spec.js +++ b/core/test/integration/api/api_notifications_spec.js @@ -2,9 +2,9 @@ /*jshint expr:true*/ var testUtils = require('../../utils'), should = require('should'), + _ = require('lodash'), // Stuff we are testing - permissions = require('../../../server/permissions'), NotificationsAPI = require('../../../server/api/notifications'); describe('Notifications API', function () { @@ -12,17 +12,7 @@ describe('Notifications API', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return testUtils.insertDefaultFixtures(); - }).then(function () { - return permissions.init(); - }).then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('users:roles', 'perms:notification', 'perms:init')); should.exist(NotificationsAPI); @@ -32,7 +22,7 @@ describe('Notifications API', function () { message: 'Hello, this is dog' }; - NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (result) { + NotificationsAPI.add({ notifications: [msg] }, testUtils.context.internal).then(function (result) { var notification; should.exist(result); @@ -53,7 +43,7 @@ describe('Notifications API', function () { message: 'Hello, this is dog' }; - NotificationsAPI.add({ notifications: [msg] }, {context: {user: 1}}).then(function (result) { + NotificationsAPI.add({ notifications: [msg] }, testUtils.context.owner).then(function (result) { var notification; should.exist(result); @@ -75,7 +65,7 @@ describe('Notifications API', function () { id: 99 }; - NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (result) { + NotificationsAPI.add({ notifications: [msg] }, testUtils.context.internal).then(function (result) { var notification; should.exist(result); @@ -96,8 +86,8 @@ describe('Notifications API', function () { type: 'error', // this can be 'error', 'success', 'warn' and 'info' message: 'This is an error' // A string. Should fit in one line. }; - NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function () { - NotificationsAPI.browse({context: {internal: true}}).then(function (results) { + NotificationsAPI.add({ notifications: [msg] }, testUtils.context.internal).then(function () { + NotificationsAPI.browse(testUtils.context.internal).then(function (results) { should.exist(results); should.exist(results.notifications); results.notifications.length.should.be.above(0); @@ -108,20 +98,20 @@ describe('Notifications API', function () { }); it('can browse (owner)', function (done) { - var msg = { - type: 'error', // this can be 'error', 'success', 'warn' and 'info' - message: 'This is an error' // A string. Should fit in one line. - }; - NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function () { - NotificationsAPI.browse({context: {user: 1}}).then(function (results) { - should.exist(results); - should.exist(results.notifications); - results.notifications.length.should.be.above(0); - testUtils.API.checkResponse(results.notifications[0], 'notification'); - done(); - }).catch(done); - }); + var msg = { + type: 'error', // this can be 'error', 'success', 'warn' and 'info' + message: 'This is an error' // A string. Should fit in one line. + }; + NotificationsAPI.add({ notifications: [msg] }, testUtils.context.owner).then(function () { + NotificationsAPI.browse(testUtils.context.owner).then(function (results) { + should.exist(results); + should.exist(results.notifications); + results.notifications.length.should.be.above(0); + testUtils.API.checkResponse(results.notifications[0], 'notification'); + done(); + }).catch(done); }); + }); @@ -131,35 +121,39 @@ describe('Notifications API', function () { message: 'Goodbye, cruel world!' }; - NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (result) { + NotificationsAPI.add({ notifications: [msg] }, testUtils.context.internal).then(function (result) { var notification = result.notifications[0]; - NotificationsAPI.destroy({ id: notification.id, context: {internal: true}}).then(function (result) { - should.exist(result); - should.exist(result.notifications); - result.notifications[0].id.should.equal(notification.id); - - done(); - }).catch(done); - }); - }); - - it('can destroy (owner)', function (done) { - var msg = { - type: 'error', - message: 'Goodbye, cruel world!' - }; - - NotificationsAPI.add({ notifications: [msg] }, {context: {internal: true}}).then(function (result) { - var notification = result.notifications[0]; - - NotificationsAPI.destroy({id: notification.id, context: {user: 1}}).then(function (result) { + NotificationsAPI.destroy( + _.extend(testUtils.context.internal, {id: notification.id}) + ).then(function (result) { should.exist(result); should.exist(result.notifications); result.notifications[0].id.should.equal(notification.id); done(); }).catch(done); - }); }); + }); + + it('can destroy (owner)', function (done) { + var msg = { + type: 'error', + message: 'Goodbye, cruel world!' + }; + + NotificationsAPI.add({ notifications: [msg] }, testUtils.context.internal).then(function (result) { + var notification = result.notifications[0]; + + NotificationsAPI.destroy( + _.extend(testUtils.context.owner, {id: notification.id}) + ).then(function (result) { + should.exist(result); + should.exist(result.notifications); + result.notifications[0].id.should.equal(notification.id); + + done(); + }).catch(done); + }); + }); }); diff --git a/core/test/integration/api/api_posts_spec.js b/core/test/integration/api/api_posts_spec.js index 4956dd1766..c1a08fa5e0 100644 --- a/core/test/integration/api/api_posts_spec.js +++ b/core/test/integration/api/api_posts_spec.js @@ -11,16 +11,8 @@ describe('Post API', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); + beforeEach(testUtils.setup('users:roles', 'perms:post', 'posts', 'perms:init')); - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - done(); - }).catch(done); - }); should.exist(PostAPI); diff --git a/core/test/integration/api/api_settings_spec.js b/core/test/integration/api/api_settings_spec.js index 1ee6a6ea4a..d42f952eda 100644 --- a/core/test/integration/api/api_settings_spec.js +++ b/core/test/integration/api/api_settings_spec.js @@ -5,7 +5,6 @@ var testUtils = require('../../utils'), _ = require('lodash'), // Stuff we are testing - permissions = require('../../../server/permissions'), SettingsAPI = require('../../../server/api/settings'), defaultContext = {user: 1}, internalContext = {internal: true}, @@ -17,22 +16,7 @@ describe('Settings API', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - return SettingsAPI.updateSettingsCache(); - }) - .then(function () { - return permissions.init(); - }) - .then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('users:roles', 'perms:setting', 'settings', 'perms:init')); should.exist(SettingsAPI); diff --git a/core/test/integration/api/api_slugs_spec.js b/core/test/integration/api/api_slugs_spec.js index 35c433d4f8..0c5830597f 100644 --- a/core/test/integration/api/api_slugs_spec.js +++ b/core/test/integration/api/api_slugs_spec.js @@ -3,7 +3,6 @@ var testUtils = require('../../utils'), should = require('should'), - permissions = require('../../../server/permissions'), SlugAPI = require('../../../server/api/slugs'); describe('Slug API', function () { @@ -11,15 +10,7 @@ describe('Slug API', function () { before(testUtils.teardown); afterEach(testUtils.teardown); - beforeEach(function (done) { - testUtils.initData().then(function () { - return testUtils.insertDefaultFixtures(); - }).then(function () { - return permissions.init(); - }).then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('users:roles', 'perms:slug', 'perms:init')); should.exist(SlugAPI); diff --git a/core/test/integration/api/api_tags_spec.js b/core/test/integration/api/api_tags_spec.js index 004739bd4f..d52b635196 100644 --- a/core/test/integration/api/api_tags_spec.js +++ b/core/test/integration/api/api_tags_spec.js @@ -4,35 +4,18 @@ var testUtils = require('../../utils'), should = require('should'), // Stuff we are testing - permissions = require('../../../server/permissions'), TagAPI = require('../../../server/api/tags'); describe('Tags API', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return testUtils.insertDefaultFixtures(); - }).then(function () { - return testUtils.insertAdminUser(); - }).then(function () { - return testUtils.insertEditorUser(); - }).then(function () { - return testUtils.insertAuthorUser(); - }).then(function () { - return permissions.init(); - }).then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('users:roles', 'tag', 'perms:tag', 'perms:init')); should.exist(TagAPI); it('can browse (internal)', function (done) { - TagAPI.browse({context: {internal: true}}).then(function (results) { + TagAPI.browse(testUtils.context.internal).then(function (results) { should.exist(results); should.exist(results.tags); results.tags.length.should.be.above(0); @@ -56,7 +39,7 @@ describe('Tags API', function () { }); it('can browse (admin)', function (done) { - TagAPI.browse({context: {user: 2}}).then(function (results) { + TagAPI.browse(testUtils.context.admin).then(function (results) { should.exist(results); should.exist(results.tags); results.tags.length.should.be.above(0); @@ -68,7 +51,7 @@ describe('Tags API', function () { }); it('can browse (editor)', function (done) { - TagAPI.browse({context: {user: 3}}).then(function (results) { + TagAPI.browse(testUtils.context.editor).then(function (results) { should.exist(results); should.exist(results.tags); results.tags.length.should.be.above(0); @@ -80,7 +63,7 @@ describe('Tags API', function () { }); it('can browse (author)', function (done) { - TagAPI.browse({context: {user: 4}}).then(function (results) { + TagAPI.browse(testUtils.context.author).then(function (results) { should.exist(results); should.exist(results.tags); results.tags.length.should.be.above(0); diff --git a/core/test/integration/api/api_themes_spec.js b/core/test/integration/api/api_themes_spec.js index b148ef9b3c..94d0435057 100644 --- a/core/test/integration/api/api_themes_spec.js +++ b/core/test/integration/api/api_themes_spec.js @@ -8,66 +8,58 @@ var _ = require('lodash'), when = require('when'), // Stuff we are testing - permissions = require('../../../server/permissions'), SettingsAPI = require('../../../server/api/settings'), - ThemeAPI = rewire('../../../server/api/themes'); + ThemeAPI = rewire('../../../server/api/themes'), + + sandbox = sinon.sandbox.create(); + describe('Themes API', function () { - var configStub, - config, - sandbox, - settingsReadStub; + var config, + configStub; // Keep the DB clean before(testUtils.teardown); - afterEach(function (done) { - testUtils.clearData().then(function () { - sandbox.restore(); - done(); - }).catch(done); + afterEach(testUtils.teardown); + afterEach(function () { + sandbox.restore(); }); - beforeEach(function (done) { - testUtils.initData().then(function () { - return testUtils.insertDefaultFixtures(); - }).then(function () { - return SettingsAPI.updateSettingsCache(); - }).then(function () { + beforeEach(testUtils.setup('users:roles', 'perms:theme', 'perms:init')); - return permissions.init(); - }).then(function () { - sandbox = sinon.sandbox.create(); + beforeEach(function () { + // Override settings.read for activeTheme + sandbox.stub(SettingsAPI, 'read', function () { + return when({ settings: [{value: 'casper'}] }); + }); - // Override settings.read for activeTheme - settingsReadStub = sandbox.stub(SettingsAPI, 'read', function () { - return when({ settings: [{value: 'casper'}] }); - }); + sandbox.stub(SettingsAPI, 'edit', function () { + return when({ settings: [{value: 'rasper'}] }); + }); - configStub = { - 'paths': { - 'subdir': '', - 'availableThemes': { - 'casper': { - 'package.json': { name: 'Casper', version: '0.9.3' } - }, - 'rasper': { - 'package.json': { name: 'Rasper', version: '0.9.6' } - } + configStub = { + 'paths': { + 'subdir': '', + 'availableThemes': { + 'casper': { + 'package.json': { name: 'Casper', version: '0.9.3' } + }, + 'rasper': { + 'package.json': { name: 'Rasper', version: '0.9.6' } } } - }; + } + }; - config = ThemeAPI.__get__('config'); - _.extend(config, configStub); + config = ThemeAPI.__get__('config'); + _.extend(config, configStub); - done(); - }).catch(done); }); should.exist(ThemeAPI); it('can browse', function (done) { - ThemeAPI.browse({context: {user: 1}}).then(function (result) { + ThemeAPI.browse(testUtils.context.owner).then(function (result) { should.exist(result); result.themes.length.should.be.above(0); testUtils.API.checkResponse(result.themes[0], 'theme'); @@ -78,12 +70,12 @@ describe('Themes API', function () { }); it('can edit', function (done) { - ThemeAPI.edit({themes: [{uuid: 'casper', active: true }]}, {context: {user: 1}}).then(function (result) { + ThemeAPI.edit({themes: [{uuid: 'rasper', active: true }]}, testUtils.context.owner).then(function (result) { should.exist(result); should.exist(result.themes); result.themes.length.should.be.above(0); testUtils.API.checkResponse(result.themes[0], 'theme'); - result.themes[0].uuid.should.equal('casper'); + result.themes[0].uuid.should.equal('rasper'); done(); }).catch(function (error) { done(new Error(JSON.stringify(error))); diff --git a/core/test/integration/api/api_users_spec.js b/core/test/integration/api/api_users_spec.js index 440bd902dd..564c4d93b3 100644 --- a/core/test/integration/api/api_users_spec.js +++ b/core/test/integration/api/api_users_spec.js @@ -1,15 +1,18 @@ /*globals describe, before, beforeEach, afterEach, it */ -var testUtils = require('../../utils'), - should = require('should'), - - permissions = require('../../../server/permissions'), - UserModel = require('../../../server/models').User; +/*jshint expr:true*/ +var testUtils = require('../../utils'), + should = require('should'), + _ = require('lodash'), // Stuff we are testing - UsersAPI = require('../../../server/api/users'); - AuthAPI = require('../../../server/api/authentication'); + UserModel = require('../../../server/models').User, + UserAPI = require('../../../server/api/users'); describe('Users API', function () { + // Keep the DB clean + before(testUtils.teardown); + afterEach(testUtils.teardown); + beforeEach(testUtils.setup('users:roles', 'perms:user', 'perms:init')); before(function (done) { testUtils.clearData().then(function () { @@ -17,296 +20,219 @@ describe('Users API', function () { }).catch(done); }); - afterEach(function (done) { - testUtils.clearData().then(function () { + it('dateTime fields are returned as Date objects', function (done) { + var userData = testUtils.DataGenerator.forModel.users[0]; + + UserModel.check({ email: userData.email, password: userData.password }).then(function (user) { + return UserAPI.read({ id: user.id }); + }).then(function (response) { + response.users[0].created_at.should.be.an.instanceof(Date); + response.users[0].updated_at.should.be.an.instanceof(Date); + response.users[0].last_login.should.be.an.instanceof(Date); + done(); }).catch(done); }); - describe('No User', function () { - beforeEach(function (done) { - testUtils.initData().then(function () { - return permissions.init(); - }).then(function () { - done(); - }).catch(done); - }); + it('Can browse (admin)', function (done) { + UserAPI.browse(testUtils.context.admin).then(function (response) { + should.exist(response); + testUtils.API.checkResponse(response, 'users'); + should.exist(response.users); + response.users.should.have.length(4); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + testUtils.API.checkResponse(response.users[1], 'user', ['roles']); + testUtils.API.checkResponse(response.users[2], 'user', ['roles']); + testUtils.API.checkResponse(response.users[3], 'user', ['roles']); - it('can add with internal user', function (done) { - AuthAPI.setup({ setup: [{ - 'name': 'Hello World', - 'email': 'hello@world.com', - 'password': 'password' - }]}).then(function (results) { - should.exist(results); - should.not.exist(results.meta); - should.exist(results.users); - results.users.should.have.length(1); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - results.users[0].name.should.equal('Hello World'); + done(); + }).catch(done); + }); + + it('Can browse (editor)', function (done) { + UserAPI.browse(testUtils.context.editor).then(function (response) { + should.exist(response); + testUtils.API.checkResponse(response, 'users'); + should.exist(response.users); + response.users.should.have.length(4); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + testUtils.API.checkResponse(response.users[1], 'user', ['roles']); + testUtils.API.checkResponse(response.users[2], 'user', ['roles']); + testUtils.API.checkResponse(response.users[3], 'user', ['roles']); + done(); + }).catch(done); + }); + + it('Can browse (author)', function (done) { + UserAPI.browse(testUtils.context.author).then(function (response) { + should.exist(response); + testUtils.API.checkResponse(response, 'users'); + should.exist(response.users); + response.users.should.have.length(4); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + testUtils.API.checkResponse(response.users[1], 'user', ['roles']); + testUtils.API.checkResponse(response.users[2], 'user', ['roles']); + testUtils.API.checkResponse(response.users[3], 'user', ['roles']); + done(); + }).catch(done); + }); + + it('no-auth user cannot browse', function (done) { + UserAPI.browse().then(function () { + done(new Error('Browse user is not denied without authentication.')); + }, function () { + done(); + }).catch(done); + }); + + it('Can read (admin)', function (done) { + UserAPI.read(_.extend(testUtils.context.admin, {id: 1})).then(function (response) { + should.exist(response); + should.not.exist(response.meta); + should.exist(response.users); + response.users[0].id.should.eql(1); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + response.users[0].created_at.should.be.a.Date; + + done(); + }).catch(done); + }); + + it('Can read (editor)', function (done) { + UserAPI.read(_.extend(testUtils.context.editor, {id: 1})).then(function (response) { + should.exist(response); + should.not.exist(response.meta); + should.exist(response.users); + response.users[0].id.should.eql(1); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + done(); + }).catch(done); + }); + + it('Can read (author)', function (done) { + UserAPI.read(_.extend(testUtils.context.author, {id: 1})).then(function (response) { + should.exist(response); + should.not.exist(response.meta); + should.exist(response.users); + response.users[0].id.should.eql(1); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + done(); + }).catch(done); + }); + + it('no-auth can read', function (done) { + UserAPI.read({id: 1}).then(function (response) { + should.exist(response); + should.not.exist(response.meta); + should.exist(response.users); + response.users[0].id.should.eql(1); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + done(); + }).catch(done); + }); + + it('Can edit (admin)', function (done) { + UserAPI.edit( + {users: [{name: 'Joe Blogger'}]}, _.extend(testUtils.context.admin, {id: 1}) + ).then(function (response) { + should.exist(response); + should.not.exist(response.meta); + should.exist(response.users); + response.users.should.have.length(1); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + response.users[0].name.should.equal('Joe Blogger'); + response.users[0].updated_at.should.be.a.Date; done(); }).catch(done); + }); + + it('Can edit (editor)', function (done) { + UserAPI.edit( + {users: [{name: 'Joe Blogger'}]}, _.extend(testUtils.context.editor, {id: 1}) + ).then(function (response) { + should.exist(response); + should.not.exist(response.meta); + should.exist(response.users); + response.users.should.have.length(1); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + response.users[0].name.should.eql('Joe Blogger'); + + done(); + }).catch(done); + }); + + it('Can edit only self (author)', function (done) { + // Test author cannot edit admin user + UserAPI.edit( + {users: [{name: 'Joe Blogger'}]}, _.extend(testUtils.context.author, {id: 1}) + ).then(function () { + done(new Error('Author should not be able to edit account which is not their own')); + }).catch(function (error) { + error.type.should.eql('NoPermissionError'); + }).finally(function () { + // Next test that author CAN edit self + return UserAPI.edit( + {users: [{name: 'Timothy Bogendath'}]}, _.extend(testUtils.context.author, {id: 4}) + ).then(function (response) { + should.exist(response); + should.not.exist(response.meta); + should.exist(response.users); + response.users.should.have.length(1); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + response.users[0].name.should.eql('Timothy Bogendath'); + done(); + }).catch(done); }); }); - describe('With Users', function () { - beforeEach(function (done) { - testUtils.initData().then(function () { - return testUtils.insertDefaultFixtures(); - }).then(function () { - return testUtils.insertAdminUser(); - }).then(function () { - return testUtils.insertEditorUser(); - }).then(function () { - return testUtils.insertAuthorUser(); - }).then(function () { - return permissions.init(); - }).then(function () { - done(); - }).catch(done); - }); - - it('dateTime fields are returned as Date objects', function (done) { - var userData = testUtils.DataGenerator.forModel.users[0]; - - UserModel.check({ email: userData.email, password: userData.password }).then(function (user) { - return UsersAPI.read({ id: user.id }); - }).then(function (results) { - results.users[0].created_at.should.be.an.instanceof(Date); - results.users[0].updated_at.should.be.an.instanceof(Date); - results.users[0].last_login.should.be.an.instanceof(Date); - - done(); - }).catch(done); - }); - - it('can browse (owner)', function (done) { - UsersAPI.browse({context: {user: 1}}).then(function (results) { - should.exist(results); - testUtils.API.checkResponse(results, 'users'); - should.exist(results.users); - results.users.should.have.length(4); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - testUtils.API.checkResponse(results.users[1], 'user', ['roles']); - testUtils.API.checkResponse(results.users[2], 'user', ['roles']); - testUtils.API.checkResponse(results.users[3], 'user', ['roles']); - - done(); - }).catch(done); - }); - - it('can browse (admin)', function (done) { - UsersAPI.browse({context: {user: 2}}).then(function (results) { - should.exist(results); - testUtils.API.checkResponse(results, 'users'); - should.exist(results.users); - results.users.should.have.length(4); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - testUtils.API.checkResponse(results.users[1], 'user', ['roles']); - testUtils.API.checkResponse(results.users[2], 'user', ['roles']); - testUtils.API.checkResponse(results.users[3], 'user', ['roles']); - done(); - }).catch(done); - }); - - it('can browse (editor)', function (done) { - UsersAPI.browse({context: {user: 3}}).then(function (results) { - should.exist(results); - testUtils.API.checkResponse(results, 'users'); - should.exist(results.users); - results.users.should.have.length(4); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - testUtils.API.checkResponse(results.users[1], 'user', ['roles']); - testUtils.API.checkResponse(results.users[2], 'user', ['roles']); - testUtils.API.checkResponse(results.users[3], 'user', ['roles']); - done(); - }).catch(done); - }); - - it('can browse (author)', function (done) { - UsersAPI.browse({context: {user: 4}}).then(function (results) { - should.exist(results); - testUtils.API.checkResponse(results, 'users'); - should.exist(results.users); - results.users.should.have.length(4); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - testUtils.API.checkResponse(results.users[1], 'user', ['roles']); - testUtils.API.checkResponse(results.users[2], 'user', ['roles']); - testUtils.API.checkResponse(results.users[3], 'user', ['roles']); - done(); - }).catch(done); - }); - - it('no-auth user cannot browse', function (done) { - UsersAPI.browse().then(function () { - done(new Error('Browse user is not denied without authentication.')); - }, function () { - done(); - }).catch(done); - }); - - it('can read (owner)', function (done) { - UsersAPI.read({id: 1, context: {user: 1}}).then(function (results) { - should.exist(results); - should.not.exist(results.meta); - should.exist(results.users); - results.users[0].id.should.eql(1); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - - results.users[0].created_at.should.be.a.Date; - - done(); - }).catch(done); - }); - - it('can read (admin)', function (done) { - UsersAPI.read({id: 1, context: {user: 2}}).then(function (results) { - should.exist(results); - should.not.exist(results.meta); - should.exist(results.users); - results.users[0].id.should.eql(1); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - - results.users[0].created_at.should.be.a.Date; - - done(); - }).catch(done); - }); - - it('can read (editor)', function (done) { - UsersAPI.read({id: 1, context: {user: 3}}).then(function (results) { - should.exist(results); - should.not.exist(results.meta); - should.exist(results.users); - results.users[0].id.should.eql(1); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - done(); - }).catch(done); - }); - - it('can read (author)', function (done) { - UsersAPI.read({id: 1, context: {user: 4}}).then(function (results) { - should.exist(results); - should.not.exist(results.meta); - should.exist(results.users); - results.users[0].id.should.eql(1); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - done(); - }).catch(done); - }); - - it('no-auth can read', function (done) { - UsersAPI.read({id: 1}).then(function (results) { - should.exist(results); - should.not.exist(results.meta); - should.exist(results.users); - results.users[0].id.should.eql(1); - testUtils.API.checkResponse(results.users[0], 'user', ['roles']); - done(); - }).catch(done); - }); - - it('can edit (owner)', function (done) { - UsersAPI.edit({users: [{name: 'Joe Blogger'}]}, {id: 1, context: {user: 1}}).then(function (response) { - should.exist(response); - should.not.exist(response.meta); - should.exist(response.users); - response.users.should.have.length(1); - testUtils.API.checkResponse(response.users[0], 'user', ['roles']); - response.users[0].name.should.equal('Joe Blogger'); - response.users[0].updated_at.should.be.a.Date; - done(); - }).catch(done); - }); - - it('can edit (admin)', function (done) { - UsersAPI.edit({users: [{name: 'Joe Blogger'}]}, {id: 1, context: {user: 2}}).then(function (response) { - should.exist(response); - should.not.exist(response.meta); - should.exist(response.users); - response.users.should.have.length(1); - testUtils.API.checkResponse(response.users[0], 'user', ['roles']); - response.users[0].name.should.equal('Joe Blogger'); - response.users[0].updated_at.should.be.a.Date; - done(); - }).catch(done); - }); - - it('can edit (editor)', function (done) { - UsersAPI.edit({users: [{name: 'Joe Blogger'}]}, {id: 1, context: {user: 2}}).then(function (response) { - should.exist(response); - should.not.exist(response.meta); - should.exist(response.users); - response.users.should.have.length(1); - testUtils.API.checkResponse(response.users[0], 'user', ['roles']); - response.users[0].name.should.equal('Joe Blogger'); - response.users[0].updated_at.should.be.a.Date; - done(); - }).catch(done); - }); - - it('author can edit only self', function (done) { - // Test author cannot edit admin user - UsersAPI.edit({users: [{name: 'Joe Blogger'}]}, {id: 1, context: {user: 4}}).then(function () { - done(new Error('Author should not be able to edit account which is not their own')); - }).catch(function (error) { - error.type.should.eql('NoPermissionError'); - }).finally(function () { - // Next test that author CAN edit self - return UsersAPI.edit({users: [{name: 'Timothy Bogendath'}]}, {id: 4, context: {user: 4}}) - .then(function (response) { - should.exist(response); - should.not.exist(response.meta); - should.exist(response.users); - response.users.should.have.length(1); - testUtils.API.checkResponse(response.users[0], 'user', ['roles']); - response.users[0].name.should.eql('Timothy Bogendath'); - done(); - }).catch(done); - }); - }); - - it('admin can\'t transfer ownership', function (done) { - // transfer ownership to user id: 2 - UsersAPI.edit({users: [{name: 'Joe Blogger', roles:[4]}]}, {id: 3, context: {user: 2}}).then(function (response) { - done(new Error('Admin is not dienied transferring ownership.')); - }, function () { - done(); - }).catch(done); - }); - - it('editor can\'t transfer ownership', function (done) { - // transfer ownership to user id: 2 - UsersAPI.edit({users: [{name: 'Joe Blogger', roles:[4]}]}, {id: 2, context: {user: 3}}).then(function (response) { - done(new Error('Admin is not dienied transferring ownership.')); - }, function () { - done(); - }).catch(done); - }); - - it('author can\'t transfer ownership', function (done) { - // transfer ownership to user id: 2 - UsersAPI.edit({users: [{name: 'Joe Blogger', roles:[4]}]}, {id: 2, context: {user: 4}}).then(function (response) { - done(new Error('Admin is not dienied transferring ownership.')); - }, function () { - done(); - }).catch(done); - }); - - it('owner can transfer ownership', function (done) { - // transfer ownership to user id: 2 - UsersAPI.edit({users: [{name: 'Joe Blogger', roles:[4]}]}, {id: 2, context: {user: 1}}).then(function (response) { - should.exist(response); - should.not.exist(response.meta); - should.exist(response.users); - response.users.should.have.length(1); - testUtils.API.checkResponse(response.users[0], 'user', ['roles']); - response.users[0].name.should.equal('Joe Blogger'); - response.users[0].id.should.equal(2); - response.users[0].roles[0].should.equal(4); - response.users[0].updated_at.should.be.a.Date; - done(); - }).catch(done); - }); + it('can\'t transfer ownership (admin)', function (done) { + // transfer ownership to user id: 2 + UserAPI.edit( + {users: [{name: 'Joe Blogger', roles:[4]}]}, _.extend(testUtils.context.admin, {id: 2}) + ).then(function () { + done(new Error('Admin is not dienied transferring ownership.')); + }, function () { + done(); + }).catch(done); }); -}); + + it('can\'t transfer ownership (editor)', function (done) { + // transfer ownership to user id: 2 + UserAPI.edit( + {users: [{name: 'Joe Blogger', roles:[4]}]}, _.extend(testUtils.context.editor, {id: 2}) + ).then(function () { + done(new Error('Admin is not dienied transferring ownership.')); + }, function () { + done(); + }).catch(done); + }); + + it('can\'t transfer ownership (author)', function (done) { + // transfer ownership to user id: 2 + UserAPI.edit( + {users: [{name: 'Joe Blogger', roles:[4]}]}, _.extend(testUtils.context.author, {id: 2}) + ).then(function () { + done(new Error('Admin is not dienied transferring ownership.')); + }, function () { + done(); + }).catch(done); + }); + + it('can transfer ownership (owner)', function (done) { + // transfer ownership to user id: 2 + UserAPI.edit( + {users: [{name: 'Joe Blogger', roles:[4]}]}, _.extend(testUtils.context.owner, {id: 2}) + ).then(function (response) { + should.exist(response); + should.not.exist(response.meta); + should.exist(response.users); + response.users.should.have.length(1); + testUtils.API.checkResponse(response.users[0], 'user', ['roles']); + response.users[0].name.should.equal('Joe Blogger'); + response.users[0].id.should.equal(2); + response.users[0].roles[0].should.equal(4); + response.users[0].updated_at.should.be.a.Date; + done(); + }).catch(done); + }); +}); \ No newline at end of file diff --git a/core/test/unit/export_spec.js b/core/test/integration/export_spec.js similarity index 70% rename from core/test/unit/export_spec.js rename to core/test/integration/export_spec.js index 2d295342e6..54824a93d2 100644 --- a/core/test/unit/export_spec.js +++ b/core/test/integration/export_spec.js @@ -1,40 +1,26 @@ /*globals describe, before, beforeEach, afterEach, it*/ /*jshint expr:true*/ -var testUtils = require('../utils'), +var testUtils = require('../utils/index'), should = require('should'), sinon = require('sinon'), when = require('when'), _ = require('lodash'), // Stuff we are testing - versioning = require('../../server/data/versioning'), - exporter = require('../../server/data/export'); + versioning = require('../../server/data/versioning/index'), + exporter = require('../../server/data/export/index'), + sandbox = sinon.sandbox.create(); describe('Exporter', function () { - should.exist(exporter); - - var sandbox; - - before(function (done) { - testUtils.clearData().then(function () { - done(); - }).catch(done); - }); - - beforeEach(function (done) { - sandbox = sinon.sandbox.create(); - testUtils.initData().then(function () { - done(); - }).catch(done); - }); - - afterEach(function (done) { + before(testUtils.teardown); + afterEach(testUtils.teardown); + afterEach(function () { sandbox.restore(); - testUtils.clearData().then(function () { - done(); - }).catch(done); }); + beforeEach(testUtils.setup('default')); + + should.exist(exporter); it('exports data', function (done) { // Stub migrations to return 000 as the current database version diff --git a/core/test/unit/import_spec.js b/core/test/integration/import_spec.js similarity index 71% rename from core/test/unit/import_spec.js rename to core/test/integration/import_spec.js index 0395567348..a398881761 100644 --- a/core/test/unit/import_spec.js +++ b/core/test/integration/import_spec.js @@ -1,122 +1,115 @@ -/*globals describe, beforeEach, afterEach, it*/ +/*globals describe, before, beforeEach, afterEach, it*/ /*jshint expr:true*/ -var testUtils = require('../utils'), - should = require('should'), - sinon = require('sinon'), - when = require('when'), - assert = require('assert'), - _ = require('lodash'), - rewire = require('rewire'), +var testUtils = require('../utils/index'), + should = require('should'), + sinon = require('sinon'), + when = require('when'), + assert = require('assert'), + _ = require('lodash'), + rewire = require('rewire'), // Stuff we are testing - config = rewire('../../server/config'), - configUpdate = config.__get__('updateConfig'), - defaultConfig = rewire('../../../config.example')[process.env.NODE_ENV], - migration = rewire('../../server/data/migration'), - versioning = require('../../server/data/versioning'), - exporter = require('../../server/data/export'), - importer = require('../../server/data/import'), - Importer000 = require('../../server/data/import/000'), - Importer001 = require('../../server/data/import/001'), - Importer002 = require('../../server/data/import/002'), - Importer003 = require('../../server/data/import/003'); + config = rewire('../../server/config'), + configUpdate = config.__get__('updateConfig'), + defaultConfig = rewire('../../../config.example')[process.env.NODE_ENV], + migration = rewire('../../server/data/migration'), + versioning = require('../../server/data/versioning'), + exporter = require('../../server/data/export'), + importer = require('../../server/data/import'), + Importer000 = require('../../server/data/import/000'), + Importer001 = require('../../server/data/import/001'), + Importer002 = require('../../server/data/import/002'), + Importer003 = require('../../server/data/import/003'), + + knex, + sandbox = sinon.sandbox.create(); describe('Import', function () { - - should.exist(exporter); - should.exist(importer); - - var sandbox, knex; - - beforeEach(function (done) { - var newConfig = _.extend(config, defaultConfig); - migration.__get__('config', newConfig); - configUpdate(newConfig); - knex = config.database.knex; - - sandbox = sinon.sandbox.create(); - // clear database... we need to initialise it manually for each test - testUtils.clearData().then(function () { - done(); - }).catch(done); - }); - + before(testUtils.teardown); + afterEach(testUtils.teardown); afterEach(function () { sandbox.restore(); }); - it('resolves 000', function (done) { - var importStub = sandbox.stub(Importer000, 'importData', function () { - return when.resolve(); - }), - fakeData = { test: true }; + should.exist(exporter); + should.exist(importer); - importer('000', fakeData).then(function () { - importStub.calledWith(fakeData).should.equal(true); + describe('Resolves', function () { - importStub.restore(); + beforeEach(testUtils.setup()); + beforeEach(function () { + var newConfig = _.extend(config, defaultConfig); + migration.__get__('config', newConfig); + configUpdate(newConfig); + knex = config.database.knex; + }); - done(); - }).catch(done); - }); + it('resolves 000', function (done) { + var importStub = sandbox.stub(Importer000, 'importData', function () { + return when.resolve(); + }), + fakeData = { test: true }; - it('resolves 001', function (done) { - var importStub = sandbox.stub(Importer001, 'importData', function () { - return when.resolve(); - }), - fakeData = { test: true }; + importer('000', fakeData).then(function () { + importStub.calledWith(fakeData).should.equal(true); - importer('001', fakeData).then(function () { - importStub.calledWith(fakeData).should.equal(true); + importStub.restore(); - importStub.restore(); - - done(); - }).catch(done); - }); - - it('resolves 002', function (done) { - var importStub = sandbox.stub(Importer002, 'importData', function () { - return when.resolve(); - }), - fakeData = { test: true }; - - importer('002', fakeData).then(function () { - importStub.calledWith(fakeData).should.equal(true); - - importStub.restore(); - - done(); - }).catch(done); - }); - - it('resolves 003', function (done) { - var importStub = sandbox.stub(Importer003, 'importData', function () { - return when.resolve(); - }), - fakeData = { test: true }; - - importer('003', fakeData).then(function () { - importStub.calledWith(fakeData).should.equal(true); - - importStub.restore(); - - done(); - }).catch(done); - }); - - describe('000', function () { - should.exist(Importer000); - - beforeEach(function (done) { - // migrate to current version - migration.migrateUpFreshDb().then(function () { - return testUtils.insertDefaultUser(); - }).then(function () { done(); }).catch(done); }); + it('resolves 001', function (done) { + var importStub = sandbox.stub(Importer001, 'importData', function () { + return when.resolve(); + }), + fakeData = { test: true }; + + importer('001', fakeData).then(function () { + importStub.calledWith(fakeData).should.equal(true); + + importStub.restore(); + + done(); + }).catch(done); + }); + + it('resolves 002', function (done) { + var importStub = sandbox.stub(Importer002, 'importData', function () { + return when.resolve(); + }), + fakeData = { test: true }; + + importer('002', fakeData).then(function () { + importStub.calledWith(fakeData).should.equal(true); + + importStub.restore(); + + done(); + }).catch(done); + }); + + it('resolves 003', function (done) { + var importStub = sandbox.stub(Importer003, 'importData', function () { + return when.resolve(); + }), + fakeData = { test: true }; + + importer('003', fakeData).then(function () { + importStub.calledWith(fakeData).should.equal(true); + + importStub.restore(); + + done(); + }).catch(done); + }); + }); + + describe('000', function () { + + beforeEach(testUtils.setup('owner', 'settings')); + + should.exist(Importer000); it('imports data from 000', function (done) { var exportData, @@ -124,7 +117,7 @@ describe('Import', function () { return when.resolve('000'); }); - testUtils.loadExportFixture('export-000').then(function (exported) { + testUtils.fixtures.loadExportFixture('export-000').then(function (exported) { exportData = exported; return importer('000', exportData); @@ -146,10 +139,10 @@ describe('Import', function () { settings = importedData[2], tags = importedData[3]; - // we always have 1 user, the default user we added + // we always have 1 user, the owner user we added users.length.should.equal(1, 'There should only be one user'); // import no longer requires all data to be dropped, and adds posts - posts.length.should.equal(exportData.data.posts.length + 1, 'Wrong number of posts'); + posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); // test settings settings.length.should.be.above(0, 'Wrong number of settings'); @@ -166,22 +159,16 @@ describe('Import', function () { }); describe('001', function () { - should.exist(Importer001); - beforeEach(function (done) { - // migrate to current version - migration.migrateUpFreshDb().then(function () { - return testUtils.insertDefaultUser(); - }).then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('owner', 'settings')); + + should.exist(Importer001); it('safely imports data from 001', function (done) { var exportData, timestamp = 1349928000000; - testUtils.loadExportFixture('export-001').then(function (exported) { + testUtils.fixtures.loadExportFixture('export-001').then(function (exported) { exportData = exported; // Modify timestamp data for testing @@ -221,7 +208,7 @@ describe('Import', function () { users[0].bio.should.equal(exportData.data.users[0].bio); // import no longer requires all data to be dropped, and adds posts - posts.length.should.equal(exportData.data.posts.length + 1, 'Wrong number of posts'); + posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); // test settings settings.length.should.be.above(0, 'Wrong number of settings'); @@ -241,10 +228,10 @@ describe('Import', function () { // When in sqlite we are returned a unix timestamp number, // in MySQL we're returned a date object. // We pass the returned post always through the date object - // to ensure the return is consistant for all DBs. - assert.equal(new Date(posts[1].created_at).getTime(), timestamp); - assert.equal(new Date(posts[1].updated_at).getTime(), timestamp); - assert.equal(new Date(posts[1].published_at).getTime(), timestamp); + // to ensure the return is consistent for all DBs. + assert.equal(new Date(posts[0].created_at).getTime(), timestamp); + assert.equal(new Date(posts[0].updated_at).getTime(), timestamp); + assert.equal(new Date(posts[0].published_at).getTime(), timestamp); done(); }).catch(done); @@ -253,8 +240,7 @@ describe('Import', function () { it('doesn\'t import invalid post data from 001', function (done) { var exportData; - - testUtils.loadExportFixture('export-001').then(function (exported) { + testUtils.fixtures.loadExportFixture('export-001').then(function (exported) { exportData = exported; //change title to 151 characters @@ -285,15 +271,16 @@ describe('Import', function () { // we always have 1 user, the default user we added users.length.should.equal(1, 'There should only be one user'); - // import no longer requires all data to be dropped, and adds posts - posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); + + // Nothing should have been imported + posts.length.should.equal(0, 'Wrong number of posts'); + tags.length.should.equal(0, 'no new tags'); // test settings settings.length.should.be.above(0, 'Wrong number of settings'); _.findWhere(settings, {key: 'databaseVersion'}).value.should.equal('003', 'Wrong database version'); - // test tags - tags.length.should.equal(exportData.data.tags.length, 'no new tags'); + done(); }); @@ -304,7 +291,7 @@ describe('Import', function () { it('doesn\'t import invalid settings data from 001', function (done) { var exportData; - testUtils.loadExportFixture('export-001').then(function (exported) { + testUtils.fixtures.loadExportFixture('export-001').then(function (exported) { exportData = exported; //change to blank settings key exportData.data.settings[3].key = null; @@ -333,16 +320,15 @@ describe('Import', function () { // we always have 1 user, the default user we added users.length.should.equal(1, 'There should only be one user'); - // import no longer requires all data to be dropped, and adds posts - posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); + + // Nothing should have been imported + posts.length.should.equal(0, 'Wrong number of posts'); + tags.length.should.equal(0, 'no new tags'); // test settings settings.length.should.be.above(0, 'Wrong number of settings'); _.findWhere(settings, {key: 'databaseVersion'}).value.should.equal('003', 'Wrong database version'); - // test tags - tags.length.should.equal(exportData.data.tags.length, 'no new tags'); - done(); }); @@ -351,22 +337,16 @@ describe('Import', function () { }); describe('002', function () { - should.exist(Importer002); - beforeEach(function (done) { - // migrate to current version - migration.migrateUpFreshDb().then(function () { - return testUtils.insertDefaultUser(); - }).then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('owner', 'settings')); + + should.exist(Importer002); it('safely imports data from 002', function (done) { var exportData, timestamp = 1349928000000; - testUtils.loadExportFixture('export-002').then(function (exported) { + testUtils.fixtures.loadExportFixture('export-002').then(function (exported) { exportData = exported; // Modify timestamp data for testing @@ -394,7 +374,7 @@ describe('Import', function () { tags = importedData[3], exportEmail; - // we always have 1 user, the default user we added + // we always have 1 user, the owner user we added users.length.should.equal(1, 'There should only be one user'); // user should still have the credentials from the original insert, not the import @@ -406,7 +386,7 @@ describe('Import', function () { users[0].bio.should.equal(exportData.data.users[0].bio); // import no longer requires all data to be dropped, and adds posts - posts.length.should.equal(exportData.data.posts.length + 1, 'Wrong number of posts'); + posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); // test settings settings.length.should.be.above(0, 'Wrong number of settings'); @@ -427,9 +407,9 @@ describe('Import', function () { // in MySQL we're returned a date object. // We pass the returned post always through the date object // to ensure the return is consistant for all DBs. - assert.equal(new Date(posts[1].created_at).getTime(), timestamp); - assert.equal(new Date(posts[1].updated_at).getTime(), timestamp); - assert.equal(new Date(posts[1].published_at).getTime(), timestamp); + assert.equal(new Date(posts[0].created_at).getTime(), timestamp); + assert.equal(new Date(posts[0].updated_at).getTime(), timestamp); + assert.equal(new Date(posts[0].published_at).getTime(), timestamp); done(); }).catch(function (error) { @@ -441,7 +421,7 @@ describe('Import', function () { var exportData; - testUtils.loadExportFixture('export-002').then(function (exported) { + testUtils.fixtures.loadExportFixture('export-002').then(function (exported) { exportData = exported; //change title to 151 characters @@ -470,18 +450,16 @@ describe('Import', function () { settings = importedData[2], tags = importedData[3]; - // we always have 1 user, the default user we added + // we always have 1 user, the owner user we added users.length.should.equal(1, 'There should only be one user'); - // import no longer requires all data to be dropped, and adds posts - posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); + // Nothing should have been imported + posts.length.should.equal(0, 'Wrong number of posts'); + tags.length.should.equal(0, 'no new tags'); // test settings settings.length.should.be.above(0, 'Wrong number of settings'); _.findWhere(settings, {key: 'databaseVersion'}).value.should.equal('003', 'Wrong database version'); - // test tags - tags.length.should.equal(exportData.data.tags.length, 'no new tags'); - done(); }); @@ -491,7 +469,7 @@ describe('Import', function () { it('doesn\'t import invalid settings data from 002', function (done) { var exportData; - testUtils.loadExportFixture('export-002').then(function (exported) { + testUtils.fixtures.loadExportFixture('export-002').then(function (exported) { exportData = exported; //change to blank settings key exportData.data.settings[3].key = null; @@ -518,18 +496,16 @@ describe('Import', function () { settings = importedData[2], tags = importedData[3]; - // we always have 1 user, the default user we added + // we always have 1 user, the owner user we added users.length.should.equal(1, 'There should only be one user'); - // import no longer requires all data to be dropped, and adds posts - posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts'); + // Nothing should have been imported + posts.length.should.equal(0, 'Wrong number of posts'); + tags.length.should.equal(0, 'no new tags'); // test settings settings.length.should.be.above(0, 'Wrong number of settings'); _.findWhere(settings, {key: 'databaseVersion'}).value.should.equal('003', 'Wrong database version'); - // test tags - tags.length.should.equal(exportData.data.tags.length, 'no new tags'); - done(); }); @@ -538,21 +514,15 @@ describe('Import', function () { }); describe('003', function () { - should.exist(Importer003); - beforeEach(function (done) { - // migrate to current version - migration.migrateUpFreshDb().then(function () { - return testUtils.insertDefaultUser(); - }).then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('owner', 'settings')); + + should.exist(Importer003); it('safely imports data from 003', function (done) { var exportData; - testUtils.loadExportFixture('export-003').then(function (exported) { + testUtils.fixtures.loadExportFixture('export-003').then(function (exported) { exportData = exported; return importer('003', exportData); }).then(function () { diff --git a/core/test/integration/model/model_app_fields_spec.js b/core/test/integration/model/model_app_fields_spec.js index 94162e4ed3..b49cd87923 100644 --- a/core/test/integration/model/model_app_fields_spec.js +++ b/core/test/integration/model/model_app_fields_spec.js @@ -5,22 +5,13 @@ var testUtils = require('../../utils'), // Stuff we are testing AppFieldsModel = require('../../../server/models').AppField, - context = {context: {user: 1}}; + context = testUtils.context.admin; describe('App Fields Model', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return testUtils.insertApps(); - }) - .then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('app_field')); should.exist(AppFieldsModel); diff --git a/core/test/integration/model/model_app_settings_spec.js b/core/test/integration/model/model_app_settings_spec.js index c9d7ab18d5..75d5b12d72 100644 --- a/core/test/integration/model/model_app_settings_spec.js +++ b/core/test/integration/model/model_app_settings_spec.js @@ -5,22 +5,13 @@ var testUtils = require('../../utils'), // Stuff we are testing AppSettingModel = require('../../../server/models').AppSetting, - context = {context: {user: 1}}; + context = testUtils.context.admin; describe('App Setting Model', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return testUtils.insertAppWithSettings(); - }) - .then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('app_setting')); should.exist(AppSettingModel); diff --git a/core/test/integration/model/model_apps_spec.js b/core/test/integration/model/model_apps_spec.js index 6cbb2777a9..fdcbb03a28 100644 --- a/core/test/integration/model/model_apps_spec.js +++ b/core/test/integration/model/model_apps_spec.js @@ -1,29 +1,19 @@ /*globals describe, before, beforeEach, afterEach, it*/ /*jshint expr:true*/ -var testUtils = require('../../utils'), - should = require('should'), - sequence = require('when/sequence'), - _ = require('lodash'), +var testUtils = require('../../utils'), + should = require('should'), + sequence = require('when/sequence'), + _ = require('lodash'), // Stuff we are testing - Models = require('../../../server/models'), - context = {context: {user: 1}}, - AppModel = Models.App; + AppModel = require('../../../server/models').App, + context = testUtils.context.admin; describe('App Model', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return testUtils.insertDefaultApp(); - }) - .then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('app')); should.exist(AppModel); diff --git a/core/test/integration/model/model_permissions_spec.js b/core/test/integration/model/model_permissions_spec.js index d353fa36a1..ddc5427be0 100644 --- a/core/test/integration/model/model_permissions_spec.js +++ b/core/test/integration/model/model_permissions_spec.js @@ -5,18 +5,13 @@ var testUtils = require('../../utils'), // Stuff we are testing PermissionModel = require('../../../server/models').Permission, - context = {context: {user: 1}}; + context = testUtils.context.admin; describe('Permission Model', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData().then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('permission')); should.exist(PermissionModel); @@ -88,4 +83,93 @@ describe('Permission Model', function () { done(); }).catch(done); }); + + +// it('can add user to role', function (done) { +// var existingUserRoles; +// +// Models.User.findOne({id: 1}, { withRelated: ['roles'] }).then(function (foundUser) { +// var testRole = new Models.Role({ +// name: 'testrole1', +// description: 'testrole1 description' +// }); +// +// should.exist(foundUser); +// +// should.exist(foundUser.roles()); +// +// existingUserRoles = foundUser.related('roles').length; +// +// return testRole.save(null, context).then(function () { +// return foundUser.roles().attach(testRole); +// }); +// }).then(function () { +// return Models.User.findOne({id: 1}, { withRelated: ['roles'] }); +// }).then(function (updatedUser) { +// should.exist(updatedUser); +// +// updatedUser.related('roles').length.should.equal(existingUserRoles + 1); +// +// done(); +// }).catch(done); +// }); +// +// it('can add user permissions', function (done) { +// Models.User.findOne({id: 1}, { withRelated: ['permissions']}).then(function (testUser) { +// var testPermission = new Models.Permission({ +// name: 'test edit posts', +// action_type: 'edit', +// object_type: 'post' +// }); +// +// testUser.related('permissions').length.should.equal(0); +// +// return testPermission.save(null, context).then(function () { +// return testUser.permissions().attach(testPermission); +// }); +// }).then(function () { +// return Models.User.findOne({id: 1}, { include: ['permissions']}); +// }).then(function (updatedUser) { +// should.exist(updatedUser); +// +// updatedUser.related('permissions').length.should.equal(1); +// +// done(); +// }).catch(done); +// }); +// +// it('can add role permissions', function (done) { +// var testRole = new Models.Role({ +// name: 'test2', +// description: 'test2 description' +// }); +// +// testRole.save(null, context) +// .then(function () { +// return testRole.load('permissions'); +// }) +// .then(function () { +// var rolePermission = new Models.Permission({ +// name: 'test edit posts', +// action_type: 'edit', +// object_type: 'post' +// }); +// +// testRole.related('permissions').length.should.equal(0); +// +// return rolePermission.save(null, context).then(function () { +// return testRole.permissions().attach(rolePermission); +// }); +// }) +// .then(function () { +// return Models.Role.findOne({id: testRole.id}, { withRelated: ['permissions']}); +// }) +// .then(function (updatedRole) { +// should.exist(updatedRole); +// +// updatedRole.related('permissions').length.should.equal(1); +// +// done(); +// }).catch(done); +// }); }); diff --git a/core/test/integration/model/model_posts_spec.js b/core/test/integration/model/model_posts_spec.js index 6ed8cd59f7..314842755d 100644 --- a/core/test/integration/model/model_posts_spec.js +++ b/core/test/integration/model/model_posts_spec.js @@ -8,22 +8,13 @@ var testUtils = require('../../utils'), // Stuff we are testing PostModel = require('../../../server/models').Post, DataGenerator = testUtils.DataGenerator, - context = {context: {user: 1}}; + context = testUtils.context.owner; describe('Post Model', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return testUtils.insertDefaultFixtures(); - }) - .then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('owner', 'posts', 'apps')); should.exist(PostModel); @@ -41,7 +32,7 @@ describe('Post Model', function () { firstPost.created_by.name.should.equal(DataGenerator.Content.users[0].name); firstPost.updated_by.name.should.equal(DataGenerator.Content.users[0].name); firstPost.published_by.name.should.equal(DataGenerator.Content.users[0].name); - firstPost.tags[0].name.should.equal('Getting Started'); + firstPost.tags[0].name.should.equal(DataGenerator.Content.tags[0].name); } it('can findAll', function (done) { @@ -61,7 +52,6 @@ describe('Post Model', function () { should.exist(results); results.length.should.be.above(0); firstPost = results.models[0].toJSON(); - checkFirstPostData(firstPost); done(); @@ -75,7 +65,7 @@ describe('Post Model', function () { results.meta.pagination.page.should.equal(1); results.meta.pagination.limit.should.equal(15); results.meta.pagination.pages.should.equal(1); - results.posts.length.should.equal(5); + results.posts.length.should.equal(4); done(); }).catch(done); @@ -91,7 +81,7 @@ describe('Post Model', function () { results.meta.pagination.page.should.equal(1); results.meta.pagination.limit.should.equal(15); results.meta.pagination.pages.should.equal(1); - results.posts.length.should.equal(5); + results.posts.length.should.equal(4); firstPost = results.posts[0]; @@ -371,7 +361,7 @@ describe('Post Model', function () { should.exist(results); post = results.toJSON(); post.id.should.equal(firstItemData.id); - post.tags.should.have.length(1); + post.tags.should.have.length(2); post.tags[0].should.equal(firstItemData.id); // Destroy the post @@ -392,9 +382,9 @@ describe('Post Model', function () { }); it('can findPage, with various options', function (done) { - testUtils.insertMorePosts().then(function () { + testUtils.fixtures.insertMorePosts().then(function () { - return testUtils.insertMorePostsTags(); + return testUtils.fixtures.insertMorePostsTags(); }).then(function () { return PostModel.findPage({page: 2}); }).then(function (paginationResult) { @@ -441,9 +431,9 @@ describe('Post Model', function () { }).catch(done); }); it('can findPage for tag, with various options', function (done) { - testUtils.insertMorePosts().then(function () { + testUtils.fixtures.insertMorePosts().then(function () { - return testUtils.insertMorePostsTags(); + return testUtils.fixtures.insertMorePostsTags(); }).then(function () { // Test tag filter return PostModel.findPage({page: 1, tag: 'bacon'}); @@ -480,7 +470,7 @@ describe('Post Model', function () { paginationResult.meta.pagination.pages.should.equal(2); paginationResult.meta.filters.tags[0].name.should.equal('injection'); paginationResult.meta.filters.tags[0].slug.should.equal('injection'); - paginationResult.posts.length.should.equal(11); + paginationResult.posts.length.should.equal(10); done(); }).catch(done); diff --git a/core/test/integration/model/model_roles_spec.js b/core/test/integration/model/model_roles_spec.js index 8f6704b448..b9579a0488 100644 --- a/core/test/integration/model/model_roles_spec.js +++ b/core/test/integration/model/model_roles_spec.js @@ -5,18 +5,14 @@ var testUtils = require('../../utils'), // Stuff we are testing RoleModel = require('../../../server/models').Role, - context = {context: {user: 1}}; + context = testUtils.context.admin; describe('Role Model', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - beforeEach(function (done) { - testUtils.initData().then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('role')); should.exist(RoleModel); diff --git a/core/test/integration/model/model_settings_spec.js b/core/test/integration/model/model_settings_spec.js index c58fcf6277..4bfaa540ec 100644 --- a/core/test/integration/model/model_settings_spec.js +++ b/core/test/integration/model/model_settings_spec.js @@ -6,18 +6,13 @@ var testUtils = require('../../utils'), // Stuff we are testing SettingsModel = require('../../../server/models').Settings, config = require('../../../server/config'), - context = {context: {user: 1}}; + context = testUtils.context.admin; describe('Settings Model', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData().then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('settings')); should.exist(SettingsModel); diff --git a/core/test/integration/model/model_tags_spec.js b/core/test/integration/model/model_tags_spec.js index 43dea23828..2d85582731 100644 --- a/core/test/integration/model/model_tags_spec.js +++ b/core/test/integration/model/model_tags_spec.js @@ -9,19 +9,13 @@ var testUtils = require('../../utils'), Models = require('../../../server/models'), TagModel = Models.Tag, PostModel = Models.Post, - context = {context: {user: 1}}; + context = testUtils.context.admin; describe('Tag Model', function () { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup()); should.exist(TagModel); @@ -141,7 +135,7 @@ describe('Tag Model', function () { return TagModel.findAll(); }).then(function (tagsFromDB) { - tagsFromDB.length.should.eql(seededTagNames.length + 1); + tagsFromDB.length.should.eql(seededTagNames.length); done(); }).catch(done); @@ -198,7 +192,7 @@ describe('Tag Model', function () { // make sure it hasn't just added a new tag with the same name // Don't expect a certain order in results - check for number of items! - Math.max.apply(Math, tagIds).should.eql(4); + Math.max.apply(Math, tagIds).should.eql(3); done(); }).catch(done); @@ -284,7 +278,7 @@ describe('Tag Model', function () { // make sure it hasn't just added a new tag with the same name // Don't expect a certain order in results - check for number of items! - Math.max.apply(Math, tagIds).should.eql(4); + Math.max.apply(Math, tagIds).should.eql(3); done(); }).catch(done); @@ -323,7 +317,7 @@ describe('Tag Model', function () { // make sure it hasn't just added a new tag with the same name // Don't expect a certain order in results - check for number of items! - Math.max.apply(Math, tagIds).should.eql(5); + Math.max.apply(Math, tagIds).should.eql(4); done(); }).catch(done); diff --git a/core/test/integration/model/model_users_spec.js b/core/test/integration/model/model_users_spec.js index 803bdf57b4..d65320e35f 100644 --- a/core/test/integration/model/model_users_spec.js +++ b/core/test/integration/model/model_users_spec.js @@ -8,60 +8,62 @@ var testUtils = require('../../utils'), // Stuff we are testing UserModel = require('../../../server/models').User, - context = {context: {user: 1}}; + context = testUtils.context.admin, + sandbox = sinon.sandbox.create(); describe('User Model', function run() { // Keep the DB clean before(testUtils.teardown); afterEach(testUtils.teardown); + afterEach(function () { + sandbox.restore(); + }); should.exist(UserModel); describe('Registration', function runRegistration() { - beforeEach(function (done) { - testUtils.initData().then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup()); it('can add first', function (done) { - var userData = testUtils.DataGenerator.forModel.users[0], - gravatarStub = sinon.stub(UserModel, 'gravatarLookup', function (userData) { - return when.resolve(userData); - }); + var userData = testUtils.DataGenerator.forModel.users[0]; + + sandbox.stub(UserModel, 'gravatarLookup', function (userData) { + return when.resolve(userData); + }); UserModel.add(userData, context).then(function (createdUser) { should.exist(createdUser); createdUser.has('uuid').should.equal(true); createdUser.attributes.password.should.not.equal(userData.password, 'password was hashed'); createdUser.attributes.email.should.eql(userData.email, 'email address correct'); - gravatarStub.restore(); + done(); }).catch(done); }); it('does NOT lowercase email', function (done) { - var userData = testUtils.DataGenerator.forModel.users[2], - gravatarStub = sinon.stub(UserModel, 'gravatarLookup', function (userData) { - return when.resolve(userData); - }); + var userData = testUtils.DataGenerator.forModel.users[2]; + + sandbox.stub(UserModel, 'gravatarLookup', function (userData) { + return when.resolve(userData); + }); UserModel.add(userData, context).then(function (createdUser) { should.exist(createdUser); createdUser.has('uuid').should.equal(true); createdUser.attributes.email.should.eql(userData.email, 'email address correct'); - gravatarStub.restore(); done(); }).catch(done); }); it('can find gravatar', function (done) { - var userData = testUtils.DataGenerator.forModel.users[4], - gravatarStub = sinon.stub(UserModel, 'gravatarLookup', function (userData) { - userData.image = 'http://www.gravatar.com/avatar/2fab21a4c4ed88e76add10650c73bae1?d=404'; - return when.resolve(userData); - }); + var userData = testUtils.DataGenerator.forModel.users[4]; + + sandbox.stub(UserModel, 'gravatarLookup', function (userData) { + userData.image = 'http://www.gravatar.com/avatar/2fab21a4c4ed88e76add10650c73bae1?d=404'; + return when.resolve(userData); + }); UserModel.add(userData, context).then(function (createdUser) { should.exist(createdUser); @@ -69,22 +71,21 @@ describe('User Model', function run() { createdUser.attributes.image.should.eql( 'http://www.gravatar.com/avatar/2fab21a4c4ed88e76add10650c73bae1?d=404', 'Gravatar found' ); - gravatarStub.restore(); done(); }).catch(done); }); it('can handle no gravatar', function (done) { - var userData = testUtils.DataGenerator.forModel.users[0], - gravatarStub = sinon.stub(UserModel, 'gravatarLookup', function (userData) { - return when.resolve(userData); - }); + var userData = testUtils.DataGenerator.forModel.users[0]; + + sandbox.stub(UserModel, 'gravatarLookup', function (userData) { + return when.resolve(userData); + }); UserModel.add(userData, context).then(function (createdUser) { should.exist(createdUser); createdUser.has('uuid').should.equal(true); should.not.exist(createdUser.image); - gravatarStub.restore(); done(); }).catch(done); }); @@ -124,16 +125,7 @@ describe('User Model', function run() { }); describe('Basic Operations', function () { - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return when(testUtils.insertDefaultUser()); - }) - .then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('owner')); it('sets last login time on successful login', function (done) { var userData = testUtils.DataGenerator.forModel.users[0]; @@ -246,16 +238,7 @@ describe('User Model', function run() { }); describe('Password Reset', function () { - - beforeEach(function (done) { - testUtils.initData() - .then(function () { - return when(testUtils.insertDefaultUser()); - }) - .then(function () { - done(); - }).catch(done); - }); + beforeEach(testUtils.setup('owner')); it('can generate reset token', function (done) { // Expires in one minute diff --git a/core/test/integration/update_check_spec.js b/core/test/integration/update_check_spec.js index 14c40b971d..e92d18b53a 100644 --- a/core/test/integration/update_check_spec.js +++ b/core/test/integration/update_check_spec.js @@ -1,14 +1,16 @@ -/*globals describe, before, beforeEach, afterEach, after, it */ -var should = require('should'), - rewire = require('rewire'), - _ = require('lodash'), - packageInfo = require('../../../package'), - ghost = require('../../../core'), - config = rewire('../../../core/server/config'), - defaultConfig = require('../../../config.example')[process.env.NODE_ENV], - permissions = require('../../server/permissions'), - testUtils = require('../utils'), - updateCheck = rewire('../../server/update-check'); +/*globals describe, before, beforeEach, afterEach, after, it*/ +/*jshint expr:true*/ +var testUtils = require('../utils'), + should = require('should'), + rewire = require('rewire'), + _ = require('lodash'), + + // Stuff we are testing + packageInfo = require('../../../package'), + ghost = require('../../../core'), + config = rewire('../../../core/server/config'), + defaultConfig = require('../../../config.example')[process.env.NODE_ENV], + updateCheck = rewire('../../server/update-check'); describe('Update Check', function () { var environmentsOrig; @@ -33,22 +35,7 @@ describe('Update Check', function () { updateCheck.__set__('allowedCheckEnvironments', environmentsOrig); }); - beforeEach(function (done) { - testUtils.initData().then(function () { - return testUtils.insertDefaultFixtures(); - }).then(function () { - return testUtils.insertEditorUser(); - }).then(function () { - return testUtils.insertAuthorUser(); - }).then(function () { - return permissions.init(); - }).then(function () { - done(); - }).catch(function (err) { - console.log('Update Check beforeEach error', err); - throw new Error(err); - }); - }); + beforeEach(testUtils.setup('owner', 'posts')); afterEach(testUtils.teardown); diff --git a/core/test/unit/permissions_spec.js b/core/test/unit/permissions_spec.js index fabaf43fe5..779e6ba577 100644 --- a/core/test/unit/permissions_spec.js +++ b/core/test/unit/permissions_spec.js @@ -1,442 +1,284 @@ /*globals describe, before, beforeEach, afterEach, after, it*/ /*jshint expr:true*/ -var testUtils = require('../utils'), - should = require('should'), - sinon = require('sinon'), - when = require('when'), - _ = require('lodash'), - Models = require('../../server/models'), +var testUtils = require('../utils'), + should = require('should'), + sinon = require('sinon'), + when = require('when'), + _ = require('lodash'), // Stuff we are testing - permissions = require('../../server/permissions'), - effectivePerms = require('../../server/permissions/effective'), - context = {context: {user: 1}}; + ModelPermission = require('../../server/models').Permission, + ModelPermissions = require('../../server/models').Permissions, + permissions = require('../../server/permissions'), + effectivePerms = require('../../server/permissions/effective'), + context = testUtils.context.owner, + sandbox = sinon.sandbox.create(); + +// TODO move to integrations or stub describe('Permissions', function () { - - var sandbox; - - before(function (done) { - testUtils.clearData().then(function () { - done(); - }).catch(done); - }); - - afterEach(function (done) { + afterEach(function () { sandbox.restore(); - testUtils.clearData() - .then(function () { - done(); - }).catch(done); }); - after(function (done) { - testUtils.clearData().then(function () { + beforeEach(function () { + var permissions = _.map(testUtils.DataGenerator.Content.permissions, function (testPerm) { + return testUtils.DataGenerator.forKnex.createPermission(testPerm); + }); + + sandbox.stub(ModelPermission, 'findAll', function () { + return when(ModelPermissions.forge(permissions)); + }); + + }); + + + it('can load an actions map from existing permissions', function (done) { + permissions.init().then(function (actionsMap) { + should.exist(actionsMap); + + actionsMap.edit.sort().should.eql(['post', 'tag', 'user', 'page'].sort()); + + actionsMap.should.equal(permissions.actionsMap); + done(); }).catch(done); }); - var testPerms = [ - { act: 'edit', obj: 'post' }, - { act: 'edit', obj: 'tag' }, - { act: 'edit', obj: 'user' }, - { act: 'edit', obj: 'page' }, - { act: 'add', obj: 'post' }, - { act: 'add', obj: 'user' }, - { act: 'add', obj: 'page' }, - { act: 'destroy', obj: 'post' }, - { act: 'destroy', obj: 'user' } - ], - currTestPermId = 1, - createPermission = function (name, act, obj) { - if (!name) { - currTestPermId += 1; - name = 'test' + currTestPermId; - } - var newPerm = { - name: name, - action_type: act, - object_type: obj - }; - return Models.Permission.add(newPerm, context); - }, - createTestPermissions = function () { - var createActions = _.map(testPerms, function (testPerm) { - return createPermission(null, testPerm.act, testPerm.obj); - }); - - return when.all(createActions); - }; - - describe('Init Permissions', function () { - - beforeEach(function (done) { - sandbox = sinon.sandbox.create(); - testUtils.initData() - .then(testUtils.insertDefaultUser) - .then(testUtils.insertDefaultApp) - .then(function () { - done(); - }).catch(done); - }); - - it('can load an actions map from existing permissions', function (done) { - createTestPermissions() - .then(permissions.init) - .then(function (actionsMap) { - should.exist(actionsMap); - - actionsMap.edit.sort().should.eql(['post', 'tag', 'user', 'page', 'theme', 'setting'].sort()); - - actionsMap.should.equal(permissions.actionsMap); - - done(); - }).catch(done); - }); - - it('can add user to role', function (done) { - var existingUserRoles; - - Models.User.findOne({id: 1}, { withRelated: ['roles'] }).then(function (foundUser) { - var testRole = new Models.Role({ - name: 'testrole1', - description: 'testrole1 description' - }); - - should.exist(foundUser); - - should.exist(foundUser.roles()); - - existingUserRoles = foundUser.related('roles').length; - - return testRole.save(null, context).then(function () { - return foundUser.roles().attach(testRole); - }); - }).then(function () { - return Models.User.findOne({id: 1}, { withRelated: ['roles'] }); - }).then(function (updatedUser) { - should.exist(updatedUser); - - updatedUser.related('roles').length.should.equal(existingUserRoles + 1); - - done(); - }).catch(done); - }); - - it('can add user permissions', function (done) { - Models.User.findOne({id: 1}, { withRelated: ['permissions']}).then(function (testUser) { - var testPermission = new Models.Permission({ - name: 'test edit posts', - action_type: 'edit', - object_type: 'post' - }); - - testUser.related('permissions').length.should.equal(0); - - return testPermission.save(null, context).then(function () { - return testUser.permissions().attach(testPermission); - }); - }).then(function () { - return Models.User.findOne({id: 1}, { include: ['permissions']}); - }).then(function (updatedUser) { - should.exist(updatedUser); - - updatedUser.related('permissions').length.should.equal(1); - - done(); - }).catch(done); - }); - - it('can add role permissions', function (done) { - var testRole = new Models.Role({ - name: 'test2', - description: 'test2 description' - }); - - testRole.save(null, context) - .then(function () { - return testRole.load('permissions'); - }) - .then(function () { - var rolePermission = new Models.Permission({ - name: 'test edit posts', - action_type: 'edit', - object_type: 'post' - }); - - testRole.related('permissions').length.should.equal(0); - - return rolePermission.save(null, context).then(function () { - return testRole.permissions().attach(rolePermission); - }); - }) - .then(function () { - return Models.Role.findOne({id: testRole.id}, { withRelated: ['permissions']}); - }) - .then(function (updatedRole) { - should.exist(updatedRole); - - updatedRole.related('permissions').length.should.equal(1); - - done(); - }).catch(done); - }); - - }); - - describe('With Permissions', function () { - - beforeEach(function (done) { - sandbox = sinon.sandbox.create(); - testUtils.initData() - .then(testUtils.insertDefaultUser) - .then(testUtils.insertDefaultApp) - .then(function () { - done(); - }).catch(done); - }); - - - it('does not allow edit post without permission', function (done) { - var fakePage = { - id: 1 - }; - - createTestPermissions() - .then(permissions.init) - .then(function () { - return Models.User.findOne({id: 1}); - }) - .then(function (foundUser) { - var canThisResult = permissions.canThis(foundUser); - - should.exist(canThisResult.edit); - should.exist(canThisResult.edit.post); - - return canThisResult.edit.page(fakePage); - }) - .then(function () { - done(new Error('was able to edit post without permission')); - }).catch(done); - }); - - it('allows edit post with permission', function (done) { - var fakePost = { - id: '1' - }; - - createTestPermissions() - .then(permissions.init) - .then(function () { - return Models.User.findOne({id: 1}); - }) - .then(function (foundUser) { - var newPerm = new Models.Permission({ - name: 'test3 edit post', - action_type: 'edit', - object_type: 'post' - }); - - return newPerm.save(null, context).then(function () { - return foundUser.permissions().attach(newPerm); - }); - }) - .then(function () { - return Models.User.findOne({id: 1}, { withRelated: ['permissions']}); - }) - .then(function (updatedUser) { - - // TODO: Verify updatedUser.related('permissions') has the permission? - var canThisResult = permissions.canThis(updatedUser.id); - - should.exist(canThisResult.edit); - should.exist(canThisResult.edit.post); - - return canThisResult.edit.post(fakePost); - }) - .then(function () { - done(); - }).catch(done); - }); - - it('can use permissable function on Model to allow something', function (done) { - var testUser, - permissableStub = sandbox.stub(Models.Post, 'permissable', function () { - return when.resolve(); - }); - - testUtils.insertAuthorUser() - .then(function () { - return Models.User.findAll(); - }) - .then(function (foundUser) { - testUser = foundUser.models[1]; - - return permissions.canThis({user: testUser.id}).edit.post(123); - }) - .then(function () { - permissableStub.restore(); - permissableStub.calledWith(123, { user: testUser.id, app: null, internal: false }) - .should.equal(true); - - done(); - }) - .catch(function () { - permissableStub.restore(); - - done(new Error('did not allow testUser')); - }); - }); - - it('can use permissable function on Model to forbid something', function (done) { - var testUser, - permissableStub = sandbox.stub(Models.Post, 'permissable', function () { - return when.reject(); - }); - - testUtils.insertAuthorUser() - .then(function () { - return Models.User.findAll(); - }) - .then(function (foundUser) { - testUser = foundUser.models[1]; - - return permissions.canThis({user: testUser.id}).edit.post(123); - }) - .then(function () { - - permissableStub.restore(); - done(new Error('Allowed testUser to edit post')); - }) - .catch(function () { - permissableStub.calledWith(123, { user: testUser.id, app: null, internal: false }) - .should.equal(true); - permissableStub.restore(); - done(); - }); - }); - - it('can get effective user permissions', function (done) { - effectivePerms.user(1).then(function (effectivePermissions) { - should.exist(effectivePermissions); - - effectivePermissions.length.should.be.above(0); - - done(); - }).catch(done); - }); - - it('can check an apps effective permissions', function (done) { - effectivePerms.app('Kudos') - .then(function (effectivePermissions) { - should.exist(effectivePermissions); - - effectivePermissions.length.should.be.above(0); - - done(); - }) - .catch(done); - }); - - it('does not allow an app to edit a post without permission', function (done) { - // Change the author of the post so the author override doesn't affect the test - Models.Post.edit({'author_id': 2}, _.extend(context, {id: 1})) - .then(function (updatedPost) { - // Add user permissions - return Models.User.findOne({id: 1}) - .then(function (foundUser) { - var newPerm = new Models.Permission({ - name: 'app test edit post', - action_type: 'edit', - object_type: 'post' - }); - - return newPerm.save(null, context).then(function () { - return foundUser.permissions().attach(newPerm).then(function () { - return when.all([updatedPost, foundUser]); - }); - }); - }); - }) - .then(function (results) { - var updatedPost = results[0], - updatedUser = results[1]; - - return permissions.canThis({ user: updatedUser.id }) - .edit - .post(updatedPost.id) - .then(function () { - return results; - }) - .catch(function (err) { - /*jshint unused:false */ - done(new Error('Did not allow user 1 to edit post 1')); - }); - }) - .then(function (results) { - var updatedPost = results[0], - updatedUser = results[1]; - - // Confirm app cannot edit it. - return permissions.canThis({ app: 'Hemingway', user: updatedUser.id }) - .edit - .post(updatedPost.id) - .then(function () { - done(new Error('Allowed an edit of post 1')); - }).catch(done); - }).catch(done); - }); - - it('allows an app to edit a post with permission', function (done) { - permissions.canThis({ app: 'Kudos', user: 1 }) - .edit - .post(1) - .then(function () { - done(); - }) - .catch(function () { - done(new Error('Did not allow an edit of post 1')); - }); - }); - - it('checks for null context passed and rejects', function (done) { - permissions.canThis(undefined) - .edit - .post(1) - .then(function () { - done(new Error('Should not allow editing post')); - }) - .catch(done); - }); - - it('allows \'internal\' to be passed for internal requests', function (done) { - // Using tag here because post implements the custom permissable interface - permissions.canThis('internal') - .edit - .tag(1) - .then(function () { - done(); - }) - .catch(function () { - done(new Error('Should allow editing post with "internal"')); - }); - }); - - it('allows { internal: true } to be passed for internal requests', function (done) { - // Using tag here because post implements the custom permissable interface - permissions.canThis({ internal: true }) - .edit - .tag(1) - .then(function () { - done(); - }) - .catch(function () { - done(new Error('Should allow editing post with { internal: true }')); - }); - }); - }); +// it('does not allow edit post without permission', function (done) { +// var fakePage = { +// id: 1 +// }; +// +// permissions.init() +// .then(function () { +// var canThisResult = permissions.canThis({id: 1}); +// +// should.exist(canThisResult.edit); +// should.exist(canThisResult.edit.post); +// +// return canThisResult.edit.page(fakePage); +// }) +// .then(function () { +// done(new Error('was able to edit post without permission')); +// }).catch(done); +// }); +////// +// it('allows edit post with permission', function (done) { +// var fakePost = { +// id: '1' +// }; +// +// permissions.init() +// .then(function () { +// return Models.User.findOne({id: 1}); +// }) +// .then(function (foundUser) { +// var newPerm = new Models.Permission({ +// name: 'test3 edit post', +// action_type: 'edit', +// object_type: 'post' +// }); +// +// return newPerm.save(null, context).then(function () { +// return foundUser.permissions().attach(newPerm); +// }); +// }) +// .then(function () { +// return Models.User.findOne({id: 1}, { withRelated: ['permissions']}); +// }) +// .then(function (updatedUser) { +// +// // TODO: Verify updatedUser.related('permissions') has the permission? +// var canThisResult = permissions.canThis(updatedUser.id); +// +// should.exist(canThisResult.edit); +// should.exist(canThisResult.edit.post); +// +// return canThisResult.edit.post(fakePost); +// }) +// .then(function () { +// done(); +// }).catch(done); +// }); +// +// it('can use permissable function on Model to allow something', function (done) { +// var testUser, +// permissableStub = sandbox.stub(Models.Post, 'permissable', function () { +// return when.resolve(); +// }); +// +// testUtils.insertAuthorUser() +// .then(function () { +// return Models.User.findAll(); +// }) +// .then(function (foundUser) { +// testUser = foundUser.models[1]; +// +// return permissions.canThis({user: testUser.id}).edit.post(123); +// }) +// .then(function () { +// permissableStub.restore(); +// permissableStub.calledWith(123, { user: testUser.id, app: null, internal: false }) +// .should.equal(true); +// +// done(); +// }) +// .catch(function () { +// permissableStub.restore(); +// +// done(new Error('did not allow testUser')); +// }); +// }); +// +// it('can use permissable function on Model to forbid something', function (done) { +// var testUser, +// permissableStub = sandbox.stub(Models.Post, 'permissable', function () { +// return when.reject(); +// }); +// +// testUtils.insertAuthorUser() +// .then(function () { +// return Models.User.findAll(); +// }) +// .then(function (foundUser) { +// testUser = foundUser.models[1]; +// +// return permissions.canThis({user: testUser.id}).edit.post(123); +// }) +// .then(function () { +// +// permissableStub.restore(); +// done(new Error('Allowed testUser to edit post')); +// }) +// .catch(function () { +// permissableStub.calledWith(123, { user: testUser.id, app: null, internal: false }) +// .should.equal(true); +// permissableStub.restore(); +// done(); +// }); +// }); +// +// it('can get effective user permissions', function (done) { +// effectivePerms.user(1).then(function (effectivePermissions) { +// should.exist(effectivePermissions); +// +// effectivePermissions.length.should.be.above(0); +// +// done(); +// }).catch(done); +// }); +// +// it('can check an apps effective permissions', function (done) { +// effectivePerms.app('Kudos') +// .then(function (effectivePermissions) { +// should.exist(effectivePermissions); +// +// effectivePermissions.length.should.be.above(0); +// +// done(); +// }) +// .catch(done); +// }); +// +// it('does not allow an app to edit a post without permission', function (done) { +// // Change the author of the post so the author override doesn't affect the test +// Models.Post.edit({'author_id': 2}, _.extend(context, {id: 1})) +// .then(function (updatedPost) { +// // Add user permissions +// return Models.User.findOne({id: 1}) +// .then(function (foundUser) { +// var newPerm = new Models.Permission({ +// name: 'app test edit post', +// action_type: 'edit', +// object_type: 'post' +// }); +// +// return newPerm.save(null, context).then(function () { +// return foundUser.permissions().attach(newPerm).then(function () { +// return when.all([updatedPost, foundUser]); +// }); +// }); +// }); +// }) +// .then(function (results) { +// var updatedPost = results[0], +// updatedUser = results[1]; +// +// return permissions.canThis({ user: updatedUser.id }) +// .edit +// .post(updatedPost.id) +// .then(function () { +// return results; +// }) +// .catch(function (err) { +// /*jshint unused:false */ +// done(new Error('Did not allow user 1 to edit post 1')); +// }); +// }) +// .then(function (results) { +// var updatedPost = results[0], +// updatedUser = results[1]; +// +// // Confirm app cannot edit it. +// return permissions.canThis({ app: 'Hemingway', user: updatedUser.id }) +// .edit +// .post(updatedPost.id) +// .then(function () { +// done(new Error('Allowed an edit of post 1')); +// }).catch(done); +// }).catch(done); +// }); +// +// it('allows an app to edit a post with permission', function (done) { +// permissions.canThis({ app: 'Kudos', user: 1 }) +// .edit +// .post(1) +// .then(function () { +// done(); +// }) +// .catch(function () { +// done(new Error('Did not allow an edit of post 1')); +// }); +// }); +// +// it('checks for null context passed and rejects', function (done) { +// permissions.canThis(undefined) +// .edit +// .post(1) +// .then(function () { +// done(new Error('Should not allow editing post')); +// }) +// .catch(done); +// }); +// +// it('allows \'internal\' to be passed for internal requests', function (done) { +// // Using tag here because post implements the custom permissable interface +// permissions.canThis('internal') +// .edit +// .tag(1) +// .then(function () { +// done(); +// }) +// .catch(function () { +// done(new Error('Should allow editing post with "internal"')); +// }); +// }); +// +// it('allows { internal: true } to be passed for internal requests', function (done) { +// // Using tag here because post implements the custom permissable interface +// permissions.canThis({ internal: true }) +// .edit +// .tag(1) +// .then(function () { +// done(); +// }) +// .catch(function () { +// done(new Error('Should allow editing post with { internal: true }')); +// }); +// }); }); \ No newline at end of file diff --git a/core/test/utils/fixtures/data-generator.js b/core/test/utils/fixtures/data-generator.js index b3e94f87c4..591d48186f 100644 --- a/core/test/utils/fixtures/data-generator.js +++ b/core/test/utils/fixtures/data-generator.js @@ -103,6 +103,78 @@ DataGenerator.Content = { } ], + permissions: [ + { + name: 'Browse posts', + action_type: 'browse', + object_type: 'post' + }, + { + name: 'test', + action_type: 'edit', + object_type: 'post' + }, + { + name: 'test', + action_type: 'edit', + object_type: 'tag' + }, + { + name: 'test', + action_type: 'edit', + object_type: 'user' + }, + { + name: 'test', + action_type: 'edit', + object_type: 'page' + }, + { + name: 'test', + action_type: 'add', + object_type: 'post' + }, + { + name: 'test', + action_type: 'add', + object_type: 'user' + }, + { + name: 'test', + action_type: 'add', + object_type: 'page' + }, + { + name: 'test', + action_type: 'destroy', + object_type: 'post' + }, + { + name: 'test', + action_type: 'destroy', + object_type: 'user' + } + ], + + roles: [ + { + "name": "Administrator", + "description": "Administrators" + }, + { + "name": "Editor", + "description": "Editors" + }, + { + "name": "Author", + "description": "Authors" + }, + { + "name": "Owner", + "description": "Blog Owner" + } + ], + apps: [ { name: 'Kudos', @@ -157,7 +229,21 @@ DataGenerator.forKnex = (function () { tags, posts_tags, apps, - app_fields; + app_fields, + roles, + users, + roles_users; + + function createBasic(overrides) { + return _.defaults(overrides, { + uuid: uuid.v4(), + created_by: 1, + created_at: new Date(), + updated_by: 1, + updated_at: new Date() + }); + } + function createPost(overrides) { return _.defaults(overrides, { @@ -193,16 +279,6 @@ DataGenerator.forKnex = (function () { }); } - function createTag(overrides) { - return _.defaults(overrides, { - uuid: uuid.v4(), - updated_at: new Date(), - updated_by: 1, - created_at: new Date(), - created_by: 1 - }); - } - function createUser(overrides) { return _.defaults(overrides, { uuid: uuid.v4(), @@ -221,13 +297,6 @@ DataGenerator.forKnex = (function () { }); } - function createUserRole(userId, roleId) { - return { - role_id: roleId, - user_id: userId - }; - } - function createPostsTags(postId, tagId) { return { post_id: postId, @@ -235,14 +304,6 @@ DataGenerator.forKnex = (function () { }; } - function createApp(overrides) { - return _.defaults(overrides, { - uuid: uuid.v4(), - created_by: 1, - created_at: new Date() - }); - } - function createAppField(overrides) { return _.defaults(overrides, { uuid: uuid.v4(), @@ -258,6 +319,7 @@ DataGenerator.forKnex = (function () { function createAppSetting(overrides) { return _.defaults(overrides, { uuid: uuid.v4(), + app_id: 1, created_by: 1, created_at: new Date() }); @@ -274,26 +336,47 @@ DataGenerator.forKnex = (function () { ]; tags = [ - createTag(DataGenerator.Content.tags[0]), - createTag(DataGenerator.Content.tags[1]), - createTag(DataGenerator.Content.tags[2]), - createTag(DataGenerator.Content.tags[3]), - createTag(DataGenerator.Content.tags[4]) + createBasic(DataGenerator.Content.tags[0]), + createBasic(DataGenerator.Content.tags[1]), + createBasic(DataGenerator.Content.tags[2]), + createBasic(DataGenerator.Content.tags[3]), + createBasic(DataGenerator.Content.tags[4]) + ]; + + roles = [ + createBasic(DataGenerator.Content.roles[0]), + createBasic(DataGenerator.Content.roles[1]), + createBasic(DataGenerator.Content.roles[2]), + createBasic(DataGenerator.Content.roles[3]), + ]; + + users = [ + createUser(DataGenerator.Content.users[0]), + createUser(DataGenerator.Content.users[1]), + createUser(DataGenerator.Content.users[2]), + createUser(DataGenerator.Content.users[3]), + ]; + + roles_users = [ + { user_id: 1, role_id: 4}, + { user_id: 2, role_id: 1}, + { user_id: 3, role_id: 2}, + { user_id: 4, role_id: 3} ]; posts_tags = [ + { post_id: 1, tag_id: 1 }, + { post_id: 1, tag_id: 2 }, + { post_id: 2, tag_id: 1 }, { post_id: 2, tag_id: 2 }, - { post_id: 2, tag_id: 3 }, - { post_id: 3, tag_id: 2 }, { post_id: 3, tag_id: 3 }, - { post_id: 4, tag_id: 4 }, - { post_id: 5, tag_id: 5 } + { post_id: 4, tag_id: 4 } ]; apps = [ - createApp(DataGenerator.Content.apps[0]), - createApp(DataGenerator.Content.apps[1]), - createApp(DataGenerator.Content.apps[2]) + createBasic(DataGenerator.Content.apps[0]), + createBasic(DataGenerator.Content.apps[1]), + createBasic(DataGenerator.Content.apps[2]) ]; app_fields = [ @@ -304,12 +387,14 @@ DataGenerator.forKnex = (function () { return { createPost: createPost, createGenericPost: createGenericPost, - createTag: createTag, + createTag: createBasic, createUser: createUser, createGenericUser: createGenericUser, - createUserRole: createUserRole, + createBasic: createBasic, + createRole: createBasic, + createPermission: createBasic, createPostsTags: createPostsTags, - createApp: createApp, + createApp: createBasic, createAppField: createAppField, createAppSetting: createAppSetting, @@ -317,7 +402,10 @@ DataGenerator.forKnex = (function () { tags: tags, posts_tags: posts_tags, apps: apps, - app_fields: app_fields + app_fields: app_fields, + roles: roles, + users: users, + roles_users: roles_users }; }()); diff --git a/core/test/utils/index.js b/core/test/utils/index.js index 754d9014d7..1ff51976d9 100644 --- a/core/test/utils/index.js +++ b/core/test/utils/index.js @@ -5,248 +5,357 @@ var when = require('when'), fs = require('fs-extra'), path = require('path'), migration = require('../../server/data/migration/'), + settings = require('../../server/models').Settings, + SettingsAPI = require('../../server/api/settings'), + permissions = require('../../server/permissions'), + permsFixtures = require('../../server/data/fixtures/permissions/permissions.json'), DataGenerator = require('./fixtures/data-generator'), API = require('./api'), fork = require('./fork'), config = require('../../server/config'), - teardown; + fixtures, + getFixtureOps, + toDoList, + postsInserted = 0, -function initData() { - return migration.init(); -} + teardown, + setup, + doAuth, -function clearData() { - // we must always try to delete all tables - return migration.reset(); -} + initData, + clearData; -function insertPosts() { - var knex = config.database.knex; - // ToDo: Get rid of pyramid of doom - return when(knex('posts').insert(DataGenerator.forKnex.posts).then(function () { - return knex('tags').insert(DataGenerator.forKnex.tags).then(function () { - return knex('posts_tags').insert(DataGenerator.forKnex.posts_tags); - }); - })); -} -function insertMorePosts(max) { - var lang, - status, - posts = [], - i, j, k = 0, - knex = config.database.knex; +/** TEST FIXTURES **/ +fixtures = { + insertPosts: function insertPosts() { + var knex = config.database.knex; + // ToDo: Get rid of pyramid of doom + return when(knex('posts').insert(DataGenerator.forKnex.posts).then(function () { + return knex('tags').insert(DataGenerator.forKnex.tags).then(function () { + return knex('posts_tags').insert(DataGenerator.forKnex.posts_tags); + }); + })); + }, - max = max || 50; + insertMorePosts: function insertMorePosts(max) { + var lang, + status, + posts = [], + i, j, k = postsInserted, + knex = config.database.knex; - for (i = 0; i < 2; i += 1) { - lang = i % 2 ? 'en' : 'fr'; - posts.push(DataGenerator.forKnex.createGenericPost(k++, null, lang)); + max = max || 50; - for (j = 0; j < max; j += 1) { - status = j % 2 ? 'draft' : 'published'; - posts.push(DataGenerator.forKnex.createGenericPost(k++, status, lang)); - } - } + for (i = 0; i < 2; i += 1) { + lang = i % 2 ? 'en' : 'fr'; + posts.push(DataGenerator.forKnex.createGenericPost(k++, null, lang)); - return sequence(_.times(posts.length, function(index) { - return function() { - return knex('posts').insert(posts[index]); - }; - })); -} - -function insertMorePostsTags(max) { - max = max || 50; - var knex = config.database.knex; - - return when.all([ - // PostgreSQL can return results in any order - knex('posts').orderBy('id', 'asc').select('id'), - knex('tags').select('id', 'name') - ]).then(function (results) { - var posts = _.pluck(results[0], 'id'), - injectionTagId = _.chain(results[1]) - .where({name: 'injection'}) - .pluck('id') - .value()[0], - promises = [], - i; - - if (max > posts.length) { - throw new Error('Trying to add more posts_tags than the number of posts.'); + for (j = 0; j < max; j += 1) { + status = j % 2 ? 'draft' : 'published'; + posts.push(DataGenerator.forKnex.createGenericPost(k++, status, lang)); + } } - for (i = 0; i < max; i += 1) { - promises.push(DataGenerator.forKnex.createPostsTags(posts[i], injectionTagId)); - } + // Keep track so we can run this function again safely + postsInserted = k; - return sequence(_.times(promises.length, function (index) { + return sequence(_.times(posts.length, function (index) { return function () { - return knex('posts_tags').insert(promises[index]); + return knex('posts').insert(posts[index]); }; })); - }); -} + }, -function insertDefaultUser() { - var user, - knex = config.database.knex; + insertMorePostsTags: function insertMorePostsTags(max) { + max = max || 50; - user = DataGenerator.forKnex.createUser(DataGenerator.Content.users[0]); + var knex = config.database.knex; - return knex('users') - .where('id', '=', '1') - .update(user); -} - -function insertAdminUser() { - var users = [], - userRoles = [], - knex = config.database.knex; - - users.push(DataGenerator.forKnex.createUser(DataGenerator.Content.users[1])); - userRoles.push(DataGenerator.forKnex.createUserRole(2, 2)); - return knex('users') - .insert(users) - .then(function () { - return knex('roles_users').insert(userRoles); - }); -} - -function insertEditorUser() { - var users = [], - userRoles = [], - knex = config.database.knex; - - users.push(DataGenerator.forKnex.createUser(DataGenerator.Content.users[2])); - userRoles.push(DataGenerator.forKnex.createUserRole(3, 2)); - return knex('users') - .insert(users) - .then(function () { - return knex('roles_users').insert(userRoles); - }); -} - -function insertAuthorUser() { - var users = [], - userRoles = [], - knex = config.database.knex; - - users.push(DataGenerator.forKnex.createUser(DataGenerator.Content.users[3])); - userRoles.push(DataGenerator.forKnex.createUserRole(4, 3)); - return knex('users') - .insert(users) - .then(function () { - return knex('roles_users').insert(userRoles); - }); -} - -function insertDefaultApp() { - var apps = [], - knex = config.database.knex; - - apps.push(DataGenerator.forKnex.createApp(DataGenerator.Content.apps[0])); - - return knex('permissions') - .select('id') - .where('object_type', 'post') - .andWhere('action_type', 'edit') - .then(function (result) { - var permission_id = result[0].id; - if (permission_id) { - return knex('apps') - .insert(apps) - .then(function () { - return knex('permissions_apps') - .insert({ - app_id: 1, - permission_id: permission_id - }); - }); - } - - throw new Error('Permissions not created'); - }); -} - -function insertApps() { - var knex = config.database.knex; - return knex('apps').insert(DataGenerator.forKnex.apps).then(function () { - return knex('app_fields').insert(DataGenerator.forKnex.app_fields); - }); -} - -function insertAppWithSettings() { - var apps = [], - app_settings = [], - knex = config.database.knex; - - apps.push(DataGenerator.forKnex.createApp(DataGenerator.Content.apps[0])); - app_settings.push(DataGenerator.forKnex.createAppSetting(DataGenerator.Content.app_settings[0])); - app_settings.push(DataGenerator.forKnex.createAppSetting(DataGenerator.Content.app_settings[1])); - - return knex('apps').insert(apps, 'id') - .then(function (results) { - var appId = results[0], i; - - for (i = 0; i < app_settings.length; i++) { - app_settings[i].app_id = appId; - } - - return knex('app_settings').insert(app_settings); - }); -} -function insertAppWithFields() { - var apps = [], - app_fields = [], - knex = config.database.knex; - - apps.push(DataGenerator.forKnex.createApp(DataGenerator.Content.apps[0])); - app_fields.push(DataGenerator.forKnex.createAppField(DataGenerator.Content.app_fields[0])); - app_fields.push(DataGenerator.forKnex.createAppField(DataGenerator.Content.app_fields[1])); - - return knex('apps').insert(apps, 'id') - .then(function (results) { - var appId = results[0], + return when.all([ + // PostgreSQL can return results in any order + knex('posts').orderBy('id', 'asc').select('id'), + knex('tags').select('id', 'name') + ]).then(function (results) { + var posts = _.pluck(results[0], 'id'), + injectionTagId = _.chain(results[1]) + .where({name: 'injection'}) + .pluck('id') + .value()[0], + promises = [], i; - for (i = 0; i < app_fields.length; i++) { - app_fields[i].app_id = appId; + if (max > posts.length) { + throw new Error('Trying to add more posts_tags than the number of posts.'); } - return knex('app_fields').insert(app_fields); + for (i = 0; i < max; i += 1) { + promises.push(DataGenerator.forKnex.createPostsTags(posts[i], injectionTagId)); + } + + return sequence(_.times(promises.length, function (index) { + return function () { + return knex('posts_tags').insert(promises[index]); + }; + })); }); -} + }, + initOwnerUser: function initOwnerUser() { + var user = DataGenerator.Content.users[0], + knex = config.database.knex; -function insertDefaultFixtures() { - return insertDefaultUser().then(function () { - return insertPosts(); - }).then(function () { - return insertApps(); - }); -} + user = DataGenerator.forKnex.createBasic(user); + user = _.extend({}, user, {'status': 'inactive'}); -function loadExportFixture(filename) { - var filepath = path.resolve(__dirname + '/fixtures/' + filename + '.json'); + return knex('users').insert(user); + }, - return nodefn.call(fs.readFile, filepath).then(function (fileContents) { - var data; + insertOwnerUser: function insertOwnerUser() { + var user, + knex = config.database.knex; - // Parse the json data - try { - data = JSON.parse(fileContents); - } catch (e) { - return when.reject(new Error("Failed to parse the file")); + user = DataGenerator.forKnex.createUser(DataGenerator.Content.users[0]); + + return knex('users').insert(user); + }, + + overrideOwnerUser: function overrideOwnerUser() { + var user, + knex = config.database.knex; + + user = DataGenerator.forKnex.createUser(DataGenerator.Content.users[0]); + + return knex('users') + .where('id', '=', '1') + .update(user); + }, + + createUsersWithRoles: function createUsersWithRoles() { + var knex = config.database.knex; + return knex('roles').insert(DataGenerator.forKnex.roles).then(function () { + return knex('users').insert(DataGenerator.forKnex.users); + }).then(function () { + return knex('roles_users').insert(DataGenerator.forKnex.roles_users); + }); + }, + + insertOne: function insertOne(obj, fn) { + var knex = config.database.knex; + return knex(obj) + .insert(DataGenerator.forKnex[fn](DataGenerator.Content[obj][0])); + }, + + insertApps: function insertApps() { + var knex = config.database.knex; + return knex('apps').insert(DataGenerator.forKnex.apps).then(function () { + return knex('app_fields').insert(DataGenerator.forKnex.app_fields); + }); + }, + + loadExportFixture: function loadExportFixture(filename) { + var filepath = path.resolve(__dirname + '/fixtures/' + filename + '.json'); + + return nodefn.call(fs.readFile, filepath).then(function (fileContents) { + var data; + + // Parse the json data + try { + data = JSON.parse(fileContents); + } catch (e) { + return when.reject(new Error("Failed to parse the file")); + } + + return data; + }); + }, + + permissionsFor: function permissionsFor(obj) { + var knex = config.database.knex, + permsToInsert = permsFixtures.permissions[obj], + permsRolesToInsert = permsFixtures.permissions_roles, + actions = [], + permissions_roles = [], + roles = { + 'Administrator': 1, + 'Editor': 2, + 'Author': 3, + 'Owner': 4 + }; + + permsToInsert = _.map(permsToInsert, function (perms) { + perms.object_type = obj; + actions.push(perms.action_type); + return DataGenerator.forKnex.createBasic(perms); + }); + + _.each(permsRolesToInsert, function (perms, role) { + if (perms[obj]) { + if (perms[obj] === 'all') { + _.each(actions, function (action, i) { + permissions_roles.push({permission_id: (i + 1), role_id: roles[role]}); + }); + } + else { + _.each(perms[obj], function (action) { + permissions_roles.push({permission_id: (_.indexOf(actions, action) + 1), role_id: roles[role]}); + }); + } + } + }); + + return knex('permissions').insert(permsToInsert).then(function () { + return knex('permissions_roles').insert(permissions_roles); + }); + } +}; + +/** Test Utility Functions **/ +initData = function initData() { + return migration.init(); +}; + +clearData = function clearData() { + // we must always try to delete all tables + return migration.reset(); +}; + +toDoList = { + 'app': function insertApp() { return fixtures.insertOne('apps', 'createApp'); }, + 'app_field': function insertAppField() { + // TODO: use the actual app ID to create the field + return fixtures.insertOne('apps', 'createApp').then(function () { + return fixtures.insertOne('app_fields', 'createAppField'); + }); + }, + 'app_setting': function insertAppSetting() { + // TODO: use the actual app ID to create the field + return fixtures.insertOne('apps', 'createApp').then(function () { + return fixtures.insertOne('app_settings', 'createAppSetting'); + }); + }, + 'permission': function insertPermission() { return fixtures.insertOne('permissions', 'createPermission'); }, + 'role': function insertRole() { return fixtures.insertOne('roles', 'createRole'); }, + 'tag': function insertRole() { return fixtures.insertOne('tags', 'createTag'); }, + 'posts': function insertPosts() { return fixtures.insertPosts(); }, + 'apps': function insertApps() { return fixtures.insertApps(); }, + 'settings': function populate() { + return settings.populateDefaults().then(function () { return SettingsAPI.updateSettingsCache(); }); + }, + 'users:roles': function createUsersWithRoles() { return fixtures.createUsersWithRoles(); }, + 'owner': function insertOwnerUser() { return fixtures.insertOwnerUser(); }, + 'owner:pre': function initOwnerUser() { return fixtures.initOwnerUser(); }, + 'owner:post': function overrideOwnerUser() { return fixtures.overrideOwnerUser(); }, + 'perms:init': function initPermissions() { return permissions.init(); }, + 'perms': function permissionsFor(obj) { + return function permissionsForObj() { return fixtures.permissionsFor(obj); }; + } +}; + +/** + * ## getFixtureOps + * + * Takes the arguments from a setup function and turns them into an array of promises to fullfil + * + * This is effectively a list of instructions with regard to which fixtures should be setup for this test. + * * `default` - a special option which will cause the full suite of normal fixtures to be initialised + * * `perms:init` - initialise the permissions object after having added permissions + * * `perms:obj` - initialise permissions for a particular object type + * * `users:roles` - create a full suite of users, one per role + * @param options + */ +getFixtureOps = function getFixtureOps(toDos) { + // default = default fixtures, if it isn't present, init with tables only + var tablesOnly = !toDos.default, + fixtureOps = []; + + // Database initialisation + if (toDos.init || toDos.default) { + fixtureOps.push(function initDB() { + return migration.init(tablesOnly); + }); + delete toDos.default; + delete toDos.init; + } + + // Go through our list of things to do, and add them to an array + _.each(toDos, function (value, toDo) { + var tmp; + if (toDo !== 'perms:init' && toDo.indexOf('perms:') !== -1) { + tmp = toDo.split(':'); + fixtureOps.push(toDoList[tmp[0]](tmp[1])); + } else { + fixtureOps.push(toDoList[toDo]); } - - return data; }); -} -teardown = function (done) { + return fixtureOps; +}; + + +// ## Test Setup and Teardown + +/** + * ## Setup Integration Tests + * Setup takes a list of arguments like: 'default', 'tag', 'perms:tag', 'perms:init' + * Setup does 'init' (DB) by default + * @returns {Function} + */ +setup = function setup() { + var options = _.merge({'init': true}, _.transform(arguments, function (result, val) { + result[val] = true; + }) + ), + fixtureOps = getFixtureOps(options); + + return function (done) { + return sequence(fixtureOps).then(function () { + done(); + }).catch(done); + }; +}; + +/** + * ## DoAuth For Route Tests + * + * This function manages the work of ensuring we have an overriden owner user, and grabbing an access token + * @returns {deferred.promise} + */ +// TODO make this do the DB init as well +doAuth = function doAuth() { + var options = arguments, + deferred = when.defer(), + request = arguments[0], + user = DataGenerator.forModel.users[0], + fixtureOps; + + // Remove request from this list + delete options[0]; + // No DB setup, but override the owner + options = _.merge({'owner:post': true}, _.transform(options, function (result, val) { + result[val] = true; + }) + ); + + fixtureOps = getFixtureOps(options); + + sequence(fixtureOps).then(function () { + request.post('/ghost/api/v0.1/authentication/token/') + .send({ grant_type: 'password', username: user.email, password: user.password, client_id: 'ghost-admin'}) + .end(function (err, res) { + if (err) { + deferred.reject(err); + } + + deferred.resolve(res.body.access_token); + }); + }); + + return deferred.promise; +}; + +teardown = function teardown(done) { migration.reset().then(function () { done(); }).catch(done); @@ -254,26 +363,24 @@ teardown = function (done) { module.exports = { teardown: teardown, + setup: setup, + doAuth: doAuth, initData: initData, clearData: clearData, - insertDefaultFixtures: insertDefaultFixtures, - insertPosts: insertPosts, - insertMorePosts: insertMorePosts, - insertMorePostsTags: insertMorePostsTags, - insertDefaultUser: insertDefaultUser, - insertAdminUser: insertAdminUser, - insertEditorUser: insertEditorUser, - insertAuthorUser: insertAuthorUser, - insertDefaultApp: insertDefaultApp, - insertApps: insertApps, - insertAppWithSettings: insertAppWithSettings, - insertAppWithFields: insertAppWithFields, - loadExportFixture: loadExportFixture, + fixtures: fixtures, DataGenerator: DataGenerator, API: API, - fork: fork + fork: fork, + + context: { + internal: {context: {internal: true}}, + owner: {context: {user: 1}}, + admin: {context: {user: 2}}, + editor: {context: {user: 3}}, + author: {context: {user: 4}} + } };