1 /* <lambda>null2 * Copyright (C) 2024 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.bedstead.multiuser 17 18 import android.os.Process 19 import android.os.UserHandle 20 import com.android.bedstead.harrier.BedsteadJUnit4 21 import com.android.bedstead.harrier.DeviceState 22 import com.android.bedstead.harrier.annotations.EnsureHasNoSecondaryUser 23 import com.android.bedstead.multiuser.annotations.EnsureCanAddUser 24 import com.android.bedstead.multiuser.annotations.EnsureHasCloneProfile 25 import com.android.bedstead.multiuser.annotations.EnsureHasNoCloneProfile 26 import com.android.bedstead.multiuser.annotations.EnsureHasSecondaryUser 27 import com.android.bedstead.multiuser.annotations.RequireHeadlessSystemUserMode 28 import com.android.bedstead.multiuser.annotations.RequireRunNotOnSecondaryUser 29 import com.android.bedstead.multiuser.annotations.RequireRunOnPrimaryUser 30 import com.android.bedstead.multiuser.annotations.RequireRunOnSecondaryUser 31 import com.android.bedstead.nene.TestApis 32 import com.android.bedstead.nene.exceptions.NeneException 33 import com.android.bedstead.nene.types.OptionalBoolean 34 import com.android.bedstead.nene.users.UserReference 35 import com.android.bedstead.nene.users.UserType 36 import com.android.bedstead.nene.utils.Poll 37 import com.google.common.truth.Truth.assertThat 38 import org.junit.Assert.assertThrows 39 import org.junit.ClassRule 40 import org.junit.Ignore 41 import org.junit.Rule 42 import org.junit.Test 43 import org.junit.runner.RunWith 44 45 @RunWith(BedsteadJUnit4::class) 46 class UsersTest { 47 48 private val mSecondaryUserType = TestApis 49 .users() 50 .supportedType(UserType.SECONDARY_USER_TYPE_NAME) 51 private val mCloneProfileType = TestApis 52 .users() 53 .supportedType(UserType.CLONE_PROFILE_TYPE_NAME) 54 private val mInstrumentedUser = TestApis 55 .users() 56 .instrumented() 57 58 @Test 59 fun supportedTypes_containsSystemUser() { 60 val systemUserType = TestApis 61 .users() 62 .supportedTypes() 63 .first { ut: UserType -> ut.name() == UserType.SYSTEM_USER_TYPE_NAME } 64 65 assertThat(systemUserType.baseType()) 66 .containsExactly(UserType.BaseType.SYSTEM, UserType.BaseType.FULL) 67 assertThat(systemUserType.enabled()).isTrue() 68 assertThat(systemUserType.maxAllowed()).isEqualTo(MAX_SYSTEM_USERS) 69 assertThat( 70 systemUserType.maxAllowedPerParent() 71 ).isEqualTo(MAX_SYSTEM_USERS_PER_PARENT) 72 } 73 74 @Test 75 fun supportedType_invalidType_returnsNull() { 76 assertThat(TestApis.users().supportedType(INVALID_TYPE_NAME)).isNull() 77 } 78 79 @Test 80 @EnsureCanAddUser 81 fun all_containsCreatedUser() { 82 val user = TestApis.users().createUser().create() 83 84 try { 85 assertThat(TestApis.users().all()).contains(user) 86 } finally { 87 user.remove() 88 } 89 } 90 91 @Test 92 @EnsureCanAddUser(number = 2) 93 fun all_userAddedSinceLastCallToUsers_containsNewUser() { 94 val user = TestApis.users().createUser().create() 95 TestApis.users().all() 96 val user2 = TestApis.users().createUser().create() 97 98 try { 99 assertThat(TestApis.users().all()).contains(user2) 100 } finally { 101 user.remove() 102 user2.remove() 103 } 104 } 105 106 @Test 107 @EnsureCanAddUser 108 fun all_userRemovedSinceLastCallToUsers_doesNotContainRemovedUser() { 109 val user = TestApis.users().createUser().create() 110 111 user.remove() 112 113 assertThat(TestApis.users().all()).doesNotContain(user) 114 } 115 116 @Test 117 @EnsureCanAddUser 118 fun find_userExists_returnsUserReference() { 119 val user = TestApis.users().createUser().create() 120 121 try { 122 assertThat(TestApis.users().find(user.id())).isEqualTo(user) 123 } finally { 124 user.remove() 125 } 126 } 127 128 @Test 129 fun find_userDoesNotExist_returnsUserReference() { 130 assertThat(TestApis.users().find(NON_EXISTING_USER_ID)).isNotNull() 131 } 132 133 @Test 134 fun find_fromUserHandle_referencesCorrectId() { 135 assertThat(TestApis.users().find(UserHandle.of(USER_ID)).id()).isEqualTo(USER_ID) 136 } 137 138 @Test 139 fun find_constructedReferenceReferencesCorrectId() { 140 assertThat(TestApis.users().find(USER_ID).id()).isEqualTo(USER_ID) 141 } 142 143 @Test 144 @EnsureCanAddUser 145 fun createUser_additionalSystemUser_throwsException() { 146 assertThrows(NeneException::class.java) { 147 TestApis.users().createUser() 148 .type(TestApis.users().supportedType(UserType.SYSTEM_USER_TYPE_NAME)) 149 .create() 150 } 151 } 152 153 @Test 154 @EnsureCanAddUser 155 fun createUser_userIsCreated_andIsNotEphemeralOrGuest() { 156 val user = TestApis.users().createUser().create() 157 158 try { 159 assertThat(user.exists()).isTrue() 160 assertThat(user.isEphemeral).isFalse() 161 assertThat(user.isGuest).isFalse() 162 } finally { 163 user.remove() 164 } 165 } 166 167 @Test 168 @EnsureCanAddUser 169 fun createUser_createdUserHasCorrectName() { 170 val userReference = TestApis 171 .users() 172 .createUser() 173 .name(USER_NAME) 174 .create() 175 176 try { 177 assertThat(userReference.name()).isEqualTo(USER_NAME) 178 } finally { 179 userReference.remove() 180 } 181 } 182 183 @Test 184 @EnsureCanAddUser 185 fun createUser_createdUserHasCorrectTypeName() { 186 val userReference = TestApis.users().createUser() 187 .type(mSecondaryUserType) 188 .create() 189 190 try { 191 assertThat(userReference.type()).isEqualTo(mSecondaryUserType) 192 } finally { 193 userReference.remove() 194 } 195 } 196 197 @Test 198 @EnsureCanAddUser 199 fun createUser_specifiesNullStringUserType_throwsException() { 200 val userBuilder = TestApis.users().createUser() 201 202 assertThrows(NullPointerException::class.java) { 203 userBuilder.type(null as String?) 204 } 205 } 206 207 @Test 208 @EnsureCanAddUser 209 fun createUser_specifiesNullUserType_throwsException() { 210 val userBuilder = TestApis.users().createUser() 211 212 assertThrows(NullPointerException::class.java) { 213 userBuilder.type(null as UserType?) 214 } 215 } 216 217 @Test 218 @EnsureCanAddUser 219 fun createUser_specifiesSystemUserType_throwsException() { 220 val type = TestApis.users().supportedType(UserType.SYSTEM_USER_TYPE_NAME) 221 val userBuilder = TestApis.users().createUser() 222 .type(type) 223 224 assertThrows(NeneException::class.java) { userBuilder.create() } 225 } 226 227 @Test 228 @EnsureCanAddUser 229 fun createUser_specifiesSecondaryUserType_createsUser() { 230 val user = TestApis.users().createUser().type(mSecondaryUserType).create() 231 232 try { 233 assertThat(user.exists()).isTrue() 234 } finally { 235 user.remove() 236 } 237 } 238 239 @Test 240 @EnsureHasNoCloneProfile 241 @EnsureCanAddUser 242 fun createUser_createsProfile_parentIsSet() { 243 val personalUser = TestApis.users().instrumented() 244 val user = TestApis 245 .users() 246 .createUser() 247 .type(mCloneProfileType) 248 .parent(personalUser) 249 .create() 250 251 try { 252 assertThat(user.parent()) 253 .isEqualTo(TestApis.users().instrumented()) 254 } finally { 255 user.remove() 256 } 257 } 258 259 @Test 260 @EnsureCanAddUser 261 fun createUser_specifiesParentOnNonProfileType_throwsException() { 262 val systemUser = TestApis.users().system() 263 val userBuilder = TestApis.users().createUser() 264 .type(mSecondaryUserType).parent(systemUser) 265 266 assertThrows(NeneException::class.java) { userBuilder.create() } 267 } 268 269 @Test 270 @EnsureCanAddUser 271 fun createUser_specifiesProfileTypeWithoutParent_throwsException() { 272 val userBuilder = TestApis.users().createUser().type(mCloneProfileType) 273 274 assertThrows(NeneException::class.java) { userBuilder.create() } 275 } 276 277 @Test 278 @EnsureCanAddUser 279 fun createAndStart_isStarted() { 280 var user: UserReference? = null 281 try { 282 user = TestApis.users().createUser().name(USER_NAME).createAndStart() 283 284 assertThat(user.isUnlocked()).isTrue() 285 } finally { 286 user?.remove() 287 } 288 } 289 290 @Test 291 fun system_hasId0() { 292 assertThat(TestApis.users().system().id()).isEqualTo(0) 293 } 294 295 @Test 296 fun instrumented_hasCurrentProcessId() { 297 assertThat(TestApis.users().instrumented().id()) 298 .isEqualTo(Process.myUserHandle().identifier) 299 } 300 301 @Test 302 @EnsureHasNoSecondaryUser 303 fun findUsersOfType_noMatching_returnsEmptySet() { 304 assertThat(TestApis.users().findUsersOfType(mSecondaryUserType)).isEmpty() 305 } 306 307 @Test 308 fun findUsersOfType_nullType_throwsException() { 309 assertThrows(NullPointerException::class.java) { 310 TestApis.users().findUsersOfType(null) 311 } 312 } 313 314 @Test 315 @EnsureHasSecondaryUser 316 @Ignore( 317 "TODO: Re-enable when harrier .secondaryUser() only" + 318 " returns the harrier-managed secondary user" 319 ) 320 @EnsureCanAddUser 321 fun findUsersOfType_returnsUsers() { 322 TestApis.users().createUser().create().use { additionalUser -> 323 324 assertThat(TestApis.users().findUsersOfType(mSecondaryUserType)) 325 .containsExactly(sDeviceState.secondaryUser(), additionalUser) 326 } 327 } 328 329 @Test 330 fun findUsersOfType_profileType_throwsException() { 331 assertThrows(NeneException::class.java) { 332 TestApis.users().findUsersOfType(mCloneProfileType) 333 } 334 } 335 336 @Test 337 @EnsureHasNoSecondaryUser 338 fun findUserOfType_noMatching_returnsNull() { 339 assertThat(TestApis.users().findUserOfType(mSecondaryUserType)).isNull() 340 } 341 342 @Test 343 fun findUserOfType_nullType_throwsException() { 344 assertThrows(NullPointerException::class.java) { 345 TestApis.users().findUserOfType(null) 346 } 347 } 348 349 @Test 350 @EnsureHasSecondaryUser 351 @EnsureCanAddUser 352 fun findUserOfType_multipleMatchingUsers_throwsException() { 353 TestApis.users().createUser().create().use { _ -> 354 355 assertThrows(NeneException::class.java) { 356 TestApis.users().findUserOfType(mSecondaryUserType) 357 } 358 } 359 } 360 361 @Test 362 @EnsureHasSecondaryUser 363 fun findUserOfType_oneMatchingUser_returnsUser() { 364 val users = TestApis.users().findUsersOfType(mSecondaryUserType) 365 val i: Iterator<UserReference> = users.iterator() 366 i.next() // Skip the first one so we leave one 367 while (i.hasNext()) { 368 i.next().remove() 369 } 370 371 assertThat(TestApis.users().findUserOfType(mSecondaryUserType)).isNotNull() 372 } 373 374 @Test 375 fun findUserOfType_profileType_throwsException() { 376 assertThrows(NeneException::class.java) { 377 TestApis.users().findUserOfType(mCloneProfileType) 378 } 379 } 380 381 @Test 382 @EnsureHasNoCloneProfile 383 fun findProfilesOfType_noMatching_returnsEmptySet() { 384 assertThat( 385 TestApis.users().findProfilesOfType(mCloneProfileType, mInstrumentedUser) 386 ).isEmpty() 387 } 388 389 @Test 390 fun findProfilesOfType_nullType_throwsException() { 391 assertThrows(NullPointerException::class.java) { 392 TestApis.users().findProfilesOfType(null, mInstrumentedUser) 393 } 394 } 395 396 @Test 397 fun findProfilesOfType_nullParent_throwsException() { 398 assertThrows(NullPointerException::class.java) { 399 TestApis.users().findProfilesOfType(mCloneProfileType, null) 400 } 401 } 402 403 // TODO(scottjonathan): Once we have profiles which support more than one instance, test this 404 @Test 405 @EnsureHasNoCloneProfile 406 fun findProfileOfType_noMatching_returnsNull() { 407 assertThat( 408 TestApis.users().findProfileOfType(mCloneProfileType, mInstrumentedUser) 409 ).isNull() 410 } 411 412 @Test 413 fun findProfilesOfType_nonProfileType_throwsException() { 414 assertThrows(NeneException::class.java) { 415 TestApis.users().findProfilesOfType(mSecondaryUserType, mInstrumentedUser) 416 } 417 } 418 419 @Test 420 fun findProfileOfType_nullType_throwsException() { 421 assertThrows(NullPointerException::class.java) { 422 TestApis.users().findProfileOfType(null, mInstrumentedUser) 423 } 424 } 425 426 @Test 427 fun findProfileOfType_nonProfileType_throwsException() { 428 assertThrows(NeneException::class.java) { 429 TestApis.users().findProfileOfType(mSecondaryUserType, mInstrumentedUser) 430 } 431 } 432 433 @Test 434 fun findProfileOfType_nullParent_throwsException() { 435 assertThrows(NullPointerException::class.java) { 436 TestApis.users().findProfileOfType(mCloneProfileType, null) 437 } 438 } 439 440 @Test // TODO(scottjonathan): This should have a way of specifying exactly 1 441 @EnsureHasCloneProfile 442 fun findProfileOfType_oneMatchingUser_returnsUser() { 443 assertThat( 444 TestApis.users().findProfileOfType(mCloneProfileType, mInstrumentedUser) 445 ).isNotNull() 446 } 447 448 @Test 449 fun nonExisting_userDoesNotExist() { 450 val userReference = TestApis.users().nonExisting() 451 452 assertThat(userReference.exists()).isFalse() 453 } 454 455 @Test 456 @EnsureHasSecondaryUser(switchedToUser = OptionalBoolean.TRUE) 457 fun currentUser_secondaryUser_returnsCurrentUser() { 458 assertThat(TestApis.users().current()).isEqualTo(sDeviceState.secondaryUser()) 459 } 460 461 @Test 462 @RequireRunOnPrimaryUser(switchedToUser = OptionalBoolean.TRUE) 463 fun currentUser_primaryUser_returnsCurrentUser() { 464 assertThat(TestApis.users().current()).isEqualTo(sDeviceState.primaryUser()) 465 } 466 467 @Test 468 @RequireRunNotOnSecondaryUser 469 @EnsureHasSecondaryUser 470 @RequireHeadlessSystemUserMode(reason = "stopBgUsersOnSwitch is only for headless") 471 @Throws(Exception::class) 472 fun switch_hasSetStopBgUsersOnSwitch_stopsUser() { 473 try { 474 sDeviceState.secondaryUser().switchTo() 475 TestApis.users().setStopBgUsersOnSwitch(OptionalBoolean.TRUE) 476 TestApis.users().system().switchTo() 477 Poll.forValue("Secondary user running") { 478 sDeviceState.secondaryUser().isRunning() 479 } 480 .toBeEqualTo(false) 481 .errorOnFail() 482 .await() 483 484 assertThat(sDeviceState.secondaryUser().isRunning()).isFalse() 485 } finally { 486 sDeviceState.secondaryUser().start() 487 TestApis.users().setStopBgUsersOnSwitch(OptionalBoolean.ANY) 488 } 489 } 490 491 @Test 492 @RequireRunOnSecondaryUser 493 fun switch_hasSetStopBgUsersOnSwitchFalse_doesNotStopUser() { 494 try { 495 TestApis.users().setStopBgUsersOnSwitch(OptionalBoolean.FALSE) 496 TestApis.users().system().switchTo() 497 assertThat(sDeviceState.secondaryUser().isRunning()).isTrue() 498 } finally { 499 TestApis.users().setStopBgUsersOnSwitch(OptionalBoolean.ANY) 500 sDeviceState.secondaryUser().start() 501 sDeviceState.secondaryUser().switchTo() 502 } 503 } 504 505 @Test 506 @EnsureCanAddUser 507 fun createEphemeralUser() { 508 TestApis.users() 509 .createUser() 510 .ephemeral(true) 511 .create().use { user -> 512 513 assertThat(user.isEphemeral).isTrue() 514 } 515 } 516 517 @Test 518 @EnsureCanAddUser 519 fun createGuestUser() { 520 TestApis.users() 521 .createUser() 522 .type(UserType.USER_TYPE_FULL_GUEST) 523 .create().use { user -> 524 525 assertThat(user.isGuest).isTrue() 526 } 527 } 528 529 companion object { 530 private const val MAX_SYSTEM_USERS = 1 531 private const val MAX_SYSTEM_USERS_PER_PARENT = UserType.UNLIMITED 532 private const val INVALID_TYPE_NAME = "invalidTypeName" 533 private const val NON_EXISTING_USER_ID = 10000 534 private const val USER_ID = NON_EXISTING_USER_ID 535 private const val USER_NAME = "userName" 536 537 @ClassRule 538 @Rule 539 @JvmField 540 val sDeviceState = DeviceState() 541 } 542 } 543