mirror of
https://github.com/moparisthebest/mail
synced 2025-01-30 22:50:17 -05:00
introduce update-handler
This commit is contained in:
parent
45e6b7834a
commit
aa7827554b
@ -43,7 +43,8 @@ define(function(require) {
|
||||
checkOutboxInterval: 5000,
|
||||
iconPath: '/img/icon.png',
|
||||
verificationUrl: '/verify/',
|
||||
verificationUuidLength: 36
|
||||
verificationUuidLength: 36,
|
||||
dbVersion: 1
|
||||
};
|
||||
|
||||
/**
|
||||
|
90
src/js/util/update/update-handler.js
Normal file
90
src/js/util/update/update-handler.js
Normal file
@ -0,0 +1,90 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var cfg = require('js/app-config').config,
|
||||
updateV1 = require('js/util/update/update-v1');
|
||||
|
||||
/**
|
||||
* Handles database migration
|
||||
*/
|
||||
var UpdateHandler = function(appConfigStorage, userStorage) {
|
||||
this._appConfigStorage = appConfigStorage;
|
||||
this._userStorage = userStorage;
|
||||
this._updateScripts = [updateV1];
|
||||
};
|
||||
|
||||
/**
|
||||
* Executes all the necessary updates
|
||||
* @param {Function} callback(error) Invoked when all the database updates were executed, or if an error occurred
|
||||
*/
|
||||
UpdateHandler.prototype.update = function(callback) {
|
||||
var self = this,
|
||||
currentVersion = 0,
|
||||
targetVersion = cfg.dbVersion,
|
||||
versionDbType = 'dbVersion';
|
||||
|
||||
self._appConfigStorage.listItems(versionDbType, 0, null, function(err, items) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// parse the database version number
|
||||
if (items && items.length > 0) {
|
||||
currentVersion = parseInt(items[0], 10);
|
||||
}
|
||||
|
||||
self._applyUpdate({
|
||||
currentVersion: currentVersion,
|
||||
targetVersion: targetVersion
|
||||
}, callback);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Schedules necessary updates and executes thom in order
|
||||
*/
|
||||
UpdateHandler.prototype._applyUpdate = function(options, callback) {
|
||||
var self = this,
|
||||
storage,
|
||||
queue = [];
|
||||
|
||||
if (options.currentVersion >= options.targetVersion) {
|
||||
// the current database version is up to date
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
storage = {
|
||||
appConfigStorage: self._appConfigStorage,
|
||||
userStorage: self._userStorage
|
||||
};
|
||||
|
||||
// add all the necessary database updates to the queue
|
||||
for (var i = options.currentVersion; i < options.targetVersion; i++) {
|
||||
queue.push(self._updateScripts[i]);
|
||||
}
|
||||
|
||||
// takes the next update from the queue and executes it
|
||||
function executeNextUpdate(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
if (queue.length < 1) {
|
||||
// we're done
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
|
||||
// process next update
|
||||
var script = queue.shift();
|
||||
script(storage, executeNextUpdate);
|
||||
}
|
||||
|
||||
executeNextUpdate();
|
||||
};
|
||||
|
||||
return UpdateHandler;
|
||||
});
|
29
src/js/util/update/update-v1.js
Normal file
29
src/js/util/update/update-v1.js
Normal file
@ -0,0 +1,29 @@
|
||||
define(function() {
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Update handler for transition databasae version 0 -> 1
|
||||
*
|
||||
* In database version 1, the stored email objects have to be purged, otherwise
|
||||
* every non-prefixed mail in the IMAP folders would be nuked due to the implementation
|
||||
* of the delta sync.
|
||||
*/
|
||||
function updateV1(options, callback) {
|
||||
var emailDbType = 'email_',
|
||||
versionDbType = 'dbVersion',
|
||||
postUpdateDbVersion = 1;
|
||||
|
||||
// remove the emails
|
||||
options.userStorage.removeList(emailDbType, function(err) {
|
||||
if (err) {
|
||||
callback(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// update the database version to postUpdateDbVersion
|
||||
options.appConfigStorage.storeList([postUpdateDbVersion], versionDbType, callback);
|
||||
});
|
||||
}
|
||||
|
||||
return updateV1;
|
||||
});
|
@ -49,7 +49,8 @@ function startTests() {
|
||||
'test/new-unit/mail-list-ctrl-test',
|
||||
'test/new-unit/write-ctrl-test',
|
||||
'test/new-unit/outbox-bo-test',
|
||||
'test/new-unit/invitation-dao-test'
|
||||
'test/new-unit/invitation-dao-test',
|
||||
'test/new-unit/update-handler-test'
|
||||
], function() {
|
||||
//Tests loaded, run tests
|
||||
mocha.run();
|
||||
|
166
test/new-unit/update-handler-test.js
Normal file
166
test/new-unit/update-handler-test.js
Normal file
@ -0,0 +1,166 @@
|
||||
define(function(require) {
|
||||
'use strict';
|
||||
|
||||
var DeviceStorageDAO = require('js/dao/devicestorage-dao'),
|
||||
cfg = require('js/app-config').config,
|
||||
UpdateHandler = require('js/util/update/update-handler'),
|
||||
expect = chai.expect;
|
||||
|
||||
chai.Assertion.includeStack = true;
|
||||
|
||||
describe('UpdateHandler', function() {
|
||||
var updateHandler, appConfigStorageStub, userStorageStub, origDbVersion;
|
||||
|
||||
beforeEach(function() {
|
||||
origDbVersion = cfg.dbVersion;
|
||||
appConfigStorageStub = sinon.createStubInstance(DeviceStorageDAO);
|
||||
userStorageStub = sinon.createStubInstance(DeviceStorageDAO);
|
||||
updateHandler = new UpdateHandler(appConfigStorageStub, userStorageStub);
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
cfg.dbVersion = origDbVersion;
|
||||
});
|
||||
|
||||
describe('#constructor', function() {
|
||||
it('should create instance', function() {
|
||||
expect(updateHandler).to.exist;
|
||||
expect(updateHandler._appConfigStorage).to.equal(appConfigStorageStub);
|
||||
expect(updateHandler._userStorage).to.equal(userStorageStub);
|
||||
|
||||
// the update handler must contain as many db update sripts as there are database versions
|
||||
expect(updateHandler._updateScripts.length).to.equal(cfg.dbVersion);
|
||||
});
|
||||
});
|
||||
|
||||
describe('#update', function() {
|
||||
var versionDbType = 'dbVersion';
|
||||
|
||||
it('should not update when up to date', function(done) {
|
||||
cfg.dbVersion = 3; // app requires database version 3
|
||||
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(null, '3'); // database version is 3
|
||||
|
||||
updateHandler.update(function(error) {
|
||||
expect(error).to.not.exist;
|
||||
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
describe('dummy updates for v0 through v4', function() {
|
||||
var updateCounter;
|
||||
|
||||
beforeEach(function() {
|
||||
updateCounter = 0;
|
||||
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(); // database version is 0
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
|
||||
});
|
||||
|
||||
|
||||
it('should work', function(done) {
|
||||
cfg.dbVersion = 4; // app requires database version 4
|
||||
|
||||
// a simple dummy update to executed that only increments the update counter
|
||||
function dummyUpdate(options, callback) {
|
||||
updateCounter++;
|
||||
callback();
|
||||
}
|
||||
|
||||
// inject the dummy updates instead of live ones
|
||||
updateHandler._updateScripts = [dummyUpdate, dummyUpdate, dummyUpdate, dummyUpdate];
|
||||
|
||||
// execute test
|
||||
updateHandler.update(function(error) {
|
||||
expect(error).to.not.exist;
|
||||
expect(updateCounter).to.equal(4);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail while updating to v3', function(done) {
|
||||
cfg.dbVersion = 4; // app requires database version 4
|
||||
|
||||
function dummyUpdate(options, callback) {
|
||||
updateCounter++;
|
||||
callback();
|
||||
}
|
||||
|
||||
function failingUpdate(options, callback) {
|
||||
updateCounter++;
|
||||
callback({});
|
||||
}
|
||||
|
||||
// inject the dummy updates instead of live ones
|
||||
updateHandler._updateScripts = [dummyUpdate, dummyUpdate, failingUpdate, dummyUpdate];
|
||||
|
||||
// execute test
|
||||
updateHandler.update(function(error) {
|
||||
expect(error).to.exist;
|
||||
expect(updateCounter).to.equal(3);
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe('v0 -> v1', function() {
|
||||
var emailDbType = 'email_';
|
||||
|
||||
beforeEach(function() {
|
||||
cfg.dbVersion = 1; // app requires database version 1
|
||||
appConfigStorageStub.listItems.withArgs(versionDbType).yieldsAsync(); // database version is 0
|
||||
});
|
||||
|
||||
afterEach(function() {
|
||||
// database version is only queried for version checking prior to the update script
|
||||
// so no need to check this in case-specific tests
|
||||
expect(appConfigStorageStub.listItems.calledOnce).to.be.true;
|
||||
});
|
||||
|
||||
it('should work', function(done) {
|
||||
userStorageStub.removeList.withArgs(emailDbType).yieldsAsync();
|
||||
appConfigStorageStub.storeList.withArgs([1], versionDbType).yieldsAsync();
|
||||
|
||||
updateHandler.update(function(error) {
|
||||
expect(error).to.not.exist;
|
||||
expect(userStorageStub.removeList.calledOnce).to.be.true;
|
||||
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail when persisting database version fails', function(done) {
|
||||
userStorageStub.removeList.yieldsAsync();
|
||||
appConfigStorageStub.storeList.yieldsAsync({});
|
||||
|
||||
updateHandler.update(function(error) {
|
||||
expect(error).to.exist;
|
||||
expect(userStorageStub.removeList.calledOnce).to.be.true;
|
||||
expect(appConfigStorageStub.storeList.calledOnce).to.be.true;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
it('should fail when wiping emails from database fails', function(done) {
|
||||
userStorageStub.removeList.yieldsAsync({});
|
||||
|
||||
updateHandler.update(function(error) {
|
||||
expect(error).to.exist;
|
||||
expect(userStorageStub.removeList.calledOnce).to.be.true;
|
||||
expect(appConfigStorageStub.storeList.called).to.be.false;
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user