1 /*
<lambda>null2  * Copyright (C) 2023 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.systemui.common.data.repository
18 
19 import android.content.Context
20 import android.content.pm.PackageManager
21 import android.os.Handler
22 import android.os.UserHandle
23 import androidx.test.ext.junit.runners.AndroidJUnit4
24 import androidx.test.filters.SmallTest
25 import com.android.systemui.SysuiTestCase
26 import com.android.systemui.common.shared.model.PackageChangeModel
27 import com.android.systemui.coroutines.collectLastValue
28 import com.android.systemui.coroutines.collectValues
29 import com.android.systemui.kosmos.applicationCoroutineScope
30 import com.android.systemui.kosmos.testDispatcher
31 import com.android.systemui.kosmos.testScope
32 import com.android.systemui.log.logcatLogBuffer
33 import com.android.systemui.testKosmos
34 import com.android.systemui.util.mockito.whenever
35 import com.android.systemui.util.time.fakeSystemClock
36 import com.google.common.truth.Truth.assertThat
37 import kotlinx.coroutines.test.runTest
38 import org.junit.Before
39 import org.junit.Test
40 import org.junit.runner.RunWith
41 import org.mockito.Mock
42 import org.mockito.MockitoAnnotations
43 
44 @SmallTest
45 @RunWith(AndroidJUnit4::class)
46 class PackageChangeRepositoryTest : SysuiTestCase() {
47 
48     private val kosmos = testKosmos()
49 
50     @Mock private lateinit var context: Context
51     @Mock private lateinit var packageManager: PackageManager
52     @Mock private lateinit var handler: Handler
53     @Mock private lateinit var packageInstallerMonitor: PackageInstallerMonitor
54 
55     private lateinit var repository: PackageChangeRepository
56     private lateinit var updateMonitor: PackageUpdateMonitor
57 
58     @Before
59     fun setUp() =
60         with(kosmos) {
61             MockitoAnnotations.initMocks(this@PackageChangeRepositoryTest)
62             whenever(context.packageManager).thenReturn(packageManager)
63 
64             repository =
65                 PackageChangeRepositoryImpl(packageInstallerMonitor) { user ->
66                     updateMonitor =
67                         PackageUpdateMonitor(
68                             user = user,
69                             bgDispatcher = testDispatcher,
70                             scope = applicationCoroutineScope,
71                             context = context,
72                             bgHandler = handler,
73                             logger = PackageUpdateLogger(logcatLogBuffer()),
74                             systemClock = fakeSystemClock,
75                         )
76                     updateMonitor
77                 }
78         }
79 
80     @Test
81     fun packageUninstalled() =
82         with(kosmos) {
83             testScope.runTest {
84                 val packageChange by collectLastValue(repository.packageChanged(USER_100))
85                 assertThat(packageChange).isNull()
86 
87                 updateMonitor.onPackageRemoved(
88                     packageName = TEST_PACKAGE,
89                     uid = UserHandle.getUid(/* userId = */ 100, /* appId = */ 10)
90                 )
91 
92                 assertThat(packageChange).isInstanceOf(PackageChangeModel.Uninstalled::class.java)
93                 assertThat(packageChange?.packageName).isEqualTo(TEST_PACKAGE)
94             }
95         }
96 
97     @Test
98     fun packageUpdateStarted() =
99         with(kosmos) {
100             testScope.runTest {
101                 val packageChange by collectLastValue(repository.packageChanged(USER_100))
102                 assertThat(packageChange).isNull()
103 
104                 updateMonitor.onPackageUpdateStarted(
105                     packageName = TEST_PACKAGE,
106                     uid = UserHandle.getUid(/* userId = */ 100, /* appId = */ 10)
107                 )
108 
109                 assertThat(packageChange).isInstanceOf(PackageChangeModel.UpdateStarted::class.java)
110                 assertThat(packageChange?.packageName).isEqualTo(TEST_PACKAGE)
111             }
112         }
113 
114     @Test
115     fun packageUpdateFinished() =
116         with(kosmos) {
117             testScope.runTest {
118                 val packageChange by collectLastValue(repository.packageChanged(USER_100))
119                 assertThat(packageChange).isNull()
120 
121                 updateMonitor.onPackageUpdateFinished(
122                     packageName = TEST_PACKAGE,
123                     uid = UserHandle.getUid(/* userId = */ 100, /* appId = */ 10)
124                 )
125 
126                 assertThat(packageChange)
127                     .isInstanceOf(PackageChangeModel.UpdateFinished::class.java)
128                 assertThat(packageChange?.packageName).isEqualTo(TEST_PACKAGE)
129             }
130         }
131 
132     @Test
133     fun packageInstalled() =
134         with(kosmos) {
135             testScope.runTest {
136                 val packageChange by collectLastValue(repository.packageChanged(UserHandle.ALL))
137                 assertThat(packageChange).isNull()
138 
139                 updateMonitor.onPackageAdded(
140                     packageName = TEST_PACKAGE,
141                     uid = UserHandle.getUid(/* userId = */ 100, /* appId = */ 10)
142                 )
143 
144                 assertThat(packageChange).isInstanceOf(PackageChangeModel.Installed::class.java)
145                 assertThat(packageChange?.packageName).isEqualTo(TEST_PACKAGE)
146             }
147         }
148 
149     @Test
150     fun packageIsChanged() =
151         with(kosmos) {
152             testScope.runTest {
153                 val packageChange by collectLastValue(repository.packageChanged(USER_100))
154                 assertThat(packageChange).isNull()
155 
156                 updateMonitor.onPackageChanged(
157                     packageName = TEST_PACKAGE,
158                     uid = UserHandle.getUid(/* userId = */ 100, /* appId = */ 10),
159                     components = emptyArray()
160                 )
161 
162                 assertThat(packageChange).isInstanceOf(PackageChangeModel.Changed::class.java)
163                 assertThat(packageChange?.packageName).isEqualTo(TEST_PACKAGE)
164             }
165         }
166 
167     @Test
168     fun filtersOutUpdatesFromOtherUsers() =
169         with(kosmos) {
170             testScope.runTest {
171                 val packageChange by collectLastValue(repository.packageChanged(USER_100))
172                 assertThat(packageChange).isNull()
173 
174                 updateMonitor.onPackageUpdateFinished(
175                     packageName = TEST_PACKAGE,
176                     uid = UserHandle.getUid(/* userId = */ 101, /* appId = */ 10)
177                 )
178 
179                 updateMonitor.onPackageAdded(
180                     packageName = TEST_PACKAGE,
181                     uid = UserHandle.getUid(/* userId = */ 99, /* appId = */ 10)
182                 )
183 
184                 assertThat(packageChange).isNull()
185             }
186         }
187 
188     @Test
189     fun listenToUpdatesFromAllUsers() =
190         with(kosmos) {
191             testScope.runTest {
192                 val packageChanges by collectValues(repository.packageChanged(UserHandle.ALL))
193                 assertThat(packageChanges).isEmpty()
194 
195                 updateMonitor.onPackageUpdateFinished(
196                     packageName = TEST_PACKAGE,
197                     uid = UserHandle.getUid(/* userId = */ 101, /* appId = */ 10)
198                 )
199 
200                 updateMonitor.onPackageAdded(
201                     packageName = TEST_PACKAGE,
202                     uid = UserHandle.getUid(/* userId = */ 99, /* appId = */ 10)
203                 )
204 
205                 assertThat(packageChanges).hasSize(2)
206             }
207         }
208 
209     private companion object {
210         val USER_100 = UserHandle.of(100)
211         const val TEST_PACKAGE = "pkg.test"
212     }
213 }
214