Merge "Add test for CM#setAcceptPartialConnectivity" am: 2693dc2696 am: 98e8422124
Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1730545 Change-Id: Ie49fb789e8731ddac1465fed46f5f139d8ce10f6
This commit is contained in:
@@ -19,6 +19,7 @@ package android.net.cts;
|
|||||||
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
|
import static android.Manifest.permission.CONNECTIVITY_INTERNAL;
|
||||||
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
|
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
|
||||||
import static android.Manifest.permission.NETWORK_SETTINGS;
|
import static android.Manifest.permission.NETWORK_SETTINGS;
|
||||||
|
import static android.Manifest.permission.READ_DEVICE_CONFIG;
|
||||||
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
|
import static android.content.pm.PackageManager.FEATURE_BLUETOOTH;
|
||||||
import static android.content.pm.PackageManager.FEATURE_ETHERNET;
|
import static android.content.pm.PackageManager.FEATURE_ETHERNET;
|
||||||
import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
|
import static android.content.pm.PackageManager.FEATURE_TELEPHONY;
|
||||||
@@ -47,6 +48,8 @@ import static android.net.NetworkCapabilities.NET_CAPABILITY_IMS;
|
|||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_INTERNET;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
|
||||||
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_PARTIAL_CONNECTIVITY;
|
||||||
|
import static android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED;
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
|
import static android.net.NetworkCapabilities.TRANSPORT_TEST;
|
||||||
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
|
||||||
import static android.net.TetheringManager.TETHERING_WIFI;
|
import static android.net.TetheringManager.TETHERING_WIFI;
|
||||||
@@ -59,6 +62,8 @@ import static android.net.cts.util.CtsNetUtils.TestNetworkCallback;
|
|||||||
import static android.net.cts.util.CtsTetheringUtils.StartTetheringCallback;
|
import static android.net.cts.util.CtsTetheringUtils.StartTetheringCallback;
|
||||||
import static android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback;
|
import static android.net.cts.util.CtsTetheringUtils.TestTetheringEventCallback;
|
||||||
import static android.net.cts.util.CtsTetheringUtils.isWifiTetheringSupported;
|
import static android.net.cts.util.CtsTetheringUtils.isWifiTetheringSupported;
|
||||||
|
import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL;
|
||||||
|
import static android.net.util.NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL;
|
||||||
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
|
import static android.os.MessageQueue.OnFileDescriptorEventListener.EVENT_INPUT;
|
||||||
import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
|
import static android.provider.Settings.Global.NETWORK_METERED_MULTIPATH_PREFERENCE;
|
||||||
import static android.system.OsConstants.AF_INET;
|
import static android.system.OsConstants.AF_INET;
|
||||||
@@ -80,7 +85,6 @@ import static org.junit.Assert.assertNotEquals;
|
|||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
import static org.junit.Assert.assertNotSame;
|
import static org.junit.Assert.assertNotSame;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.Assert.assertNull;
|
||||||
import static org.junit.Assert.assertThrows;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.fail;
|
import static org.junit.Assert.fail;
|
||||||
import static org.junit.Assume.assumeTrue;
|
import static org.junit.Assume.assumeTrue;
|
||||||
@@ -121,6 +125,7 @@ import android.net.TelephonyNetworkSpecifier;
|
|||||||
import android.net.TestNetworkInterface;
|
import android.net.TestNetworkInterface;
|
||||||
import android.net.TestNetworkManager;
|
import android.net.TestNetworkManager;
|
||||||
import android.net.TetheringManager;
|
import android.net.TetheringManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.net.cts.util.CtsNetUtils;
|
import android.net.cts.util.CtsNetUtils;
|
||||||
import android.net.util.KeepaliveUtils;
|
import android.net.util.KeepaliveUtils;
|
||||||
import android.net.wifi.WifiManager;
|
import android.net.wifi.WifiManager;
|
||||||
@@ -135,6 +140,7 @@ import android.os.SystemProperties;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.VintfRuntimeInfo;
|
import android.os.VintfRuntimeInfo;
|
||||||
import android.platform.test.annotations.AppModeFull;
|
import android.platform.test.annotations.AppModeFull;
|
||||||
|
import android.provider.DeviceConfig;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.telephony.SubscriptionManager;
|
import android.telephony.SubscriptionManager;
|
||||||
import android.telephony.TelephonyManager;
|
import android.telephony.TelephonyManager;
|
||||||
@@ -159,6 +165,7 @@ import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo;
|
|||||||
import com.android.testutils.DevSdkIgnoreRuleKt;
|
import com.android.testutils.DevSdkIgnoreRuleKt;
|
||||||
import com.android.testutils.RecorderCallback.CallbackEntry;
|
import com.android.testutils.RecorderCallback.CallbackEntry;
|
||||||
import com.android.testutils.SkipPresubmit;
|
import com.android.testutils.SkipPresubmit;
|
||||||
|
import com.android.testutils.TestHttpServer;
|
||||||
import com.android.testutils.TestNetworkTracker;
|
import com.android.testutils.TestNetworkTracker;
|
||||||
import com.android.testutils.TestableNetworkCallback;
|
import com.android.testutils.TestableNetworkCallback;
|
||||||
|
|
||||||
@@ -201,6 +208,10 @@ import java.util.function.Supplier;
|
|||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import fi.iki.elonen.NanoHTTPD.Method;
|
||||||
|
import fi.iki.elonen.NanoHTTPD.Response.IStatus;
|
||||||
|
import fi.iki.elonen.NanoHTTPD.Response.Status;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class ConnectivityManagerTest {
|
public class ConnectivityManagerTest {
|
||||||
@Rule
|
@Rule
|
||||||
@@ -244,6 +255,12 @@ public class ConnectivityManagerTest {
|
|||||||
private static final int AIRPLANE_MODE_OFF = 0;
|
private static final int AIRPLANE_MODE_OFF = 0;
|
||||||
private static final int AIRPLANE_MODE_ON = 1;
|
private static final int AIRPLANE_MODE_ON = 1;
|
||||||
|
|
||||||
|
private static final String TEST_HTTPS_URL_PATH = "/https_path";
|
||||||
|
private static final String TEST_HTTP_URL_PATH = "/http_path";
|
||||||
|
private static final String LOCALHOST_HOSTNAME = "localhost";
|
||||||
|
// Re-connecting to the AP, obtaining an IP address, revalidating can take a long time
|
||||||
|
private static final long WIFI_CONNECT_TIMEOUT_MS = 60_000L;
|
||||||
|
|
||||||
private Context mContext;
|
private Context mContext;
|
||||||
private Instrumentation mInstrumentation;
|
private Instrumentation mInstrumentation;
|
||||||
private ConnectivityManager mCm;
|
private ConnectivityManager mCm;
|
||||||
@@ -258,6 +275,8 @@ public class ConnectivityManagerTest {
|
|||||||
// Used for cleanup purposes.
|
// Used for cleanup purposes.
|
||||||
private final List<Range<Integer>> mVpnRequiredUidRanges = new ArrayList<>();
|
private final List<Range<Integer>> mVpnRequiredUidRanges = new ArrayList<>();
|
||||||
|
|
||||||
|
private final TestHttpServer mHttpServer = new TestHttpServer(LOCALHOST_HOSTNAME);
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
mInstrumentation = InstrumentationRegistry.getInstrumentation();
|
||||||
@@ -2309,4 +2328,139 @@ public class ConnectivityManagerTest {
|
|||||||
}
|
}
|
||||||
oemPrefListener.expectOnComplete();
|
oemPrefListener.expectOnComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetAcceptPartialConnectivity_NoPermission_GetException() {
|
||||||
|
assumeTrue(TestUtils.shouldTestSApis());
|
||||||
|
assertThrows(SecurityException.class, () -> mCm.setAcceptPartialConnectivity(
|
||||||
|
mCm.getActiveNetwork(), false /* accept */ , false /* always */));
|
||||||
|
}
|
||||||
|
|
||||||
|
@AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
|
||||||
|
@Test
|
||||||
|
public void testAcceptPartialConnectivity_validatedNetwork() throws Exception {
|
||||||
|
assumeTrue(TestUtils.shouldTestSApis());
|
||||||
|
assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute"
|
||||||
|
+ " unless device supports WiFi",
|
||||||
|
mPackageManager.hasSystemFeature(FEATURE_WIFI));
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Wait for partial connectivity to be detected on the network
|
||||||
|
final Network network = preparePartialConnectivity();
|
||||||
|
|
||||||
|
runAsShell(NETWORK_SETTINGS, () -> {
|
||||||
|
// The always bit is verified in NetworkAgentTest
|
||||||
|
mCm.setAcceptPartialConnectivity(network, true /* accept */, false /* always */);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Accept partial connectivity network should result in a validated network
|
||||||
|
expectNetworkHasCapability(network, NET_CAPABILITY_VALIDATED, WIFI_CONNECT_TIMEOUT_MS);
|
||||||
|
} finally {
|
||||||
|
resetValidationConfig();
|
||||||
|
// Reconnect wifi to reset the wifi status
|
||||||
|
mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
|
||||||
|
mCtsNetUtils.ensureWifiConnected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AppModeFull(reason = "WRITE_DEVICE_CONFIG permission can't be granted to instant apps")
|
||||||
|
@Test
|
||||||
|
public void testRejectPartialConnectivity_TearDownNetwork() throws Exception {
|
||||||
|
assumeTrue(TestUtils.shouldTestSApis());
|
||||||
|
assumeTrue("testAcceptPartialConnectivity_validatedNetwork cannot execute"
|
||||||
|
+ " unless device supports WiFi",
|
||||||
|
mPackageManager.hasSystemFeature(FEATURE_WIFI));
|
||||||
|
|
||||||
|
final TestNetworkCallback cb = new TestNetworkCallback();
|
||||||
|
try {
|
||||||
|
// Wait for partial connectivity to be detected on the network
|
||||||
|
final Network network = preparePartialConnectivity();
|
||||||
|
|
||||||
|
mCm.requestNetwork(makeWifiNetworkRequest(), cb);
|
||||||
|
runAsShell(NETWORK_SETTINGS, () -> {
|
||||||
|
// The always bit is verified in NetworkAgentTest
|
||||||
|
mCm.setAcceptPartialConnectivity(network, false /* accept */, false /* always */);
|
||||||
|
});
|
||||||
|
// Reject partial connectivity network should cause the network being torn down
|
||||||
|
assertEquals(network, cb.waitForLost());
|
||||||
|
} finally {
|
||||||
|
mCm.unregisterNetworkCallback(cb);
|
||||||
|
resetValidationConfig();
|
||||||
|
// Wifi will not automatically reconnect to the network. ensureWifiDisconnected cannot
|
||||||
|
// apply here. Thus, turn off wifi first and restart to restore.
|
||||||
|
runShellCommand("svc wifi disable");
|
||||||
|
mCtsNetUtils.ensureWifiConnected();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private Network expectNetworkHasCapability(Network network, int expectedNetCap, long timeout)
|
||||||
|
throws Exception {
|
||||||
|
final CompletableFuture<Network> future = new CompletableFuture();
|
||||||
|
final NetworkCallback cb = new NetworkCallback() {
|
||||||
|
@Override
|
||||||
|
public void onCapabilitiesChanged(Network n, NetworkCapabilities nc) {
|
||||||
|
if (n.equals(network) && nc.hasCapability(expectedNetCap)) {
|
||||||
|
future.complete(network);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
try {
|
||||||
|
mCm.registerNetworkCallback(new NetworkRequest.Builder().build(), cb);
|
||||||
|
return future.get(timeout, TimeUnit.MILLISECONDS);
|
||||||
|
} finally {
|
||||||
|
mCm.unregisterNetworkCallback(cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetValidationConfig() {
|
||||||
|
NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig();
|
||||||
|
mHttpServer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
private Network preparePartialConnectivity() throws Exception {
|
||||||
|
runAsShell(READ_DEVICE_CONFIG, () -> {
|
||||||
|
// Verify that the test URLs are not normally set on the device, but do not fail if the
|
||||||
|
// test URLs are set to what this test uses (URLs on localhost), in case the test was
|
||||||
|
// interrupted manually and rerun.
|
||||||
|
assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTPS_URL);
|
||||||
|
assertEmptyOrLocalhostUrl(TEST_CAPTIVE_PORTAL_HTTP_URL);
|
||||||
|
});
|
||||||
|
|
||||||
|
NetworkValidationTestUtil.clearValidationTestUrlsDeviceConfig();
|
||||||
|
|
||||||
|
mHttpServer.start();
|
||||||
|
// Configure response code for partial connectivity
|
||||||
|
configTestServer(Status.INTERNAL_ERROR /* httpsStatusCode */,
|
||||||
|
Status.NO_CONTENT /* httpStatusCode */);
|
||||||
|
// Disconnect wifi first then start wifi network with configuration.
|
||||||
|
mCtsNetUtils.ensureWifiDisconnected(null /* wifiNetworkToCheck */);
|
||||||
|
final Network network = mCtsNetUtils.ensureWifiConnected();
|
||||||
|
|
||||||
|
return expectNetworkHasCapability(network, NET_CAPABILITY_PARTIAL_CONNECTIVITY,
|
||||||
|
WIFI_CONNECT_TIMEOUT_MS);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String makeUrl(String path) {
|
||||||
|
return "http://localhost:" + mHttpServer.getListeningPort() + path;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertEmptyOrLocalhostUrl(String urlKey) {
|
||||||
|
final String url = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_CONNECTIVITY, urlKey);
|
||||||
|
assertTrue(urlKey + " must not be set in production scenarios, current value= " + url,
|
||||||
|
TextUtils.isEmpty(url) || LOCALHOST_HOSTNAME.equals(Uri.parse(url).getHost()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void configTestServer(IStatus httpsStatusCode, IStatus httpStatusCode) {
|
||||||
|
mHttpServer.addResponse(new TestHttpServer.Request(
|
||||||
|
TEST_HTTPS_URL_PATH, Method.GET, "" /* queryParameters */),
|
||||||
|
httpsStatusCode, null /* locationHeader */, "" /* content */);
|
||||||
|
mHttpServer.addResponse(new TestHttpServer.Request(
|
||||||
|
TEST_HTTP_URL_PATH, Method.GET, "" /* queryParameters */),
|
||||||
|
httpStatusCode, null /* locationHeader */, "" /* content */);
|
||||||
|
NetworkValidationTestUtil.setHttpsUrlDeviceConfig(makeUrl(TEST_HTTPS_URL_PATH));
|
||||||
|
NetworkValidationTestUtil.setHttpUrlDeviceConfig(makeUrl(TEST_HTTP_URL_PATH));
|
||||||
|
NetworkValidationTestUtil.setUrlExpirationDeviceConfig(
|
||||||
|
System.currentTimeMillis() + WIFI_CONNECT_TIMEOUT_MS);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ internal object NetworkValidationTestUtil {
|
|||||||
/**
|
/**
|
||||||
* Clear the test network validation URLs.
|
* Clear the test network validation URLs.
|
||||||
*/
|
*/
|
||||||
fun clearValidationTestUrlsDeviceConfig() {
|
@JvmStatic fun clearValidationTestUrlsDeviceConfig() {
|
||||||
setHttpsUrlDeviceConfig(null)
|
setHttpsUrlDeviceConfig(null)
|
||||||
setHttpUrlDeviceConfig(null)
|
setHttpUrlDeviceConfig(null)
|
||||||
setUrlExpirationDeviceConfig(null)
|
setUrlExpirationDeviceConfig(null)
|
||||||
@@ -40,7 +40,7 @@ internal object NetworkValidationTestUtil {
|
|||||||
*
|
*
|
||||||
* @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL
|
* @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL
|
||||||
*/
|
*/
|
||||||
fun setHttpsUrlDeviceConfig(url: String?) =
|
@JvmStatic fun setHttpsUrlDeviceConfig(url: String?) =
|
||||||
setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL, url)
|
setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTPS_URL, url)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -48,7 +48,7 @@ internal object NetworkValidationTestUtil {
|
|||||||
*
|
*
|
||||||
* @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL
|
* @see NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL
|
||||||
*/
|
*/
|
||||||
fun setHttpUrlDeviceConfig(url: String?) =
|
@JvmStatic fun setHttpUrlDeviceConfig(url: String?) =
|
||||||
setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL, url)
|
setConfig(NetworkStackUtils.TEST_CAPTIVE_PORTAL_HTTP_URL, url)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -56,7 +56,7 @@ internal object NetworkValidationTestUtil {
|
|||||||
*
|
*
|
||||||
* @see NetworkStackUtils.TEST_URL_EXPIRATION_TIME
|
* @see NetworkStackUtils.TEST_URL_EXPIRATION_TIME
|
||||||
*/
|
*/
|
||||||
fun setUrlExpirationDeviceConfig(timestamp: Long?) =
|
@JvmStatic fun setUrlExpirationDeviceConfig(timestamp: Long?) =
|
||||||
setConfig(NetworkStackUtils.TEST_URL_EXPIRATION_TIME, timestamp?.toString())
|
setConfig(NetworkStackUtils.TEST_URL_EXPIRATION_TIME, timestamp?.toString())
|
||||||
|
|
||||||
private fun setConfig(configKey: String, value: String?) {
|
private fun setConfig(configKey: String, value: String?) {
|
||||||
|
|||||||
Reference in New Issue
Block a user