1/*
2 * Copyright 2017 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.hotspot2;
18
19import static org.junit.Assert.*;
20import static org.mockito.Mockito.any;
21import static org.mockito.Mockito.anyInt;
22import static org.mockito.Mockito.doReturn;
23import static org.mockito.Mockito.eq;
24import static org.mockito.Mockito.never;
25import static org.mockito.Mockito.times;
26import static org.mockito.Mockito.verify;
27import static org.mockito.Mockito.when;
28
29import android.content.BroadcastReceiver;
30import android.content.Context;
31import android.content.IntentFilter;
32import android.net.ConnectivityManager;
33import android.net.LinkAddress;
34import android.net.LinkProperties;
35import android.net.Network;
36import android.net.NetworkRequest;
37import android.net.NetworkUtils;
38import android.net.RouteInfo;
39import android.net.wifi.WifiConfiguration;
40import android.net.wifi.WifiInfo;
41import android.net.wifi.WifiManager;
42import android.net.wifi.WifiSsid;
43import android.os.Handler;
44import android.os.test.TestLooper;
45import android.support.test.filters.SmallTest;
46
47import com.android.server.wifi.TestUtil;
48
49import org.junit.Before;
50import org.junit.Test;
51import org.mockito.ArgumentCaptor;
52import org.mockito.Mock;
53import org.mockito.MockitoAnnotations;
54
55import java.net.InetAddress;
56
57/**
58 * Unit tests for {@link com.android.server.wifi.hotspot2.PasspointProvisioner}.
59 */
60@SmallTest
61public class OsuNetworkConnectionTest {
62    private static final String TAG = "OsuNetworkConnectionTest";
63    private static final int ENABLE_LOGGING = 1;
64    private static final int DISABLE_LOGGING = 0;
65
66    private static final int TEST_NETWORK_ID = 6;
67    private static final String TEST_NAI = null;
68    private static final String TEST_NAI_OSEN = "access.test.com";
69    private static final WifiSsid TEST_SSID = WifiSsid.createFromAsciiEncoded("Test SSID");
70
71    private OsuNetworkConnection mNetworkConnection;
72    private TestLooper mLooper;
73    private Handler mHandler;
74
75    @Mock Context mContext;
76    @Mock WifiManager mWifiManager;
77    @Mock ConnectivityManager mConnectivityManager;
78    @Mock OsuNetworkConnection.Callbacks mNetworkCallbacks;
79    @Mock WifiInfo mWifiInfo;
80    @Mock Network mCurrentNetwork;
81
82    @Before
83    public void setUp() throws Exception {
84        MockitoAnnotations.initMocks(this);
85        doReturn(mWifiManager).when(mContext)
86                .getSystemService(eq(Context.WIFI_SERVICE));
87        doReturn(mConnectivityManager).when(mContext)
88                .getSystemService(eq(Context.CONNECTIVITY_SERVICE));
89        when(mWifiManager.isWifiEnabled()).thenReturn(true);
90        when(mWifiManager.enableNetwork(TEST_NETWORK_ID, true)).thenReturn(true);
91        when(mWifiManager.addNetwork(any(WifiConfiguration.class))).thenReturn(TEST_NETWORK_ID);
92        when(mWifiInfo.getNetworkId()).thenReturn(TEST_NETWORK_ID);
93        mLooper = new TestLooper();
94        mHandler = new Handler(mLooper.getLooper());
95        mNetworkConnection = new OsuNetworkConnection(mContext);
96        mNetworkConnection.enableVerboseLogging(ENABLE_LOGGING);
97    }
98
99    private LinkProperties createProvisionedLinkProperties() {
100        InetAddress addrV4 = NetworkUtils.numericToInetAddress("75.208.6.1");
101        InetAddress dns1 = NetworkUtils.numericToInetAddress("75.208.7.1");
102        LinkAddress linkAddrV4 = new LinkAddress(addrV4, 32);
103        InetAddress gateway1 = NetworkUtils.numericToInetAddress("75.208.8.1");
104        LinkProperties lp4 = new LinkProperties();
105        lp4.addLinkAddress(linkAddrV4);
106        lp4.addDnsServer(dns1);
107        lp4.addRoute(new RouteInfo(gateway1));
108        return lp4;
109    }
110
111    /**
112     * Verify that the class registers for receiving the necessary broadcast intents upon init.
113     * Verify that the initialization only occurs once even if init() is called  multiple times.
114     */
115    @Test
116    public void verifyBroadcastIntentRegistration() {
117        mNetworkConnection.init(mHandler);
118
119        ArgumentCaptor<IntentFilter> intentFilterCaptor =
120                ArgumentCaptor.forClass(IntentFilter.class);
121        verify(mContext).registerReceiver(any(BroadcastReceiver.class),
122                intentFilterCaptor.capture(), any(), eq(mHandler));
123        verify(mWifiManager).isWifiEnabled();
124        IntentFilter intentFilter = intentFilterCaptor.getValue();
125        assertEquals(intentFilter.countActions(), 1);
126    }
127
128    /**
129     * Verifies that onWifiEnabled() callback is invoked when the relevant intent is
130     * received and the caller is subscribed to receive the callback.
131     */
132    @Test
133    public void verifyWifiStateCallbacks() {
134        when(mWifiManager.isWifiEnabled()).thenReturn(false);
135        mNetworkConnection.init(mHandler);
136        ArgumentCaptor<BroadcastReceiver> broadcastReceiverCaptor =
137                ArgumentCaptor.forClass(BroadcastReceiver.class);
138        verify(mContext).registerReceiver(broadcastReceiverCaptor.capture(),
139                any(IntentFilter.class), any(), eq(mHandler));
140        BroadcastReceiver broadcastReceiver = broadcastReceiverCaptor.getValue();
141        mLooper.dispatchAll();
142        mNetworkConnection.setEventCallback(mNetworkCallbacks);
143        TestUtil.sendWifiStateChanged(broadcastReceiver, mContext,
144                WifiManager.WIFI_STATE_ENABLED);
145        TestUtil.sendWifiStateChanged(broadcastReceiver, mContext,
146                WifiManager.WIFI_STATE_DISABLED);
147        mNetworkConnection.setEventCallback(null);
148        TestUtil.sendWifiStateChanged(broadcastReceiver, mContext,
149                WifiManager.WIFI_STATE_ENABLED);
150        TestUtil.sendWifiStateChanged(broadcastReceiver, mContext,
151                WifiManager.WIFI_STATE_DISABLED);
152        verify(mNetworkCallbacks, times(1)).onWifiEnabled();
153        verify(mNetworkCallbacks, times(1)).onWifiDisabled();
154    }
155
156    /**
157     * Verifies that connect() API returns false when Wifi is not enabled
158     */
159    @Test
160    public void verifyNetworkConnectionWhenWifiIsDisabled() {
161        when(mWifiManager.isWifiEnabled()).thenReturn(false);
162        mNetworkConnection.init(mHandler);
163        assertEquals(false, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
164    }
165
166    /**
167     * Verifies that connect() API returns false when OSU AP is a part of an OSEN
168     */
169    @Test
170    public void verifyOSENUnsupported() {
171        mNetworkConnection.init(mHandler);
172        assertEquals(false, mNetworkConnection.connect(TEST_SSID, TEST_NAI_OSEN));
173    }
174
175    /**
176     * Verifies that connect() API returns false when WifiManager's addNetwork()
177     * returns an invalid network ID
178     */
179    @Test
180    public void verifyNetworkConnectionWhenAddNetworkFails() {
181        when(mWifiManager.addNetwork(any(WifiConfiguration.class))).thenReturn(-1);
182        mNetworkConnection.init(mHandler);
183        assertEquals(false, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
184        verify(mWifiManager, never()).removeNetwork(TEST_NETWORK_ID);
185    }
186
187    /**
188     * Verifies that connect() API returns false when WifiManager's enableNetwork()
189     * fails for the given network ID corresponding to the OSU AP
190     */
191    @Test
192    public void verifyNetworkConnectionWhenEnableNetworkFails() {
193        when(mWifiManager.enableNetwork(TEST_NETWORK_ID, true)).thenReturn(false);
194        mNetworkConnection.init(mHandler);
195        assertEquals(false, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
196        verify(mWifiManager).removeNetwork(TEST_NETWORK_ID);
197    }
198
199    /**
200     * Verifies that network state callbacks are invoked when network callbacks
201     * are received and when WifiManager has successfully requested connection to the OSU AP.
202     * Ensure IP connectivity is available before invoking onConnected callback.
203     */
204    @Test
205    public void verifyNetworkCallbackInvokedWhenConnected() {
206        mNetworkConnection.init(mHandler);
207
208        mNetworkConnection.setEventCallback(mNetworkCallbacks);
209        assertEquals(true, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
210
211        ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallbackCaptor =
212                ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
213        verify(mConnectivityManager).requestNetwork(any(NetworkRequest.class),
214                networkCallbackCaptor.capture(), any(Handler.class), anyInt());
215        ConnectivityManager.NetworkCallback callback = networkCallbackCaptor.getValue();
216        callback.onLinkPropertiesChanged(mCurrentNetwork, createProvisionedLinkProperties());
217        verify(mNetworkCallbacks).onConnected(mCurrentNetwork);
218
219        callback.onLost(mCurrentNetwork);
220        verify(mNetworkCallbacks).onDisconnected();
221        mNetworkConnection.disconnectIfNeeded();
222        verify(mWifiManager).removeNetwork(TEST_NETWORK_ID);
223    }
224
225    /**
226     * Verifies that network state callbacks are invoked when the network callbacks
227     * are received and when WifiManager has successfully requested connection to the OSU AP.
228     * If IP connectivity is not provisioned, do not invoke onConnected callback.
229     */
230    @Test
231    public void verifyNetworkConnectionTimeout() {
232        mNetworkConnection.init(mHandler);
233
234        mNetworkConnection.setEventCallback(mNetworkCallbacks);
235        assertEquals(true, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
236
237        ArgumentCaptor<ConnectivityManager.NetworkCallback> networkCallbackCaptor =
238                ArgumentCaptor.forClass(ConnectivityManager.NetworkCallback.class);
239        verify(mConnectivityManager).requestNetwork(any(NetworkRequest.class),
240                networkCallbackCaptor.capture(), any(Handler.class), anyInt());
241        ConnectivityManager.NetworkCallback callback = networkCallbackCaptor.getValue();
242        callback.onLinkPropertiesChanged(mCurrentNetwork, new LinkProperties());
243        verify(mNetworkCallbacks, never()).onConnected(mCurrentNetwork);
244
245        callback.onUnavailable();
246        verify(mNetworkCallbacks).onTimeOut();
247        mNetworkConnection.disconnectIfNeeded();
248        verify(mWifiManager).removeNetwork(TEST_NETWORK_ID);
249    }
250
251    /**
252     * Verifies that WifiManager's removeNetwork() is called when disconnectIfNeeded() is called
253     * on the OSU AP's network ID.
254     */
255    @Test
256    public void verifyNetworkDisconnect() {
257        mNetworkConnection.init(mHandler);
258        assertEquals(true, mNetworkConnection.connect(TEST_SSID, TEST_NAI));
259        mNetworkConnection.disconnectIfNeeded();
260        verify(mWifiManager).removeNetwork(TEST_NETWORK_ID);
261    }
262}
263
264