summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
Diffstat (limited to 'tests')
-rw-r--r--tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt4
-rw-r--r--tests/testables/src/android/testing/TestWithLooperRule.java161
-rw-r--r--tests/testables/src/android/testing/TestableResources.java38
-rw-r--r--tests/testables/tests/AndroidManifest.xml2
-rw-r--r--tests/testables/tests/AndroidTest.xml27
5 files changed, 186 insertions, 46 deletions
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
index 4efee55b97b5..8f07f213521b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromLockNotificationWithLockOverlayApp.kt
@@ -109,11 +109,11 @@ class OpenAppFromLockNotificationWithLockOverlayApp(flicker: FlickerTest) :
override fun navBarLayerIsVisibleAtStartAndEnd() = super.navBarLayerIsVisibleAtStartAndEnd()
/** {@inheritDoc} */
- @FlakyTest(bugId = 209599395)
+ @Presubmit
@Test
override fun navBarWindowIsAlwaysVisible() = super.navBarWindowIsAlwaysVisible()
- @FlakyTest(bugId = 266730606)
+ @Presubmit
@Test
override fun entireScreenCovered() = super.entireScreenCovered()
diff --git a/tests/testables/src/android/testing/TestWithLooperRule.java b/tests/testables/src/android/testing/TestWithLooperRule.java
new file mode 100644
index 000000000000..99b303e0c43a
--- /dev/null
+++ b/tests/testables/src/android/testing/TestWithLooperRule.java
@@ -0,0 +1,161 @@
+/*
+ * Copyright (C) 2023 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 android.testing;
+
+import android.testing.TestableLooper.LooperFrameworkMethod;
+import android.testing.TestableLooper.RunWithLooper;
+
+import org.junit.internal.runners.statements.InvokeMethod;
+import org.junit.rules.MethodRule;
+import org.junit.runner.RunWith;
+import org.junit.runners.model.FrameworkMethod;
+import org.junit.runners.model.Statement;
+
+import java.lang.reflect.Field;
+import java.util.ArrayList;
+import java.util.List;
+
+/*
+ * This rule is meant to be an alternative of using AndroidTestingRunner.
+ * It let tests to start from background thread, and assigns mainLooper or new
+ * Looper for the Statement.
+ */
+public class TestWithLooperRule implements MethodRule {
+
+ /*
+ * This rule requires to be the inner most Rule, so the next statement is RunAfters
+ * instead of another rule. You can set it by '@Rule(order = Integer.MAX_VALUE)'
+ */
+ @Override
+ public Statement apply(Statement base, FrameworkMethod method, Object target) {
+ // getting testRunner check, if AndroidTestingRunning then we skip this rule
+ RunWith runWithAnnotation = target.getClass().getAnnotation(RunWith.class);
+ if (runWithAnnotation != null) {
+ // if AndroidTestingRunner or it's subclass is in use, do nothing
+ if (AndroidTestingRunner.class.isAssignableFrom(runWithAnnotation.value())) {
+ return base;
+ }
+ }
+
+ // check if RunWithLooper annotation is used. If not skip this rule
+ RunWithLooper looperAnnotation = method.getAnnotation(RunWithLooper.class);
+ if (looperAnnotation == null) {
+ looperAnnotation = target.getClass().getAnnotation(RunWithLooper.class);
+ }
+ if (looperAnnotation == null) {
+ return base;
+ }
+
+ try {
+ wrapMethodInStatement(base, method, target);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return base;
+ }
+
+ // This method is based on JUnit4 test runner flow. It might need to be revisited when JUnit is
+ // upgraded
+ // TODO(b/277743626): use a cleaner way to wrap each statements; may require some JUnit
+ // patching to facilitate this.
+ private void wrapMethodInStatement(Statement base, FrameworkMethod method, Object target)
+ throws Exception {
+ Statement next = base;
+ try {
+ while (next != null) {
+ switch (next.getClass().getSimpleName()) {
+ case "RunAfters":
+ this.<List<FrameworkMethod>>wrapFieldMethodFor(next,
+ next.getClass(), "afters", method, target);
+ next = getNextStatement(next, "next");
+ break;
+ case "RunBefores":
+ this.<List<FrameworkMethod>>wrapFieldMethodFor(next,
+ next.getClass(), "befores", method, target);
+ next = getNextStatement(next, "next");
+ break;
+ case "FailOnTimeout":
+ // Note: withPotentialTimeout() from BlockJUnit4ClassRunner might use
+ // FailOnTimeout which always wraps a new thread during InvokeMethod
+ // method evaluation.
+ next = getNextStatement(next, "originalStatement");
+ break;
+ case "InvokeMethod":
+ this.<FrameworkMethod>wrapFieldMethodFor(next,
+ InvokeMethod.class, "testMethod", method, target);
+ return;
+ default:
+ throw new Exception(
+ String.format("Unexpected Statement received: [%s]",
+ next.getClass().getName())
+ );
+ }
+ }
+ } catch (Exception e) {
+ throw e;
+ }
+ }
+
+ // Wrapping the befores, afters, and InvokeMethods with LooperFrameworkMethod
+ // within the statement.
+ private <T> void wrapFieldMethodFor(Statement base, Class<?> targetClass, String fieldStr,
+ FrameworkMethod method, Object target)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field field = targetClass.getDeclaredField(fieldStr);
+ field.setAccessible(true);
+ T fieldInstance = (T) field.get(base);
+ if (fieldInstance instanceof FrameworkMethod) {
+ field.set(base, looperWrap(method, target, (FrameworkMethod) fieldInstance));
+ } else {
+ // Befores and afters methods lists
+ field.set(base, looperWrap(method, target, (List<FrameworkMethod>) fieldInstance));
+ }
+ }
+
+ // Retrieve the next wrapped statement based on the selected field string
+ private Statement getNextStatement(Statement base, String fieldStr)
+ throws NoSuchFieldException, IllegalAccessException {
+ Field nextField = base.getClass().getDeclaredField(fieldStr);
+ nextField.setAccessible(true);
+ Object value = nextField.get(base);
+ return value instanceof Statement ? (Statement) value : null;
+ }
+
+ protected FrameworkMethod looperWrap(FrameworkMethod method, Object test,
+ FrameworkMethod base) {
+ RunWithLooper annotation = method.getAnnotation(RunWithLooper.class);
+ if (annotation == null) annotation = test.getClass().getAnnotation(RunWithLooper.class);
+ if (annotation != null) {
+ return LooperFrameworkMethod.get(base, annotation.setAsMainLooper(), test);
+ }
+ return base;
+ }
+
+ protected List<FrameworkMethod> looperWrap(FrameworkMethod method, Object test,
+ List<FrameworkMethod> methods) {
+ RunWithLooper annotation = method.getAnnotation(RunWithLooper.class);
+ if (annotation == null) annotation = test.getClass().getAnnotation(RunWithLooper.class);
+ if (annotation != null) {
+ methods = new ArrayList<>(methods);
+ for (int i = 0; i < methods.size(); i++) {
+ methods.set(i, LooperFrameworkMethod.get(methods.get(i),
+ annotation.setAsMainLooper(), test));
+ }
+ }
+ return methods;
+ }
+}
diff --git a/tests/testables/src/android/testing/TestableResources.java b/tests/testables/src/android/testing/TestableResources.java
index c60f07d56d92..27d5b66b355e 100644
--- a/tests/testables/src/android/testing/TestableResources.java
+++ b/tests/testables/src/android/testing/TestableResources.java
@@ -59,7 +59,8 @@ public class TestableResources {
* Since resource ids are unique there is a single addOverride that will override the value
* whenever it is gotten regardless of which method is used (i.e. getColor or getDrawable).
* </p>
- * @param id The resource id to be overridden
+ *
+ * @param id The resource id to be overridden
* @param value The value of the resource, null to cause a {@link Resources.NotFoundException}
* when gotten.
*/
@@ -74,28 +75,33 @@ public class TestableResources {
* cause a {@link Resources.NotFoundException} whereas removing the override will actually
* switch back to returning the default/real value of the resource.
* </p>
- * @param id
*/
public void removeOverride(int id) {
mOverrides.remove(id);
}
private Object answer(InvocationOnMock invocationOnMock) throws Throwable {
- try {
- int id = invocationOnMock.getArgument(0);
- int index = mOverrides.indexOfKey(id);
- if (index >= 0) {
- Object value = mOverrides.valueAt(index);
- if (value == null) throw new Resources.NotFoundException();
- return value;
+ // Only try to override methods with an integer first argument
+ if (invocationOnMock.getArguments().length > 0) {
+ Object argument = invocationOnMock.getArgument(0);
+ if (argument instanceof Integer) {
+ try {
+ int id = (Integer)argument;
+ int index = mOverrides.indexOfKey(id);
+ if (index >= 0) {
+ Object value = mOverrides.valueAt(index);
+ if (value == null) throw new Resources.NotFoundException();
+ return value;
+ }
+ } catch (Resources.NotFoundException e) {
+ // Let through NotFoundException.
+ throw e;
+ } catch (Throwable t) {
+ // Generic catching for the many things that can go wrong, fall back to
+ // the real implementation.
+ Log.i(TAG, "Falling back to default resources call " + t);
+ }
}
- } catch (Resources.NotFoundException e) {
- // Let through NotFoundException.
- throw e;
- } catch (Throwable t) {
- // Generic catching for the many things that can go wrong, fall back to
- // the real implementation.
- Log.i(TAG, "Falling back to default resources call " + t);
}
return invocationOnMock.callRealMethod();
}
diff --git a/tests/testables/tests/AndroidManifest.xml b/tests/testables/tests/AndroidManifest.xml
index 1731f6be4bf2..2bfb04fdb765 100644
--- a/tests/testables/tests/AndroidManifest.xml
+++ b/tests/testables/tests/AndroidManifest.xml
@@ -21,7 +21,7 @@
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
<uses-permission android:name="android.permission.MANAGE_USERS" />
- <application android:debuggable="true" android:testOnly="true">
+ <application android:debuggable="true">
<uses-library android:name="android.test.runner" />
</application>
diff --git a/tests/testables/tests/AndroidTest.xml b/tests/testables/tests/AndroidTest.xml
deleted file mode 100644
index 6d2979423efa..000000000000
--- a/tests/testables/tests/AndroidTest.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- ~ Copyright (C) 2022 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.
- -->
-<configuration description="Runs Testable Tests.">
- <option name="test-tag" value="TestablesTests" />
- <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
- <option name="cleanup-apks" value="true" />
- <option name="install-arg" value="-t" />
- <option name="test-file-name" value="TestablesTests.apk" />
- </target_preparer>
- <test class="com.android.tradefed.testtype.AndroidJUnitTest">
- <option name="package" value="com.android.testables"/>
- </test>
-</configuration>