0
Fork 0
mirror of https://github.com/TryGhost/Ghost.git synced 2025-03-18 02:21:47 -05:00

Improve getDatabaseVersion & versioning tests

refs #6301

- `currentVersion` was leftover from before the first public release of Ghost!
- simplified the code for `getDatabaseVersion`
- improved & made consistent how errors are handled in `getDatabaseVersion`
- migration error handling updated to reflect the changes in `getDatabaseVersion`
- added tests for both `getDatabaseVersion` and `setDatabaseVersion`
This commit is contained in:
Hannah Wolfe 2016-03-11 22:46:05 +00:00
parent 39dfb2c09a
commit 81deb88263
4 changed files with 161 additions and 23 deletions

View file

@ -110,7 +110,7 @@ init = function (tablesOnly) {
);
}
}, function (err) {
if (err.message || err === 'Settings table does not exist') {
if (err && err.message === 'Settings table does not exist') {
// 4. The database has not yet been created
// Bring everything up from initial version.
logInfo('Database initialisation required for version ' + versioning.getDefaultDatabaseVersion());

View file

@ -1,10 +1,8 @@
var _ = require('lodash'),
db = require('../db'),
var db = require('../db'),
errors = require('../../errors'),
i18n = require('../../i18n'),
defaultSettings = require('./default-settings'),
initialVersion = '000',
defaultDatabaseVersion;
// Default Database Version
@ -29,25 +27,20 @@ function getDatabaseVersion() {
// Temporary code to deal with old databases with currentVersion settings
return db.knex('settings')
.where('key', 'databaseVersion')
.orWhere('key', 'currentVersion')
.select('value')
.then(function (versions) {
var databaseVersion = _.reduce(versions, function (memo, version) {
if (isNaN(version.value)) {
errors.throwError(i18n.t('errors.data.versioning.index.dbVersionNotRecognized'));
}
return parseInt(version.value, 10) > parseInt(memo, 10) ? version.value : memo;
}, initialVersion);
if (!databaseVersion || databaseVersion.length === 0) {
// we didn't get a response we understood, assume initialVersion
databaseVersion = initialVersion;
.first('value')
.then(function (version) {
if (!version || isNaN(version.value)) {
return errors.rejectError(new Error(
i18n.t('errors.data.versioning.index.dbVersionNotRecognized')
));
}
return databaseVersion;
return version.value;
});
}
throw new Error(i18n.t('errors.data.versioning.index.settingsTableDoesNotExist'));
return errors.rejectError(new Error(
i18n.t('errors.data.versioning.index.settingsTableDoesNotExist')
));
});
}

View file

@ -12,7 +12,7 @@ describe('DB API', function () {
// Keep the DB clean
before(testUtils.teardown);
afterEach(testUtils.teardown);
beforeEach(testUtils.setup('users:roles', 'posts', 'perms:db', 'perms:init'));
beforeEach(testUtils.setup('users:roles', 'settings', 'posts', 'perms:db', 'perms:init'));
should.exist(dbAPI);

View file

@ -1,9 +1,11 @@
/*globals describe, it, afterEach */
var should = require('should'),
sinon = require('sinon'),
/*globals describe, it, afterEach, beforeEach */
var should = require('should'),
sinon = require('sinon'),
Promise = require('bluebird'),
// Stuff we are testing
versioning = require('../../server/data/schema').versioning,
db = require('../../server/data/db'),
errors = require('../../server/errors'),
sandbox = sinon.sandbox.create();
@ -43,6 +45,149 @@ describe('Versioning', function () {
});
});
describe('getDatabaseVersion', function () {
var errorSpy, knexStub, knexMock, queryMock;
beforeEach(function () {
errorSpy = sandbox.spy(errors, 'rejectError');
queryMock = {
where: sandbox.stub().returnsThis(),
first: sandbox.stub()
};
knexMock = sandbox.stub().returns(queryMock);
knexMock.schema = {
hasTable: sandbox.stub()
};
// this MUST use sinon, not sandbox, see sinonjs/sinon#781
knexStub = sinon.stub(db, 'knex', {get: function () { return knexMock; }});
});
afterEach(function () {
knexStub.restore();
});
it('should throw error if settings table does not exist', function (done) {
// Setup
knexMock.schema.hasTable.returns(new Promise.resolve(false));
// Execute
versioning.getDatabaseVersion().then(function () {
done('Should throw an error if the settings table does not exist');
}).catch(function (err) {
should.exist(err);
err.message.should.eql('Settings table does not exist');
errorSpy.calledOnce.should.be.true();
knexStub.get.calledOnce.should.be.true();
knexMock.schema.hasTable.calledOnce.should.be.true();
knexMock.schema.hasTable.calledWith('settings').should.be.true();
queryMock.where.called.should.be.false();
queryMock.first.called.should.be.false();
done();
}).catch(done);
});
it('should lookup & return version, if settings table exists', function (done) {
// Setup
knexMock.schema.hasTable.returns(new Promise.resolve(true));
queryMock.first.returns(new Promise.resolve({value: '001'}));
// Execute
versioning.getDatabaseVersion().then(function (version) {
should.exist(version);
version.should.eql('001');
errorSpy.called.should.be.false();
knexStub.get.calledTwice.should.be.true();
knexMock.schema.hasTable.calledOnce.should.be.true();
knexMock.schema.hasTable.calledWith('settings').should.be.true();
queryMock.where.called.should.be.true();
queryMock.first.called.should.be.true();
done();
}).catch(done);
});
it('should throw error if version does not exist', function (done) {
// Setup
knexMock.schema.hasTable.returns(new Promise.resolve(true));
queryMock.first.returns(new Promise.resolve());
// Execute
versioning.getDatabaseVersion().then(function () {
done('Should throw an error if version does not exist');
}).catch(function (err) {
should.exist(err);
err.message.should.eql('Database version is not recognized');
errorSpy.calledOnce.should.be.true();
knexStub.get.calledTwice.should.be.true();
knexMock.schema.hasTable.calledOnce.should.be.true();
knexMock.schema.hasTable.calledWith('settings').should.be.true();
queryMock.where.called.should.be.true();
queryMock.first.called.should.be.true();
done();
}).catch(done);
});
it('should throw error if version is not a number', function (done) {
// Setup
knexMock.schema.hasTable.returns(new Promise.resolve(true));
queryMock.first.returns(new Promise.resolve('Eyjafjallajökull'));
// Execute
versioning.getDatabaseVersion().then(function () {
done('Should throw an error if version is not a number');
}).catch(function (err) {
should.exist(err);
err.message.should.eql('Database version is not recognized');
errorSpy.calledOnce.should.be.true();
knexStub.get.calledTwice.should.be.true();
knexMock.schema.hasTable.calledOnce.should.be.true();
knexMock.schema.hasTable.calledWith('settings').should.be.true();
queryMock.where.called.should.be.true();
queryMock.first.called.should.be.true();
done();
}).catch(done);
});
});
describe('setDatabaseVersion', function () {
var knexStub, knexMock, queryMock;
beforeEach(function () {
queryMock = {
where: sandbox.stub().returnsThis(),
update: sandbox.stub().returns(new Promise.resolve())
};
knexMock = sandbox.stub().returns(queryMock);
// this MUST use sinon, not sandbox, see sinonjs/sinon#781
knexStub = sinon.stub(db, 'knex', {get: function () { return knexMock; }});
});
afterEach(function () {
knexStub.restore();
});
it('should try to update the databaseVersion', function (done) {
versioning.setDatabaseVersion().then(function () {
knexStub.get.calledOnce.should.be.true();
queryMock.where.called.should.be.true();
queryMock.update.called.should.be.true();
done();
}).catch(done);
});
});
describe('showCannotMigrateError', function () {
it('should output a detailed error message', function () {
var errorStub = sandbox.stub(errors, 'logAndRejectError');