diff options
author | felipeal <felipeal@google.com> | 2020-04-27 14:16:43 -0700 |
---|---|---|
committer | felipeal <felipeal@google.com> | 2020-04-28 17:11:00 -0700 |
commit | 7f731773c6520854171df90acbaa013e713d4a86 (patch) | |
tree | fecb68856ca53ee210e0fdcd75a8db917ab43e36 | |
parent | d8964ac0928b81af424cb8e4c10903bef66c7696 (diff) | |
download | Car-7f731773c6520854171df90acbaa013e713d4a86.tar.gz |
More improvements on android.car.test.utils package.
- Added more helpers to mock static methods on AbstractExtendMockitoTestCase.
- Refactored blocking UserLifeCycleListener into OneEventUserLifecycleListener.
- Moved custom ArgumentMatchers to CarArgumentMatchers.
- Moved common car-related mock calls to CarMockitoHelper.
Bug: 149099817
Test: atest \
CarUserManagerHelperTest InitialUserSetterTest \
UserHelperTest CarPowerManagementServiceTest \
UserHalServiceTest VendorServiceControllerTest \
CarUserManagerUnitTest CarUserNoticeServiceTest CarUserServiceTest
Change-Id: Ia2b9359d5b0a502d72e35eabbe8b2e487885e8d8
16 files changed, 345 insertions, 231 deletions
diff --git a/car-test-lib/Android.bp b/car-test-lib/Android.bp index e3dbfad869..965ea7bf8a 100644 --- a/car-test-lib/Android.bp +++ b/car-test-lib/Android.bp @@ -41,6 +41,7 @@ java_library { "src/android/car/test/**/*.java", ], libs: [ + "android.hardware.automotive.vehicle-V2.0-java", "mockito-target-extended", ], } diff --git a/car-test-lib/src/android/car/test/mocks/AbstractExtendMockitoTestCase.java b/car-test-lib/src/android/car/test/mocks/AbstractExtendMockitoTestCase.java index 12dc1ce13d..5efc29fa1b 100644 --- a/car-test-lib/src/android/car/test/mocks/AbstractExtendMockitoTestCase.java +++ b/car-test-lib/src/android/car/test/mocks/AbstractExtendMockitoTestCase.java @@ -21,6 +21,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSess import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.ActivityManager; +import android.os.UserManager; import android.util.Log; import com.android.dx.mockito.inline.extended.StaticMockitoSessionBuilder; @@ -110,6 +111,20 @@ public abstract class AbstractExtendMockitoTestCase { doReturn(userId).when(() -> ActivityManager.getCurrentUser()); } + /** + * Mocks a call to {@link UserManager#isHeadlessSystemUserMode()}. + * + * @param mode result of such call + * + * @throws IllegalStateException if class didn't override {@link #newSessionBuilder()} and + * called {@code spyStatic(UserManager.class)} on the session passed to it. + */ + protected final void mockIsHeadlessSystemUserMode(boolean mode) { + if (VERBOSE) Log.v(TAG, getLogPrefix() + "mockIsHeadlessSystemUserMode(" + mode + ")"); + assertSpied(UserManager.class); + doReturn(mode).when(() -> UserManager.isHeadlessSystemUserMode()); + } + @NonNull private MockitoSessionBuilder newSessionBuilder() { StaticMockitoSessionBuilder builder = mockitoSession() @@ -149,6 +164,9 @@ public abstract class AbstractExtendMockitoTestCase { mStaticMockedClasses = staticMockedClasses; } + // TODO(b/148403316): this is only used to mock Settings.Global / Settings.Secure, and using + // spy on such occurrence doesn't work - hopefully we can get rid of this method by + // refactoring how Settings are mocked. /** * Same as {@link StaticMockitoSessionBuilder#mockStatic(Class)}. */ diff --git a/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java b/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java new file mode 100644 index 0000000000..62328c0554 --- /dev/null +++ b/car-test-lib/src/android/car/test/mocks/CarArgumentMatchers.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2020 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.car.test.mocks; + +import static org.mockito.ArgumentMatchers.argThat; + +import android.annotation.Nullable; +import android.annotation.UserIdInt; +import android.content.pm.UserInfo; +import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; +import android.os.UserHandle; +import android.util.Log; + +import org.mockito.ArgumentMatcher; + +import java.util.Arrays; + +/** + * Provides custom mockito matcher for Android / Car objects. + * + */ +public final class CarArgumentMatchers { + + private static final String TAG = CarArgumentMatchers.class.getSimpleName(); + + /** + * Matches if a {@link UserInfo} has the given {@code userId}. + */ + public static UserInfo isUserInfo(@UserIdInt int userId) { + return argThat(new UserInfoMatcher(userId)); + } + + /** + * Matches if a {@link UserHandle} has the given {@code userId}. + */ + public static UserHandle isUserHandle(@UserIdInt int userId) { + return argThat(new UserHandleMatcher(userId)); + } + + /** + * Matches if a {@link VehiclePropValue} has the given {@code prop}. + */ + public static VehiclePropValue isProperty(int prop) { + return argThat(new PropertyIdMatcher(prop)); + } + + /** + * Matches if a {@link VehiclePropValue} has the given {@code prop} and {@code int32} values. + */ + public static VehiclePropValue isPropertyWithValues(int prop, int...values) { + return argThat(new PropertyIdMatcher(prop, values)); + } + + private static class UserInfoMatcher implements ArgumentMatcher<UserInfo> { + + public final @UserIdInt int userId; + + private UserInfoMatcher(@UserIdInt int userId) { + this.userId = userId; + } + + @Override + public boolean matches(@Nullable UserInfo argument) { + if (argument == null) { + Log.w(TAG, "isUserInfo(): null argument"); + return false; + } + if (argument.id != userId) { + Log.w(TAG, "isUserInfo(): argument mismatch (expected " + userId + + ", got " + argument.id); + return false; + } + return true; + } + + @Override + public String toString() { + return "isUserInfo(userId=" + userId + ")"; + } + } + + private static class UserHandleMatcher implements ArgumentMatcher<UserHandle> { + + public final @UserIdInt int userId; + + private UserHandleMatcher(@UserIdInt int userId) { + this.userId = userId; + } + + @Override + public boolean matches(UserHandle argument) { + if (argument == null) { + Log.w(TAG, "isUserHandle(): null argument"); + return false; + } + if (argument.getIdentifier() != userId) { + Log.w(TAG, "isUserHandle(): argument mismatch (expected " + userId + + ", got " + argument.getIdentifier()); + return false; + } + return true; + } + + @Override + public String toString() { + return "isUserHandle(userId=" + userId + ")"; + } + } + + private static class PropertyIdMatcher implements ArgumentMatcher<VehiclePropValue> { + + final int mProp; + private final int[] mValues; + + private PropertyIdMatcher(int prop) { + this(prop, null); + } + + private PropertyIdMatcher(int prop, int[] values) { + mProp = prop; + mValues = values; + } + + @Override + public boolean matches(VehiclePropValue argument) { + Log.v(TAG, "PropertyIdMatcher: argument=" + argument); + if (argument.prop != mProp) { + Log.w(TAG, "PropertyIdMatcher: Invalid prop on " + argument); + return false; + } + if (mValues == null) return true; + // Make sure values match + if (mValues.length != argument.value.int32Values.size()) { + Log.w(TAG, "PropertyIdMatcher: number of values (expected " + mValues.length + + ") mismatch on " + argument); + return false; + } + + for (int i = 0; i < mValues.length; i++) { + if (mValues[i] != argument.value.int32Values.get(i)) { + Log.w(TAG, "PropertyIdMatcher: value mismatch at index " + i + " on " + argument + + ": expected " + Arrays.toString(mValues)); + return false; + } + } + return true; + } + } + + private CarArgumentMatchers() { + throw new UnsupportedOperationException("contains only static methods"); + } +} diff --git a/car-test-lib/src/android/car/testapi/CarMockitoHelper.java b/car-test-lib/src/android/car/testapi/CarMockitoHelper.java new file mode 100644 index 0000000000..d69a0f8ea4 --- /dev/null +++ b/car-test-lib/src/android/car/testapi/CarMockitoHelper.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 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.car.testapi; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.isA; +import static org.mockito.Mockito.doAnswer; + +import android.annotation.NonNull; +import android.car.Car; +import android.os.RemoteException; + +/** + * Provides common Mockito calls for Car-specific classes. + */ +public final class CarMockitoHelper { + + /** + * Mocks a call to {@link Car#handleRemoteExceptionFromCarService(RemoteException, Object)} so + * it returns the passed as 2nd argument. + */ + public static void mockHandleRemoteExceptionFromCarServiceWithDefaultValue( + @NonNull Car car) { + doAnswer((invocation) -> { + return invocation.getArguments()[1]; + }).when(car).handleRemoteExceptionFromCarService(isA(RemoteException.class), any()); + } + + private CarMockitoHelper() { + throw new UnsupportedOperationException("contains only static methods"); + } +} diff --git a/car-test-lib/src/android/car/testapi/OneEventUserLifecycleListener.java b/car-test-lib/src/android/car/testapi/OneEventUserLifecycleListener.java new file mode 100644 index 0000000000..40af9a6866 --- /dev/null +++ b/car-test-lib/src/android/car/testapi/OneEventUserLifecycleListener.java @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2020 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.car.testapi; + +import android.annotation.Nullable; +import android.car.user.CarUserManager.UserLifecycleEvent; +import android.car.user.CarUserManager.UserLifecycleListener; +import android.util.Log; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; + +/** + * UserLifecycleListener that blocks until the event is received. + * + * <p>It should be used in cases where just one event is expected. + */ +public final class OneEventUserLifecycleListener implements UserLifecycleListener { + + private static final String TAG = OneEventUserLifecycleListener.class.getSimpleName(); + + private static final long USER_LIFECYCLE_EVENT_TIMEOUT_MS = 2_000; + + private final CountDownLatch mLatch = new CountDownLatch(1); + + @Nullable + private UserLifecycleEvent mReceivedEvent; + + private final long mTimeoutMs; + + /** + * Constructor with default timeout of {@value #USER_LIFECYCLE_EVENT_TIMEOUT_MS}. + */ + public OneEventUserLifecycleListener() { + this(USER_LIFECYCLE_EVENT_TIMEOUT_MS); + } + + /** + * Constructor with custom timeout. + * + * @param timeoutMs how long to wait (in milliseconds) when calling {@link #waitForEvent()}. + */ + public OneEventUserLifecycleListener(long timeoutMs) { + this.mTimeoutMs = timeoutMs; + } + + @Override + public void onEvent(UserLifecycleEvent event) { + this.mReceivedEvent = event; + mLatch.countDown(); + } + + /** + * Blocks until {@link #onEvent(UserLifecycleEvent)} is invoked. + * + * @throws IllegalStateException if it times out before {@code onEvent()} is called. + * @throws InterruptedException if interrupted before {@code onEvent()} is called. + */ + @Nullable + public UserLifecycleEvent waitForEvent() throws InterruptedException { + if (!mLatch.await(mTimeoutMs, TimeUnit.MILLISECONDS)) { + String errorMessage = "onEvent() not called in " + mTimeoutMs + " seconds"; + Log.e(TAG, errorMessage); + throw new IllegalStateException(errorMessage); + } + return mReceivedEvent; + } +} diff --git a/tests/carservice_unit_test/Android.mk b/tests/carservice_unit_test/Android.mk index f45323e5f5..1033f41a2b 100644 --- a/tests/carservice_unit_test/Android.mk +++ b/tests/carservice_unit_test/Android.mk @@ -51,6 +51,7 @@ LOCAL_JAVA_LIBRARIES := \ EncryptionRunner LOCAL_STATIC_JAVA_LIBRARIES := \ + android.car.testapi \ android.car.test.utils \ androidx.test.core \ androidx.test.ext.junit \ diff --git a/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java b/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java index 755aa3867c..2603f2a852 100644 --- a/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java +++ b/tests/carservice_unit_test/src/android/car/userlib/CarUserManagerHelperTest.java @@ -16,8 +16,6 @@ package android.car.userlib; -import static android.car.userlib.InitialUserSetterTest.setHeadlessSystemUserMode; - import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; @@ -293,7 +291,7 @@ public class CarUserManagerHelperTest extends AbstractExtendMockitoTestCase { @Test public void testHasInitialUser_onlyHeadlessSystemUser() { - setHeadlessSystemUserMode(true); + mockIsHeadlessSystemUserMode(true); mockGetUsers(mSystemUser); assertThat(mCarUserManagerHelper.hasInitialUser()).isFalse(); @@ -301,7 +299,7 @@ public class CarUserManagerHelperTest extends AbstractExtendMockitoTestCase { @Test public void testHasInitialUser_onlyNonHeadlessSystemUser() { - setHeadlessSystemUserMode(false); + mockIsHeadlessSystemUserMode(false); mockGetUsers(mSystemUser); assertThat(mCarUserManagerHelper.hasInitialUser()).isTrue(); @@ -309,7 +307,7 @@ public class CarUserManagerHelperTest extends AbstractExtendMockitoTestCase { @Test public void testHasInitialUser_hasNormalUser() { - setHeadlessSystemUserMode(true); + mockIsHeadlessSystemUserMode(true); UserInfo normalUser = createUserInfoForId(10); mockGetUsers(mSystemUser, normalUser); @@ -318,7 +316,7 @@ public class CarUserManagerHelperTest extends AbstractExtendMockitoTestCase { @Test public void testHasInitialUser_hasOnlyWorkProfile() { - setHeadlessSystemUserMode(true); + mockIsHeadlessSystemUserMode(true); UserInfo workProfile = createUserInfoForId(10); workProfile.userType = UserManager.USER_TYPE_PROFILE_MANAGED; assertThat(workProfile.isManagedProfile()).isTrue(); // Sanity check diff --git a/tests/carservice_unit_test/src/android/car/userlib/InitialUserSetterTest.java b/tests/carservice_unit_test/src/android/car/userlib/InitialUserSetterTest.java index 02d5a4a68b..d3dff42eae 100644 --- a/tests/carservice_unit_test/src/android/car/userlib/InitialUserSetterTest.java +++ b/tests/carservice_unit_test/src/android/car/userlib/InitialUserSetterTest.java @@ -15,6 +15,8 @@ */ package android.car.userlib; +import static android.car.test.mocks.CarArgumentMatchers.isUserInfo; + import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.google.common.truth.Truth.assertThat; @@ -23,7 +25,6 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.never; @@ -49,7 +50,6 @@ import com.android.internal.widget.LockPatternUtils; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentMatcher; import org.mockito.Mock; import java.util.function.Consumer; @@ -567,7 +567,7 @@ public final class InitialUserSetterTest extends AbstractExtendMockitoTestCase { @Test public void testStartForegroundUser_nonHeadlessSystemUser() throws Exception { - setHeadlessSystemUserMode(false); + mockIsHeadlessSystemUserMode(false); expectAmStartFgUser(UserHandle.USER_SYSTEM); assertThat(mSetter.startForegroundUser(UserHandle.USER_SYSTEM)).isTrue(); @@ -575,7 +575,7 @@ public final class InitialUserSetterTest extends AbstractExtendMockitoTestCase { @Test public void testStartForegroundUser_headlessSystemUser() throws Exception { - setHeadlessSystemUserMode(true); + mockIsHeadlessSystemUserMode(true); assertThat(mSetter.startForegroundUser(UserHandle.USER_SYSTEM)).isFalse(); @@ -761,10 +761,6 @@ public final class InitialUserSetterTest extends AbstractExtendMockitoTestCase { // TODO(b/149099817): move stuff below (and some from above) to common testing code - public static void setHeadlessSystemUserMode(boolean mode) { - doReturn(mode).when(() -> UserManager.isHeadlessSystemUserMode()); - } - @NonNull public static UserInfo newSecondaryUser(@UserIdInt int userId) { UserInfo userInfo = new UserInfo(); @@ -783,31 +779,4 @@ public final class InitialUserSetterTest extends AbstractExtendMockitoTestCase { } return userInfo; } - - /** - * Custom Mockito matcher to check if a {@link UserInfo} has the given {@code userId}. - */ - public static UserInfo isUserInfo(@UserIdInt int userId) { - return argThat(new UserInfoMatcher(userId)); - } - - private static class UserInfoMatcher implements ArgumentMatcher<UserInfo> { - - public final @UserIdInt int userId; - - private UserInfoMatcher(@UserIdInt int userId) { - this.userId = userId; - } - - @Override - public boolean matches(@Nullable UserInfo argument) { - return argument != null && argument.id == userId; - } - - @Override - public String toString() { - return "UserInfo(userId=" + userId + ")"; - } - } - } diff --git a/tests/carservice_unit_test/src/android/car/userlib/UserHelperTest.java b/tests/carservice_unit_test/src/android/car/userlib/UserHelperTest.java index 29f1b08519..e50dd2fd32 100644 --- a/tests/carservice_unit_test/src/android/car/userlib/UserHelperTest.java +++ b/tests/carservice_unit_test/src/android/car/userlib/UserHelperTest.java @@ -16,8 +16,6 @@ package android.car.userlib; -import static android.car.userlib.InitialUserSetterTest.setHeadlessSystemUserMode; - import static com.google.common.truth.Truth.assertThat; import android.car.test.mocks.AbstractExtendMockitoTestCase; @@ -44,25 +42,25 @@ public final class UserHelperTest extends AbstractExtendMockitoTestCase { @Test public void testIsHeadlessSystemUser_system_headlessMode() { - setHeadlessSystemUserMode(true); + mockIsHeadlessSystemUserMode(true); assertThat(UserHelper.isHeadlessSystemUser(UserHandle.USER_SYSTEM)).isTrue(); } @Test public void testIsHeadlessSystemUser_system_nonHeadlessMode() { - setHeadlessSystemUserMode(false); + mockIsHeadlessSystemUserMode(false); assertThat(UserHelper.isHeadlessSystemUser(UserHandle.USER_SYSTEM)).isFalse(); } @Test public void testIsHeadlessSystemUser_nonSystem_headlessMode() { - setHeadlessSystemUserMode(true); + mockIsHeadlessSystemUserMode(true); assertThat(UserHelper.isHeadlessSystemUser(10)).isFalse(); } @Test public void testIsHeadlessSystemUser_nonSystem_nonHeadlessMode() { - setHeadlessSystemUserMode(false); + mockIsHeadlessSystemUserMode(false); assertThat(UserHelper.isHeadlessSystemUser(10)).isFalse(); } } diff --git a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java index 625e472da5..0beba1bcc1 100644 --- a/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java +++ b/tests/carservice_unit_test/src/com/android/car/CarPowerManagementServiceTest.java @@ -16,7 +16,7 @@ package com.android.car; -import static android.car.userlib.InitialUserSetterTest.isUserInfo; +import static android.car.test.mocks.CarArgumentMatchers.isUserInfo; import static android.car.userlib.InitialUserSetterTest.newGuestUser; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doAnswer; @@ -878,7 +878,6 @@ public class CarPowerManagementServiceTest extends AbstractExtendMockitoTestCase int value(); } - // TODO(b/149099817): move to common code private interface Visitor<T> { void visit(T t); } diff --git a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java index d48bcd3392..877c3f3275 100644 --- a/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java +++ b/tests/carservice_unit_test/src/com/android/car/hal/UserHalServiceTest.java @@ -19,6 +19,8 @@ import static android.car.VehiclePropertyIds.CURRENT_GEAR; import static android.car.VehiclePropertyIds.INITIAL_USER_INFO; import static android.car.VehiclePropertyIds.SWITCH_USER; import static android.car.VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION; +import static android.car.test.mocks.CarArgumentMatchers.isProperty; +import static android.car.test.mocks.CarArgumentMatchers.isPropertyWithValues; import static android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType.COLD_BOOT; import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_1; import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.KEY_FOB; @@ -28,7 +30,6 @@ import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.verify; @@ -63,7 +64,6 @@ import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; -import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; @@ -827,61 +827,6 @@ public final class UserHalServiceTest { // TODO(b/149099817): move stuff below to common code /** - * Custom Mockito matcher to check if a {@link VehiclePropValue} has the given {@code prop}. - */ - public static VehiclePropValue isProperty(int prop) { - return argThat(new PropertyIdMatcher(prop)); - } - - /** - * Custom Mockito matcher to check if a {@link VehiclePropValue} has the given {@code prop} and - * {@code int32} values. - */ - public static VehiclePropValue isPropertyWithValues(int prop, int...values) { - return argThat(new PropertyIdMatcher(prop, values)); - } - - private static class PropertyIdMatcher implements ArgumentMatcher<VehiclePropValue> { - - final int mProp; - private final int[] mValues; - - private PropertyIdMatcher(int prop) { - this(prop, null); - } - - private PropertyIdMatcher(int prop, int[] values) { - mProp = prop; - mValues = values; - } - - @Override - public boolean matches(VehiclePropValue argument) { - Log.v(TAG, "PropertyIdMatcher: argument=" + argument); - if (argument.prop != mProp) { - Log.w(TAG, "PropertyIdMatcher: Invalid prop on " + argument); - return false; - } - if (mValues == null) return true; - // Make sure values match - if (mValues.length != argument.value.int32Values.size()) { - Log.w(TAG, "PropertyIdMatcher: number of values (expected " + mValues.length - + ") mismatch on " + argument); - return false; - } - - for (int i = 0; i < mValues.length; i++) { - if (mValues[i] != argument.value.int32Values.get(i)) { - Log.w(TAG, "PropertyIdMatcher: value mismatch at index " + i + " on " + argument - + ": expected " + Arrays.toString(mValues)); - return false; - } - } - return true; - } - } - - /** * Creates an empty config for the given property. */ private static VehiclePropConfig newConfig(int prop) { diff --git a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java index 2fc5ccc336..f4bbad3956 100644 --- a/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java +++ b/tests/carservice_unit_test/src/com/android/car/pm/VendorServiceControllerTest.java @@ -16,20 +16,20 @@ package com.android.car.pm; +import static android.car.test.mocks.CarArgumentMatchers.isUserHandle; + import static com.google.common.truth.Truth.assertThat; import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.fail; -import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.Mockito.when; import android.annotation.UserIdInt; import android.app.ActivityManager; import android.car.test.mocks.AbstractExtendMockitoTestCase; +import android.car.testapi.OneEventUserLifecycleListener; import android.car.user.CarUserManager; -import android.car.user.CarUserManager.UserLifecycleEvent; import android.car.user.CarUserManager.UserLifecycleEventType; -import android.car.user.CarUserManager.UserLifecycleListener; import android.car.userlib.CarUserManagerHelper; import android.content.ComponentName; import android.content.Context; @@ -44,7 +44,6 @@ import android.os.UserHandle; import android.os.UserManager; import android.util.Log; -import androidx.annotation.Nullable; import androidx.test.core.app.ApplicationProvider; import com.android.car.CarLocalServices; @@ -56,7 +55,6 @@ import com.android.internal.util.Preconditions; import org.junit.After; import org.junit.Before; import org.junit.Test; -import org.mockito.ArgumentMatcher; import org.mockito.Mock; import org.mockito.Mockito; @@ -197,7 +195,7 @@ public final class VendorServiceControllerTest extends AbstractExtendMockitoTest } private void mockUserUnlock(@UserIdInt int userId) { - when(mUserManager.isUserUnlockingOrUnlocked(isUser(userId))).thenReturn(true); + when(mUserManager.isUserUnlockingOrUnlocked(isUserHandle(userId))).thenReturn(true); when(mUserManager.isUserUnlockingOrUnlocked(userId)).thenReturn(true); } @@ -213,7 +211,7 @@ public final class VendorServiceControllerTest extends AbstractExtendMockitoTest @UserIdInt int userId) throws InterruptedException { // Adding a blocking listener to ensure CarUserService event notification is completed // before proceeding with test execution. - BlockingUserLifecycleListener blockingListener = new BlockingUserLifecycleListener(); + OneEventUserLifecycleListener blockingListener = new OneEventUserLifecycleListener(); mCarUserService.addUserLifecycleListener(blockingListener); runOnMainThreadAndWaitForIdle(() -> mCarUserService.onUserLifecycleEvent(eventType, @@ -342,63 +340,4 @@ public final class VendorServiceControllerTest extends AbstractExtendMockitoTest return super.getSystemService(name); } } - - // TODO(b/149099817): move stuff below to common code - - /** - * Custom Mockito matcher to check if a {@link UserHandle} has the given {@code userId}. - */ - public static UserHandle isUser(@UserIdInt int userId) { - return argThat(new UserHandleMatcher(userId)); - } - - private static class UserHandleMatcher implements ArgumentMatcher<UserHandle> { - - public final @UserIdInt int userId; - - private UserHandleMatcher(@UserIdInt int userId) { - this.userId = userId; - } - - @Override - public boolean matches(UserHandle argument) { - return argument != null && argument.getIdentifier() == userId; - } - } - - /** - * CarUserService now notifies listener in its own handler thread. This wrapper is used to - * block test thread until listener is notified. - */ - // TODO(b/149099817): Move this class to a common place - private static final class BlockingUserLifecycleListener implements UserLifecycleListener { - - public static final int USER_LIFECYCLE_LISTENER_ON_EVENT_TIMEOUT_SECONDS = 2; - - private final CountDownLatch mLatch = new CountDownLatch(1); - - @Nullable - private UserLifecycleEvent mReceivedEvent; - - @Override - public void onEvent(UserLifecycleEvent event) { - this.mReceivedEvent = event; - mLatch.countDown(); - } - - /** - * Blocks until onEvent is invoked. - */ - @Nullable - public UserLifecycleEvent waitForEvent() throws InterruptedException { - if (!mLatch.await(USER_LIFECYCLE_LISTENER_ON_EVENT_TIMEOUT_SECONDS, - TimeUnit.SECONDS)) { - String errorMessage = "mUserLifecycleListenerWrapper.onEvent not called in " - + USER_LIFECYCLE_LISTENER_ON_EVENT_TIMEOUT_SECONDS + " seconds"; - Log.e(TAG, errorMessage); - fail(errorMessage); - } - return mReceivedEvent; - } - } } diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java index c78ff4878b..5a702b61aa 100644 --- a/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java +++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserManagerUnitTest.java @@ -15,16 +15,13 @@ */ package com.android.car.user; +import static android.car.testapi.CarMockitoHelper.mockHandleRemoteExceptionFromCarServiceWithDefaultValue; import static android.os.UserHandle.USER_SYSTEM; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; - import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.ArgumentMatchers.isA; import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doThrow; @@ -79,7 +76,7 @@ public final class CarUserManagerUnitTest extends AbstractExtendMockitoTestCase @Test public void testIsValidUser_headlessSystemUser() { - setHeadlessSystemUserMode(true); + mockIsHeadlessSystemUserMode(true); setExistingUsers(USER_SYSTEM); assertThat(mMgr.isValidUser(USER_SYSTEM)).isFalse(); @@ -87,7 +84,7 @@ public final class CarUserManagerUnitTest extends AbstractExtendMockitoTestCase @Test public void testIsValidUser_nonHeadlessSystemUser() { - setHeadlessSystemUserMode(false); + mockIsHeadlessSystemUserMode(false); setExistingUsers(USER_SYSTEM); assertThat(mMgr.isValidUser(USER_SYSTEM)).isTrue(); @@ -130,7 +127,7 @@ public final class CarUserManagerUnitTest extends AbstractExtendMockitoTestCase @Test public void testSwitchUser_remoteException() throws Exception { expectServiceSwitchUserSucceeds(11); - expectCarHandleExceptionReturnsDefaultValue(); + mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); AndroidFuture<UserSwitchResult> future = mMgr.switchUser(11); @@ -184,14 +181,4 @@ public final class CarUserManagerUnitTest extends AbstractExtendMockitoTestCase user.id = userId; return user; } - - private static void setHeadlessSystemUserMode(boolean mode) { - doReturn(mode).when(() -> UserManager.isHeadlessSystemUserMode()); - } - - private void expectCarHandleExceptionReturnsDefaultValue() { - doAnswer((invocation) -> { - return invocation.getArguments()[1]; - }).when(mCar).handleRemoteExceptionFromCarService(isA(RemoteException.class), any()); - } } diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java index 09c6deb7eb..695db41c69 100644 --- a/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java +++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserNoticeServiceTest.java @@ -101,7 +101,7 @@ public class CarUserNoticeServiceTest extends AbstractExtendMockitoTestCase { @Override protected void onSessionBuilder(CustomMockitoSessionBuilder session) { session - .mockStatic(CarLocalServices.class) + .spyStatic(CarLocalServices.class) .mockStatic(Settings.Secure.class); } @@ -113,7 +113,6 @@ public class CarUserNoticeServiceTest extends AbstractExtendMockitoTestCase { doReturn(mCarPowerManager).when(() -> CarLocalServices.createCarPowerManager(mMockContext)); doReturn(mMockCarPowerManagementService) .when(() -> CarLocalServices.getService(CarPowerManagementService.class)); - doReturn(mCarPowerManager).when(() -> CarLocalServices.createCarPowerManager(mMockContext)); doReturn(mMockCarUserService) .when(() -> CarLocalServices.getService(CarUserService.class)); @@ -251,7 +250,7 @@ public class CarUserNoticeServiceTest extends AbstractExtendMockitoTestCase { return latch; } - private CountDownLatch mockKeySettings(String key, int value) { + private static CountDownLatch mockKeySettings(String key, int value) { CountDownLatch latch = new CountDownLatch(1); when(Settings.Secure.getIntForUser(any(), eq(key), anyInt(), diff --git a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java index 70024b0ca1..f2052b1445 100644 --- a/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java +++ b/tests/carservice_unit_test/src/com/android/car/user/CarUserServiceTest.java @@ -27,7 +27,6 @@ import static com.google.common.truth.Truth.assertWithMessage; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; @@ -51,6 +50,7 @@ import android.car.CarOccupantZoneManager.OccupantTypeEnum; import android.car.CarOccupantZoneManager.OccupantZoneInfo; import android.car.settings.CarSettings; import android.car.test.mocks.AbstractExtendMockitoTestCase; +import android.car.testapi.OneEventUserLifecycleListener; import android.car.user.CarUserManager; import android.car.user.CarUserManager.UserLifecycleEvent; import android.car.user.CarUserManager.UserLifecycleEventType; @@ -132,8 +132,8 @@ public final class CarUserServiceTest extends AbstractExtendMockitoTestCase { @Mock private Resources mMockedResources; @Mock private Drawable mMockedDrawable; - private final BlockingUserLifecycleListener mUserLifecycleListener = - new BlockingUserLifecycleListener(); + private final OneEventUserLifecycleListener mUserLifecycleListener = + new OneEventUserLifecycleListener(); @Captor private ArgumentCaptor<UsersInfo> mUsersInfoCaptor; @@ -1508,40 +1508,4 @@ public final class CarUserServiceTest extends AbstractExtendMockitoTestCase { return mResultData; } } - - /** - * CarUserService now notifies listener in its own handler thread. This wrapper is used to - * block test thread until listener is notified. - */ - // TODO(b/149099817): Move this class to a common place - private static final class BlockingUserLifecycleListener implements UserLifecycleListener { - - public static final int USER_LIFECYCLE_LISTENER_ON_EVENT_TIMEOUT_SECONDS = 2; - - private final CountDownLatch mLatch = new CountDownLatch(1); - - @Nullable - private UserLifecycleEvent mReceivedEvent; - - @Override - public void onEvent(UserLifecycleEvent event) { - this.mReceivedEvent = event; - mLatch.countDown(); - } - - /** - * Blocks until onEvent is invoked. - */ - @Nullable - public UserLifecycleEvent waitForEvent() throws InterruptedException { - if (!mLatch.await(USER_LIFECYCLE_LISTENER_ON_EVENT_TIMEOUT_SECONDS, - TimeUnit.SECONDS)) { - String errorMessage = "mUserLifecycleListenerWrapper.onEvent not called in " - + USER_LIFECYCLE_LISTENER_ON_EVENT_TIMEOUT_SECONDS + " seconds"; - Log.e(TAG, errorMessage); - fail(errorMessage); - } - return mReceivedEvent; - } - } } diff --git a/tests/common_utils/Android.mk b/tests/common_utils/Android.mk index 19302c6033..57f40e5f80 100644 --- a/tests/common_utils/Android.mk +++ b/tests/common_utils/Android.mk @@ -23,4 +23,7 @@ LOCAL_MODULE_TAGS := optional LOCAL_SRC_FILES := $(call all-java-files-under, src) +LOCAL_STATIC_JAVA_LIBRARIES := \ + mockito-target-extended \ + include $(BUILD_STATIC_JAVA_LIBRARY) |