cmsdk: Add unit test for PartnerInterface
Created the AndroidTestCase unit test Added functional testing for airplane mode, which can be restored without contaminating other tests. Also added setZenMode testing, which currently contaminates other tests. But we will allow for lack of a better way FOR-156 Change-Id: I2ab5642c60f41266d9de8aab897e4852e872ad38
This commit is contained in:
parent
7622e3c7d6
commit
3dffa871e4
@ -0,0 +1,317 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2015, The CyanogenMod Project
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.cyanogenmod.tests.settings.unit;
|
||||||
|
|
||||||
|
import android.app.INotificationManager;
|
||||||
|
import android.content.Context;
|
||||||
|
import android.net.Uri;
|
||||||
|
import android.os.RemoteException;
|
||||||
|
import android.os.ServiceManager;
|
||||||
|
import android.service.notification.Condition;
|
||||||
|
import android.service.notification.IConditionListener;
|
||||||
|
import android.test.AndroidTestCase;
|
||||||
|
import android.test.suitebuilder.annotation.SmallTest;
|
||||||
|
import android.provider.Settings;
|
||||||
|
import android.text.format.DateUtils;
|
||||||
|
import android.util.Log;
|
||||||
|
import cyanogenmod.app.PartnerInterface;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unit test for PartnerInterface
|
||||||
|
*/
|
||||||
|
public class CMPartnerInterfaceTest extends AndroidTestCase {
|
||||||
|
|
||||||
|
private static final String TAG = "CMPartnerInterfaceTest";
|
||||||
|
|
||||||
|
private PartnerInterface mPartnerInterface;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
mPartnerInterface = PartnerInterface.getInstance(getContext());
|
||||||
|
|
||||||
|
setupAirplaneModeTests();
|
||||||
|
setupZenModeTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void tearDown() throws Exception {
|
||||||
|
super.tearDown();
|
||||||
|
teardownAirplaneModeTests();
|
||||||
|
teardownZenModeTests();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testPartnerInterfaceExists() {
|
||||||
|
assertNotNull(mPartnerInterface);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testPartnerInterfaceAvailable() {
|
||||||
|
assertNotNull(mPartnerInterface.getService());
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
// Airplane Mode tests
|
||||||
|
|
||||||
|
private boolean mAirplaneModeEnabled;
|
||||||
|
private void setupAirplaneModeTests() {
|
||||||
|
// Remember the initial state
|
||||||
|
mAirplaneModeEnabled = getAirplaneModeEnabled();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void teardownAirplaneModeTests() {
|
||||||
|
// Restore airplane mode
|
||||||
|
mPartnerInterface.setAirplaneModeEnabled(mAirplaneModeEnabled);
|
||||||
|
}
|
||||||
|
@SmallTest
|
||||||
|
public void testSetAirplaneModeOn() {
|
||||||
|
mPartnerInterface.setAirplaneModeEnabled(true);
|
||||||
|
assertTrue(getAirplaneModeEnabled());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testSetAirplaneModeOff() {
|
||||||
|
mPartnerInterface.setAirplaneModeEnabled(false);
|
||||||
|
assertTrue(getAirplaneModeEnabled() == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getAirplaneModeEnabled() {
|
||||||
|
return Settings.System.getInt(getContext().getContentResolver(),
|
||||||
|
Settings.System.AIRPLANE_MODE_ON, 0) == 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/////////////////////////////////////////////////////
|
||||||
|
// Zen Mode Testing:
|
||||||
|
// Allow the tests below for now, but in the future
|
||||||
|
// implement a valid method for restoring the zen mode
|
||||||
|
// setting, e.g. in tearDownZenModeTests
|
||||||
|
|
||||||
|
// Because it's not possible to get & restore zen mode
|
||||||
|
// duration, these tests will contaminate system state
|
||||||
|
// whenver they're run. Ideally testing should instead
|
||||||
|
// be done in another suite, such as using Mokito
|
||||||
|
// https://corner.squareup.com/2012/10/mockito-android.html
|
||||||
|
//
|
||||||
|
// However because of the complexity, for now allow
|
||||||
|
// these unit tests as-is.
|
||||||
|
//
|
||||||
|
// THESE WILL WIPE OUT any duration-based zen modes in
|
||||||
|
// effect!
|
||||||
|
private static final long DURATION_30s_MS = 30 * DateUtils.SECOND_IN_MILLIS;
|
||||||
|
private static final long DURATION_TOLERANCE_MS = 5; //5 ms in tolerance due to latency
|
||||||
|
private static final long DURATION_TEST_MAX_MS = DateUtils.MINUTE_IN_MILLIS; //Allow 1 minute max for unit testing
|
||||||
|
|
||||||
|
private INotificationManager mNotificationManager;
|
||||||
|
private CountdownConditionListener mConditionListener;
|
||||||
|
|
||||||
|
private void setupZenModeTests() {
|
||||||
|
mNotificationManager = INotificationManager.Stub.asInterface(
|
||||||
|
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
|
||||||
|
|
||||||
|
mConditionListener = new CountdownConditionListener();
|
||||||
|
try {
|
||||||
|
mNotificationManager.requestZenModeConditions(mConditionListener, Condition.FLAG_RELEVANT_ALWAYS);
|
||||||
|
} catch (RemoteException e) {
|
||||||
|
fail("requestZenModeConditions exception " + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void teardownZenModeTests() {
|
||||||
|
// For now, restore the zen mode to the system default
|
||||||
|
mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_OFF);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testSetZenModeImportantInterruptions() {
|
||||||
|
mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS);
|
||||||
|
assertEquals(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS, getZenMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testSetZenModeImportantInterruptionsWithDurations() {
|
||||||
|
// 0 duration
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS, 0);
|
||||||
|
|
||||||
|
// Indefinitely
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS, Long.MAX_VALUE);
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS, -1);
|
||||||
|
|
||||||
|
// normal duration values (1, 5s)
|
||||||
|
// NOTE: these tests do not return until duration has passed. Use with care!
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS, DateUtils.SECOND_IN_MILLIS);
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_IMPORTANT_INTERRUPTIONS, 5 * DateUtils.SECOND_IN_MILLIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testSetZenModeNoInterruptions() {
|
||||||
|
mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS);
|
||||||
|
assertEquals(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS, getZenMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testSetZenModeNoInterruptionsWithDurations() {
|
||||||
|
// 0 duration
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS, 0);
|
||||||
|
|
||||||
|
// Indefinitely
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS, Long.MAX_VALUE);
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS, -1);
|
||||||
|
|
||||||
|
// normal duration values (1, 5s)
|
||||||
|
// NOTE: these tests do not return until duration has passed. Use with care!
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS, DateUtils.SECOND_IN_MILLIS);
|
||||||
|
testZenModeWithDuration(PartnerInterface.ZEN_MODE_NO_INTERRUPTIONS, 5 * DateUtils.SECOND_IN_MILLIS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SmallTest
|
||||||
|
public void testSetZenModeOff() {
|
||||||
|
mPartnerInterface.setZenMode(PartnerInterface.ZEN_MODE_OFF);
|
||||||
|
assertEquals(PartnerInterface.ZEN_MODE_OFF, getZenMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* testZenModeWithDuration: sets Zen Mode with duration and blocks
|
||||||
|
* until the duration is verified. Use with care! This does not
|
||||||
|
* return until after durationMillis
|
||||||
|
* @param mode
|
||||||
|
* @param durationMillis
|
||||||
|
*/
|
||||||
|
private void testZenModeWithDuration(int mode, long durationMillis) {
|
||||||
|
|
||||||
|
final long startTimeMillis = System.currentTimeMillis();
|
||||||
|
mPartnerInterface.setZenModeWithDuration(mode, durationMillis);
|
||||||
|
final int actualZenMode = getZenMode();
|
||||||
|
|
||||||
|
// check zen mode is correct
|
||||||
|
if (durationMillis == 0) {
|
||||||
|
assertTrue(actualZenMode == mode || actualZenMode == PartnerInterface.ZEN_MODE_OFF);
|
||||||
|
} else {
|
||||||
|
assertEquals(mode, actualZenMode);
|
||||||
|
}
|
||||||
|
// skip durations that are indefinite
|
||||||
|
if (actualZenMode == PartnerInterface.ZEN_MODE_OFF || durationMillis < 0 || durationMillis == Long.MAX_VALUE) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// check duration is correct
|
||||||
|
final long zenDuration = getZenModeDuration(startTimeMillis);
|
||||||
|
assertTrue(Math.abs(zenDuration - durationMillis) <= DURATION_TOLERANCE_MS); //Allow a tolerance
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getZenModeDuration: Blocking call to wait for ZenMode duration.
|
||||||
|
* @param startTimeMillis - start time of the duration
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
private long getZenModeDuration(long startTimeMillis) {
|
||||||
|
// NOTE: waits for the next duration to be triggered
|
||||||
|
return mConditionListener.waitForDuration(startTimeMillis);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getZenMode() {
|
||||||
|
int zenMode = -1;
|
||||||
|
try {
|
||||||
|
zenMode = mNotificationManager.getZenMode();
|
||||||
|
} catch (RemoteException rex) {
|
||||||
|
fail("INotificationManager.getZenMode() " + rex.getMessage());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Log.d(TAG, "getZenMode returning " + zenMode);
|
||||||
|
return zenMode;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* CountdownConditionListener
|
||||||
|
* This class is passed to blocks until the Countdown is received
|
||||||
|
*/
|
||||||
|
private static class CountdownConditionListener
|
||||||
|
extends IConditionListener.Stub {
|
||||||
|
|
||||||
|
private static long INVALID_ENDTIME = -1;
|
||||||
|
private long mEndTime = INVALID_ENDTIME;
|
||||||
|
|
||||||
|
public CountdownConditionListener() {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* waitForDuration: blocks until onConditionReceived
|
||||||
|
* This CountdownConditionListener was previously passed
|
||||||
|
* to the
|
||||||
|
* @return
|
||||||
|
* the duration of
|
||||||
|
*/
|
||||||
|
public synchronized long waitForDuration(long startTimeMillis) {
|
||||||
|
Log.d(TAG, "waitForDuration");
|
||||||
|
// If we have a stale endtime, then discard it
|
||||||
|
if (mEndTime < startTimeMillis) {
|
||||||
|
mEndTime = INVALID_ENDTIME;
|
||||||
|
}
|
||||||
|
// If no valid endtime, then block and wait for the current
|
||||||
|
// duration to expire. The wait ends when
|
||||||
|
// onConditionsReceived is called
|
||||||
|
if (mEndTime == INVALID_ENDTIME) {
|
||||||
|
try {
|
||||||
|
// wait no more than DURATION_TEST_MAX_MS
|
||||||
|
wait(DURATION_TEST_MAX_MS);
|
||||||
|
} catch (InterruptedException iex) {
|
||||||
|
Log.e(TAG, "waitForDuration", iex);
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (mEndTime == INVALID_ENDTIME) {
|
||||||
|
Log.d(TAG, "waitForDuration found invalid endtime. Did you exceed the max duration (" + DURATION_TEST_MAX_MS + " ms)?");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.d(TAG, "waitForDuration returning endtime:" + mEndTime + " duration:" + (mEndTime - startTimeMillis));
|
||||||
|
final long duration = mEndTime - startTimeMillis;
|
||||||
|
|
||||||
|
// Reset endtime to show that it's been consumed
|
||||||
|
mEndTime = INVALID_ENDTIME;
|
||||||
|
return duration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* onConditionReceived: called when a condition is triggered
|
||||||
|
* @param conditions - conditions that triggered
|
||||||
|
* This is actually just the Alarm endtime that CountdownConditionProvider
|
||||||
|
* previously submitted
|
||||||
|
* @throws RemoteException
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public synchronized void onConditionsReceived(Condition[] conditions) throws RemoteException {
|
||||||
|
// CountdownConditionProvider only triggers 1 condition at a time
|
||||||
|
mEndTime = parseEndTime(conditions[0].id);
|
||||||
|
notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
private long parseEndTime(Uri conditionUri) {
|
||||||
|
final List<String> pathSegments = conditionUri.getPathSegments();
|
||||||
|
return Long.decode(pathSegments.get(pathSegments.size() - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private method for debugging
|
||||||
|
private void logConditions(Condition[] conditions) {
|
||||||
|
for (int i = 0; i < conditions.length; i++) {
|
||||||
|
Log.d(TAG, "condition[" + i + "]:" + conditions[i].id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user