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