1 /* 2 * Copyright (C) 2022 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.statusbar.pipeline.wifi.ui.viewmodel 18 19 import androidx.test.ext.junit.runners.AndroidJUnit4 20 import androidx.test.filters.SmallTest 21 import com.android.systemui.RoboPilotTest 22 import com.android.systemui.SysuiTestCase 23 import com.android.systemui.coroutines.collectLastValue 24 import com.android.systemui.log.table.TableLogBuffer 25 import com.android.systemui.statusbar.phone.StatusBarLocation 26 import com.android.systemui.statusbar.pipeline.airplane.data.repository.FakeAirplaneModeRepository 27 import com.android.systemui.statusbar.pipeline.airplane.domain.interactor.AirplaneModeInteractor 28 import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModel 29 import com.android.systemui.statusbar.pipeline.airplane.ui.viewmodel.AirplaneModeViewModelImpl 30 import com.android.systemui.statusbar.pipeline.shared.ConnectivityConstants 31 import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot 32 import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel 33 import com.android.systemui.statusbar.pipeline.shared.data.repository.FakeConnectivityRepository 34 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository 35 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor 36 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractorImpl 37 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants 38 import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel 39 import com.android.systemui.statusbar.pipeline.wifi.ui.model.WifiIcon 40 import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.LocationBasedWifiViewModel.Companion.viewModelForLocation 41 import com.google.common.truth.Truth.assertThat 42 import kotlinx.coroutines.flow.MutableStateFlow 43 import kotlinx.coroutines.test.TestScope 44 import kotlinx.coroutines.test.runTest 45 import org.junit.Before 46 import org.junit.Test 47 import org.junit.runner.RunWith 48 import org.mockito.Mock 49 import org.mockito.Mockito.`when` as whenever 50 import org.mockito.MockitoAnnotations 51 52 @SmallTest 53 @RoboPilotTest 54 @RunWith(AndroidJUnit4::class) 55 class WifiViewModelTest : SysuiTestCase() { 56 57 private lateinit var underTest: WifiViewModel 58 59 @Mock private lateinit var tableLogBuffer: TableLogBuffer 60 @Mock private lateinit var connectivityConstants: ConnectivityConstants 61 @Mock private lateinit var wifiConstants: WifiConstants 62 private lateinit var airplaneModeRepository: FakeAirplaneModeRepository 63 private lateinit var connectivityRepository: FakeConnectivityRepository 64 private lateinit var wifiRepository: FakeWifiRepository 65 private lateinit var interactor: WifiInteractor 66 private lateinit var airplaneModeViewModel: AirplaneModeViewModel 67 private val shouldShowSignalSpacerProviderFlow = MutableStateFlow(false) 68 private val testScope = TestScope() 69 70 @Before 71 fun setUp() { 72 MockitoAnnotations.initMocks(this) 73 airplaneModeRepository = FakeAirplaneModeRepository() 74 connectivityRepository = FakeConnectivityRepository() 75 wifiRepository = FakeWifiRepository() 76 wifiRepository.setIsWifiEnabled(true) 77 interactor = 78 WifiInteractorImpl(connectivityRepository, wifiRepository, testScope.backgroundScope) 79 airplaneModeViewModel = 80 AirplaneModeViewModelImpl( 81 AirplaneModeInteractor( 82 airplaneModeRepository, 83 connectivityRepository, 84 ), 85 tableLogBuffer, 86 testScope.backgroundScope, 87 ) 88 89 createAndSetViewModel() 90 } 91 92 // See [WifiViewModelIconParameterizedTest] for additional view model tests. 93 94 // Note on testing: [WifiViewModel] exposes 3 different instances of 95 // [LocationBasedWifiViewModel]. In practice, these 3 different instances will get the exact 96 // same data for icon, activity, etc. flows. So, most of these tests will test just one of the 97 // instances. There are also some tests that verify all 3 instances received the same data. 98 99 @Test 100 fun wifiIcon_allLocationViewModelsReceiveSameData() = 101 testScope.runTest { 102 val home = viewModelForLocation(underTest, StatusBarLocation.HOME) 103 val keyguard = viewModelForLocation(underTest, StatusBarLocation.KEYGUARD) 104 val qs = viewModelForLocation(underTest, StatusBarLocation.QS) 105 106 val latestHome by collectLastValue(home.wifiIcon) 107 val latestKeyguard by collectLastValue(keyguard.wifiIcon) 108 val latestQs by collectLastValue(qs.wifiIcon) 109 110 wifiRepository.setWifiNetwork( 111 WifiNetworkModel.Active(NETWORK_ID, isValidated = true, level = 1) 112 ) 113 114 assertThat(latestHome).isInstanceOf(WifiIcon.Visible::class.java) 115 assertThat(latestHome).isEqualTo(latestKeyguard) 116 assertThat(latestKeyguard).isEqualTo(latestQs) 117 } 118 119 @Test 120 fun activity_showActivityConfigFalse_outputsFalse() = 121 testScope.runTest { 122 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(false) 123 createAndSetViewModel() 124 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 125 126 val activityIn by collectLastValue(underTest.isActivityInViewVisible) 127 val activityOut by collectLastValue(underTest.isActivityOutViewVisible) 128 val activityContainer by collectLastValue(underTest.isActivityContainerVisible) 129 130 // Verify that on launch, we receive false. 131 assertThat(activityIn).isFalse() 132 assertThat(activityOut).isFalse() 133 assertThat(activityContainer).isFalse() 134 } 135 136 @Test 137 fun activity_showActivityConfigFalse_noUpdatesReceived() = 138 testScope.runTest { 139 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(false) 140 createAndSetViewModel() 141 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 142 143 val activityIn by collectLastValue(underTest.isActivityInViewVisible) 144 val activityOut by collectLastValue(underTest.isActivityOutViewVisible) 145 val activityContainer by collectLastValue(underTest.isActivityContainerVisible) 146 147 // WHEN we update the repo to have activity 148 val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) 149 wifiRepository.setWifiActivity(activity) 150 151 // THEN we didn't update to the new activity (because our config is false) 152 assertThat(activityIn).isFalse() 153 assertThat(activityOut).isFalse() 154 assertThat(activityContainer).isFalse() 155 } 156 157 @Test 158 fun activity_nullSsid_outputsFalse() = 159 testScope.runTest { 160 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 161 createAndSetViewModel() 162 163 wifiRepository.setWifiNetwork( 164 WifiNetworkModel.Active(NETWORK_ID, ssid = null, level = 1) 165 ) 166 167 val activityIn by collectLastValue(underTest.isActivityInViewVisible) 168 val activityOut by collectLastValue(underTest.isActivityOutViewVisible) 169 val activityContainer by collectLastValue(underTest.isActivityContainerVisible) 170 171 // WHEN we update the repo to have activity 172 val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) 173 wifiRepository.setWifiActivity(activity) 174 175 // THEN we still output false because our network's SSID is null 176 assertThat(activityIn).isFalse() 177 assertThat(activityOut).isFalse() 178 assertThat(activityContainer).isFalse() 179 } 180 181 @Test 182 fun activity_allLocationViewModelsReceiveSameData() = 183 testScope.runTest { 184 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 185 createAndSetViewModel() 186 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 187 188 val home = viewModelForLocation(underTest, StatusBarLocation.HOME) 189 val keyguard = viewModelForLocation(underTest, StatusBarLocation.KEYGUARD) 190 val qs = viewModelForLocation(underTest, StatusBarLocation.QS) 191 192 val latestHome by collectLastValue(home.isActivityInViewVisible) 193 val latestKeyguard by collectLastValue(keyguard.isActivityInViewVisible) 194 val latestQs by collectLastValue(qs.isActivityInViewVisible) 195 196 val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) 197 wifiRepository.setWifiActivity(activity) 198 199 assertThat(latestHome).isTrue() 200 assertThat(latestKeyguard).isTrue() 201 assertThat(latestQs).isTrue() 202 } 203 204 @Test 205 fun activityIn_hasActivityInTrue_outputsTrue() = 206 testScope.runTest { 207 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 208 createAndSetViewModel() 209 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 210 211 val latest by collectLastValue(underTest.isActivityInViewVisible) 212 213 val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = false) 214 wifiRepository.setWifiActivity(activity) 215 216 assertThat(latest).isTrue() 217 } 218 219 @Test 220 fun activityIn_hasActivityInFalse_outputsFalse() = 221 testScope.runTest { 222 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 223 createAndSetViewModel() 224 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 225 226 val latest by collectLastValue(underTest.isActivityInViewVisible) 227 228 val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = true) 229 wifiRepository.setWifiActivity(activity) 230 231 assertThat(latest).isFalse() 232 } 233 234 @Test 235 fun activityOut_hasActivityOutTrue_outputsTrue() = 236 testScope.runTest { 237 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 238 createAndSetViewModel() 239 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 240 241 val latest by collectLastValue(underTest.isActivityOutViewVisible) 242 243 val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = true) 244 wifiRepository.setWifiActivity(activity) 245 246 assertThat(latest).isTrue() 247 } 248 249 @Test 250 fun activityOut_hasActivityOutFalse_outputsFalse() = 251 testScope.runTest { 252 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 253 createAndSetViewModel() 254 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 255 256 val latest by collectLastValue(underTest.isActivityOutViewVisible) 257 258 val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = false) 259 wifiRepository.setWifiActivity(activity) 260 261 assertThat(latest).isFalse() 262 } 263 264 @Test 265 fun activityContainer_hasActivityInTrue_outputsTrue() = 266 testScope.runTest { 267 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 268 createAndSetViewModel() 269 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 270 271 val latest by collectLastValue(underTest.isActivityContainerVisible) 272 273 val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = false) 274 wifiRepository.setWifiActivity(activity) 275 276 assertThat(latest).isTrue() 277 } 278 279 @Test 280 fun activityContainer_hasActivityOutTrue_outputsTrue() = 281 testScope.runTest { 282 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 283 createAndSetViewModel() 284 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 285 286 val latest by collectLastValue(underTest.isActivityContainerVisible) 287 288 val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = true) 289 wifiRepository.setWifiActivity(activity) 290 291 assertThat(latest).isTrue() 292 } 293 294 @Test 295 fun activityContainer_inAndOutTrue_outputsTrue() = 296 testScope.runTest { 297 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 298 createAndSetViewModel() 299 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 300 301 val latest by collectLastValue(underTest.isActivityContainerVisible) 302 303 val activity = DataActivityModel(hasActivityIn = true, hasActivityOut = true) 304 wifiRepository.setWifiActivity(activity) 305 306 assertThat(latest).isTrue() 307 } 308 309 @Test 310 fun activityContainer_inAndOutFalse_outputsFalse() = 311 testScope.runTest { 312 whenever(connectivityConstants.shouldShowActivityConfig).thenReturn(true) 313 createAndSetViewModel() 314 wifiRepository.setWifiNetwork(ACTIVE_VALID_WIFI_NETWORK) 315 316 val latest by collectLastValue(underTest.isActivityContainerVisible) 317 318 val activity = DataActivityModel(hasActivityIn = false, hasActivityOut = false) 319 wifiRepository.setWifiActivity(activity) 320 321 assertThat(latest).isFalse() 322 } 323 324 @Test 325 fun airplaneSpacer_notAirplaneMode_outputsFalse() = 326 testScope.runTest { 327 val latest by collectLastValue(underTest.isAirplaneSpacerVisible) 328 329 airplaneModeRepository.setIsAirplaneMode(false) 330 331 assertThat(latest).isFalse() 332 } 333 334 @Test 335 fun airplaneSpacer_airplaneForceHidden_outputsFalse() = 336 testScope.runTest { 337 val latest by collectLastValue(underTest.isAirplaneSpacerVisible) 338 339 airplaneModeRepository.setIsAirplaneMode(true) 340 connectivityRepository.setForceHiddenIcons(setOf(ConnectivitySlot.AIRPLANE)) 341 342 assertThat(latest).isFalse() 343 } 344 345 @Test 346 fun airplaneSpacer_airplaneIconVisible_outputsTrue() = 347 testScope.runTest { 348 val latest by collectLastValue(underTest.isAirplaneSpacerVisible) 349 350 airplaneModeRepository.setIsAirplaneMode(true) 351 352 assertThat(latest).isTrue() 353 } 354 355 @Test 356 fun signalSpacer_firstSubNotShowingNetworkTypeIcon_outputsFalse() = 357 testScope.runTest { 358 val latest by collectLastValue(underTest.isSignalSpacerVisible) 359 360 shouldShowSignalSpacerProviderFlow.value = false 361 362 assertThat(latest).isFalse() 363 } 364 365 @Test 366 fun signalSpacer_firstSubIsShowingNetworkTypeIcon_outputsTrue() = 367 testScope.runTest { 368 val latest by collectLastValue(underTest.isSignalSpacerVisible) 369 370 shouldShowSignalSpacerProviderFlow.value = true 371 372 assertThat(latest).isTrue() 373 } 374 375 private fun createAndSetViewModel() { 376 // [WifiViewModel] creates its flows as soon as it's instantiated, and some of those flow 377 // creations rely on certain config values that we mock out in individual tests. This method 378 // allows tests to create the view model only after those configs are correctly set up. 379 underTest = 380 WifiViewModel( 381 airplaneModeViewModel, 382 { shouldShowSignalSpacerProviderFlow }, 383 connectivityConstants, 384 context, 385 tableLogBuffer, 386 interactor, 387 testScope.backgroundScope, 388 wifiConstants, 389 ) 390 } 391 392 companion object { 393 private const val NETWORK_ID = 2 394 private val ACTIVE_VALID_WIFI_NETWORK = 395 WifiNetworkModel.Active(NETWORK_ID, ssid = "AB", level = 1) 396 } 397 } 398