Skip to content

Commit

Permalink
Merge branch 'setalarm-testing'
Browse files Browse the repository at this point in the history
  • Loading branch information
jensstein committed Jun 29, 2019
2 parents f18a418 + fe876f2 commit bcd7a9f
Show file tree
Hide file tree
Showing 6 changed files with 219 additions and 28 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@
src/main/assets
build
local.properties
sonarqube-env
26 changes: 4 additions & 22 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id "com.android.application" version "3.2.1"
id "com.android.application" version "3.4.1"
id "org.sonarqube" version "2.6"
id "jacoco"
}
Expand All @@ -15,7 +15,7 @@ ext {
hamcrest_version = "1.3"
junit_version = "4.12"
lightweight_stream_api_version = "1.2.1"
mockito_version = "2.23.4"
mockito_version = "2.24.0"
room_version = "2.1.0-alpha03"
uiautomator_version = "2.2.0"
lifecycle_version = "2.0.0"
Expand Down Expand Up @@ -45,21 +45,7 @@ dependencies {
androidTestImplementation group: "com.android.support.test",
name: "rules", version: android_support_test_version
androidTestImplementation(group: "org.mockito", name: "mockito-android",
version: mockito_version) {
exclude group: "net.bytebuddy", module: "byte-buddy"
exclude group: "net.bytebuddy", module: "byte-buddy-android"
exclude group: "net.bytebuddy", module: "byte-buddy-agent"
}
/* The version of byte-buddy included in mockito 2.23.4 causes runtime
* errors when run with gradle android plugin versions before 3.3.0.
* https://github.com/mockito/mockito/issues/1511
*/
androidTestImplementation group: "net.bytebuddy", name: "byte-buddy",
version: "1.8.22"
androidTestImplementation group: "net.bytebuddy", name: "byte-buddy-android",
version: "1.8.22"
androidTestImplementation group: "net.bytebuddy", name: "byte-buddy-agent",
version: "1.8.22"
version: mockito_version)
androidTestImplementation group: "androidx.test.uiautomator",
name: "uiautomator", version: uiautomator_version
implementation group: "androidx.lifecycle", name: "lifecycle-livedata",
Expand Down Expand Up @@ -95,7 +81,7 @@ Map<String, Integer> abiVersionCodes = [
sonarqube {
properties {
def jacocoReports = []
fileTree("${buildDir}/outputs/code-coverage").forEach({f ->
fileTree("${buildDir}/outputs/code_coverage").forEach({f ->
if(f.path.endsWith(".ec") || f.path.endsWith(".exec")){
jacocoReports << f
}
Expand Down Expand Up @@ -305,10 +291,6 @@ android.applicationVariants.all { variant ->
}
}

task wrapper(type: Wrapper) {
gradleVersion = '2.8'
}

clean {
doLast {
abiFlavorMap.values().each {
Expand Down
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-4.10.2-all.zip
distributionUrl=http\://services.gradle.org/distributions/gradle-5.5-all.zip
107 changes: 107 additions & 0 deletions src/androidTest/java/dk/jens/backup/schedules/HandleAlarmsTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package dk.jens.backup.schedules;

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import dk.jens.backup.AbstractInstrumentationTest;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

@RunWith(AndroidJUnit4.class)
public class HandleAlarmsTest extends AbstractInstrumentationTest {
@Mock
private AlarmManager alarmManager = mock(AlarmManager.class);

@Mock
private HandleAlarms.DeviceIdleChecker deviceIdleChecker = mock(HandleAlarms.DeviceIdleChecker.class);

@Rule
public ActivityTestRule<Scheduler> schedulerActivityTestRule =
new ActivityTestRule<>(Scheduler.class, false, true);

@Test
public void test_setAlarm_ignoringOptimizations() {
final HandleAlarms handleAlarms = new HandleAlarms(
schedulerActivityTestRule.getActivity());
handleAlarms.alarmManager = alarmManager;
handleAlarms.deviceIdleChecker = deviceIdleChecker;

when(deviceIdleChecker.isIdleModeSupported()).thenReturn(true);
when(deviceIdleChecker.isIgnoringBatteryOptimizations())
.thenReturn(true);

handleAlarms.setAlarm(2, 1020);
final Intent intent = new Intent(
schedulerActivityTestRule.getActivity(), AlarmReceiver.class);
intent.putExtra("id", 2);
final PendingIntent pendingIntent =
PendingIntent.getBroadcast(schedulerActivityTestRule.getActivity(),
2, intent, 0);
verify(alarmManager).setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP,
1020L, pendingIntent);
}

@Test
public void test_setAlarm_hasBatteryOptimizations() {
final HandleAlarms handleAlarms = new HandleAlarms(
schedulerActivityTestRule.getActivity());
handleAlarms.alarmManager = alarmManager;
handleAlarms.deviceIdleChecker = deviceIdleChecker;

when(deviceIdleChecker.isIdleModeSupported()).thenReturn(true);
when(deviceIdleChecker.isIgnoringBatteryOptimizations())
.thenReturn(false);

handleAlarms.setAlarm(2, 1020);
final Intent intent = new Intent(
schedulerActivityTestRule.getActivity(), AlarmReceiver.class);
intent.putExtra("id", 2);
final PendingIntent pendingIntent =
PendingIntent.getBroadcast(schedulerActivityTestRule.getActivity(),
2, intent, 0);
verify(alarmManager).set(AlarmManager.RTC_WAKEUP,
1020L, pendingIntent);
}

@Test
public void test_setAlarm_idleModeNotSupported() {
final HandleAlarms handleAlarms = new HandleAlarms(
schedulerActivityTestRule.getActivity());
handleAlarms.alarmManager = alarmManager;
handleAlarms.deviceIdleChecker = deviceIdleChecker;

when(deviceIdleChecker.isIdleModeSupported()).thenReturn(false);
when(deviceIdleChecker.isIgnoringBatteryOptimizations())
.thenReturn(false);

handleAlarms.setAlarm(2, 1020);
final Intent intent = new Intent(
schedulerActivityTestRule.getActivity(), AlarmReceiver.class);
intent.putExtra("id", 2);
final PendingIntent pendingIntent =
PendingIntent.getBroadcast(schedulerActivityTestRule.getActivity(),
2, intent, 0);
verify(alarmManager).set(AlarmManager.RTC_WAKEUP,
1020L, pendingIntent);
}

@Test
public void test_timeUntilNextEvent() {
// 1561791600000 => 2019-06-29T09:00:00
final long now = 1561791600000L;
final long nextEvent = HandleAlarms.timeUntilNextEvent(1, 10, now,
now);
// 90000000 => 25h
assertThat(nextEvent, is(90000000L));
}
}
41 changes: 36 additions & 5 deletions src/main/java/dk/jens/backup/schedules/HandleAlarms.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,25 @@
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.PowerManager;
import android.util.Log;
import androidx.annotation.RequiresApi;
import dk.jens.backup.OAndBackup;

import java.util.Calendar;

public class HandleAlarms
{
static final String TAG = OAndBackup.TAG;
AlarmManager alarmManager;
DeviceIdleChecker deviceIdleChecker;

Context context;
public HandleAlarms(Context context)
{
this.context = context;
this.alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
this.deviceIdleChecker = new DeviceIdleChecker(context);
}
public void setAlarm(int id, int interval, int hour) {
if(interval > 0) {
Expand All @@ -28,15 +34,15 @@ public void setAlarm(int id, int interval, int hour) {
}
public void setAlarm(int id, long start)
{
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
Intent intent = new Intent(context, AlarmReceiver.class);
intent.putExtra("id", id); // requestCode of PendingIntent is not used yet so a separate extra is needed
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, id, intent, 0);
am.cancel(pendingIntent);
if(Build.VERSION.SDK_INT >= 23) {
am.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, start, pendingIntent);
alarmManager.cancel(pendingIntent);
if(deviceIdleChecker.isIdleModeSupported() &&
deviceIdleChecker.isIgnoringBatteryOptimizations()) {
alarmManager.setAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, start, pendingIntent);
} else {
am.set(AlarmManager.RTC_WAKEUP, start, pendingIntent);
alarmManager.set(AlarmManager.RTC_WAKEUP, start, pendingIntent);
}
Log.i(TAG, "backup starting in: " +
((start - System.currentTimeMillis()) / 1000f / 60 / 60f));
Expand All @@ -58,4 +64,29 @@ public static long timeUntilNextEvent(int interval, int hour,
c.set(Calendar.MINUTE, 0);
return c.getTimeInMillis() - now;
}

// Adapted from the DozeChecker class from k9-mail:
// https://github.com/k9mail/k-9/blob/master/app/core/src/main/java/com/fsck/k9/power/DozeChecker.java
// That class is licensed under the Apache v2 license which is
// compatible with the MIT license used by this project.
static class DeviceIdleChecker {
private final Context context;
private final PowerManager powerManager;

private DeviceIdleChecker(Context context) {
this.context = context;
this.powerManager = (PowerManager) context.getSystemService(
Context.POWER_SERVICE);
}

boolean isIdleModeSupported() {
return Build.VERSION.SDK_INT >= 23;
}

@RequiresApi(api = Build.VERSION_CODES.M)
boolean isIgnoringBatteryOptimizations() {
return powerManager.isIgnoringBatteryOptimizations(
context.getPackageName());
}
}
}
70 changes: 70 additions & 0 deletions tests/connected_android_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/usr/bin/env bash

set -xe

FLAVOUR=arm64

function start_test() {
test_c=
if test ! -z $1; then
test_c="-e class $1"
fi
./gradlew test${FLAVOUR^}DebugUnitTest assemble${FLAVOUR^}Debug assemble${FLAVOUR^}DebugAndroidTest
adb push build/outputs/apk/${FLAVOUR}/debug/oandbackup-${FLAVOUR}-debug.apk /data/local/tmp/dk.jens.backup
adb shell pm install -t -r "/data/local/tmp/dk.jens.backup"
adb push build/outputs/apk/androidTest/${FLAVOUR}/debug/oandbackup-${FLAVOUR}-debug-androidTest.apk /data/local/tmp/dk.jens.backup.test
adb shell pm install -t -r "/data/local/tmp/dk.jens.backup.test"

adb shell am instrument -w -r -e debug false ${test_c} dk.jens.backup.test/android.support.test.runner.AndroidJUnitRunner
}

function init() {
adb uninstall dk.jens.backup || true
start_test "dk.jens.backup.TestHelper"
}

function sonarqube() {
if test -e sonarqube-env; then
source sonarqube-env
fi
./gradlew create${FLAVOUR^}DebugCoverageReport sonarqube \
-Dsonar.host.url=$SONARQUBE_HOST \
-Dsonar.login=$SONARQUBE_TOKEN
}

action=
while [ $# -gt 0 ]; do
case "$1" in
"--test-class")
test_class="$2"
shift
;;
"--flavour")
FLAVOUR="$2"
shift
;;
"--clean")
./gradlew clean
;;
"--sonarqube")
action="sonarqube"
;;
"-h"|"--help")
printf "usage: $0 [-h] [--test-class CLASS] [--flavour FLAVOUR] [--clean] [--sonarqube]"
exit 0
;;
*)
printf "unknown option $1\n" $1
exit 1
;;
esac
shift
done

init

if test ! -z $action && test $action = "sonarqube"; then
sonarqube
else
start_test "$test_class"
fi

0 comments on commit bcd7a9f

Please sign in to comment.