0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-04-08 02:52:39 -05:00

Use Bookshelf in our test env (#9592)

refs #9601

- replace raw knex queries by Bookshelf queries
- optimise lot's of test setups, so we don't experience a massive slow down in the test run
- this has troubled in the past e.g. with normalisation, any custom model logic - the test env always had to simulate things
- there are for sure thousands things which can be optimised now, but because of time, we do them step by step
- this is especially important for the url service (https://github.com/TryGhost/Ghost/issues/9601), because we have to ensure that inserting/updating/removing resources will trigger model events

`grunt test-all` with SQLite finishes in 2,5-3min. (on master: 1-2min) 
`grunt test-all` with MySQL finishes in 4min. (on master: 3min)

**NOTE: We want to move as much as possible routing and integration tests to unit tests. This will speed up the test run again.** See #9342. But we need to find time for that. Any help is welcome!
This commit is contained in:
Katharina Irrgang 2018-04-25 17:13:35 +02:00 committed by GitHub
parent 2a1be3729d
commit e23fd511eb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
28 changed files with 1339 additions and 1105 deletions

View file

@ -1,13 +1,15 @@
'use strict';
var should = require('should'),
supertest = require('supertest'),
testUtils = require('../../../utils'),
moment = require('moment'),
user = testUtils.DataGenerator.forModel.users[0],
userForKnex = testUtils.DataGenerator.forKnex.users[0],
models = require('../../../../../core/server/models'),
constants = require('../../../../../core/server/lib/constants'),
config = require('../../../../../core/server/config'),
security = require('../../../../../core/server/lib/security'),
settingsCache = require('../../../../../core/server/services/settings/cache'),
ghost = testUtils.startGhost,
request;
@ -217,14 +219,13 @@ describe('Authentication API', function () {
});
it('reset password', function (done) {
models.Settings
.findOne({key: 'db_hash'})
.then(function (response) {
models.User.getOwnerUser(testUtils.context.internal)
.then(function (ownerUser) {
var token = security.tokens.resetToken.generateHash({
expires: Date.now() + (1000 * 60),
email: user.email,
dbHash: response.attributes.value,
password: userForKnex.password
dbHash: settingsCache.get('db_hash'),
password: ownerUser.get('password')
});
request.put(testUtils.API.getApiQuery('authentication/passwordreset'))

View file

@ -1415,7 +1415,7 @@ describe('Post API', function () {
// create author
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+2@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[2]
role: testUtils.DataGenerator.Content.roles[2].name
});
})
.then(function (_author) {
@ -1555,7 +1555,7 @@ describe('Post API', function () {
// create contributor
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+3@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[4]
role: testUtils.DataGenerator.Content.roles[4].name
});
})
.then(function (_contributor) {

View file

@ -18,7 +18,7 @@ describe('Public API', function () {
request = supertest.agent(config.get('url'));
})
.then(function () {
return testUtils.doAuth(request, 'posts', 'tags:extra', 'client:trusted-domain');
return testUtils.doAuth(request, 'users:no-owner', 'posts', 'tags:extra', 'client:trusted-domain');
});
});
@ -312,7 +312,7 @@ describe('Public API', function () {
var jsonResponse = res.body;
should.exist(jsonResponse.users);
testUtils.API.checkResponse(jsonResponse, 'users');
jsonResponse.users.should.have.length(2);
jsonResponse.users.should.have.length(6);
// We don't expose the email address.
testUtils.API.checkResponse(jsonResponse.users[0], 'user', null, null, null, {public: true});
@ -335,7 +335,7 @@ describe('Public API', function () {
var jsonResponse = res.body;
should.exist(jsonResponse.users);
testUtils.API.checkResponse(jsonResponse, 'users');
jsonResponse.users.should.have.length(2);
jsonResponse.users.should.have.length(6);
// We don't expose the email address.
testUtils.API.checkResponse(jsonResponse.users[0], 'user', null, null, null, {public: true});
@ -466,7 +466,7 @@ describe('Public API', function () {
var jsonResponse = res.body;
should.exist(jsonResponse.users);
testUtils.API.checkResponse(jsonResponse, 'users');
jsonResponse.users.should.have.length(2);
jsonResponse.users.should.have.length(6);
// We don't expose the email address.
testUtils.API.checkResponse(jsonResponse.users[0], 'user', ['count'], null, null, {public: true});
@ -489,7 +489,7 @@ describe('Public API', function () {
var jsonResponse = res.body;
should.exist(jsonResponse.users);
testUtils.API.checkResponse(jsonResponse, 'users');
jsonResponse.users.should.have.length(2);
jsonResponse.users.should.have.length(6);
// We don't expose the email address.
testUtils.API.checkResponse(jsonResponse.users[0], 'user', null, null, null, {public: true});

View file

@ -30,7 +30,7 @@ describe('Spam Prevention API', function () {
.then(function () {
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+1@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[1]
role: testUtils.DataGenerator.Content.roles[1].name
});
})
.then(function (user) {

View file

@ -74,7 +74,7 @@ describe('Themes API', function () {
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+1@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[1]
role: testUtils.DataGenerator.Content.roles[1].name
});
})
.then(function (user) {
@ -88,7 +88,7 @@ describe('Themes API', function () {
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+author@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[2]
role: testUtils.DataGenerator.Content.roles[2].name
});
})
.then(function (user) {

View file

@ -14,7 +14,7 @@ describe('User API', function () {
authorAccessToken = '',
editor, author, ghostServer, inactiveUser;
beforeEach(function () {
before(function () {
return ghost()
.then(function (_ghostServer) {
ghostServer = _ghostServer;
@ -24,7 +24,7 @@ describe('User API', function () {
// create editor
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+1@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[1]
role: testUtils.DataGenerator.Content.roles[1].name
});
})
.then(function (_user1) {
@ -33,7 +33,7 @@ describe('User API', function () {
// create author
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+2@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[2]
role: testUtils.DataGenerator.Content.roles[2].name
});
})
.then(function (_user2) {
@ -42,7 +42,7 @@ describe('User API', function () {
// create inactive user
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+3@ghost.org', status: 'inactive'}),
role: testUtils.DataGenerator.Content.roles[2]
role: testUtils.DataGenerator.Content.roles[2].name
});
})
.then(function (_user3) {
@ -558,6 +558,60 @@ describe('User API', function () {
});
describe('As Editor', function () {
before(function () {
return ghost()
.then(function (_ghostServer) {
ghostServer = _ghostServer;
request = supertest.agent(config.get('url'));
})
.then(function () {
// create editor
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+1@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[1].name
});
})
.then(function (_user1) {
editor = _user1;
// create author
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+2@ghost.org'}),
role: testUtils.DataGenerator.Content.roles[2].name
});
})
.then(function (_user2) {
author = _user2;
// create inactive user
return testUtils.createUser({
user: testUtils.DataGenerator.forKnex.createUser({email: 'test+3@ghost.org', status: 'inactive'}),
role: testUtils.DataGenerator.Content.roles[2].name
});
})
.then(function (_user3) {
inactiveUser = _user3;
// by default we login with the owner
return testUtils.doAuth(request);
})
.then(function (token) {
ownerAccessToken = token;
request.user = editor;
return testUtils.doAuth(request);
})
.then(function (token) {
editorAccessToken = token;
request.user = author;
return testUtils.doAuth(request);
})
.then(function (token) {
authorAccessToken = token;
});
});
describe('success cases', function () {
it('can edit himself', function (done) {
request.put(testUtils.API.getApiQuery('users/' + editor.id + '/'))

View file

@ -439,11 +439,13 @@ describe('Channel Routes', function () {
describe('Author', function () {
var lockedUser = {
name: 'Locked so what',
slug: 'locked-so-what',
email: 'locked@example.com',
status: 'locked'
},
suspendedUser = {
name: 'Suspended meeh',
slug: 'suspended-meeh',
email: 'suspended@example.com',
status: 'inactive'
@ -553,12 +555,12 @@ describe('Channel Routes', function () {
testUtils.clearData().then(function () {
// we initialise data, but not a user. No user should be required for navigating the frontend
return testUtils.initData();
}).then(function () {
return testUtils.fixtures.overrideOwnerUser('ghost-owner');
}).then(function () {
return testUtils.fixtures.insertPostsAndTags();
}).then(function () {
return testUtils.fixtures.insertExtraPosts(9);
}).then(function () {
return testUtils.fixtures.overrideOwnerUser('ghost-owner');
}).then(function () {
done();
}).catch(done);

View file

@ -12,8 +12,8 @@ var should = require('should'),
sandbox = sinon.sandbox.create();
describe('Invites API', function () {
beforeEach(testUtils.teardown);
beforeEach(testUtils.setup('invites', 'settings', 'users:roles', 'perms:invite', 'perms:init'));
before(testUtils.teardown);
before(testUtils.setup('invites', 'settings', 'users:roles', 'perms:invite', 'perms:init'));
beforeEach(function () {
sandbox.stub(mail, 'send').callsFake(function () {
@ -28,6 +28,31 @@ describe('Invites API', function () {
after(testUtils.teardown);
describe('CRUD', function () {
describe('Browse', function () {
it('browse invites', function (done) {
InvitesAPI.browse(testUtils.context.owner)
.then(function (response) {
response.invites.length.should.eql(2);
response.invites[0].status.should.eql('sent');
response.invites[0].email.should.eql('test1@ghost.org');
response.invites[0].role_id.should.eql(testUtils.roles.ids.admin);
response.invites[1].status.should.eql('sent');
response.invites[1].email.should.eql('test2@ghost.org');
response.invites[1].role_id.should.eql(testUtils.roles.ids.author);
should.not.exist(response.invites[0].token);
should.exist(response.invites[0].expires);
should.not.exist(response.invites[1].token);
should.exist(response.invites[1].expires);
done();
}).catch(done);
});
});
describe('Add', function () {
it('add invite 1', function (done) {
InvitesAPI.add({
@ -101,31 +126,6 @@ describe('Invites API', function () {
});
});
describe('Browse', function () {
it('browse invites', function (done) {
InvitesAPI.browse(testUtils.context.owner)
.then(function (response) {
response.invites.length.should.eql(2);
response.invites[0].status.should.eql('sent');
response.invites[0].email.should.eql('test1@ghost.org');
response.invites[0].role_id.should.eql(testUtils.roles.ids.admin);
response.invites[1].status.should.eql('sent');
response.invites[1].email.should.eql('test2@ghost.org');
response.invites[1].role_id.should.eql(testUtils.roles.ids.author);
should.not.exist(response.invites[0].token);
should.exist(response.invites[0].expires);
should.not.exist(response.invites[1].token);
should.exist(response.invites[1].expires);
done();
}).catch(done);
});
});
describe('Read', function () {
it('read invites: not found', function (done) {
InvitesAPI.read(_.merge({}, testUtils.context.owner, {

View file

@ -3,13 +3,18 @@ var should = require('should'),
uuid = require('uuid'),
ObjectId = require('bson-objectid'),
testUtils = require('../../utils'),
models = require('../../../server/models'),
NotificationsAPI = require('../../../server/api/notifications');
describe('Notifications API', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('settings', 'users:roles', 'perms:setting', 'perms:notification', 'perms:init'));
after(testUtils.teardown);
before(testUtils.setup('settings', 'users:roles', 'perms:setting', 'perms:notification', 'perms:init'));
beforeEach(function () {
return models.Settings.edit({key: 'notifications', value: '[]'}, testUtils.context.internal);
});
should.exist(NotificationsAPI);

View file

@ -17,34 +17,9 @@ describe('Post API', function () {
var localSettingsCache = {};
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('users:roles', 'perms:post', 'perms:init'));
after(testUtils.teardown);
// @TODO: remove when https://github.com/TryGhost/Ghost/issues/6930 is fixed
// we insert the posts via the model layer, because right now the test utils insert dates wrong
beforeEach(function (done) {
Promise.mapSeries(testUtils.DataGenerator.forKnex.posts, function (post) {
return models.Post.add(post, {context: {internal: true}});
}).then(function () {
done();
}).catch(done);
});
beforeEach(function (done) {
Promise.mapSeries(testUtils.DataGenerator.forKnex.tags, function (tag) {
return models.Tag.add(tag, {context: {internal: true}});
}).then(function () {
done();
}).catch(done);
});
beforeEach(function (done) {
db.knex('posts_tags').insert(testUtils.DataGenerator.forKnex.posts_tags)
.then(function () {
done();
})
.catch(done);
});
before(testUtils.setup('users:roles', 'perms:post', 'perms:init', 'posts'));
beforeEach(function () {
sandbox.stub(settingsCache, 'get').callsFake(function (key) {
@ -60,14 +35,6 @@ describe('Post API', function () {
should.exist(PostAPI);
describe('Browse', function () {
beforeEach(function () {
return db.knex('posts_authors').insert({
id: ObjectId.generate(),
post_id: testUtils.DataGenerator.forKnex.posts[0].id,
author_id: testUtils.DataGenerator.forKnex.users[1].id
});
});
beforeEach(function () {
localSettingsCache.permalinks = '/:slug/';
});
@ -396,7 +363,8 @@ describe('Post API', function () {
post.primary_author.slug.should.eql('joe-bloggs');
});
_.find(results.posts, {id: testUtils.DataGenerator.forKnex.posts[0].id}).authors.length.should.eql(2);
_.find(results.posts, {id: testUtils.DataGenerator.forKnex.posts[0].id}).authors.length.should.eql(1);
_.find(results.posts, {id: testUtils.DataGenerator.forKnex.posts[3].id}).authors.length.should.eql(2);
done();
}).catch(done);
@ -682,6 +650,10 @@ describe('Post API', function () {
});
describe('Destroy', function () {
beforeEach(testUtils.teardown);
beforeEach(testUtils.setup('users:roles', 'perms:post', 'perms:init', 'posts'));
after(testUtils.teardown);
it('can delete a post', function (done) {
var options = {
context: {user: testUtils.DataGenerator.Content.users[1].id},
@ -717,6 +689,10 @@ describe('Post API', function () {
});
describe('Edit', function () {
beforeEach(testUtils.teardown);
beforeEach(testUtils.setup('users:roles', 'perms:post', 'perms:init', 'posts'));
after(testUtils.teardown);
it('can edit own post', function (done) {
PostAPI.edit({posts: [{status: 'test'}]}, {
context: {user: testUtils.DataGenerator.Content.users[1].id},

View file

@ -7,8 +7,9 @@ var should = require('should'),
describe('Roles API', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('users:roles', 'perms:role', 'perms:init'));
after(testUtils.teardown);
before(testUtils.setup('users:roles', 'perms:role', 'perms:init'));
describe('Browse', function () {
function checkBrowseResponse(response) {

View file

@ -174,7 +174,7 @@ describe('Schedules API', function () {
describe('fn: publishPost', function () {
var originalCannotScheduleAPostBeforeInMinutes;
beforeEach(function (done) {
before(function (done) {
originalCannotScheduleAPostBeforeInMinutes = config.get('times').cannotScheduleAPostBeforeInMinutes;
// we can insert published_at less then 5minutes
@ -407,7 +407,7 @@ describe('Schedules API', function () {
});
it('other user has no access', function (done) {
testUtils.fixtures.insertOne('users', 'createUser', 4)
testUtils.fixtures.insertOne('User', 'users', 'createUser', 4)
.then(function (result) {
api.schedules.publishPost({id: scope.posts[0].id, context: {user: result[0]}})
.then(function () {

View file

@ -13,8 +13,8 @@ var should = require('should'),
describe('Settings API', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('users:roles', 'perms:setting', 'settings', 'perms:init'));
after(testUtils.teardown);
before(testUtils.setup('settings', 'users:roles', 'perms:setting', 'perms:init'));
should.exist(SettingsAPI);

View file

@ -6,9 +6,9 @@ var should = require('should'),
describe('Slug API', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
after(testUtils.teardown);
beforeEach(testUtils.setup('users:roles', 'perms:slug', 'perms:init'));
before(testUtils.setup('settings', 'users:roles', 'perms:slug', 'perms:init'));
should.exist(SlugAPI);

View file

@ -14,17 +14,27 @@ var should = require('should'),
describe('Subscribers API', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
after(testUtils.teardown);
afterEach(function () {
sandbox.restore();
});
beforeEach(testUtils.setup('users:roles', 'perms:subscriber', 'perms:init', 'posts', 'subscriber'));
before(testUtils.setup('settings', 'users:roles', 'perms:subscriber', 'perms:init', 'posts'));
should.exist(SubscribersAPI);
describe('Add', function () {
var newSubscriber;
beforeEach(function () {
return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber');
});
afterEach(function () {
return testUtils.truncate('subscribers');
});
beforeEach(function () {
newSubscriber = _.clone(testUtils.DataGenerator.forKnex.createSubscriber(testUtils.DataGenerator.Content.subscribers[1]));
Promise.resolve(newSubscriber);
@ -95,6 +105,14 @@ describe('Subscribers API', function () {
});
describe('Edit', function () {
beforeEach(function () {
return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber');
});
afterEach(function () {
return testUtils.truncate('subscribers');
});
var newSubscriberEmail = 'subscriber@updated.com',
firstSubscriber = testUtils.DataGenerator.Content.subscribers[0].id;
@ -153,6 +171,14 @@ describe('Subscribers API', function () {
});
describe('Destroy', function () {
beforeEach(function () {
return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber');
});
afterEach(function () {
return testUtils.truncate('subscribers');
});
var firstSubscriber = testUtils.DataGenerator.Content.subscribers[0];
it('can destroy subscriber as admin', function (done) {
@ -197,6 +223,14 @@ describe('Subscribers API', function () {
});
describe('Browse', function () {
beforeEach(function () {
return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber');
});
afterEach(function () {
return testUtils.truncate('subscribers');
});
it('can browse (internal)', function (done) {
SubscribersAPI.browse(testUtils.context.internal).then(function (results) {
should.exist(results);
@ -229,6 +263,14 @@ describe('Subscribers API', function () {
});
describe('Read', function () {
beforeEach(function () {
return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber');
});
afterEach(function () {
return testUtils.truncate('subscribers');
});
it('with id', function (done) {
SubscribersAPI.browse({context: {user: 1}}).then(function (results) {
should.exist(results);
@ -275,6 +317,14 @@ describe('Subscribers API', function () {
describe('Read CSV', function () {
var scope = {};
beforeEach(function () {
return testUtils.fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber');
});
afterEach(function () {
return testUtils.truncate('subscribers');
});
beforeEach(function () {
sandbox.stub(fs, 'unlink').resolves();
sandbox.stub(fsLib, 'readCSV').value(function () {

View file

@ -17,14 +17,23 @@ function onlyFixtures(slug) {
describe('Tags API', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('users:roles', 'perms:tag', 'perms:init', 'posts'));
after(testUtils.teardown);
before(testUtils.setup('settings', 'users:roles', 'perms:tag', 'perms:init'));
should.exist(TagAPI);
describe('Add', function () {
var newTag;
beforeEach(function () {
return testUtils.fixtures.insertTags();
});
afterEach(function () {
return testUtils.truncate('tags');
});
beforeEach(function () {
newTag = _.clone(_.omit(testUtils.DataGenerator.forKnex.createTag(testUtils.DataGenerator.Content.tags[0]), 'id'));
});
@ -108,6 +117,14 @@ describe('Tags API', function () {
});
describe('Edit', function () {
beforeEach(function () {
return testUtils.fixtures.insertTags();
});
afterEach(function () {
return testUtils.truncate('tags');
});
var newTagName = 'tagNameUpdated',
firstTag = testUtils.DataGenerator.Content.tags[0].id;
@ -163,6 +180,14 @@ describe('Tags API', function () {
});
describe('Destroy', function () {
beforeEach(function () {
return testUtils.fixtures.insertTags();
});
afterEach(function () {
return testUtils.truncate('tags');
});
var firstTag = testUtils.DataGenerator.Content.tags[0].id;
it('can destroy Tag', function (done) {
@ -176,10 +201,14 @@ describe('Tags API', function () {
});
describe('Browse', function () {
beforeEach(function (done) {
testUtils.fixtures.insertExtraTags().then(function () {
done();
});
before(function () {
return testUtils.fixtures.insertPostsAndTags();
});
after(testUtils.teardown);
before(function () {
return testUtils.fixtures.insertExtraTags();
});
it('can browse (internal)', function (done) {
@ -356,6 +385,8 @@ describe('Tags API', function () {
});
describe('Read', function () {
before(testUtils.setup('users:roles', 'posts'));
it('returns count.posts with include count.posts', function (done) {
TagAPI.read({context: {user: 1}, include: 'count.posts', slug: 'kitchen-sink'}).then(function (results) {
should.exist(results);

View file

@ -19,6 +19,10 @@ describe('Users API', function () {
// Keep the DB clean
before(testUtils.teardown);
before(testUtils.setup(
'settings', 'users:roles', 'users:extra', 'user-token', 'perms:user', 'perms:role', 'perms:setting', 'perms:init', 'posts'
));
beforeEach(function () {
eventsTriggered = {};
@ -31,15 +35,12 @@ describe('Users API', function () {
});
});
beforeEach(testUtils.setup(
'users:roles', 'users:extra', 'user-token', 'perms:user', 'perms:role', 'perms:setting', 'perms:init', 'posts'
));
afterEach(function () {
sandbox.restore();
return testUtils.teardown();
});
after(testUtils.teardown);
function checkForErrorType(type, done) {
return function checkForErrorType(error) {
if (error.errorType) {
@ -51,20 +52,6 @@ describe('Users API', function () {
};
}
it('dateTime fields are returned as Date objects', function (done) {
var userData = testUtils.DataGenerator.forModel.users[0];
models.User.check({email: userData.email, password: userData.password}).then(function (user) {
return UserAPI.read(_.merge({id: user.id}, context.internal));
}).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_seen.should.be.an.instanceof(Date);
done();
}).catch(done);
});
describe('Browse', function () {
function checkBrowseResponse(response, count, additional, missing, only, options) {
should.exist(response);
@ -519,6 +506,20 @@ describe('Users API', function () {
}).catch(done);
});
it('dateTime fields are returned as Date objects', function (done) {
var userData = testUtils.DataGenerator.forModel.users[0];
models.User.check({email: userData.email, password: userData.password}).then(function (user) {
return UserAPI.read(_.merge({id: user.id}, context.internal));
}).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_seen.should.be.an.instanceof(Date);
done();
}).catch(done);
});
describe('Change status', function () {
describe('as owner', function () {
it('[success] can change status to inactive for admin', function () {
@ -841,7 +842,15 @@ describe('Users API', function () {
});
describe('Destroy', function () {
before(testUtils.teardown);
describe('General Tests', function () {
beforeEach(testUtils.setup(
'settings', 'users:roles', 'users:extra', 'user-token', 'perms:user', 'perms:role', 'perms:setting', 'perms:init', 'posts'
));
afterEach(testUtils.teardown);
it('ensure posts get deleted', function (done) {
var postIdsToDelete = [], postIsToKeep = [], options = {};
@ -971,160 +980,168 @@ describe('Users API', function () {
});
});
describe('Owner', function () {
it('CANNOT destroy self', function (done) {
UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.owner}))
.then(function () {
done(new Error('Owner should not be able to delete itself'));
}).catch(checkForErrorType('NoPermissionError', done));
});
describe('Permissions', function () {
beforeEach(testUtils.setup(
'settings', 'users:roles', 'users:extra', 'perms:user', 'perms:role', 'perms:setting', 'perms:init'
));
it('Can destroy admin, editor, author, contributor', function (done) {
// Admin
UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.admin}))
.then(function (response) {
should.not.exist(response);
// Editor
return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.editor}));
}).then(function (response) {
should.not.exist(response);
afterEach(testUtils.teardown);
// Author
return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.author}));
}).then(function (response) {
should.not.exist(response);
describe('Owner', function () {
it('CANNOT destroy self', function (done) {
UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.owner}))
.then(function () {
done(new Error('Owner should not be able to delete itself'));
}).catch(checkForErrorType('NoPermissionError', done));
});
// Contributor
return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.contributor}));
}).then(function (response) {
should.not.exist(response);
done();
}).catch(done);
});
});
describe('Admin', function () {
it('CANNOT destroy owner', function (done) {
UserAPI.destroy(_.extend({}, context.admin, {id: userIdFor.owner}))
.then(function () {
done(new Error('Admin should not be able to delete owner'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('Can destroy admin, editor, author, contributor', function (done) {
// Admin
UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[0].id}))
.then(function (response) {
it('Can destroy admin, editor, author, contributor', function (done) {
// Admin
UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.admin}))
.then(function (response) {
should.not.exist(response);
// Editor
return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.editor}));
}).then(function (response) {
should.not.exist(response);
// Editor
return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[1].id}));
// Author
return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.author}));
}).then(function (response) {
should.not.exist(response);
should.not.exist(response);
// Author
return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[2].id}));
}).then(function (response) {
should.not.exist(response);
// Contributor
return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[3].id}));
}).then(function (response) {
should.not.exist(response);
done();
}).catch(done);
});
});
describe('Editor', function () {
it('CANNOT destroy owner', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.owner}))
.then(function () {
done(new Error('Editor should not be able to delete owner'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy admin', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.admin}))
.then(function () {
done(new Error('Editor should not be able to delete admin'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy other editor', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: testUtils.DataGenerator.Content.extraUsers[1].id}))
.then(function () {
done(new Error('Editor should not be able to delete other editor'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('Can destroy self', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.editor}))
.then(function (response) {
// Contributor
return UserAPI.destroy(_.extend({}, context.owner, {id: userIdFor.contributor}));
}).then(function (response) {
should.not.exist(response);
done();
}).catch(done);
});
});
it('Can destroy author', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.author}))
.then(function (response) {
describe('Admin', function () {
it('CANNOT destroy owner', function (done) {
UserAPI.destroy(_.extend({}, context.admin, {id: userIdFor.owner}))
.then(function () {
done(new Error('Admin should not be able to delete owner'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('Can destroy admin, editor, author, contributor', function (done) {
// Admin
UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[0].id}))
.then(function (response) {
should.not.exist(response);
// Editor
return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[1].id}));
}).then(function (response) {
should.not.exist(response);
// Author
return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[2].id}));
}).then(function (response) {
should.not.exist(response);
// Contributor
return UserAPI.destroy(_.extend({}, context.admin, {id: testUtils.DataGenerator.Content.extraUsers[3].id}));
}).then(function (response) {
should.not.exist(response);
done();
}).catch(done);
});
});
describe('Author', function () {
it('CANNOT destroy owner', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.owner}))
.then(function () {
done(new Error('Author should not be able to delete owner'));
}).catch(checkForErrorType('NoPermissionError', done));
});
});
it('CANNOT destroy admin', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.admin}))
.then(function () {
done(new Error('Author should not be able to delete admin'));
}).catch(checkForErrorType('NoPermissionError', done));
describe('Editor', function () {
it('CANNOT destroy owner', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.owner}))
.then(function () {
done(new Error('Editor should not be able to delete owner'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy admin', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.admin}))
.then(function () {
done(new Error('Editor should not be able to delete admin'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy other editor', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: testUtils.DataGenerator.Content.extraUsers[1].id}))
.then(function () {
done(new Error('Editor should not be able to delete other editor'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('Can destroy self', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.editor}))
.then(function (response) {
should.not.exist(response);
done();
}).catch(done);
});
it('Can destroy author', function (done) {
UserAPI.destroy(_.extend({}, context.editor, {id: userIdFor.author}))
.then(function (response) {
should.not.exist(response);
done();
}).catch(done);
});
});
it('CANNOT destroy editor', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.editor}))
.then(function () {
done(new Error('Author should not be able to delete editor'));
}).catch(checkForErrorType('NoPermissionError', done));
describe('Author', function () {
it('CANNOT destroy owner', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.owner}))
.then(function () {
done(new Error('Author should not be able to delete owner'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy admin', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.admin}))
.then(function () {
done(new Error('Author should not be able to delete admin'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy editor', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.editor}))
.then(function () {
done(new Error('Author should not be able to delete editor'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy other author', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: testUtils.DataGenerator.Content.extraUsers[2].id}))
.then(function () {
done(new Error('Author should not be able to delete other author'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy self', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.author}))
.then(function () {
done(new Error('Author should not be able to delete self'));
}).catch(checkForErrorType('NoPermissionError', done));
});
});
it('CANNOT destroy other author', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: testUtils.DataGenerator.Content.extraUsers[2].id}))
.then(function () {
done(new Error('Author should not be able to delete other author'));
}).catch(checkForErrorType('NoPermissionError', done));
});
describe('Contributor', function () {
it('CANNOT destroy owner', function (done) {
UserAPI.destroy(_.extend({}, context.contributor, {id: userIdFor.owner}))
.then(function () {
done(new Error('Contributor should not be able to delete owner'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy self', function (done) {
UserAPI.destroy(_.extend({}, context.author, {id: userIdFor.author}))
.then(function () {
done(new Error('Author should not be able to delete self'));
}).catch(checkForErrorType('NoPermissionError', done));
});
});
describe('Contributor', function () {
it('CANNOT destroy owner', function (done) {
UserAPI.destroy(_.extend({}, context.contributor, {id: userIdFor.owner}))
.then(function () {
done(new Error('Contributor should not be able to delete owner'));
}).catch(checkForErrorType('NoPermissionError', done));
});
it('CANNOT destroy self', function (done) {
UserAPI.destroy(_.extend({}, context.contributor, {id: userIdFor.contributor}))
.then(function () {
done(new Error('Contributor should not be able to delete self'));
}).catch(checkForErrorType('NoPermissionError', done));
it('CANNOT destroy self', function (done) {
UserAPI.destroy(_.extend({}, context.contributor, {id: userIdFor.contributor}))
.then(function () {
done(new Error('Contributor should not be able to delete self'));
}).catch(checkForErrorType('NoPermissionError', done));
});
});
});
});
@ -1132,6 +1149,18 @@ describe('Users API', function () {
describe('Edit and assign role', function () {
var newName = 'Jo McBlogger';
before(testUtils.teardown);
before(testUtils.setup(
'settings', 'users:roles', 'users:extra', 'perms:user', 'perms:role', 'perms:setting', 'perms:init'
));
beforeEach(function () {
return testUtils.fixtures.resetRoles();
});
after(testUtils.teardown);
function checkEditResponse(response) {
should.exist(response);
should.not.exist(response.meta);
@ -1465,6 +1494,14 @@ describe('Users API', function () {
});
describe('Transfer ownership', function () {
before(testUtils.teardown);
beforeEach(testUtils.setup(
'settings', 'users:roles', 'perms:user', 'perms:role', 'perms:setting', 'perms:init'
));
afterEach(testUtils.teardown);
it('Owner can transfer ownership', function (done) {
// transfer ownership to admin user id:2
UserAPI.transferOwnership(
@ -1564,6 +1601,14 @@ describe('Users API', function () {
});
describe('Change Password', function () {
before(testUtils.teardown);
beforeEach(testUtils.setup(
'settings', 'users:roles', 'perms:user', 'perms:role', 'perms:setting', 'perms:init'
));
afterEach(testUtils.teardown);
it('Owner can change own password', function (done) {
var payload = {
password: [{

View file

@ -243,31 +243,36 @@ describe('Import', function () {
// user should still have the credentials from the original insert, not the import
users[0].email.should.equal(testUtils.DataGenerator.Content.users[0].email);
users[0].password.should.equal(testUtils.DataGenerator.Content.users[0].password);
// but the name, slug, and bio should have been overridden
users[0].name.should.equal(exportData.data.users[0].name);
users[0].slug.should.equal(exportData.data.users[0].slug);
should.not.exist(users[0].bio, 'bio is not imported');
// import no longer requires all data to be dropped, and adds posts
posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts');
models.User.isPasswordCorrect({
hashedPassword: users[0].password,
plainPassword: testUtils.DataGenerator.Content.users[0].password
}).then(function () {
// but the name, slug, and bio should have been overridden
users[0].name.should.equal(exportData.data.users[0].name);
users[0].slug.should.equal(exportData.data.users[0].slug);
should.not.exist(users[0].bio, 'bio is not imported');
// active_theme should NOT have been overridden
_.find(settings, {key: 'active_theme'}).value.should.equal('casper', 'Wrong theme');
// import no longer requires all data to be dropped, and adds posts
posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts');
// test tags
tags.length.should.equal(exportData.data.tags.length, 'no new tags');
// active_theme should NOT have been overridden
_.find(settings, {key: 'active_theme'}).value.should.equal('casper', 'Wrong theme');
// Ensure imported post retains set timestamp
// 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 consistent for all DBs.
assert.equal(moment(posts[0].created_at).valueOf(), 1388318310000);
assert.equal(moment(posts[0].updated_at).valueOf(), 1388318310000);
assert.equal(moment(posts[0].published_at).valueOf(), 1388404710000);
// test tags
tags.length.should.equal(exportData.data.tags.length, 'no new tags');
done();
// Ensure imported post retains set timestamp
// 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 consistent for all DBs.
assert.equal(moment(posts[0].created_at).valueOf(), 1388318310000);
assert.equal(moment(posts[0].updated_at).valueOf(), 1388318310000);
assert.equal(moment(posts[0].published_at).valueOf(), 1388404710000);
done();
});
}).catch(done);
});
@ -341,32 +346,37 @@ describe('Import', function () {
// user should still have the credentials from the original insert, not the import
users[0].email.should.equal(testUtils.DataGenerator.Content.users[0].email);
users[0].password.should.equal(testUtils.DataGenerator.Content.users[0].password);
// but the name, slug, and bio should have been overridden
users[0].name.should.equal(exportData.data.users[0].name);
users[0].slug.should.equal(exportData.data.users[0].slug);
should.not.exist(users[0].bio, 'bio is not imported');
// import no longer requires all data to be dropped, and adds posts
posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts');
posts[0].comment_id.should.eql(exportData.data.posts[0].id.toString());
models.User.isPasswordCorrect({
hashedPassword: users[0].password,
plainPassword: testUtils.DataGenerator.Content.users[0].password
}).then(function () {
// but the name, slug, and bio should have been overridden
users[0].name.should.equal(exportData.data.users[0].name);
users[0].slug.should.equal(exportData.data.users[0].slug);
should.not.exist(users[0].bio, 'bio is not imported');
// active_theme should NOT have been overridden
_.find(settings, {key: 'active_theme'}).value.should.equal('casper', 'Wrong theme');
// import no longer requires all data to be dropped, and adds posts
posts.length.should.equal(exportData.data.posts.length, 'Wrong number of posts');
posts[0].comment_id.should.eql(exportData.data.posts[0].id.toString());
// test tags
tags.length.should.equal(exportData.data.tags.length, 'no new tags');
// active_theme should NOT have been overridden
_.find(settings, {key: 'active_theme'}).value.should.equal('casper', 'Wrong theme');
// Ensure imported post retains set timestamp
// 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(moment(posts[0].created_at).valueOf(), 1419940710000);
assert.equal(moment(posts[0].updated_at).valueOf(), 1420027110000);
assert.equal(moment(posts[0].published_at).valueOf(), 1420027110000);
// test tags
tags.length.should.equal(exportData.data.tags.length, 'no new tags');
done();
// Ensure imported post retains set timestamp
// 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(moment(posts[0].created_at).valueOf(), 1419940710000);
assert.equal(moment(posts[0].updated_at).valueOf(), 1420027110000);
assert.equal(moment(posts[0].published_at).valueOf(), 1420027110000);
done();
});
}).catch(done);
});
});
@ -398,18 +408,23 @@ describe('Import', function () {
// user should still have the credentials from the original insert, not the import
users[0].email.should.equal(testUtils.DataGenerator.Content.users[0].email);
users[0].password.should.equal(testUtils.DataGenerator.Content.users[0].password);
// but the name, slug, and bio should have been overridden
users[0].name.should.equal(exportData.data.users[0].name);
users[0].slug.should.equal(exportData.data.users[0].slug);
should.not.exist(users[0].bio, 'bio is not imported');
// test posts
posts.length.should.equal(1, 'Wrong number of posts');
// test tags
tags.length.should.equal(1, 'no new tags');
models.User.isPasswordCorrect({
hashedPassword: users[0].password,
plainPassword: testUtils.DataGenerator.Content.users[0].password
}).then(function () {
// but the name, slug, and bio should have been overridden
users[0].name.should.equal(exportData.data.users[0].name);
users[0].slug.should.equal(exportData.data.users[0].slug);
should.not.exist(users[0].bio, 'bio is not imported');
done();
// test posts
posts.length.should.equal(1, 'Wrong number of posts');
// test tags
tags.length.should.equal(1, 'no new tags');
done();
});
}).catch(done);
});
@ -501,23 +516,28 @@ describe('Import', function () {
// user should still have the credentials from the original insert, not the import
users[0].email.should.equal(testUtils.DataGenerator.Content.users[0].email);
users[0].password.should.equal(testUtils.DataGenerator.Content.users[0].password);
// but the name, slug, and bio should have been overridden
users[0].name.should.equal('Joe Bloggs');
users[0].slug.should.equal('joe-bloggs');
should.not.exist(users[0].bio, 'bio is not imported');
// test posts
posts.length.should.equal(1, 'Wrong number of posts');
models.User.isPasswordCorrect({
hashedPassword: users[0].password,
plainPassword: testUtils.DataGenerator.Content.users[0].password
}).then(function () {
// but the name, slug, and bio should have been overridden
users[0].name.should.equal('Joe Bloggs');
users[0].slug.should.equal('joe-bloggs');
should.not.exist(users[0].bio, 'bio is not imported');
// we fallback to owner user
// NOTE: ember can handle unknown author_id, but still a fallback to an existing user is better.
posts[0].author_id.should.eql('1');
// test posts
posts.length.should.equal(1, 'Wrong number of posts');
// test tags
tags.length.should.equal(0, 'no tags');
// we fallback to owner user
// NOTE: ember can handle unknown author_id, but still a fallback to an existing user is better.
posts[0].author_id.should.eql('1');
done();
// test tags
tags.length.should.equal(0, 'no tags');
done();
});
}).catch(done);
});
@ -861,42 +881,47 @@ describe('Import (new test structure)', function () {
});
ownerUser.email.should.equal(testUtils.DataGenerator.Content.users[0].email);
ownerUser.password.should.equal(testUtils.DataGenerator.Content.users[0].password);
ownerUser.status.should.equal('active');
user1.email.should.equal(exportData.data.users[0].email);
user2.email.should.equal(exportData.data.users[1].email);
user3.email.should.equal(exportData.data.users[2].email);
models.User.isPasswordCorrect({
hashedPassword: users[0].password,
plainPassword: testUtils.DataGenerator.Content.users[0].password
}).then(function () {
ownerUser.status.should.equal('active');
// Newly created users should have a status of locked
user2.status.should.equal('locked');
user3.status.should.equal('locked');
user1.email.should.equal(exportData.data.users[0].email);
user2.email.should.equal(exportData.data.users[1].email);
user3.email.should.equal(exportData.data.users[2].email);
// Newly created users should have created_at/_by and updated_at/_by set to when they were imported
user2.created_by.should.equal(user1.id);
user2.created_at.should.not.equal(exportData.data.users[1].created_at);
user2.updated_by.should.equal(ownerUser.id);
user2.updated_at.should.not.equal(exportData.data.users[1].updated_at);
user3.created_by.should.equal(user1.id);
user3.created_at.should.not.equal(exportData.data.users[2].created_at);
user3.updated_by.should.equal(ownerUser.id);
user3.updated_at.should.not.equal(exportData.data.users[2].updated_at);
// Newly created users should have a status of locked
user2.status.should.equal('locked');
user3.status.should.equal('locked');
rolesUsers.length.should.equal(4, 'There should be 4 role relations');
// Newly created users should have created_at/_by and updated_at/_by set to when they were imported
user2.created_by.should.equal(user1.id);
user2.created_at.should.not.equal(exportData.data.users[1].created_at);
user2.updated_by.should.equal(ownerUser.id);
user2.updated_at.should.not.equal(exportData.data.users[1].updated_at);
user3.created_by.should.equal(user1.id);
user3.created_at.should.not.equal(exportData.data.users[2].created_at);
user3.updated_by.should.equal(ownerUser.id);
user3.updated_at.should.not.equal(exportData.data.users[2].updated_at);
_.each(rolesUsers, function (roleUser) {
if (roleUser.user_id === ownerUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner');
}
if (roleUser.user_id === user2.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Josephine should be an admin');
}
if (roleUser.user_id === user3.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[2].id, 'Smith should be an author by default');
}
rolesUsers.length.should.equal(4, 'There should be 4 role relations');
_.each(rolesUsers, function (roleUser) {
if (roleUser.user_id === ownerUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner');
}
if (roleUser.user_id === user2.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Josephine should be an admin');
}
if (roleUser.user_id === user3.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[2].id, 'Smith should be an author by default');
}
});
done();
});
done();
}).catch(done);
});
@ -1098,40 +1123,45 @@ describe('Import (new test structure)', function () {
});
user1.email.should.equal(testUtils.DataGenerator.Content.users[0].email);
user1.password.should.equal(testUtils.DataGenerator.Content.users[0].password);
user1.status.should.equal('active');
user2.email.should.equal(exportData.data.users[0].email);
user3.email.should.equal(exportData.data.users[1].email);
// Newly created users should have a status of locked
user2.status.should.equal('locked');
user3.status.should.equal('locked');
models.User.isPasswordCorrect({
hashedPassword: users[0].password,
plainPassword: testUtils.DataGenerator.Content.users[0].password
}).then(function () {
user1.status.should.equal('active');
user2.email.should.equal(exportData.data.users[0].email);
user3.email.should.equal(exportData.data.users[1].email);
// Newly created users should have created_at/_by and updated_at/_by set to when they were imported
user2.created_by.should.equal(user1.id);
user2.created_at.should.not.equal(exportData.data.users[0].created_at);
user2.updated_by.should.equal(user1.id);
user2.updated_at.should.not.equal(exportData.data.users[0].updated_at);
user3.created_by.should.equal(user1.id);
user3.created_at.should.not.equal(exportData.data.users[1].created_at);
user3.updated_by.should.equal(user1.id);
user3.updated_at.should.not.equal(exportData.data.users[1].updated_at);
// Newly created users should have a status of locked
user2.status.should.equal('locked');
user3.status.should.equal('locked');
rolesUsers.length.should.equal(3, 'There should be 3 role relations');
// Newly created users should have created_at/_by and updated_at/_by set to when they were imported
user2.created_by.should.equal(user1.id);
user2.created_at.should.not.equal(exportData.data.users[0].created_at);
user2.updated_by.should.equal(user1.id);
user2.updated_at.should.not.equal(exportData.data.users[0].updated_at);
user3.created_by.should.equal(user1.id);
user3.created_at.should.not.equal(exportData.data.users[1].created_at);
user3.updated_by.should.equal(user1.id);
user3.updated_at.should.not.equal(exportData.data.users[1].updated_at);
_.each(rolesUsers, function (roleUser) {
if (roleUser.user_id === user1.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner');
}
if (roleUser.user_id === user2.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Josephine should be an admin');
}
if (roleUser.user_id === user3.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[2].id, 'Smith should be an author by default');
}
rolesUsers.length.should.equal(3, 'There should be 3 role relations');
_.each(rolesUsers, function (roleUser) {
if (roleUser.user_id === user1.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner');
}
if (roleUser.user_id === user2.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Josephine should be an admin');
}
if (roleUser.user_id === user3.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[2].id, 'Smith should be an author by default');
}
});
done();
});
done();
}).catch(done);
});
@ -1331,40 +1361,45 @@ describe('Import (new test structure)', function () {
});
ownerUser.email.should.equal(testUtils.DataGenerator.Content.users[0].email);
ownerUser.password.should.equal(testUtils.DataGenerator.Content.users[0].password);
ownerUser.status.should.equal('active');
newUser.email.should.equal(exportData.data.users[1].email);
existingUser.email.should.equal(exportData.data.users[2].email);
// Newly created users should have a status of locked
newUser.status.should.equal('locked');
// The already existing user should still have a status of active
existingUser.status.should.equal('active');
models.User.isPasswordCorrect({
hashedPassword: users[0].password,
plainPassword: testUtils.DataGenerator.Content.users[0].password
}).then(function () {
ownerUser.status.should.equal('active');
newUser.email.should.equal(exportData.data.users[1].email);
existingUser.email.should.equal(exportData.data.users[2].email);
// Newly created users should have created_at/_by and updated_at/_by set to when they were imported
newUser.created_by.should.equal(importedOwnerUser.id);
newUser.created_at.should.not.equal(exportData.data.users[1].created_at);
newUser.updated_by.should.equal(ownerUser.id);
newUser.updated_at.should.not.equal(exportData.data.users[1].updated_at);
// Newly created users should have a status of locked
newUser.status.should.equal('locked');
// The already existing user should still have a status of active
existingUser.status.should.equal('active');
rolesUsers.length.should.equal(7, 'There should be 7 role relations');
// Newly created users should have created_at/_by and updated_at/_by set to when they were imported
newUser.created_by.should.equal(importedOwnerUser.id);
newUser.created_at.should.not.equal(exportData.data.users[1].created_at);
newUser.updated_by.should.equal(ownerUser.id);
newUser.updated_at.should.not.equal(exportData.data.users[1].updated_at);
_.each(rolesUsers, function (roleUser) {
if (roleUser.user_id === ownerUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner');
}
if (roleUser.user_id === importedOwnerUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Imported owner should be an admin now.');
}
if (roleUser.user_id === newUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'New user should be an admin');
}
if (roleUser.user_id === existingUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Existing user was an admin');
}
rolesUsers.length.should.equal(7, 'There should be 7 role relations');
_.each(rolesUsers, function (roleUser) {
if (roleUser.user_id === ownerUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[3].id, 'Original user should be an owner');
}
if (roleUser.user_id === importedOwnerUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Imported owner should be an admin now.');
}
if (roleUser.user_id === newUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'New user should be an admin');
}
if (roleUser.user_id === existingUser.id) {
roleUser.role_id.should.equal(testUtils.DataGenerator.Content.roles[0].id, 'Existing user was an admin');
}
});
done();
});
done();
}).catch(done);
});

View file

@ -18,7 +18,7 @@ describe('Accesstoken Model', function () {
sandbox.restore();
});
beforeEach(testUtils.setup('users:roles', 'clients'));
beforeEach(testUtils.setup('owner', 'clients'));
it('on creation emits token.added event', function (done) {
// Setup

View file

@ -8,8 +8,8 @@ var should = require('should'),
describe('App Fields Model', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('app_field'));
after(testUtils.teardown);
before(testUtils.setup('app_field'));
before(function () {
should.exist(AppFieldsModel);

View file

@ -8,8 +8,8 @@ var should = require('should'),
describe('App Setting Model', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('app_setting'));
after(testUtils.teardown);
before(testUtils.setup('app_setting'));
before(function () {
should.exist(AppSettingModel);

View file

@ -10,8 +10,8 @@ var should = require('should'),
describe('App Model', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('app'));
after(testUtils.teardown);
before(testUtils.setup('app'));
before(function () {
should.exist(AppModel);

View file

@ -8,8 +8,8 @@ var should = require('should'),
describe('Permission Model', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('permission'));
after(testUtils.teardown);
before(testUtils.setup('permission'));
before(function () {
should.exist(PermissionModel);

File diff suppressed because it is too large Load diff

View file

@ -15,8 +15,8 @@ describe('Tag Model', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('users:roles', 'posts'));
after(testUtils.teardown);
before(testUtils.setup('users:roles', 'posts'));
afterEach(function () {
sandbox.restore();
@ -26,33 +26,6 @@ describe('Tag Model', function () {
eventSpy = sandbox.spy(common.events, 'emit');
});
describe('add', function () {
it('uses Date objects for dateTime fields', function (done) {
models.Tag.add(_.omit(testUtils.DataGenerator.forModel.tags[0], 'id'), context)
.then(function (tag) {
return models.Tag.findOne({id: tag.id});
})
.then(function (tag) {
should.exist(tag);
tag.get('created_at').should.be.an.instanceof(Date);
done();
})
.catch(done);
});
it('returns count.posts if include count.posts', function (done) {
models.Tag.findOne({slug: 'kitchen-sink'}, {withRelated: ['count.posts']})
.then(function (tag) {
should.exist(tag);
tag.toJSON().count.posts.should.equal(2);
done();
})
.catch(done);
});
});
describe('findPage', function () {
it('with limit all', function (done) {
models.Tag.findPage({limit: 'all'})
@ -104,6 +77,33 @@ describe('Tag Model', function () {
});
});
describe('add', function () {
it('uses Date objects for dateTime fields', function (done) {
models.Tag.add(_.omit(testUtils.DataGenerator.forModel.tags[0], 'id'), context)
.then(function (tag) {
return models.Tag.findOne({id: tag.id});
})
.then(function (tag) {
should.exist(tag);
tag.get('created_at').should.be.an.instanceof(Date);
done();
})
.catch(done);
});
it('returns count.posts if include count.posts', function (done) {
models.Tag.findOne({slug: 'kitchen-sink'}, {withRelated: ['count.posts']})
.then(function (tag) {
should.exist(tag);
tag.toJSON().count.posts.should.equal(2);
done();
})
.catch(done);
});
});
describe('destroy', function () {
it('can destroy Tag (using transaction)', function () {
var firstTag = testUtils.DataGenerator.Content.tags[0].id;

View file

@ -25,13 +25,15 @@ describe('Update Check', function () {
configUtils.restore();
});
after(testUtils.teardown);
describe('fn: updateCheck', function () {
var updateCheckRequestSpy,
updateCheckResponseSpy,
updateCheckErrorSpy;
beforeEach(testUtils.setup('owner', 'posts', 'perms:setting', 'perms:user', 'perms:init'));
afterEach(testUtils.teardown);
beforeEach(testUtils.teardown);
beforeEach(testUtils.setup('roles', 'owner'));
beforeEach(function () {
updateCheckRequestSpy = sandbox.stub().returns(Promise.resolve());
@ -107,9 +109,8 @@ describe('Update Check', function () {
configUtils.restore();
});
beforeEach(testUtils.setup('owner', 'settings', 'posts', 'perms:setting', 'perms:user', 'perms:init'));
afterEach(testUtils.teardown);
beforeEach(testUtils.teardown);
beforeEach(testUtils.setup('roles', 'owner', 'settings', 'posts', 'perms:setting', 'perms:user', 'perms:init'));
it('should report the correct data', function (done) {
var updateCheckData = updateCheck.__get__('updateCheckData');
@ -148,14 +149,13 @@ describe('Update Check', function () {
updateCheck.__set__('ghostVersion.original', currentVersionOrig);
});
beforeEach(testUtils.setup('owner', 'posts', 'settings', 'perms:setting', 'perms:notification', 'perms:user', 'perms:init'));
beforeEach(testUtils.teardown);
beforeEach(testUtils.setup('settings', 'roles', 'owner', 'perms:setting', 'perms:notification', 'perms:user', 'perms:init'));
beforeEach(function () {
return NotificationsAPI.destroyAll(testUtils.context.internal);
});
afterEach(testUtils.teardown);
it('should create a release notification for target version', function (done) {
var createCustomNotification = updateCheck.__get__('createCustomNotification'),
notification = {
@ -315,8 +315,8 @@ describe('Update Check', function () {
});
describe('fn: updateCheckResponse', function () {
beforeEach(testUtils.setup('settings', 'perms:setting', 'perms:init'));
afterEach(testUtils.teardown);
beforeEach(testUtils.teardown);
beforeEach(testUtils.setup('roles', 'settings', 'perms:setting', 'perms:init'));
it('receives a notifications with messages', function (done) {
var updateCheckResponse = updateCheck.__get__('updateCheckResponse'),

View file

@ -52,8 +52,8 @@ DataGenerator.Content = {
feature_image: 'http://placekitten.com/500/200',
meta_description: 'test stuff',
published_at: new Date('2015-01-03'),
uuid: '2ac6b4f6-e1f3-406c-9247-c94a0496d39d',
featured: true
featured: true,
uuid: '2ac6b4f6-e1f3-406c-9247-c94a0496d39d'
},
{
id: ObjectId.generate(),
@ -132,7 +132,7 @@ DataGenerator.Content = {
name: 'Joe Bloggs',
slug: 'joe-bloggs',
email: 'jbloggs@example.com',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS',
password: 'Sl1m3rson99',
profile_image: 'https://example.com/super_photo.jpg'
},
{
@ -141,7 +141,7 @@ DataGenerator.Content = {
name: 'Smith Wellingsworth',
slug: 'smith-wellingsworth',
email: 'swellingsworth@example.com',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS'
password: 'Sl1m3rson99'
},
{
// editor
@ -149,7 +149,7 @@ DataGenerator.Content = {
name: 'Jimothy Bogendath',
slug: 'jimothy-bogendath',
email: 'jbOgendAth@example.com',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS'
password: 'Sl1m3rson99'
},
{
// author
@ -157,7 +157,7 @@ DataGenerator.Content = {
name: 'Slimer McEctoplasm',
slug: 'slimer-mcectoplasm',
email: 'smcectoplasm@example.com',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS'
password: 'Sl1m3rson99'
},
{
// editor 2
@ -165,7 +165,7 @@ DataGenerator.Content = {
name: 'Ivan Email',
slug: 'ivan-email',
email: 'info1@ghost.org',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS'
password: 'Sl1m3rson99'
},
{
// author 2
@ -173,7 +173,7 @@ DataGenerator.Content = {
name: 'Author2',
slug: 'a-2',
email: 'info2@ghost.org',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS'
password: 'Sl1m3rson99'
},
{
// admin 2
@ -181,7 +181,7 @@ DataGenerator.Content = {
name: 'admin2',
slug: 'ad-2',
email: 'info3@ghost.org',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS'
password: 'Sl1m3rson99'
},
{
// contributor
@ -189,7 +189,7 @@ DataGenerator.Content = {
name: 'Contributor',
slug: 'contributor',
email: 'contributor@ghost.org',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS'
password: 'Sl1m3rson99'
},
{
// contributor
@ -197,7 +197,7 @@ DataGenerator.Content = {
name: 'contributor2',
slug: 'contrib-2',
email: 'contributor2@ghost.org',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS'
password: 'Sl1m3rson99'
}
],
@ -472,7 +472,7 @@ DataGenerator.forKnex = (function () {
name: 'name',
slug: 'slug_' + Date.now(),
status: 'active',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS',
password: 'Sl1m3rson99',
created_by: DataGenerator.Content.users[0].id,
created_at: new Date(),
updated_at: new Date(),
@ -505,7 +505,7 @@ DataGenerator.forKnex = (function () {
name: 'Joe Bloggs',
slug: 'joe-blogs',
email: 'joe_' + uniqueInteger + '@example.com',
password: '$2b$10$ujPIlqjTsYwfc2/zrqZXZ.yd7cQQm2iOkAFenTAJfveKkc23nwdeS'
password: 'Sl1m3rson99'
});
}

View file

@ -1,4 +1,5 @@
/*jshint expr:true*/
'use strict';
var Promise = require('bluebird'),
_ = require('lodash'),
fs = require('fs-extra'),
@ -12,8 +13,8 @@ var Promise = require('bluebird'),
KnexMigrator = require('knex-migrator'),
ghost = require('../../server'),
common = require('../../server/lib/common'),
db = require('../../server/data/db'),
fixtureUtils = require('../../server/data/schema/fixtures/utils'),
db = require('../../server/data/db'),
schema = require('../../server/data/schema').tables,
schemaTables = Object.keys(schema),
models = require('../../server/models'),
@ -41,6 +42,7 @@ var Promise = require('bluebird'),
unmockNotExistingModule,
teardown,
setup,
truncate,
doAuth,
createUser,
createPost,
@ -60,102 +62,72 @@ require('./assertions');
/** TEST FIXTURES **/
fixtures = {
insertPosts: function insertPosts(posts) {
return Promise.resolve(db.knex('posts').insert(posts));
return Promise.map(posts, function (post) {
return models.Post.add(post, module.exports.context.internal);
});
},
insertPostsAndTags: function insertPostsAndTags() {
return Promise.resolve(db.knex('posts').insert(DataGenerator.forKnex.posts)).then(function () {
return db.knex('tags').insert(DataGenerator.forKnex.tags);
return Promise.map(DataGenerator.forKnex.tags, function (tag) {
return models.Tag.add(tag, module.exports.context.internal);
}).then(function () {
return db.knex('posts_tags').insert(DataGenerator.forKnex.posts_tags);
}).then(function () {
return db.knex('posts_authors').insert(DataGenerator.forKnex.posts_authors)
.catch(function (err) {
var clonedPostsAuthors;
return Promise.map(_.cloneDeep(DataGenerator.forKnex.posts), function (post) {
let postTagRelations = _.filter(DataGenerator.forKnex.posts_tags, {post_id: post.id});
let postAuthorsRelations = _.filter(DataGenerator.forKnex.posts_authors, {post_id: post.id});
// CASE: routing tests insert extra posts, but some tests don't add the users from the data generator
// The only users which exist via the default Ghost fixtures are the Owner and the Ghost author
// This results a MySQL error: `ER_NO_REFERENCED_ROW_2`
// @TODO: rework if we overhaul the test env
if (err.errno === 1452) {
clonedPostsAuthors = _.cloneDeep(DataGenerator.forKnex.posts_authors);
// Fallback to owner user - this user does exist for sure
_.each(clonedPostsAuthors, function (postsAuthorRelation) {
postsAuthorRelation.author_id = DataGenerator.forKnex.users[0].id;
});
return db.knex('posts_authors').insert(clonedPostsAuthors);
}
throw err;
postTagRelations = _.map(postTagRelations, function (postTagRelation) {
return _.find(DataGenerator.forKnex.tags, {id: postTagRelation.tag_id});
});
postAuthorsRelations = _.map(postAuthorsRelations, function (postAuthorsRelation) {
return _.find(DataGenerator.forKnex.users, {id: postAuthorsRelation.author_id});
});
post.tags = postTagRelations;
post.authors = postAuthorsRelations;
return models.Post.add(post, module.exports.context.internal);
});
});
},
insertMultiAuthorPosts: function insertMultiAuthorPosts(max) {
/*jshint unused:false*/
var author,
authors,
i, j, k = postsInserted,
let i, j, k = 0,
posts = [];
max = max || 50;
// insert users of different roles
return Promise.resolve(fixtures.createUsersWithRoles()).then(function () {
// create the tags
return db.knex('tags').insert(DataGenerator.forKnex.tags);
return Promise.map(DataGenerator.forKnex.tags, function (tag) {
return models.Tag.add(tag, module.exports.context.internal);
});
}).then(function () {
return db.knex('users').select('id');
return Promise.all([
models.User.fetchAll(_.merge({columns: ['id']}, module.exports.context.internal)),
models.Tag.fetchAll(_.merge({columns: ['id']}, module.exports.context.internal))
]);
}).then(function (results) {
authors = _.map(results, 'id');
let users = results[0],
tags = results[1];
tags = tags.toJSON();
users = users.toJSON();
users = _.map(users, 'id');
// Let's insert posts with random authors
for (i = 0; i < max; i += 1) {
author = authors[i % authors.length];
const author = users[i % users.length];
posts.push(DataGenerator.forKnex.createGenericPost(k, null, null, author));
k = k + 1;
}
// Keep track so we can run this function again safely
postsInserted = k;
return sequence(_.times(posts.length, function (index) {
return function () {
return db.knex('posts').insert(posts[index])
.then(function () {
return db.knex('posts_authors').insert({
id: ObjectId.generate(),
post_id: posts[index].id,
author_id: posts[index].author_id
});
});
};
}));
}).then(function () {
return Promise.all([
db.knex('posts').orderBy('id', 'asc').select('id'),
db.knex('tags').select('id')
]);
}).then(function (results) {
var posts = _.map(results[0], 'id'),
tags = _.map(results[1], 'id'),
promises = [],
i;
if (max > posts.length) {
throw new Error('Trying to add more posts_tags than the number of posts. ' + max + ' ' + posts.length);
}
for (i = 0; i < max; i += 1) {
promises.push(DataGenerator.forKnex.createPostsTags(posts[i], tags[i % tags.length]));
}
return sequence(_.times(promises.length, function (index) {
return function () {
return db.knex('posts_tags').insert(promises[index]);
};
}));
return Promise.map(posts, function (post, index) {
posts[index].authors = [{id: posts[index].author_id}];
posts[index].tags = [tags[Math.floor(Math.random() * (tags.length - 1))]];
return models.Post.add(posts[index], module.exports.context.internal);
});
});
},
@ -182,22 +154,19 @@ fixtures = {
// Keep track so we can run this function again safely
postsInserted = k;
return sequence(_.times(posts.length, function (index) {
return function () {
return db.knex('posts').insert(posts[index])
.then(function () {
return db.knex('posts_authors').insert({
id: ObjectId.generate(),
post_id: posts[index].id,
author_id: posts[index].author_id
});
});
};
}));
return models.User.getOwnerUser(module.exports.context.internal)
.then(function (ownerUser) {
return Promise.map(posts, function (post, index) {
posts[index].authors = [ownerUser.toJSON()];
return models.Post.add(posts[index], module.exports.context.internal);
});
});
},
insertTags: function insertTags() {
return db.knex('tags').insert(DataGenerator.forKnex.tags);
return Promise.map(DataGenerator.forKnex.tags, function (tag) {
return models.Tag.add(tag, module.exports.context.internal);
});
},
insertExtraTags: function insertExtraTags(max) {
@ -211,46 +180,44 @@ fixtures = {
tags.push(DataGenerator.forKnex.createBasic({name: tagName, slug: tagName}));
}
return sequence(_.times(tags.length, function (index) {
return function () {
return db.knex('tags').insert(tags[index]);
};
}));
return Promise.map(tags, function (tag, index) {
return models.Tag.add(tags[index], module.exports.context.internal);
});
},
insertExtraPostsTags: function insertExtraPostsTags(max) {
max = max || 50;
return Promise.all([
db.knex('posts').orderBy('id', 'asc').select('id'),
db.knex('tags').select('id', 'name')
models.Post.fetchAll(_.merge({columns: ['id'], withRelated: 'tags'}, module.exports.context.internal)),
models.Tag.fetchAll(_.merge({columns: ['id', 'name']}, module.exports.context.internal))
]).then(function (results) {
var posts = _.map(results[0], 'id'),
injectionTagId = _.chain(results[1])
let posts = results[0].toJSON();
let tags = results[1].toJSON();
const injectionTagId = _.chain(tags)
.filter({name: 'injection'})
.map('id')
.value()[0],
promises = [],
i;
.value()[0];
if (max > posts.length) {
throw new Error('Trying to add more posts_tags than the number of posts.');
}
for (i = 0; i < max; i += 1) {
promises.push(DataGenerator.forKnex.createPostsTags(posts[i], injectionTagId));
}
return Promise.map(posts.slice(0, max), function (post) {
post.tags = post.tags ? post.tags : [];
return sequence(_.times(promises.length, function (index) {
return function () {
return db.knex('posts_tags').insert(promises[index]);
};
}));
return models.Post.edit({
tags: post.tags.concat([_.find(DataGenerator.Content.tags, {id: injectionTagId})])
}, _.merge({id: post.id}, module.exports.context.internal));
});
});
},
insertRoles: function insertRoles() {
return db.knex('roles').insert(DataGenerator.forKnex.roles);
return Promise.map(DataGenerator.forKnex.roles, function (role) {
return models.Role.add(role, module.exports.context.internal);
});
},
initOwnerUser: function initOwnerUser() {
@ -259,65 +226,89 @@ fixtures = {
user = DataGenerator.forKnex.createBasic(user);
user = _.extend({}, user, {status: 'inactive'});
return db.knex('roles').insert(DataGenerator.forKnex.roles).then(function () {
return db.knex('users').insert(user);
return Promise.map(DataGenerator.forKnex.roles, function (role) {
return models.Role.add(role, module.exports.context.internal);
}).then(function () {
return db.knex('roles_users').insert(DataGenerator.forKnex.roles_users[0]);
const userRolesRelation = _.cloneDeep(DataGenerator.forKnex.roles_users[0]);
user.roles = _.filter(DataGenerator.forKnex.roles, {id: userRolesRelation.role_id});
return models.User.add(user, module.exports.context.internal);
});
},
insertOwnerUser: function insertOwnerUser() {
var user;
user = DataGenerator.forKnex.createUser(DataGenerator.Content.users[0]);
return db.knex('users').insert(user).then(function () {
return db.knex('roles_users').insert(DataGenerator.forKnex.roles_users[0]);
});
const user = _.cloneDeep(DataGenerator.forKnex.users[0]);
user.roles = [DataGenerator.forKnex.roles[3]];
return models.User.add(user, module.exports.context.internal);
},
overrideOwnerUser: function overrideOwnerUser(slug) {
var user;
user = DataGenerator.forKnex.createUser(DataGenerator.Content.users[0]);
return models.User.getOwnerUser(module.exports.context.internal)
.then(function (ownerUser) {
var user = DataGenerator.forKnex.createUser(DataGenerator.Content.users[0]);
if (slug) {
user.slug = slug;
}
if (slug) {
user.slug = slug;
}
return db.knex('users')
.where('id', '=', DataGenerator.Content.users[0].id)
.update(user);
return models.User.edit(user, _.merge({id: ownerUser.id}, module.exports.context.internal));
});
},
changeOwnerUserStatus: function changeOwnerUserStatus(options) {
return db.knex('users')
.where('slug', '=', options.slug)
.update({
status: options.status
return models.User.getOwnerUser(module.exports.context.internal)
.then(function (user) {
return models.User.edit({status: options.status}, _.merge({id: user.id}, module.exports.context.internal));
});
},
createUsersWithRoles: function createUsersWithRoles() {
return db.knex('roles').insert(DataGenerator.forKnex.roles).then(function () {
return db.knex('users').insert(DataGenerator.forKnex.users);
return Promise.map(DataGenerator.forKnex.roles, function (role) {
return models.Role.add(role, module.exports.context.internal);
}).then(function () {
return db.knex('roles_users').insert(DataGenerator.forKnex.roles_users);
return Promise.map(_.cloneDeep(DataGenerator.forKnex.users), function (user) {
let userRolesRelations = _.filter(DataGenerator.forKnex.roles_users, {user_id: user.id});
userRolesRelations = _.map(userRolesRelations, function (userRolesRelation) {
return _.find(DataGenerator.forKnex.roles, {id: userRolesRelation.role_id});
});
user.roles = userRolesRelations;
return models.User.add(user, module.exports.context.internal);
});
});
},
resetRoles: function resetRoles() {
return Promise.map(_.cloneDeep(DataGenerator.forKnex.users), function (user) {
let userRolesRelations = _.filter(DataGenerator.forKnex.roles_users, {user_id: user.id});
userRolesRelations = _.map(userRolesRelations, function (userRolesRelation) {
return _.find(DataGenerator.forKnex.roles, {id: userRolesRelation.role_id});
});
user.roles = userRolesRelations;
return models.User.edit(user, _.merge({id: user.id}, module.exports.context.internal));
});
},
createUsersWithoutOwner: function createUsersWithoutOwner() {
var usersWithoutOwner = DataGenerator.forKnex.users.slice(1);
var usersWithoutOwner = _.cloneDeep(DataGenerator.forKnex.users.slice(1));
return db.knex('users').insert(usersWithoutOwner)
.then(function () {
return db.knex('roles_users').insert(DataGenerator.forKnex.roles_users);
return Promise.map(usersWithoutOwner, function (user) {
let userRolesRelations = _.filter(DataGenerator.forKnex.roles_users, {user_id: user.id});
userRolesRelations = _.map(userRolesRelations, function (userRolesRelation) {
return _.find(DataGenerator.forKnex.roles, {id: userRolesRelation.role_id});
});
user.roles = userRolesRelations;
return models.User.add(user, module.exports.context.internal);
});
},
createExtraUsers: function createExtraUsers() {
// grab 3 more users
var extraUsers = DataGenerator.Content.users.slice(2, 6);
var extraUsers = _.cloneDeep(DataGenerator.Content.users.slice(2, 6));
extraUsers = _.map(extraUsers, function (user) {
return DataGenerator.forKnex.createUser(_.extend({}, user, {
id: ObjectId.generate(),
@ -326,53 +317,52 @@ fixtures = {
}));
});
const roles = {};
roles[extraUsers[0].id] = DataGenerator.Content.roles[0];
roles[extraUsers[1].id] = DataGenerator.Content.roles[1];
roles[extraUsers[2].id] = DataGenerator.Content.roles[2];
roles[extraUsers[3].id] = DataGenerator.Content.roles[4];
// @TODO: remove when overhauling test env
// tests need access to the extra created users (especially to the created id)
// replacement for admin2, editor2 etc
DataGenerator.Content.extraUsers = extraUsers;
return db.knex('users').insert(extraUsers).then(function () {
return db.knex('roles_users').insert([
{id: ObjectId.generate(), user_id: extraUsers[0].id, role_id: DataGenerator.Content.roles[0].id},
{id: ObjectId.generate(), user_id: extraUsers[1].id, role_id: DataGenerator.Content.roles[1].id},
{id: ObjectId.generate(), user_id: extraUsers[2].id, role_id: DataGenerator.Content.roles[2].id},
{id: ObjectId.generate(), user_id: extraUsers[3].id, role_id: DataGenerator.Content.roles[4].id}
]);
return Promise.map(extraUsers, function (user) {
user.roles = roles[user.id];
return models.User.add(user, module.exports.context.internal);
});
},
insertOneUser: function insertOneUser(options) {
options = options || {};
return db.knex('users').insert(DataGenerator.forKnex.createUser({
return models.User.add({
name: options.name,
email: options.email,
slug: options.slug,
status: options.status
}));
}, module.exports.context.internal);
},
// Creates a client, and access and refresh tokens for user with index or 2 by default
createTokensForUser: function createTokensForUser(index) {
return db.knex('clients').insert(DataGenerator.forKnex.clients).then(function () {
return db.knex('accesstokens').insert(DataGenerator.forKnex.createToken({
user_id: DataGenerator.Content.users[index || 2].id
}));
return Promise.map(DataGenerator.forKnex.clients, function (client) {
return models.Client.add(client, module.exports.context.internal);
}).then(function () {
return db.knex('refreshtokens').insert(DataGenerator.forKnex.createToken({
return models.Accesstoken.add(DataGenerator.forKnex.createToken({
user_id: DataGenerator.Content.users[index || 2].id
}));
}), module.exports.context.internal);
}).then(function () {
return models.Refreshtoken.add(DataGenerator.forKnex.createToken({
user_id: DataGenerator.Content.users[index || 2].id
}), module.exports.context.internal);
});
},
insertOne: function insertOne(obj, fn, index) {
return db.knex(obj)
.insert(DataGenerator.forKnex[fn](DataGenerator.Content[obj][index || 0]));
},
insertApps: function insertApps() {
return db.knex('apps').insert(DataGenerator.forKnex.apps).then(function () {
return db.knex('app_fields').insert(DataGenerator.forKnex.app_fields);
});
insertOne: function insertOne(modelName, tableName, fn, index) {
const obj = DataGenerator.forKnex[fn](DataGenerator.Content[tableName][index || 0]);
return models[modelName].add(obj, module.exports.context.internal);
},
getImportFixturePath: function (filename) {
@ -404,10 +394,10 @@ fixtures = {
},
permissionsFor: function permissionsFor(obj) {
var permsToInsert = fixtureUtils.findModelFixtures('Permission', {object_type: obj}).entries,
var permsToInsert = _.cloneDeep(fixtureUtils.findModelFixtures('Permission', {object_type: obj}).entries),
permsRolesToInsert = fixtureUtils.findPermissionRelationsForObject(obj).entries,
actions = [],
permissionsRoles = [],
permissionsRoles = {},
roles = {
Administrator: DataGenerator.Content.roles[0].id,
Editor: DataGenerator.Content.roles[1].id,
@ -432,58 +422,64 @@ fixtures = {
if (perms[obj]) {
if (perms[obj] === 'all') {
_.each(actions, function (action) {
permissionsRoles.push({
id: ObjectId.generate(),
permission_id: action.permissionId,
role_id: roles[role]
});
if (!permissionsRoles[action.permissionId]) {
permissionsRoles[action.permissionId] = [];
}
permissionsRoles[action.permissionId].push(_.find(DataGenerator.Content.roles, {id: roles[role]}));
});
} else {
_.each(perms[obj], function (action) {
permissionsRoles.push({
id: ObjectId.generate(),
permission_id: _.find(actions, {type: action}).permissionId,
role_id: roles[role]
});
if (!permissionsRoles[_.find(actions, {type: action}).permissionId]) {
permissionsRoles[_.find(actions, {type: action}).permissionId] = [];
}
permissionsRoles[_.find(actions, {type: action}).permissionId].push(_.find(DataGenerator.Content.roles, {id: roles[role]}));
});
}
}
});
return db.knex('permissions').insert(permsToInsert).then(function () {
if (_.isEmpty(permissionsRoles)) {
return Promise.resolve();
return Promise.map(permsToInsert, function (perm) {
if (!_.isEmpty(permissionsRoles)) {
perm.roles = permissionsRoles[perm.id];
}
return db.knex('permissions_roles').insert(permissionsRoles);
return models.Permission.add(perm, module.exports.context.internal);
});
},
insertClients: function insertClients() {
return db.knex('clients').insert(DataGenerator.forKnex.clients);
return Promise.map(DataGenerator.forKnex.clients, function (client) {
return models.Client.add(client, module.exports.context.internal);
});
},
insertClientWithTrustedDomain: function insertClientWithTrustedDomain() {
var client = DataGenerator.forKnex.createClient({slug: 'ghost-test'});
const client = DataGenerator.forKnex.createClient({slug: 'ghost-test'});
return db.knex('clients')
.insert(client)
return models.Client.add(client, module.exports.context.internal)
.then(function () {
return db.knex('client_trusted_domains')
.insert(DataGenerator.forKnex.createTrustedDomain({client_id: client.id}));
return models.ClientTrustedDomain.add(DataGenerator.forKnex.createTrustedDomain({
client_id: client.id
}), module.exports.context.internal);
});
},
insertAccessToken: function insertAccessToken(override) {
return db.knex('accesstokens').insert(DataGenerator.forKnex.createToken(override));
return models.Accesstoken.insert(DataGenerator.forKnex.createToken(override), module.exports.context.internal);
},
insertInvites: function insertInvites() {
return db.knex('invites').insert(DataGenerator.forKnex.invites);
return Promise.map(DataGenerator.forKnex.invites, function (invite) {
return models.Invite.add(invite, module.exports.context.internal);
});
},
insertWebhooks: function insertWebhooks() {
return db.knex('webhooks').insert(DataGenerator.forKnex.webhooks);
return Promise.map(DataGenerator.forKnex.webhooks, function (webhook) {
return models.Webhook.add(webhook, module.exports.context.internal);
});
}
};
@ -496,6 +492,20 @@ clearBruteData = function clearBruteData() {
return db.knex('brute').truncate();
};
truncate = function truncate(tableName) {
if (config.get('database:client') === 'sqlite3') {
return db.knex(tableName).truncate();
}
return db.knex.raw('SET FOREIGN_KEY_CHECKS=0;')
.then(function () {
return db.knex(tableName).truncate();
})
.then(function () {
return db.knex.raw('SET FOREIGN_KEY_CHECKS=1;');
});
};
// we must always try to delete all tables
clearData = function clearData() {
debug('Database reset');
@ -504,34 +514,34 @@ clearData = function clearData() {
toDoList = {
app: function insertApp() {
return fixtures.insertOne('apps', 'createApp');
return fixtures.insertOne('App', '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');
return fixtures.insertOne('App', 'apps', 'createApp').then(function () {
return fixtures.insertOne('AppField', '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');
return fixtures.insertOne('App', 'apps', 'createApp').then(function () {
return fixtures.insertOne('AppSetting', 'app_settings', 'createAppSetting');
});
},
permission: function insertPermission() {
return fixtures.insertOne('permissions', 'createPermission');
return fixtures.insertOne('Permission', 'permissions', 'createPermission');
},
role: function insertRole() {
return fixtures.insertOne('roles', 'createRole');
return fixtures.insertOne('Role', 'roles', 'createRole');
},
roles: function insertRoles() {
return fixtures.insertRoles();
},
tag: function insertTag() {
return fixtures.insertOne('tags', 'createTag');
return fixtures.insertOne('Tag', 'tags', 'createTag');
},
subscriber: function insertSubscriber() {
return fixtures.insertOne('subscribers', 'createSubscriber');
return fixtures.insertOne('Subscriber', 'subscribers', 'createSubscriber');
},
posts: function insertPostsAndTags() {
return fixtures.insertPostsAndTags();
@ -671,6 +681,7 @@ initFixtures = function initFixtures() {
* @returns {Function}
*/
setup = function setup() {
/*eslint no-invalid-this: "off"*/
const self = this,
args = arguments;
@ -713,19 +724,15 @@ createUser = function createUser(options) {
var user = options.user,
role = options.role;
return db.knex('users').insert(user)
.then(function () {
return db.knex('roles');
})
return models.Role.fetchAll(module.exports.context.internal)
.then(function (roles) {
return db.knex('roles_users').insert({
id: ObjectId.generate(),
role_id: _.find(roles, {name: role.name}).id,
user_id: user.id
});
})
.then(function () {
return user;
roles = roles.toJSON();
user.roles = [_.find(roles, {name: role})];
return models.User.add(user, module.exports.context.internal)
.then(function () {
return user;
});
});
};
@ -736,15 +743,8 @@ createPost = function createPost(options) {
post.author_id = options.author.id;
}
return db.knex('posts')
.insert(post)
.then(function () {
return db.knex('posts_authors').insert({
id: ObjectId.generate(),
author_id: post.author_id,
post_id: post.id
}).return(post);
});
post.authors = [{id: post.author_id}];
return models.Post.add(post, module.exports.context.internal);
};
login = function login(request) {
@ -989,6 +989,7 @@ module.exports = {
startGhost: startGhost,
configureGhost: configureGhost,
teardown: teardown,
truncate: truncate,
setup: setup,
doAuth: doAuth,
createUser: createUser,