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.mockito.Mockito.any; 20 import static org.mockito.Mockito.anyInt; 21 import static org.mockito.Mockito.eq; 22 import static org.mockito.Mockito.inOrder; 23 import static org.mockito.Mockito.mock; 24 import static org.mockito.Mockito.never; 25 import static org.mockito.Mockito.verify; 26 import static org.mockito.Mockito.when; 27 28 import android.content.BroadcastReceiver; 29 import android.content.Context; 30 import android.content.IntentFilter; 31 import android.net.ConnectivityManager; 32 import android.net.InterfaceConfiguration; 33 import android.net.LinkAddress; 34 import android.net.wifi.WifiConfiguration; 35 import android.net.wifi.WifiManager; 36 import android.os.INetworkManagementService; 37 import android.test.suitebuilder.annotation.SmallTest; 38 39 import org.junit.Before; 40 import org.junit.Test; 41 import org.mockito.ArgumentCaptor; 42 import org.mockito.InOrder; 43 import org.mockito.Mock; 44 import org.mockito.MockitoAnnotations; 45 46 import java.util.ArrayList; 47 import java.util.Arrays; 48 import java.util.Locale; 49 50 /** Unit tests for {@link SoftApManager}. */ 51 @SmallTest 52 public class SoftApManagerTest { 53 54 private static final String TAG = "SoftApManagerTest"; 55 56 private static final String TEST_INTERFACE_NAME = "TestInterface"; 57 private static final String TEST_COUNTRY_CODE = "TestCountry"; 58 private static final Integer[] ALLOWED_2G_CHANNELS = {1, 2, 3, 4}; 59 private static final String[] AVAILABLE_DEVICES = { TEST_INTERFACE_NAME }; 60 61 private final ArrayList<Integer> mAllowed2GChannels = 62 new ArrayList<Integer>(Arrays.asList(ALLOWED_2G_CHANNELS)); 63 64 MockLooper mLooper; 65 @Mock Context mContext; 66 @Mock WifiNative mWifiNative; 67 @Mock INetworkManagementService mNmService; 68 @Mock ConnectivityManager mConnectivityManager; 69 @Mock SoftApManager.Listener mListener; 70 @Mock InterfaceConfiguration mInterfaceConfiguration; 71 72 /** 73 * Internal BroadcastReceiver that SoftApManager uses to listen for tethering 74 * events from ConnectivityManager. 75 */ 76 BroadcastReceiver mBroadcastReceiver; 77 78 SoftApManager mSoftApManager; 79 80 /** Sets up test. */ 81 @Before setUp()82 public void setUp() throws Exception { 83 MockitoAnnotations.initMocks(this); 84 mLooper = new MockLooper(); 85 86 when(mWifiNative.getInterfaceName()).thenReturn(TEST_INTERFACE_NAME); 87 when(mNmService.getInterfaceConfig(TEST_INTERFACE_NAME)) 88 .thenReturn(mInterfaceConfiguration); 89 when(mConnectivityManager.getTetherableWifiRegexs()) 90 .thenReturn(AVAILABLE_DEVICES); 91 92 mSoftApManager = new SoftApManager(mContext, 93 mLooper.getLooper(), 94 mWifiNative, 95 mNmService, 96 mConnectivityManager, 97 TEST_COUNTRY_CODE, 98 mAllowed2GChannels, 99 mListener); 100 ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor = 101 ArgumentCaptor.forClass(BroadcastReceiver.class); 102 verify(mContext).registerReceiver( 103 broadcastReceiverCaptor.capture(), any(IntentFilter.class)); 104 mBroadcastReceiver = broadcastReceiverCaptor.getValue(); 105 106 mLooper.dispatchAll(); 107 } 108 109 /** Verifies startSoftAp will fail if AP configuration is not provided. */ 110 @Test startSoftApWithoutConfig()111 public void startSoftApWithoutConfig() throws Exception { 112 InOrder order = inOrder(mListener); 113 114 mSoftApManager.start(null); 115 mLooper.dispatchAll(); 116 117 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); 118 order.verify(mListener).onStateChanged( 119 WifiManager.WIFI_AP_STATE_FAILED, WifiManager.SAP_START_FAILURE_GENERAL); 120 } 121 122 /** Tests the handling of timeout after tethering is started. */ 123 @Test tetheringTimedOut()124 public void tetheringTimedOut() throws Exception { 125 startSoftApAndVerifyEnabled(); 126 announceAvailableForTethering(); 127 verifyTetheringRequested(); 128 129 InOrder order = inOrder(mListener); 130 131 /* Move the time forward to simulate notification timeout. */ 132 mLooper.moveTimeForward(5000); 133 mLooper.dispatchAll(); 134 135 /* Verify soft ap is disabled. */ 136 verify(mNmService).stopAccessPoint(eq(TEST_INTERFACE_NAME)); 137 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); 138 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); 139 } 140 141 /** Tests the handling of tethered notification after tethering is started. */ 142 @Test tetherCompleted()143 public void tetherCompleted() throws Exception { 144 startSoftApAndVerifyEnabled(); 145 announceAvailableForTethering(); 146 verifyTetheringRequested(); 147 announceTethered(); 148 verifySoftApNotDisabled(); 149 } 150 151 /** Tests the handling of stop command when soft AP is not started. */ 152 @Test stopWhenNotStarted()153 public void stopWhenNotStarted() throws Exception { 154 mSoftApManager.stop(); 155 mLooper.dispatchAll(); 156 /* Verify no state changes. */ 157 verify(mListener, never()).onStateChanged(anyInt(), anyInt()); 158 } 159 160 /** Tests the handling of stop command when soft AP is started. */ 161 @Test stopWhenStarted()162 public void stopWhenStarted() throws Exception { 163 startSoftApAndVerifyEnabled(); 164 165 InOrder order = inOrder(mListener); 166 167 mSoftApManager.stop(); 168 mLooper.dispatchAll(); 169 170 verify(mNmService).stopAccessPoint(TEST_INTERFACE_NAME); 171 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); 172 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); 173 } 174 175 /** Starts soft AP and verifies that it is enabled successfully. */ startSoftApAndVerifyEnabled()176 protected void startSoftApAndVerifyEnabled() throws Exception { 177 InOrder order = inOrder(mListener); 178 179 /** 180 * Only test the default configuration. Testing for different configurations 181 * are taken care of by ApConfigUtilTest. 182 */ 183 WifiConfiguration config = new WifiConfiguration(); 184 config.apBand = WifiConfiguration.AP_BAND_2GHZ; 185 when(mWifiNative.isHalStarted()).thenReturn(false); 186 when(mWifiNative.setCountryCodeHal(TEST_COUNTRY_CODE.toUpperCase(Locale.ROOT))) 187 .thenReturn(true); 188 mSoftApManager.start(config); 189 mLooper.dispatchAll(); 190 verify(mNmService).startAccessPoint( 191 any(WifiConfiguration.class), eq(TEST_INTERFACE_NAME)); 192 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLING, 0); 193 order.verify(mListener).onStateChanged(WifiManager.WIFI_AP_STATE_ENABLED, 0); 194 } 195 196 /** Verifies that soft AP was not disabled. */ verifySoftApNotDisabled()197 protected void verifySoftApNotDisabled() throws Exception { 198 verify(mListener, never()).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLING, 0); 199 verify(mListener, never()).onStateChanged(WifiManager.WIFI_AP_STATE_DISABLED, 0); 200 } 201 202 /** Sends a broadcast intent indicating that the interface is available for tethering. */ announceAvailableForTethering()203 protected void announceAvailableForTethering() throws Exception { 204 when(mConnectivityManager.tether(TEST_INTERFACE_NAME)) 205 .thenReturn(ConnectivityManager.TETHER_ERROR_NO_ERROR); 206 ArrayList<String> availableList = 207 new ArrayList<String>(Arrays.asList(AVAILABLE_DEVICES)); 208 TestUtil.sendTetherStateChanged( 209 mBroadcastReceiver, mContext, availableList, new ArrayList<String>()); 210 mLooper.dispatchAll(); 211 } 212 213 /** Verifies that tethering was requested. */ verifyTetheringRequested()214 protected void verifyTetheringRequested() throws Exception { 215 verify(mInterfaceConfiguration).setLinkAddress(any(LinkAddress.class)); 216 verify(mInterfaceConfiguration).setInterfaceUp(); 217 verify(mNmService).setInterfaceConfig(eq(TEST_INTERFACE_NAME), eq(mInterfaceConfiguration)); 218 } 219 220 /** Sends a broadcast intent indicating that the interface is tethered. */ announceTethered()221 protected void announceTethered() throws Exception { 222 ArrayList<String> deviceList = 223 new ArrayList<String>(Arrays.asList(AVAILABLE_DEVICES)); 224 TestUtil.sendTetherStateChanged( 225 mBroadcastReceiver, mContext, deviceList, deviceList); 226 mLooper.dispatchAll(); 227 } 228 } 229