From 7d97bad8bf9e4b37129f484aea9384de99beb235 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 22 Feb 2023 09:34:23 -0800 Subject: [PATCH] Refactored ExtendedMockitoTestCase into ExtendedMockitoRule ExtendedMockitoTestCase was created mostly for session management (to make sure tests properly closed the session and to clear some internal mockito state that could cause OOM), but to be really effective, all classes would have to extend it. Given that constraint - and the fact that there is already a rule to facilitate session management - this CL gets rid of that super class and provide another rule instead (which's built on top of the existing one). Also fixed CpuInfoReaderTest, which was using %d instead of %s on assertWithMessage() and replace those calls by expectWithMessage()). Bug: Test: atest \ FrameworksMockingServicesTests:AlarmManagerServiceTest \ FrameworksMockingServicesTests:ActivityManagerServiceInjectorTest \ FrameworksMockingServicesTests:BroadcastQueueModernImplTest \ FrameworksMockingServicesTests:CachedAppOptimizerTest \ FrameworksMockingServicesTests:CpuInfoReaderTest \ FrameworksMockingServicesTests:CpuMonitorServiceTest \ FrameworksMockingServicesTests:UserManagerServiceTest \ FrameworksMockingServicesTests:UserVisibilityMediatorMUMDTest \ FrameworksMockingServicesTests:UserVisibilityMediatorMUPANDTest \ FrameworksMockingServicesTests:UserVisibilityMediatorSUSDTest Bug: 268515318 Change-Id: I59f3ee693cbad01e9289cf069b7d039840f7c811 --- .../android/server/ExpectableTestCase.java | 181 +++++++++++++ .../android/server/ExtendedMockitoRule.java | 183 +++++++++++++ .../server/ExtendedMockitoTestCase.java | 249 ------------------ .../src/com/android/server/Visitor.java | 23 ++ .../server/alarm/AlarmManagerServiceTest.java | 28 +- .../ActivityManagerServiceInjectorTest.java | 14 +- .../am/BroadcastQueueModernImplTest.java | 20 +- .../server/am/CachedAppOptimizerTest.java | 14 +- .../android/server/cpu/CpuInfoReaderTest.java | 8 +- .../server/cpu/CpuMonitorServiceTest.java | 14 +- .../server/pm/UserManagerServiceTest.java | 21 +- .../pm/UserVisibilityMediatorMUPANDTest.java | 5 +- .../pm/UserVisibilityMediatorTestCase.java | 7 +- 13 files changed, 446 insertions(+), 321 deletions(-) create mode 100644 services/tests/mockingservicestests/src/com/android/server/ExpectableTestCase.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoRule.java delete mode 100644 services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoTestCase.java create mode 100644 services/tests/mockingservicestests/src/com/android/server/Visitor.java diff --git a/services/tests/mockingservicestests/src/com/android/server/ExpectableTestCase.java b/services/tests/mockingservicestests/src/com/android/server/ExpectableTestCase.java new file mode 100644 index 0000000000000..a329f5a144770 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/ExpectableTestCase.java @@ -0,0 +1,181 @@ +/* + * 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 com.android.server; + +import com.google.common.annotations.GwtIncompatible; +import com.google.common.base.Optional; +import com.google.common.collect.Multimap; +import com.google.common.collect.Multiset; +import com.google.common.collect.Table; +import com.google.common.truth.BigDecimalSubject; +import com.google.common.truth.BooleanSubject; +import com.google.common.truth.ClassSubject; +import com.google.common.truth.ComparableSubject; +import com.google.common.truth.DoubleSubject; +import com.google.common.truth.Expect; +import com.google.common.truth.FloatSubject; +import com.google.common.truth.GuavaOptionalSubject; +import com.google.common.truth.IntegerSubject; +import com.google.common.truth.IterableSubject; +import com.google.common.truth.LongSubject; +import com.google.common.truth.MapSubject; +import com.google.common.truth.MultimapSubject; +import com.google.common.truth.MultisetSubject; +import com.google.common.truth.ObjectArraySubject; +import com.google.common.truth.PrimitiveBooleanArraySubject; +import com.google.common.truth.PrimitiveByteArraySubject; +import com.google.common.truth.PrimitiveCharArraySubject; +import com.google.common.truth.PrimitiveDoubleArraySubject; +import com.google.common.truth.PrimitiveFloatArraySubject; +import com.google.common.truth.PrimitiveIntArraySubject; +import com.google.common.truth.PrimitiveLongArraySubject; +import com.google.common.truth.PrimitiveShortArraySubject; +import com.google.common.truth.StandardSubjectBuilder; +import com.google.common.truth.StringSubject; +import com.google.common.truth.Subject; +import com.google.common.truth.TableSubject; +import com.google.common.truth.ThrowableSubject; + +import org.junit.Rule; + +import java.math.BigDecimal; +import java.util.Map; + +// NOTE: it could be a more generic AbstractTruthTestCase that provide similar methods +// for assertThat() / assertWithMessage(), but then we'd need to remove all static import imports +// from classes that indirectly extend it. +/** + * Base class to make it easier to use {@code Truth} {@link Expect} assertions. + */ +public abstract class ExpectableTestCase { + + @Rule + public final Expect mExpect = Expect.create(); + + protected final StandardSubjectBuilder expectWithMessage(String msg) { + return mExpect.withMessage(msg); + } + + protected final StandardSubjectBuilder expectWithMessage(String format, Object...args) { + return mExpect.withMessage(format, args); + } + + protected final > ComparableSubject expectThat( + ComparableT actual) { + return mExpect.that(actual); + } + + protected final BigDecimalSubject expectThat(BigDecimal actual) { + return mExpect.that(actual); + } + + protected final Subject expectThat(Object actual) { + return mExpect.that(actual); + } + + @GwtIncompatible("ClassSubject.java") + protected final ClassSubject expectThat(Class actual) { + return mExpect.that(actual); + } + + protected final ThrowableSubject expectThat(Throwable actual) { + return mExpect.that(actual); + } + + protected final LongSubject expectThat(Long actual) { + return mExpect.that(actual); + } + + protected final DoubleSubject expectThat(Double actual) { + return mExpect.that(actual); + } + + protected final FloatSubject expectThat(Float actual) { + return mExpect.that(actual); + } + + protected final IntegerSubject expectThat(Integer actual) { + return mExpect.that(actual); + } + + protected final BooleanSubject expectThat(Boolean actual) { + return mExpect.that(actual); + } + + protected final StringSubject expectThat(String actual) { + return mExpect.that(actual); + } + + protected final IterableSubject expectThat(Iterable actual) { + return mExpect.that(actual); + } + + protected final ObjectArraySubject expectThat(T[] actual) { + return mExpect.that(actual); + } + + protected final PrimitiveBooleanArraySubject expectThat(boolean[] actual) { + return mExpect.that(actual); + } + + protected final PrimitiveShortArraySubject expectThat(short[] actual) { + return mExpect.that(actual); + } + + protected final PrimitiveIntArraySubject expectThat(int[] actual) { + return mExpect.that(actual); + } + + protected final PrimitiveLongArraySubject expectThat(long[] actual) { + return mExpect.that(actual); + } + + protected final PrimitiveCharArraySubject expectThat(char[] actual) { + return mExpect.that(actual); + } + + protected final PrimitiveByteArraySubject expectThat(byte[] actual) { + return mExpect.that(actual); + } + + protected final PrimitiveFloatArraySubject expectThat(float[] actual) { + return mExpect.that(actual); + } + + protected final PrimitiveDoubleArraySubject expectThat(double[] actual) { + return mExpect.that(actual); + } + + protected final GuavaOptionalSubject expectThat(Optional actual) { + return mExpect.that(actual); + } + + protected final MapSubject expectThat(Map actual) { + return mExpect.that(actual); + } + + protected final MultimapSubject expectThat(Multimap actual) { + return mExpect.that(actual); + } + + protected final MultisetSubject expectThat(Multiset actual) { + return mExpect.that(actual); + } + + protected final TableSubject expectThat(Table actual) { + return mExpect.that(actual); + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoRule.java b/services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoRule.java new file mode 100644 index 0000000000000..881dd504428d6 --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoRule.java @@ -0,0 +1,183 @@ +/* + * 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 com.android.server; + +import android.annotation.Nullable; +import android.util.Log; + +import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; +import com.android.internal.util.Preconditions; +import com.android.modules.utils.testing.StaticMockFixture; +import com.android.modules.utils.testing.StaticMockFixtureRule; + +import org.mockito.Mockito; +import org.mockito.quality.Strictness; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +/** + * Rule to make it easier to use Extended Mockito. + * + *

It's derived from {@link StaticMockFixtureRule}, with the additional features: + * + *

    + *
  • Easier to define which classes must be statically mocked or spied + *
  • Automatically starts mocking (so tests don't need a mockito runner or rule) + *
  • Automatically clears the inlined mocks at the end (to avoid OOM) + *
  • Allows other customization like strictness + *
+ */ +public final class ExtendedMockitoRule extends StaticMockFixtureRule { + + private static final String TAG = ExtendedMockitoRule.class.getSimpleName(); + + private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); + + private final Object mTestClassInstance; + private final Strictness mStrictness; + + private ExtendedMockitoRule(Builder builder) { + super(() -> new SimpleStatickMockFixture(builder.mMockedStaticClasses, + builder.mSpiedStaticClasses, builder.mDynamicSessionBuilderConfigurator, + builder.mAfterSessionFinishedCallback)); + mTestClassInstance = builder.mTestClassInstance; + mStrictness = builder.mStrictness; + if (VERBOSE) { + Log.v(TAG, "strictness=" + mStrictness + ", testClassInstance" + mTestClassInstance + + ", mockedStaticClasses=" + builder.mMockedStaticClasses + + ", spiedStaticClasses=" + builder.mSpiedStaticClasses + + ", dynamicSessionBuilderConfigurator=" + + builder.mDynamicSessionBuilderConfigurator + + ", afterSessionFinishedCallback=" + builder.mAfterSessionFinishedCallback); + } + } + + @Override + public StaticMockitoSessionBuilder getSessionBuilder() { + StaticMockitoSessionBuilder sessionBuilder = super.getSessionBuilder(); + if (mStrictness != null) { + if (VERBOSE) { + Log.v(TAG, "Setting strictness to " + mStrictness + " on " + sessionBuilder); + } + sessionBuilder.strictness(mStrictness); + } + return sessionBuilder.initMocks(mTestClassInstance); + } + + public static final class Builder { + private final Object mTestClassInstance; + private @Nullable Strictness mStrictness; + private final List> mMockedStaticClasses = new ArrayList<>(); + private final List> mSpiedStaticClasses = new ArrayList<>(); + private @Nullable Visitor mDynamicSessionBuilderConfigurator; + private @Nullable Runnable mAfterSessionFinishedCallback; + + public Builder(Object testClassInstance) { + mTestClassInstance = Objects.requireNonNull(testClassInstance); + } + + public Builder setStrictness(Strictness strictness) { + mStrictness = Objects.requireNonNull(strictness); + return this; + } + + public Builder mockStatic(Class clazz) { + Objects.requireNonNull(clazz); + Preconditions.checkState(!mMockedStaticClasses.contains(clazz), + "class %s already mocked", clazz); + mMockedStaticClasses.add(clazz); + return this; + } + + public Builder spyStatic(Class clazz) { + Objects.requireNonNull(clazz); + Preconditions.checkState(!mSpiedStaticClasses.contains(clazz), + "class %s already spied", clazz); + mSpiedStaticClasses.add(clazz); + return this; + } + + public Builder dynamiclyConfigureSessionBuilder( + Visitor dynamicSessionBuilderConfigurator) { + mDynamicSessionBuilderConfigurator = Objects + .requireNonNull(dynamicSessionBuilderConfigurator); + return this; + } + + public Builder afterSessionFinished(Runnable runnable) { + mAfterSessionFinishedCallback = Objects.requireNonNull(runnable); + return this; + } + + public ExtendedMockitoRule build() { + return new ExtendedMockitoRule(this); + } + } + + private static final class SimpleStatickMockFixture implements StaticMockFixture { + + private final List> mMockedStaticClasses; + private final List> mSpiedStaticClasses; + @Nullable + private final Visitor mDynamicSessionBuilderConfigurator; + @Nullable + private final Runnable mAfterSessionFinishedCallback; + + private SimpleStatickMockFixture(List> mockedStaticClasses, + List> spiedStaticClasses, + @Nullable Visitor dynamicSessionBuilderConfigurator, + @Nullable Runnable afterSessionFinishedCallback) { + mMockedStaticClasses = mockedStaticClasses; + mSpiedStaticClasses = spiedStaticClasses; + mDynamicSessionBuilderConfigurator = dynamicSessionBuilderConfigurator; + mAfterSessionFinishedCallback = afterSessionFinishedCallback; + } + + @Override + public StaticMockitoSessionBuilder setUpMockedClasses( + StaticMockitoSessionBuilder sessionBuilder) { + mMockedStaticClasses.forEach((c) -> sessionBuilder.mockStatic(c)); + mSpiedStaticClasses.forEach((c) -> sessionBuilder.spyStatic(c)); + if (mDynamicSessionBuilderConfigurator != null) { + mDynamicSessionBuilderConfigurator.visit(sessionBuilder); + } + return sessionBuilder; + } + + @Override + public void setUpMockBehaviors() { + } + + @Override + public void tearDown() { + try { + if (mAfterSessionFinishedCallback != null) { + mAfterSessionFinishedCallback.run(); + } + } finally { + if (VERBOSE) { + Log.v(TAG, "calling Mockito.framework().clearInlineMocks()"); + } + // When using inline mock maker, clean up inline mocks to prevent OutOfMemory + // errors. See https://github.com/mockito/mockito/issues/1614 and b/259280359. + Mockito.framework().clearInlineMocks(); + } + } + } +} diff --git a/services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoTestCase.java b/services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoTestCase.java deleted file mode 100644 index 48483a14a8a03..0000000000000 --- a/services/tests/mockingservicestests/src/com/android/server/ExtendedMockitoTestCase.java +++ /dev/null @@ -1,249 +0,0 @@ -/* - * 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. - */ -package com.android.server; - -import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; - -import android.annotation.Nullable; -import android.util.Log; - -import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; - -import com.google.common.truth.Expect; -import com.google.common.truth.StandardSubjectBuilder; - -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.rules.RuleChain; -import org.mockito.Mockito; -import org.mockito.MockitoSession; -import org.mockito.quality.Strictness; - -import java.lang.reflect.Constructor; - -/** - * Base class to make it easier to write tests that uses {@code ExtendedMockito}. - * - */ -public abstract class ExtendedMockitoTestCase { - - private static final String TAG = ExtendedMockitoTestCase.class.getSimpleName(); - - private static final boolean VERBOSE = Log.isLoggable(TAG, Log.VERBOSE); - - /** - * Number of invocations, used to force a failure on {@link #forceFailure(int, Class, String)}. - */ - private static int sInvocationsCounter; - - /** - * Sessions follow the "Highlander Rule": There can be only one! - * - *

So, we keep track of that and force-close it if needed. - */ - @Nullable - private static MockitoSession sHighlanderSession; - - /** - * Points to where the current session was created. - */ - private static Exception sSessionCreationLocation; - - private MockitoSession mSession; - - protected final Expect mExpect = Expect.create(); - protected final DumpableDumperRule mDumpableDumperRule = new DumpableDumperRule(); - - @Rule - public final RuleChain mTwoRingsOfPowerAndOneChainToRuleThemAll = RuleChain - .outerRule(mDumpableDumperRule) - .around(mExpect); - - public ExtendedMockitoTestCase() { - sInvocationsCounter++; - } - - @Before - public final void startSession() { - if (VERBOSE) { - Log.v(TAG, "startSession() for " + getTestName() + " on thread " - + Thread.currentThread() + "; sHighlanderSession=" + sHighlanderSession); - } - createSessionLocation(); - finishHighlanderSessionIfNeeded("startSession()"); - StaticMockitoSessionBuilder builder = mockitoSession() - .initMocks(this) - .strictness(getSessionStrictness()); - initializeSession(builder); - sHighlanderSession = mSession = builder.startMocking(); - } - - private void createSessionLocation() { - try { - sSessionCreationLocation = new Exception(getTestName()); - } catch (Exception e) { - // Better safe than sorry... - Log.e(TAG, "Could not create sSessionCreationLocation with " + getTestName() - + " on thread " + Thread.currentThread(), e); - sSessionCreationLocation = e; - } - } - - /** - * Gets the session strictness. - * - * @return {@link Strictness.LENIENT} by default; subclasses can override. - */ - protected Strictness getSessionStrictness() { - return Strictness.LENIENT; - } - - /** - * Initializes the mockito session. - * - *

Typically used to define which classes should have static methods mocked or spied. - */ - protected void initializeSession(StaticMockitoSessionBuilder builder) { - if (VERBOSE) { - Log.v(TAG, "initializeSession()"); - } - } - - @After - public final void finishSession() throws Exception { - if (false) { // For obvious reasons, should NEVER be merged as true - forceFailure(1, RuntimeException.class, "to simulate an unfinished session"); - } - - // mSession.finishMocking() must ALWAYS be called (hence the over-protective try/finally - // statements), otherwise it would cause failures on future tests as mockito - // cannot start a session when a previous one is not finished - try { - if (VERBOSE) { - Log.v(TAG, "finishSession() for " + getTestName() + " on thread " - + Thread.currentThread() + "; sHighlanderSession=" + sHighlanderSession); - - } - } finally { - sHighlanderSession = null; - finishSessionMocking(); - afterSessionFinished(); - } - } - - /** - * Called after the mockito session was finished - * - *

This method should be used by subclasses that MUST do their cleanup after the session is - * finished (as methods marked with {@link After} in the subclasses would be called BEFORE - * that). - */ - protected void afterSessionFinished() { - if (VERBOSE) { - Log.v(TAG, "afterSessionFinished()"); - } - } - - private void finishSessionMocking() { - if (mSession == null) { - Log.w(TAG, getClass().getSimpleName() + ".finishSession(): no session"); - return; - } - try { - mSession.finishMocking(); - } finally { - // Shouldn't need to set mSession to null as JUnit always instantiate a new object, - // but it doesn't hurt.... - mSession = null; - // When using inline mock maker, clean up inline mocks to prevent OutOfMemory - // errors. See https://github.com/mockito/mockito/issues/1614 and b/259280359. - Mockito.framework().clearInlineMocks(); - } - } - - private void finishHighlanderSessionIfNeeded(String where) { - if (sHighlanderSession == null) { - if (VERBOSE) { - Log.v(TAG, "finishHighlanderSessionIfNeeded(): sHighlanderSession already null"); - } - return; - } - - if (sSessionCreationLocation != null) { - if (VERBOSE) { - Log.e(TAG, where + ": There can be only one! Closing unfinished session, " - + "created at", sSessionCreationLocation); - } else { - Log.e(TAG, where + ": There can be only one! Closing unfinished session, " - + "created at " + sSessionCreationLocation); - } - } else { - Log.e(TAG, where + ": There can be only one! Closing unfinished session created at " - + "unknown location"); - } - try { - sHighlanderSession.finishMocking(); - } catch (Throwable t) { - if (VERBOSE) { - Log.e(TAG, "Failed to close unfinished session on " + getTestName(), t); - } else { - Log.e(TAG, "Failed to close unfinished session on " + getTestName() + ": " + t); - } - } finally { - if (VERBOSE) { - Log.v(TAG, "Resetting sHighlanderSession at finishHighlanderSessionIfNeeded()"); - } - sHighlanderSession = null; - } - } - - /** - * Forces a failure at the given invocation of a test method by throwing an exception. - */ - protected final void forceFailure(int invocationCount, - Class failureClass, String reason) throws T { - if (sInvocationsCounter != invocationCount) { - Log.d(TAG, "forceFailure(" + invocationCount + "): no-op on invocation #" - + sInvocationsCounter); - return; - } - String message = "Throwing on invocation #" + sInvocationsCounter + ": " + reason; - Log.e(TAG, message); - T throwable; - try { - Constructor constructor = failureClass.getConstructor(String.class); - throwable = constructor.newInstance("Throwing on invocation #" + sInvocationsCounter - + ": " + reason); - } catch (Exception e) { - throw new IllegalArgumentException("Could not create exception of class " + failureClass - + " using msg='" + message + "' as constructor"); - } - throw throwable; - } - - protected final @Nullable String getTestName() { - return mDumpableDumperRule.getTestName(); - } - - protected final StandardSubjectBuilder expectWithMessage(String msg) { - return mExpect.withMessage(msg); - } - - protected final StandardSubjectBuilder expectWithMessage(String format, Object...args) { - return mExpect.withMessage(format, args); - } -} diff --git a/services/tests/mockingservicestests/src/com/android/server/Visitor.java b/services/tests/mockingservicestests/src/com/android/server/Visitor.java new file mode 100644 index 0000000000000..447910eba60ba --- /dev/null +++ b/services/tests/mockingservicestests/src/com/android/server/Visitor.java @@ -0,0 +1,23 @@ +/* + * 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 com.android.server; + +/** + * Generic visitor. + */ +public interface Visitor { + void visit(V visitee); +} diff --git a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java index 9dd2f82ad59b8..b395f42478b15 100644 --- a/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/alarm/AlarmManagerServiceTest.java @@ -159,7 +159,6 @@ import android.util.SparseArray; import androidx.test.runner.AndroidJUnit4; import com.android.dx.mockito.inline.extended.MockedVoidMethod; -import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.internal.annotations.GuardedBy; import com.android.internal.app.IAppOpsCallback; import com.android.internal.app.IAppOpsService; @@ -168,7 +167,7 @@ import com.android.server.AlarmManagerInternal; import com.android.server.AppStateTracker; import com.android.server.AppStateTrackerImpl; import com.android.server.DeviceIdleInternal; -import com.android.server.ExtendedMockitoTestCase; +import com.android.server.ExtendedMockitoRule; import com.android.server.LocalServices; import com.android.server.SystemClockTime.TimeConfidence; import com.android.server.SystemService; @@ -182,6 +181,7 @@ import com.android.server.usage.AppStandbyInternal; import libcore.util.EmptyArray; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Answers; @@ -204,7 +204,7 @@ import java.util.function.LongConsumer; @Presubmit @SuppressWarnings("GuardedBy") // This test enforces synchronous behavior. @RunWith(AndroidJUnit4.class) -public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase { +public final class AlarmManagerServiceTest { private static final String TAG = AlarmManagerServiceTest.class.getSimpleName(); private static final int SYSTEM_UI_UID = 12345; private static final int TEST_CALLING_USER = UserHandle.getUserId(TEST_CALLING_UID); @@ -411,14 +411,9 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase { } } - @Override - protected Strictness getSessionStrictness() { - return Strictness.WARN; - } - - @Override - protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) + .setStrictness(Strictness.WARN) .spyStatic(ActivityManager.class) .mockStatic(CompatChanges.class) .spyStatic(DateFormat.class) @@ -431,8 +426,10 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase { .mockStatic(ServiceManager.class) .mockStatic(Settings.Global.class) .mockStatic(SystemProperties.class) - .spyStatic(UserHandle.class); - } + .spyStatic(UserHandle.class) + .afterSessionFinished( + () -> LocalServices.removeServiceForTest(AlarmManagerInternal.class)) + .build(); @Before public final void setUp() { @@ -3805,9 +3802,4 @@ public final class AlarmManagerServiceTest extends ExtendedMockitoTestCase { mListener.removeListenerAlarmsForCachedUid(TEST_CALLING_UID_2); assertEquals(2, mService.mAlarmsPerUid.get(TEST_CALLING_UID_2)); } - - @Override - public void afterSessionFinished() { - LocalServices.removeServiceForTest(AlarmManagerInternal.class); - } } diff --git a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceInjectorTest.java b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceInjectorTest.java index e01a9a9d473ab..9ceb5e7b018dc 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceInjectorTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/ActivityManagerServiceInjectorTest.java @@ -31,11 +31,11 @@ import android.os.UserManager; import android.util.Log; import android.view.Display; -import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; -import com.android.server.ExtendedMockitoTestCase; +import com.android.server.ExtendedMockitoRule; import com.android.server.am.ActivityManagerService.Injector; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; @@ -45,7 +45,7 @@ import java.util.Arrays; * Run as {@code atest * FrameworksMockingServicesTests:com.android.server.am.ActivityManagerServiceInjectorTest} */ -public final class ActivityManagerServiceInjectorTest extends ExtendedMockitoTestCase { +public final class ActivityManagerServiceInjectorTest { private static final String TAG = ActivityManagerServiceInjectorTest.class.getSimpleName(); @@ -63,10 +63,10 @@ public final class ActivityManagerServiceInjectorTest extends ExtendedMockitoTes when(mContext.getSystemService(DisplayManager.class)).thenReturn(mDisplayManager); } - @Override - protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.spyStatic(UserManager.class); - } + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) + .spyStatic(UserManager.class) + .build(); @Test public void testGetDisplayIdsForStartingBackgroundUsers_notSupported() { diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java index dcdee37059a97..95c2ed2f841fa 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueModernImplTest.java @@ -78,18 +78,15 @@ import android.util.Pair; import androidx.test.filters.SmallTest; -import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.internal.util.FrameworkStatsLog; -import com.android.server.ExtendedMockitoTestCase; +import com.android.server.ExtendedMockitoRule; import com.android.server.am.BroadcastQueueTest.SyncBarrier; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; -import org.mockito.junit.MockitoJUnitRunner; import java.io.ByteArrayOutputStream; import java.io.PrintWriter; @@ -98,8 +95,7 @@ import java.util.ArrayList; import java.util.List; @SmallTest -@RunWith(MockitoJUnitRunner.class) -public class BroadcastQueueModernImplTest extends ExtendedMockitoTestCase { +public final class BroadcastQueueModernImplTest { private static final int TEST_UID = android.os.Process.FIRST_APPLICATION_UID; private static final int TEST_UID2 = android.os.Process.FIRST_APPLICATION_UID + 1; @@ -118,15 +114,13 @@ public class BroadcastQueueModernImplTest extends ExtendedMockitoTestCase { BroadcastProcessQueue mHead; - @Override - protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.spyStatic(FrameworkStatsLog.class); - } + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) + .spyStatic(FrameworkStatsLog.class) + .build(); @Before public void setUp() throws Exception { - MockitoAnnotations.initMocks(this); - mHandlerThread = new HandlerThread(getClass().getSimpleName()); mHandlerThread.start(); diff --git a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java index f8cfdf131a28d..ec9e5b50579c2 100644 --- a/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/am/CachedAppOptimizerTest.java @@ -40,9 +40,8 @@ import android.text.TextUtils; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.modules.utils.testing.TestableDeviceConfig; -import com.android.server.ExtendedMockitoTestCase; +import com.android.server.ExtendedMockitoRule; import com.android.server.LocalServices; import com.android.server.ServiceThread; import com.android.server.appop.AppOpsService; @@ -69,7 +68,7 @@ import java.util.concurrent.TimeUnit; * atest FrameworksMockingServicesTests:CachedAppOptimizerTest */ @Presubmit -public final class CachedAppOptimizerTest extends ExtendedMockitoTestCase { +public final class CachedAppOptimizerTest { private ServiceThread mThread; @@ -93,10 +92,11 @@ public final class CachedAppOptimizerTest extends ExtendedMockitoTestCase { public final ApplicationExitInfoTest.ServiceThreadRule mServiceThreadRule = new ApplicationExitInfoTest.ServiceThreadRule(); - @Override - protected void initializeSession(StaticMockitoSessionBuilder builder) { - mDeviceConfig.setUpMockedClasses(builder); - } + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) + .dynamiclyConfigureSessionBuilder( + sessionBuilder -> mDeviceConfig.setUpMockedClasses(sessionBuilder)) + .build(); @Before public void setUp() { diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java index 9f3bc3358a4c1..b214787533010 100644 --- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuInfoReaderTest.java @@ -29,7 +29,7 @@ import android.content.res.AssetManager; import android.util.Log; import android.util.SparseArray; -import com.android.server.ExtendedMockitoTestCase; +import com.android.server.ExpectableTestCase; import libcore.io.Streams; @@ -44,7 +44,7 @@ import java.io.OutputStream; import java.util.Objects; /** This class contains unit tests for the {@link CpuInfoReader}. */ -public final class CpuInfoReaderTest extends ExtendedMockitoTestCase { +public final class CpuInfoReaderTest extends ExpectableTestCase { private static final String TAG = CpuInfoReaderTest.class.getSimpleName(); private static final String ROOT_DIR_NAME = "CpuInfoReaderTest"; private static final String VALID_CPUSET_DIR = "valid_cpuset"; @@ -426,7 +426,7 @@ public final class CpuInfoReaderTest extends ExtendedMockitoTestCase { .isNull(); } - private static void compareCpuInfos(String message, + private void compareCpuInfos(String message, SparseArray expected, SparseArray actual) { assertWithMessage("%s. Total CPU infos", message).that(actual.size()) @@ -435,7 +435,7 @@ public final class CpuInfoReaderTest extends ExtendedMockitoTestCase { int cpuCoreId = expected.keyAt(i); CpuInfoReader.CpuInfo expectedCpuInfo = expected.valueAt(i); CpuInfoReader.CpuInfo actualCpuInfo = actual.get(cpuCoreId); - assertWithMessage("%s. Core %d's CPU info", message, cpuCoreId).that(actualCpuInfo) + expectWithMessage("%s. Core %s's CPU info", message, cpuCoreId).that(actualCpuInfo) .isEqualTo(expectedCpuInfo); } } diff --git a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java index 7ab1363b5087e..49a2cc6967442 100644 --- a/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/cpu/CpuMonitorServiceTest.java @@ -32,16 +32,16 @@ import android.os.HandlerExecutor; import android.os.Looper; import android.os.ServiceManager; -import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; -import com.android.server.ExtendedMockitoTestCase; +import com.android.server.ExtendedMockitoRule; import com.android.server.LocalServices; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; -public final class CpuMonitorServiceTest extends ExtendedMockitoTestCase { +public final class CpuMonitorServiceTest { private static final CpuAvailabilityMonitoringConfig TEST_CPU_AVAILABILITY_MONITORING_CONFIG = new CpuAvailabilityMonitoringConfig.Builder(CPUSET_ALL) .addThreshold(30).addThreshold(70).build(); @@ -56,10 +56,10 @@ public final class CpuMonitorServiceTest extends ExtendedMockitoTestCase { private HandlerExecutor mHandlerExecutor; private CpuMonitorInternal mLocalService; - @Override - protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder.mockStatic(ServiceManager.class); - } + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) + .mockStatic(ServiceManager.class) + .build(); @Before public void setUp() { diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java index 1ed2f789d9b22..564893c3c6292 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserManagerServiceTest.java @@ -40,9 +40,8 @@ import android.util.SparseArray; import androidx.test.annotation.UiThreadTest; -import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; import com.android.internal.widget.LockSettingsInternal; -import com.android.server.ExtendedMockitoTestCase; +import com.android.server.ExtendedMockitoRule; import com.android.server.LocalServices; import com.android.server.am.UserState; import com.android.server.pm.UserManagerService.UserData; @@ -50,13 +49,14 @@ import com.android.server.storage.DeviceStorageMonitorInternal; import org.junit.After; import org.junit.Before; +import org.junit.Rule; import org.junit.Test; import org.mockito.Mock; /** * Run as {@code atest FrameworksMockingServicesTests:com.android.server.pm.UserManagerServiceTest} */ -public final class UserManagerServiceTest extends ExtendedMockitoTestCase { +public final class UserManagerServiceTest { private static final String TAG = UserManagerServiceTest.class.getSimpleName(); @@ -84,6 +84,13 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { */ private static final int PROFILE_USER_ID = 643; + @Rule + public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(this) + .spyStatic(UserManager.class) + .spyStatic(LocalServices.class) + .mockStatic(Settings.Global.class) + .build(); + private final Object mPackagesLock = new Object(); private final Context mRealContext = androidx.test.InstrumentationRegistry.getInstrumentation() .getTargetContext(); @@ -109,14 +116,6 @@ public final class UserManagerServiceTest extends ExtendedMockitoTestCase { */ private UserManagerInternal mUmi; - @Override - protected void initializeSession(StaticMockitoSessionBuilder builder) { - builder - .spyStatic(UserManager.class) - .spyStatic(LocalServices.class) - .mockStatic(Settings.Global.class); - } - @Before @UiThreadTest // Needed to initialize main handler public void setFixtures() { diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java index 38cf6341e798b..9aa53db6fe1be 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java @@ -20,8 +20,6 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_FAILURE; -import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_ALREADY_VISIBLE; -import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE; import static com.android.server.pm.UserManagerInternal.USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE; import static com.android.server.pm.UserVisibilityChangedEvent.onInvisible; import static com.android.server.pm.UserVisibilityChangedEvent.onVisible; @@ -128,7 +126,8 @@ public final class UserVisibilityMediatorMUPANDTest listener.verify(); } - /* TODO: re-add + + /* TODO(b/261538337): re-add after the reverted CL is merged again @Test public void diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java index 5176d684ace68..1bf921c503d85 100644 --- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java +++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java @@ -45,7 +45,8 @@ import android.util.IntArray; import android.util.Log; import com.android.internal.util.Preconditions; -import com.android.server.ExtendedMockitoTestCase; +import com.android.server.DumpableDumperRule; +import com.android.server.ExpectableTestCase; import org.junit.Before; import org.junit.Test; @@ -64,7 +65,7 @@ import java.util.Arrays; * is visible, display associated to the user, etc...) for each scenario (full user started on fg, * profile user started on bg, etc...). */ -abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { +abstract class UserVisibilityMediatorTestCase extends ExpectableTestCase { private static final String TAG = UserVisibilityMediatorTestCase.class.getSimpleName(); @@ -125,6 +126,8 @@ abstract class UserVisibilityMediatorTestCase extends ExtendedMockitoTestCase { mBackgroundUserOnDefaultDisplayAllowed = backgroundUserOnDefaultDisplayAllowed; } + protected final DumpableDumperRule mDumpableDumperRule = new DumpableDumperRule(); + @Before public final void setFixtures() { mHandler = Handler.getMain();