Merge changes I81bf8969,I2edba513,Ibb913979 into sc-dev
* changes: Add CTS for NetworkScore.setTransportPrimary Add some CTS tests for NetworkScore. Add a first CTS for NetworkScore
This commit is contained in:
committed by
Android (Google) Code Review
commit
98c351f429
217
tests/cts/net/src/android/net/cts/NetworkScoreTest.kt
Normal file
217
tests/cts/net/src/android/net/cts/NetworkScoreTest.kt
Normal file
@@ -0,0 +1,217 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package android.net.cts
|
||||
|
||||
import android.Manifest.permission.MANAGE_TEST_NETWORKS
|
||||
import android.content.Context
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.LinkProperties
|
||||
import android.net.NetworkAgent
|
||||
import android.net.NetworkAgentConfig
|
||||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkProvider
|
||||
import android.net.NetworkRequest
|
||||
import android.net.NetworkScore
|
||||
import android.net.VpnManager
|
||||
import android.net.VpnTransportInfo
|
||||
import android.os.Build
|
||||
import android.os.Handler
|
||||
import android.os.HandlerThread
|
||||
import androidx.test.InstrumentationRegistry
|
||||
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
|
||||
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
|
||||
import com.android.testutils.DevSdkIgnoreRunner
|
||||
import com.android.testutils.TestableNetworkCallback
|
||||
import com.android.testutils.TestableNetworkCallback.HasNetwork
|
||||
import org.junit.After
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
// This test doesn't really have a constraint on how fast the methods should return. If it's
|
||||
// going to fail, it will simply wait forever, so setting a high timeout lowers the flake ratio
|
||||
// without affecting the run time of successful runs. Thus, set a very high timeout.
|
||||
private const val TIMEOUT_MS = 30_000L
|
||||
// When waiting for a NetworkCallback to determine there was no timeout, waiting is the
|
||||
// only possible thing (the relevant handler is the one in the real ConnectivityService,
|
||||
// and then there is the Binder call), so have a short timeout for this as it will be
|
||||
// exhausted every time.
|
||||
private const val NO_CALLBACK_TIMEOUT = 200L
|
||||
|
||||
private val testContext: Context
|
||||
get() = InstrumentationRegistry.getContext()
|
||||
|
||||
private fun score(exiting: Boolean = false, primary: Boolean = false) =
|
||||
NetworkScore.Builder().setExiting(exiting).setTransportPrimary(primary)
|
||||
// TODO : have a constant KEEP_CONNECTED_FOR_TEST ?
|
||||
.setKeepConnectedReason(NetworkScore.KEEP_CONNECTED_FOR_HANDOVER)
|
||||
.build()
|
||||
|
||||
@IgnoreUpTo(Build.VERSION_CODES.R)
|
||||
@RunWith(DevSdkIgnoreRunner::class)
|
||||
class NetworkScoreTest {
|
||||
private val mCm = testContext.getSystemService(ConnectivityManager::class.java)
|
||||
private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
|
||||
private val mHandler by lazy { Handler(mHandlerThread.looper) }
|
||||
private val agentsToCleanUp = mutableListOf<NetworkAgent>()
|
||||
private val callbacksToCleanUp = mutableListOf<TestableNetworkCallback>()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
mHandlerThread.start()
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
agentsToCleanUp.forEach { it.unregister() }
|
||||
mHandlerThread.quitSafely()
|
||||
callbacksToCleanUp.forEach { mCm.unregisterNetworkCallback(it) }
|
||||
}
|
||||
|
||||
// Returns a networkCallback that sends onAvailable on the best network with TRANSPORT_TEST.
|
||||
private fun makeTestNetworkCallback() = TestableNetworkCallback(TIMEOUT_MS).also { cb ->
|
||||
mCm.registerBestMatchingNetworkCallback(NetworkRequest.Builder().clearCapabilities()
|
||||
.addTransportType(NetworkCapabilities.TRANSPORT_TEST).build(), cb, mHandler)
|
||||
callbacksToCleanUp.add(cb)
|
||||
}
|
||||
|
||||
// TestNetworkCallback is made to interact with a wrapper of NetworkAgent, because it's
|
||||
// made for ConnectivityServiceTest.
|
||||
// TODO : have TestNetworkCallback work for NetworkAgent too and remove this class.
|
||||
private class AgentWrapper(val agent: NetworkAgent) : HasNetwork {
|
||||
override val network = agent.network
|
||||
fun sendNetworkScore(s: NetworkScore) = agent.sendNetworkScore(s)
|
||||
}
|
||||
|
||||
private fun createTestNetworkAgent(
|
||||
// The network always has TRANSPORT_TEST, plus optional transports
|
||||
optionalTransports: IntArray = IntArray(size = 0),
|
||||
everUserSelected: Boolean = false,
|
||||
acceptUnvalidated: Boolean = false,
|
||||
isExiting: Boolean = false,
|
||||
isPrimary: Boolean = false
|
||||
): AgentWrapper {
|
||||
val nc = NetworkCapabilities.Builder().apply {
|
||||
addTransportType(NetworkCapabilities.TRANSPORT_TEST)
|
||||
optionalTransports.forEach { addTransportType(it) }
|
||||
// Add capabilities that are common, just for realism. It's not strictly necessary
|
||||
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_SUSPENDED)
|
||||
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING)
|
||||
// Remove capabilities that a test network agent shouldn't have and that are not
|
||||
// needed for the purposes of this test.
|
||||
removeCapability(NetworkCapabilities.NET_CAPABILITY_TRUSTED)
|
||||
removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
|
||||
removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_RESTRICTED)
|
||||
if (optionalTransports.contains(NetworkCapabilities.TRANSPORT_VPN)) {
|
||||
addTransportType(NetworkCapabilities.TRANSPORT_VPN)
|
||||
removeCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VPN)
|
||||
setTransportInfo(VpnTransportInfo(VpnManager.TYPE_VPN_SERVICE, null))
|
||||
}
|
||||
addCapability(NetworkCapabilities.NET_CAPABILITY_NOT_VCN_MANAGED)
|
||||
}.build()
|
||||
val config = NetworkAgentConfig.Builder()
|
||||
.setExplicitlySelected(everUserSelected)
|
||||
.setUnvalidatedConnectivityAcceptable(acceptUnvalidated)
|
||||
.build()
|
||||
val score = score(exiting = isExiting, primary = isPrimary)
|
||||
val context = testContext
|
||||
val looper = mHandlerThread.looper
|
||||
val agent = object : NetworkAgent(context, looper, "NetworkScore test agent", nc,
|
||||
LinkProperties(), score, config, NetworkProvider(context, looper,
|
||||
"NetworkScore test provider")) {}.also {
|
||||
agentsToCleanUp.add(it)
|
||||
}
|
||||
runWithShellPermissionIdentity({ agent.register() }, MANAGE_TEST_NETWORKS)
|
||||
agent.markConnected()
|
||||
return AgentWrapper(agent)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testExitingLosesAndOldSatisfierWins() {
|
||||
val cb = makeTestNetworkCallback()
|
||||
val agent1 = createTestNetworkAgent()
|
||||
cb.expectAvailableThenValidatedCallbacks(agent1)
|
||||
val agent2 = createTestNetworkAgent()
|
||||
// Because the existing network must win, the callback stays on agent1.
|
||||
cb.assertNoCallback(NO_CALLBACK_TIMEOUT)
|
||||
agent1.sendNetworkScore(score(exiting = true))
|
||||
// Now that agent1 is exiting, the callback is satisfied by agent2.
|
||||
cb.expectAvailableCallbacks(agent2.network)
|
||||
agent1.sendNetworkScore(score(exiting = false))
|
||||
// Agent1 is no longer exiting, but agent2 is the current satisfier.
|
||||
cb.assertNoCallback(NO_CALLBACK_TIMEOUT)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testVpnWins() {
|
||||
val cb = makeTestNetworkCallback()
|
||||
val agent1 = createTestNetworkAgent()
|
||||
cb.expectAvailableThenValidatedCallbacks(agent1.network)
|
||||
val agent2 = createTestNetworkAgent(intArrayOf(NetworkCapabilities.TRANSPORT_VPN))
|
||||
// VPN wins out against agent1 even before it's validated (hence the "then validated",
|
||||
// because it becomes the best network for this callback before it validates)
|
||||
cb.expectAvailableThenValidatedCallbacks(agent2.network)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testEverUserSelectedAcceptUnvalidatedWins() {
|
||||
val cb = makeTestNetworkCallback()
|
||||
val agent1 = createTestNetworkAgent()
|
||||
cb.expectAvailableThenValidatedCallbacks(agent1.network)
|
||||
val agent2 = createTestNetworkAgent(everUserSelected = true, acceptUnvalidated = true)
|
||||
// agent2 wins out against agent1 even before it's validated, because user-selected and
|
||||
// accept unvalidated networks should win against even networks that are validated.
|
||||
cb.expectAvailableThenValidatedCallbacks(agent2.network)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testPreferredTransportOrder() {
|
||||
val cb = makeTestNetworkCallback()
|
||||
val agentCell = createTestNetworkAgent(intArrayOf(NetworkCapabilities.TRANSPORT_CELLULAR))
|
||||
cb.expectAvailableThenValidatedCallbacks(agentCell.network)
|
||||
val agentWifi = createTestNetworkAgent(intArrayOf(NetworkCapabilities.TRANSPORT_WIFI))
|
||||
// In the absence of other discriminating factors, agentWifi wins against agentCell because
|
||||
// of its better transport, but only after it validates.
|
||||
cb.expectAvailableDoubleValidatedCallbacks(agentWifi)
|
||||
val agentEth = createTestNetworkAgent(intArrayOf(NetworkCapabilities.TRANSPORT_ETHERNET))
|
||||
// Likewise, agentEth wins against agentWifi after validation because of its better
|
||||
// transport.
|
||||
cb.expectAvailableCallbacksValidated(agentEth)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testTransportPrimary() {
|
||||
val cb = makeTestNetworkCallback()
|
||||
val agent1 = createTestNetworkAgent()
|
||||
cb.expectAvailableThenValidatedCallbacks(agent1)
|
||||
val agent2 = createTestNetworkAgent()
|
||||
// Because the existing network must win, the callback stays on agent1.
|
||||
cb.assertNoCallback(NO_CALLBACK_TIMEOUT)
|
||||
agent2.sendNetworkScore(score(primary = true))
|
||||
// Now that agent2 is primary, the callback is satisfied by agent2.
|
||||
cb.expectAvailableCallbacks(agent2.network)
|
||||
agent1.sendNetworkScore(score(primary = true))
|
||||
// Agent1 is primary too, but agent2 is the current satisfier
|
||||
cb.assertNoCallback(NO_CALLBACK_TIMEOUT)
|
||||
agent2.sendNetworkScore(score(primary = false))
|
||||
// Now agent1 is primary and agent2 isn't
|
||||
cb.expectAvailableCallbacks(agent1.network)
|
||||
}
|
||||
|
||||
// TODO (b/187929636) : add a test making sure that validated networks win over unvalidated
|
||||
// ones. Right now this is not possible because this CTS can't directly manipulate the
|
||||
// validation state of a network.
|
||||
}
|
||||
Reference in New Issue
Block a user