1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 package com.android.car.hal; 17 18 import static android.car.VehiclePropertyIds.CREATE_USER; 19 import static android.car.VehiclePropertyIds.CURRENT_GEAR; 20 import static android.car.VehiclePropertyIds.INITIAL_USER_INFO; 21 import static android.car.VehiclePropertyIds.REMOVE_USER; 22 import static android.car.VehiclePropertyIds.SWITCH_USER; 23 import static android.car.VehiclePropertyIds.USER_IDENTIFICATION_ASSOCIATION; 24 import static android.car.test.mocks.CarArgumentMatchers.isProperty; 25 import static android.car.test.mocks.CarArgumentMatchers.isPropertyWithValues; 26 import static android.car.test.util.VehicleHalTestingHelper.newConfig; 27 import static android.car.test.util.VehicleHalTestingHelper.newSubscribableConfig; 28 import static android.hardware.automotive.vehicle.V2_0.InitialUserInfoRequestType.COLD_BOOT; 29 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationSetValue.ASSOCIATE_CURRENT_USER; 30 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.CUSTOM_1; 31 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationType.KEY_FOB; 32 import static android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociationValue.ASSOCIATED_CURRENT_USER; 33 34 import static com.google.common.truth.Truth.assertThat; 35 import static com.google.common.truth.Truth.assertWithMessage; 36 37 import static org.junit.Assert.fail; 38 import static org.mockito.ArgumentMatchers.anyInt; 39 import static org.mockito.Mockito.doAnswer; 40 import static org.mockito.Mockito.doReturn; 41 import static org.mockito.Mockito.doThrow; 42 import static org.mockito.Mockito.never; 43 import static org.mockito.Mockito.spy; 44 import static org.mockito.Mockito.verify; 45 import static org.mockito.Mockito.when; 46 import static org.testng.Assert.assertThrows; 47 48 import android.annotation.NonNull; 49 import android.car.hardware.property.VehicleHalStatusCode; 50 import android.car.userlib.HalCallback; 51 import android.car.userlib.UserHalHelper; 52 import android.hardware.automotive.vehicle.V2_0.CreateUserRequest; 53 import android.hardware.automotive.vehicle.V2_0.CreateUserResponse; 54 import android.hardware.automotive.vehicle.V2_0.CreateUserStatus; 55 import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponse; 56 import android.hardware.automotive.vehicle.V2_0.InitialUserInfoResponseAction; 57 import android.hardware.automotive.vehicle.V2_0.RemoveUserRequest; 58 import android.hardware.automotive.vehicle.V2_0.SwitchUserMessageType; 59 import android.hardware.automotive.vehicle.V2_0.SwitchUserRequest; 60 import android.hardware.automotive.vehicle.V2_0.SwitchUserResponse; 61 import android.hardware.automotive.vehicle.V2_0.SwitchUserStatus; 62 import android.hardware.automotive.vehicle.V2_0.UserFlags; 63 import android.hardware.automotive.vehicle.V2_0.UserIdentificationAssociation; 64 import android.hardware.automotive.vehicle.V2_0.UserIdentificationGetRequest; 65 import android.hardware.automotive.vehicle.V2_0.UserIdentificationResponse; 66 import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetAssociation; 67 import android.hardware.automotive.vehicle.V2_0.UserIdentificationSetRequest; 68 import android.hardware.automotive.vehicle.V2_0.UserInfo; 69 import android.hardware.automotive.vehicle.V2_0.UsersInfo; 70 import android.hardware.automotive.vehicle.V2_0.VehiclePropConfig; 71 import android.hardware.automotive.vehicle.V2_0.VehiclePropValue; 72 import android.os.Handler; 73 import android.os.Looper; 74 import android.os.ServiceSpecificException; 75 import android.os.SystemClock; 76 import android.os.UserHandle; 77 import android.util.Log; 78 import android.util.Pair; 79 80 import com.android.car.CarLocalServices; 81 import com.android.car.user.CarUserService; 82 83 import org.junit.After; 84 import org.junit.Before; 85 import org.junit.Test; 86 import org.junit.runner.RunWith; 87 import org.mockito.ArgumentCaptor; 88 import org.mockito.Mock; 89 import org.mockito.junit.MockitoJUnitRunner; 90 91 import java.util.ArrayList; 92 import java.util.Arrays; 93 import java.util.Collections; 94 import java.util.List; 95 import java.util.concurrent.CountDownLatch; 96 import java.util.concurrent.TimeUnit; 97 import java.util.concurrent.atomic.AtomicReference; 98 99 @RunWith(MockitoJUnitRunner.class) 100 public final class UserHalServiceTest { 101 102 private static final String TAG = UserHalServiceTest.class.getSimpleName(); 103 104 /** 105 * Timeout passed to {@link UserHalService} methods. This is the timeout for which 106 * {@link UserHalService} wait for the property change event and return 107 * {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} if HAL doesn't respond. This timeout is used 108 * where we expect HAL to return something and {@link UserHalService} methods are not expected 109 * to timeout. Tests are not supposed to wait for this much so this value can be high. If test 110 * requires HAL to timeout, then use {@link HAL_TIMEOUT_MS}. 111 */ 112 private static final int HAL_TIMEOUT_MS = 5_000; 113 114 /** 115 * Timeout passed to {@link UserHalService} methods only if test expects that call will be 116 * timeout and {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} is expected response. A higher 117 * value for this is going to slow down tests. If this timeout is used, then it is expected that 118 * {@link HalCallback.STATUS_HAL_RESPONSE_TIMEOUT} is checked. 119 */ 120 private static final int HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS = 250; 121 122 /** 123 * If tests expect {@link UserHalService} call to timeout, and if they require to sleep then 124 * sleep for this much time. This value should be higher than {@link HAL_TIMEOUT_MS}. A much 125 * higher value for this is going to slow down the test. 126 */ 127 private static final int WAITING_TIME_FOR_NEGATIVE_TESTS_MS = HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS 128 + 100; 129 130 /** 131 * Timeout for {@link GenericHalCallback#assertCalled()} for tests. In each case, 132 * {@link UserHalService} is supposed to return something - either a valid response or a 133 * timeout. This timeout is for the callback to wait for the response. A higher value of this 134 * timeout should not affect the test duration. 135 */ 136 private static final int CALLBACK_TIMEOUT = 5_000; 137 138 // Used when crafting a request property - the real value will be set by the mock. 139 private static final int REQUEST_ID_PLACE_HOLDER = 1111; 140 141 private static final int DEFAULT_REQUEST_ID = 2222; 142 143 private static final int DEFAULT_USER_ID = 333; 144 private static final int DEFAULT_USER_FLAGS = 444; 145 146 private static final int INITIAL_USER_INFO_RESPONSE_ACTION = 108; 147 148 @Mock 149 private VehicleHal mVehicleHal; 150 @Mock 151 private CarUserService mCarUserService; 152 153 private final Handler mHandler = new Handler(Looper.getMainLooper()); 154 155 private final UserInfo mUser0 = new UserInfo(); 156 private final UserInfo mUser10 = new UserInfo(); 157 158 private final UsersInfo mUsersInfo = new UsersInfo(); 159 160 // Must be a spy so we can mock getNextRequestId() 161 private UserHalService mUserHalService; 162 163 @Before setFixtures()164 public void setFixtures() { 165 mUserHalService = spy(new UserHalService(mVehicleHal, mHandler)); 166 // Needs at least one property, otherwise isSupported() and isUserAssociationSupported() 167 // will return false 168 mUserHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 169 newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER), 170 newSubscribableConfig(SWITCH_USER), 171 newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION))); 172 173 mUser0.userId = 0; 174 mUser0.flags = 100; 175 mUser10.userId = 10; 176 mUser10.flags = 110; 177 178 mUsersInfo.currentUser = mUser0; 179 mUsersInfo.numberUsers = 2; 180 mUsersInfo.existingUsers = new ArrayList<>(2); 181 mUsersInfo.existingUsers.add(mUser0); 182 mUsersInfo.existingUsers.add(mUser10); 183 184 CarLocalServices.addService(CarUserService.class, mCarUserService); 185 } 186 187 @After clearFixtures()188 public void clearFixtures() { 189 CarLocalServices.removeServiceForTest(CarUserService.class); 190 } 191 192 @Test testTakeSupportedProperties_supportedNoProperties()193 public void testTakeSupportedProperties_supportedNoProperties() { 194 // Cannot use mUserHalService because it's already set with supported properties 195 UserHalService myHalService = new UserHalService(mVehicleHal); 196 197 myHalService.takeProperties(Collections.emptyList()); 198 assertThat(myHalService.isSupported()).isFalse(); 199 assertThat(myHalService.isUserAssociationSupported()).isFalse(); 200 } 201 202 @Test testTakeSupportedProperties_supportedFewProperties()203 public void testTakeSupportedProperties_supportedFewProperties() { 204 // Cannot use mUserHalService because it's already set with supported properties 205 UserHalService myHalService = new UserHalService(mVehicleHal); 206 myHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 207 newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER))); 208 209 assertThat(myHalService.isSupported()).isFalse(); 210 assertThat(myHalService.isUserAssociationSupported()).isFalse(); 211 } 212 213 @Test testTakeSupportedProperties_supportedAllCoreProperties()214 public void testTakeSupportedProperties_supportedAllCoreProperties() { 215 // Cannot use mUserHalService because it's already set with supported properties 216 UserHalService myHalService = new UserHalService(mVehicleHal); 217 myHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 218 newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER), 219 newSubscribableConfig(SWITCH_USER))); 220 221 assertThat(myHalService.isSupported()).isTrue(); 222 assertThat(myHalService.isUserAssociationSupported()).isFalse(); 223 } 224 225 @Test testTakeSupportedProperties_supportedAllProperties()226 public void testTakeSupportedProperties_supportedAllProperties() { 227 // Cannot use mUserHalService because it's already set with supported properties 228 UserHalService myHalService = new UserHalService(mVehicleHal); 229 myHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 230 newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER), 231 newSubscribableConfig(SWITCH_USER), 232 newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION))); 233 234 assertThat(myHalService.isSupported()).isTrue(); 235 assertThat(myHalService.isUserAssociationSupported()).isTrue(); 236 } 237 238 @Test testTakeSupportedPropertiesAndInit()239 public void testTakeSupportedPropertiesAndInit() { 240 // Cannot use mUserHalService because it's already set with supported properties 241 UserHalService myHalService = new UserHalService(mVehicleHal); 242 VehiclePropConfig unsupportedConfig = newConfig(CURRENT_GEAR); 243 244 myHalService.takeProperties(Arrays.asList(newSubscribableConfig(INITIAL_USER_INFO), 245 newSubscribableConfig(CREATE_USER), newSubscribableConfig(REMOVE_USER), 246 newSubscribableConfig(SWITCH_USER), unsupportedConfig, 247 newSubscribableConfig(USER_IDENTIFICATION_ASSOCIATION))); 248 249 250 // Ideally there should be 2 test methods (one for takeSupportedProperties() and one for 251 // init()), but on "real life" VehicleHal calls these 2 methods in sequence, and the latter 252 // depends on the properties set by the former, so it's ok to test both here... 253 myHalService.init(); 254 verify(mVehicleHal).subscribeProperty(myHalService, INITIAL_USER_INFO); 255 verify(mVehicleHal).subscribeProperty(myHalService, CREATE_USER); 256 verify(mVehicleHal).subscribeProperty(myHalService, REMOVE_USER); 257 verify(mVehicleHal).subscribeProperty(myHalService, SWITCH_USER); 258 verify(mVehicleHal).subscribeProperty(myHalService, USER_IDENTIFICATION_ASSOCIATION); 259 } 260 261 @Test testSupportedProperties()262 public void testSupportedProperties() { 263 assertThat(mUserHalService.getAllSupportedProperties()).asList().containsExactly( 264 INITIAL_USER_INFO, CREATE_USER, REMOVE_USER, SWITCH_USER, 265 USER_IDENTIFICATION_ASSOCIATION); 266 } 267 268 @Test testGetUserInfo_noHalSupported()269 public void testGetUserInfo_noHalSupported() { 270 // Cannot use mUserHalService because it's already set with supported properties 271 UserHalService myHalService = new UserHalService(mVehicleHal); 272 273 assertThrows(IllegalStateException.class, () -> myHalService.getInitialUserInfo(COLD_BOOT, 274 HAL_TIMEOUT_MS, mUsersInfo, noOpCallback())); 275 } 276 277 @Test testGetUserInfo_invalidTimeout()278 public void testGetUserInfo_invalidTimeout() { 279 assertThrows(IllegalArgumentException.class, () -> 280 mUserHalService.getInitialUserInfo(COLD_BOOT, 0, mUsersInfo, noOpCallback())); 281 assertThrows(IllegalArgumentException.class, () -> 282 mUserHalService.getInitialUserInfo(COLD_BOOT, -1, mUsersInfo, noOpCallback())); 283 } 284 285 @Test testGetUserInfo_noUsersInfo()286 public void testGetUserInfo_noUsersInfo() { 287 assertThrows(NullPointerException.class, () -> mUserHalService.getInitialUserInfo(COLD_BOOT, 288 HAL_TIMEOUT_MS, null, noOpCallback())); 289 } 290 291 @Test testGetUserInfo_noCallback()292 public void testGetUserInfo_noCallback() { 293 assertThrows(NullPointerException.class, 294 () -> mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, 295 mUsersInfo, null)); 296 } 297 298 @Test testGetUserInfo_halSetTimedOut()299 public void testGetUserInfo_halSetTimedOut() throws Exception { 300 replySetPropertyWithTimeoutException(INITIAL_USER_INFO); 301 302 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 303 CALLBACK_TIMEOUT); 304 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 305 callback); 306 307 callback.assertCalled(); 308 assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT); 309 assertThat(callback.response).isNull(); 310 311 // Make sure the pending request was removed 312 SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS); 313 callback.assertNotCalledAgain(); 314 } 315 316 @Test testGetUserInfo_halDidNotReply()317 public void testGetUserInfo_halDidNotReply() throws Exception { 318 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 319 CALLBACK_TIMEOUT); 320 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo, 321 callback); 322 323 callback.assertCalled(); 324 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 325 assertThat(callback.response).isNull(); 326 } 327 328 @Test testGetUserInfo_secondCallFailWhilePending()329 public void testGetUserInfo_secondCallFailWhilePending() throws Exception { 330 GenericHalCallback<InitialUserInfoResponse> callback1 = new GenericHalCallback<>( 331 CALLBACK_TIMEOUT); 332 GenericHalCallback<InitialUserInfoResponse> callback2 = new GenericHalCallback<>( 333 CALLBACK_TIMEOUT); 334 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo, 335 callback1); 336 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 337 callback2); 338 339 callback1.assertCalled(); 340 assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 341 assertThat(callback1.response).isNull(); 342 343 callback2.assertCalled(); 344 assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION); 345 assertThat(callback1.response).isNull(); 346 } 347 348 @Test testGetUserInfo_halReplyWithWrongRequestId()349 public void testGetUserInfo_halReplyWithWrongRequestId() throws Exception { 350 VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO, 351 REQUEST_ID_PLACE_HOLDER, INITIAL_USER_INFO_RESPONSE_ACTION); 352 353 replySetPropertyWithOnChangeEvent(INITIAL_USER_INFO, propResponse, 354 /* rightRequestId= */ false); 355 356 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 357 CALLBACK_TIMEOUT); 358 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, mUsersInfo, 359 callback); 360 361 callback.assertCalled(); 362 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 363 assertThat(callback.response).isNull(); 364 } 365 366 @Test testGetUserInfo_halReturnedInvalidAction()367 public void testGetUserInfo_halReturnedInvalidAction() throws Exception { 368 VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO, 369 REQUEST_ID_PLACE_HOLDER, INITIAL_USER_INFO_RESPONSE_ACTION); 370 371 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 372 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true); 373 374 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 375 CALLBACK_TIMEOUT); 376 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 377 callback); 378 379 callback.assertCalled(); 380 381 // Make sure the arguments were properly converted 382 assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT); 383 384 // Assert response 385 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 386 assertThat(callback.response).isNull(); 387 } 388 389 @Test testGetUserInfo_successDefault()390 public void testGetUserInfo_successDefault() throws Exception { 391 VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO, 392 REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.DEFAULT); 393 394 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 395 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true); 396 397 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 398 CALLBACK_TIMEOUT); 399 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 400 callback); 401 402 callback.assertCalled(); 403 404 // Make sure the arguments were properly converted 405 assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT); 406 407 // Assert response 408 assertCallbackStatus(callback, HalCallback.STATUS_OK); 409 InitialUserInfoResponse actualResponse = callback.response; 410 assertThat(actualResponse.action).isEqualTo(InitialUserInfoResponseAction.DEFAULT); 411 assertThat(actualResponse.userNameToCreate).isEmpty(); 412 assertThat(actualResponse.userToSwitchOrCreate).isNotNull(); 413 assertThat(actualResponse.userToSwitchOrCreate.userId).isEqualTo(UserHandle.USER_NULL); 414 assertThat(actualResponse.userToSwitchOrCreate.flags).isEqualTo(UserFlags.NONE); 415 } 416 417 @Test testGetUserInfo_successSwitchUser()418 public void testGetUserInfo_successSwitchUser() throws Exception { 419 int userIdToSwitch = 42; 420 VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO, 421 REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.SWITCH); 422 propResponse.value.int32Values.add(userIdToSwitch); 423 424 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 425 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true); 426 427 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 428 CALLBACK_TIMEOUT); 429 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 430 callback); 431 432 callback.assertCalled(); 433 434 // Make sure the arguments were properly converted 435 assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT); 436 437 assertCallbackStatus(callback, HalCallback.STATUS_OK); 438 InitialUserInfoResponse actualResponse = callback.response; 439 assertThat(actualResponse.action).isEqualTo(InitialUserInfoResponseAction.SWITCH); 440 assertThat(actualResponse.userNameToCreate).isEmpty(); 441 UserInfo userToSwitch = actualResponse.userToSwitchOrCreate; 442 assertThat(userToSwitch).isNotNull(); 443 assertThat(userToSwitch.userId).isEqualTo(userIdToSwitch); 444 assertThat(userToSwitch.flags).isEqualTo(UserFlags.NONE); 445 } 446 447 @Test testGetUserInfo_successCreateUser()448 public void testGetUserInfo_successCreateUser() throws Exception { 449 int newUserFlags = 108; 450 String newUserName = "Groot"; 451 VehiclePropValue propResponse = UserHalHelper.createPropRequest(INITIAL_USER_INFO, 452 REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.CREATE); 453 propResponse.value.int32Values.add(666); // userId (not used) 454 propResponse.value.int32Values.add(newUserFlags); 455 propResponse.value.stringValue = "||" + newUserName; 456 457 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 458 INITIAL_USER_INFO, propResponse, /* rightRequestId= */ true); 459 460 GenericHalCallback<InitialUserInfoResponse> callback = new GenericHalCallback<>( 461 CALLBACK_TIMEOUT); 462 mUserHalService.getInitialUserInfo(COLD_BOOT, HAL_TIMEOUT_MS, mUsersInfo, 463 callback); 464 465 callback.assertCalled(); 466 467 // Make sure the arguments were properly converted 468 assertInitialUserInfoSetRequest(reqCaptor.get(), COLD_BOOT); 469 470 assertCallbackStatus(callback, HalCallback.STATUS_OK); 471 assertThat(callback.status).isEqualTo(HalCallback.STATUS_OK); 472 InitialUserInfoResponse actualResponse = callback.response; 473 assertThat(actualResponse.action).isEqualTo(InitialUserInfoResponseAction.CREATE); 474 assertThat(actualResponse.userLocales).isEmpty(); 475 assertThat(actualResponse.userNameToCreate).isEqualTo(newUserName); 476 UserInfo newUser = actualResponse.userToSwitchOrCreate; 477 assertThat(newUser).isNotNull(); 478 assertThat(newUser.userId).isEqualTo(UserHandle.USER_NULL); 479 assertThat(newUser.flags).isEqualTo(newUserFlags); 480 } 481 482 @Test testGetUserInfo_twoSuccessfulCalls()483 public void testGetUserInfo_twoSuccessfulCalls() throws Exception { 484 testGetUserInfo_successDefault(); 485 testGetUserInfo_successDefault(); 486 } 487 488 @Test testSwitchUser_noHalSupported()489 public void testSwitchUser_noHalSupported() { 490 // Cannot use mUserHalService because it's already set with supported properties 491 UserHalService myHalService = new UserHalService(mVehicleHal); 492 493 assertThrows(IllegalStateException.class, 494 () -> myHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), 495 HAL_TIMEOUT_MS, noOpCallback())); 496 } 497 498 @Test testSwitchUser_invalidTimeout()499 public void testSwitchUser_invalidTimeout() { 500 assertThrows(IllegalArgumentException.class, () -> mUserHalService 501 .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), 0, noOpCallback())); 502 assertThrows(IllegalArgumentException.class, () -> mUserHalService 503 .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), -1, noOpCallback())); 504 } 505 506 @Test testSwitchUser_noUsersInfo()507 public void testSwitchUser_noUsersInfo() { 508 assertThrows(IllegalArgumentException.class, () -> mUserHalService 509 .switchUser(createUserSwitchRequest(mUser10, null), HAL_TIMEOUT_MS, 510 noOpCallback())); 511 } 512 513 @Test testSwitchUser_noCallback()514 public void testSwitchUser_noCallback() { 515 assertThrows(NullPointerException.class, () -> mUserHalService 516 .switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS, null)); 517 } 518 519 @Test testSwitchUser_nullRequest()520 public void testSwitchUser_nullRequest() { 521 assertThrows(NullPointerException.class, () -> mUserHalService 522 .switchUser(null, HAL_TIMEOUT_MS, noOpCallback())); 523 } 524 525 @Test testSwitchUser_noTarget()526 public void testSwitchUser_noTarget() { 527 assertThrows(NullPointerException.class, () -> mUserHalService 528 .switchUser(createUserSwitchRequest(null, mUsersInfo), HAL_TIMEOUT_MS, 529 noOpCallback())); 530 } 531 532 @Test testSwitchUser_halSetTimedOut()533 public void testSwitchUser_halSetTimedOut() throws Exception { 534 replySetPropertyWithTimeoutException(SWITCH_USER); 535 536 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 537 CALLBACK_TIMEOUT); 538 mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), 539 HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 540 callback); 541 542 callback.assertCalled(); 543 assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT); 544 assertThat(callback.response).isNull(); 545 546 // Make sure the pending request was removed 547 SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS); 548 callback.assertNotCalledAgain(); 549 } 550 551 @Test testSwitchUser_halDidNotReply()552 public void testSwitchUser_halDidNotReply() throws Exception { 553 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 554 CALLBACK_TIMEOUT); 555 mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), 556 HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 557 callback); 558 559 callback.assertCalled(); 560 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 561 assertThat(callback.response).isNull(); 562 } 563 564 @Test testSwitchUser_halReplyWithWrongRequestId()565 public void testSwitchUser_halReplyWithWrongRequestId() throws Exception { 566 VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER, 567 REQUEST_ID_PLACE_HOLDER, InitialUserInfoResponseAction.SWITCH); 568 569 replySetPropertyWithOnChangeEvent(SWITCH_USER, propResponse, 570 /* rightRequestId= */ false); 571 572 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 573 CALLBACK_TIMEOUT); 574 mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), 575 HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 576 callback); 577 578 callback.assertCalled(); 579 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 580 assertThat(callback.response).isNull(); 581 } 582 583 @Test testSwitchUser_halReturnedInvalidMessageType()584 public void testSwitchUser_halReturnedInvalidMessageType() throws Exception { 585 VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER, 586 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.LEGACY_ANDROID_SWITCH); 587 propResponse.value.int32Values.add(SwitchUserStatus.SUCCESS); 588 589 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 590 SWITCH_USER, propResponse, /* rightRequestId= */ true); 591 592 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 593 CALLBACK_TIMEOUT); 594 mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS, 595 callback); 596 597 callback.assertCalled(); 598 599 // Make sure the arguments were properly converted 600 assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH, 601 mUser10); 602 603 // Assert response 604 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 605 assertThat(callback.response).isNull(); 606 } 607 608 @Test testSwitchUser_success()609 public void testSwitchUser_success() throws Exception { 610 VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER, 611 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE); 612 propResponse.value.int32Values.add(SwitchUserStatus.SUCCESS); 613 614 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 615 SWITCH_USER, propResponse, /* rightRequestId= */ true); 616 617 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 618 CALLBACK_TIMEOUT); 619 mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS, 620 callback); 621 622 callback.assertCalled(); 623 624 // Make sure the arguments were properly converted 625 assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH, 626 mUser10); 627 628 // Assert response 629 assertCallbackStatus(callback, HalCallback.STATUS_OK); 630 SwitchUserResponse actualResponse = callback.response; 631 assertThat(actualResponse.status).isEqualTo(SwitchUserStatus.SUCCESS); 632 assertThat(actualResponse.messageType).isEqualTo(SwitchUserMessageType.VEHICLE_RESPONSE); 633 assertThat(actualResponse.errorMessage).isEmpty(); 634 } 635 636 @Test testSwitchUser_failure()637 public void testSwitchUser_failure() throws Exception { 638 VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER, 639 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE); 640 propResponse.value.int32Values.add(SwitchUserStatus.FAILURE); 641 propResponse.value.stringValue = "D'OH!"; 642 643 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 644 SWITCH_USER, propResponse, /* rightRequestId= */ true); 645 646 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 647 CALLBACK_TIMEOUT); 648 mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS, 649 callback); 650 651 callback.assertCalled(); 652 653 // Make sure the arguments were properly converted 654 assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH, 655 mUser10); 656 657 // Assert response 658 assertCallbackStatus(callback, HalCallback.STATUS_OK); 659 SwitchUserResponse actualResponse = callback.response; 660 assertThat(actualResponse.status).isEqualTo(SwitchUserStatus.FAILURE); 661 assertThat(actualResponse.messageType).isEqualTo(SwitchUserMessageType.VEHICLE_RESPONSE); 662 assertThat(actualResponse.errorMessage).isEqualTo("D'OH!"); 663 } 664 665 @Test testSwitchUser_secondCallFailWhilePending()666 public void testSwitchUser_secondCallFailWhilePending() throws Exception { 667 GenericHalCallback<SwitchUserResponse> callback1 = new GenericHalCallback<>( 668 CALLBACK_TIMEOUT); 669 GenericHalCallback<SwitchUserResponse> callback2 = new GenericHalCallback<>( 670 CALLBACK_TIMEOUT); 671 mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), 672 HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 673 callback1); 674 mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS, 675 callback2); 676 677 callback1.assertCalled(); 678 assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 679 assertThat(callback1.response).isNull(); 680 681 callback2.assertCalled(); 682 assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION); 683 assertThat(callback1.response).isNull(); 684 } 685 686 @Test testSwitchUser_halReturnedInvalidStatus()687 public void testSwitchUser_halReturnedInvalidStatus() throws Exception { 688 VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER, 689 REQUEST_ID_PLACE_HOLDER, SwitchUserMessageType.VEHICLE_RESPONSE); 690 propResponse.value.int32Values.add(/*status =*/ 110); // an invalid status 691 692 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 693 SWITCH_USER, propResponse, /* rightRequestId= */ true); 694 695 GenericHalCallback<SwitchUserResponse> callback = new GenericHalCallback<>( 696 CALLBACK_TIMEOUT); 697 mUserHalService.switchUser(createUserSwitchRequest(mUser10, mUsersInfo), HAL_TIMEOUT_MS, 698 callback); 699 700 callback.assertCalled(); 701 702 // Make sure the arguments were properly converted 703 assertHalSetSwitchUserRequest(reqCaptor.get(), SwitchUserMessageType.ANDROID_SWITCH, 704 mUser10); 705 706 // Assert response 707 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 708 assertThat(callback.response).isNull(); 709 } 710 711 @Test testUserSwitch_OEMRequest_success()712 public void testUserSwitch_OEMRequest_success() throws Exception { 713 int requestId = -4; 714 int targetUserId = 11; 715 VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER, 716 requestId, SwitchUserMessageType.VEHICLE_REQUEST); 717 718 propResponse.value.int32Values.add(targetUserId); 719 720 mUserHalService.onHalEvents(Arrays.asList(propResponse)); 721 waitForHandler(); 722 723 verify(mCarUserService).switchAndroidUserFromHal(requestId, targetUserId); 724 } 725 726 @Test testUserSwitch_OEMRequest_failure_positiveRequestId()727 public void testUserSwitch_OEMRequest_failure_positiveRequestId() throws Exception { 728 int requestId = 4; 729 int targetUserId = 11; 730 VehiclePropValue propResponse = UserHalHelper.createPropRequest(SWITCH_USER, 731 requestId, SwitchUserMessageType.VEHICLE_REQUEST); 732 propResponse.value.int32Values.add(targetUserId); 733 734 mUserHalService.onHalEvents(Arrays.asList(propResponse)); 735 waitForHandler(); 736 737 verify(mCarUserService, never()).switchAndroidUserFromHal(anyInt(), anyInt()); 738 } 739 740 @Test testPostSwitchResponse_noHalSupported()741 public void testPostSwitchResponse_noHalSupported() { 742 // Cannot use mUserHalService because it's already set with supported properties 743 UserHalService myHalService = new UserHalService(mVehicleHal); 744 745 assertThrows(IllegalStateException.class, 746 () -> myHalService.postSwitchResponse(new SwitchUserRequest())); 747 } 748 749 @Test testPostSwitchResponse_nullRequest()750 public void testPostSwitchResponse_nullRequest() { 751 assertThrows(NullPointerException.class, () -> mUserHalService.postSwitchResponse(null)); 752 } 753 754 @Test testPostSwitchResponse_noUsersInfo()755 public void testPostSwitchResponse_noUsersInfo() { 756 SwitchUserRequest request = createUserSwitchRequest(mUser10, null); 757 request.requestId = 42; 758 assertThrows(IllegalArgumentException.class, 759 () -> mUserHalService.postSwitchResponse(request)); 760 } 761 762 @Test testPostSwitchResponse_HalCalledWithCorrectProp()763 public void testPostSwitchResponse_HalCalledWithCorrectProp() { 764 SwitchUserRequest request = createUserSwitchRequest(mUser10, mUsersInfo); 765 request.requestId = 42; 766 mUserHalService.postSwitchResponse(request); 767 ArgumentCaptor<VehiclePropValue> propCaptor = 768 ArgumentCaptor.forClass(VehiclePropValue.class); 769 verify(mVehicleHal).set(propCaptor.capture()); 770 VehiclePropValue prop = propCaptor.getValue(); 771 assertHalSetSwitchUserRequest(prop, SwitchUserMessageType.ANDROID_POST_SWITCH, mUser10); 772 } 773 774 @Test testLegacyUserSwitch_nullRequest()775 public void testLegacyUserSwitch_nullRequest() { 776 assertThrows(NullPointerException.class, () -> mUserHalService.legacyUserSwitch(null)); 777 } 778 779 @Test testLegacyUserSwitch_noMessageType()780 public void testLegacyUserSwitch_noMessageType() { 781 SwitchUserRequest request = new SwitchUserRequest(); 782 783 assertThrows(IllegalArgumentException.class, 784 () -> mUserHalService.legacyUserSwitch(request)); 785 } 786 787 @Test testLegacyUserSwitch_noTargetUserInfo()788 public void testLegacyUserSwitch_noTargetUserInfo() { 789 SwitchUserRequest request = new SwitchUserRequest(); 790 request.messageType = SwitchUserMessageType.ANDROID_SWITCH; 791 792 assertThrows(IllegalArgumentException.class, 793 () -> mUserHalService.legacyUserSwitch(request)); 794 } 795 796 @Test testRemoveUser_noHalSupported()797 public void testRemoveUser_noHalSupported() { 798 // Cannot use mUserHalService because it's already set with supported properties 799 UserHalService myHalService = new UserHalService(mVehicleHal); 800 801 assertThrows(IllegalStateException.class, 802 () -> myHalService.removeUser(new RemoveUserRequest())); 803 } 804 805 @Test testRemoveUser_nullRequest()806 public void testRemoveUser_nullRequest() { 807 RemoveUserRequest request = null; 808 809 assertThrows(NullPointerException.class, 810 () -> mUserHalService.removeUser(request)); 811 } 812 813 @Test testRemoveUser_noRequestId()814 public void testRemoveUser_noRequestId() { 815 RemoveUserRequest request = new RemoveUserRequest(); 816 817 assertThrows(IllegalArgumentException.class, 818 () -> mUserHalService.removeUser(request)); 819 } 820 821 @Test testRemoveUser_noRemovedUserInfo()822 public void testRemoveUser_noRemovedUserInfo() { 823 RemoveUserRequest request = new RemoveUserRequest(); 824 request.requestId = 1; 825 826 assertThrows(IllegalArgumentException.class, 827 () -> mUserHalService.removeUser(request)); 828 } 829 830 @Test testRemoveUser_noUsersInfo()831 public void testRemoveUser_noUsersInfo() { 832 RemoveUserRequest request = new RemoveUserRequest(); 833 request.requestId = 1; 834 request.removedUserInfo = mUser10; 835 836 assertThrows(IllegalArgumentException.class, 837 () -> mUserHalService.removeUser(request)); 838 } 839 840 @Test testRemoveUser_HalCalledWithCorrectProp()841 public void testRemoveUser_HalCalledWithCorrectProp() { 842 RemoveUserRequest request = new RemoveUserRequest(); 843 request.removedUserInfo = mUser10; 844 request.usersInfo = mUsersInfo; 845 ArgumentCaptor<VehiclePropValue> propCaptor = 846 ArgumentCaptor.forClass(VehiclePropValue.class); 847 848 mUserHalService.removeUser(request); 849 850 verify(mVehicleHal).set(propCaptor.capture()); 851 assertHalSetRemoveUserRequest(propCaptor.getValue(), mUser10); 852 } 853 854 @Test testLegacyUserSwitch_noHalSupported()855 public void testLegacyUserSwitch_noHalSupported() { 856 // Cannot use mUserHalService because it's already set with supported properties 857 UserHalService myHalService = new UserHalService(mVehicleHal); 858 859 assertThrows(IllegalStateException.class, 860 () -> myHalService.legacyUserSwitch(new SwitchUserRequest())); 861 } 862 863 @Test testLegacyUserSwitch_noUsersInfo()864 public void testLegacyUserSwitch_noUsersInfo() { 865 SwitchUserRequest request = new SwitchUserRequest(); 866 request.messageType = SwitchUserMessageType.ANDROID_SWITCH; 867 request.targetUser = mUser10; 868 869 assertThrows(IllegalArgumentException.class, 870 () -> mUserHalService.legacyUserSwitch(request)); 871 } 872 873 @Test testLegacyUserSwitch_HalCalledWithCorrectProp()874 public void testLegacyUserSwitch_HalCalledWithCorrectProp() { 875 SwitchUserRequest request = new SwitchUserRequest(); 876 request.messageType = SwitchUserMessageType.LEGACY_ANDROID_SWITCH; 877 request.targetUser = mUser10; 878 request.usersInfo = mUsersInfo; 879 880 mUserHalService.legacyUserSwitch(request); 881 ArgumentCaptor<VehiclePropValue> propCaptor = 882 ArgumentCaptor.forClass(VehiclePropValue.class); 883 verify(mVehicleHal).set(propCaptor.capture()); 884 VehiclePropValue prop = propCaptor.getValue(); 885 assertHalSetSwitchUserRequest(prop, SwitchUserMessageType.LEGACY_ANDROID_SWITCH, 886 mUser10); 887 } 888 889 @Test testCreateUser_noHalSupported()890 public void testCreateUser_noHalSupported() { 891 // Cannot use mUserHalService because it's already set with supported properties 892 UserHalService myHalService = new UserHalService(mVehicleHal); 893 894 assertThrows(IllegalStateException.class, 895 () -> myHalService.createUser(new CreateUserRequest(), HAL_TIMEOUT_MS, 896 noOpCallback())); 897 } 898 899 @Test testCreateUser_noRequest()900 public void testCreateUser_noRequest() { 901 assertThrows(NullPointerException.class, () -> mUserHalService 902 .createUser(null, HAL_TIMEOUT_MS, noOpCallback())); 903 } 904 905 @Test testCreateUser_invalidTimeout()906 public void testCreateUser_invalidTimeout() { 907 assertThrows(IllegalArgumentException.class, () -> mUserHalService 908 .createUser(new CreateUserRequest(), 0, noOpCallback())); 909 assertThrows(IllegalArgumentException.class, () -> mUserHalService 910 .createUser(new CreateUserRequest(), -1, noOpCallback())); 911 } 912 913 @Test testCreateUser_noCallback()914 public void testCreateUser_noCallback() { 915 CreateUserRequest request = new CreateUserRequest(); 916 request.newUserInfo.userId = 10; 917 request.usersInfo.existingUsers.add(request.newUserInfo); 918 919 assertThrows(NullPointerException.class, () -> mUserHalService 920 .createUser(request, HAL_TIMEOUT_MS, null)); 921 } 922 923 /** 924 * Creates a valid {@link CreateUserRequest} for tests that doesn't check its contents. 925 */ 926 @NonNull newValidCreateUserRequest()927 private CreateUserRequest newValidCreateUserRequest() { 928 CreateUserRequest request = new CreateUserRequest(); 929 request.newUserInfo = mUser10; 930 request.usersInfo = mUsersInfo; 931 return request; 932 } 933 934 @Test testCreateUser_halSetTimedOut()935 public void testCreateUser_halSetTimedOut() throws Exception { 936 replySetPropertyWithTimeoutException(CREATE_USER); 937 938 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 939 CALLBACK_TIMEOUT); 940 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 941 callback); 942 943 callback.assertCalled(); 944 assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT); 945 assertThat(callback.response).isNull(); 946 947 // Make sure the pending request was removed 948 SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS); 949 callback.assertNotCalledAgain(); 950 } 951 952 @Test testCreateUser_halDidNotReply()953 public void testCreateUser_halDidNotReply() throws Exception { 954 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 955 CALLBACK_TIMEOUT); 956 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 957 callback); 958 959 callback.assertCalled(); 960 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 961 assertThat(callback.response).isNull(); 962 } 963 964 @Test testCreateUser_halReplyWithWrongRequestId()965 public void testCreateUser_halReplyWithWrongRequestId() throws Exception { 966 VehiclePropValue propResponse = 967 UserHalHelper.createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER); 968 969 replySetPropertyWithOnChangeEvent(CREATE_USER, propResponse, 970 /* rightRequestId= */ false); 971 972 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 973 CALLBACK_TIMEOUT); 974 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 975 callback); 976 977 callback.assertCalled(); 978 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 979 assertThat(callback.response).isNull(); 980 } 981 982 @Test testCreateUser_success()983 public void testCreateUser_success() throws Exception { 984 VehiclePropValue propResponse = 985 UserHalHelper.createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER); 986 propResponse.value.int32Values.add(CreateUserStatus.SUCCESS); 987 988 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 989 CREATE_USER, propResponse, /* rightRequestId= */ true); 990 991 CreateUserRequest request = new CreateUserRequest(); 992 request.newUserInfo = mUser10; 993 request.usersInfo = mUsersInfo; 994 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 995 CALLBACK_TIMEOUT); 996 mUserHalService.createUser(request, HAL_TIMEOUT_MS, callback); 997 998 callback.assertCalled(); 999 1000 // Make sure the arguments were properly converted 1001 assertHalSetCreateUserRequest(reqCaptor.get(), request); 1002 1003 // Assert response 1004 assertCallbackStatus(callback, HalCallback.STATUS_OK); 1005 CreateUserResponse actualResponse = callback.response; 1006 assertThat(actualResponse.status).isEqualTo(CreateUserStatus.SUCCESS); 1007 assertThat(actualResponse.errorMessage).isEmpty(); 1008 } 1009 1010 @Test testCreateUser_failure()1011 public void testCreateUser_failure() throws Exception { 1012 VehiclePropValue propResponse = 1013 UserHalHelper.createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER); 1014 propResponse.value.int32Values.add(CreateUserStatus.FAILURE); 1015 propResponse.value.stringValue = "D'OH!"; 1016 1017 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 1018 CREATE_USER, propResponse, /* rightRequestId= */ true); 1019 1020 CreateUserRequest request = new CreateUserRequest(); 1021 request.newUserInfo = mUser10; 1022 request.usersInfo = mUsersInfo; 1023 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 1024 CALLBACK_TIMEOUT); 1025 mUserHalService.createUser(request, HAL_TIMEOUT_MS, callback); 1026 1027 callback.assertCalled(); 1028 1029 // Make sure the arguments were properly converted 1030 assertHalSetCreateUserRequest(reqCaptor.get(), request); 1031 1032 // Assert response 1033 assertCallbackStatus(callback, HalCallback.STATUS_OK); 1034 CreateUserResponse actualResponse = callback.response; 1035 assertThat(actualResponse.status).isEqualTo(CreateUserStatus.FAILURE); 1036 assertThat(actualResponse.errorMessage).isEqualTo("D'OH!"); 1037 } 1038 1039 @Test testCreateUser_secondCallFailWhilePending()1040 public void testCreateUser_secondCallFailWhilePending() throws Exception { 1041 GenericHalCallback<CreateUserResponse> callback1 = new GenericHalCallback<>( 1042 CALLBACK_TIMEOUT); 1043 GenericHalCallback<CreateUserResponse> callback2 = new GenericHalCallback<>( 1044 CALLBACK_TIMEOUT); 1045 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, 1046 callback1); 1047 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_MS, callback2); 1048 1049 callback1.assertCalled(); 1050 assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 1051 assertThat(callback1.response).isNull(); 1052 1053 callback2.assertCalled(); 1054 assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION); 1055 assertThat(callback1.response).isNull(); 1056 } 1057 1058 @Test testCreateUser_halReturnedInvalidStatus()1059 public void testCreateUser_halReturnedInvalidStatus() throws Exception { 1060 VehiclePropValue propResponse = 1061 UserHalHelper.createPropRequest(CREATE_USER, REQUEST_ID_PLACE_HOLDER); 1062 propResponse.value.int32Values.add(/*status =*/ -1); // an invalid status 1063 1064 AtomicReference<VehiclePropValue> reqCaptor = replySetPropertyWithOnChangeEvent( 1065 CREATE_USER, propResponse, /* rightRequestId= */ true); 1066 1067 GenericHalCallback<CreateUserResponse> callback = new GenericHalCallback<>( 1068 CALLBACK_TIMEOUT); 1069 mUserHalService.createUser(newValidCreateUserRequest(), HAL_TIMEOUT_MS, callback); 1070 1071 callback.assertCalled(); 1072 1073 // Assert response 1074 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 1075 assertThat(callback.response).isNull(); 1076 } 1077 1078 @Test testGetUserAssociation_noHalSupported()1079 public void testGetUserAssociation_noHalSupported() { 1080 // Cannot use mUserHalService because it's already set with supported properties 1081 UserHalService myHalService = new UserHalService(mVehicleHal); 1082 1083 assertThrows(IllegalStateException.class, 1084 () -> myHalService.getUserAssociation(new UserIdentificationGetRequest())); 1085 } 1086 1087 @Test testGetUserAssociation_nullRequest()1088 public void testGetUserAssociation_nullRequest() { 1089 assertThrows(NullPointerException.class, () -> mUserHalService.getUserAssociation(null)); 1090 } 1091 1092 @Test testGetUserAssociation_requestWithDuplicatedTypes()1093 public void testGetUserAssociation_requestWithDuplicatedTypes() { 1094 UserIdentificationGetRequest request = new UserIdentificationGetRequest(); 1095 request.numberAssociationTypes = 2; 1096 request.associationTypes.add(KEY_FOB); 1097 request.associationTypes.add(KEY_FOB); 1098 1099 assertThrows(IllegalArgumentException.class, 1100 () -> mUserHalService.getUserAssociation(request)); 1101 } 1102 1103 @Test testGetUserAssociation_invalidResponse()1104 public void testGetUserAssociation_invalidResponse() { 1105 VehiclePropValue propResponse = new VehiclePropValue(); 1106 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1107 propResponse.value.int32Values.add(DEFAULT_REQUEST_ID); 1108 propResponse.value.int32Values.add(1); // 1 associations 1109 propResponse.value.int32Values.add(KEY_FOB); // type only, it's missing value 1110 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1111 propResponse); 1112 1113 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1114 } 1115 1116 @Test testGetUserAssociation_nullResponse()1117 public void testGetUserAssociation_nullResponse() { 1118 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest(null); 1119 1120 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1121 1122 verifyValidGetUserIdentificationRequestMade(); 1123 } 1124 1125 @Test testGetUserAssociation_wrongNumberOfAssociationsOnResponse()1126 public void testGetUserAssociation_wrongNumberOfAssociationsOnResponse() { 1127 VehiclePropValue propResponse = new VehiclePropValue(); 1128 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1129 propResponse.value.int32Values.add(DEFAULT_REQUEST_ID); 1130 propResponse.value.int32Values.add(2); // 2 associations 1131 propResponse.value.int32Values.add(KEY_FOB); 1132 propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER); 1133 propResponse.value.int32Values.add(CUSTOM_1); 1134 propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER); 1135 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1136 propResponse); 1137 1138 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1139 1140 verifyValidGetUserIdentificationRequestMade(); 1141 } 1142 1143 @Test testGetUserAssociation_typesOnResponseMismatchTypesOnRequest()1144 public void testGetUserAssociation_typesOnResponseMismatchTypesOnRequest() { 1145 VehiclePropValue propResponse = new VehiclePropValue(); 1146 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1147 propResponse.value.int32Values.add(DEFAULT_REQUEST_ID); 1148 propResponse.value.int32Values.add(1); // 1 association 1149 propResponse.value.int32Values.add(CUSTOM_1); 1150 propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER); 1151 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1152 propResponse); 1153 1154 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1155 1156 verifyValidGetUserIdentificationRequestMade(); 1157 } 1158 1159 @Test testGetUserAssociation_requestIdMismatch()1160 public void testGetUserAssociation_requestIdMismatch() { 1161 VehiclePropValue propResponse = new VehiclePropValue(); 1162 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1163 propResponse.value.int32Values.add(DEFAULT_REQUEST_ID + 1); 1164 propResponse.value.int32Values.add(1); // 1 association 1165 propResponse.value.int32Values.add(KEY_FOB); 1166 propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER); 1167 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1168 propResponse); 1169 1170 assertThat(mUserHalService.getUserAssociation(request)).isNull(); 1171 1172 verifyValidGetUserIdentificationRequestMade(); 1173 } 1174 1175 @Test testGetUserAssociation_ok()1176 public void testGetUserAssociation_ok() { 1177 VehiclePropValue propResponse = new VehiclePropValue(); 1178 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1179 propResponse.value.int32Values.add(DEFAULT_REQUEST_ID); 1180 propResponse.value.int32Values.add(1); // 1 association 1181 propResponse.value.int32Values.add(KEY_FOB); 1182 propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER); 1183 UserIdentificationGetRequest request = replyToValidGetUserIdentificationRequest( 1184 propResponse); 1185 1186 UserIdentificationResponse response = mUserHalService.getUserAssociation(request); 1187 1188 assertThat(response.requestId).isEqualTo(DEFAULT_REQUEST_ID); 1189 assertThat(response.numberAssociation).isEqualTo(1); 1190 assertThat(response.associations).hasSize(1); 1191 UserIdentificationAssociation actualAssociation = response.associations.get(0); 1192 assertThat(actualAssociation.type).isEqualTo(KEY_FOB); 1193 assertThat(actualAssociation.value).isEqualTo(ASSOCIATED_CURRENT_USER); 1194 } 1195 1196 @Test testSetUserAssociation_noHalSupported()1197 public void testSetUserAssociation_noHalSupported() { 1198 // Cannot use mUserHalService because it's already set with supported properties 1199 UserHalService myHalService = new UserHalService(mVehicleHal); 1200 1201 assertThrows(IllegalStateException.class, 1202 () -> myHalService.setUserAssociation(HAL_TIMEOUT_MS, 1203 new UserIdentificationSetRequest(), noOpCallback())); 1204 } 1205 1206 @Test testSetUserAssociation_invalidTimeout()1207 public void testSetUserAssociation_invalidTimeout() { 1208 UserIdentificationSetRequest request = new UserIdentificationSetRequest(); 1209 assertThrows(IllegalArgumentException.class, () -> 1210 mUserHalService.setUserAssociation(0, request, noOpCallback())); 1211 assertThrows(IllegalArgumentException.class, () -> 1212 mUserHalService.setUserAssociation(-1, request, noOpCallback())); 1213 } 1214 1215 @Test testSetUserAssociation_nullRequest()1216 public void testSetUserAssociation_nullRequest() { 1217 assertThrows(NullPointerException.class, () -> 1218 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, null, noOpCallback())); 1219 } 1220 1221 @Test testSetUserAssociation_nullCallback()1222 public void testSetUserAssociation_nullCallback() { 1223 UserIdentificationSetRequest request = new UserIdentificationSetRequest(); 1224 assertThrows(NullPointerException.class, () -> 1225 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, null)); 1226 } 1227 1228 @Test testSetUserAssociation_requestWithDuplicatedTypes()1229 public void testSetUserAssociation_requestWithDuplicatedTypes() { 1230 UserIdentificationSetRequest request = new UserIdentificationSetRequest(); 1231 request.numberAssociations = 2; 1232 UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation(); 1233 association1.type = KEY_FOB; 1234 association1.value = ASSOCIATE_CURRENT_USER; 1235 request.associations.add(association1); 1236 request.associations.add(association1); 1237 1238 assertThrows(IllegalArgumentException.class, () -> 1239 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, noOpCallback())); 1240 } 1241 1242 @Test testSetUserAssociation_halSetTimedOut()1243 public void testSetUserAssociation_halSetTimedOut() throws Exception { 1244 UserIdentificationSetRequest request = validUserIdentificationSetRequest(); 1245 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1246 CALLBACK_TIMEOUT); 1247 replySetPropertyWithTimeoutException(USER_IDENTIFICATION_ASSOCIATION); 1248 1249 mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback); 1250 1251 callback.assertCalled(); 1252 assertCallbackStatus(callback, HalCallback.STATUS_HAL_SET_TIMEOUT); 1253 assertThat(callback.response).isNull(); 1254 1255 // Make sure the pending request was removed 1256 SystemClock.sleep(WAITING_TIME_FOR_NEGATIVE_TESTS_MS); 1257 callback.assertNotCalledAgain(); 1258 } 1259 1260 @Test testSetUserAssociation_halDidNotReply()1261 public void testSetUserAssociation_halDidNotReply() throws Exception { 1262 UserIdentificationSetRequest request = validUserIdentificationSetRequest(); 1263 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1264 CALLBACK_TIMEOUT); 1265 1266 mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback); 1267 1268 callback.assertCalled(); 1269 assertCallbackStatus(callback, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 1270 assertThat(callback.response).isNull(); 1271 } 1272 1273 @Test testSetUserAssociation_secondCallFailWhilePending()1274 public void testSetUserAssociation_secondCallFailWhilePending() throws Exception { 1275 UserIdentificationSetRequest request = validUserIdentificationSetRequest(); 1276 GenericHalCallback<UserIdentificationResponse> callback1 = new GenericHalCallback<>( 1277 CALLBACK_TIMEOUT); 1278 GenericHalCallback<UserIdentificationResponse> callback2 = new GenericHalCallback<>( 1279 CALLBACK_TIMEOUT); 1280 1281 mUserHalService.setUserAssociation(HAL_TIMEOUT_FOR_NEGATIVE_TESTS_MS, request, callback1); 1282 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback2); 1283 1284 callback1.assertCalled(); 1285 assertCallbackStatus(callback1, HalCallback.STATUS_HAL_RESPONSE_TIMEOUT); 1286 assertThat(callback1.response).isNull(); 1287 1288 callback2.assertCalled(); 1289 assertCallbackStatus(callback2, HalCallback.STATUS_CONCURRENT_OPERATION); 1290 assertThat(callback1.response).isNull(); 1291 } 1292 1293 @Test testSetUserAssociation_responseWithWrongRequestId()1294 public void testSetUserAssociation_responseWithWrongRequestId() throws Exception { 1295 VehiclePropValue propResponse = new VehiclePropValue(); 1296 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1297 propResponse.value.int32Values.add(DEFAULT_REQUEST_ID + 1); 1298 AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent( 1299 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true); 1300 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1301 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1302 CALLBACK_TIMEOUT); 1303 1304 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback); 1305 1306 // Assert request 1307 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1308 // Assert response 1309 callback.assertCalled(); 1310 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 1311 assertThat(callback.response).isNull(); 1312 } 1313 1314 @Test testSetUserAssociation_notEnoughValuesOnResponse()1315 public void testSetUserAssociation_notEnoughValuesOnResponse() throws Exception { 1316 VehiclePropValue propResponse = new VehiclePropValue(); 1317 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1318 // need at least 4: requestId, number associations, type1, value1 1319 propResponse.value.int32Values.add(1); 1320 propResponse.value.int32Values.add(2); 1321 propResponse.value.int32Values.add(3); 1322 1323 AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent( 1324 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true); 1325 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1326 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1327 CALLBACK_TIMEOUT); 1328 1329 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback); 1330 1331 // Assert request 1332 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1333 // Assert response 1334 callback.assertCalled(); 1335 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 1336 assertThat(callback.response).isNull(); 1337 } 1338 1339 @Test testSetUserAssociation_wrongNumberOfAssociationsOnResponse()1340 public void testSetUserAssociation_wrongNumberOfAssociationsOnResponse() throws Exception { 1341 VehiclePropValue propResponse = new VehiclePropValue(); 1342 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1343 propResponse.value.int32Values.add(DEFAULT_REQUEST_ID); 1344 propResponse.value.int32Values.add(2); // 2 associations; request is just 1 1345 propResponse.value.int32Values.add(KEY_FOB); 1346 propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER); 1347 propResponse.value.int32Values.add(CUSTOM_1); 1348 propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER); 1349 1350 AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent( 1351 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true); 1352 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1353 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1354 CALLBACK_TIMEOUT); 1355 1356 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback); 1357 1358 // Assert request 1359 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1360 // Assert response 1361 callback.assertCalled(); 1362 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 1363 assertThat(callback.response).isNull(); 1364 } 1365 1366 @Test testSetUserAssociation_typeMismatchOnResponse()1367 public void testSetUserAssociation_typeMismatchOnResponse() throws Exception { 1368 VehiclePropValue propResponse = new VehiclePropValue(); 1369 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1370 propResponse.value.int32Values.add(DEFAULT_REQUEST_ID); 1371 propResponse.value.int32Values.add(1); // 1 association 1372 propResponse.value.int32Values.add(CUSTOM_1); // request is KEY_FOB 1373 propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER); 1374 1375 AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent( 1376 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true); 1377 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1378 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1379 CALLBACK_TIMEOUT); 1380 1381 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback); 1382 1383 // Assert request 1384 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1385 // Assert response 1386 callback.assertCalled(); 1387 assertCallbackStatus(callback, HalCallback.STATUS_WRONG_HAL_RESPONSE); 1388 assertThat(callback.response).isNull(); 1389 } 1390 1391 @Test testSetUserAssociation_ok()1392 public void testSetUserAssociation_ok() throws Exception { 1393 VehiclePropValue propResponse = new VehiclePropValue(); 1394 propResponse.prop = USER_IDENTIFICATION_ASSOCIATION; 1395 propResponse.value.int32Values.add(DEFAULT_REQUEST_ID); 1396 propResponse.value.int32Values.add(1); // 1 association 1397 propResponse.value.int32Values.add(KEY_FOB); 1398 propResponse.value.int32Values.add(ASSOCIATED_CURRENT_USER); 1399 1400 AtomicReference<VehiclePropValue> propRequest = replySetPropertyWithOnChangeEvent( 1401 USER_IDENTIFICATION_ASSOCIATION, propResponse, /* rightRequestId= */ true); 1402 UserIdentificationSetRequest request = replyToValidSetUserIdentificationRequest(); 1403 GenericHalCallback<UserIdentificationResponse> callback = new GenericHalCallback<>( 1404 CALLBACK_TIMEOUT); 1405 1406 mUserHalService.setUserAssociation(HAL_TIMEOUT_MS, request, callback); 1407 1408 // Assert request 1409 verifyValidSetUserIdentificationRequestMade(propRequest.get()); 1410 // Assert response 1411 callback.assertCalled(); 1412 assertCallbackStatus(callback, HalCallback.STATUS_OK); 1413 1414 UserIdentificationResponse actualResponse = callback.response; 1415 1416 assertThat(actualResponse.requestId).isEqualTo(DEFAULT_REQUEST_ID); 1417 assertThat(actualResponse.numberAssociation).isEqualTo(1); 1418 assertThat(actualResponse.associations).hasSize(1); 1419 UserIdentificationAssociation actualAssociation = actualResponse.associations.get(0); 1420 assertThat(actualAssociation.type).isEqualTo(KEY_FOB); 1421 assertThat(actualAssociation.value).isEqualTo(ASSOCIATED_CURRENT_USER); 1422 } 1423 1424 /** 1425 * Asserts the given {@link UsersInfo} is properly represented in the {@link VehiclePropValue}. 1426 * 1427 * @param value property containing the info 1428 * @param info info to be checked 1429 * @param initialIndex first index of the info values in the property's {@code int32Values} 1430 */ assertUsersInfo(VehiclePropValue value, UsersInfo info, int initialIndex)1431 private void assertUsersInfo(VehiclePropValue value, UsersInfo info, int initialIndex) { 1432 // TODO: consider using UserHalHelper to convert the property into a specific request, 1433 // and compare the request's UsersInfo. 1434 // But such method is not needed in production code yet. 1435 ArrayList<Integer> values = value.value.int32Values; 1436 assertWithMessage("wrong values size").that(values) 1437 .hasSize(initialIndex + 3 + info.numberUsers * 2); 1438 1439 int i = initialIndex; 1440 assertWithMessage("currentUser.id mismatch at index %s", i).that(values.get(i)) 1441 .isEqualTo(info.currentUser.userId); 1442 i++; 1443 assertWithMessage("currentUser.flags mismatch at index %s", i).that(values.get(i)) 1444 .isEqualTo(info.currentUser.flags); 1445 i++; 1446 assertWithMessage("numberUsers mismatch at index %s", i).that(values.get(i)) 1447 .isEqualTo(info.numberUsers); 1448 i++; 1449 1450 for (int j = 0; j < info.numberUsers; j++) { 1451 int actualUserId = values.get(i++); 1452 int actualUserFlags = values.get(i++); 1453 UserInfo expectedUser = info.existingUsers.get(j); 1454 assertWithMessage("wrong id for existing user#%s at index %s", j, i) 1455 .that(actualUserId).isEqualTo(expectedUser.userId); 1456 assertWithMessage("wrong flags for existing user#%s at index %s", j, i) 1457 .that(actualUserFlags).isEqualTo(expectedUser.flags); 1458 } 1459 } 1460 1461 /** 1462 * Sets the VHAL mock to emulate a property change event upon a call to set a property. 1463 * 1464 * @param prop prop to be set 1465 * @param response response to be set on event 1466 * @param rightRequestId whether the response id should match the request 1467 * @return 1468 * 1469 * @return reference to the value passed to {@code set()}. 1470 */ replySetPropertyWithOnChangeEvent(int prop, VehiclePropValue response, boolean rightRequestId)1471 private AtomicReference<VehiclePropValue> replySetPropertyWithOnChangeEvent(int prop, 1472 VehiclePropValue response, boolean rightRequestId) throws Exception { 1473 AtomicReference<VehiclePropValue> ref = new AtomicReference<>(); 1474 doAnswer((inv) -> { 1475 VehiclePropValue request = inv.getArgument(0); 1476 ref.set(request); 1477 int requestId = request.value.int32Values.get(0); 1478 int responseId = rightRequestId ? requestId : requestId + 1000; 1479 response.value.int32Values.set(0, responseId); 1480 Log.d(TAG, "replySetPropertyWithOnChangeEvent(): resp=" + response + " for req=" 1481 + request); 1482 mUserHalService.onHalEvents(Arrays.asList(response)); 1483 return null; 1484 }).when(mVehicleHal).set(isProperty(prop)); 1485 return ref; 1486 } 1487 1488 /** 1489 * Sets the VHAL mock to emulate a property timeout exception upon a call to set a property. 1490 */ replySetPropertyWithTimeoutException(int prop)1491 private void replySetPropertyWithTimeoutException(int prop) throws Exception { 1492 doThrow(new ServiceSpecificException(VehicleHalStatusCode.STATUS_TRY_AGAIN, 1493 "PropId: 0x" + Integer.toHexString(prop))).when(mVehicleHal).set(isProperty(prop)); 1494 } 1495 1496 @NonNull createUserSwitchRequest(@onNull UserInfo targetUser, @NonNull UsersInfo usersInfo)1497 private SwitchUserRequest createUserSwitchRequest(@NonNull UserInfo targetUser, 1498 @NonNull UsersInfo usersInfo) { 1499 SwitchUserRequest request = new SwitchUserRequest(); 1500 request.targetUser = targetUser; 1501 request.usersInfo = usersInfo; 1502 return request; 1503 } 1504 1505 /** 1506 * Creates and set expectations for a valid request. 1507 */ replyToValidGetUserIdentificationRequest( @onNull VehiclePropValue response)1508 private UserIdentificationGetRequest replyToValidGetUserIdentificationRequest( 1509 @NonNull VehiclePropValue response) { 1510 mockNextRequestId(DEFAULT_REQUEST_ID); 1511 1512 UserIdentificationGetRequest request = new UserIdentificationGetRequest(); 1513 request.userInfo.userId = DEFAULT_USER_ID; 1514 request.userInfo.flags = DEFAULT_USER_FLAGS; 1515 request.numberAssociationTypes = 1; 1516 request.associationTypes.add(KEY_FOB); 1517 1518 when(mVehicleHal.get(isPropertyWithValues(USER_IDENTIFICATION_ASSOCIATION, 1519 DEFAULT_REQUEST_ID, DEFAULT_USER_ID, DEFAULT_USER_FLAGS, 1520 /* numberAssociations= */ 1, KEY_FOB))) 1521 .thenReturn(response); 1522 1523 return request; 1524 } 1525 1526 /** 1527 * Creates and set expectations for a valid request. 1528 */ replyToValidSetUserIdentificationRequest()1529 private UserIdentificationSetRequest replyToValidSetUserIdentificationRequest() { 1530 mockNextRequestId(DEFAULT_REQUEST_ID); 1531 return validUserIdentificationSetRequest(); 1532 } 1533 1534 /** 1535 * Creates a valid request that can be used in test cases where its content is not asserted. 1536 */ validUserIdentificationSetRequest()1537 private UserIdentificationSetRequest validUserIdentificationSetRequest() { 1538 UserIdentificationSetRequest request = new UserIdentificationSetRequest(); 1539 request.userInfo.userId = DEFAULT_USER_ID; 1540 request.userInfo.flags = DEFAULT_USER_FLAGS; 1541 request.numberAssociations = 1; 1542 UserIdentificationSetAssociation association1 = new UserIdentificationSetAssociation(); 1543 association1.type = KEY_FOB; 1544 association1.value = ASSOCIATE_CURRENT_USER; 1545 request.associations.add(association1); 1546 return request; 1547 } 1548 1549 /** 1550 * Run empty runnable to make sure that all posted handlers are done. 1551 */ waitForHandler()1552 private void waitForHandler() { 1553 mHandler.runWithScissors(() -> { }, /* Default timeout */ CALLBACK_TIMEOUT); 1554 } 1555 mockNextRequestId(int requestId)1556 private void mockNextRequestId(int requestId) { 1557 doReturn(requestId).when(mUserHalService).getNextRequestId(); 1558 } 1559 assertInitialUserInfoSetRequest(VehiclePropValue req, int requestType)1560 private void assertInitialUserInfoSetRequest(VehiclePropValue req, int requestType) { 1561 assertThat(req.value.int32Values.get(1)).isEqualTo(requestType); 1562 assertUsersInfo(req, mUsersInfo, 2); 1563 } 1564 assertHalSetSwitchUserRequest(VehiclePropValue req, int messageType, UserInfo targetUserInfo)1565 private void assertHalSetSwitchUserRequest(VehiclePropValue req, int messageType, 1566 UserInfo targetUserInfo) { 1567 assertThat(req.prop).isEqualTo(SWITCH_USER); 1568 assertWithMessage("wrong request Id on %s", req).that(req.value.int32Values.get(0)) 1569 .isAtLeast(1); 1570 assertThat(req.value.int32Values.get(1)).isEqualTo(messageType); 1571 assertWithMessage("targetuser.id mismatch on %s", req).that(req.value.int32Values.get(2)) 1572 .isEqualTo(targetUserInfo.userId); 1573 assertWithMessage("targetuser.flags mismatch on %s", req).that(req.value.int32Values.get(3)) 1574 .isEqualTo(targetUserInfo.flags); 1575 assertUsersInfo(req, mUsersInfo, 4); 1576 } 1577 assertHalSetRemoveUserRequest(VehiclePropValue req, UserInfo userInfo)1578 private void assertHalSetRemoveUserRequest(VehiclePropValue req, UserInfo userInfo) { 1579 assertThat(req.prop).isEqualTo(REMOVE_USER); 1580 assertWithMessage("wrong request Id on %s", req).that(req.value.int32Values.get(0)) 1581 .isAtLeast(1); 1582 assertWithMessage("user.id mismatch on %s", req).that(req.value.int32Values.get(1)) 1583 .isEqualTo(userInfo.userId); 1584 assertWithMessage("user.flags mismatch on %s", req).that(req.value.int32Values.get(2)) 1585 .isEqualTo(userInfo.flags); 1586 assertUsersInfo(req, mUsersInfo, 3); 1587 } 1588 assertHalSetCreateUserRequest(VehiclePropValue prop, CreateUserRequest request)1589 private void assertHalSetCreateUserRequest(VehiclePropValue prop, CreateUserRequest request) { 1590 assertThat(prop.prop).isEqualTo(CREATE_USER); 1591 assertWithMessage("wrong request Id on %s", prop).that(prop.value.int32Values.get(0)) 1592 .isEqualTo(request.requestId); 1593 assertWithMessage("newUser.userId mismatch on %s", prop).that(prop.value.int32Values.get(1)) 1594 .isEqualTo(request.newUserInfo.userId); 1595 assertWithMessage("newUser.flags mismatch on %s", prop).that(prop.value.int32Values.get(2)) 1596 .isEqualTo(request.newUserInfo.flags); 1597 assertUsersInfo(prop, request.usersInfo, 3); 1598 } 1599 assertCallbackStatus(GenericHalCallback<?> callback, int expectedStatus)1600 private void assertCallbackStatus(GenericHalCallback<?> callback, int expectedStatus) { 1601 int actualStatus = callback.status; 1602 if (actualStatus == expectedStatus) return; 1603 1604 fail("Wrong callback status; expected " 1605 + UserHalHelper.halCallbackStatusToString(expectedStatus) + ", got " 1606 + UserHalHelper.halCallbackStatusToString(actualStatus)); 1607 } 1608 1609 /** 1610 * Verifies {@code hal.get()} was called with the values used on 1611 * {@link #replyToValidGetUserIdentificationRequest(VehiclePropValue)}. 1612 */ verifyValidGetUserIdentificationRequestMade()1613 private void verifyValidGetUserIdentificationRequestMade() { 1614 verify(mVehicleHal).get(isPropertyWithValues(USER_IDENTIFICATION_ASSOCIATION, 1615 DEFAULT_REQUEST_ID, DEFAULT_USER_ID, DEFAULT_USER_FLAGS, 1616 /* numberAssociations= */ 1, KEY_FOB)); 1617 } 1618 1619 /** 1620 * Verifies {@code hal.set()} was called with the values used on 1621 * {@link #replyToValidSetUserIdentificationRequest(VehiclePropValue)}. 1622 */ verifyValidSetUserIdentificationRequestMade(@onNull VehiclePropValue request)1623 private void verifyValidSetUserIdentificationRequestMade(@NonNull VehiclePropValue request) { 1624 assertThat(request.prop).isEqualTo(USER_IDENTIFICATION_ASSOCIATION); 1625 assertThat(request.value.int32Values).containsExactly(DEFAULT_REQUEST_ID, DEFAULT_USER_ID, 1626 DEFAULT_USER_FLAGS, 1627 /* numberAssociations= */ 1, KEY_FOB, ASSOCIATE_CURRENT_USER); 1628 } 1629 noOpCallback()1630 private static <T> HalCallback<T> noOpCallback() { 1631 return (i, r) -> { }; 1632 } 1633 1634 private final class GenericHalCallback<R> implements HalCallback<R> { 1635 1636 private final CountDownLatch mLatch = new CountDownLatch(1); 1637 private final int mTimeout; 1638 private final List<Pair<Integer, R>> mExtraCalls = new ArrayList<>(); 1639 1640 public int status; 1641 public R response; 1642 GenericHalCallback(int timeout)1643 GenericHalCallback(int timeout) { 1644 this.mTimeout = timeout; 1645 } 1646 1647 @Override onResponse(int status, R response)1648 public void onResponse(int status, R response) { 1649 Log.d(TAG, "onResponse(): status=" + status + ", response=" + response); 1650 if (mLatch.getCount() == 0) { 1651 Log.e(TAG, "Already responded"); 1652 mExtraCalls.add(new Pair<>(status, response)); 1653 return; 1654 } 1655 this.status = status; 1656 this.response = response; 1657 mLatch.countDown(); 1658 } 1659 1660 /** 1661 * Asserts that the callback was called, or fail if it timed out. 1662 */ assertCalled()1663 public void assertCalled() throws InterruptedException { 1664 Log.d(TAG, "assertCalled(): waiting " + mTimeout + "ms"); 1665 if (!mLatch.await(mTimeout, TimeUnit.MILLISECONDS)) { 1666 throw new AssertionError("callback not called in " + mTimeout + "ms"); 1667 } 1668 } 1669 1670 /** 1671 * Asserts that the callback was not called more than once. 1672 */ assertNotCalledAgain()1673 public void assertNotCalledAgain() { 1674 if (mExtraCalls.isEmpty()) return; 1675 throw new AssertionError("Called " + mExtraCalls.size() + " times more than expected: " 1676 + mExtraCalls); 1677 } 1678 } 1679 }