Home | History | Annotate | Download | only in wifi
      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 
     17 package com.android.server.wifi;
     18 
     19 import static org.junit.Assert.assertEquals;
     20 import static org.mockito.Mockito.*;
     21 
     22 import android.net.wifi.IApInterface;
     23 import android.net.wifi.IWificond;
     24 import android.net.wifi.WifiConfiguration;
     25 import android.net.wifi.WifiManager;
     26 import android.os.INetworkManagementService;
     27 import android.os.test.TestLooper;
     28 import android.test.suitebuilder.annotation.SmallTest;
     29 import android.util.Log;
     30 
     31 import org.junit.After;
     32 import org.junit.Before;
     33 import org.junit.Test;
     34 import org.mockito.Mock;
     35 import org.mockito.MockitoAnnotations;
     36 import org.mockito.invocation.InvocationOnMock;
     37 import org.mockito.stubbing.Answer;
     38 
     39 /**
     40  * Unit tests for {@link com.android.server.wifi.WifiStateMachinePrime}.
     41  */
     42 @SmallTest
     43 public class WifiStateMachinePrimeTest {
     44     public static final String TAG = "WifiStateMachinePrimeTest";
     45 
     46     private static final String CLIENT_MODE_STATE_STRING = "ClientModeState";
     47     private static final String SCAN_ONLY_MODE_STATE_STRING = "ScanOnlyModeState";
     48     private static final String SOFT_AP_MODE_STATE_STRING = "SoftAPModeState";
     49     private static final String WIFI_DISABLED_STATE_STRING = "WifiDisabledState";
     50     private static final String CLIENT_MODE_ACTIVE_STATE_STRING = "ClientModeActiveState";
     51     private static final String SCAN_ONLY_MODE_ACTIVE_STATE_STRING = "ScanOnlyModeActiveState";
     52     private static final String SOFT_AP_MODE_ACTIVE_STATE_STRING = "SoftAPModeActiveState";
     53 
     54     @Mock WifiInjector mWifiInjector;
     55     @Mock WifiApConfigStore mWifiApConfigStore;
     56     TestLooper mLooper;
     57     @Mock IWificond mWificond;
     58     @Mock IApInterface mApInterface;
     59     @Mock INetworkManagementService mNMService;
     60     @Mock SoftApManager mSoftApManager;
     61     SoftApManager.Listener mSoftApListener;
     62     WifiStateMachinePrime mWifiStateMachinePrime;
     63 
     64     /**
     65      * Set up the test environment.
     66      */
     67     @Before
     68     public void setUp() throws Exception {
     69         Log.d(TAG, "Setting up ...");
     70 
     71         MockitoAnnotations.initMocks(this);
     72         mLooper = new TestLooper();
     73 
     74         mWifiInjector = mock(WifiInjector.class);
     75         mWifiStateMachinePrime = createWifiStateMachinePrime();
     76     }
     77 
     78     private WifiStateMachinePrime createWifiStateMachinePrime() {
     79         when(mWifiInjector.makeWificond()).thenReturn(null);
     80         return new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(), mNMService);
     81     }
     82 
     83     /**
     84      * Clean up after tests - explicitly set tested object to null.
     85      */
     86     @After
     87     public void cleanUp() throws Exception {
     88         mWifiStateMachinePrime = null;
     89     }
     90 
     91     private void enterSoftApActiveMode() throws Exception {
     92         enterSoftApActiveMode(null);
     93     }
     94 
     95     /**
     96      * Helper method to enter the SoftApActiveMode for WifiStateMachinePrime.
     97      *
     98      * This method puts the test object into the correct state and verifies steps along the way.
     99      */
    100     private void enterSoftApActiveMode(WifiConfiguration wifiConfig) throws Exception {
    101         String fromState = mWifiStateMachinePrime.getCurrentMode();
    102         when(mWifiInjector.makeWificond()).thenReturn(mWificond);
    103         when(mWificond.createApInterface()).thenReturn(mApInterface);
    104         doAnswer(
    105                 new Answer<Object>() {
    106                     public SoftApManager answer(InvocationOnMock invocation) {
    107                         Object[] args = invocation.getArguments();
    108                         assertEquals(mNMService, (INetworkManagementService) args[0]);
    109                         mSoftApListener = (SoftApManager.Listener) args[1];
    110                         assertEquals(mApInterface, (IApInterface) args[2]);
    111                         assertEquals(wifiConfig, (WifiConfiguration) args[3]);
    112                         return mSoftApManager;
    113                     }
    114                 }).when(mWifiInjector).makeSoftApManager(any(INetworkManagementService.class),
    115                                                          any(SoftApManager.Listener.class),
    116                                                          any(IApInterface.class),
    117                                                          any());
    118         mWifiStateMachinePrime.enterSoftAPMode(wifiConfig);
    119         mLooper.dispatchAll();
    120         Log.e("WifiStateMachinePrimeTest", "check fromState: " + fromState);
    121         if (!fromState.equals(WIFI_DISABLED_STATE_STRING)) {
    122             verify(mWificond).tearDownInterfaces();
    123         }
    124         assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    125         verify(mSoftApManager).start();
    126     }
    127 
    128     /**
    129      * Test that when a new instance of WifiStateMachinePrime is created, any existing interfaces in
    130      * the retrieved Wificond instance are cleaned up.
    131      * Expectations:  When the new WifiStateMachinePrime instance is created a call to
    132      * Wificond.tearDownInterfaces() is made.
    133      */
    134     @Test
    135     public void testWificondExistsOnStartup() throws Exception {
    136         when(mWifiInjector.makeWificond()).thenReturn(mWificond);
    137         WifiStateMachinePrime testWifiStateMachinePrime =
    138                 new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(), mNMService);
    139         verify(mWificond).tearDownInterfaces();
    140     }
    141 
    142     /**
    143      * Test that WifiStateMachinePrime properly enters the SoftApModeActiveState from the
    144      * WifiDisabled state.
    145      */
    146     @Test
    147     public void testEnterSoftApModeFromDisabled() throws Exception {
    148         enterSoftApActiveMode();
    149     }
    150 
    151     /**
    152      * Test that WifiStateMachinePrime properly enters the SoftApModeActiveState from another state.
    153      * Expectations: When going from one state to another, any interfaces that are still up are torn
    154      * down.
    155      */
    156     @Test
    157     public void testEnterSoftApModeFromDifferentState() throws Exception {
    158         when(mWifiInjector.makeWificond()).thenReturn(mWificond);
    159         mWifiStateMachinePrime.enterClientMode();
    160         mLooper.dispatchAll();
    161         assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    162         enterSoftApActiveMode();
    163     }
    164 
    165     /**
    166      * Test that we can disable wifi fully from the SoftApModeActiveState.
    167      */
    168     @Test
    169     public void testDisableWifiFromSoftApModeActiveState() throws Exception {
    170         enterSoftApActiveMode();
    171 
    172         mWifiStateMachinePrime.disableWifi();
    173         mLooper.dispatchAll();
    174         verify(mSoftApManager).stop();
    175         verify(mWificond).tearDownInterfaces();
    176         assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    177     }
    178 
    179     /**
    180      * Test that we can disable wifi fully from the SoftApModeState.
    181      */
    182     @Test
    183     public void testDisableWifiFromSoftApModeState() throws Exception {
    184         // Use a failure getting wificond to stay in the SoftAPModeState
    185         when(mWifiInjector.makeWificond()).thenReturn(null);
    186         mWifiStateMachinePrime.enterSoftAPMode(null);
    187         mLooper.dispatchAll();
    188         assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    189 
    190         mWifiStateMachinePrime.disableWifi();
    191         mLooper.dispatchAll();
    192         // mWificond will be null due to this test, no call to tearDownInterfaces here.
    193         assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    194     }
    195 
    196     /**
    197      * Test that we can switch from SoftApActiveMode to another mode.
    198      * Expectation: When switching out of SoftApModeActiveState we stop the SoftApManager and tear
    199      * down existing interfaces.
    200      */
    201     @Test
    202     public void testSwitchModeWhenSoftApActiveMode() throws Exception {
    203         enterSoftApActiveMode();
    204 
    205         mWifiStateMachinePrime.enterClientMode();
    206         mLooper.dispatchAll();
    207         verify(mSoftApManager).stop();
    208         verify(mWificond).tearDownInterfaces();
    209         assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    210     }
    211 
    212     /**
    213      * Test that we do not attempt to enter SoftApModeActiveState when we cannot get a reference to
    214      * wificond.
    215      * Expectations: After a failed attempt to get wificond from WifiInjector, we should remain in
    216      * the SoftApModeState.
    217      */
    218     @Test
    219     public void testWificondNullWhenSwitchingToApMode() throws Exception {
    220         when(mWifiInjector.makeWificond()).thenReturn(null);
    221         mWifiStateMachinePrime.enterSoftAPMode(null);
    222         mLooper.dispatchAll();
    223         assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    224     }
    225 
    226     /**
    227      * Test that we do not attempt to enter SoftApModeActiveState when we cannot get an ApInterface
    228      * from wificond.
    229      * Expectations: After a failed attempt to get an ApInterface from WifiInjector, we should
    230      * remain in the SoftApModeState.
    231      */
    232     @Test
    233     public void testAPInterfaceFailedWhenSwitchingToApMode() throws Exception {
    234         when(mWifiInjector.makeWificond()).thenReturn(mWificond);
    235         when(mWificond.createApInterface()).thenReturn(null);
    236         mWifiStateMachinePrime.enterSoftAPMode(null);
    237         mLooper.dispatchAll();
    238         assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    239     }
    240 
    241     /**
    242      * Test that we do can enter the SoftApModeActiveState if we are already in the SoftApModeState.
    243      * Expectations: We should exit the current SoftApModeState and re-enter before successfully
    244      * entering the SoftApModeActiveState.
    245      */
    246     @Test
    247     public void testEnterSoftApModeActiveWhenAlreadyInSoftApMode() throws Exception {
    248         when(mWifiInjector.makeWificond()).thenReturn(mWificond);
    249         when(mWificond.createApInterface()).thenReturn(null);
    250         mWifiStateMachinePrime.enterSoftAPMode(null);
    251         mLooper.dispatchAll();
    252         assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    253 
    254         enterSoftApActiveMode();
    255     }
    256 
    257     /**
    258      * Test that we return to the SoftApModeState after a failure is reported when in the
    259      * SoftApModeActiveState.
    260      * Expectations: We should exit the SoftApModeActiveState and stop the SoftApManager.
    261      */
    262     @Test
    263     public void testSoftApFailureWhenActive() throws Exception {
    264         enterSoftApActiveMode();
    265         // now inject failure through the SoftApManager.Listener
    266         mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
    267         mLooper.dispatchAll();
    268         assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    269         verify(mSoftApManager).stop();
    270     }
    271 
    272     /**
    273      * Test that we return to the SoftApModeState after the SoftApManager is stopped in the
    274      * SoftApModeActiveState.
    275      * Expectations: We should exit the SoftApModeActiveState and stop the SoftApManager.
    276      */
    277     @Test
    278     public void testSoftApDisabledWhenActive() throws Exception {
    279         enterSoftApActiveMode();
    280         // now inject failure through the SoftApManager.Listener
    281         mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
    282         mLooper.dispatchAll();
    283         assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    284         verify(mSoftApManager).stop();
    285     }
    286 
    287     /**
    288      * Test that a config passed in to the call to enterSoftApMode is used to create the new
    289      * SoftApManager.
    290      * Expectations: We should create a SoftApManager in WifiInjector with the config passed in to
    291      * WifiStateMachinePrime to switch to SoftApMode.
    292      */
    293     @Test
    294     public void testConfigIsPassedToWifiInjector() throws Exception {
    295         WifiConfiguration config = new WifiConfiguration();
    296         config.SSID = "ThisIsAConfig";
    297         enterSoftApActiveMode(config);
    298     }
    299 
    300     /**
    301      * Test that when enterSoftAPMode is called with a null config, we pass a null config to
    302      * WifiInjector.makeSoftApManager.
    303      *
    304      * Passing a null config to SoftApManager indicates that the default config should be used.
    305      *
    306      * Expectations: WifiInjector should be called with a null config.
    307      */
    308     @Test
    309     public void testNullConfigIsPassedToWifiInjector() throws Exception {
    310         enterSoftApActiveMode(null);
    311     }
    312 
    313     /**
    314      * Test that the proper config is used if a prior attempt fails without using the config.
    315      * Expectations: A call to start softap with a null config fails, but a second call has a set
    316      * config - this second call should use the correct config.
    317      */
    318     @Test
    319     public void testNullConfigFailsSecondCallWithConfigSuccessful() throws Exception {
    320         when(mWifiInjector.makeWificond()).thenReturn(mWificond);
    321         when(mWificond.createApInterface()).thenReturn(null);
    322         mWifiStateMachinePrime.enterSoftAPMode(null);
    323         mLooper.dispatchAll();
    324         assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    325         WifiConfiguration config = new WifiConfiguration();
    326         config.SSID = "ThisIsAConfig";
    327         enterSoftApActiveMode(config);
    328     }
    329 
    330     /**
    331      * Test that a failed call to start softap with a valid config has the config saved for future
    332      * calls to enable softap.
    333      *
    334      * Expectations: A call to start SoftAPMode with a config should write out the config if we
    335      * did not create a SoftApManager.
    336      */
    337     @Test
    338     public void testValidConfigIsSavedOnFailureToStart() throws Exception {
    339         when(mWifiInjector.makeWificond()).thenReturn(null);
    340         when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
    341         WifiConfiguration config = new WifiConfiguration();
    342         config.SSID = "ThisIsAConfig";
    343         mWifiStateMachinePrime.enterSoftAPMode(config);
    344         mLooper.dispatchAll();
    345         assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    346         verify(mWifiApConfigStore).setApConfiguration(eq(config));
    347     }
    348 
    349     /**
    350      * Thest that two calls to switch to SoftAPMode in succession ends up with the correct config.
    351      *
    352      * Expectation: we should end up in SoftAPMode state configured with the second config.
    353      */
    354     @Test
    355     public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception {
    356         when(mWifiInjector.makeWificond()).thenReturn(mWificond);
    357         when(mWificond.createApInterface()).thenReturn(mApInterface);
    358         when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
    359         WifiConfiguration config1 = new WifiConfiguration();
    360         config1.SSID = "ThisIsAConfig";
    361         WifiConfiguration config2 = new WifiConfiguration();
    362         config2.SSID = "ThisIsASecondConfig";
    363 
    364         when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
    365                                              any(SoftApManager.Listener.class),
    366                                              any(IApInterface.class),
    367                                              eq(config1)))
    368                 .thenReturn(mSoftApManager);
    369         when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
    370                                              any(SoftApManager.Listener.class),
    371                                              any(IApInterface.class),
    372                                              eq(config2)))
    373                 .thenReturn(mSoftApManager);
    374 
    375 
    376         mWifiStateMachinePrime.enterSoftAPMode(config1);
    377         mWifiStateMachinePrime.enterSoftAPMode(config2);
    378         mLooper.dispatchAll();
    379         assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
    380     }
    381 
    382     /**
    383      * Test that we safely disable wifi if it is already disabled.
    384      * Expectations: We should not interact with wificond since we should have already cleaned up
    385      * everything.
    386      */
    387     @Test
    388     public void disableWifiWhenAlreadyOff() throws Exception {
    389         verifyNoMoreInteractions(mWificond);
    390         mWifiStateMachinePrime.disableWifi();
    391     }
    392 }
    393