/* * 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.user; import static android.car.test.mock.CarMockitoHelper.mockHandleRemoteExceptionFromCarServiceWithDefaultValue; import static android.car.test.util.CarTestingHelper.getResult; import static android.os.UserHandle.SYSTEM; import static android.os.UserHandle.USER_SYSTEM; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.ArgumentMatchers.notNull; import static org.mockito.ArgumentMatchers.same; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.car.ICarUserService; import android.car.SyncResultCallback; import android.car.test.AbstractExpectableTestCase; import android.car.test.util.UserTestingHelper; import android.car.user.CarUserManager.UserHandleSwitchUiCallback; import android.car.user.CarUserManager.UserLifecycleListener; import android.car.user.CarUserManager.UserSwitchUiCallback; import android.car.util.concurrent.AndroidFuture; import android.car.util.concurrent.AsyncFuture; import android.content.Context; import android.content.pm.UserInfo; import android.content.pm.UserInfo.UserInfoFlag; import android.hardware.automotive.vehicle.UserIdentificationAssociationSetValue; import android.hardware.automotive.vehicle.UserIdentificationAssociationType; import android.hardware.automotive.vehicle.UserIdentificationAssociationValue; import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.platform.test.ravenwood.RavenwoodRule; import com.android.car.internal.ICarBase; import com.android.car.internal.ResultCallbackImpl; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import java.util.Arrays; import java.util.List; import java.util.stream.Collectors; @RunWith(MockitoJUnitRunner.class) public final class CarUserManagerUnitTest extends AbstractExpectableTestCase { // Need to a rule to setup host implementation for SystemProperties.get which is used inside // CarSystemProperties.getUserHalTimeout() during CarUserManager initialization. @Rule public final RavenwoodRule mRavenwood = new RavenwoodRule.Builder() .setSystemPropertyImmutable("android.car.user_hal_timeout", "") // AndroidFuture uses getMainHandler .setProvideMainThread(true) .build(); @Mock private ICarBase mCar; @Mock private UserManager mUserManager; @Mock private ICarUserService mService; @Mock private Context mMockContext; private CarUserManager mMgr; @Before public void setFixtures() { mMgr = new CarUserManager(mCar, mService, mUserManager, /* isHeadlessSystemUserMode= */ true); when(mCar.getContext()).thenReturn(mMockContext); } @Test public void testUserIdentificationAssociationType() { assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_KEY_FOB) .isEqualTo(UserIdentificationAssociationType.KEY_FOB); assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_1) .isEqualTo(UserIdentificationAssociationType.CUSTOM_1); assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_2) .isEqualTo(UserIdentificationAssociationType.CUSTOM_2); assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_3) .isEqualTo(UserIdentificationAssociationType.CUSTOM_3); assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_TYPE_CUSTOM_4) .isEqualTo(UserIdentificationAssociationType.CUSTOM_4); } @Test public void testUserIdentificationAssociationSetValue() { assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_ASSOCIATE_CURRENT_USER) .isEqualTo(UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER); assertThat( CarUserManager.USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_CURRENT_USER) .isEqualTo(UserIdentificationAssociationSetValue.DISASSOCIATE_CURRENT_USER); assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_SET_VALUE_DISASSOCIATE_ALL_USERS) .isEqualTo(UserIdentificationAssociationSetValue.DISASSOCIATE_ALL_USERS); } @Test public void testUserIdentificationAssociationValue() { assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_VALUE_UNKNOWN) .isEqualTo(UserIdentificationAssociationValue.UNKNOWN); assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATE_CURRENT_USER) .isEqualTo(UserIdentificationAssociationValue.ASSOCIATED_CURRENT_USER); assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_VALUE_ASSOCIATED_ANOTHER_USER) .isEqualTo(UserIdentificationAssociationValue.ASSOCIATED_ANOTHER_USER); assertThat(CarUserManager.USER_IDENTIFICATION_ASSOCIATION_VALUE_NOT_ASSOCIATED_ANY_USER) .isEqualTo(UserIdentificationAssociationValue.NOT_ASSOCIATED_ANY_USER); } @Test public void testIsValidUserId_headlessSystemUser() { setExistingUsers(USER_SYSTEM); assertThat(mMgr.isValidUser(USER_SYSTEM)).isFalse(); } @Test public void testIsValidUser_headlessSystemUser() { setExistingUsers(USER_SYSTEM); assertThat(mMgr.isValidUser(SYSTEM)).isFalse(); } @Test public void testIsValidUserId_nonHeadlessSystemUser() { mockIsHeadlessSystemUserMode(false); setExistingUsers(USER_SYSTEM); assertThat(mMgr.isValidUser(USER_SYSTEM)).isTrue(); } @Test public void testIsValidUser_nonHeadlessSystemUser() { mockIsHeadlessSystemUserMode(false); setExistingUsers(USER_SYSTEM); assertThat(mMgr.isValidUser(SYSTEM)).isTrue(); } @Test public void testIsValidUserId_found() { setExistingUsers(1, 2, 3); expectThat(mMgr.isValidUser(1)).isTrue(); expectThat(mMgr.isValidUser(2)).isTrue(); expectThat(mMgr.isValidUser(3)).isTrue(); } @Test public void testIsValidUser_found() { setExistingUsers(1, 2, 3); expectThat(mMgr.isValidUser(UserHandle.of(1))).isTrue(); expectThat(mMgr.isValidUser(UserHandle.of(2))).isTrue(); expectThat(mMgr.isValidUser(UserHandle.of(3))).isTrue(); } @Test public void testIsValidUserId_notFound() { setExistingUsers(1, 2, 3); assertThat(mMgr.isValidUser(4)).isFalse(); } @Test public void testIsValidUser_notFound() { setExistingUsers(1, 2, 3); assertThat(mMgr.isValidUser(UserHandle.of(4))).isFalse(); } @Test public void testIsValidUserId_emptyUsers() { assertThat(mMgr.isValidUser(666)).isFalse(); } @Test public void testIsValidUser_emptyUsers() { assertThat(mMgr.isValidUser(UserHandle.of(666))).isFalse(); } @Test public void testAddListener_nullExecutor() { assertThrows(NullPointerException.class, () -> mMgr.addListener(null, (e) -> { })); } @Test public void testAddListener_nullListener() { assertThrows(NullPointerException.class, () -> mMgr.addListener(Runnable::run, null)); } @Test public void testAddListener_nullFilter() { assertThrows(NullPointerException.class, () -> mMgr.addListener(Runnable::run, /* filter= */null, (e) -> {})); } @Test public void testAddListener_sameListenerAddedTwice() { UserLifecycleListener listener = (e) -> { }; mMgr.addListener(Runnable::run, listener); assertThrows(IllegalStateException.class, () -> mMgr.addListener(Runnable::run, listener)); } @Test public void testAddListener_differentListenersAddedTwice() throws Exception { mMgr.addListener(Runnable::run, (e) -> { }); mMgr.addListener(Runnable::run, (e) -> { }); verify(mService, times(2)).setLifecycleListenerForApp(any(), isNull(), any()); } @Test public void testAddListener_differentListenersWithFilter() throws Exception { UserLifecycleEventFilter filter1 = new UserLifecycleEventFilter.Builder() .addEventType(CarUserManager.USER_LIFECYCLE_EVENT_TYPE_STARTING).build(); mMgr.addListener(Runnable::run, filter1, (e) -> { }); UserLifecycleEventFilter filter2 = new UserLifecycleEventFilter.Builder() .addUser(UserHandle.CURRENT).build(); mMgr.addListener(Runnable::run, filter2, (e) -> { }); verify(mService).setLifecycleListenerForApp(any(), eq(filter1), any()); verify(mService).setLifecycleListenerForApp(any(), eq(filter2), any()); } @Test public void testRemoveListener_nullListener() { assertThrows(NullPointerException.class, () -> mMgr.removeListener(null)); } @Test public void testRemoveListener_notAddedBefore() { UserLifecycleListener listener = (e) -> { }; assertThrows(IllegalStateException.class, () -> mMgr.removeListener(listener)); } @Test public void testRemoveListener_addAndRemove() { UserLifecycleListener listener = (e) -> { }; mMgr.addListener(Runnable::run, listener); mMgr.removeListener(listener); // Make sure it was removed assertThrows(IllegalStateException.class, () -> mMgr.removeListener(listener)); } @Test public void testSwitchUser_success() throws Exception { expectServiceSwitchUserSucceeds(11, UserSwitchResult.STATUS_SUCCESSFUL); mMgr.switchUser(new UserSwitchRequest.Builder( UserHandle.of(11)).build(), Runnable::run, response -> { assertThat(response.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL); assertThat(response.getErrorMessage()).isNull(); } ); } @Test public void testSwitchUserId_success() throws Exception { expectServiceSwitchUserSucceeds(11, UserSwitchResult.STATUS_SUCCESSFUL); AsyncFuture future = mMgr.switchUser(11); assertThat(future).isNotNull(); UserSwitchResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL); assertThat(result.getErrorMessage()).isNull(); } @Test public void testSwitchUser_remoteException() throws Exception { expectServiceSwitchUserFails(11, new RemoteException("D'OH!")); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); mMgr.switchUser(new UserSwitchRequest.Builder( UserHandle.of(11)).build(), Runnable::run, response -> { assertThat(response.getStatus()).isEqualTo( UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(response.getErrorMessage()).isNull(); } ); } @Test public void testSwitchUserId_remoteException() throws Exception { expectServiceSwitchUserFails(11, new RemoteException("D'OH!")); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); AsyncFuture future = mMgr.switchUser(11); assertThat(future).isNotNull(); UserSwitchResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(result.getErrorMessage()).isNull(); } @Test public void testSwitchUser_runtimeException() throws Exception { expectServiceSwitchUserFails(11, new RuntimeException("D'OH!")); mMgr.switchUser(new UserSwitchRequest.Builder( UserHandle.of(11)).build(), Runnable::run, response -> { assertThat(response.getStatus()).isEqualTo( UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(response.getErrorMessage()).isNull(); } ); } @Test public void testSwitchUserId_runtimeException() throws Exception { expectServiceSwitchUserFails(11, new RuntimeException("D'OH!")); AsyncFuture future = mMgr.switchUser(11); assertThat(future).isNotNull(); UserSwitchResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(result.getErrorMessage()).isNull(); } @Test public void testLogoutUser_success() throws Exception { expectServiceLogoutUserSucceeds(UserSwitchResult.STATUS_SUCCESSFUL); AsyncFuture future = mMgr.logoutUser(); assertThat(future).isNotNull(); UserSwitchResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_SUCCESSFUL); assertThat(result.getErrorMessage()).isNull(); } @Test public void testLogoutUser_remoteException() throws Exception { expectServiceLogoutUserFails(new RemoteException("D'OH!")); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); AsyncFuture future = mMgr.logoutUser(); assertThat(future).isNotNull(); UserSwitchResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(result.getErrorMessage()).isNull(); } @Test public void testLogoutUser_runtimeException() throws Exception { expectServiceLogoutUserFails(new RuntimeException("D'OH!")); AsyncFuture future = mMgr.logoutUser(); assertThat(future).isNotNull(); UserSwitchResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserSwitchResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(result.getErrorMessage()).isNull(); } @Test public void testRemoveUser_success() throws Exception { expectServiceRemoveUserSucceeds(100); mMgr.removeUser(new UserRemovalRequest.Builder( UserHandle.of(100)).build(), Runnable::run, response -> assertThat(response.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL) ); } @Test public void testRemoveUserId_success() throws Exception { expectServiceRemoveUserSucceeds(100); UserRemovalResult result = mMgr.removeUser(100); assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_SUCCESSFUL); } @Test public void testRemoveUser_remoteException() throws Exception { doThrow(new RemoteException("D'OH!")).when(mService).removeUser(eq(100), any()); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); mMgr.removeUser(new UserRemovalRequest.Builder( UserHandle.of(100)).build(), Runnable::run, response -> assertThat(response.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE) ); } @Test public void testRemoveUserId_remoteException() throws Exception { doThrow(new RemoteException("D'OH!")).when(mService).removeUser(eq(100), any()); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); UserRemovalResult result = mMgr.removeUser(100); assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE); } @Test public void testRemoveUser_runtimeException() throws Exception { doThrow(new RuntimeException("D'OH!")).when(mService).removeUser(eq(100), any()); mMgr.removeUser(new UserRemovalRequest.Builder( UserHandle.of(100)).build(), Runnable::run, response -> assertThat(response.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE) ); } @Test public void testRemoveUserId_runtimeException() throws Exception { doThrow(new RuntimeException("D'OH!")).when(mService).removeUser(eq(100), any()); UserRemovalResult result = mMgr.removeUser(100); assertThat(result.getStatus()).isEqualTo(UserRemovalResult.STATUS_ANDROID_FAILURE); } @Test public void testSetSwitchUserIdUICallback_success() throws Exception { UserSwitchUiCallback callback = (u)-> {}; mMgr.setUserSwitchUiCallback(callback); verify(mService).setUserSwitchUiCallback(any()); } @Test public void testSetSwitchUserUICallback_nullCallback() throws Exception { assertThrows(IllegalArgumentException.class, () -> mMgr.setUserSwitchUiCallback(null)); } @Test public void testSetSwitchUserUICallback_success() throws Exception { UserHandleSwitchUiCallback callback = (u)-> {}; mMgr.setUserSwitchUiCallback(Runnable::run, callback); verify(mService).setUserSwitchUiCallback(any()); } @Test public void testCreateUser_success() throws Exception { expectServiceCreateUserSucceeds("dude", UserManager.USER_TYPE_FULL_SECONDARY, 42, UserCreationResult.STATUS_SUCCESSFUL); SyncResultCallback userCreationResultCallback = new SyncResultCallback<>(); mMgr.createUser(new UserCreationRequest.Builder().setName("dude").build(), Runnable::run, userCreationResultCallback); UserCreationResult result = userCreationResultCallback.get(); assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL); assertThat(result.isSuccess()).isTrue(); assertThat(result.getErrorMessage()).isNull(); UserHandle newUser = result.getUser(); assertThat(newUser).isNotNull(); assertThat(newUser.getIdentifier()).isEqualTo(108); } @Test public void testCreateUserId_success() throws Exception { expectServiceCreateUserSucceeds("dude", UserManager.USER_TYPE_FULL_SECONDARY, 42, UserCreationResult.STATUS_SUCCESSFUL); AsyncFuture future = mMgr.createUser("dude", 42); assertThat(future).isNotNull(); UserCreationResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL); assertThat(result.isSuccess()).isTrue(); assertThat(result.getErrorMessage()).isNull(); UserHandle newUser = result.getUser(); assertThat(newUser).isNotNull(); assertThat(newUser.getIdentifier()).isEqualTo(108); } @Test public void testCreateUser_remoteException() throws Exception { expectServiceCreateUserFails(); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); SyncResultCallback userCreationResultCallback = new SyncResultCallback<>(); mMgr.createUser(new UserCreationRequest.Builder().setName("dude").build(), Runnable::run, userCreationResultCallback); UserCreationResult result = userCreationResultCallback.get(); assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(result.isSuccess()).isFalse(); assertThat(result.getErrorMessage()).isNull(); assertThat(result.getUser()).isNull(); } @Test public void testCreateUserId_remoteException() throws Exception { expectServiceCreateUserFails(); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); AsyncFuture future = mMgr.createUser("dude", 42); assertThat(future).isNotNull(); UserCreationResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(result.isSuccess()).isFalse(); assertThat(result.getErrorMessage()).isNull(); assertThat(result.getUser()).isNull(); } @Test public void testCreateUser_runtimeException() throws Exception { doThrow(new RuntimeException("D'OH!")).when(mService).createUser(notNull(), anyInt(), notNull()); SyncResultCallback userCreationResultCallback = new SyncResultCallback<>(); mMgr.createUser(new UserCreationRequest.Builder().setName("dude").build(), Runnable::run, userCreationResultCallback); UserCreationResult result = userCreationResultCallback.get(); assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(result.isSuccess()).isFalse(); assertThat(result.getErrorMessage()).isNull(); assertThat(result.getUser()).isNull(); } @Test public void testCreateUserId_runtimeException() throws Exception { doThrow(new RuntimeException("D'OH!")).when(mService).createUser(notNull(), anyInt(), notNull()); AsyncFuture future = mMgr.createUser("dude", 42); assertThat(future).isNotNull(); UserCreationResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(result.isSuccess()).isFalse(); assertThat(result.getErrorMessage()).isNull(); assertThat(result.getUser()).isNull(); } @Test public void testCreateGuest_success() throws Exception { expectServiceCreateUserSucceeds("dudeGuest", UserManager.USER_TYPE_FULL_GUEST, 0, UserCreationResult.STATUS_SUCCESSFUL); AsyncFuture future = mMgr.createGuest("dudeGuest"); assertThat(future).isNotNull(); UserCreationResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_SUCCESSFUL); assertThat(result.isSuccess()).isTrue(); assertThat(result.getErrorMessage()).isNull(); UserHandle newUser = result.getUser(); assertThat(newUser).isNotNull(); assertThat(newUser.getIdentifier()).isEqualTo(108); } @Test public void testCreateGuest_remoteException() throws Exception { expectServiceCreateUserFails(); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); AsyncFuture future = mMgr.createGuest("dudeGuest"); assertThat(future).isNotNull(); UserCreationResult result = getResult(future); assertThat(result.getStatus()).isEqualTo(UserCreationResult.STATUS_HAL_INTERNAL_FAILURE); assertThat(result.isSuccess()).isFalse(); assertThat(result.getErrorMessage()).isNull(); assertThat(result.getUser()).isNull(); } @Test public void testGetUserIdentificationAssociation_nullTypes() throws Exception { assertThrows(IllegalArgumentException.class, () -> mMgr.getUserIdentificationAssociation(null)); } @Test public void testGetUserIdentificationAssociation_emptyTypes() throws Exception { assertThrows(IllegalArgumentException.class, () -> mMgr.getUserIdentificationAssociation(new int[] {})); } @Test public void testGetUserIdentificationAssociation_remoteException() throws Exception { int[] types = new int[] {1}; when(mService.getUserIdentificationAssociation(types)) .thenThrow(new RemoteException("D'OH!")); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); UserIdentificationAssociationResponse response = mMgr.getUserIdentificationAssociation(types); assertThat(response).isNotNull(); assertThat(response.isSuccess()).isFalse(); } @Test public void testGetUserIdentificationAssociation_runtimeException() throws Exception { int[] types = new int[] {1}; when(mService.getUserIdentificationAssociation(types)) .thenThrow(new RuntimeException("D'OH!")); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); UserIdentificationAssociationResponse response = mMgr.getUserIdentificationAssociation(types); assertThat(response).isNotNull(); assertThat(response.isSuccess()).isFalse(); } @Test public void testGetUserIdentificationAssociation_ok() throws Exception { int[] types = new int[] { 4, 8, 15, 16, 23, 42 }; UserIdentificationAssociationResponse expectedResponse = UserIdentificationAssociationResponse.forSuccess(types); when(mService.getUserIdentificationAssociation(types)).thenReturn(expectedResponse); UserIdentificationAssociationResponse actualResponse = mMgr.getUserIdentificationAssociation(types); assertThat(actualResponse).isSameInstanceAs(expectedResponse); } @Test public void testSetUserIdentificationAssociation_nullTypes() throws Exception { assertThrows(IllegalArgumentException.class, () -> mMgr.setUserIdentificationAssociation(null, new int[] {42})); } @Test public void testSetUserIdentificationAssociation_emptyTypes() throws Exception { assertThrows(IllegalArgumentException.class, () -> mMgr.setUserIdentificationAssociation(new int[0], new int[] {42})); } @Test public void testSetUserIdentificationAssociation_nullValues() throws Exception { assertThrows(IllegalArgumentException.class, () -> mMgr.setUserIdentificationAssociation(new int[] {42}, null)); } @Test public void testSetUserIdentificationAssociation_emptyValues() throws Exception { assertThrows(IllegalArgumentException.class, () -> mMgr.setUserIdentificationAssociation(new int[] {42}, new int[0])); } @Test public void testSetUserIdentificationAssociation_sizeMismatch() throws Exception { assertThrows(IllegalArgumentException.class, () -> mMgr.setUserIdentificationAssociation(new int[] {1}, new int[] {2, 3})); } @Test public void testSetUserIdentificationAssociation_remoteException() throws Exception { int[] types = new int[] {1}; int[] values = new int[] {2}; doThrow(new RemoteException("D'OH!")).when(mService) .setUserIdentificationAssociation(anyInt(), same(types), same(values), notNull()); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); AsyncFuture future = mMgr.setUserIdentificationAssociation(types, values); assertThat(future).isNotNull(); UserIdentificationAssociationResponse result = getResult(future); assertThat(result.isSuccess()).isFalse(); assertThat(result.getValues()).isNull(); assertThat(result.getErrorMessage()).isNull(); } @Test public void testSetUserIdentificationAssociation_runtimeException() throws Exception { int[] types = new int[] {1}; int[] values = new int[] {2}; doThrow(new RuntimeException("D'OH!")).when(mService) .setUserIdentificationAssociation(anyInt(), same(types), same(values), notNull()); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); AsyncFuture future = mMgr.setUserIdentificationAssociation(types, values); assertThat(future).isNotNull(); UserIdentificationAssociationResponse result = getResult(future); assertThat(result.isSuccess()).isFalse(); assertThat(result.getValues()).isNull(); assertThat(result.getErrorMessage()).isNull(); } @Test public void testSetUserIdentificationAssociation_ok() throws Exception { int[] types = new int[] { 1, 2, 3 }; int[] values = new int[] { 10, 20, 30 }; doAnswer((inv) -> { @SuppressWarnings("unchecked") AndroidFuture future = (AndroidFuture) inv .getArguments()[3]; UserIdentificationAssociationResponse response = UserIdentificationAssociationResponse .forSuccess(values, "D'OH!"); future.complete(response); return null; }).when(mService) .setUserIdentificationAssociation(anyInt(), same(types), same(values), notNull()); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); AsyncFuture future = mMgr.setUserIdentificationAssociation(types, values); assertThat(future).isNotNull(); UserIdentificationAssociationResponse result = getResult(future); assertThat(result.isSuccess()).isTrue(); assertThat(result.getValues()).asList().containsAtLeast(10, 20, 30).inOrder(); assertThat(result.getErrorMessage()).isEqualTo("D'OH!"); } @Test public void testIsUserHalUserAssociation() throws Exception { when(mService.isUserHalUserAssociationSupported()).thenReturn(false).thenReturn(true); assertThat(mMgr.isUserHalUserAssociationSupported()).isFalse(); assertThat(mMgr.isUserHalUserAssociationSupported()).isTrue(); } @Test public void testIsUserHalUserAssociation_remoteException() throws Exception { doThrow(new RemoteException("D'OH!")).when(mService).isUserHalUserAssociationSupported(); mockHandleRemoteExceptionFromCarServiceWithDefaultValue(mCar); assertThat(mMgr.isUserHalUserAssociationSupported()).isFalse(); } @Test public void testIsUserHalUserAssociation_runtimeException() throws Exception { doThrow(new RuntimeException("D'OH!")).when(mService).isUserHalUserAssociationSupported(); assertThat(mMgr.isUserHalUserAssociationSupported()).isFalse(); } private void expectServiceSwitchUserSucceeds(@UserIdInt int userId, @UserSwitchResult.Status int status) throws RemoteException { doAnswer((invocation) -> { @SuppressWarnings("unchecked") ResultCallbackImpl resultCallbackImpl = (ResultCallbackImpl) invocation.getArguments()[2]; resultCallbackImpl.complete(new UserSwitchResult(status, /* errorMessage= */ null)); return null; }).when(mService).switchUser(eq(userId), anyInt(), notNull(), anyBoolean()); } private void expectServiceSwitchUserFails(@UserIdInt int userId, Exception e) throws Exception { doThrow(e).when(mService).switchUser(eq(userId), anyInt(), notNull(), anyBoolean()); } private void expectServiceLogoutUserSucceeds(@UserSwitchResult.Status int status) throws RemoteException { doAnswer((invocation) -> { @SuppressWarnings("unchecked") ResultCallbackImpl resultCallbackImpl = (ResultCallbackImpl) invocation.getArguments()[1]; resultCallbackImpl.complete(new UserSwitchResult(status, /* errorMessage= */ null)); return null; }).when(mService).logoutUser(anyInt(), notNull()); } private void expectServiceLogoutUserFails(Exception e) throws Exception { doThrow(e).when(mService).logoutUser(anyInt(), notNull()); } private void expectServiceRemoveUserSucceeds(@UserIdInt int userId) throws RemoteException { doAnswer((invocation) -> { @SuppressWarnings("unchecked") ResultCallbackImpl resultResultCallbackImpl = (ResultCallbackImpl) invocation.getArguments()[1]; resultResultCallbackImpl.complete( new UserRemovalResult(UserRemovalResult.STATUS_SUCCESSFUL)); return null; }).when(mService).removeUser(eq(userId), notNull()); } private void expectServiceCreateUserSucceeds(@Nullable String name, @NonNull String userType, @UserInfoFlag int flags, @UserCreationResult.Status int status) throws RemoteException { doAnswer((invocation) -> { @SuppressWarnings("unchecked") UserInfo newUser = new UserTestingHelper.UserInfoBuilder(108) .setName(name).setType(userType).setFlags(flags).build(); ResultCallbackImpl resultCallbackImpl = (ResultCallbackImpl) invocation.getArguments()[2]; resultCallbackImpl.complete(new UserCreationResult(status, newUser.getUserHandle())); return null; }).when(mService).createUser(notNull(), anyInt(), notNull()); } private void expectServiceCreateUserFails() throws RemoteException { doThrow(new RemoteException("D'OH!")).when(mService).createUser(notNull(), anyInt(), notNull()); } private void setExistingUsers(int... userIds) { // TODO(b/197184481): move this logic to helper classes (UserTestingHelper.java & // AndroidMockitoHelper.java) List userHandles = Arrays.stream(userIds) .mapToObj(id -> UserHandle.of(id)) .collect(Collectors.toList()); when(mUserManager.getUserHandles(/* excludeDying= */ true)).thenReturn(userHandles); } private void mockIsHeadlessSystemUserMode(boolean mode) { mMgr = new CarUserManager(mCar, mService, mUserManager, /* isHeadlessSystemUserMode= */ mode); } }