Test suite for repeating tasks--includes offline tests and tests for syncing with astrid.com, producteev, and gtasks, with repeating tasks completed remotely and locally. Also includes some bug fixes exposed by the tests.

pull/14/head
Sam Bosley 15 years ago
parent dc1c14a5b7
commit b9b8e47cd8

@ -270,6 +270,20 @@ public class ActFmSyncProvider extends SyncProvider<ActFmTaskContainer> {
return local;
}
@Override
protected void readRemotelyUpdated(SyncData<ActFmTaskContainer> data) throws IOException {
int serverTime = Preferences.getInt(ActFmPreferenceService.PREF_SERVER_TIME, 0);
ArrayList<ActFmTaskContainer> remoteTasks = new ArrayList<ActFmTaskContainer>();
try {
fetchRemoteTasks(serverTime, remoteTasks);
data.remoteUpdated = remoteTasks;
} catch (JSONException e) {
// Ingnored
}
super.readRemotelyUpdated(data);
}
// ----------------------------------------------------------------------
// --------------------------------------------------------- read / write
// ----------------------------------------------------------------------

@ -183,6 +183,8 @@ public class GtasksSyncProvider extends SyncProvider<GtasksTaskContainer> {
SyncData<GtasksTaskContainer> syncData = populateSyncData();
try {
synchronizeTasks(syncData);
AndroidUtilities.sleepDeep(3000L); // Wait for changes to be saved (i.e. for repeating tasks to be cloned)
checkForCreatedDuringSync();
} finally {
syncData.localCreated.close();
syncData.localUpdated.close();
@ -207,6 +209,19 @@ public class GtasksSyncProvider extends SyncProvider<GtasksTaskContainer> {
}
}
private void checkForCreatedDuringSync() {
TodorooCursor<Task> localCreated = gtasksMetadataService.getLocallyCreated(PROPERTIES);
try {
SyncData<GtasksTaskContainer> localCreatedData = new SyncData<GtasksTaskContainer>(null, localCreated, null);
sendLocallyCreated(localCreatedData, new HashMap<String, Integer>());
} catch (IOException e) {
handleException("gtasks-sync", e, true);
} finally {
System.err.println("Sent " + localCreated.getCount() + " new tasks");
localCreated.close();
}
}
private void getActiveList(TaskLists taskView) throws IOException {
String listId;
if(taskView.items.size() == 0) {

@ -228,6 +228,8 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
SyncData<ProducteevTaskContainer> syncData = populateSyncData(remoteTasks);
try {
synchronizeTasks(syncData);
AndroidUtilities.sleepDeep(3000L);
checkForCreatedDuringSync();
} finally {
syncData.localCreated.close();
syncData.localUpdated.close();
@ -253,6 +255,19 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
}
}
private void checkForCreatedDuringSync() {
TodorooCursor<Task> localCreated = dataService.getLocallyCreated(PROPERTIES);
try {
SyncData<ProducteevTaskContainer> localCreatedData = new SyncData<ProducteevTaskContainer>(null, localCreated, null);
sendLocallyCreated(localCreatedData, new HashMap<String, Integer>());
} catch (IOException e) {
handleException("gtasks-sync", e, true);
} finally {
System.err.println("Sent " + localCreated.getCount() + " new tasks");
localCreated.close();
}
}
/**
* @param activities
* @return
@ -592,7 +607,8 @@ public class ProducteevSyncProvider extends SyncProvider<ProducteevTaskContainer
@Override
protected void write(ProducteevTaskContainer task) throws IOException {
if(task.task.isSaved()) {
Task local = PluginServices.getTaskService().fetchById(task.task.getId(), Task.COMPLETION_DATE);
Task local = PluginServices.getTaskService().fetchById(task.task.getId(), Task.COMPLETION_DATE, Task.FLAGS);
task.task.setFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION, local.getFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION));
if(task.task.isCompleted() && !local.isCompleted())
StatisticsService.reportEvent("pdv-task-completed"); //$NON-NLS-1$
}

@ -42,7 +42,7 @@ public class RepeatTaskCompleteListener extends BroadcastReceiver {
return;
Task task = PluginServices.getTaskService().fetchById(taskId, Task.ID, Task.RECURRENCE,
Task.DUE_DATE, Task.FLAGS, Task.HIDE_UNTIL, Task.REMOTE_ID);
Task.DUE_DATE, Task.FLAGS, Task.HIDE_UNTIL, Task.REMOTE_ID, Task.COMPLETION_DATE);
if(task == null)
return;
@ -75,6 +75,8 @@ public class RepeatTaskCompleteListener extends BroadcastReceiver {
}
// clone to create new task
Flags.set(Flags.ACTFM_SUPPRESS_SYNC);
Flags.set(Flags.GTASKS_SUPPRESS_SYNC);
Task clone = PluginServices.getTaskService().clone(task);
clone.setValue(Task.DUE_DATE, newDueDate);
clone.setValue(Task.HIDE_UNTIL, hideUntil);
@ -110,7 +112,7 @@ public class RepeatTaskCompleteListener extends BroadcastReceiver {
RRule rrule = initRRule(recurrence);
// initialize startDateAsDV
Date original = setUpStartDate(task, repeatAfterCompletion);
Date original = setUpStartDate(task, repeatAfterCompletion, rrule.getFreq());
DateValue startDateAsDV = setUpStartDateAsDV(task, rrule, original, repeatAfterCompletion);
if(rrule.getFreq() == Frequency.HOURLY)
@ -178,14 +180,18 @@ public class RepeatTaskCompleteListener extends BroadcastReceiver {
return rrule;
}
/** Set up repeat start date */
private static Date setUpStartDate(Task task, boolean repeatAfterCompletion) {
/** Set up repeat start date
* @param frequency */
private static Date setUpStartDate(Task task, boolean repeatAfterCompletion, Frequency frequency) {
Date startDate = new Date();
if(task.hasDueDate()) {
Date dueDate = new Date(task.getValue(Task.DUE_DATE));
if(!repeatAfterCompletion)
if(repeatAfterCompletion)
startDate = new Date(task.getValue(Task.COMPLETION_DATE));
else
startDate = dueDate;
else if(task.hasDueTime()) {
if(task.hasDueTime() && frequency != Frequency.HOURLY && frequency != Frequency.MINUTELY) {
startDate.setHours(dueDate.getHours());
startDate.setMinutes(dueDate.getMinutes());
startDate.setSeconds(dueDate.getSeconds());
@ -199,8 +205,7 @@ public class RepeatTaskCompleteListener extends BroadcastReceiver {
// if repeat after completion with weekdays, pre-compute
if(repeatAfterCompletion && rrule.getByDay().size() > 0) {
startDate = new Date(startDate.getTime() + DateUtilities.ONE_WEEK * rrule.getInterval() -
DateUtilities.ONE_DAY);
startDate = new Date(startDate.getTime() + DateUtilities.ONE_WEEK * rrule.getInterval());
rrule.setInterval(1);
}

@ -1098,6 +1098,8 @@ public class TaskListActivity extends ListActivity implements OnScrollListener,
Task original = new Task();
original.setId(itemId);
Flags.set(Flags.ACTFM_SUPPRESS_SYNC);
Flags.set(Flags.GTASKS_SUPPRESS_SYNC);
Task clone = taskService.clone(original);
clone.setValue(Task.CREATION_DATE, DateUtilities.now());
clone.setValue(Task.COMPLETION_DATE, 0L);

@ -111,6 +111,7 @@ public class TaskService {
try {
if(cursor.getCount() > 0) {
Metadata metadata = new Metadata();
taskDao.save(newTask);
long newId = newTask.getId();
for(cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
metadata.readFromCursor(cursor);
@ -119,7 +120,7 @@ public class TaskService {
continue;
if(GtasksMetadata.METADATA_KEY.equals(metadata.getValue(Metadata.KEY)))
metadata.setValue(GtasksMetadata.ID, "0"); //$NON-NLS-1$
metadata.setValue(GtasksMetadata.ID, "");
if(ProducteevTask.METADATA_KEY.equals(metadata.getValue(Metadata.KEY)))
metadata.setValue(ProducteevTask.ID, 0L);
if(MilkTaskFields.METADATA_KEY.equals(metadata.getValue(Metadata.KEY))) {

@ -0,0 +1,421 @@
package com.todoroo.astrid.repeats;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import android.content.Intent;
import com.google.ical.values.Frequency;
import com.google.ical.values.RRule;
import com.google.ical.values.Weekday;
import com.google.ical.values.WeekdayNum;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.api.AstridApiConstants;
import com.todoroo.astrid.dao.MetadataDao;
import com.todoroo.astrid.dao.TaskDao;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.StartupService;
import com.todoroo.astrid.test.DatabaseTestCase;
import com.todoroo.astrid.utility.Flags;
public class NewRepeatTests<REMOTE_MODEL> extends DatabaseTestCase {
@Autowired
TaskDao taskDao;
@Autowired
MetadataDao metadataDao;
@Override
protected void setUp() throws Exception {
super.setUp();
Preferences.setStringFromInteger(R.string.p_default_urgency_key, 0);
RepeatTaskCompleteListener.setSkipActFmCheck(true);
}
private void saveAndTriggerRepeatListener(Task task) {
Flags.set(Flags.SUPPRESS_HOOKS);
if(task.isSaved())
taskDao.saveExisting(task);
else
taskDao.createNew(task);
Intent intent = new Intent(AstridApiConstants.BROADCAST_EVENT_TASK_COMPLETED);
intent.putExtra(AstridApiConstants.EXTRAS_TASK_ID, task.getId());
new RepeatTaskCompleteListener().onReceive(getContext(), intent);
}
protected void waitAndSync() {
// Subclasses can override this to insert sync functionality
}
/**
* @param t
* @param expectedDueDate
*/
protected REMOTE_MODEL assertTaskExistsRemotely(Task t, long expectedDueDate) {
// Subclasses can override this to check the existence of remote objects
return null;
}
protected void assertTaskCompletedRemotely(Task t) {
// Subclasses can override this to check the status of the corresponding remote task
}
/**
* @param remoteModel
*/
protected long setCompletionDate(boolean completeBefore, Task t,
REMOTE_MODEL remoteModel, long dueDate) {
long completionDate;
if (completeBefore)
completionDate = dueDate - DateUtilities.ONE_DAY;
else
completionDate = dueDate + DateUtilities.ONE_DAY;
t.setValue(Task.COMPLETION_DATE, completionDate);
saveAndTriggerRepeatListener(t);
return completionDate;
}
protected void assertTimesMatch(long expectedTime, long newDueDate) {
assertTrue(String.format("Expected %s, was %s", new Date(expectedTime), new Date(newDueDate)),
Math.abs(expectedTime - newDueDate) < 5000);
}
/*
* Tests for no sync
*/
public void testNoRepeat() {
Task t = new Task();
t.setValue(Task.TITLE, "no repeat");
taskDao.save(t);
t.setValue(Task.COMPLETION_DATE, DateUtilities.now());
saveAndTriggerRepeatListener(t);
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.ID));
try {
assertEquals(1, cursor.getCount());
} finally {
cursor.close();
}
}
protected void testRepeating(boolean completeBefore, boolean fromCompletion, RRule rrule, Frequency frequency, String title) {
for (int i = 0; i < StartupService.INTRO_TASK_SIZE; i++) { // Create startup tasks so sync services don't miss the test tasks
Task temp = new Task();
temp.setValue(Task.TITLE, "" + i);
taskDao.save(temp);
}
Task t = new Task();
t.setValue(Task.TITLE, title);
long dueDate = DateUtilities.now() + DateUtilities.ONE_DAY * 3;
dueDate = (dueDate / 1000L) * 1000L; // Strip milliseconds
if (fromCompletion)
t.setFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION, true);
t.setValue(Task.DUE_DATE, dueDate);
if (rrule == null) {
rrule = new RRule();
rrule.setFreq(frequency);
int interval = 5;
rrule.setInterval(interval);
}
t.setValue(Task.RECURRENCE, rrule.toIcal());
taskDao.save(t);
waitAndSync();
t = taskDao.fetch(t.getId(), Task.PROPERTIES); // Refetch
REMOTE_MODEL remoteModel = assertTaskExistsRemotely(t, dueDate);
long completionDate = setCompletionDate(completeBefore, t, remoteModel, dueDate);
waitAndSync();
assertTaskCompletedRemotely(t);
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.PROPERTIES).where(TaskCriteria.notDeleted()));
try {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
Task task = new Task(cursor);
System.err.println("Task: " + task.getValue(Task.TITLE) + ", due: " + task.getValue(Task.DUE_DATE));
}
assertEquals(StartupService.INTRO_TASK_SIZE + 2, cursor.getCount());
cursor.moveToFirst();
for (int i = 0; i < StartupService.INTRO_TASK_SIZE; i++) {
cursor.moveToNext();
}
t.readFromCursor(cursor);
assertEquals(title, t.getValue(Task.TITLE));
assertEquals(dueDate, (long)t.getValue(Task.DUE_DATE));
assertTrue(t.isCompleted());
cursor.moveToNext();
t.readFromCursor(cursor);
assertEquals(title, t.getValue(Task.TITLE));
assertFalse(t.isCompleted());
long newDueDate = t.getValue(Task.DUE_DATE);
assertTrue(t.hasDueTime());
long fromDate = (fromCompletion? completionDate : dueDate);
long expectedTime = computeNextDueDateFromDate(fromDate, rrule, fromCompletion);
assertTaskExistsRemotely(t, expectedTime);
assertTimesMatch(expectedTime, newDueDate);
} finally {
cursor.close();
}
}
private long computeWeeklyCaseDueDate(long fromDate, RRule rrule, boolean fromCompletion) {
long result = fromDate;
Frequency frequency = rrule.getFreq();
assertTrue(frequency.equals(Frequency.WEEKLY));
List<WeekdayNum> weekdayNums = rrule.getByDay();
if (weekdayNums.size() == 0) {
result += DateUtilities.ONE_WEEK * rrule.getInterval();
return result;
}
HashSet<Weekday> weekdays = new HashSet<Weekday>();
for (WeekdayNum curr : weekdayNums) {
weekdays.add(curr.wday);
}
Weekday[] allWeekdays = Weekday.values();
result -= DateUtilities.ONE_DAY;
Date date = new Date(result);
Weekday start = allWeekdays[date.getDay()];
int i;
for (i = 0; i < allWeekdays.length; i++) {
if (start == allWeekdays[i]) break;
}
int index = i;
int daysToAdd = 0;
Weekday next = null;
for (i = index + 1; i < allWeekdays.length; i++) {
Weekday curr = allWeekdays[i];
daysToAdd++;
if (weekdays.contains(curr)) {
next = curr;
break;
}
}
if (next == null) {
for (i = 0; i < index + 1; i++) {
Weekday curr = allWeekdays[i];
daysToAdd++;
if (weekdays.contains(curr)) {
next = curr;
break;
}
}
}
if (fromCompletion) {
result += DateUtilities.ONE_WEEK * rrule.getInterval();
}
result += DateUtilities.ONE_DAY * daysToAdd;
return result;
}
/** Advanced weekly repeating tests */
protected long computeNextDueDateFromDate(long fromDate, RRule rrule, boolean fromCompletion) {
long expectedTime = fromDate;
Frequency frequency = rrule.getFreq();
int interval = rrule.getInterval();
if (frequency.equals(Frequency.MINUTELY)) {
expectedTime += DateUtilities.ONE_MINUTE * interval;
} else if (frequency.equals(Frequency.HOURLY)) {
expectedTime += DateUtilities.ONE_HOUR * interval;
} else if (frequency.equals(Frequency.DAILY)) {
expectedTime += DateUtilities.ONE_DAY * interval;
} else if (frequency.equals(Frequency.WEEKLY)) {
expectedTime = computeWeeklyCaseDueDate(fromDate, rrule, fromCompletion);
} else if (frequency.equals(Frequency.MONTHLY)) {
Date originalDate = new Date(expectedTime);
for (int i = 0; i < interval; i++) {
int month = originalDate.getMonth();
if (month == 11) { // Roll over the year and set the month to January
originalDate.setYear(originalDate.getYear() + 1);
originalDate.setMonth(0);
} else {
originalDate.setMonth(originalDate.getMonth() + 1);
}
}
expectedTime = originalDate.getTime();
} else if (frequency.equals(Frequency.YEARLY)) {
Date originalCompleteDate = new Date(expectedTime);
originalCompleteDate.setYear(originalCompleteDate.getYear() + interval);
expectedTime = originalCompleteDate.getTime();
}
return expectedTime;
}
private void testFromDueDate(boolean completeBefore, Frequency frequency, String title) {
testRepeating(completeBefore, false, null, frequency, title);
}
private void testFromCompletionDate(boolean completeBefore, Frequency frequency, String title) {
testRepeating(completeBefore, true, null, frequency, title);
}
/** Tests for repeating from due date */
public void testRepeatMinutelyFromDueDateCompleteBefore() {
testFromDueDate(true, Frequency.MINUTELY, "minutely-before");
}
public void testRepeatMinutelyFromDueDateCompleteAfter() {
testFromDueDate(false, Frequency.MINUTELY, "minutely-after");
}
public void testRepeatHourlyFromDueDateCompleteBefore() {
testFromDueDate(true, Frequency.HOURLY, "hourly-before");
}
public void testRepeatHourlyFromDueDateCompleteAfter() {
testFromDueDate(false, Frequency.HOURLY, "hourly-after");
}
public void testRepeatDailyFromDueDateCompleteBefore() {
testFromDueDate(true, Frequency.DAILY, "daily-before");
}
public void testRepeatDailyFromDueDateCompleteAfter() {
testFromDueDate(false, Frequency.DAILY, "daily-after");
}
public void testRepeatWeeklyFromDueDateCompleteBefore() {
testFromDueDate(true, Frequency.WEEKLY, "weekly-before");
}
public void testRepeatWeeklyFromDueDateCompleteAfter() {
testFromDueDate(false, Frequency.WEEKLY, "weekly-after");
}
public void testRepeatMonthlyFromDueDateCompleteBefore() {
testFromDueDate(true, Frequency.MONTHLY, "monthly-before");
}
public void testRepeatMonthlyFromDueDateCompleteAfter() {
testFromDueDate(false, Frequency.MONTHLY, "monthly-after");
}
public void testRepeatYearlyFromDueDateCompleteBefore() {
testFromDueDate(true, Frequency.YEARLY, "yearly-before");
}
public void testRepeatYearlyFromDueDateCompleteAfter() {
testFromDueDate(false, Frequency.YEARLY, "yearly-after");
}
/** Tests for repeating from completionDate */
public void testRepeatMinutelyFromCompleteDateCompleteBefore() {
testFromCompletionDate(true, Frequency.MINUTELY, "minutely-before");
}
public void testRepeatMinutelyFromCompleteDateCompleteAfter() {
testFromCompletionDate(false, Frequency.MINUTELY, "minutely-after");
}
public void testRepeatHourlyFromCompleteDateCompleteBefore() {
testFromCompletionDate(true, Frequency.HOURLY, "hourly-before");
}
public void testRepeatHourlyFromCompleteDateCompleteAfter() {
testFromCompletionDate(false, Frequency.HOURLY, "hourly-after");
}
public void testRepeatDailyFromCompleteDateCompleteBefore() {
testFromCompletionDate(true, Frequency.DAILY, "daily-before");
}
public void testRepeatDailyFromCompleteDateCompleteAfter() {
testFromCompletionDate(false, Frequency.DAILY, "daily-after");
}
public void testRepeatWeeklyFromCompleteDateCompleteBefore() {
testFromCompletionDate(true, Frequency.WEEKLY, "weekly-before");
}
public void testRepeatWeeklyFromCompleteDateCompleteAfter() {
testFromCompletionDate(false, Frequency.WEEKLY, "weekly-after");
}
public void testRepeatMonthlyFromCompleteDateCompleteBefore() {
testFromCompletionDate(true, Frequency.MONTHLY, "monthly-before");
}
public void testRepeatMonthlyFromCompleteDateCompleteAfter() {
testFromCompletionDate(false, Frequency.MONTHLY, "monthly-after");
}
public void testRepeatYearlyFromCompleteDateCompleteBefore() {
testFromCompletionDate(true, Frequency.YEARLY, "yearly-before");
}
public void testRepeatYearlyFromCompleteDateCompleteAfter() {
testFromCompletionDate(false, Frequency.YEARLY, "yearly-after");
}
private void testAdvancedWeeklyFromDueDate(boolean completeBefore, String title) {
RRule rrule = new RRule();
rrule.setFreq(Frequency.WEEKLY);
int interval = 1;
rrule.setInterval(interval);
List<WeekdayNum> weekdays = new ArrayList<WeekdayNum>();
weekdays.add(new WeekdayNum(0, Weekday.MO));
weekdays.add(new WeekdayNum(0, Weekday.WE));
rrule.setByDay(weekdays);
testRepeating(completeBefore, false, rrule, Frequency.WEEKLY, title);
}
private void testAdvancedWeeklyFromCompleteDate(boolean completeBefore, String title) {
RRule rrule = new RRule();
rrule.setFreq(Frequency.WEEKLY);
int interval = 1;
rrule.setInterval(interval);
List<WeekdayNum> weekdays = new ArrayList<WeekdayNum>();
weekdays.add(new WeekdayNum(0, Weekday.MO));
weekdays.add(new WeekdayNum(0, Weekday.WE));
rrule.setByDay(weekdays);
testRepeating(completeBefore, true, rrule, Frequency.WEEKLY, title);
}
public void testAdvancedRepeatWeeklyFromDueDateCompleteBefore() {
testAdvancedWeeklyFromDueDate(true, "advanced-weekly-before");
}
public void testAdvancedRepeatWeeklyFromDueDateCompleteAfter() {
testAdvancedWeeklyFromDueDate(false, "advanced-weekly-after");
}
public void testAdvancedRepeatWeeklyFromCompleteDateCompleteBefore() {
testAdvancedWeeklyFromCompleteDate(true, "advanced-weekly-before");
}
public void testAdvancedRepeatWeeklyFromCompleteDateCompleteAfter() {
testAdvancedWeeklyFromCompleteDate(false, "advanced-weekly-after");
}
}

@ -43,7 +43,6 @@ public class RepeatTests extends DatabaseTestCase {
task.setValue(Task.COMPLETION_DATE, DateUtilities.now());
saveAndTriggerRepeatListener(task);
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.ID));
try {
assertEquals(1, cursor.getCount());

@ -0,0 +1,177 @@
package com.todoroo.astrid.repeats;
import java.io.IOException;
import java.util.ArrayList;
import org.json.JSONArray;
import org.json.JSONObject;
import com.google.ical.values.Frequency;
import com.google.ical.values.RRule;
import com.timsu.astrid.R;
import com.todoroo.andlib.data.TodorooCursor;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.sql.Query;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.actfm.sync.ActFmDataService;
import com.todoroo.astrid.actfm.sync.ActFmInvoker;
import com.todoroo.astrid.actfm.sync.ActFmPreferenceService;
import com.todoroo.astrid.actfm.sync.ActFmSyncProvider;
import com.todoroo.astrid.actfm.sync.ActFmSyncService;
import com.todoroo.astrid.dao.TaskDao.TaskCriteria;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.StartupService;
public class RepeatTestsActFmSync extends NewRepeatTests<Task> {
@Autowired MetadataService metadataService;
@Autowired ActFmDataService actFmDataService;
@Autowired ActFmSyncService actFmSyncService;
@Autowired ActFmPreferenceService actFmPreferenceService;
protected static ActFmInvoker invoker = null;
private static final String TEST_ACCOUNT = "sync_tester2@astrid.com";
private static final String TEST_PASSWORD = "wonkwonkjj";
private static boolean initialized = false;
@Override
protected void setUp() throws Exception {
super.setUp();
Preferences.setStringFromInteger(R.string.p_default_urgency_key, 0);
RepeatTaskCompleteListener.setSkipActFmCheck(false);
if (!initialized) {
initializeTestService();
}
clearTasks();
}
private void initializeTestService() throws Exception {
invoker = new ActFmInvoker();
authenticate(TEST_ACCOUNT, null, ActFmInvoker.PROVIDER_PASSWORD, TEST_PASSWORD);
initialized = true;
}
private void clearTasks() throws Exception {
JSONObject result = invoker.invoke("task_list", "active", 1);
JSONArray taskList = result.getJSONArray("list");
for(int i = 0; i < taskList.length(); i++) {
Task remote = new Task();
ActFmSyncService.JsonHelper.taskFromJson(taskList.getJSONObject(i), remote, new ArrayList<Metadata>());
remote.setValue(Task.DELETION_DATE, DateUtilities.now());
actFmSyncService.pushTaskOnSave(remote, remote.getSetValues());
}
}
private void authenticate(String email, String name, String provider, String secret) {
try {
JSONObject result = invoker.authenticate(email, name, provider, secret);
String token = invoker.getToken();
postAuthenticate(result, token);
} catch (IOException e) {
e.printStackTrace();
fail("Error authenticating");
}
}
@SuppressWarnings("nls")
private void postAuthenticate(JSONObject result, String token) {
actFmPreferenceService.setToken(token);
Preferences.setLong(ActFmPreferenceService.PREF_USER_ID,
result.optLong("id"));
Preferences.setString(ActFmPreferenceService.PREF_NAME, result.optString("name"));
Preferences.setString(ActFmPreferenceService.PREF_EMAIL, result.optString("email"));
Preferences.setString(ActFmPreferenceService.PREF_PICTURE, result.optString("picture"));
}
@Override
protected void waitAndSync() {
AndroidUtilities.sleepDeep(3000L);
new ActFmSyncProvider().synchronize(null);
AndroidUtilities.sleepDeep(3000L);
}
/**
* @param t
* @param expectedDueDate
*/
@Override
protected Task assertTaskExistsRemotely(Task t, long expectedDueDate) {
Task remote = new Task();
try {
ActFmSyncService.JsonHelper.taskFromJson(invoker.invoke("task_show", "id", t.getValue(Task.REMOTE_ID)), remote,
new ArrayList<Metadata>());
assertTimesMatch(expectedDueDate, remote.getValue(Task.DUE_DATE).longValue());
} catch (Exception e) {
e.printStackTrace();
fail("Error in ActFm invoker");
}
return remote;
}
@Override
protected void testRepeating(boolean completeBefore, boolean fromCompletion, RRule rrule, Frequency frequency, String title) {
for (int i = 0; i < StartupService.INTRO_TASK_SIZE; i++) { // Create startup tasks so sync services don't miss the test tasks
Task temp = new Task();
temp.setValue(Task.TITLE, "" + i);
taskDao.save(temp);
}
Task t = new Task();
t.setValue(Task.TITLE, title);
long dueDate = DateUtilities.now() + DateUtilities.ONE_DAY * 3;
dueDate = (dueDate / 1000L) * 1000L; // Strip milliseconds
if (fromCompletion)
t.setFlag(Task.FLAGS, Task.FLAG_REPEAT_AFTER_COMPLETION, true);
t.setValue(Task.DUE_DATE, dueDate);
if (rrule == null) {
rrule = new RRule();
rrule.setFreq(frequency);
int interval = 5;
rrule.setInterval(interval);
}
t.setValue(Task.RECURRENCE, rrule.toIcal());
taskDao.save(t);
waitAndSync();
t = taskDao.fetch(t.getId(), Task.PROPERTIES); // Refetch
Task remoteModel = assertTaskExistsRemotely(t, dueDate);
long completionDate = setCompletionDate(completeBefore, t, remoteModel, dueDate);
waitAndSync();
TodorooCursor<Task> cursor = taskDao.query(Query.select(Task.PROPERTIES).where(TaskCriteria.notDeleted()));
try {
assertEquals(StartupService.INTRO_TASK_SIZE + 1, cursor.getCount());
cursor.moveToFirst();
for (int i = 0; i < StartupService.INTRO_TASK_SIZE; i++) {
cursor.moveToNext();
}
t.readFromCursor(cursor);
long fromDate = (fromCompletion? completionDate : dueDate);
long expectedTime = computeNextDueDateFromDate(fromDate, rrule, fromCompletion);
long newDueDate = t.getValue(Task.DUE_DATE);
assertTaskExistsRemotely(t, expectedTime);
assertTrue(t.hasDueTime());
assertEquals(title, t.getValue(Task.TITLE));
assertTimesMatch(expectedTime, newDueDate);
assertFalse(t.isCompleted());
} finally {
cursor.close();
}
}
}

@ -0,0 +1,112 @@
package com.todoroo.astrid.repeats;
import java.util.ArrayList;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Task;
public class RepeatTestsActFmSyncRemote extends RepeatTestsActFmSync {
@Override
protected long setCompletionDate(boolean completeBefore, Task t,
Task remoteModel, long dueDate) {
long completionDate;
if (completeBefore)
completionDate = dueDate - DateUtilities.ONE_DAY;
else
completionDate = dueDate + DateUtilities.ONE_DAY;
ArrayList<Object> params = new ArrayList<Object>();
params.add("completed"); params.add(completionDate / 1000L);
params.add("id"); params.add(remoteModel.getValue(Task.REMOTE_ID));
try {
invoker.invoke("task_save", params.toArray(new Object[params.size()]));
} catch (Exception e) {
e.printStackTrace();
fail("Error in actfm invoker");
}
return completionDate;
}
@Override
public void testRepeatMinutelyFromCompleteDateCompleteBefore() {
// (DISABLED) super.testRepeatMinutelyFromCompleteDateCompleteBefore();
}
@Override
public void testRepeatMinutelyFromCompleteDateCompleteAfter() {
// (DISABLED) super.testRepeatMinutelyFromCompleteDateCompleteAfter();
}
@Override
public void testRepeatHourlyFromCompleteDateCompleteBefore() {
// (DISABLED) super.testRepeatHourlyFromCompleteDateCompleteBefore();
}
@Override
public void testRepeatHourlyFromCompleteDateCompleteAfter() {
// (DISABLED) super.testRepeatHourlyFromCompleteDateCompleteAfter();
}
@Override
public void testRepeatDailyFromCompleteDateCompleteBefore() {
// (DISABLED) super.testRepeatDailyFromCompleteDateCompleteBefore();
}
@Override
public void testRepeatDailyFromCompleteDateCompleteAfter() {
// (DISABLED) super.testRepeatDailyFromCompleteDateCompleteAfter();
}
@Override
public void testRepeatWeeklyFromCompleteDateCompleteBefore() {
// (DISABLED) super.testRepeatWeeklyFromCompleteDateCompleteBefore();
}
@Override
public void testRepeatWeeklyFromCompleteDateCompleteAfter() {
// (DISABLED) super.testRepeatWeeklyFromCompleteDateCompleteAfter();
}
@Override
public void testRepeatMonthlyFromCompleteDateCompleteBefore() {
// (DISABLED) super.testRepeatMonthlyFromCompleteDateCompleteBefore();
}
@Override
public void testRepeatMonthlyFromCompleteDateCompleteAfter() {
// (DISABLED) super.testRepeatMonthlyFromCompleteDateCompleteAfter();
}
@Override
public void testRepeatYearlyFromCompleteDateCompleteBefore() {
// (DISABLED) super.testRepeatYearlyFromCompleteDateCompleteBefore();
}
@Override
public void testRepeatYearlyFromCompleteDateCompleteAfter() {
// (DISABLED) super.testRepeatYearlyFromCompleteDateCompleteAfter();
}
@Override
public void testAdvancedRepeatWeeklyFromDueDateCompleteBefore() {
// (DISABLED) super.testAdvancedRepeatWeeklyFromDueDateCompleteBefore();
}
@Override
public void testAdvancedRepeatWeeklyFromDueDateCompleteAfter() {
// (DISABLED) super.testAdvancedRepeatWeeklyFromDueDateCompleteAfter();
}
@Override
public void testAdvancedRepeatWeeklyFromCompleteDateCompleteBefore() {
// (DISABLED) super.testAdvancedRepeatWeeklyFromCompleteDateCompleteBefore();
}
@Override
public void testAdvancedRepeatWeeklyFromCompleteDateCompleteAfter() {
// (DISABLED) super.testAdvancedRepeatWeeklyFromCompleteDateCompleteAfter();
}
}

@ -0,0 +1,152 @@
package com.todoroo.astrid.repeats;
import java.io.IOException;
import java.util.Date;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.content.Intent;
import android.os.Bundle;
import com.google.api.client.googleapis.extensions.android2.auth.GoogleAccountManager;
import com.google.api.services.tasks.v1.model.Tasks;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.service.ContextManager;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.data.Metadata;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.GtasksMetadata;
import com.todoroo.astrid.gtasks.GtasksMetadataService;
import com.todoroo.astrid.gtasks.GtasksPreferenceService;
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
import com.todoroo.astrid.gtasks.api.GtasksService;
import com.todoroo.astrid.gtasks.auth.GtasksTokenValidator;
import com.todoroo.astrid.gtasks.sync.GtasksSyncProvider;
import com.todoroo.astrid.service.MetadataService;
public class RepeatTestsGtasksSync extends NewRepeatTests<com.google.api.services.tasks.v1.model.Task> {
@Autowired MetadataService metadataService;
@Autowired GtasksMetadataService gtasksMetadataService;
@Autowired GtasksPreferenceService gtasksPreferenceService;
private static final String TEST_ACCOUNT = "sync_tester2@astrid.com";
private static final String DEFAULT_LIST = "@default";
private static boolean initialized = false;
protected static GtasksService gtasksService;
@Override
protected void setUp() throws Exception {
super.setUp();
Preferences.setStringFromInteger(R.string.p_default_urgency_key, 0);
RepeatTaskCompleteListener.setSkipActFmCheck(true);
if (!initialized) {
initializeTestService();
}
setupTestList();
}
@Override
protected void waitAndSync() {
AndroidUtilities.sleepDeep(3000L);
new GtasksSyncProvider().synchronize(null);
AndroidUtilities.sleepDeep(3000L);
}
@Override
protected com.google.api.services.tasks.v1.model.Task assertTaskExistsRemotely(Task t, long expectedRemoteTime) {
Metadata metadata = gtasksMetadataService.getTaskMetadata(t.getId());
assertNotNull(metadata);
String listId = metadata.getValue(GtasksMetadata.LIST_ID);
String taskId = metadata.getValue(GtasksMetadata.ID);
com.google.api.services.tasks.v1.model.Task remote = null;
try {
remote = gtasksService.getGtask(listId, taskId);
} catch (IOException e){
e.printStackTrace();
fail("Exception in gtasks service");
}
assertNotNull(remote);
assertEquals(t.getValue(Task.TITLE), remote.title);
Date expected = new Date(expectedRemoteTime);
expected.setHours(0);
expected.setMinutes(0);
expected.setSeconds(0);
long gtasksTime = GtasksApiUtilities.gtasksDueTimeToUnixTime(remote.due, 0);
assertEquals(expected.getTime(), gtasksTime);
return remote;
}
@Override
protected void assertTaskCompletedRemotely(Task t) {
Metadata metadata = gtasksMetadataService.getTaskMetadata(t.getId());
assertNotNull(metadata);
String listId = metadata.getValue(GtasksMetadata.LIST_ID);
String taskId = metadata.getValue(GtasksMetadata.ID);
com.google.api.services.tasks.v1.model.Task remote = null;
try {
remote = gtasksService.getGtask(listId, taskId);
} catch (IOException e) {
e.printStackTrace();
fail("Exception in gtasks service");
}
assertNotNull(remote);
assertEquals(t.getValue(Task.TITLE), remote.title);
assertEquals("completed", remote.status);
}
private void initializeTestService() throws Exception {
GoogleAccountManager manager = new GoogleAccountManager(ContextManager.getContext());
Account[] accounts = manager.getAccounts();
Account toUse = null;
for (Account a : accounts) {
if (a.name.equals(TEST_ACCOUNT)) {
toUse = a;
break;
}
}
if (toUse == null) {
if (accounts.length == 0) {
return;
}
toUse = accounts[0];
}
Preferences.setString(GtasksPreferenceService.PREF_USER_NAME, toUse.name);
AccountManagerFuture<Bundle> accountManagerFuture = manager.manager.getAuthToken(toUse, "oauth2:https://www.googleapis.com/auth/tasks", true, null, null);
Bundle authTokenBundle = accountManagerFuture.getResult();
if (authTokenBundle.containsKey(AccountManager.KEY_INTENT)) {
Intent i = (Intent) authTokenBundle.get(AccountManager.KEY_INTENT);
ContextManager.getContext().startActivity(i);
return;
}
String authToken = authTokenBundle.getString(AccountManager.KEY_AUTHTOKEN);
authToken = GtasksTokenValidator.validateAuthToken(authToken);
gtasksPreferenceService.setToken(authToken);
gtasksService = new GtasksService(authToken);
initialized = true;
}
private void setupTestList() throws Exception {
Tasks defaultListTasks = gtasksService.getAllGtasksFromListId(DEFAULT_LIST, false, false);
if (defaultListTasks.items != null) {
for (com.google.api.services.tasks.v1.model.Task t : defaultListTasks.items) {
gtasksService.deleteGtask(DEFAULT_LIST, t.id);
}
}
}
}

@ -0,0 +1,49 @@
package com.todoroo.astrid.repeats;
import java.io.IOException;
import java.util.Date;
import com.google.ical.values.Frequency;
import com.google.ical.values.RRule;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.gtasks.api.GtasksApiUtilities;
public class RepeatTestsGtasksSyncRemote extends RepeatTestsGtasksSync {
// Test logic in superclass
@Override
protected long setCompletionDate(boolean completeBefore, Task t,
com.google.api.services.tasks.v1.model.Task remoteModel, long dueDate) {
long completionDate;
if (completeBefore)
completionDate = dueDate - DateUtilities.ONE_DAY;
else
completionDate = dueDate + DateUtilities.ONE_DAY;
remoteModel.completed = GtasksApiUtilities.unixTimeToGtasksDate(completionDate);
remoteModel.status = "completed";
try {
gtasksService.updateGtask(GtasksApiUtilities.extractListIdFromSelfLink(remoteModel), remoteModel);
} catch (IOException e) {
e.printStackTrace();
fail("Exception in gtasks service");
}
return completionDate;
}
@Override
protected long computeNextDueDateFromDate(long fromDate, RRule rrule, boolean fromCompletion) {
long expectedDate = super.computeNextDueDateFromDate(fromDate, rrule, fromCompletion);
Frequency freq = rrule.getFreq();
if (fromCompletion && (freq == Frequency.HOURLY || freq == Frequency.MINUTELY)) {
long millis = (freq == Frequency.HOURLY ? DateUtilities.ONE_HOUR : DateUtilities.ONE_MINUTE);
Date rounded = new Date(expectedDate);
rounded.setHours(0);
rounded.setMinutes(0);
rounded.setSeconds(0);
return rounded.getTime() + rrule.getInterval() * millis;
} else {
return expectedDate;
}
}
}

@ -0,0 +1,128 @@
package com.todoroo.astrid.repeats;
import org.json.JSONArray;
import org.json.JSONObject;
import com.timsu.astrid.R;
import com.todoroo.andlib.service.Autowired;
import com.todoroo.andlib.utility.AndroidUtilities;
import com.todoroo.andlib.utility.Preferences;
import com.todoroo.astrid.data.Task;
import com.todoroo.astrid.producteev.ProducteevUtilities;
import com.todoroo.astrid.producteev.api.ApiUtilities;
import com.todoroo.astrid.producteev.api.ProducteevInvoker;
import com.todoroo.astrid.producteev.sync.ProducteevDataService;
import com.todoroo.astrid.producteev.sync.ProducteevSyncProvider;
import com.todoroo.astrid.producteev.sync.ProducteevTask;
import com.todoroo.astrid.service.MetadataService;
import com.todoroo.astrid.service.TaskService;
import com.todoroo.astrid.tags.TagService;
public class RepeatTestsProducteevSync extends NewRepeatTests<JSONObject> {
private static boolean initialized = false;
protected static ProducteevInvoker invoker;
@Autowired TaskService taskService;
@Autowired MetadataService metadataService;
@Autowired TagService tagService;
protected ProducteevDataService producteevDataService;
private static final String TEST_USER = "sync_tester2@astrid.com";
private static final String TEST_PASSWORD = "wonkwonkjj";
@Override
protected void setUp() throws Exception {
super.setUp();
Preferences.setString(ProducteevUtilities.PREF_SERVER_LAST_SYNC, null);
if (!initialized) {
initializeTestService();
}
producteevDataService = ProducteevDataService.getInstance();
producteevDataService.updateDashboards(new JSONArray());
clearAllRemoteTasks();
}
private void initializeTestService() throws Exception {
//Set the username and password for the service
Preferences.setString(R.string.producteev_PPr_email, TEST_USER);
Preferences.setString(R.string.producteev_PPr_password, TEST_PASSWORD);
invoker = ProducteevSyncProvider.getInvoker();
invoker.authenticate(TEST_USER, TEST_PASSWORD);
initialized = true;
}
/*
* Deletes all the remote tasks on the default dashboard to ensure
* clean tests.
*/
private void clearAllRemoteTasks() {
try {
JSONArray remoteTasks = invoker.tasksShowList(null, null);
for (int i = 0; i < remoteTasks.length(); i++) {
JSONObject task = remoteTasks.getJSONObject(i).getJSONObject("task");
System.err.println(invoker.tasksDelete(getRemoteId(task)));
}
} catch (Exception e) {
fail("Failed to clear remote tasks before tests");
}
}
protected long getRemoteId(JSONObject remoteTask) {
long remoteId = 0;
try {
remoteId = remoteTask.getLong("id_task");
} catch (Exception e) {
fail("Remote task object did not contain id_task field");
}
return remoteId;
}
@Override
protected void waitAndSync() {
AndroidUtilities.sleepDeep(3000L);
new ProducteevSyncProvider().synchronize(null);
AndroidUtilities.sleepDeep(3000L);
}
/**
* @param t
* @param expectedDueDate
*/
@Override
protected JSONObject assertTaskExistsRemotely(Task t, long expectedDueDate) {
long remoteId = producteevDataService.getTaskMetadata(t.getId()).getValue(ProducteevTask.ID);
JSONObject remoteTask = null;
try {
remoteTask = invoker.tasksView(remoteId).getJSONObject("task");
assertNotNull(remoteTask);
long remoteDueDate = ApiUtilities.producteevToUnixTime(remoteTask.getString("deadline"), 0);
assertTimesMatch(expectedDueDate, remoteDueDate);
} catch (Exception e) {
e.printStackTrace();
fail("Error in producteev invoker");
}
return remoteTask;
}
@Override
protected void assertTaskCompletedRemotely(Task t) {
long remoteId = producteevDataService.getTaskMetadata(t.getId()).getValue(ProducteevTask.ID);
JSONObject remoteTask = null;
try {
remoteTask = invoker.tasksView(remoteId).getJSONObject("task");
assertNotNull(remoteTask);
System.err.println(remoteTask);
assertEquals(2, remoteTask.getInt("status"));
} catch (Exception e) {
e.printStackTrace();
fail("Error in producteev invoker");
}
}
}

@ -0,0 +1,44 @@
package com.todoroo.astrid.repeats;
import java.util.Date;
import org.json.JSONObject;
import com.google.ical.values.RRule;
import com.todoroo.andlib.utility.DateUtilities;
import com.todoroo.astrid.data.Task;
public class RepeatTestsProducteevSyncRemote extends RepeatTestsProducteevSync {
@Override
protected long setCompletionDate(boolean completeBefore, Task t,
JSONObject remoteModel, long dueDate) {
long completionDate;
if (completeBefore)
completionDate = dueDate - DateUtilities.ONE_DAY;
else
completionDate = dueDate + DateUtilities.ONE_DAY;
try {
invoker.tasksSetStatus(getRemoteId(remoteModel), 2);
} catch (Exception e) {
e.printStackTrace();
fail("Error in producteev invoker");
}
return completionDate;
}
@Override
protected long computeNextDueDateFromDate(long fromDate, RRule rrule, boolean fromCompletion) {
if (fromCompletion) {
fromDate = DateUtilities.now() - 5000L;
}
return super.computeNextDueDateFromDate(fromDate, rrule, fromCompletion);
}
@Override
protected void assertTimesMatch(long expectedTime, long newDueDate) {
assertTrue(String.format("Expected %s, was %s", new Date(expectedTime), new Date(newDueDate)),
Math.abs(expectedTime - newDueDate) < 60000); // More lenient with producteev since we use now() in setting completion during sync
}
}
Loading…
Cancel
Save