Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
1071 lines
26 KiB
JavaScript
Executable file
1071 lines
26 KiB
JavaScript
Executable file
define(function(require) {
|
|
'use strict';
|
|
|
|
var AbstractProvider = require('provider/abstract');
|
|
var CaldavProvider = require('provider/caldav');
|
|
var CaldavPullEvents = require('provider/caldav_pull_events');
|
|
var CalendarError = require('common/error');
|
|
var Calc = require('common/calc');
|
|
var Factory = require('test/support/factory');
|
|
var ICAL = require('ext/ical');
|
|
var Responder = require('common/responder');
|
|
var ServiceSupport = require('test/service/helper');
|
|
var core = require('core');
|
|
var nextTick = require('common/next_tick');
|
|
|
|
suite('provider/caldav', function() {
|
|
var subject;
|
|
var controller;
|
|
var db;
|
|
|
|
var accountStore;
|
|
var calendarStore;
|
|
var componentStore;
|
|
var eventStore;
|
|
|
|
setup(function(done) {
|
|
controller = core.serviceController;
|
|
db = core.db;
|
|
|
|
subject = new CaldavProvider();
|
|
|
|
var storeFactory = core.storeFactory;
|
|
calendarStore = storeFactory.get('Calendar');
|
|
accountStore = storeFactory.get('Account');
|
|
componentStore = storeFactory.get('IcalComponent');
|
|
|
|
eventStore = storeFactory.get('Event');
|
|
|
|
db.open(done);
|
|
});
|
|
|
|
testSupport.calendar.accountEnvironment(
|
|
null,
|
|
{
|
|
_id: 'one',
|
|
accountId: 'one',
|
|
firstEventSyncDate: null,
|
|
lastEventSyncToken: null
|
|
}
|
|
);
|
|
|
|
var account;
|
|
var calendar;
|
|
setup(function() {
|
|
account = this.account;
|
|
calendar = this.calendar;
|
|
});
|
|
|
|
var ical;
|
|
suiteSetup(function(done) {
|
|
ical = new ServiceSupport.Fixtures('ical');
|
|
ical.load('daily_event');
|
|
ical.load('recurring_event');
|
|
ical.onready = done;
|
|
});
|
|
|
|
teardown(function(done) {
|
|
testSupport.calendar.clearStore(
|
|
db,
|
|
done
|
|
);
|
|
});
|
|
|
|
teardown(function() {
|
|
db.close();
|
|
});
|
|
|
|
test('initialization', function() {
|
|
assert.instanceOf(
|
|
subject,
|
|
AbstractProvider
|
|
);
|
|
});
|
|
|
|
test('capabilites', function() {
|
|
assert.isTrue(subject.useUrl);
|
|
assert.isTrue(subject.useCredentials);
|
|
});
|
|
|
|
suite('#calendarCapabilities', function() {
|
|
/**
|
|
* Creates a test for a privilege set
|
|
*/
|
|
function testPrivilege(name, privileges, expected) {
|
|
test(name, function() {
|
|
var calendar = Factory('calendar', {
|
|
remote: {
|
|
privilegeSet: privileges
|
|
}
|
|
});
|
|
|
|
var result = subject.calendarCapabilities(
|
|
calendar
|
|
);
|
|
|
|
assert.hasProperties(result, expected);
|
|
});
|
|
}
|
|
|
|
testPrivilege('missing privilegeSet', null, {
|
|
canUpdateEvent: true,
|
|
canDeleteEvent: true,
|
|
canCreateEvent: true
|
|
});
|
|
|
|
testPrivilege('delete', ['unbind'], {
|
|
canDeleteEvent: true
|
|
});
|
|
|
|
testPrivilege('create/update', ['write-content'], {
|
|
canCreateEvent: true,
|
|
canUpdateEvent: true
|
|
});
|
|
});
|
|
|
|
suite('#_handleServiceError', function() {
|
|
var permErrors = [
|
|
{ input: 'caldav-authentication', expect: 'Authentication' },
|
|
{ input: 'caldav-invalid-entrypoint', expect: 'InvalidServer' }
|
|
];
|
|
|
|
function validatePermError(error) {
|
|
suite(error.input, function() {
|
|
var result;
|
|
var givenErr;
|
|
var expectedClass;
|
|
|
|
setup(function(done) {
|
|
expectedClass = CalendarError[error.expect];
|
|
|
|
givenErr = { name: error.input };
|
|
result = subject._handleServiceError(
|
|
givenErr,
|
|
{ account: account }
|
|
);
|
|
|
|
accountStore.once('update', function(id, model) {
|
|
if (id === account._id) {
|
|
done();
|
|
}
|
|
});
|
|
});
|
|
|
|
test('returned value', function() {
|
|
assert.instanceOf(result, expectedClass);
|
|
});
|
|
|
|
test('updated error', function() {
|
|
assert.ok(account.error, 'has error');
|
|
|
|
assert.equal(
|
|
account.error.name,
|
|
(new expectedClass()).name,
|
|
'marks error with name'
|
|
);
|
|
});
|
|
});
|
|
}
|
|
|
|
permErrors.forEach(validatePermError);
|
|
|
|
test('generic error', function() {
|
|
var result = subject._handleServiceError(
|
|
{ name: 'caldav-server-failure' },
|
|
{ account: account }
|
|
);
|
|
|
|
assert.instanceOf(result, CalendarError);
|
|
});
|
|
|
|
test('new account', function() {
|
|
var account = Factory('account');
|
|
var result = subject._handleServiceError(
|
|
{ name: 'caldav-authentication' },
|
|
{ account: account }
|
|
);
|
|
|
|
assert.instanceOf(result, CalendarError);
|
|
});
|
|
});
|
|
|
|
suite('#eventCapabilities', function() {
|
|
|
|
test('recurring', function(done) {
|
|
var event = Factory('event', {
|
|
calendarId: this.calendar._id,
|
|
remote: {
|
|
isRecurring: true
|
|
}
|
|
});
|
|
|
|
var expected = {
|
|
canUpdate: false,
|
|
canDelete: false,
|
|
canCreate: false
|
|
};
|
|
|
|
subject.eventCapabilities(event, function(err, actual) {
|
|
done(function() {
|
|
assert.deepEqual(actual, expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
test('without calendar permissions', function(done) {
|
|
var event = Factory('event', {
|
|
calendarId: this.calendar._id
|
|
});
|
|
|
|
assert.isFalse(event.remote.isRecurring);
|
|
|
|
var expected = {
|
|
canUpdate: true,
|
|
canCreate: true,
|
|
canDelete: true
|
|
};
|
|
|
|
subject.eventCapabilities(event, function(err, actual) {
|
|
done(function() {
|
|
assert.deepEqual(actual, expected);
|
|
});
|
|
});
|
|
});
|
|
|
|
test('with calendar permissions', function(done) {
|
|
subject.calendarCapabilities = function() {
|
|
return {
|
|
canCreateEvent: false,
|
|
canDeleteEvent: true,
|
|
canUpdateEvent: true
|
|
};
|
|
};
|
|
|
|
var event = Factory('event', {
|
|
calendarId: calendar._id
|
|
});
|
|
|
|
subject.eventCapabilities(event, function(err, caps) {
|
|
done(function() {
|
|
assert.deepEqual(caps, {
|
|
canCreate: false,
|
|
canUpdate: true,
|
|
canDelete: true
|
|
});
|
|
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('methods that wrap request', function() {
|
|
var calledWith;
|
|
var error;
|
|
var result;
|
|
var input;
|
|
var realMark;
|
|
|
|
setup(function() {
|
|
input = Factory('account');
|
|
// mock out real markWith Error
|
|
realMark = accountStore.markWithError;
|
|
accountStore.markWithError = function() {};
|
|
});
|
|
|
|
teardown(function() {
|
|
accountStore.markWithError = realMark;
|
|
});
|
|
|
|
/**
|
|
* Validate error handling for a given request.
|
|
*
|
|
*
|
|
* request(validateErrorHandling(done, ['calendar', 'account']));
|
|
*
|
|
*/
|
|
function validateErrorHandling(done, fields) {
|
|
error = { name: 'caldav-authentication' };
|
|
|
|
var pending = 2;
|
|
function next() {
|
|
--pending;
|
|
if (pending === 0) {
|
|
nextTick(done);
|
|
}
|
|
}
|
|
|
|
var realHandleServiceError = subject._handleServiceError;
|
|
|
|
subject._handleServiceError = function(givenErr, detail) {
|
|
assert.equal(givenErr, error, 'sends error');
|
|
|
|
fields.forEach(function(field) {
|
|
assert.ok(detail[field], 'detail.' + field);
|
|
});
|
|
|
|
next();
|
|
return realHandleServiceError.apply(this, arguments);
|
|
};
|
|
|
|
return function(cbError) {
|
|
assert.ok(cbError, 'callback recieves error');
|
|
next();
|
|
};
|
|
}
|
|
|
|
setup(function() {
|
|
controller.request = function() {
|
|
calledWith = Array.prototype.slice.call(arguments);
|
|
var cb = arguments[arguments.length - 1];
|
|
setTimeout(function() {
|
|
cb(error, result);
|
|
}, 0);
|
|
};
|
|
});
|
|
|
|
suite('#getAccount', function() {
|
|
test('success', function(done) {
|
|
result = { id: 'wow' };
|
|
|
|
subject.getAccount(input, function cb(cbError, cbResult) {
|
|
done(function() {
|
|
assert.equal(cbResult, result);
|
|
assert.equal(cbError, error);
|
|
});
|
|
});
|
|
});
|
|
|
|
test('error handling', function(done) {
|
|
subject.getAccount(
|
|
input,
|
|
validateErrorHandling(done, ['account'])
|
|
);
|
|
});
|
|
|
|
test('offline handling', function(done) {
|
|
subject.isOffline = function() { return true; };
|
|
subject.getAccount(input, function cb(cbError, cbResult) {
|
|
done(function() {
|
|
delete subject.isOffline;
|
|
assert.equal(cbError.name, 'offline');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('#findCalendars', function() {
|
|
test('error', function(done) {
|
|
subject.findCalendars(
|
|
input,
|
|
validateErrorHandling(done, ['account'])
|
|
);
|
|
});
|
|
|
|
test('success', function(done) {
|
|
result = {
|
|
one: Factory.build('caldav.calendar'),
|
|
two: Factory.build('caldav.calendar', { color: null })
|
|
};
|
|
|
|
error = null;
|
|
|
|
subject.findCalendars(input, function cb(cbError, cbResult) {
|
|
done(function() {
|
|
assert.equal(
|
|
cbResult.one,
|
|
result.one,
|
|
'does not process events with color'
|
|
);
|
|
|
|
// hack clone
|
|
var withColor = JSON.parse(JSON.stringify(result.two));
|
|
withColor.color = subject.defaultColor;
|
|
|
|
assert.deepEqual(
|
|
cbResult.two,
|
|
withColor,
|
|
'adds color'
|
|
);
|
|
|
|
assert.equal(cbError, error);
|
|
});
|
|
});
|
|
});
|
|
|
|
test('offline handling', function(done) {
|
|
subject.isOffline = function() { return true; };
|
|
subject.findCalendars(input, function cb(cbError, cbResult) {
|
|
done(function() {
|
|
delete subject.isOffline;
|
|
assert.equal(cbError.name, 'offline');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('#createEvent', function() {
|
|
var event;
|
|
var id;
|
|
|
|
setup(function() {
|
|
error = null;
|
|
event = Factory('event', {
|
|
calendarId: calendar._id
|
|
});
|
|
|
|
result = Factory.create('event').remote;
|
|
result.id = 'foo';
|
|
result.syncToken = 'hit';
|
|
result.icalComponent = 'xfoo';
|
|
|
|
id = calendar._id + '-foo';
|
|
});
|
|
|
|
suite('success', function() {
|
|
setup(function(done) {
|
|
subject.createEvent(event, done);
|
|
});
|
|
|
|
test('icalComponent', function(done) {
|
|
componentStore.get(id, function(err, result) {
|
|
done(function() {
|
|
assert.deepEqual(result, {
|
|
eventId: id,
|
|
ical: 'xfoo'
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
test('event', function(done) {
|
|
eventStore.get(id, function(err, result) {
|
|
var remote = result.remote;
|
|
assert.equal(remote.id, 'foo');
|
|
assert.equal(remote.syncToken, 'hit');
|
|
assert.ok(!remote.icalComponent, 'does not have icalComponent');
|
|
done();
|
|
});
|
|
});
|
|
});
|
|
|
|
test('error handling', function(done) {
|
|
subject.createEvent(
|
|
event,
|
|
validateErrorHandling(done, ['account', 'calendar'])
|
|
);
|
|
});
|
|
|
|
test('offline handling', function(done) {
|
|
subject.isOffline = function() { return true; };
|
|
subject.createEvent(event, function cb(cbError, cbResult) {
|
|
done(function() {
|
|
delete subject.isOffline;
|
|
assert.equal(cbError.name, 'offline');
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
suite('#updateEvent', function() {
|
|
var event;
|
|
var component;
|
|
|
|
setup(function(done) {
|
|
var trans = db.transaction(
|
|
['events', 'icalComponents'],
|
|
'readwrite'
|
|
);
|
|
|
|
trans.oncomplete = function() {
|
|
done();
|
|
};
|
|
|
|
event = Factory('event', {
|
|
calendarId: calendar._id
|
|
});
|
|
|
|
component = Factory('icalComponent', {
|
|
eventId: event._id,
|
|
ical: 'original'
|
|
});
|
|
|
|
eventStore.persist(event, done);
|
|
componentStore.persist(component, done);
|
|
});
|
|
|
|
suite('success', function() {
|
|
setup(function(done) {
|
|
error = null;
|
|
result = Factory.create('event').remote;
|
|
result.icalComponent = 'xfooo';
|
|
result.syncToken = 'changedmefoo';
|
|
subject.updateEvent(event, done);
|
|
});
|
|
|
|
test('sent data', function() {
|
|
var details = calledWith[calledWith.length - 2];
|
|
|
|
assert.ok(details.event, 'sends event');
|
|
|
|
assert.equal(
|
|
details.icalComponent,
|
|
'original',
|
|
'icalComponent'
|
|
);
|
|
});
|
|
|
|
test('component', function(done) {
|
|
componentStore.get(event._id, function(err, item) {
|
|
done(function() {
|
|
assert.deepEqual(
|
|
item,
|
|
{ eventId: event._id, ical: 'xfooo' }
|
|
);
|
|
});
|
|
});
|
|
});
|
|
|
|
test('event', function(done) {
|
|
eventStore.get(event._id, function(err, item) {
|
|
done(function() {
|
|
assert.equal(item.remote.syncToken, result.syncToken);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
test('error handling', function(done) {
|
|
subject.updateEvent(
|
|
event,
|
|
validateErrorHandling(done, ['calendar', 'account'])
|
|
);
|
|
});
|
|
|
|
test('offline handling', function(done) {
|
|
subject.isOffline = function() { return true; };
|
|
subject.updateEvent(event, function cb(cbError, cbResult) {
|
|
done(function() {
|
|
delete subject.isOffline;
|
|
assert.equal(cbError.name, 'offline');
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
suite('#deleteEvent', function() {
|
|
var event;
|
|
setup(function() {
|
|
event = Factory('event', {
|
|
calendarId: calendar._id
|
|
});
|
|
});
|
|
|
|
test('failure', function(done) {
|
|
subject.deleteEvent(
|
|
event,
|
|
validateErrorHandling(done, ['account', 'calendar'])
|
|
);
|
|
});
|
|
|
|
test('success', function(done) {
|
|
|
|
subject.deleteEvent(event, function() {
|
|
done(function() {
|
|
assert.equal(calledWith[0], 'caldav');
|
|
assert.equal(calledWith[1], 'deleteEvent');
|
|
|
|
var slice = calledWith.slice(2, 5);
|
|
|
|
assert.hasProperties(
|
|
slice[0], account,
|
|
'sends account'
|
|
);
|
|
|
|
assert.hasProperties(
|
|
slice[1],
|
|
calendar.remote,
|
|
'sends calendar'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
slice[2],
|
|
event.remote,
|
|
'sends event'
|
|
);
|
|
|
|
});
|
|
});
|
|
});
|
|
|
|
test('offline handling', function(done) {
|
|
var event = Factory('event', {
|
|
calendarId: calendar._id
|
|
});
|
|
subject.isOffline = function() { return true; };
|
|
subject.deleteEvent(event, function cb(cbError, cbResult) {
|
|
done(function() {
|
|
delete subject.isOffline;
|
|
assert.equal(cbError.name, 'offline');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('#_cachedEventsFor', function() {
|
|
var events = [];
|
|
var calendar;
|
|
|
|
setup(function(done) {
|
|
events.length = 0;
|
|
calendar = Factory('calendar');
|
|
calendarStore.persist(calendar, done);
|
|
});
|
|
|
|
// create some events
|
|
var i = 0;
|
|
/*jshint loopfunc: true */
|
|
for (; i < 2; i++) {
|
|
setup(function(done) {
|
|
var event = Factory('event', {
|
|
calendarId: calendar._id,
|
|
remote: {
|
|
id: i,
|
|
url: 'some_foo_' + i + '.ics',
|
|
syncToken: i
|
|
}
|
|
});
|
|
|
|
events.push(event);
|
|
eventStore.persist(event, done);
|
|
});
|
|
}
|
|
|
|
test('result', function(done) {
|
|
var expected = Object.create(null);
|
|
events.forEach(function(item) {
|
|
expected[item.remote.url] = {
|
|
syncToken: item.remote.syncToken,
|
|
id: item._id
|
|
};
|
|
});
|
|
|
|
subject._cachedEventsFor(calendar, function(err, result) {
|
|
done(function() {
|
|
assert.deepEqual(result, expected);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('#syncEvents', function() {
|
|
var events = [];
|
|
|
|
var calledWith;
|
|
|
|
function addEvent(cb) {
|
|
setup(function(done) {
|
|
var event = cb();
|
|
events.push(event);
|
|
eventStore.persist(event, done);
|
|
});
|
|
}
|
|
|
|
setup(function(done) {
|
|
calledWith = null;
|
|
events.length = 0;
|
|
|
|
subject._syncEvents = function() {
|
|
calledWith = arguments;
|
|
var cb = calledWith[calledWith.length - 1];
|
|
setTimeout(cb, 0, null);
|
|
};
|
|
|
|
var trans = db.transaction(
|
|
['accounts', 'calendars'],
|
|
'readwrite'
|
|
);
|
|
|
|
trans.oncomplete = function() {
|
|
done();
|
|
};
|
|
});
|
|
|
|
suite('sync with cached events', function() {
|
|
addEvent(function() {
|
|
return Factory('event', {
|
|
calendarId: calendar._id,
|
|
remote: {
|
|
url: 'one.ics',
|
|
syncToken: 'one'
|
|
}
|
|
});
|
|
});
|
|
|
|
test('result', function(done) {
|
|
subject.syncEvents(account, calendar, function() {
|
|
done(function() {
|
|
assert.equal(calledWith[0], account, 'has account');
|
|
assert.equal(calledWith[1], calendar, 'has calendar');
|
|
|
|
// expected cached events (url -> sync token)
|
|
var sentCache = calledWith[2];
|
|
assert.ok(sentCache, 'sends cache');
|
|
assert.ok(sentCache[events[0].remote.url], 'sends url');
|
|
});
|
|
});
|
|
});
|
|
|
|
test('offline handling', function(done) {
|
|
subject.isOffline = function() { return true; };
|
|
subject.syncEvents(account, calendar, function cb(cbError, cbResult) {
|
|
done(function() {
|
|
delete subject.isOffline;
|
|
assert.equal(cbError.name, 'offline');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('sync tokens match', function() {
|
|
setup(function() {
|
|
calendar.lastEventSyncToken = 'sync';
|
|
calendar.remote.syncToken = 'sync';
|
|
});
|
|
|
|
test('result', function(done) {
|
|
var isAsync = false;
|
|
// tokens match should not sync!
|
|
subject.syncEvents(account, calendar, function() {
|
|
assert.ok(!calledWith);
|
|
assert.ok(isAsync, 'should be async');
|
|
done();
|
|
});
|
|
isAsync = true;
|
|
});
|
|
|
|
test('offline handling', function(done) {
|
|
subject.isOffline = function() { return true; };
|
|
subject.syncEvents(account, calendar, function cb(cbError, cbResult) {
|
|
done(function() {
|
|
delete subject.isOffline;
|
|
assert.equal(cbError.name, 'offline');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|
|
|
|
suite('#_syncEvents', function() {
|
|
var calledWith;
|
|
var cached = {};
|
|
var error;
|
|
|
|
setup(function(done) {
|
|
// add an error to calendar to simulate clearing the error
|
|
calendar.error = {};
|
|
calendarStore.persist(calendar, done);
|
|
});
|
|
|
|
setup(function() {
|
|
error = null;
|
|
subject.service.stream = function() {
|
|
var args = Array.slice(arguments);
|
|
|
|
if (args.shift() !== 'caldav') {
|
|
throw new Error('expected caldav service');
|
|
}
|
|
|
|
if (args.shift() !== 'streamEvents') {
|
|
throw new Error('expected streamEvents');
|
|
}
|
|
|
|
calledWith = args;
|
|
var stream = new Responder();
|
|
stream.request = function(callback) {
|
|
setTimeout(callback, 0, error);
|
|
};
|
|
return stream;
|
|
};
|
|
});
|
|
|
|
test('with error', function(done) {
|
|
error = { name: 'caldav-authentication' };
|
|
|
|
function oncomplete(cbErr) {
|
|
done(function() {
|
|
assert.instanceOf(cbErr, CalendarError.Authentication);
|
|
assert.deepEqual(cbErr.detail, {
|
|
account: account,
|
|
calendar: calendar
|
|
});
|
|
});
|
|
}
|
|
|
|
subject._syncEvents(
|
|
account,
|
|
calendar,
|
|
cached,
|
|
oncomplete
|
|
);
|
|
});
|
|
|
|
suite('with first syncDate', function() {
|
|
var expectedSyncDate = new Date(2012, 0, 1);
|
|
|
|
setup(function(done) {
|
|
calendar.firstEventSyncDate = expectedSyncDate;
|
|
calendarStore.persist(calendar, done);
|
|
});
|
|
|
|
test('result', function(done) {
|
|
var expectedDate = new Date(expectedSyncDate.valueOf());
|
|
expectedDate.setDate(
|
|
expectedDate.getDate() - subject.daysToSyncInPast
|
|
);
|
|
|
|
var options = {
|
|
startDate: expectedDate,
|
|
cached: cached
|
|
};
|
|
|
|
|
|
// simulate error clearing
|
|
calendar.error = {};
|
|
|
|
var pull = subject._syncEvents(
|
|
account,
|
|
calendar,
|
|
cached,
|
|
oncomplete
|
|
);
|
|
|
|
function oncomplete() {
|
|
var expected = [
|
|
account.toJSON(),
|
|
calendar.remote,
|
|
options
|
|
];
|
|
|
|
assert.deepEqual(
|
|
calledWith,
|
|
expected
|
|
);
|
|
|
|
assert.instanceOf(
|
|
pull,
|
|
CaldavPullEvents
|
|
);
|
|
|
|
assert.equal(pull.account, account);
|
|
assert.equal(pull.calendar, calendar);
|
|
|
|
calendarStore.get(calendar._id, function(err, result) {
|
|
done(function() {
|
|
assert.ok(!result.error, 'clears errors');
|
|
|
|
assert.equal(
|
|
result.lastEventSyncToken,
|
|
result.remote.syncToken,
|
|
'updates sync token'
|
|
);
|
|
|
|
assert.deepEqual(
|
|
result.firstEventSyncDate,
|
|
expectedSyncDate,
|
|
'first sync date is never modified'
|
|
);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
test('without first sync date', function(done) {
|
|
var syncDate = Calc.createDay(new Date());
|
|
var expectedSyncDate = new Date(syncDate.valueOf());
|
|
|
|
syncDate.setDate(syncDate.getDate() - subject.daysToSyncInPast);
|
|
calendar.firstEventSyncDate = null;
|
|
|
|
var options = {
|
|
startDate: syncDate,
|
|
cached: cached
|
|
};
|
|
|
|
subject._syncEvents(account, calendar, cached, oncomplete);
|
|
|
|
function oncomplete() {
|
|
var expected = [
|
|
account.toJSON(),
|
|
calendar.remote,
|
|
options
|
|
];
|
|
|
|
assert.deepEqual(
|
|
calledWith,
|
|
expected
|
|
);
|
|
|
|
calendarStore.get(calendar._id, function(err, record) {
|
|
done(function() {
|
|
assert.deepEqual(
|
|
record.firstEventSyncDate,
|
|
expectedSyncDate,
|
|
'updates first sync date'
|
|
);
|
|
|
|
assert.equal(
|
|
record.lastEventSyncToken,
|
|
record.remote.syncToken,
|
|
'updates sync token'
|
|
);
|
|
});
|
|
});
|
|
}
|
|
});
|
|
});
|
|
|
|
suite('#ensureRecurrencesExpanded', function() {
|
|
var maxDate = new Date(2013, 2, 17);
|
|
|
|
test('with no icalComponent records', function(done) {
|
|
subject.ensureRecurrencesExpanded(maxDate, function(err, didExpand) {
|
|
done(function() {
|
|
assert.isFalse(didExpand);
|
|
});
|
|
});
|
|
});
|
|
|
|
test('with lastRecurrenceId after maxDate', function(done) {
|
|
var comp = Factory('icalComponent', {
|
|
ical: '',
|
|
eventId: 22,
|
|
lastRecurrenceId: new Date(2013, 2, 18)
|
|
});
|
|
|
|
componentStore.persist(comp, function(err) {
|
|
if (err) {
|
|
return done(err);
|
|
}
|
|
|
|
subject.ensureRecurrencesExpanded(maxDate, function(err, didExpand) {
|
|
if (err) {
|
|
return done(err);
|
|
}
|
|
|
|
done(function() {
|
|
assert.isFalse(didExpand, 'expanded');
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
suite('with simulated pre-expansion component', function() {
|
|
/*jshint -W027 */
|
|
// this test still is a little too much for travis
|
|
// CI... we need to ensure it is more reliable soon.
|
|
return;
|
|
var comp;
|
|
var didExpand;
|
|
var eventId;
|
|
var givenLastRecur = new Date(2012, 10, 1);
|
|
|
|
setup(function() {
|
|
var jCal = ICAL.parse(ical.recurringEvent);
|
|
var vcal = new ICAL.Component(jCal[1]);
|
|
var vevent = vcal.getFirstSubcomponent('vevent');
|
|
|
|
eventId = calendar._id + '-' + vevent.getFirstPropertyValue('uid');
|
|
});
|
|
|
|
setup(function(done) {
|
|
didExpand = false;
|
|
comp = Factory('icalComponent', {
|
|
calendarId: calendar._id,
|
|
eventId: eventId,
|
|
ical: ical.recurringEvent,
|
|
iterator: {},
|
|
lastRecurrenceId: Calc.dateToTransport(
|
|
givenLastRecur
|
|
)
|
|
});
|
|
|
|
componentStore.persist(comp, done);
|
|
|
|
core.serviceController.start();
|
|
});
|
|
|
|
setup(function(done) {
|
|
subject.ensureRecurrencesExpanded(maxDate, function(err, result) {
|
|
didExpand = result;
|
|
done();
|
|
});
|
|
});
|
|
|
|
test('after expansion', function(done) {
|
|
assert.isTrue(didExpand, 'has expanded');
|
|
|
|
var stores = ['icalComponents', 'busytimes'];
|
|
var trans = db.transaction(stores);
|
|
|
|
var pending = 0;
|
|
var results = {};
|
|
|
|
function next() {
|
|
if (!(--pending)) {
|
|
done(complete);
|
|
}
|
|
}
|
|
|
|
stores.forEach(function(store) {
|
|
pending++;
|
|
|
|
var obj = trans.objectStore(store);
|
|
obj.mozGetAll().onsuccess = function(e) {
|
|
results[store] = e.target.result;
|
|
next();
|
|
};
|
|
});
|
|
|
|
function complete() {
|
|
assert.length(results.icalComponents, 1);
|
|
assert.ok(results.busytimes.length, 1);
|
|
|
|
var comp = results.icalComponents[0];
|
|
var lastRecur = Calc.dateFromTransport(
|
|
comp.lastRecurrenceId
|
|
);
|
|
|
|
var dates = [];
|
|
|
|
results.busytimes.forEach(function(time) {
|
|
dates.push(time.startDate);
|
|
});
|
|
|
|
dates = dates.sort();
|
|
|
|
assert.isTrue(
|
|
dates[0].valueOf() > givenLastRecur.valueOf(),
|
|
'first occurrence is after last given'
|
|
);
|
|
|
|
assert.isTrue(
|
|
dates[dates.length - 1].valueOf() < maxDate.valueOf(),
|
|
'last occurrence is before max date'
|
|
);
|
|
|
|
assert.isTrue(
|
|
lastRecur.valueOf() > givenLastRecur.valueOf(),
|
|
'should expand beyond the given lastRecurId'
|
|
);
|
|
}
|
|
});
|
|
});
|
|
});
|
|
});
|
|
|
|
});
|