More reminder service tests

pull/127/merge
Alex Baker 9 years ago
parent 4aa3326245
commit d164fdb3fc

@ -6,9 +6,9 @@ import com.todoroo.astrid.data.Task;
import org.junit.After; import org.junit.After;
import org.junit.Before; import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test; import org.junit.Test;
import org.junit.runner.RunWith; import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InOrder; import org.mockito.InOrder;
import org.tasks.Snippet; import org.tasks.Snippet;
import org.tasks.injection.InjectingTestCase; import org.tasks.injection.InjectingTestCase;
@ -16,29 +16,30 @@ import org.tasks.injection.TestComponent;
import org.tasks.jobs.JobQueue; import org.tasks.jobs.JobQueue;
import org.tasks.jobs.Reminder; import org.tasks.jobs.Reminder;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import org.tasks.reminders.Random;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.util.concurrent.TimeUnit;
import javax.inject.Inject; import javax.inject.Inject;
import static com.natpryce.makeiteasy.MakeItEasy.with; import static com.natpryce.makeiteasy.MakeItEasy.with;
import static com.todoroo.andlib.utility.DateUtilities.ONE_HOUR;
import static com.todoroo.andlib.utility.DateUtilities.ONE_WEEK;
import static com.todoroo.astrid.data.Task.NOTIFY_AFTER_DEADLINE; import static com.todoroo.astrid.data.Task.NOTIFY_AFTER_DEADLINE;
import static com.todoroo.astrid.data.Task.NOTIFY_AT_DEADLINE; import static com.todoroo.astrid.data.Task.NOTIFY_AT_DEADLINE;
import static com.todoroo.astrid.reminders.ReminderService.TYPE_RANDOM;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.inOrder;
import static org.mockito.Mockito.mock; import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions;
import static org.mockito.Mockito.when;
import static org.tasks.Freeze.freezeClock; import static org.tasks.Freeze.freezeClock;
import static org.tasks.date.DateTimeUtils.newDateTime; import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.makers.TaskMaker.COMPLETION_TIME; import static org.tasks.makers.TaskMaker.COMPLETION_TIME;
import static org.tasks.makers.TaskMaker.CREATION_TIME;
import static org.tasks.makers.TaskMaker.DELETION_TIME; import static org.tasks.makers.TaskMaker.DELETION_TIME;
import static org.tasks.makers.TaskMaker.DUE_DATE; import static org.tasks.makers.TaskMaker.DUE_DATE;
import static org.tasks.makers.TaskMaker.DUE_TIME; import static org.tasks.makers.TaskMaker.DUE_TIME;
import static org.tasks.makers.TaskMaker.ID; import static org.tasks.makers.TaskMaker.ID;
import static org.tasks.makers.TaskMaker.PRIORITY;
import static org.tasks.makers.TaskMaker.RANDOM_REMINDER_PERIOD; import static org.tasks.makers.TaskMaker.RANDOM_REMINDER_PERIOD;
import static org.tasks.makers.TaskMaker.REMINDERS; import static org.tasks.makers.TaskMaker.REMINDERS;
import static org.tasks.makers.TaskMaker.REMINDER_LAST; import static org.tasks.makers.TaskMaker.REMINDER_LAST;
@ -52,12 +53,15 @@ public class ReminderServiceTest extends InjectingTestCase {
@Inject Preferences preferences; @Inject Preferences preferences;
private ReminderService service; private ReminderService service;
private Random random;
private JobQueue<Reminder> jobs; private JobQueue<Reminder> jobs;
@Before @Before
public void before() { public void before() {
jobs = mock(JobQueue.class); jobs = mock(JobQueue.class);
service = new ReminderService(preferences, jobs); random = mock(Random.class);
when(random.nextFloat()).thenReturn(1.0f);
service = new ReminderService(preferences, jobs, random);
} }
@After @After
@ -164,23 +168,6 @@ public class ReminderServiceTest extends InjectingTestCase {
verify(jobs).cancel(1); verify(jobs).cancel(1);
} }
@Test
public void snoozeOverridesAll() {
DateTime now = newDateTime();
Task task = newTask(
with(ID, 1L),
with(DUE_TIME, now),
with(SNOOZE_TIME, now.plusMonths(12)),
with(REMINDERS, NOTIFY_AT_DEADLINE | NOTIFY_AFTER_DEADLINE),
with(RANDOM_REMINDER_PERIOD, TimeUnit.HOURS.toMillis(1)));
service.scheduleAlarm(null, task);
InOrder order = inOrder(jobs);
order.verify(jobs).cancel(1);
order.verify(jobs).add(new Reminder(1, now.plusMonths(12).getMillis(), ReminderService.TYPE_SNOOZE));
}
@Test @Test
public void ignoreLapsedSnoozeTime() { public void ignoreLapsedSnoozeTime() {
Task task = newTask( Task task = newTask(
@ -197,119 +184,170 @@ public class ReminderServiceTest extends InjectingTestCase {
} }
@Test @Test
public void scheduleRandomReminder() { public void scheduleInitialRandomReminder() {
freezeClock().thawAfter(new Snippet() {{
DateTime now = newDateTime();
when(random.nextFloat()).thenReturn(0.3865f);
Task task = newTask(
with(ID, 1L),
with(REMINDER_LAST, (DateTime) null),
with(CREATION_TIME, now.minusDays(1)),
with(RANDOM_REMINDER_PERIOD, ONE_WEEK));
service.scheduleAlarm(null, task);
InOrder order = inOrder(jobs);
order.verify(jobs).cancel(1);
order.verify(jobs).add(new Reminder(1L, now.minusDays(1).getMillis() + 584206592, ReminderService.TYPE_RANDOM));
}});
}
@Test
public void scheduleNextRandomReminder() {
freezeClock().thawAfter(new Snippet() {{
DateTime now = newDateTime();
when(random.nextFloat()).thenReturn(0.3865f);
Task task = newTask(
with(ID, 1L),
with(REMINDER_LAST, now.minusDays(1)),
with(CREATION_TIME, now.minusDays(30)),
with(RANDOM_REMINDER_PERIOD, ONE_WEEK));
service.scheduleAlarm(null, task);
InOrder order = inOrder(jobs);
order.verify(jobs).cancel(1);
order.verify(jobs).add(new Reminder(1L, now.minusDays(1).getMillis() + 584206592, ReminderService.TYPE_RANDOM));
}});
}
@Test
public void scheduleOverdueRandomReminder() {
freezeClock().thawAfter(new Snippet() {{
DateTime now = newDateTime();
when(random.nextFloat()).thenReturn(0.3865f);
Task task = newTask(
with(ID, 1L),
with(REMINDER_LAST, now.minusDays(14)),
with(CREATION_TIME, now.minusDays(30)),
with(RANDOM_REMINDER_PERIOD, ONE_WEEK));
service.scheduleAlarm(null, task);
InOrder order = inOrder(jobs);
order.verify(jobs).cancel(1);
order.verify(jobs).add(new Reminder(1L, now.getMillis() + 10148400, ReminderService.TYPE_RANDOM));
}});
}
@Test
public void scheduleOverdueForFutureDueDate() {
freezeClock().thawAfter(new Snippet() {{
when(random.nextFloat()).thenReturn(0.3865f);
Task task = newTask(
with(ID, 1L),
with(DUE_TIME, newDateTime().plusMinutes(5)),
with(REMINDERS, NOTIFY_AFTER_DEADLINE));
service.scheduleAlarm(null, task);
InOrder order = inOrder(jobs);
order.verify(jobs).cancel(1);
order.verify(jobs).add(new Reminder(1L, task.getDueDate() + 4582800, ReminderService.TYPE_OVERDUE));
}});
}
@Test
public void scheduleOverdueForPastDueDateWithNoReminderPastDueDate() {
freezeClock().thawAfter(new Snippet() {{
DateTime now = newDateTime();
Task task = newTask(
with(ID, 1L),
with(DUE_TIME, now.minusMinutes(5)),
with(REMINDERS, NOTIFY_AFTER_DEADLINE));
service.scheduleAlarm(null, task);
InOrder order = inOrder(jobs);
order.verify(jobs).cancel(1);
order.verify(jobs).add(new Reminder(1L, currentTimeMillis(), ReminderService.TYPE_OVERDUE));
}});
}
@Test
public void scheduleOverdueForPastDueDateLastReminderSixHoursAgo() {
freezeClock().thawAfter(new Snippet() {{ freezeClock().thawAfter(new Snippet() {{
Task task = newTask( Task task = newTask(
with(ID, 1L), with(ID, 1L),
with(RANDOM_REMINDER_PERIOD, TimeUnit.DAYS.toMillis(7))); with(DUE_TIME, newDateTime().minusHours(12)),
with(REMINDER_LAST, newDateTime().minusHours(6)),
with(REMINDERS, NOTIFY_AFTER_DEADLINE));
service.scheduleAlarm(null, task); service.scheduleAlarm(null, task);
ArgumentCaptor<Reminder> captor = ArgumentCaptor.forClass(Reminder.class);
InOrder order = inOrder(jobs); InOrder order = inOrder(jobs);
order.verify(jobs).cancel(1); order.verify(jobs).cancel(1);
order.verify(jobs).add(captor.capture()); order.verify(jobs).add(new Reminder(1L, currentTimeMillis(), ReminderService.TYPE_OVERDUE));
}});
}
Reminder reminder = captor.getValue(); @Test
assertTrue(reminder.getTime() > currentTimeMillis()); public void scheduleOverdueForPastDueDateLastReminderWithinSixHours() {
assertTrue(reminder.getTime() < currentTimeMillis() + 1.2 * TimeUnit.DAYS.toMillis(7)); freezeClock().thawAfter(new Snippet() {{
assertEquals(TYPE_RANDOM, reminder.getType()); when(random.nextFloat()).thenReturn(0.3865f);
Task task = newTask(
with(ID, 1L),
with(DUE_TIME, newDateTime().minusHours(12)),
with(PRIORITY, 2),
with(REMINDER_LAST, newDateTime().minusHours(3)),
with(REMINDERS, NOTIFY_AFTER_DEADLINE));
service.scheduleAlarm(null, task);
InOrder order = inOrder(jobs);
order.verify(jobs).cancel(1);
order.verify(jobs).add(new Reminder(1L, currentTimeMillis() + 22748400, ReminderService.TYPE_OVERDUE));
}}); }});
} }
// @Test @Test
// public void testOverdue() { public void snoozeOverridesAll() {
// // test due date in the future DateTime now = newDateTime();
// reminderService.setScheduler(new AlarmExpected() { Task task = newTask(
// @Override with(ID, 1L),
// public void createAlarm(Task task, long time, int type) { with(DUE_TIME, now),
// if (time == ReminderService.NO_ALARM) with(SNOOZE_TIME, now.plusMonths(12)),
// return; with(REMINDERS, NOTIFY_AT_DEADLINE | NOTIFY_AFTER_DEADLINE),
// super.createAlarm(task, time, type); with(RANDOM_REMINDER_PERIOD, ONE_HOUR));
// assertTrue(time > task.getDueDate());
// assertTrue(time < task.getDueDate() + DateUtilities.ONE_DAY); service.scheduleAlarm(null, task);
// assertEquals(type, ReminderService.TYPE_OVERDUE);
// } InOrder order = inOrder(jobs);
// }); order.verify(jobs).cancel(1);
// final Task task = new Task(); order.verify(jobs).add(new Reminder(1, now.plusMonths(12).getMillis(), ReminderService.TYPE_SNOOZE));
// task.setTitle("water"); }
// task.setDueDate(DateUtilities.now() + DateUtilities.ONE_DAY);
// task.setReminderFlags(Task.NOTIFY_AFTER_DEADLINE); @Test
// taskDao.save(task); @Ignore
// public void randomReminderBeforeDueAndOverdue() {
// // test due date in the past
// task.setDueDate(DateUtilities.now() - DateUtilities.ONE_DAY); }
// reminderService.setScheduler(new AlarmExpected() {
// @Override @Test
// public void createAlarm(Task task, long time, int type) { @Ignore
// if (time == ReminderService.NO_ALARM) public void randomReminderAfterDue() {
// return;
// super.createAlarm(task, time, type); }
// assertTrue(time > DateUtilities.now() - 1000L);
// assertTrue(time < DateUtilities.now() + 2 * DateUtilities.ONE_DAY); @Test
// assertEquals(type, ReminderService.TYPE_OVERDUE); @Ignore
// } public void randomReminderAfterOverdue() {
// });
// taskDao.save(task); }
// assertTrue(((AlarmExpected) reminderService.getScheduler()).alarmCreated);
// @Test
// // test due date in the past, but recently notified @Ignore
// task.setReminderLast(DateUtilities.now()); public void dueDateBeforeOverdue() {
// reminderService.setScheduler(new AlarmExpected() {
// @Override }
// public void createAlarm(Task task, long time, int type) {
// if (time == ReminderService.NO_ALARM)
// return;
// super.createAlarm(task, time, type);
// assertTrue(time > DateUtilities.now() + DateUtilities.ONE_HOUR);
// assertTrue(time < DateUtilities.now() + DateUtilities.ONE_DAY);
// assertEquals(type, ReminderService.TYPE_OVERDUE);
// }
// });
// taskDao.save(task);
// assertTrue(((AlarmExpected) reminderService.getScheduler()).alarmCreated);
// }
//
// @Test
// public void testMultipleReminders() {
// // test due date in the future, enable random
// final Task task = new Task();
// task.setTitle("water");
// task.setDueDate(DateUtilities.now() + DateUtilities.ONE_WEEK);
// task.setReminderFlags(Task.NOTIFY_AT_DEADLINE);
// task.setReminderPeriod(DateUtilities.ONE_HOUR);
// reminderService.setScheduler(new AlarmExpected() {
// @Override
// public void createAlarm(Task task, long time, int type) {
// if (time == ReminderService.NO_ALARM)
// return;
// super.createAlarm(task, time, type);
// assertTrue(time > DateUtilities.now());
// assertTrue(time < DateUtilities.now() + DateUtilities.ONE_DAY);
// assertEquals(type, ReminderService.TYPE_RANDOM);
// }
// });
// taskDao.save(task);
// assertTrue(((AlarmExpected) reminderService.getScheduler()).alarmCreated);
//
// // now set the due date in the past
// task.setDueDate(DateUtilities.now() - DateUtilities.ONE_WEEK);
// ((AlarmExpected) reminderService.getScheduler()).alarmCreated = false;
// reminderService.scheduleAlarm(taskDao, task);
// assertTrue(((AlarmExpected) reminderService.getScheduler()).alarmCreated);
//
// // now set the due date before the random
// task.setDueDate(DateUtilities.now() + DateUtilities.ONE_HOUR);
// reminderService.setScheduler(new AlarmExpected() {
// @Override
// public void createAlarm(Task task, long time, int type) {
// if (time == ReminderService.NO_ALARM)
// return;
// super.createAlarm(task, time, type);
// assertEquals((long) task.getDueDate(), time);
// assertEquals(type, ReminderService.TYPE_DUE);
// }
// });
// taskDao.save(task);
// assertTrue(((AlarmExpected) reminderService.getScheduler()).alarmCreated);
// }
} }

@ -9,8 +9,8 @@ import com.todoroo.astrid.data.Task;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import static com.natpryce.makeiteasy.Property.newProperty; import static com.natpryce.makeiteasy.Property.newProperty;
import static org.tasks.date.DateTimeUtils.newDateTime;
import static org.tasks.makers.Maker.make; import static org.tasks.makers.Maker.make;
import static org.tasks.time.DateTimeUtils.currentTimeMillis;
public class TaskMaker { public class TaskMaker {
@ -18,10 +18,12 @@ public class TaskMaker {
public static Property<Task, String> TITLE = newProperty(); public static Property<Task, String> TITLE = newProperty();
public static Property<Task, DateTime> DUE_DATE = newProperty(); public static Property<Task, DateTime> DUE_DATE = newProperty();
public static Property<Task, DateTime> DUE_TIME = newProperty(); public static Property<Task, DateTime> DUE_TIME = newProperty();
public static Property<Task, Integer> PRIORITY = newProperty();
public static Property<Task, DateTime> REMINDER_LAST = newProperty(); public static Property<Task, DateTime> REMINDER_LAST = newProperty();
public static Property<Task, Long> RANDOM_REMINDER_PERIOD = newProperty(); public static Property<Task, Long> RANDOM_REMINDER_PERIOD = newProperty();
public static Property<Task, Integer> HIDE_TYPE = newProperty(); public static Property<Task, Integer> HIDE_TYPE = newProperty();
public static Property<Task, Integer> REMINDERS = newProperty(); public static Property<Task, Integer> REMINDERS = newProperty();
public static Property<Task, DateTime> CREATION_TIME = newProperty();
public static Property<Task, DateTime> COMPLETION_TIME = newProperty(); public static Property<Task, DateTime> COMPLETION_TIME = newProperty();
public static Property<Task, DateTime> DELETION_TIME = newProperty(); public static Property<Task, DateTime> DELETION_TIME = newProperty();
public static Property<Task, DateTime> SNOOZE_TIME = newProperty(); public static Property<Task, DateTime> SNOOZE_TIME = newProperty();
@ -44,6 +46,11 @@ public class TaskMaker {
task.setId(id); task.setId(id);
} }
int priority = lookup.valueOf(PRIORITY, -1);
if (priority >= 0) {
task.setImportance(priority);
}
DateTime dueDate = lookup.valueOf(DUE_DATE, (DateTime) null); DateTime dueDate = lookup.valueOf(DUE_DATE, (DateTime) null);
if (dueDate != null) { if (dueDate != null) {
task.setDueDate(Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate.getMillis())); task.setDueDate(Task.createDueDate(Task.URGENCY_SPECIFIC_DAY, dueDate.getMillis()));
@ -89,7 +96,8 @@ public class TaskMaker {
task.setReminderPeriod(randomReminderPeriod); task.setReminderPeriod(randomReminderPeriod);
} }
task.setCreationDate(currentTimeMillis()); DateTime creationTime = lookup.valueOf(CREATION_TIME, newDateTime());
task.setCreationDate(creationTime.getMillis());
return task; return task;
}; };

@ -19,10 +19,10 @@ import org.tasks.jobs.JobManager;
import org.tasks.jobs.JobQueue; import org.tasks.jobs.JobQueue;
import org.tasks.jobs.Reminder; import org.tasks.jobs.Reminder;
import org.tasks.preferences.Preferences; import org.tasks.preferences.Preferences;
import org.tasks.reminders.Random;
import org.tasks.time.DateTime; import org.tasks.time.DateTime;
import java.util.List; import java.util.List;
import java.util.Random;
import javax.inject.Inject; import javax.inject.Inject;
@ -57,22 +57,23 @@ public final class ReminderService {
/** flag for an alarm reminder */ /** flag for an alarm reminder */
public static final int TYPE_ALARM = 4; public static final int TYPE_ALARM = 4;
private static final Random random = new Random();
private static final long NO_ALARM = Long.MAX_VALUE; private static final long NO_ALARM = Long.MAX_VALUE;
private final JobQueue<Reminder> jobs; private final JobQueue<Reminder> jobs;
private final Random random;
private final Preferences preferences; private final Preferences preferences;
private long now = -1; // For tracking when reminders might be scheduled all at once private long now = -1; // For tracking when reminders might be scheduled all at once
@Inject @Inject
ReminderService(Preferences preferences, JobManager jobManager) { ReminderService(Preferences preferences, JobManager jobManager) {
this(preferences, JobQueue.newReminderQueue(preferences, jobManager)); this(preferences, JobQueue.newReminderQueue(preferences, jobManager), new Random());
} }
ReminderService(Preferences preferences, JobQueue<Reminder> jobs) { ReminderService(Preferences preferences, JobQueue<Reminder> jobs, Random random) {
this.preferences = preferences; this.preferences = preferences;
this.jobs = jobs; this.jobs = jobs;
this.random = random;
} }
private static final int MILLIS_PER_HOUR = 60 * 60 * 1000; private static final int MILLIS_PER_HOUR = 60 * 60 * 1000;
@ -139,7 +140,6 @@ public final class ReminderService {
// notifications at due date // notifications at due date
long whenDueDate = calculateNextDueDateReminder(task); long whenDueDate = calculateNextDueDateReminder(task);
// notifications after due date // notifications after due date
long whenOverdue = calculateNextOverdueReminder(task); long whenOverdue = calculateNextOverdueReminder(task);

@ -0,0 +1,10 @@
package org.tasks.reminders;
public class Random {
private static final java.util.Random random = new java.util.Random();
public float nextFloat() {
return random.nextFloat();
}
}

@ -189,6 +189,10 @@ public class DateTime {
return subtract(Calendar.DATE, days); return subtract(Calendar.DATE, days);
} }
public DateTime minusHours(int hours) {
return subtract(Calendar.HOUR, hours);
}
public DateTime minusMinutes(int minutes) { public DateTime minusMinutes(int minutes) {
return subtract(Calendar.MINUTE, minutes); return subtract(Calendar.MINUTE, minutes);
} }

Loading…
Cancel
Save