Write tests for IntentScheduler

pull/655/head
Alinson S. Xavier 5 years ago
parent ddea9e78a9
commit 720f98f9bd

@ -23,14 +23,12 @@ import android.appwidget.*;
import android.content.*;
import android.content.res.*;
import android.os.*;
import androidx.annotation.NonNull;
import androidx.annotation.StyleRes;
import androidx.test.*;
import androidx.test.filters.*;
import android.util.*;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.annotation.*;
import androidx.test.filters.*;
import androidx.test.platform.app.*;
import androidx.test.uiautomator.*;
import junit.framework.*;
@ -44,9 +42,12 @@ import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import java.io.*;
import java.time.*;
import java.util.*;
import java.util.concurrent.*;
import static androidx.test.platform.app.InstrumentationRegistry.*;
import static androidx.test.uiautomator.UiDevice.*;
import static org.hamcrest.CoreMatchers.*;
import static org.hamcrest.MatcherAssert.*;
@ -78,11 +79,14 @@ public class BaseAndroidTest extends TestCase
private boolean isDone = false;
private UiDevice device;
@Override
@Before
public void setUp()
{
if (Looper.myLooper() == null) Looper.prepare();
device = getInstance(getInstrumentation());
targetContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
testContext = InstrumentationRegistry.getInstrumentation().getContext();
@ -215,4 +219,52 @@ public class BaseAndroidTest extends TestCase
{
return DateUtils.getToday().minus(offset);
}
public void setSystemTime(String tz,
int year,
int javaMonth,
int day,
int hourOfDay,
int minute) throws Exception
{
GregorianCalendar cal = new GregorianCalendar();
cal.setTimeZone(TimeZone.getTimeZone(tz));
cal.set(Calendar.SECOND, 0);
cal.set(year, javaMonth, day, hourOfDay, minute);
setSystemTime(cal);
}
private void setSystemTime(GregorianCalendar cal) throws Exception
{
ZoneId tz = cal.getTimeZone().toZoneId();
// Set time zone (temporary)
String command = String.format("service call alarm 3 s16 %s", tz);
device.executeShellCommand(command);
// Set time zone (permanent)
command = String.format("setprop persist.sys.timezone %s", tz);
device.executeShellCommand(command);
// Set time
command = String.format("date -u @%d", cal.getTimeInMillis() / 1000);
device.executeShellCommand(command);
// Wait for system events to settle
Thread.sleep(1000);
}
private GregorianCalendar savedCalendar = null;
public void saveSystemTime()
{
savedCalendar = new GregorianCalendar();
}
public void restoreSystemTime() throws Exception
{
if (savedCalendar == null) throw new NullPointerException();
setSystemTime(savedCalendar);
}
}

@ -31,6 +31,9 @@ import org.isoron.uhabits.core.ui.screens.habits.list.*;
import org.isoron.uhabits.core.utils.*;
import org.junit.*;
import java.time.*;
import java.util.*;
import static androidx.test.core.app.ApplicationProvider.*;
import static androidx.test.platform.app.InstrumentationRegistry.*;
import static androidx.test.uiautomator.UiDevice.*;
@ -128,4 +131,5 @@ public class BaseUserInterfaceTest
device.setOrientationLeft();
device.setOrientationNatural();
}
}

@ -22,7 +22,6 @@ package org.isoron.uhabits
import dagger.*
import org.isoron.androidbase.activities.*
import org.isoron.uhabits.activities.*
import org.isoron.uhabits.activities.about.*
import org.isoron.uhabits.activities.habits.list.*
import org.isoron.uhabits.activities.habits.list.views.*
import org.isoron.uhabits.activities.habits.show.*

@ -22,6 +22,7 @@ package org.isoron.uhabits;
import org.isoron.androidbase.*;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.tasks.*;
import org.isoron.uhabits.intents.*;
import dagger.*;
@ -34,7 +35,7 @@ import dagger.*;
public interface HabitsApplicationTestComponent
extends HabitsApplicationComponent
{
IntentScheduler getIntentScheduler();
}
@Module

@ -0,0 +1,120 @@
/*
* Copyright (C) 2016-2020 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.intents
import android.content.ContentUris.*
import androidx.test.ext.junit.runners.*
import androidx.test.filters.*
import org.hamcrest.Matchers.*
import org.isoron.uhabits.*
import org.isoron.uhabits.core.reminders.ReminderScheduler.SchedulerResult.*
import org.isoron.uhabits.receivers.*
import org.junit.*
import org.junit.Assert.*
import org.junit.runner.*
import java.util.*
import java.util.Calendar.*
class IntentSchedulerTest : BaseAndroidTest() {
@Before
override fun setUp() {
super.setUp()
saveSystemTime()
}
@After
override fun tearDown() {
restoreSystemTime()
super.tearDown()
}
@Test
@MediumTest
@Throws(Exception::class)
fun testSetSystemTime() {
setSystemTime("America/Chicago", 2020, JUNE, 1, 12, 40)
var cal = GregorianCalendar()
assertThat(cal.timeZone, equalTo(TimeZone.getTimeZone("America/Chicago")))
assertThat(cal[YEAR], equalTo(2020))
assertThat(cal[MONTH], equalTo(JUNE))
assertThat(cal[DAY_OF_MONTH], equalTo(1))
assertThat(cal[HOUR_OF_DAY], equalTo(12))
assertThat(cal[MINUTE], equalTo(40))
setSystemTime("Europe/Paris", 2019, MAY, 15, 6, 30)
cal = GregorianCalendar()
assertThat(cal.timeZone, equalTo(TimeZone.getTimeZone("Europe/Paris")))
assertThat(cal[YEAR], equalTo(2019))
assertThat(cal[MONTH], equalTo(MAY))
assertThat(cal[DAY_OF_MONTH], equalTo(15))
assertThat(cal[HOUR_OF_DAY], equalTo(6))
assertThat(cal[MINUTE], equalTo(30))
setSystemTime("Asia/Tokyo", 2021, DECEMBER, 20, 18, 0)
cal = GregorianCalendar()
assertThat(cal.timeZone, equalTo(TimeZone.getTimeZone("Asia/Tokyo")))
assertThat(cal[YEAR], equalTo(2021))
assertThat(cal[MONTH], equalTo(DECEMBER))
assertThat(cal[DAY_OF_MONTH], equalTo(20))
assertThat(cal[HOUR_OF_DAY], equalTo(18))
assertThat(cal[MINUTE], equalTo(0))
}
@Test
@MediumTest
fun testScheduleShowReminder() {
for (h in habitList) h.setReminder(null)
ReminderReceiver.clearLastReceivedIntent()
setSystemTime("America/Chicago", 2020, JUNE, 1, 12, 30)
val reminderTime = 1591155900000 // 2020-06-02 22:45:00 (America/Chicago)
val habit = habitList.getByPosition(0)
val scheduler = appComponent.intentScheduler
assertThat(scheduler.scheduleShowReminder(reminderTime, habit, 0), equalTo(OK))
setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 44)
assertNull(ReminderReceiver.getLastReceivedIntent())
setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 46)
val intent = ReminderReceiver.getLastReceivedIntent()
assertNotNull(intent)
assertThat(parseId(intent.data!!), equalTo(habit.id))
}
@Test
@MediumTest
fun testScheduleWidgetUpdate() {
WidgetReceiver.clearLastReceivedIntent()
setSystemTime("America/Chicago", 2020, JUNE, 1, 12, 30)
val updateTime = 1591155900000 // 2020-06-02 22:45:00 (America/Chicago)
val scheduler = appComponent.intentScheduler
assertThat(scheduler.scheduleWidgetUpdate(updateTime), equalTo(OK))
setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 44)
assertNull(WidgetReceiver.getLastReceivedIntent())
setSystemTime("America/Chicago", 2020, JUNE, 2, 22, 46)
val intent = WidgetReceiver.getLastReceivedIntent()
assertNotNull(intent)
}
}

@ -27,10 +27,9 @@ import android.os.Build.VERSION.*
import android.os.Build.VERSION_CODES.*
import android.util.*
import org.isoron.androidbase.*
import org.isoron.uhabits.*
import org.isoron.uhabits.core.*
import org.isoron.uhabits.core.models.*
import org.isoron.uhabits.core.reminders.*
import org.isoron.uhabits.core.reminders.ReminderScheduler.*
import org.isoron.uhabits.core.utils.*
import java.util.*
import javax.inject.*
@ -40,36 +39,37 @@ class IntentScheduler
@Inject constructor(
@AppContext context: Context,
private val pendingIntents: PendingIntentFactory
) : ReminderScheduler.SystemScheduler {
) : SystemScheduler {
private val manager =
context.getSystemService(ALARM_SERVICE) as AlarmManager
fun schedule(timestamp: Long, intent: PendingIntent, alarmType: Int) {
Log.d("IntentScheduler",
"timestamp=" + timestamp + " current=" + System.currentTimeMillis())
if (timestamp < System.currentTimeMillis()) {
private fun schedule(timestamp: Long, intent: PendingIntent, alarmType: Int): SchedulerResult {
val now = System.currentTimeMillis()
Log.d("IntentScheduler", "timestamp=$timestamp now=$now")
if (timestamp < now) {
Log.e("IntentScheduler",
"Ignoring attempt to schedule intent in the past.")
return;
return SchedulerResult.IGNORED
}
if (SDK_INT >= M)
manager.setExactAndAllowWhileIdle(alarmType, timestamp, intent)
else
manager.setExact(alarmType, timestamp, intent)
return SchedulerResult.OK
}
override fun scheduleShowReminder(reminderTime: Long,
habit: Habit,
timestamp: Long) {
timestamp: Long): SchedulerResult {
val intent = pendingIntents.showReminder(habit, reminderTime, timestamp)
schedule(reminderTime, intent, RTC_WAKEUP)
logReminderScheduled(habit, reminderTime)
return schedule(reminderTime, intent, RTC_WAKEUP)
}
override fun scheduleWidgetUpdate(updateTime: Long) {
override fun scheduleWidgetUpdate(updateTime: Long): SchedulerResult {
val intent = pendingIntents.updateWidgets()
schedule(updateTime, intent, RTC)
return schedule(updateTime, intent, RTC)
}
override fun log(componentName: String, msg: String) {

@ -48,11 +48,14 @@ public class ReminderReceiver extends BroadcastReceiver
private static final String TAG = "ReminderReceiver";
private static Intent lastReceivedIntent = null;
@Override
public void onReceive(@Nullable final Context context, @Nullable Intent intent)
{
if (context == null || intent == null) return;
if (intent.getAction() == null) return;
lastReceivedIntent = intent;
HabitsApplication app = (HabitsApplication) context.getApplicationContext();
HabitsApplicationComponent appComponent = app.getComponent();
@ -107,4 +110,14 @@ public class ReminderReceiver extends BroadcastReceiver
Log.e(TAG, "could not process intent", e);
}
}
public static void clearLastReceivedIntent()
{
lastReceivedIntent = null;
}
public static Intent getLastReceivedIntent()
{
return lastReceivedIntent;
}
}

@ -58,6 +58,8 @@ public class WidgetReceiver extends BroadcastReceiver
private static final String TAG = "WidgetReceiver";
private static Intent lastReceivedIntent = null;
@Override
public void onReceive(final Context context, Intent intent)
{
@ -75,6 +77,7 @@ public class WidgetReceiver extends BroadcastReceiver
WidgetUpdater widgetUpdater = app.getComponent().getWidgetUpdater();
Log.i(TAG, String.format("Received intent: %s", intent.toString()));
lastReceivedIntent = intent;
try
{
@ -112,6 +115,7 @@ public class WidgetReceiver extends BroadcastReceiver
controller.onRemoveRepetition(data.getHabit(),
data.getTimestamp());
break;
case ACTION_SET_NUMERICAL_VALUE:
context.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
Intent numberSelectorIntent = new Intent(context, NumericalCheckmarkWidgetActivity.class);
@ -121,6 +125,7 @@ public class WidgetReceiver extends BroadcastReceiver
parser.copyIntentData(intent,numberSelectorIntent);
context.startActivity(numberSelectorIntent);
break;
case ACTION_UPDATE_WIDGETS_VALUE:
widgetUpdater.updateWidgets();
widgetUpdater.scheduleStartDayWidgetUpdate();
@ -139,4 +144,14 @@ public class WidgetReceiver extends BroadcastReceiver
{
WidgetBehavior getWidgetController();
}
public static Intent getLastReceivedIntent()
{
return lastReceivedIntent;
}
public static void clearLastReceivedIntent()
{
lastReceivedIntent = null;
}
}

@ -162,10 +162,16 @@ public class ReminderScheduler implements CommandRunner.Listener
public interface SystemScheduler
{
void scheduleShowReminder(long reminderTime, Habit habit, long timestamp);
SchedulerResult scheduleShowReminder(long reminderTime, Habit habit, long timestamp);
void scheduleWidgetUpdate(long updateTime);
SchedulerResult scheduleWidgetUpdate(long updateTime);
void log(String componentName, String msg);
}
public enum SchedulerResult
{
IGNORED,
OK
}
}

Loading…
Cancel
Save