Add a first CTS for NetworkScore am: e349356eb9

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Connectivity/+/1744646

Change-Id: I3c971e176fe42cac13414346e84f77c3ddb8b9f0
This commit is contained in:
Chalard Jean
2021-06-25 15:42:39 +00:00
committed by Automerger Merge Worker

View File

@@ -0,0 +1,154 @@
/*
* 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.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)
}
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)
}
}