Ghost/core/test/unit/import_spec.js
Harry Wolff cddd23f926 Only reference model properties through the models module.
This frees us up to enforce one single point of access, thus paving
the way towards allowing us to initialize the models at are request,
and not when it's require().

addresses #2170
2014-07-10 08:04:32 -04:00

576 lines
23 KiB
JavaScript

/*globals describe, beforeEach, afterEach, it*/
/*jshint expr:true*/
var testUtils = require('../utils'),
should = require('should'),
sinon = require('sinon'),
when = require('when'),
assert = require('assert'),
_ = require('lodash'),
// Stuff we are testing
config = require('../../server/config'),
migration = require('../../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');
describe('Import', function () {
should.exist(exporter);
should.exist(importer);
var sandbox,
knex = config().database.knex;
beforeEach(function (done) {
sandbox = sinon.sandbox.create();
// clear database... we need to initialise it manually for each test
testUtils.clearData().then(function () {
done();
}).catch(done);
});
afterEach(function () {
sandbox.restore();
});
it('resolves 000', function (done) {
var importStub = sandbox.stub(Importer000, 'importData', function () {
return when.resolve();
}),
fakeData = { test: true };
importer('000', fakeData).then(function () {
importStub.calledWith(fakeData).should.equal(true);
importStub.restore();
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 () {
should.exist(Importer000);
beforeEach(function (done) {
// migrate to current version
migration.migrateUpFreshDb().then(function () {
return testUtils.insertDefaultUser();
}).then(function () {
done();
}).catch(done);
});
it('imports data from 000', function (done) {
var exportData,
versioningStub = sandbox.stub(versioning, 'getDatabaseVersion', function () {
return when.resolve('000');
});
testUtils.loadExportFixture('export-000').then(function (exported) {
exportData = exported;
return importer('000', exportData);
}).then(function () {
// Grab the data from tables
return when.all([
knex('users').select(),
knex('posts').select(),
knex('settings').select(),
knex('tags').select()
]);
}).then(function (importedData) {
should.exist(importedData);
importedData.length.should.equal(4, 'Did not get data successfully');
var users = importedData[0],
posts = importedData[1],
settings = importedData[2],
tags = importedData[3];
// 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 + 1, 'Wrong number of posts');
// 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');
versioningStub.restore();
done();
}).catch(done);
});
});
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);
});
it('safely imports data from 001', function (done) {
var exportData,
timestamp = 1349928000000;
testUtils.loadExportFixture('export-001').then(function (exported) {
exportData = exported;
// Modify timestamp data for testing
exportData.data.posts[0].created_at = timestamp;
exportData.data.posts[0].updated_at = timestamp;
exportData.data.posts[0].published_at = timestamp;
return importer('001', exportData);
}).then(function () {
// Grab the data from tables
return when.all([
knex('users').select(),
knex('posts').select(),
knex('settings').select(),
knex('tags').select()
]);
}).then(function (importedData) {
should.exist(importedData);
importedData.length.should.equal(4, 'Did not get data successfully');
var users = importedData[0],
posts = importedData[1],
settings = importedData[2],
tags = importedData[3],
exportEmail;
// we always have 1 user, the default 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
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);
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');
// test settings
settings.length.should.be.above(0, 'Wrong number of settings');
_.findWhere(settings, {key: 'databaseVersion'}).value.should.equal('003', 'Wrong database version');
// activeTheme should NOT have been overridden
_.findWhere(settings, {key: 'activeTheme'}).value.should.equal('casper', 'Wrong theme');
// email address should have been overridden
exportEmail = _.findWhere(exportData.data.settings, {key: 'email'}).value;
_.findWhere(settings, {key: 'email'}).value.should.equal(exportEmail, 'Wrong email in settings');
// test tags
tags.length.should.equal(exportData.data.tags.length, 'no new tags');
// 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(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);
done();
}).catch(done);
});
it('doesn\'t import invalid post data from 001', function (done) {
var exportData;
testUtils.loadExportFixture('export-001').then(function (exported) {
exportData = exported;
//change title to 151 characters
exportData.data.posts[0].title = new Array(152).join('a');
exportData.data.posts[0].tags = 'Tag';
return importer('001', exportData);
}).then(function () {
(1).should.eql(0, 'Data import should not resolve promise.');
}, function (error) {
error[0].message.should.eql('Value in [posts.title] exceeds maximum length of 150 characters.');
error[0].type.should.eql('ValidationError');
when.all([
knex('users').select(),
knex('posts').select(),
knex('settings').select(),
knex('tags').select()
]).then(function (importedData) {
should.exist(importedData);
importedData.length.should.equal(4, 'Did not get data successfully');
var users = importedData[0],
posts = importedData[1],
settings = importedData[2],
tags = importedData[3];
// 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');
// 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();
});
}).catch(done);
});
it('doesn\'t import invalid settings data from 001', function (done) {
var exportData;
testUtils.loadExportFixture('export-001').then(function (exported) {
exportData = exported;
//change to blank settings key
exportData.data.settings[3].key = null;
return importer('001', exportData);
}).then(function () {
(1).should.eql(0, 'Data import should not resolve promise.');
}, function (error) {
error[0].message.should.eql('Setting key cannot be empty.');
error[0].type.should.eql('ValidationError');
when.all([
knex('users').select(),
knex('posts').select(),
knex('settings').select(),
knex('tags').select()
]).then(function (importedData) {
should.exist(importedData);
importedData.length.should.equal(4, 'Did not get data successfully');
var users = importedData[0],
posts = importedData[1],
settings = importedData[2],
tags = importedData[3];
// 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');
// 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();
});
}).catch(done);
});
});
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);
});
it('safely imports data from 002', function (done) {
var exportData,
timestamp = 1349928000000;
testUtils.loadExportFixture('export-002').then(function (exported) {
exportData = exported;
// Modify timestamp data for testing
exportData.data.posts[0].created_at = timestamp;
exportData.data.posts[0].updated_at = timestamp;
exportData.data.posts[0].published_at = timestamp;
return importer('002', exportData);
}).then(function () {
// Grab the data from tables
return when.all([
knex('users').select(),
knex('posts').select(),
knex('settings').select(),
knex('tags').select()
]);
}).then(function (importedData) {
should.exist(importedData);
importedData.length.should.equal(4, 'Did not get data successfully');
var users = importedData[0],
posts = importedData[1],
settings = importedData[2],
tags = importedData[3],
exportEmail;
// we always have 1 user, the default 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
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);
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');
// test settings
settings.length.should.be.above(0, 'Wrong number of settings');
_.findWhere(settings, {key: 'databaseVersion'}).value.should.equal('003', 'Wrong database version');
// activeTheme should NOT have been overridden
_.findWhere(settings, {key: 'activeTheme'}).value.should.equal('casper', 'Wrong theme');
// email address should have been overridden
exportEmail = _.findWhere(exportData.data.settings, {key: 'email'}).value;
_.findWhere(settings, {key: 'email'}).value.should.equal(exportEmail, 'Wrong email in settings');
// test tags
tags.length.should.equal(exportData.data.tags.length, 'no new tags');
// 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(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);
done();
}).catch(function (error) {
done(new Error(error));
});
});
it('doesn\'t import invalid post data from 002', function (done) {
var exportData;
testUtils.loadExportFixture('export-002').then(function (exported) {
exportData = exported;
//change title to 151 characters
exportData.data.posts[0].title = new Array(152).join('a');
exportData.data.posts[0].tags = 'Tag';
return importer('002', exportData);
}).then(function () {
(1).should.eql(0, 'Data import should not resolve promise.');
}, function (error) {
error[0].message.should.eql('Value in [posts.title] exceeds maximum length of 150 characters.');
error[0].type.should.eql('ValidationError');
when.all([
knex('users').select(),
knex('posts').select(),
knex('settings').select(),
knex('tags').select()
]).then(function (importedData) {
should.exist(importedData);
importedData.length.should.equal(4, 'Did not get data successfully');
var users = importedData[0],
posts = importedData[1],
settings = importedData[2],
tags = importedData[3];
// 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');
// 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();
});
}).catch(done);
});
it('doesn\'t import invalid settings data from 002', function (done) {
var exportData;
testUtils.loadExportFixture('export-002').then(function (exported) {
exportData = exported;
//change to blank settings key
exportData.data.settings[3].key = null;
return importer('002', exportData);
}).then(function () {
(1).should.eql(0, 'Data import should not resolve promise.');
}, function (error) {
error[0].message.should.eql('Setting key cannot be empty.');
error[0].type.should.eql('ValidationError');
when.all([
knex('users').select(),
knex('posts').select(),
knex('settings').select(),
knex('tags').select()
]).then(function (importedData) {
should.exist(importedData);
importedData.length.should.equal(4, 'Did not get data successfully');
var users = importedData[0],
posts = importedData[1],
settings = importedData[2],
tags = importedData[3];
// 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');
// 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();
});
}).catch(done);
});
});
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);
});
it('safely imports data from 003', function (done) {
var exportData;
testUtils.loadExportFixture('export-003').then(function (exported) {
exportData = exported;
return importer('003', exportData);
}).then(function () {
// Grab the data from tables
return when.all([
knex('apps').select(),
knex('app_settings').select()
]);
}).then(function (importedData) {
should.exist(importedData);
importedData.length.should.equal(2, 'Did not get data successfully');
var apps = importedData[0];
// app_settings = importedData[1];
// test apps
apps.length.should.equal(exportData.data.apps.length, 'imported apps');
// test app settings
// app_settings.length.should.equal(exportData.data.app_settings.length, 'imported app settings');
done();
}).catch(done);
});
});
});