CTS test for Eth network management APIs
CTS tests for EthernetManager APIs:
#updateConfiguration
Bug: 236420528
Bug: 210487893
Test: atest CtsNetTestCases
:android.net.cts.EthernetManagerTest --iterations
Change-Id: I394cd306c0f78973564f9196834e690e4a51a3fd
diff --git a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
index d72cf1f..89b107e 100644
--- a/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
+++ b/tests/cts/net/src/android/net/cts/EthernetManagerTest.kt
@@ -21,9 +21,9 @@
import android.content.Context
import android.net.ConnectivityManager
import android.net.EthernetManager
-import android.net.EthernetManager.InterfaceStateListener
import android.net.EthernetManager.ETHERNET_STATE_DISABLED
import android.net.EthernetManager.ETHERNET_STATE_ENABLED
+import android.net.EthernetManager.InterfaceStateListener
import android.net.EthernetManager.ROLE_CLIENT
import android.net.EthernetManager.ROLE_NONE
import android.net.EthernetManager.ROLE_SERVER
@@ -37,13 +37,16 @@
import android.net.EthernetNetworkUpdateRequest
import android.net.InetAddresses
import android.net.IpConfiguration
+import android.net.LinkAddress
import android.net.MacAddress
import android.net.Network
import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_TEMPORARILY_NOT_METERED
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkRequest
+import android.net.StaticIpConfiguration
import android.net.TestNetworkInterface
import android.net.TestNetworkManager
import android.net.cts.EthernetManagerTest.EthernetStateListener.CallbackEntry.EthernetStateChanged
@@ -57,16 +60,17 @@
import androidx.test.platform.app.InstrumentationRegistry
import com.android.net.module.util.ArrayTrackRecord
import com.android.net.module.util.TrackRecord
-import com.android.testutils.anyNetwork
import com.android.testutils.ConnectivityModuleTest
-import com.android.testutils.DeviceInfoUtils.isKernelVersionAtLeast
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRunner
+import com.android.testutils.DeviceInfoUtils.isKernelVersionAtLeast
import com.android.testutils.RecorderCallback.CallbackEntry.Available
+import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
import com.android.testutils.RecorderCallback.CallbackEntry.Lost
import com.android.testutils.RouterAdvertisementResponder
import com.android.testutils.TapPacketReader
import com.android.testutils.TestableNetworkCallback
+import com.android.testutils.anyNetwork
import com.android.testutils.runAsShell
import com.android.testutils.waitForIdle
import org.junit.After
@@ -77,8 +81,8 @@
import java.net.Inet6Address
import java.util.concurrent.CompletableFuture
import java.util.concurrent.ExecutionException
-import java.util.concurrent.TimeoutException
import java.util.concurrent.TimeUnit
+import java.util.concurrent.TimeoutException
import java.util.function.IntConsumer
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@@ -88,17 +92,25 @@
import kotlin.test.assertTrue
import kotlin.test.fail
+private const val TAG = "EthernetManagerTest"
// TODO: try to lower this timeout in the future. Currently, ethernet tests are still flaky because
// the interface is not ready fast enough (mostly due to the up / up / down / up issue).
private const val TIMEOUT_MS = 2000L
-private const val NO_CALLBACK_TIMEOUT_MS = 200L
+// Timeout used to confirm no callbacks matching given criteria are received. Must be long enough to
+// process all callbacks including ip provisioning when using the updateConfiguration API.
+private const val NO_CALLBACK_TIMEOUT_MS = 500L
+
private val DEFAULT_IP_CONFIGURATION = IpConfiguration(IpConfiguration.IpAssignment.DHCP,
- IpConfiguration.ProxySettings.NONE, null, null)
+ IpConfiguration.ProxySettings.NONE, null, null)
private val ETH_REQUEST: NetworkRequest = NetworkRequest.Builder()
- .addTransportType(TRANSPORT_TEST)
- .addTransportType(TRANSPORT_ETHERNET)
- .removeCapability(NET_CAPABILITY_TRUSTED)
- .build()
+ .addTransportType(TRANSPORT_TEST)
+ .addTransportType(TRANSPORT_ETHERNET)
+ .removeCapability(NET_CAPABILITY_TRUSTED)
+ .build()
+private val STATIC_IP_CONFIGURATION = IpConfiguration.Builder()
+ .setStaticIpConfiguration(StaticIpConfiguration.Builder()
+ .setIpAddress(LinkAddress("192.0.2.1/30")).build())
+ .build()
@AppModeFull(reason = "Instant apps can't access EthernetManager")
// EthernetManager is not updatable before T, so tests do not need to be backwards compatible.
@@ -436,7 +448,10 @@
// It can take multiple seconds for the network to become available.
private fun TestableNetworkCallback.expectAvailable() =
- expectCallback<Available>(anyNetwork(), 5000 /* ms timeout */).network
+ expectCallback<Available>(anyNetwork(), 5000 /* ms timeout */).network
+
+ private fun TestableNetworkCallback.expectLost(n: Network = anyNetwork()) =
+ expectCallback<Lost>(n, 5000 /* ms timeout */)
// b/233534110: eventuallyExpect<Lost>() does not advance ReadHead, use
// eventuallyExpect(Lost::class) instead.
@@ -444,7 +459,9 @@
eventuallyExpect(Lost::class, TIMEOUT_MS) { n?.equals(it.network) ?: true }
private fun TestableNetworkCallback.assertNeverLost(n: Network? = null) =
- assertNoCallbackThat() { it is Lost && (n?.equals(it.network) ?: true) }
+ assertNoCallbackThat(NO_CALLBACK_TIMEOUT_MS) {
+ it is Lost && (n?.equals(it.network) ?: true)
+ }
private fun TestableNetworkCallback.assertNeverAvailable(n: Network? = null) =
assertNoCallbackThat() { it is Available && (n?.equals(it.network) ?: true) }
@@ -454,6 +471,18 @@
it.networkSpecifier == EthernetNetworkSpecifier(name)
}
+ private fun TestableNetworkCallback.expectCapabilitiesWithCapability(cap: Int) =
+ expectCapabilitiesThat(anyNetwork(), TIMEOUT_MS) {
+ it.hasCapability(cap)
+ }
+
+ private fun TestableNetworkCallback.expectLinkPropertiesWithLinkAddress(addr: LinkAddress) =
+ expectLinkPropertiesThat(anyNetwork(), TIMEOUT_MS) {
+ // LinkAddress.equals isn't possible as the system changes the LinkAddress.flags value.
+ // any() must be used since the interface may also have a link-local address.
+ it.linkAddresses.any { x -> x.isSameAddressAs(addr) }
+ }
+
@Test
fun testCallbacks() {
// If an interface exists when the callback is registered, it is reported on registration.
@@ -732,4 +761,66 @@
enableInterface(iface).expectResult(iface.name)
cb.expectAvailable()
}
+
+ @Test
+ fun testUpdateConfiguration_forBothIpConfigAndCapabilities() {
+ val iface = createInterface()
+ val cb = requestNetwork(ETH_REQUEST.createCopyWithEthernetSpecifier(iface.name))
+ val network = cb.expectAvailable()
+ cb.assertNeverLost()
+
+ val testCapability = NET_CAPABILITY_TEMPORARILY_NOT_METERED
+ val nc = NetworkCapabilities
+ .Builder(ETH_REQUEST.networkCapabilities)
+ .addCapability(testCapability)
+ .build()
+ updateConfiguration(iface, STATIC_IP_CONFIGURATION, nc)
+
+ // UpdateConfiguration() currently does a restarts on the ethernet interface therefore lost
+ // will be expected first before available, as part of the restart.
+ cb.expectLost(network)
+ cb.expectAvailable()
+ cb.expectCapabilitiesWithCapability(testCapability)
+ cb.expectLinkPropertiesWithLinkAddress(
+ STATIC_IP_CONFIGURATION.staticIpConfiguration.ipAddress!!)
+ }
+
+ @Test
+ fun testUpdateConfiguration_forOnlyIpConfig() {
+ val iface: EthernetTestInterface = createInterface()
+ val cb = requestNetwork(ETH_REQUEST.createCopyWithEthernetSpecifier(iface.name))
+ val network = cb.expectAvailable()
+ cb.assertNeverLost()
+
+ updateConfiguration(iface, STATIC_IP_CONFIGURATION)
+
+ // UpdateConfiguration() currently does a restarts on the ethernet interface therefore lost
+ // will be expected first before available, as part of the restart.
+ cb.expectLost(network)
+ cb.expectAvailable()
+ cb.expectCallback<CapabilitiesChanged>()
+ cb.expectLinkPropertiesWithLinkAddress(
+ STATIC_IP_CONFIGURATION.staticIpConfiguration.ipAddress!!)
+ }
+
+ @Test
+ fun testUpdateConfiguration_forOnlyCapabilities() {
+ val iface: EthernetTestInterface = createInterface()
+ val cb = requestNetwork(ETH_REQUEST.createCopyWithEthernetSpecifier(iface.name))
+ val network = cb.expectAvailable()
+ cb.assertNeverLost()
+
+ val testCapability = NET_CAPABILITY_TEMPORARILY_NOT_METERED
+ val nc = NetworkCapabilities
+ .Builder(ETH_REQUEST.networkCapabilities)
+ .addCapability(testCapability)
+ .build()
+ updateConfiguration(iface, capabilities = nc)
+
+ // UpdateConfiguration() currently does a restarts on the ethernet interface therefore lost
+ // will be expected first before available, as part of the restart.
+ cb.expectLost(network)
+ cb.expectAvailable()
+ cb.expectCapabilitiesWithCapability(testCapability)
+ }
}