1/* 2 * Copyright (C) 2016 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 17package com.android.server.wifi; 18 19import static org.junit.Assert.assertEquals; 20import static org.mockito.Mockito.*; 21 22import android.content.Context; 23import android.net.wifi.WifiConfiguration; 24import android.net.wifi.WifiManager; 25import android.os.BatteryStats; 26import android.os.test.TestLooper; 27import android.support.test.filters.SmallTest; 28import android.util.Log; 29 30import com.android.internal.app.IBatteryStats; 31 32import org.junit.After; 33import org.junit.Before; 34import org.junit.Test; 35import org.mockito.ArgumentCaptor; 36import org.mockito.Mock; 37import org.mockito.MockitoAnnotations; 38import org.mockito.invocation.InvocationOnMock; 39import org.mockito.stubbing.Answer; 40 41import java.io.ByteArrayOutputStream; 42import java.io.PrintWriter; 43 44/** 45 * Unit tests for {@link com.android.server.wifi.WifiStateMachinePrime}. 46 */ 47@SmallTest 48public class WifiStateMachinePrimeTest { 49 public static final String TAG = "WifiStateMachinePrimeTest"; 50 51 private static final String CLIENT_MODE_STATE_STRING = "ClientModeActiveState"; 52 private static final String SCAN_ONLY_MODE_STATE_STRING = "ScanOnlyModeActiveState"; 53 private static final String WIFI_DISABLED_STATE_STRING = "WifiDisabledState"; 54 private static final String WIFI_IFACE_NAME = "mockWlan"; 55 56 @Mock WifiInjector mWifiInjector; 57 @Mock Context mContext; 58 @Mock WifiNative mWifiNative; 59 @Mock WifiApConfigStore mWifiApConfigStore; 60 TestLooper mLooper; 61 @Mock ClientModeManager mClientModeManager; 62 @Mock ScanOnlyModeManager mScanOnlyModeManager; 63 @Mock SoftApManager mSoftApManager; 64 @Mock DefaultModeManager mDefaultModeManager; 65 @Mock IBatteryStats mBatteryStats; 66 @Mock SelfRecovery mSelfRecovery; 67 @Mock BaseWifiDiagnostics mWifiDiagnostics; 68 @Mock ScanRequestProxy mScanRequestProxy; 69 ClientModeManager.Listener mClientListener; 70 ScanOnlyModeManager.Listener mScanOnlyListener; 71 ScanOnlyModeCallback mScanOnlyCallback = new ScanOnlyModeCallback(); 72 ClientModeCallback mClientModeCallback = new ClientModeCallback(); 73 WifiManager.SoftApCallback mSoftApManagerCallback; 74 @Mock WifiManager.SoftApCallback mSoftApStateMachineCallback; 75 WifiNative.StatusListener mWifiNativeStatusListener; 76 WifiStateMachinePrime mWifiStateMachinePrime; 77 78 final ArgumentCaptor<WifiNative.StatusListener> mStatusListenerCaptor = 79 ArgumentCaptor.forClass(WifiNative.StatusListener.class); 80 81 /** 82 * Set up the test environment. 83 */ 84 @Before 85 public void setUp() throws Exception { 86 Log.d(TAG, "Setting up ..."); 87 88 MockitoAnnotations.initMocks(this); 89 mLooper = new TestLooper(); 90 91 when(mWifiInjector.getSelfRecovery()).thenReturn(mSelfRecovery); 92 when(mWifiInjector.getWifiDiagnostics()).thenReturn(mWifiDiagnostics); 93 when(mWifiInjector.getScanRequestProxy()).thenReturn(mScanRequestProxy); 94 95 mWifiStateMachinePrime = createWifiStateMachinePrime(); 96 mLooper.dispatchAll(); 97 98 verify(mWifiNative).registerStatusListener(mStatusListenerCaptor.capture()); 99 mWifiNativeStatusListener = mStatusListenerCaptor.getValue(); 100 101 mWifiStateMachinePrime.registerSoftApCallback(mSoftApStateMachineCallback); 102 mWifiStateMachinePrime.registerScanOnlyCallback(mScanOnlyCallback); 103 mWifiStateMachinePrime.registerClientModeCallback(mClientModeCallback); 104 } 105 106 private WifiStateMachinePrime createWifiStateMachinePrime() { 107 return new WifiStateMachinePrime(mWifiInjector, 108 mContext, 109 mLooper.getLooper(), 110 mWifiNative, 111 mDefaultModeManager, 112 mBatteryStats); 113 } 114 115 /** 116 * Clean up after tests - explicitly set tested object to null. 117 */ 118 @After 119 public void cleanUp() throws Exception { 120 mWifiStateMachinePrime = null; 121 } 122 123 private class ClientModeCallback implements ClientModeManager.Listener { 124 public int currentState = WifiManager.WIFI_STATE_UNKNOWN; 125 126 @Override 127 public void onStateChanged(int state) { 128 currentState = state; 129 } 130 } 131 132 private class ScanOnlyModeCallback implements ScanOnlyModeManager.Listener { 133 public int currentState = WifiManager.WIFI_STATE_UNKNOWN; 134 135 @Override 136 public void onStateChanged(int state) { 137 currentState = state; 138 } 139 } 140 141 private void enterSoftApActiveMode() throws Exception { 142 enterSoftApActiveMode( 143 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, null)); 144 } 145 146 /** 147 * Helper method to enter the ClientModeActiveState for WifiStateMachinePrime. 148 */ 149 private void enterClientModeActiveState() throws Exception { 150 String fromState = mWifiStateMachinePrime.getCurrentMode(); 151 doAnswer( 152 new Answer<Object>() { 153 public ClientModeManager answer(InvocationOnMock invocation) { 154 Object[] args = invocation.getArguments(); 155 mClientListener = (ClientModeManager.Listener) args[0]; 156 return mClientModeManager; 157 } 158 }).when(mWifiInjector).makeClientModeManager( 159 any(ClientModeManager.Listener.class)); 160 mWifiStateMachinePrime.enterClientMode(); 161 mLooper.dispatchAll(); 162 mClientListener.onStateChanged(WifiManager.WIFI_STATE_ENABLED); 163 mLooper.dispatchAll(); 164 165 assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 166 verify(mClientModeManager).start(); 167 verify(mBatteryStats).noteWifiOn(); 168 } 169 170 /** 171 * Helper method to enter the ScanOnlyModeActiveState for WifiStateMachinePrime. 172 */ 173 private void enterScanOnlyModeActiveState() throws Exception { 174 String fromState = mWifiStateMachinePrime.getCurrentMode(); 175 doAnswer( 176 new Answer<Object>() { 177 public ScanOnlyModeManager answer(InvocationOnMock invocation) { 178 Object[] args = invocation.getArguments(); 179 mScanOnlyListener = (ScanOnlyModeManager.Listener) args[0]; 180 return mScanOnlyModeManager; 181 } 182 }).when(mWifiInjector).makeScanOnlyModeManager( 183 any(ScanOnlyModeManager.Listener.class)); 184 mWifiStateMachinePrime.enterScanOnlyMode(); 185 mLooper.dispatchAll(); 186 mScanOnlyListener.onStateChanged(WifiManager.WIFI_STATE_ENABLED); 187 mLooper.dispatchAll(); 188 189 assertEquals(SCAN_ONLY_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 190 verify(mScanOnlyModeManager).start(); 191 verify(mBatteryStats).noteWifiOn(); 192 verify(mBatteryStats).noteWifiState(eq(BatteryStats.WIFI_STATE_OFF_SCANNING), eq(null)); 193 } 194 195 /** 196 * Helper method to enter the SoftApActiveMode for WifiStateMachinePrime. 197 * 198 * This method puts the test object into the correct state and verifies steps along the way. 199 */ 200 private void enterSoftApActiveMode(SoftApModeConfiguration softApConfig) throws Exception { 201 String fromState = mWifiStateMachinePrime.getCurrentMode(); 202 doAnswer( 203 new Answer<Object>() { 204 public SoftApManager answer(InvocationOnMock invocation) { 205 Object[] args = invocation.getArguments(); 206 mSoftApManagerCallback = (WifiManager.SoftApCallback) args[0]; 207 assertEquals(softApConfig, (SoftApModeConfiguration) args[1]); 208 return mSoftApManager; 209 } 210 }).when(mWifiInjector).makeSoftApManager(any(WifiManager.SoftApCallback.class), 211 any()); 212 mWifiStateMachinePrime.enterSoftAPMode(softApConfig); 213 mLooper.dispatchAll(); 214 verify(mSoftApManager).start(); 215 if (fromState.equals(WIFI_DISABLED_STATE_STRING)) { 216 verify(mBatteryStats).noteWifiOn(); 217 } 218 } 219 220 /** 221 * Test that after starting up, WSMP is in the Disabled State. 222 */ 223 @Test 224 public void testWifiDisabledAtStartup() throws Exception { 225 assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 226 } 227 228 /** 229 * Test that WifiStateMachinePrime properly enters the ScanOnlyModeActiveState from the 230 * WifiDisabled state. 231 */ 232 @Test 233 public void testEnterScanOnlyModeFromDisabled() throws Exception { 234 enterScanOnlyModeActiveState(); 235 } 236 237 /** 238 * Test that WifiStateMachinePrime properly enters the SoftApModeActiveState from the 239 * WifiDisabled state. 240 */ 241 @Test 242 public void testEnterSoftApModeFromDisabled() throws Exception { 243 enterSoftApActiveMode(); 244 } 245 246 /** 247 * Test that WifiStateMachinePrime properly enters the SoftApModeActiveState from another state. 248 */ 249 @Test 250 public void testEnterSoftApModeFromDifferentState() throws Exception { 251 enterClientModeActiveState(); 252 mLooper.dispatchAll(); 253 assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 254 reset(mBatteryStats); 255 enterSoftApActiveMode(); 256 } 257 258 /** 259 * Test that we can disable wifi fully from the ScanOnlyModeActiveState. 260 */ 261 @Test 262 public void testDisableWifiFromScanOnlyModeActiveState() throws Exception { 263 enterScanOnlyModeActiveState(); 264 265 mWifiStateMachinePrime.disableWifi(); 266 mLooper.dispatchAll(); 267 verify(mScanOnlyModeManager).stop(); 268 verify(mBatteryStats).noteWifiOff(); 269 assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 270 } 271 272 /** 273 * Test that we can disable wifi from the SoftApModeActiveState and not impact softap. 274 */ 275 @Test 276 public void testDisableWifiFromSoftApModeActiveStateDoesNotStopSoftAp() throws Exception { 277 enterSoftApActiveMode(); 278 279 reset(mDefaultModeManager); 280 mWifiStateMachinePrime.disableWifi(); 281 mLooper.dispatchAll(); 282 verify(mSoftApManager, never()).stop(); 283 verify(mBatteryStats, never()).noteWifiOff(); 284 verify(mDefaultModeManager).sendScanAvailableBroadcast(eq(mContext), eq(false)); 285 assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 286 } 287 288 /** 289 * Thest that we can switch from ScanOnlyActiveMode to another mode. 290 * Expectation: When switching out of ScanOlyModeActivState we stop the ScanOnlyModeManager. 291 */ 292 @Test 293 public void testSwitchModeWhenScanOnlyModeActiveState() throws Exception { 294 enterScanOnlyModeActiveState(); 295 296 reset(mBatteryStats); 297 enterClientModeActiveState(); 298 mLooper.dispatchAll(); 299 verify(mScanOnlyModeManager).stop(); 300 assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 301 } 302 303 /** 304 * Test that we can switch from SoftApActiveMode to another mode. 305 * Expectation: When switching out of SoftApModeActiveState we do not impact softap operation 306 */ 307 @Test 308 public void testSwitchModeWhenSoftApActiveMode() throws Exception { 309 enterSoftApActiveMode(); 310 311 reset(mWifiNative); 312 313 enterClientModeActiveState(); 314 mLooper.dispatchAll(); 315 verify(mSoftApManager, never()).stop(); 316 assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 317 verify(mWifiNative, never()).teardownAllInterfaces(); 318 } 319 320 /** 321 * Test that we do enter the SoftApModeActiveState if we are already in WifiDisabledState due to 322 * a failure. 323 * Expectations: We should exit the current WifiDisabledState and re-enter before successfully 324 * entering the SoftApModeActiveState. 325 */ 326 @Test 327 public void testEnterSoftApModeActiveWhenAlreadyInSoftApMode() throws Exception { 328 enterSoftApActiveMode(); 329 // now inject failure through the SoftApManager.Listener 330 mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0); 331 mLooper.dispatchAll(); 332 assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 333 // clear the first call to start SoftApManager 334 reset(mSoftApManager, mBatteryStats); 335 336 enterSoftApActiveMode(); 337 } 338 339 /** 340 * Test that we return to the WifiDisabledState after a failure is reported when in the 341 * ScanOnlyModeActiveState. 342 * Expectations: we should exit the ScanOnlyModeActiveState and stop the ScanOnlyModeManager. 343 */ 344 @Test 345 public void testScanOnlyModeFailureWhenActive() throws Exception { 346 enterScanOnlyModeActiveState(); 347 // now inject a failure through the ScanOnlyModeManager.Listener 348 mScanOnlyListener.onStateChanged(WifiManager.WIFI_STATE_UNKNOWN); 349 mLooper.dispatchAll(); 350 assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 351 verify(mScanOnlyModeManager).stop(); 352 verify(mBatteryStats).noteWifiOff(); 353 assertEquals(WifiManager.WIFI_STATE_UNKNOWN, mScanOnlyCallback.currentState); 354 } 355 356 /** 357 * Test that we return to the WifiDisabledState after a failure is reported when in the 358 * SoftApModeActiveState. 359 * Expectations: We should exit the SoftApModeActiveState and stop the SoftApManager. 360 */ 361 @Test 362 public void testSoftApFailureWhenActive() throws Exception { 363 enterSoftApActiveMode(); 364 // now inject failure through the SoftApManager.Listener 365 mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0); 366 mLooper.dispatchAll(); 367 verify(mBatteryStats).noteWifiOff(); 368 } 369 370 /** 371 * Test that we return to the WifiDisabledState after the ScanOnlyModeManager is stopping in the 372 * ScanOnlyModeActiveState. 373 * Expectations: We should exit the ScanOnlyModeActiveState and stop the ScanOnlyModeManager. 374 */ 375 @Test 376 public void testScanOnlyModeDisabledWhenActive() throws Exception { 377 enterScanOnlyModeActiveState(); 378 // now inject the stop message through the ScanOnlyModeManager.Listener 379 mScanOnlyListener.onStateChanged(WifiManager.WIFI_STATE_DISABLED); 380 mLooper.dispatchAll(); 381 assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 382 verify(mScanOnlyModeManager).stop(); 383 verify(mBatteryStats).noteWifiOff(); 384 } 385 386 /** 387 * Test that we return to the WifiDisabledState after the SoftApManager is stopped in the 388 * SoftApModeActiveState. 389 * Expectations: We should exit the SoftApModeActiveState and stop the SoftApManager. 390 */ 391 @Test 392 public void testSoftApDisabledWhenActive() throws Exception { 393 enterSoftApActiveMode(); 394 reset(mWifiNative); 395 // now inject failure through the SoftApManager.Listener 396 mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0); 397 mLooper.dispatchAll(); 398 verify(mBatteryStats).noteWifiOff(); 399 verifyNoMoreInteractions(mWifiNative); 400 } 401 402 /** 403 * Verifies that SoftApStateChanged event is being passed from SoftApManager to WifiServiceImpl 404 */ 405 @Test 406 public void callsWifiServiceCallbackOnSoftApStateChanged() throws Exception { 407 enterSoftApActiveMode(); 408 409 mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0); 410 mLooper.dispatchAll(); 411 412 verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0); 413 } 414 415 /** 416 * Verifies that triggering a state change update will not crash if the callback to 417 * WifiServiceImpl is null. 418 */ 419 @Test 420 public void testNullCallbackToWifiServiceImplForStateChange() throws Exception { 421 //set the callback to null 422 mWifiStateMachinePrime.registerSoftApCallback(null); 423 424 enterSoftApActiveMode(); 425 426 mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); 427 mLooper.dispatchAll(); 428 429 verify(mSoftApStateMachineCallback, never()).onStateChanged(anyInt(), anyInt()); 430 } 431 432 /** 433 * Verifies that NumClientsChanged event is being passed from SoftApManager to WifiServiceImpl 434 */ 435 @Test 436 public void callsWifiServiceCallbackOnSoftApNumClientsChanged() throws Exception { 437 final int testNumClients = 3; 438 enterSoftApActiveMode(); 439 mSoftApManagerCallback.onNumClientsChanged(testNumClients); 440 mLooper.dispatchAll(); 441 442 verify(mSoftApStateMachineCallback).onNumClientsChanged(testNumClients); 443 } 444 445 /** 446 * Verifies that triggering a number of clients changed update will not crash if the callback to 447 * WifiServiceImpl is null. 448 */ 449 @Test 450 public void testNullCallbackToWifiServiceImplForNumClientsChanged() throws Exception { 451 452 final int testNumClients = 3; 453 454 //set the callback to null 455 mWifiStateMachinePrime.registerSoftApCallback(null); 456 457 enterSoftApActiveMode(); 458 mSoftApManagerCallback.onNumClientsChanged(testNumClients); 459 460 verify(mSoftApStateMachineCallback, never()).onNumClientsChanged(anyInt()); 461 } 462 463 /** 464 * Test that we remain in the active state when we get a state change update that scan mode is 465 * active. 466 * Expectations: We should remain in the ScanOnlyModeActive state. 467 */ 468 @Test 469 public void testScanOnlyModeStaysActiveOnEnabledUpdate() throws Exception { 470 enterScanOnlyModeActiveState(); 471 // now inject failure through the SoftApManager.Listener 472 mScanOnlyListener.onStateChanged(WifiManager.WIFI_STATE_ENABLED); 473 mLooper.dispatchAll(); 474 assertEquals(SCAN_ONLY_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 475 verify(mScanOnlyModeManager, never()).stop(); 476 } 477 478 /** 479 * Test that we do not act on unepected state string messages and remain in the active state. 480 * Expectations: We should remain in the ScanOnlyModeActive state. 481 */ 482 @Test 483 public void testScanOnlyModeStaysActiveOnUnexpectedStateUpdate() throws Exception { 484 enterScanOnlyModeActiveState(); 485 // now inject failure through the SoftApManager.Listener 486 mScanOnlyListener.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING); 487 mLooper.dispatchAll(); 488 assertEquals(SCAN_ONLY_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode()); 489 verify(mScanOnlyModeManager, never()).stop(); 490 } 491 492 /** 493 * Test that a config passed in to the call to enterSoftApMode is used to create the new 494 * SoftApManager. 495 * Expectations: We should create a SoftApManager in WifiInjector with the config passed in to 496 * WifiStateMachinePrime to switch to SoftApMode. 497 */ 498 @Test 499 public void testConfigIsPassedToWifiInjector() throws Exception { 500 WifiConfiguration config = new WifiConfiguration(); 501 config.SSID = "ThisIsAConfig"; 502 SoftApModeConfiguration softApConfig = 503 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config); 504 enterSoftApActiveMode(softApConfig); 505 } 506 507 /** 508 * Test that when enterSoftAPMode is called with a null config, we pass a null config to 509 * WifiInjector.makeSoftApManager. 510 * 511 * Passing a null config to SoftApManager indicates that the default config should be used. 512 * 513 * Expectations: WifiInjector should be called with a null config. 514 */ 515 @Test 516 public void testNullConfigIsPassedToWifiInjector() throws Exception { 517 enterSoftApActiveMode(); 518 } 519 520 /** 521 * Test that two calls to switch to SoftAPMode in succession ends up with the correct config. 522 * 523 * Expectation: we should end up in SoftAPMode state configured with the second config. 524 */ 525 @Test 526 public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception { 527 when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore); 528 WifiConfiguration config1 = new WifiConfiguration(); 529 config1.SSID = "ThisIsAConfig"; 530 SoftApModeConfiguration softApConfig1 = 531 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config1); 532 WifiConfiguration config2 = new WifiConfiguration(); 533 config2.SSID = "ThisIsASecondConfig"; 534 SoftApModeConfiguration softApConfig2 = 535 new SoftApModeConfiguration(WifiManager.IFACE_IP_MODE_TETHERED, config2); 536 537 when(mWifiInjector.makeSoftApManager(any(WifiManager.SoftApCallback.class), 538 eq(softApConfig1))) 539 .thenReturn(mSoftApManager); 540 // make a second softap manager 541 SoftApManager softapManager = mock(SoftApManager.class); 542 when(mWifiInjector.makeSoftApManager(any(WifiManager.SoftApCallback.class), 543 eq(softApConfig2))) 544 .thenReturn(softapManager); 545 546 mWifiStateMachinePrime.enterSoftAPMode(softApConfig1); 547 mWifiStateMachinePrime.enterSoftAPMode(softApConfig2); 548 mLooper.dispatchAll(); 549 verify(mSoftApManager).start(); 550 verify(softapManager).start(); 551 verify(mBatteryStats).noteWifiOn(); 552 } 553 554 /** 555 * Test that we safely disable wifi if it is already disabled. 556 * Expectations: We should not interact with WifiNative since we should have already cleaned up 557 * everything. 558 */ 559 @Test 560 public void disableWifiWhenAlreadyOff() throws Exception { 561 mWifiStateMachinePrime.disableWifi(); 562 // since we start up in disabled, this should not re-enter the disabled state 563 verify(mDefaultModeManager).sendScanAvailableBroadcast(eq(mContext), eq(false)); 564 } 565 566 /** 567 * Trigger recovery and a bug report if we see a native failure. 568 */ 569 @Test 570 public void handleWifiNativeFailure() throws Exception { 571 mWifiNativeStatusListener.onStatusChanged(false); 572 mLooper.dispatchAll(); 573 verify(mWifiDiagnostics).captureBugReportData( 574 WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE); 575 verify(mSelfRecovery).trigger(eq(SelfRecovery.REASON_WIFINATIVE_FAILURE)); 576 } 577 578 /** 579 * Verify an onStatusChanged callback with "true" does not trigger recovery. 580 */ 581 @Test 582 public void handleWifiNativeStatusReady() throws Exception { 583 mWifiNativeStatusListener.onStatusChanged(true); 584 mLooper.dispatchAll(); 585 verify(mWifiDiagnostics, never()).captureBugReportData( 586 WifiDiagnostics.REPORT_REASON_WIFINATIVE_FAILURE); 587 verify(mSelfRecovery, never()).trigger(eq(SelfRecovery.REASON_WIFINATIVE_FAILURE)); 588 } 589 590 /** 591 * Verify that mode stop is safe even if the underlying Client mode exited already. 592 */ 593 @Test 594 public void shutdownWifiDoesNotCrashWhenClientModeExitsOnDestroyed() throws Exception { 595 enterClientModeActiveState(); 596 597 mClientListener.onStateChanged(WifiManager.WIFI_STATE_DISABLED); 598 mLooper.dispatchAll(); 599 600 mWifiStateMachinePrime.shutdownWifi(); 601 602 assertEquals(WifiManager.WIFI_STATE_DISABLED, mClientModeCallback.currentState); 603 } 604 605 /** 606 * Verify that an interface destruction callback is safe after already having been stopped. 607 */ 608 @Test 609 public void onDestroyedCallbackDoesNotCrashWhenClientModeAlreadyStopped() throws Exception { 610 enterClientModeActiveState(); 611 612 mWifiStateMachinePrime.shutdownWifi(); 613 614 mClientListener.onStateChanged(WifiManager.WIFI_STATE_DISABLED); 615 mLooper.dispatchAll(); 616 617 assertEquals(WifiManager.WIFI_STATE_DISABLED, mClientModeCallback.currentState); 618 } 619 620 /** 621 * Verify that mode stop is safe even if the underlying softap mode exited already. 622 */ 623 @Test 624 public void shutdownWifiDoesNotCrashWhenSoftApExitsOnDestroyed() throws Exception { 625 enterSoftApActiveMode(); 626 627 mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); 628 mLooper.dispatchAll(); 629 630 mWifiStateMachinePrime.shutdownWifi(); 631 632 verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); 633 } 634 635 /** 636 * Verify that an interface destruction callback is safe after already having been stopped. 637 */ 638 @Test 639 public void onDestroyedCallbackDoesNotCrashWhenSoftApModeAlreadyStopped() throws Exception { 640 enterSoftApActiveMode(); 641 642 mWifiStateMachinePrime.shutdownWifi(); 643 644 mSoftApManagerCallback.onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); 645 mLooper.dispatchAll(); 646 647 verify(mSoftApStateMachineCallback).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); 648 } 649 650 /** 651 * Verify that we do not crash when calling dump and wifi is fully disabled. 652 */ 653 @Test 654 public void dumpWhenWifiFullyOffDoesNotCrash() throws Exception { 655 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 656 PrintWriter writer = new PrintWriter(stream); 657 mWifiStateMachinePrime.dump(null, writer, null); 658 } 659 660 /** 661 * Verify that we trigger dump on active mode managers. 662 */ 663 @Test 664 public void dumpCallsActiveModeManagers() throws Exception { 665 enterSoftApActiveMode(); 666 enterClientModeActiveState(); 667 enterScanOnlyModeActiveState(); 668 669 ByteArrayOutputStream stream = new ByteArrayOutputStream(); 670 PrintWriter writer = new PrintWriter(stream); 671 mWifiStateMachinePrime.dump(null, writer, null); 672 673 verify(mSoftApManager).dump(eq(null), eq(writer), eq(null)); 674 // can only be in scan or client, so we should not have a client mode active 675 verify(mClientModeManager, never()).dump(eq(null), eq(writer), eq(null)); 676 verify(mScanOnlyModeManager).dump(eq(null), eq(writer), eq(null)); 677 } 678} 679