• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * 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 
17 package com.android.intentresolver.data.repository
18 
19 import android.content.pm.UserInfo
20 import android.os.UserHandle
21 import android.os.UserHandle.SYSTEM
22 import android.os.UserHandle.USER_SYSTEM
23 import android.os.UserManager
24 import com.android.intentresolver.coroutines.collectLastValue
25 import com.android.intentresolver.platform.FakeUserManager
26 import com.android.intentresolver.platform.FakeUserManager.ProfileType
27 import com.android.intentresolver.shared.model.User
28 import com.android.intentresolver.shared.model.User.Role
29 import com.google.common.truth.Truth.assertThat
30 import com.google.common.truth.Truth.assertWithMessage
31 import kotlinx.coroutines.Dispatchers
32 import kotlinx.coroutines.flow.flowOf
33 import kotlinx.coroutines.test.TestScope
34 import kotlinx.coroutines.test.runTest
35 import org.junit.Test
36 import org.mockito.kotlin.any
37 import org.mockito.kotlin.doReturn
38 import org.mockito.kotlin.mock
39 
40 internal class UserRepositoryImplTest {
41     private val userManager = FakeUserManager()
42     private val userState = userManager.state
43 
44     @Test
<lambda>null45     fun initialization() = runTest {
46         val repo = createUserRepository(userManager)
47         val users by collectLastValue(repo.users)
48 
49         assertWithMessage("collectLastValue(repo.users)").that(users).isNotNull()
50         assertThat(users)
51             .containsExactly(User(userState.primaryUserHandle.identifier, Role.PERSONAL))
52     }
53 
54     @Test
<lambda>null55     fun createProfile() = runTest {
56         val repo = createUserRepository(userManager)
57         val users by collectLastValue(repo.users)
58 
59         assertWithMessage("collectLastValue(repo.users)").that(users).isNotNull()
60         assertThat(users).hasSize(1)
61 
62         val profile = userState.createProfile(ProfileType.WORK)
63         assertThat(users).hasSize(2)
64         assertThat(users).contains(User(profile.identifier, Role.WORK))
65     }
66 
67     @Test
<lambda>null68     fun removeProfile() = runTest {
69         val repo = createUserRepository(userManager)
70         val users by collectLastValue(repo.users)
71 
72         assertWithMessage("collectLastValue(repo.users)").that(users).isNotNull()
73         val work = userState.createProfile(ProfileType.WORK)
74         assertThat(users).contains(User(work.identifier, Role.WORK))
75 
76         userState.removeProfile(work)
77         assertThat(users).doesNotContain(User(work.identifier, Role.WORK))
78     }
79 
80     @Test
<lambda>null81     fun isAvailable() = runTest {
82         val repo = createUserRepository(userManager)
83         val work = userState.createProfile(ProfileType.WORK)
84         val workUser = User(work.identifier, Role.WORK)
85 
86         val available by collectLastValue(repo.availability)
87         assertThat(available?.get(workUser)).isTrue()
88 
89         userState.setQuietMode(work, true)
90         assertThat(available?.get(workUser)).isFalse()
91 
92         userState.setQuietMode(work, false)
93         assertThat(available?.get(workUser)).isTrue()
94     }
95 
96     @Test
<lambda>null97     fun onHandleAvailabilityChange_userStateMaintained() = runTest {
98         val repo = createUserRepository(userManager)
99         val private = userState.createProfile(ProfileType.PRIVATE)
100         val privateUser = User(private.identifier, Role.PRIVATE)
101 
102         val users by collectLastValue(repo.users)
103 
104         repo.requestState(privateUser, false)
105         repo.requestState(privateUser, true)
106 
107         assertWithMessage("users.size").that(users?.size ?: 0).isEqualTo(2) // personal + private
108 
109         assertWithMessage("No duplicate IDs")
110             .that(users?.count { it.id == private.identifier })
111             .isEqualTo(1)
112     }
113 
114     @Test
<lambda>null115     fun requestState() = runTest {
116         val repo = createUserRepository(userManager)
117         val work = userState.createProfile(ProfileType.WORK)
118         val workUser = User(work.identifier, Role.WORK)
119 
120         val available by collectLastValue(repo.availability)
121         assertThat(available?.get(workUser)).isTrue()
122 
123         repo.requestState(workUser, false)
124         assertThat(available?.get(workUser)).isFalse()
125 
126         repo.requestState(workUser, true)
127         assertThat(available?.get(workUser)).isTrue()
128     }
129 
130     /**
131      * This and all the 'recovers_from_*' tests below all configure a static event flow instead of
132      * using [FakeUserManager]. These tests verify that a invalid broadcast causes the flow to
133      * reinitialize with the user profile group.
134      */
135     @Test
<lambda>null136     fun recovers_from_invalid_profile_added_event() = runTest {
137         val userManager =
138             mockUserManager(validUser = USER_SYSTEM, invalidUser = UserHandle.USER_NULL)
139         val events = flowOf(ProfileAdded(UserHandle.of(UserHandle.USER_NULL)))
140         val repo =
141             UserRepositoryImpl(
142                 profileParent = SYSTEM,
143                 userManager = userManager,
144                 userEvents = events,
145                 scope = backgroundScope,
146                 backgroundDispatcher = Dispatchers.Unconfined
147             )
148         val users by collectLastValue(repo.users)
149 
150         assertWithMessage("collectLastValue(repo.users)").that(users).isNotNull()
151         assertThat(users).containsExactly(User(USER_SYSTEM, Role.PERSONAL))
152     }
153 
154     @Test
<lambda>null155     fun recovers_from_invalid_profile_removed_event() = runTest {
156         val userManager =
157             mockUserManager(validUser = USER_SYSTEM, invalidUser = UserHandle.USER_NULL)
158         val events = flowOf(ProfileRemoved(UserHandle.of(UserHandle.USER_NULL)))
159         val repo =
160             UserRepositoryImpl(
161                 profileParent = SYSTEM,
162                 userManager = userManager,
163                 userEvents = events,
164                 scope = backgroundScope,
165                 backgroundDispatcher = Dispatchers.Unconfined
166             )
167         val users by collectLastValue(repo.users)
168 
169         assertWithMessage("collectLastValue(repo.users)").that(users).isNotNull()
170         assertThat(users).containsExactly(User(USER_SYSTEM, Role.PERSONAL))
171     }
172 
173     @Test
<lambda>null174     fun recovers_from_invalid_profile_available_event() = runTest {
175         val userManager =
176             mockUserManager(validUser = USER_SYSTEM, invalidUser = UserHandle.USER_NULL)
177         val events = flowOf(AvailabilityChange(UserHandle.of(UserHandle.USER_NULL)))
178         val repo =
179             UserRepositoryImpl(SYSTEM, userManager, events, backgroundScope, Dispatchers.Unconfined)
180         val users by collectLastValue(repo.users)
181 
182         assertWithMessage("collectLastValue(repo.users)").that(users).isNotNull()
183         assertThat(users).containsExactly(User(USER_SYSTEM, Role.PERSONAL))
184     }
185 
186     @Test
<lambda>null187     fun recovers_from_unknown_event() = runTest {
188         val userManager =
189             mockUserManager(validUser = USER_SYSTEM, invalidUser = UserHandle.USER_NULL)
190         val events = flowOf(UnknownEvent("UNKNOWN_EVENT"))
191         val repo =
192             UserRepositoryImpl(
193                 profileParent = SYSTEM,
194                 userManager = userManager,
195                 userEvents = events,
196                 scope = backgroundScope,
197                 backgroundDispatcher = Dispatchers.Unconfined
198             )
199         val users by collectLastValue(repo.users)
200 
201         assertWithMessage("collectLastValue(repo.users)").that(users).isNotNull()
202         assertThat(users).containsExactly(User(USER_SYSTEM, Role.PERSONAL))
203     }
204 }
205 
206 @Suppress("SameParameterValue")
mockUserManagernull207 private fun mockUserManager(validUser: Int, invalidUser: Int) =
208     mock<UserManager> {
209         val info = UserInfo(validUser, "", "", UserInfo.FLAG_FULL)
210         on { getEnabledProfiles(any()) } doReturn listOf(info)
211         on { getUserInfo(validUser) } doReturn info
212         on { getEnabledProfiles(invalidUser) } doReturn listOf()
213         on { getUserInfo(invalidUser) } doReturn null
214     }
215 
createUserRepositorynull216 private fun TestScope.createUserRepository(userManager: FakeUserManager): UserRepositoryImpl {
217     return UserRepositoryImpl(
218         profileParent = userManager.state.primaryUserHandle,
219         userManager = userManager,
220         userEvents = userManager.state.userEvents,
221         scope = backgroundScope,
222         backgroundDispatcher = Dispatchers.Unconfined
223     )
224 }
225