• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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