Fix expectCallback does not fail when no callback received

This hides 3 bugs where,
  1. In Android S, onNetworkRequested is no longer broadcasted
     by ConnectivityService in any condition. However, the test
     still passes since assertion does not fail when no callback
     received. Ignore the test on S+ devices since the behavior
     changed on S or later devices.
  2. Test network agent is not registered, but the test still
     passes.
  3. Test network agent does not fulfill the request that kept
     the network up, so the test fails since the test network
     is not needed and be torn down.

Test: android.net.NetworkProviderTest on R/S device
Bug: 189074532
Merged-In: I627dcd0f57b6ef4197d16e6c1ec0c53e675ab055
Change-Id: I627dcd0f57b6ef4197d16e6c1ec0c53e675ab055
  (cherry-picked from aosp/1731450)
This commit is contained in:
Junyu Lai
2021-05-24 13:04:52 +00:00
parent 512efafd32
commit 52e3fa127a

View File

@@ -18,6 +18,7 @@ package android.net
import android.app.Instrumentation import android.app.Instrumentation
import android.content.Context import android.content.Context
import android.net.NetworkCapabilities.NET_CAPABILITY_TRUSTED
import android.net.NetworkCapabilities.TRANSPORT_TEST import android.net.NetworkCapabilities.TRANSPORT_TEST
import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable import android.net.NetworkProviderTest.TestNetworkCallback.CallbackEntry.OnUnavailable
import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetworkRequestWithdrawn
@@ -25,14 +26,18 @@ import android.net.NetworkProviderTest.TestNetworkProvider.CallbackEntry.OnNetwo
import android.os.Build import android.os.Build
import android.os.HandlerThread import android.os.HandlerThread
import android.os.Looper import android.os.Looper
import android.util.Log
import androidx.test.InstrumentationRegistry import androidx.test.InstrumentationRegistry
import com.android.net.module.util.ArrayTrackRecord import com.android.net.module.util.ArrayTrackRecord
import com.android.testutils.CompatUtil import com.android.testutils.CompatUtil
import com.android.testutils.DevSdkIgnoreRule
import com.android.testutils.DevSdkIgnoreRule.IgnoreAfter
import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo import com.android.testutils.DevSdkIgnoreRule.IgnoreUpTo
import com.android.testutils.DevSdkIgnoreRunner import com.android.testutils.DevSdkIgnoreRunner
import com.android.testutils.isDevSdkInRange import com.android.testutils.isDevSdkInRange
import org.junit.After import org.junit.After
import org.junit.Before import org.junit.Before
import org.junit.Rule
import org.junit.Test import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
import org.mockito.Mockito.doReturn import org.mockito.Mockito.doReturn
@@ -41,6 +46,7 @@ import org.mockito.Mockito.verifyNoMoreInteractions
import java.util.UUID import java.util.UUID
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertNotEquals import kotlin.test.assertNotEquals
import kotlin.test.fail
private const val DEFAULT_TIMEOUT_MS = 5000L private const val DEFAULT_TIMEOUT_MS = 5000L
private val instrumentation: Instrumentation private val instrumentation: Instrumentation
@@ -51,6 +57,8 @@ private val PROVIDER_NAME = "NetworkProviderTest"
@RunWith(DevSdkIgnoreRunner::class) @RunWith(DevSdkIgnoreRunner::class)
@IgnoreUpTo(Build.VERSION_CODES.Q) @IgnoreUpTo(Build.VERSION_CODES.Q)
class NetworkProviderTest { class NetworkProviderTest {
@Rule @JvmField
val mIgnoreRule = DevSdkIgnoreRule()
private val mCm = context.getSystemService(ConnectivityManager::class.java) private val mCm = context.getSystemService(ConnectivityManager::class.java)
private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread") private val mHandlerThread = HandlerThread("${javaClass.simpleName} handler thread")
@@ -68,6 +76,7 @@ class NetworkProviderTest {
private class TestNetworkProvider(context: Context, looper: Looper) : private class TestNetworkProvider(context: Context, looper: Looper) :
NetworkProvider(context, looper, PROVIDER_NAME) { NetworkProvider(context, looper, PROVIDER_NAME) {
private val TAG = this::class.simpleName
private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead() private val seenEvents = ArrayTrackRecord<CallbackEntry>().newReadHead()
sealed class CallbackEntry { sealed class CallbackEntry {
@@ -80,22 +89,30 @@ class NetworkProviderTest {
} }
override fun onNetworkRequested(request: NetworkRequest, score: Int, id: Int) { override fun onNetworkRequested(request: NetworkRequest, score: Int, id: Int) {
Log.d(TAG, "onNetworkRequested $request, $score, $id")
seenEvents.add(OnNetworkRequested(request, score, id)) seenEvents.add(OnNetworkRequested(request, score, id))
} }
override fun onNetworkRequestWithdrawn(request: NetworkRequest) { override fun onNetworkRequestWithdrawn(request: NetworkRequest) {
Log.d(TAG, "onNetworkRequestWithdrawn $request")
seenEvents.add(OnNetworkRequestWithdrawn(request)) seenEvents.add(OnNetworkRequestWithdrawn(request))
} }
inline fun <reified T : CallbackEntry> expectCallback( inline fun <reified T : CallbackEntry> eventuallyExpectCallbackThat(
crossinline predicate: (T) -> Boolean crossinline predicate: (T) -> Boolean
) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) } ) = seenEvents.poll(DEFAULT_TIMEOUT_MS) { it is T && predicate(it) }
?: fail("Did not receive callback after ${DEFAULT_TIMEOUT_MS}ms")
} }
private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider { private fun createNetworkProvider(ctx: Context = context): TestNetworkProvider {
return TestNetworkProvider(ctx, mHandlerThread.looper) return TestNetworkProvider(ctx, mHandlerThread.looper)
} }
// In S+ framework, do not run this test, since the provider will no longer receive
// onNetworkRequested for every request. Instead, provider needs to
// call {@code registerNetworkOffer} with the description of networks they
// might have ability to setup, and expects {@link NetworkOfferCallback#onNetworkNeeded}.
@IgnoreAfter(Build.VERSION_CODES.R)
@Test @Test
fun testOnNetworkRequested() { fun testOnNetworkRequested() {
val provider = createNetworkProvider() val provider = createNetworkProvider()
@@ -105,13 +122,15 @@ class NetworkProviderTest {
val specifier = CompatUtil.makeTestNetworkSpecifier( val specifier = CompatUtil.makeTestNetworkSpecifier(
UUID.randomUUID().toString()) UUID.randomUUID().toString())
// Test network is not allowed to be trusted.
val nr: NetworkRequest = NetworkRequest.Builder() val nr: NetworkRequest = NetworkRequest.Builder()
.addTransportType(TRANSPORT_TEST) .addTransportType(TRANSPORT_TEST)
.removeCapability(NET_CAPABILITY_TRUSTED)
.setNetworkSpecifier(specifier) .setNetworkSpecifier(specifier)
.build() .build()
val cb = ConnectivityManager.NetworkCallback() val cb = ConnectivityManager.NetworkCallback()
mCm.requestNetwork(nr, cb) mCm.requestNetwork(nr, cb)
provider.expectCallback<OnNetworkRequested>() { callback -> provider.eventuallyExpectCallbackThat<OnNetworkRequested>() { callback ->
callback.request.getNetworkSpecifier() == specifier && callback.request.getNetworkSpecifier() == specifier &&
callback.request.hasTransport(TRANSPORT_TEST) callback.request.hasTransport(TRANSPORT_TEST)
} }
@@ -131,22 +150,24 @@ class NetworkProviderTest {
val config = NetworkAgentConfig.Builder().build() val config = NetworkAgentConfig.Builder().build()
val agent = object : NetworkAgent(context, mHandlerThread.looper, "TestAgent", nc, lp, val agent = object : NetworkAgent(context, mHandlerThread.looper, "TestAgent", nc, lp,
initialScore, config, provider) {} initialScore, config, provider) {}
agent.register()
agent.markConnected()
provider.expectCallback<OnNetworkRequested>() { callback -> provider.eventuallyExpectCallbackThat<OnNetworkRequested>() { callback ->
callback.request.getNetworkSpecifier() == specifier && callback.request.getNetworkSpecifier() == specifier &&
callback.score == initialScore && callback.score == initialScore &&
callback.id == agent.providerId callback.id == agent.providerId
} }
agent.sendNetworkScore(updatedScore) agent.sendNetworkScore(updatedScore)
provider.expectCallback<OnNetworkRequested>() { callback -> provider.eventuallyExpectCallbackThat<OnNetworkRequested>() { callback ->
callback.request.getNetworkSpecifier() == specifier && callback.request.getNetworkSpecifier() == specifier &&
callback.score == updatedScore && callback.score == updatedScore &&
callback.id == agent.providerId callback.id == agent.providerId
} }
mCm.unregisterNetworkCallback(cb) mCm.unregisterNetworkCallback(cb)
provider.expectCallback<OnNetworkRequestWithdrawn>() { callback -> provider.eventuallyExpectCallbackThat<OnNetworkRequestWithdrawn>() { callback ->
callback.request.getNetworkSpecifier() == specifier && callback.request.getNetworkSpecifier() == specifier &&
callback.request.hasTransport(TRANSPORT_TEST) callback.request.hasTransport(TRANSPORT_TEST)
} }