From 0a29e73ffbc066f551533d14597b713d23d2fdee Mon Sep 17 00:00:00 2001 From: Anushree Ganjam Date: Wed, 15 Jan 2025 17:17:21 -0800 Subject: [PATCH] Use RunListener to Clear inline mocks at the end of each test class. Inline mocks are leaking activity contexts and accumulation of these activity contexts led to OOM that resulted in test failure. See https://github.com/mockito/mockito/issues/1614 for details on mockito caused memory leaks This change works for both soong and gradle builds. Bug: 378520480 Test: atest and android studio builds Flag: TEST_ONLY Change-Id: I4a50993621ea416a02a41dd2f9c330d1599f065c --- .../LauncherSwipeHandlerV2TestCase.java | 2 + .../RecentsAnimationDeviceStateTest.kt | 72 ++++++++++--------- tests/AndroidManifest.xml | 4 +- .../launcher3/util/GlobalTestRunListener.java | 38 ++++++++++ 4 files changed, 83 insertions(+), 33 deletions(-) create mode 100644 tests/multivalentTests/src/com/android/launcher3/util/GlobalTestRunListener.java diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java index e6c5a6c4de..66c4ab5ce3 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/LauncherSwipeHandlerV2TestCase.java @@ -33,11 +33,13 @@ import com.android.launcher3.util.LauncherMultivalentJUnit; import com.android.quickstep.views.RecentsView; import org.junit.Before; +import org.junit.Ignore; import org.junit.runner.RunWith; import org.mockito.Mock; @SmallTest @RunWith(LauncherMultivalentJUnit.class) +@Ignore public class LauncherSwipeHandlerV2TestCase extends AbsSwipeUpHandlerTestCase< LauncherState, QuickstepLauncher, diff --git a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt index 80fbce7265..6cab71ab73 100644 --- a/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt +++ b/quickstep/tests/src/com/android/quickstep/RecentsAnimationDeviceStateTest.kt @@ -8,6 +8,8 @@ import com.android.launcher3.util.DisplayController.CHANGE_DENSITY import com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE import com.android.launcher3.util.DisplayController.CHANGE_ROTATION import com.android.launcher3.util.DisplayController.Info +import com.android.launcher3.util.Executors.MAIN_EXECUTOR +import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR import com.android.launcher3.util.NavigationMode import com.android.quickstep.util.GestureExclusionManager import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY @@ -22,6 +24,7 @@ import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SE import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED import com.google.common.truth.Truth.assertThat +import org.junit.After import org.junit.Before import org.junit.Test import org.junit.runner.RunWith @@ -50,6 +53,13 @@ class RecentsAnimationDeviceStateTest { underTest = RecentsAnimationDeviceState(context, exclusionManager) } + @After + fun tearDown() { + underTest.close() + UI_HELPER_EXECUTOR.submit {}.get() + MAIN_EXECUTOR.submit {}.get() + } + @Test fun registerExclusionListener_success() { underTest.registerExclusionListener() @@ -121,8 +131,8 @@ class RecentsAnimationDeviceStateTest { @Test fun trackpadGesturesNotAllowedForSelectedStates() { - val disablingStates = GESTURE_DISABLING_SYSUI_STATES + - SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED + val disablingStates = + GESTURE_DISABLING_SYSUI_STATES + SYSUI_STATE_TOUCHPAD_GESTURES_DISABLED allSysUiStates().forEach { state -> val canStartGesture = !disablingStates.contains(state) @@ -133,13 +143,13 @@ class RecentsAnimationDeviceStateTest { @Test fun trackpadGesturesNotAllowedIfHomeAndOverviewIsDisabled() { - val stateToExpectedResult = mapOf( - SYSUI_STATE_HOME_DISABLED to true, - SYSUI_STATE_OVERVIEW_DISABLED to true, - DEFAULT_STATE - .enable(SYSUI_STATE_OVERVIEW_DISABLED) - .enable(SYSUI_STATE_HOME_DISABLED) to false - ) + val stateToExpectedResult = + mapOf( + SYSUI_STATE_HOME_DISABLED to true, + SYSUI_STATE_OVERVIEW_DISABLED to true, + DEFAULT_STATE.enable(SYSUI_STATE_OVERVIEW_DISABLED) + .enable(SYSUI_STATE_HOME_DISABLED) to false, + ) stateToExpectedResult.forEach { (state, allowed) -> underTest.setSystemUiFlags(state) @@ -160,22 +170,19 @@ class RecentsAnimationDeviceStateTest { @Test fun systemGesturesNotAllowedWhenGestureStateDisabledAndNavBarVisible() { - val stateToExpectedResult = mapOf( - DEFAULT_STATE - .enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) - .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true, - DEFAULT_STATE - .enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) - .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to true, - DEFAULT_STATE - .disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) - .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true, - DEFAULT_STATE - .disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) - .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to false, - ) + val stateToExpectedResult = + mapOf( + DEFAULT_STATE.enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) + .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true, + DEFAULT_STATE.enable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) + .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to true, + DEFAULT_STATE.disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) + .disable(SYSUI_STATE_NAV_BAR_HIDDEN) to true, + DEFAULT_STATE.disable(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) + .enable(SYSUI_STATE_NAV_BAR_HIDDEN) to false, + ) - stateToExpectedResult.forEach {(state, gestureAllowed) -> + stateToExpectedResult.forEach { (state, gestureAllowed) -> underTest.setSystemUiFlags(state) assertThat(underTest.canStartSystemGesture()).isEqualTo(gestureAllowed) } @@ -187,14 +194,15 @@ class RecentsAnimationDeviceStateTest { } companion object { - private val GESTURE_DISABLING_SYSUI_STATES = listOf( - SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED, - SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING, - SYSUI_STATE_QUICK_SETTINGS_EXPANDED, - SYSUI_STATE_MAGNIFICATION_OVERLAP, - SYSUI_STATE_DEVICE_DREAMING, - SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION, - ) + private val GESTURE_DISABLING_SYSUI_STATES = + listOf( + SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED, + SYSUI_STATE_STATUS_BAR_KEYGUARD_SHOWING, + SYSUI_STATE_QUICK_SETTINGS_EXPANDED, + SYSUI_STATE_MAGNIFICATION_OVERLAP, + SYSUI_STATE_DEVICE_DREAMING, + SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION, + ) private const val SYSUI_STATES_COUNT = 33 private const val DEFAULT_STATE = 0L } diff --git a/tests/AndroidManifest.xml b/tests/AndroidManifest.xml index 5cf96c8554..862b862ab3 100644 --- a/tests/AndroidManifest.xml +++ b/tests/AndroidManifest.xml @@ -29,6 +29,8 @@ android:functionalTest="false" android:handleProfiling="false" android:name="androidx.test.runner.AndroidJUnitRunner" - android:targetPackage="com.android.launcher3" > + android:targetPackage="com.android.launcher3" > + diff --git a/tests/multivalentTests/src/com/android/launcher3/util/GlobalTestRunListener.java b/tests/multivalentTests/src/com/android/launcher3/util/GlobalTestRunListener.java new file mode 100644 index 0000000000..667f540340 --- /dev/null +++ b/tests/multivalentTests/src/com/android/launcher3/util/GlobalTestRunListener.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2025 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.launcher3.util; + +import org.junit.runner.Description; +import org.junit.runner.notification.RunListener; +import org.mockito.Mockito; + +public class GlobalTestRunListener extends RunListener { + /** + * See {@link RunListener#testFinished} which executes per atomic test. + * {@link RunListener#testSuiteFinished} which executes per test suite. Test suite = test class + * in this context. + * {@link RunListener#testRunFinished} which executes after everything (all test suites) is + * completed. + */ + @Override + public void testSuiteFinished(Description description) throws Exception { + // This method runs after every test class and will clear mocks after every test class + // execution is completed. + Mockito.framework().clearInlineMocks(); + super.testSuiteFinished(description); + } +}