Add more test coverage to ConnectivityManagerTest.

1. Test NetworkCallbacks as well as CONNECTIVITY_ACTION, since
   we are moving away from CONNECTIVITY_ACTION.
2. Use the Network objects we get back to test
   Network#getSocketFactory().
3. Check that TCP connections are closed with ECONNABORTED when
   a network disconnects.

Bug: 28251576
Change-Id: I41a438b82ef9251e52866332f3445f1bf876e04f
This commit is contained in:
Lorenzo Colitti
2016-04-19 13:00:51 +09:00
parent 0e47422a47
commit 8a14c224e3

View File

@@ -38,9 +38,16 @@ import android.net.wifi.WifiManager;
import android.test.AndroidTestCase;
import android.util.Log;
import android.os.SystemProperties;
import android.system.Os;
import android.system.OsConstants;
import com.android.internal.telephony.PhoneConstants;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
@@ -57,7 +64,15 @@ public class ConnectivityManagerTest extends AndroidTestCase {
public static final int TYPE_MOBILE = ConnectivityManager.TYPE_MOBILE;
public static final int TYPE_WIFI = ConnectivityManager.TYPE_WIFI;
private static final int HOST_ADDRESS = 0x7f000001;// represent ip 127.0.0.1
private static final String TEST_HOST = "connectivitycheck.gstatic.com";
private static final int SOCKET_TIMEOUT_MS = 2000;
private static final int HTTP_PORT = 80;
private static final String HTTP_REQUEST =
"GET /generate_204 HTTP/1.0\r\n" +
"Host: " + TEST_HOST + "\r\n" +
"Connection: keep-alive\r\n\r\n";
// Action sent to ConnectivityActionReceiver when a network callback is sent via PendingIntent.
private static final String NETWORK_CALLBACK_ACTION =
@@ -249,6 +264,12 @@ public class ConnectivityManagerTest extends AndroidTestCase {
mCm.getBackgroundDataSetting();
}
private NetworkRequest makeWifiNetworkRequest() {
return new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
}
/**
* Exercises both registerNetworkCallback and unregisterNetworkCallback. This checks to
* see if we get a callback for the TRANSPORT_WIFI transport type being available.
@@ -265,16 +286,14 @@ public class ConnectivityManagerTest extends AndroidTestCase {
}
// We will register for a WIFI network being available or lost.
final NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
final TestNetworkCallback callback = new TestNetworkCallback();
mCm.registerNetworkCallback(request, callback);
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
final TestNetworkCallback defaultTrackingCallback = new TestNetworkCallback();
mCm.registerDefaultNetworkCallback(defaultTrackingCallback);
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
Network wifiNetwork = null;
try {
// Make sure WiFi is connected to an access point to start with.
@@ -285,10 +304,11 @@ public class ConnectivityManagerTest extends AndroidTestCase {
// Now we should expect to get a network callback about availability of the wifi
// network even if it was already connected as a state-based action when the callback
// is registered.
assertTrue("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI",
callback.waitForAvailable());
wifiNetwork = callback.waitForAvailable();
assertNotNull("Did not receive NetworkCallback.onAvailable for TRANSPORT_WIFI",
wifiNetwork);
assertTrue("Did not receive NetworkCallback.onAvailable for any default network",
assertNotNull("Did not receive NetworkCallback.onAvailable for any default network",
defaultTrackingCallback.waitForAvailable());
} catch (InterruptedException e) {
fail("Broadcast receiver or NetworkCallback wait was interrupted.");
@@ -298,7 +318,7 @@ public class ConnectivityManagerTest extends AndroidTestCase {
// Return WiFi to its original enabled/disabled state.
if (!previousWifiEnabledState) {
disconnectFromWifi();
disconnectFromWifi(wifiNetwork);
}
}
}
@@ -329,10 +349,7 @@ public class ConnectivityManagerTest extends AndroidTestCase {
mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
// We will register for a WIFI network being available or lost.
NetworkRequest request = new NetworkRequest.Builder()
.addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
.build();
mCm.registerNetworkCallback(request, pendingIntent);
mCm.registerNetworkCallback(makeWifiNetworkRequest(), pendingIntent);
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
@@ -356,7 +373,7 @@ public class ConnectivityManagerTest extends AndroidTestCase {
// Return WiFi to its original enabled/disabled state.
if (!previousWifiEnabledState) {
disconnectFromWifi();
disconnectFromWifi(null);
}
}
}
@@ -370,8 +387,10 @@ public class ConnectivityManagerTest extends AndroidTestCase {
// We will toggle the state of wifi to generate a connectivity change.
final boolean previousWifiEnabledState = mWifiManager.isWifiEnabled();
if (previousWifiEnabledState) {
disconnectFromWifi();
Network wifiNetwork = getWifiNetwork();
disconnectFromWifi(wifiNetwork);
} else {
connectToWifi();
}
@@ -387,12 +406,16 @@ public class ConnectivityManagerTest extends AndroidTestCase {
if (previousWifiEnabledState) {
connectToWifi();
} else {
disconnectFromWifi();
disconnectFromWifi(null);
}
}
/** Enable WiFi and wait for it to become connected to a network. */
private void connectToWifi() {
private Network connectToWifi() {
final TestNetworkCallback callback = new TestNetworkCallback();
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
Network wifiNetwork = null;
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
ConnectivityManager.TYPE_WIFI, NetworkInfo.State.CONNECTED);
IntentFilter filter = new IntentFilter();
@@ -402,36 +425,94 @@ public class ConnectivityManagerTest extends AndroidTestCase {
boolean connected = false;
try {
assertTrue(mWifiManager.setWifiEnabled(true));
// Ensure we get both an onAvailable callback and a CONNECTIVITY_ACTION.
wifiNetwork = callback.waitForAvailable();
assertNotNull(wifiNetwork);
connected = receiver.waitForState();
} catch (InterruptedException ex) {
fail("connectToWifi was interrupted");
} finally {
mCm.unregisterNetworkCallback(callback);
mContext.unregisterReceiver(receiver);
}
assertTrue("Wifi must be configured to connect to an access point for this test.",
connected);
return wifiNetwork;
}
private Socket getBoundSocket(Network network, String host, int port) throws IOException {
InetSocketAddress addr = new InetSocketAddress(host, port);
Socket s = network.getSocketFactory().createSocket();
try {
s.setSoTimeout(SOCKET_TIMEOUT_MS);
s.connect(addr, SOCKET_TIMEOUT_MS);
} catch (IOException e) {
s.close();
throw e;
}
return s;
}
private void testHttpRequest(Socket s) throws IOException {
OutputStream out = s.getOutputStream();
InputStream in = s.getInputStream();
final byte[] requestBytes = HTTP_REQUEST.getBytes("UTF-8");
byte[] responseBytes = new byte[4096];
out.write(requestBytes);
in.read(responseBytes);
assertTrue(new String(responseBytes, "UTF-8").startsWith("HTTP/1.0 204 No Content\r\n"));
}
/** Disable WiFi and wait for it to become disconnected from the network. */
private void disconnectFromWifi() {
private void disconnectFromWifi(Network wifiNetworkToCheck) {
final TestNetworkCallback callback = new TestNetworkCallback();
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
Network lostWifiNetwork = null;
ConnectivityActionReceiver receiver = new ConnectivityActionReceiver(
ConnectivityManager.TYPE_WIFI, NetworkInfo.State.DISCONNECTED);
IntentFilter filter = new IntentFilter();
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
mContext.registerReceiver(receiver, filter);
// Assert that we can establish a TCP connection on wifi.
Socket wifiBoundSocket = null;
if (wifiNetworkToCheck != null) {
try {
wifiBoundSocket = getBoundSocket(wifiNetworkToCheck, TEST_HOST, HTTP_PORT);
testHttpRequest(wifiBoundSocket);
} catch (IOException e) {
fail("HTTP request before wifi disconnected failed with: " + e);
}
}
boolean disconnected = false;
try {
assertTrue(mWifiManager.setWifiEnabled(false));
// Ensure we get both an onLost callback and a CONNECTIVITY_ACTION.
lostWifiNetwork = callback.waitForLost();
assertNotNull(lostWifiNetwork);
disconnected = receiver.waitForState();
} catch (InterruptedException ex) {
fail("disconnectFromWifi was interrupted");
} finally {
mCm.unregisterNetworkCallback(callback);
mContext.unregisterReceiver(receiver);
}
assertTrue("Wifi failed to reach DISCONNECTED state.", disconnected);
// Check that the socket is closed when wifi disconnects.
if (wifiBoundSocket != null) {
try {
testHttpRequest(wifiBoundSocket);
fail("HTTP request should not succeed after wifi disconnects");
} catch (IOException expected) {
assertEquals(Os.strerror(OsConstants.ECONNABORTED), expected.getMessage());
}
}
}
/**
@@ -498,15 +579,48 @@ public class ConnectivityManagerTest extends AndroidTestCase {
*/
private static class TestNetworkCallback extends ConnectivityManager.NetworkCallback {
private final CountDownLatch mAvailableLatch = new CountDownLatch(1);
private final CountDownLatch mLostLatch = new CountDownLatch(1);
public boolean waitForAvailable() throws InterruptedException {
return mAvailableLatch.await(30, TimeUnit.SECONDS);
public Network currentNetwork;
public Network lastLostNetwork;
public Network waitForAvailable() throws InterruptedException {
return mAvailableLatch.await(30, TimeUnit.SECONDS) ? currentNetwork : null;
}
public Network waitForLost() throws InterruptedException {
return mLostLatch.await(30, TimeUnit.SECONDS) ? lastLostNetwork : null;
}
@Override
public void onAvailable(Network network) {
currentNetwork = network;
mAvailableLatch.countDown();
}
@Override
public void onLost(Network network) {
lastLostNetwork = network;
if (network.equals(currentNetwork)) {
currentNetwork = null;
}
mLostLatch.countDown();
}
}
private Network getWifiNetwork() {
TestNetworkCallback callback = new TestNetworkCallback();
mCm.registerNetworkCallback(makeWifiNetworkRequest(), callback);
Network network = null;
try {
network = callback.waitForAvailable();
} catch (InterruptedException e) {
fail("NetworkCallback wait was interrupted.");
} finally {
mCm.unregisterNetworkCallback(callback);
}
assertNotNull("Cannot find Network for wifi. Is wifi connected?", network);
return network;
}
/** Verify restricted networks cannot be requested. */
@@ -523,8 +637,6 @@ public class ConnectivityManagerTest extends AndroidTestCase {
try {
mCm.requestNetwork(request, callback);
fail("No exception thrown when restricted network requested.");
} catch (SecurityException e) {
// Expected.
}
} catch (SecurityException expected) {}
}
}