blob: 060919d6563218a6b070586bcad1aa238cf9799f [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wifi;
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.*;
import android.net.wifi.IApInterface;
import android.net.wifi.IWificond;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiManager;
import android.os.INetworkManagementService;
import android.os.test.TestLooper;
import android.test.suitebuilder.annotation.SmallTest;
import android.util.Log;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
/**
* Unit tests for {@link com.android.server.wifi.WifiStateMachinePrime}.
*/
@SmallTest
public class WifiStateMachinePrimeTest {
public static final String TAG = "WifiStateMachinePrimeTest";
private static final String CLIENT_MODE_STATE_STRING = "ClientModeState";
private static final String SCAN_ONLY_MODE_STATE_STRING = "ScanOnlyModeState";
private static final String SOFT_AP_MODE_STATE_STRING = "SoftAPModeState";
private static final String WIFI_DISABLED_STATE_STRING = "WifiDisabledState";
private static final String CLIENT_MODE_ACTIVE_STATE_STRING = "ClientModeActiveState";
private static final String SCAN_ONLY_MODE_ACTIVE_STATE_STRING = "ScanOnlyModeActiveState";
private static final String SOFT_AP_MODE_ACTIVE_STATE_STRING = "SoftAPModeActiveState";
private static final String WIFI_IFACE_NAME = "mockWlan";
@Mock WifiInjector mWifiInjector;
@Mock WifiNative mWifiNative;
@Mock WifiApConfigStore mWifiApConfigStore;
TestLooper mLooper;
@Mock IWificond mWificond;
@Mock IApInterface mApInterface;
@Mock INetworkManagementService mNMService;
@Mock SoftApManager mSoftApManager;
SoftApManager.Listener mSoftApListener;
WifiStateMachinePrime mWifiStateMachinePrime;
/**
* Set up the test environment.
*/
@Before
public void setUp() throws Exception {
Log.d(TAG, "Setting up ...");
MockitoAnnotations.initMocks(this);
mLooper = new TestLooper();
when(mWifiInjector.getWifiNative()).thenReturn(mWifiNative);
when(mWifiNative.getInterfaceName()).thenReturn(WIFI_IFACE_NAME);
mWifiStateMachinePrime = createWifiStateMachinePrime();
}
private WifiStateMachinePrime createWifiStateMachinePrime() {
when(mWifiInjector.makeWificond()).thenReturn(null);
return new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(), mNMService);
}
/**
* Clean up after tests - explicitly set tested object to null.
*/
@After
public void cleanUp() throws Exception {
mWifiStateMachinePrime = null;
}
private void enterSoftApActiveMode() throws Exception {
enterSoftApActiveMode(null);
}
/**
* Helper method to enter the SoftApActiveMode for WifiStateMachinePrime.
*
* This method puts the test object into the correct state and verifies steps along the way.
*/
private void enterSoftApActiveMode(WifiConfiguration wifiConfig) throws Exception {
String fromState = mWifiStateMachinePrime.getCurrentMode();
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(mApInterface);
doAnswer(
new Answer<Object>() {
public SoftApManager answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
assertEquals(mNMService, (INetworkManagementService) args[0]);
mSoftApListener = (SoftApManager.Listener) args[1];
assertEquals(mApInterface, (IApInterface) args[2]);
assertEquals(wifiConfig, (WifiConfiguration) args[3]);
return mSoftApManager;
}
}).when(mWifiInjector).makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
any());
mWifiStateMachinePrime.enterSoftAPMode(wifiConfig);
mLooper.dispatchAll();
Log.e("WifiStateMachinePrimeTest", "check fromState: " + fromState);
if (!fromState.equals(WIFI_DISABLED_STATE_STRING)) {
verify(mWificond).tearDownInterfaces();
}
assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
verify(mSoftApManager).start();
}
/**
* Test that when a new instance of WifiStateMachinePrime is created, any existing interfaces in
* the retrieved Wificond instance are cleaned up.
* Expectations: When the new WifiStateMachinePrime instance is created a call to
* Wificond.tearDownInterfaces() is made.
*/
@Test
public void testWificondExistsOnStartup() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
WifiStateMachinePrime testWifiStateMachinePrime =
new WifiStateMachinePrime(mWifiInjector, mLooper.getLooper(), mNMService);
verify(mWificond).tearDownInterfaces();
}
/**
* Test that WifiStateMachinePrime properly enters the SoftApModeActiveState from the
* WifiDisabled state.
*/
@Test
public void testEnterSoftApModeFromDisabled() throws Exception {
enterSoftApActiveMode();
}
/**
* Test that WifiStateMachinePrime properly enters the SoftApModeActiveState from another state.
* Expectations: When going from one state to another, any interfaces that are still up are torn
* down.
*/
@Test
public void testEnterSoftApModeFromDifferentState() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
mWifiStateMachinePrime.enterClientMode();
mLooper.dispatchAll();
assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
enterSoftApActiveMode();
}
/**
* Test that we can disable wifi fully from the SoftApModeActiveState.
*/
@Test
public void testDisableWifiFromSoftApModeActiveState() throws Exception {
enterSoftApActiveMode();
mWifiStateMachinePrime.disableWifi();
mLooper.dispatchAll();
verify(mSoftApManager).stop();
verify(mWificond).tearDownInterfaces();
assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
* Test that we can disable wifi fully from the SoftApModeState.
*/
@Test
public void testDisableWifiFromSoftApModeState() throws Exception {
// Use a failure getting wificond to stay in the SoftAPModeState
when(mWifiInjector.makeWificond()).thenReturn(null);
mWifiStateMachinePrime.enterSoftAPMode(null);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
mWifiStateMachinePrime.disableWifi();
mLooper.dispatchAll();
// mWificond will be null due to this test, no call to tearDownInterfaces here.
assertEquals(WIFI_DISABLED_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
* Test that we can switch from SoftApActiveMode to another mode.
* Expectation: When switching out of SoftApModeActiveState we stop the SoftApManager and tear
* down existing interfaces.
*/
@Test
public void testSwitchModeWhenSoftApActiveMode() throws Exception {
enterSoftApActiveMode();
mWifiStateMachinePrime.enterClientMode();
mLooper.dispatchAll();
verify(mSoftApManager).stop();
verify(mWificond).tearDownInterfaces();
assertEquals(CLIENT_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
* Test that we do not attempt to enter SoftApModeActiveState when we cannot get a reference to
* wificond.
* Expectations: After a failed attempt to get wificond from WifiInjector, we should remain in
* the SoftApModeState.
*/
@Test
public void testWificondNullWhenSwitchingToApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(null);
mWifiStateMachinePrime.enterSoftAPMode(null);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
* Test that we do not attempt to enter SoftApModeActiveState when we cannot get an ApInterface
* from wificond.
* Expectations: After a failed attempt to get an ApInterface from WifiInjector, we should
* remain in the SoftApModeState.
*/
@Test
public void testAPInterfaceFailedWhenSwitchingToApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
mWifiStateMachinePrime.enterSoftAPMode(null);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
* Test that we do can enter the SoftApModeActiveState if we are already in the SoftApModeState.
* Expectations: We should exit the current SoftApModeState and re-enter before successfully
* entering the SoftApModeActiveState.
*/
@Test
public void testEnterSoftApModeActiveWhenAlreadyInSoftApMode() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
mWifiStateMachinePrime.enterSoftAPMode(null);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
enterSoftApActiveMode();
}
/**
* Test that we return to the SoftApModeState after a failure is reported when in the
* SoftApModeActiveState.
* Expectations: We should exit the SoftApModeActiveState and stop the SoftApManager.
*/
@Test
public void testSoftApFailureWhenActive() throws Exception {
enterSoftApActiveMode();
// now inject failure through the SoftApManager.Listener
mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
verify(mSoftApManager).stop();
}
/**
* Test that we return to the SoftApModeState after the SoftApManager is stopped in the
* SoftApModeActiveState.
* Expectations: We should exit the SoftApModeActiveState and stop the SoftApManager.
*/
@Test
public void testSoftApDisabledWhenActive() throws Exception {
enterSoftApActiveMode();
// now inject failure through the SoftApManager.Listener
mSoftApListener.onStateChanged(WifiManager.WIFI_AP_STATE_FAILED, 0);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
verify(mSoftApManager).stop();
}
/**
* Test that a config passed in to the call to enterSoftApMode is used to create the new
* SoftApManager.
* Expectations: We should create a SoftApManager in WifiInjector with the config passed in to
* WifiStateMachinePrime to switch to SoftApMode.
*/
@Test
public void testConfigIsPassedToWifiInjector() throws Exception {
WifiConfiguration config = new WifiConfiguration();
config.SSID = "ThisIsAConfig";
enterSoftApActiveMode(config);
}
/**
* Test that when enterSoftAPMode is called with a null config, we pass a null config to
* WifiInjector.makeSoftApManager.
*
* Passing a null config to SoftApManager indicates that the default config should be used.
*
* Expectations: WifiInjector should be called with a null config.
*/
@Test
public void testNullConfigIsPassedToWifiInjector() throws Exception {
enterSoftApActiveMode(null);
}
/**
* Test that the proper config is used if a prior attempt fails without using the config.
* Expectations: A call to start softap with a null config fails, but a second call has a set
* config - this second call should use the correct config.
*/
@Test
public void testNullConfigFailsSecondCallWithConfigSuccessful() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(null);
mWifiStateMachinePrime.enterSoftAPMode(null);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
WifiConfiguration config = new WifiConfiguration();
config.SSID = "ThisIsAConfig";
enterSoftApActiveMode(config);
}
/**
* Test that a failed call to start softap with a valid config has the config saved for future
* calls to enable softap.
*
* Expectations: A call to start SoftAPMode with a config should write out the config if we
* did not create a SoftApManager.
*/
@Test
public void testValidConfigIsSavedOnFailureToStart() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(null);
when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
WifiConfiguration config = new WifiConfiguration();
config.SSID = "ThisIsAConfig";
mWifiStateMachinePrime.enterSoftAPMode(config);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
verify(mWifiApConfigStore).setApConfiguration(eq(config));
}
/**
* Thest that two calls to switch to SoftAPMode in succession ends up with the correct config.
*
* Expectation: we should end up in SoftAPMode state configured with the second config.
*/
@Test
public void testStartSoftApModeTwiceWithTwoConfigs() throws Exception {
when(mWifiInjector.makeWificond()).thenReturn(mWificond);
when(mWificond.createApInterface(WIFI_IFACE_NAME)).thenReturn(mApInterface);
when(mWifiInjector.getWifiApConfigStore()).thenReturn(mWifiApConfigStore);
WifiConfiguration config1 = new WifiConfiguration();
config1.SSID = "ThisIsAConfig";
WifiConfiguration config2 = new WifiConfiguration();
config2.SSID = "ThisIsASecondConfig";
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
eq(config1)))
.thenReturn(mSoftApManager);
when(mWifiInjector.makeSoftApManager(any(INetworkManagementService.class),
any(SoftApManager.Listener.class),
any(IApInterface.class),
eq(config2)))
.thenReturn(mSoftApManager);
mWifiStateMachinePrime.enterSoftAPMode(config1);
mWifiStateMachinePrime.enterSoftAPMode(config2);
mLooper.dispatchAll();
assertEquals(SOFT_AP_MODE_ACTIVE_STATE_STRING, mWifiStateMachinePrime.getCurrentMode());
}
/**
* Test that we safely disable wifi if it is already disabled.
* Expectations: We should not interact with wificond since we should have already cleaned up
* everything.
*/
@Test
public void disableWifiWhenAlreadyOff() throws Exception {
verifyNoMoreInteractions(mWificond);
mWifiStateMachinePrime.disableWifi();
}
}