diff options
14 files changed, 222 insertions, 52 deletions
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml index b12fd1c9ba89..9bb21808e9bc 100644 --- a/packages/SystemUI/tests/AndroidManifest.xml +++ b/packages/SystemUI/tests/AndroidManifest.xml @@ -48,7 +48,7 @@ android:process=":killable" /> </application> - <instrumentation android:name="android.support.test.runner.AndroidJUnitRunner" + <instrumentation android:name="android.testing.TestableInstrumentation" android:targetPackage="com.android.systemui.tests" android:label="Tests for SystemUI"> </instrumentation> diff --git a/packages/SystemUI/tests/src/com/android/systemui/RoundedCornersTest.java b/packages/SystemUI/tests/src/com/android/systemui/RoundedCornersTest.java index 945af34c1df1..507515a8c2e9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/RoundedCornersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/RoundedCornersTest.java @@ -21,7 +21,6 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; @@ -30,7 +29,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.Fragment; -import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.testing.AndroidTestingRunner; import android.view.Display; @@ -48,12 +46,10 @@ import com.android.systemui.tuner.TunablePadding.TunablePaddingService; import com.android.systemui.tuner.TunerService; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @RunWith(AndroidTestingRunner.class) -@FlakyTest @SmallTest public class RoundedCornersTest extends SysuiTestCase { @@ -72,6 +68,7 @@ public class RoundedCornersTest extends SysuiTestCase { mWindowManager = mock(WindowManager.class); mView = spy(new StatusBarWindowView(mContext, null)); when(mStatusBar.getStatusBarWindow()).thenReturn(mView); + when(mStatusBar.getNavigationBarWindow()).thenReturn(mView); mContext.putComponent(StatusBar.class, mStatusBar); Display display = mContext.getSystemService(WindowManager.class).getDefaultDisplay(); @@ -94,6 +91,8 @@ public class RoundedCornersTest extends SysuiTestCase { @Test public void testNoRounding() { mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 0); + mContext.getOrCreateTestableResources() + .addOverride(dimen.rounded_corner_content_padding, 0); mRoundedCorners.start(); // No views added. @@ -107,6 +106,8 @@ public class RoundedCornersTest extends SysuiTestCase { @Test public void testRounding() { mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 20); + mContext.getOrCreateTestableResources() + .addOverride(dimen.rounded_corner_content_padding, 20); mRoundedCorners.start(); // Add 2 windows for rounded corners (top and bottom). diff --git a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java index 361a20fb7bdc..66d00dd6c5c6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java +++ b/packages/SystemUI/tests/src/com/android/systemui/SysuiTestCase.java @@ -31,6 +31,8 @@ import android.util.Log; import org.junit.After; import org.junit.Before; import org.junit.Rule; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; @@ -56,10 +58,14 @@ public abstract class SysuiTestCase { mRealInstrumentation = InstrumentationRegistry.getInstrumentation(); Instrumentation inst = spy(mRealInstrumentation); - when(inst.getContext()).thenThrow(new RuntimeException( - "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext")); - when(inst.getTargetContext()).thenThrow(new RuntimeException( - "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext")); + when(inst.getContext()).thenAnswer(invocation -> { + throw new RuntimeException( + "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext"); + }); + when(inst.getTargetContext()).thenAnswer(invocation -> { + throw new RuntimeException( + "SysUI Tests should use SysuiTestCase#getContext or SysuiTestCase#mContext"); + }); InstrumentationRegistry.registerInstance(inst, InstrumentationRegistry.getArguments()); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java index 2363b2aadc10..8641faca5d6e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeTriggersTest.java @@ -27,7 +27,6 @@ import android.app.Instrumentation; import android.os.Handler; import android.os.Looper; import android.support.test.InstrumentationRegistry; -import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java index 6a85511daca2..ed47fbb89077 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSDetailTest.java @@ -23,10 +23,7 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; -import org.junit.After; -import org.junit.Ignore; import android.support.test.filters.SmallTest; -import android.support.test.filters.FlakyTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; @@ -41,6 +38,7 @@ import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.DetailAdapter; import org.junit.Before; +import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java index f4fda065860e..d25bbe1e4904 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSFooterTest.java @@ -21,7 +21,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.support.test.filters.SmallTest; -import android.support.test.filters.FlakyTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java index 637b2440af09..85cdfcc2ce09 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSPanelTest.java @@ -20,7 +20,6 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.support.test.filters.SmallTest; -import android.support.test.filters.FlakyTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.testing.TestableLooper.RunWithLooper; @@ -31,7 +30,6 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.qs.customize.QSCustomizer; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @@ -40,7 +38,6 @@ import java.util.Collections; @RunWith(AndroidTestingRunner.class) @RunWithLooper @SmallTest -@FlakyTest public class QSPanelTest extends SysuiTestCase { private MetricsLogger mMetricsLogger; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java index 664ea710d61e..2f6511c8481e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/ExpandableNotificationRowTest.java @@ -21,27 +21,21 @@ import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.verify; -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.annotation.UiThreadTest; -import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.View; +import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.notification.AboveShelfChangedListener; import com.android.systemui.statusbar.stack.NotificationChildrenContainer; -import com.android.systemui.SysuiTestCase; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) -@FlakyTest public class ExpandableNotificationRowTest extends SysuiTestCase { private ExpandableNotificationRow mGroup; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java index 4dce2f5f87ed..436849c9d700 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationContentViewTest.java @@ -16,30 +16,25 @@ package com.android.systemui.statusbar; -import android.content.Context; -import android.support.test.InstrumentationRegistry; +import static org.mockito.ArgumentMatchers.anyFloat; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.spy; + import android.support.test.annotation.UiThreadTest; -import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.View; +import com.android.systemui.SysuiTestCase; + import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; -import static org.mockito.ArgumentMatchers.anyFloat; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.doReturn; -import static org.mockito.Mockito.spy; - -import com.android.systemui.SysuiTestCase; - @SmallTest @RunWith(AndroidJUnit4.class) -@FlakyTest public class NotificationContentViewTest extends SysuiTestCase { NotificationContentView mView; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java index d18e63bcc151..6e59d10aad3c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationCustomViewWrapperTest.java @@ -16,10 +16,7 @@ package com.android.systemui.statusbar; -import android.content.Context; -import android.support.test.InstrumentationRegistry; import android.support.test.annotation.UiThreadTest; -import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.View; @@ -32,13 +29,11 @@ import com.android.systemui.statusbar.notification.NotificationViewWrapper; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) -@FlakyTest public class NotificationCustomViewWrapperTest extends SysuiTestCase { private ExpandableNotificationRow mRow; diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java index bc6833df1e30..5ac965cf4042 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/stack/NotificationChildrenContainerTest.java @@ -16,10 +16,6 @@ package com.android.systemui.statusbar.stack; -import android.content.Context; -import android.support.test.InstrumentationRegistry; -import android.support.test.annotation.UiThreadTest; -import android.support.test.filters.FlakyTest; import android.support.test.filters.SmallTest; import android.support.test.runner.AndroidJUnit4; import android.view.NotificationHeaderView; @@ -31,13 +27,11 @@ import com.android.systemui.statusbar.NotificationTestHelper; import org.junit.Assert; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; @SmallTest @RunWith(AndroidJUnit4.class) -@FlakyTest public class NotificationChildrenContainerTest extends SysuiTestCase { private ExpandableNotificationRow mGroup; diff --git a/services/tests/notification/AndroidManifest.xml b/services/tests/notification/AndroidManifest.xml index 99d9c7b87301..c20020abb85c 100644 --- a/services/tests/notification/AndroidManifest.xml +++ b/services/tests/notification/AndroidManifest.xml @@ -31,7 +31,7 @@ </application> <instrumentation - android:name="android.support.test.runner.AndroidJUnitRunner" + android:name="android.testing.TestableInstrumentation" android:targetPackage="com.android.frameworks.tests.notification" android:label="Notification Tests" /> </manifest> diff --git a/tests/testables/src/android/testing/TestableInstrumentation.java b/tests/testables/src/android/testing/TestableInstrumentation.java new file mode 100644 index 000000000000..93fed859cf39 --- /dev/null +++ b/tests/testables/src/android/testing/TestableInstrumentation.java @@ -0,0 +1,181 @@ +/* + * 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 android.testing; + +import android.os.Bundle; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; +import android.os.TestLooperManager; +import android.support.test.runner.AndroidJUnitRunner; +import android.util.Log; + +import java.util.ArrayList; + +/** + * Wrapper around instrumentation that spins up a TestLooperManager around + * the main looper whenever a test is not using it to attempt to stop crashes + * from stopping other tests from running. + */ +public class TestableInstrumentation extends AndroidJUnitRunner { + + private static final String TAG = "TestableInstrumentation"; + + private static final int MAX_CRASHES = 5; + private static MainLooperManager sManager; + + @Override + public void onCreate(Bundle arguments) { + sManager = new MainLooperManager(); + Log.setWtfHandler((tag, what, system) -> { + if (system) { + Log.e(TAG, "WTF!!", what); + } else { + // These normally kill the app, but we don't want that in a test, instead we want + // it to throw. + throw new RuntimeException(what); + } + }); + super.onCreate(arguments); + } + + @Override + public void finish(int resultCode, Bundle results) { + sManager.destroy(); + super.finish(resultCode, results); + } + + public static void acquireMain() { + if (sManager != null) { + sManager.acquireMain(); + } + } + + public static void releaseMain() { + if (sManager != null) { + sManager.releaseMain(); + } + } + + public class MainLooperManager implements Runnable { + + private final ArrayList<Throwable> mExceptions = new ArrayList<>(); + private Message mStopMessage; + private final Handler mMainHandler; + private TestLooperManager mManager; + + public MainLooperManager() { + mMainHandler = new Handler(Looper.getMainLooper()); + startManaging(); + } + + @Override + public void run() { + try { + synchronized (this) { + // Let the thing starting us know we are up and ready to run. + notify(); + } + while (true) { + Message m = mManager.next(); + if (m == mStopMessage) { + mManager.recycle(m); + return; + } + try { + mManager.execute(m); + } catch (Throwable t) { + if (!checkStack(t) || (mExceptions.size() == MAX_CRASHES)) { + throw t; + } + mExceptions.add(t); + Log.d(TAG, "Ignoring exception to run more tests", t); + } + mManager.recycle(m); + } + } finally { + mManager.release(); + synchronized (this) { + // Let the caller know we are done managing the main thread. + notify(); + } + } + } + + private boolean checkStack(Throwable t) { + StackTraceElement topStack = t.getStackTrace()[0]; + String className = topStack.getClassName(); + if (className.equals(TestLooperManager.class.getName())) { + topStack = t.getCause().getStackTrace()[0]; + className = topStack.getClassName(); + } + // Only interested in blocking exceptions from the app itself, not from android + // framework. + return !className.startsWith("android.") + && !className.startsWith("com.android.internal"); + } + + public void destroy() { + mStopMessage.sendToTarget(); + if (mExceptions.size() != 0) { + throw new RuntimeException("Exception caught during tests", mExceptions.get(0)); + } + } + + public void acquireMain() { + synchronized (this) { + mStopMessage.sendToTarget(); + try { + wait(); + } catch (InterruptedException e) { + } + } + } + + public void releaseMain() { + startManaging(); + } + + private void startManaging() { + mStopMessage = mMainHandler.obtainMessage(); + synchronized (this) { + mManager = acquireLooperManager(Looper.getMainLooper()); + // This bit needs to happen on a background thread or it will hang if called + // from the same thread we are looking to block. + new Thread(() -> { + // Post a message to the main handler that will manage executing all future + // messages. + mMainHandler.post(this); + while (!mManager.hasMessages(mMainHandler, null, this)); + // Lastly run the message that executes this so it can manage the main thread. + Message next = mManager.next(); + // Run through messages until we reach ours. + while (next.getCallback() != this) { + mManager.execute(next); + mManager.recycle(next); + next = mManager.next(); + } + mManager.execute(next); + }).start(); + if (Looper.myLooper() != Looper.getMainLooper()) { + try { + wait(); + } catch (InterruptedException e) { + } + } + } + } + } +} diff --git a/tests/testables/src/android/testing/TestableLooper.java b/tests/testables/src/android/testing/TestableLooper.java index f6c3cb3ec498..f1a70921a469 100644 --- a/tests/testables/src/android/testing/TestableLooper.java +++ b/tests/testables/src/android/testing/TestableLooper.java @@ -29,7 +29,6 @@ import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; -import java.lang.reflect.Field; import java.util.Map; /** @@ -49,7 +48,7 @@ public class TestableLooper { private TestLooperManager mQueueWrapper; public TestableLooper(Looper l) throws Exception { - this(InstrumentationRegistry.getInstrumentation().acquireLooperManager(l), l); + this(acquireLooperManager(l), l); } private TestableLooper(TestLooperManager wrapper, Looper l) throws Exception { @@ -78,6 +77,9 @@ public class TestableLooper { */ public void destroy() throws NoSuchFieldException, IllegalAccessException { mQueueWrapper.release(); + if (mLooper == Looper.getMainLooper()) { + TestableInstrumentation.releaseMain(); + } } /** @@ -196,6 +198,13 @@ public class TestableLooper { } } + private static TestLooperManager acquireLooperManager(Looper l) { + if (l == Looper.getMainLooper()) { + TestableInstrumentation.acquireMain(); + } + return InstrumentationRegistry.getInstrumentation().acquireLooperManager(l); + } + private static final Map<Object, TestableLooper> sLoopers = new ArrayMap<>(); /** @@ -247,8 +256,7 @@ public class TestableLooper { } boolean set = mTestableLooper.mQueueWrapper == null; if (set) { - mTestableLooper.mQueueWrapper = InstrumentationRegistry.getInstrumentation() - .acquireLooperManager(mLooper); + mTestableLooper.mQueueWrapper = acquireLooperManager(mLooper); } try { Object[] ret = new Object[1]; @@ -283,6 +291,9 @@ public class TestableLooper { if (set) { mTestableLooper.mQueueWrapper.release(); mTestableLooper.mQueueWrapper = null; + if (mLooper == Looper.getMainLooper()) { + TestableInstrumentation.releaseMain(); + } } } } |