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