From e4298941b4fa1a3cb5ffd9b8e58f06096d8d2b84 Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Thu, 17 Aug 2017 14:26:01 -0700 Subject: [PATCH 1/2] Add functional test for bt anomaly detector This cl: Set up the environment for functional test 1. Update Android.mk by adding instrumentation and libs 2. Update AndroidManifest.xml by adding runner Add functional test for bt anomaly, with the following workflow 1. reset battery stats 2. pretend unplug and screen off 3. Start AnomalyTester app, set values and click start button 4. Wait its running 5. Check anomaly preference in battery main page 6. reset all parameters Bug: 63815938 Test: runtest -x BluetoothAnomalyTest Change-Id: Ief02a314d21f6c32d70729047a1d4bdce9ad9920 --- tests/anomaly-tester/Android.mk | 11 +- tests/anomaly-tester/AndroidManifest.xml | 8 ++ .../anomaly/tests/BluetoothAnomalyTest.java | 108 ++++++++++++++++++ .../settings/anomaly/tests/TestUtils.java | 91 +++++++++++++++ 4 files changed, 217 insertions(+), 1 deletion(-) create mode 100644 tests/anomaly-tester/src/com/android/settings/anomaly/tests/BluetoothAnomalyTest.java create mode 100644 tests/anomaly-tester/src/com/android/settings/anomaly/tests/TestUtils.java diff --git a/tests/anomaly-tester/Android.mk b/tests/anomaly-tester/Android.mk index beb5d69a9e7..ade37db0284 100644 --- a/tests/anomaly-tester/Android.mk +++ b/tests/anomaly-tester/Android.mk @@ -2,6 +2,15 @@ LOCAL_PATH:= $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests +LOCAL_CERTIFICATE := platform + +LOCAL_JAVA_LIBRARIES := android.test.runner bouncycastle + +LOCAL_STATIC_JAVA_LIBRARIES := \ + android-support-test \ + mockito-target \ + ub-uiautomator \ + truth-prebuilt \ LOCAL_SRC_FILES := $(call all-subdir-java-files) @@ -9,7 +18,7 @@ LOCAL_PROGUARD_ENABLED := disabled LOCAL_PACKAGE_NAME := AnomalyTester -LOCAL_CERTIFICATE := platform +LOCAL_INSTRUMENTATION_FOR := Settings LOCAL_USE_AAPT2 := true diff --git a/tests/anomaly-tester/AndroidManifest.xml b/tests/anomaly-tester/AndroidManifest.xml index 68e2dd71a0f..7893b866bfa 100644 --- a/tests/anomaly-tester/AndroidManifest.xml +++ b/tests/anomaly-tester/AndroidManifest.xml @@ -22,11 +22,13 @@ + + @@ -41,4 +43,10 @@ android:exported="false"/> + + + \ No newline at end of file diff --git a/tests/anomaly-tester/src/com/android/settings/anomaly/tests/BluetoothAnomalyTest.java b/tests/anomaly-tester/src/com/android/settings/anomaly/tests/BluetoothAnomalyTest.java new file mode 100644 index 00000000000..3630ce420dd --- /dev/null +++ b/tests/anomaly-tester/src/com/android/settings/anomaly/tests/BluetoothAnomalyTest.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2017 The Android Open Source 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 com.android.settings.anomaly.tests; + +import static com.google.common.truth.Truth.assertWithMessage; + +import android.app.Instrumentation; +import android.content.Context; +import android.content.Intent; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.Until; +import android.text.format.DateUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Functional test for bluetooth unoptimized scanning anomaly detector + * + * @see com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector + */ +@RunWith(AndroidJUnit4.class) +public class BluetoothAnomalyTest { + private static final String BATTERY_INTENT = "android.intent.action.POWER_USAGE_SUMMARY"; + private static final String RES_BT_EDITTEXT = + "com.android.settings.anomaly.tester:id/bluetooth_run_time"; + private static final String RES_BT_BUTTON = + "com.android.settings.anomaly.tester:id/bluetooth_button"; + private static final long TIME_OUT = 3000; + private UiDevice mDevice; + + @Before + public void setUp() { + final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + final Context context = instrumentation.getContext(); + mDevice = UiDevice.getInstance(instrumentation); + + // setup environment + TestUtils.setUp(instrumentation); + // start anomaly-tester app + TestUtils.startAnomalyApp(context, mDevice); + } + + @After + public void tearDown() { + TestUtils.tearDown(InstrumentationRegistry.getInstrumentation()); + } + + @Test + public void testBluetoothAnomaly_longScanningTime_reportAnomaly() throws InterruptedException { + // Set running time + final long durationMs = DateUtils.SECOND_IN_MILLIS * 15; + TestUtils.setEditTextWithValue(mDevice, RES_BT_EDITTEXT, durationMs); + + // Click start button + TestUtils.clickButton(mDevice, RES_BT_BUTTON); + + // Wait for its running + mDevice.pressHome(); + TestUtils.wait(mDevice, durationMs); + + // Check it in battery main page + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + instrumentation.startActivitySync(new Intent(BATTERY_INTENT)); + assertWithMessage("Doesn't have bluetooth anomaly").that( + mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")), + TIME_OUT)).isNotNull(); + } + + @Test + public void testBluetoothAnomaly_shortScanningTime_notReport() throws InterruptedException { + // Set running time + final long durationMs = DateUtils.SECOND_IN_MILLIS; + TestUtils.setEditTextWithValue(mDevice, RES_BT_EDITTEXT, durationMs); + + // Click start button + TestUtils.clickButton(mDevice, RES_BT_BUTTON); + + // Wait for its running + mDevice.pressHome(); + TestUtils.wait(mDevice, durationMs); + + // Check it in battery main page + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + instrumentation.startActivitySync(new Intent(BATTERY_INTENT)); + assertWithMessage("Shouldn't have bluetooth anomaly").that( + mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")), + TIME_OUT)).isNull(); + } + +} diff --git a/tests/anomaly-tester/src/com/android/settings/anomaly/tests/TestUtils.java b/tests/anomaly-tester/src/com/android/settings/anomaly/tests/TestUtils.java new file mode 100644 index 00000000000..ac15d77bb18 --- /dev/null +++ b/tests/anomaly-tester/src/com/android/settings/anomaly/tests/TestUtils.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2017 The Android Open Source 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 com.android.settings.anomaly.tests; + +import static com.google.common.truth.Truth.assertWithMessage; + +import android.app.Instrumentation; +import android.app.UiAutomation; +import android.content.Context; +import android.content.Intent; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.UiObject2; +import android.support.test.uiautomator.Until; + +public class TestUtils { + private static final String PACKAGE_NAME = "com.android.settings.anomaly.tester"; + private static final long TIME_OUT = 3000; + + /** + * This method set up the environment for anomaly test + * + * @param instrumentation to execute command + */ + public static void setUp(Instrumentation instrumentation) { + final UiAutomation uiAutomation = instrumentation.getUiAutomation(); + // pretend unplug and screen off, also reset the battery stats + uiAutomation.executeShellCommand("dumpsys battery unplug"); + uiAutomation.executeShellCommand("dumpsys batterystats enable pretend-screen-off"); + uiAutomation.executeShellCommand("dumpsys batterystats --reset"); + } + + /** + * This method cleans up all the commands in {@link #setUp(Instrumentation)} + * + * @param instrumentation to execute command + */ + public static void tearDown(Instrumentation instrumentation) { + final UiAutomation uiAutomation = instrumentation.getUiAutomation(); + // reset unplug and screen-off + uiAutomation.executeShellCommand("dumpsys battery reset"); + uiAutomation.executeShellCommand("dumpsys batterystats disable pretend-screen-off"); + } + + public static void startAnomalyApp(Context context, UiDevice uiDevice) { + final Intent intent = context.getPackageManager().getLaunchIntentForPackage(PACKAGE_NAME); + intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); + context.startActivity(intent); + uiDevice.wait(Until.hasObject(By.pkg(PACKAGE_NAME).depth(0)), TIME_OUT); + } + + /** + * Find {@link android.widget.EditText} with {@code res} and set its {@code value} + */ + public static void setEditTextWithValue(UiDevice uiDevice, String res, long value) { + final UiObject2 editText = uiDevice.findObject(By.res(res)); + assertWithMessage("Cannot find editText with res: " + res).that(editText).isNotNull(); + editText.setText(String.valueOf(value)); + } + + /** + * Find {@link android.widget.Button} with {@code res} and click it + */ + public static void clickButton(UiDevice uiDevice, String res) { + final UiObject2 button = uiDevice.findObject(By.res(res)); + assertWithMessage("Cannot find button with res: " + res).that(button).isNotNull(); + button.click(); + } + + /** + * Make {@link UiDevice} wait for {@code timeMs} + * + * @see Thread#sleep(long) + */ + public static void wait(UiDevice uiDevice, long timeMs) throws InterruptedException { + uiDevice.waitForIdle(); + Thread.sleep(timeMs); + } +} From d8bfc742569ca4c4697c788f03dfb504037f846c Mon Sep 17 00:00:00 2001 From: jackqdyulei Date: Thu, 17 Aug 2017 15:06:06 -0700 Subject: [PATCH 2/2] Add functional test for wakelock anomaly detector Bug: 63815938 Test: runtest -x WakelockAnomalyTest Change-Id: I4d10d5be8b38264f29c67c2c945fdbbd1090430d --- .../anomaly/tests/WakelockAnomalyTest.java | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 tests/anomaly-tester/src/com/android/settings/anomaly/tests/WakelockAnomalyTest.java diff --git a/tests/anomaly-tester/src/com/android/settings/anomaly/tests/WakelockAnomalyTest.java b/tests/anomaly-tester/src/com/android/settings/anomaly/tests/WakelockAnomalyTest.java new file mode 100644 index 00000000000..a2f38048977 --- /dev/null +++ b/tests/anomaly-tester/src/com/android/settings/anomaly/tests/WakelockAnomalyTest.java @@ -0,0 +1,132 @@ +/* + * Copyright (C) 2017 The Android Open Source 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 com.android.settings.anomaly.tests; + +import static com.google.common.truth.Truth.assertWithMessage; + +import android.app.Instrumentation; +import android.content.Context; +import android.content.Intent; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; +import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; +import android.support.test.uiautomator.Until; +import android.text.format.DateUtils; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Functional test for bluetooth unoptimized scanning anomaly detector + * + * @see com.android.settings.fuelgauge.anomaly.checker.BluetoothScanAnomalyDetector + */ +@RunWith(AndroidJUnit4.class) +public class WakelockAnomalyTest { + private static final String BATTERY_INTENT = "android.intent.action.POWER_USAGE_SUMMARY"; + private static final String RES_WAKELOCK_EDITTEXT = + "com.android.settings.anomaly.tester:id/wakelock_run_time"; + private static final String RES_WAKELOCK_BUTTON = + "com.android.settings.anomaly.tester:id/wakelock_button"; + private static final long TIME_OUT = 3000; + private UiDevice mDevice; + + @Before + public void setUp() { + final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + final Context context = instrumentation.getContext(); + mDevice = UiDevice.getInstance(instrumentation); + + // setup environment + TestUtils.setUp(instrumentation); + // start anomaly-tester app + TestUtils.startAnomalyApp(context, mDevice); + } + + @After + public void tearDown() { + TestUtils.tearDown(InstrumentationRegistry.getInstrumentation()); + } + + @Test + public void testWakelockAnomaly_longTimeWhileRunning_report() throws InterruptedException { + // Set running time + final long durationMs = DateUtils.SECOND_IN_MILLIS * 15; + TestUtils.setEditTextWithValue(mDevice, RES_WAKELOCK_EDITTEXT, durationMs); + + // Click start button + TestUtils.clickButton(mDevice, RES_WAKELOCK_BUTTON); + + // Wait for its running + mDevice.pressHome(); + // Sleeping time less than running time, so the app still holding wakelock when we check + TestUtils.wait(mDevice, durationMs - TIME_OUT); + + // Check it in battery main page + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + instrumentation.startActivitySync(new Intent(BATTERY_INTENT)); + assertWithMessage("Doesn't have wakelock anomaly").that( + mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")), + TIME_OUT)).isNotNull(); + } + + @Test + public void testWakelockAnomaly_shortTime_notReport() throws InterruptedException { + // Set running time + final long durationMs = DateUtils.SECOND_IN_MILLIS; + TestUtils.setEditTextWithValue(mDevice, RES_WAKELOCK_EDITTEXT, durationMs); + + // Click start button + TestUtils.clickButton(mDevice, RES_WAKELOCK_BUTTON); + + // Wait for its running + mDevice.pressHome(); + TestUtils.wait(mDevice, durationMs); + + // Check it in battery main page + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + instrumentation.startActivitySync(new Intent(BATTERY_INTENT)); + assertWithMessage("Shouldn't have wakelock anomaly").that( + mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")), + TIME_OUT)).isNull(); + } + + @Test + public void testWakelockAnomaly_longTimeWhileNotRunning_notReport() + throws InterruptedException { + // Set running time + final long durationMs = DateUtils.SECOND_IN_MILLIS * 10; + TestUtils.setEditTextWithValue(mDevice, RES_WAKELOCK_EDITTEXT, durationMs); + + // Click start button + TestUtils.clickButton(mDevice, RES_WAKELOCK_BUTTON); + + // Wait for its running + mDevice.pressHome(); + // Wait more time for releasing the wakelock + TestUtils.wait(mDevice, durationMs + TIME_OUT); + + // Check it in battery main page + Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation(); + instrumentation.startActivitySync(new Intent(BATTERY_INTENT)); + assertWithMessage("Shouldn't have wakelock anomaly").that( + mDevice.wait(Until.findObject(By.text("AnomalyTester draining battery")), + TIME_OUT)).isNull(); + } + +}