Make a base class for testable callbacks
Have TestableNetworkCallback adopt it, as a first client. It's also by far the most complex. Test: TH Flag: EXEMPT test-only Change-Id: Ie58d051b4478c901b7f0f54e89a67d22f1ee2ce2
This commit is contained in:
parent
5c015cfb69
commit
2db96977db
9 changed files with 577 additions and 166 deletions
|
|
@ -122,6 +122,7 @@ class TestableNetworkCallbackTest {
|
|||
mCallback.assertNoCallback(SHORT_TIMEOUT_MS)
|
||||
mCallback.onAvailable(Network(100))
|
||||
assertFails { mCallback.assertNoCallback(SHORT_TIMEOUT_MS) }
|
||||
mCallback.expect<Available>()
|
||||
val net = Network(101)
|
||||
mCallback.assertNoCallback { it is Available }
|
||||
mCallback.onAvailable(net)
|
||||
|
|
@ -277,33 +278,33 @@ class TestableNetworkCallbackTest {
|
|||
fun testAllExpectOverloads() {
|
||||
// This test should never run, it only checks that all overloads exist and build
|
||||
assumeTrue(false)
|
||||
val hn = object : TestableNetworkCallback.HasNetwork { override val network = ANY_NETWORK }
|
||||
val hn = object : TestableNetworkCallback.HasNetwork { override val network = AnyNetwork }
|
||||
|
||||
// Method with all arguments (version that takes a Network)
|
||||
mCallback.expect(AVAILABLE, ANY_NETWORK, 10, "error") { true }
|
||||
mCallback.expect(AVAILABLE, AnyNetwork, 10, "error") { true }
|
||||
|
||||
// Java overloads omitting one argument. One line for omitting each argument, in positional
|
||||
// order. Versions that take a Network.
|
||||
mCallback.expect(AVAILABLE, 10, "error") { true }
|
||||
mCallback.expect(AVAILABLE, ANY_NETWORK, "error") { true }
|
||||
mCallback.expect(AVAILABLE, ANY_NETWORK, 10) { true }
|
||||
mCallback.expect(AVAILABLE, ANY_NETWORK, 10, "error")
|
||||
mCallback.expect(AVAILABLE, AnyNetwork, "error") { true }
|
||||
mCallback.expect(AVAILABLE, AnyNetwork, 10) { true }
|
||||
mCallback.expect(AVAILABLE, AnyNetwork, 10, "error")
|
||||
|
||||
// Java overloads for omitting two arguments. One line for omitting each pair of arguments.
|
||||
// Versions that take a Network.
|
||||
mCallback.expect(AVAILABLE, "error") { true }
|
||||
mCallback.expect(AVAILABLE, 10) { true }
|
||||
mCallback.expect(AVAILABLE, 10, "error")
|
||||
mCallback.expect(AVAILABLE, ANY_NETWORK) { true }
|
||||
mCallback.expect(AVAILABLE, ANY_NETWORK, "error")
|
||||
mCallback.expect(AVAILABLE, ANY_NETWORK, 10)
|
||||
mCallback.expect(AVAILABLE, AnyNetwork) { true }
|
||||
mCallback.expect(AVAILABLE, AnyNetwork, "error")
|
||||
mCallback.expect(AVAILABLE, AnyNetwork, 10)
|
||||
|
||||
// Java overloads for omitting three arguments. One line for each remaining argument.
|
||||
// Versions that take a Network.
|
||||
mCallback.expect(AVAILABLE) { true }
|
||||
mCallback.expect(AVAILABLE, "error")
|
||||
mCallback.expect(AVAILABLE, 10)
|
||||
mCallback.expect(AVAILABLE, ANY_NETWORK)
|
||||
mCallback.expect(AVAILABLE, AnyNetwork)
|
||||
|
||||
// Java overload for omitting all four arguments.
|
||||
mCallback.expect(AVAILABLE)
|
||||
|
|
@ -322,23 +323,23 @@ class TestableNetworkCallbackTest {
|
|||
mCallback.expect(AVAILABLE, hn)
|
||||
|
||||
// Same as above but for reified versions.
|
||||
mCallback.expect<Available>(ANY_NETWORK, 10, "error") { true }
|
||||
mCallback.expect<Available>(AnyNetwork, 10, "error") { true }
|
||||
mCallback.expect<Available>(timeoutMs = 10, errorMsg = "error") { true }
|
||||
mCallback.expect<Available>(network = ANY_NETWORK, errorMsg = "error") { true }
|
||||
mCallback.expect<Available>(network = ANY_NETWORK, timeoutMs = 10) { true }
|
||||
mCallback.expect<Available>(network = ANY_NETWORK, timeoutMs = 10, errorMsg = "error")
|
||||
mCallback.expect<Available>(network = AnyNetwork, errorMsg = "error") { true }
|
||||
mCallback.expect<Available>(network = AnyNetwork, timeoutMs = 10) { true }
|
||||
mCallback.expect<Available>(network = AnyNetwork, timeoutMs = 10, errorMsg = "error")
|
||||
|
||||
mCallback.expect<Available>(errorMsg = "error") { true }
|
||||
mCallback.expect<Available>(timeoutMs = 10) { true }
|
||||
mCallback.expect<Available>(timeoutMs = 10, errorMsg = "error")
|
||||
mCallback.expect<Available>(network = ANY_NETWORK) { true }
|
||||
mCallback.expect<Available>(network = ANY_NETWORK, errorMsg = "error")
|
||||
mCallback.expect<Available>(network = ANY_NETWORK, timeoutMs = 10)
|
||||
mCallback.expect<Available>(network = AnyNetwork) { true }
|
||||
mCallback.expect<Available>(network = AnyNetwork, errorMsg = "error")
|
||||
mCallback.expect<Available>(network = AnyNetwork, timeoutMs = 10)
|
||||
|
||||
mCallback.expect<Available> { true }
|
||||
mCallback.expect<Available>(errorMsg = "error")
|
||||
mCallback.expect<Available>(timeoutMs = 10)
|
||||
mCallback.expect<Available>(network = ANY_NETWORK)
|
||||
mCallback.expect<Available>(network = AnyNetwork)
|
||||
mCallback.expect<Available>()
|
||||
|
||||
mCallback.expect<Available>(hn, 10, "error") { true }
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
package com.android.testutils;
|
||||
|
||||
import static com.android.testutils.TestableNetworkCallback.Event.AVAILABLE;
|
||||
import static com.android.testutils.TestableNetworkCallbackKt.anyNetwork;
|
||||
import static com.android.testutils.TestableNetworkCallbackKt.AnyNetwork;
|
||||
|
||||
import static org.junit.Assume.assumeTrue;
|
||||
|
||||
|
|
@ -25,37 +25,37 @@ import org.junit.Test;
|
|||
|
||||
public class TestableNetworkCallbackTestJava {
|
||||
@Test
|
||||
void testAllExpectOverloads() {
|
||||
public void testAllExpectOverloads() {
|
||||
// This test should never run, it only checks that all overloads exist and build
|
||||
assumeTrue(false);
|
||||
final TestableNetworkCallback callback = new TestableNetworkCallback();
|
||||
TestableNetworkCallback.HasNetwork hn = TestableNetworkCallbackKt::anyNetwork;
|
||||
TestableNetworkCallback.HasNetwork hn = TestableNetworkCallbackKt::AnyNetwork;
|
||||
|
||||
// Method with all arguments (version that takes a Network)
|
||||
callback.expect(AVAILABLE, anyNetwork(), 10, "error", cb -> true);
|
||||
callback.expect(AVAILABLE, AnyNetwork(), 10, "error", cb -> true);
|
||||
|
||||
// Overloads omitting one argument. One line for omitting each argument, in positional
|
||||
// order. Versions that take a Network.
|
||||
callback.expect(AVAILABLE, 10, "error", cb -> true);
|
||||
callback.expect(AVAILABLE, anyNetwork(), "error", cb -> true);
|
||||
callback.expect(AVAILABLE, anyNetwork(), 10, cb -> true);
|
||||
callback.expect(AVAILABLE, anyNetwork(), 10, "error");
|
||||
callback.expect(AVAILABLE, AnyNetwork(), "error", cb -> true);
|
||||
callback.expect(AVAILABLE, AnyNetwork(), 10, cb -> true);
|
||||
callback.expect(AVAILABLE, AnyNetwork(), 10, "error");
|
||||
|
||||
// Overloads for omitting two arguments. One line for omitting each pair of arguments.
|
||||
// Versions that take a Network.
|
||||
callback.expect(AVAILABLE, "error", cb -> true);
|
||||
callback.expect(AVAILABLE, 10, cb -> true);
|
||||
callback.expect(AVAILABLE, 10, "error");
|
||||
callback.expect(AVAILABLE, anyNetwork(), cb -> true);
|
||||
callback.expect(AVAILABLE, anyNetwork(), "error");
|
||||
callback.expect(AVAILABLE, anyNetwork(), 10);
|
||||
callback.expect(AVAILABLE, AnyNetwork(), cb -> true);
|
||||
callback.expect(AVAILABLE, AnyNetwork(), "error");
|
||||
callback.expect(AVAILABLE, AnyNetwork(), 10);
|
||||
|
||||
// Overloads for omitting three arguments. One line for each remaining argument.
|
||||
// Versions that take a Network.
|
||||
callback.expect(AVAILABLE, cb -> true);
|
||||
callback.expect(AVAILABLE, "error");
|
||||
callback.expect(AVAILABLE, 10);
|
||||
callback.expect(AVAILABLE, anyNetwork());
|
||||
callback.expect(AVAILABLE, AnyNetwork());
|
||||
|
||||
// Java overload for omitting all four arguments.
|
||||
callback.expect(AVAILABLE);
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class ConnectivityCheckTest {
|
|||
.addCapability(NET_CAPABILITY_INTERNET)
|
||||
.build()
|
||||
)
|
||||
val capChanged = cb.eventuallyExpect<CapabilitiesChanged>(from = 0)
|
||||
val capChanged = cb.eventuallyExpect<CapabilitiesChanged>()
|
||||
val network = capChanged.network
|
||||
val ssid = capChanged.caps.ssid
|
||||
assertFalse(ssid.isNullOrEmpty(), "No SSID for wifi network $network")
|
||||
|
|
|
|||
|
|
@ -23,7 +23,12 @@ import android.net.Network
|
|||
import android.net.NetworkCapabilities
|
||||
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
|
||||
import android.util.Log
|
||||
import com.android.net.module.util.ArrayTrackRecord
|
||||
import com.android.net.module.util.Expectable
|
||||
import com.android.net.module.util.TestableCallback
|
||||
import com.android.net.module.util.assertNo
|
||||
import com.android.net.module.util.eventuallyExpect
|
||||
import com.android.net.module.util.expect
|
||||
import com.android.testutils.TestableNetworkCallback.Event
|
||||
import com.android.testutils.TestableNetworkCallback.Event.Available
|
||||
import com.android.testutils.TestableNetworkCallback.Event.BlockedStatus
|
||||
import com.android.testutils.TestableNetworkCallback.Event.BlockedStatusInt
|
||||
|
|
@ -38,12 +43,11 @@ import com.android.testutils.TestableNetworkCallback.Event.Suspended
|
|||
import com.android.testutils.TestableNetworkCallback.Event.Unavailable
|
||||
import kotlin.reflect.KClass
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.fail
|
||||
|
||||
object NULL_NETWORK : Network(-1)
|
||||
object ANY_NETWORK : Network(-2)
|
||||
fun anyNetwork() = ANY_NETWORK
|
||||
object NullNetwork : Network(-1)
|
||||
object AnyNetwork : Network(-2)
|
||||
fun AnyNetwork() = AnyNetwork
|
||||
|
||||
private val DEFAULT_TAG = TestableNetworkCallback::class.simpleName
|
||||
?: fail("Could not determine class name")
|
||||
|
|
@ -56,15 +60,15 @@ private val NOOP = Runnable {}
|
|||
* See comments on the public constructor below for a description of the arguments.
|
||||
*/
|
||||
open class TestableNetworkCallback private constructor(
|
||||
src: TestableNetworkCallback?,
|
||||
val defaultTimeoutMs: Long,
|
||||
private val defaultNoCallbackTimeoutMs: Long,
|
||||
defaultCallbackTimeoutMs: Long,
|
||||
defaultCallbackNoEventTimeoutMs: Long,
|
||||
private val waiterFunc: Runnable,
|
||||
private val logTag: String
|
||||
) : NetworkCallback() {
|
||||
private val backingRecord: ArrayTrackRecord<Event> =
|
||||
src?.backingRecord ?: ArrayTrackRecord()
|
||||
val history: ArrayTrackRecord<Event>.ReadHead = backingRecord.newReadHead()
|
||||
private val logTag: String,
|
||||
val callbackTracker: TestableCallback<Event> = TestableCallback(
|
||||
defaultCallbackTimeoutMs,
|
||||
defaultCallbackNoEventTimeoutMs
|
||||
)
|
||||
) : NetworkCallback(), Expectable<Event> by callbackTracker {
|
||||
val mark get() = history.mark
|
||||
|
||||
sealed class Event {
|
||||
|
|
@ -80,7 +84,7 @@ open class TestableNetworkCallback private constructor(
|
|||
override val network: Network,
|
||||
val caps: NetworkCapabilities
|
||||
) : Event() {
|
||||
constructor(caps: NetworkCapabilities) : this(NULL_NETWORK, caps)
|
||||
constructor(caps: NetworkCapabilities) : this(NullNetwork, caps)
|
||||
}
|
||||
data class Available(override val network: Network) : Event()
|
||||
data class CapabilitiesChanged(
|
||||
|
|
@ -102,7 +106,7 @@ open class TestableNetworkCallback private constructor(
|
|||
data class Unavailable(
|
||||
override val network: Network
|
||||
) : Event() {
|
||||
constructor() : this(NULL_NETWORK)
|
||||
constructor() : this(NullNetwork)
|
||||
}
|
||||
data class BlockedStatus(
|
||||
override val network: Network,
|
||||
|
|
@ -226,18 +230,25 @@ open class TestableNetworkCallback private constructor(
|
|||
noCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT,
|
||||
waiterFunc: Runnable = NOOP, // "() -> Unit" would forbid calling with a void func from Java
|
||||
logTag: String = DEFAULT_TAG
|
||||
) : this(null, timeoutMs, noCallbackTimeoutMs, waiterFunc, logTag)
|
||||
) : this(
|
||||
timeoutMs,
|
||||
noCallbackTimeoutMs,
|
||||
waiterFunc,
|
||||
logTag,
|
||||
TestableCallback(timeoutMs, noCallbackTimeoutMs)
|
||||
)
|
||||
|
||||
fun createLinkedCopy() = TestableNetworkCallback(
|
||||
this,
|
||||
defaultTimeoutMs,
|
||||
defaultNoCallbackTimeoutMs,
|
||||
defaultNoEventTimeoutMs,
|
||||
waiterFunc,
|
||||
logTag
|
||||
logTag,
|
||||
callbackTracker
|
||||
)
|
||||
|
||||
// The last available network, or null if any network was lost since the last call to
|
||||
// onAvailable. TODO : fix this by fixing the tests that rely on this behavior
|
||||
// DO NOT ADD CALLS TO THIS METHOD. USE THE RETURN VALUE OF expect<> INSTEAD.
|
||||
val lastAvailableNetwork: Network?
|
||||
get() = when (val it = history.lastOrNull { it is Available || it is Lost }) {
|
||||
is Available -> it.network
|
||||
|
|
@ -254,25 +265,56 @@ open class TestableNetworkCallback private constructor(
|
|||
fun poll(timeoutMs: Long = defaultTimeoutMs, predicate: (Event) -> Boolean = { true }) =
|
||||
history.poll(timeoutMs, predicate)
|
||||
|
||||
// Proxy methods to avoid having to write expect<_, T>, see TestableCallback.kt
|
||||
inline fun <reified T : Event> expect(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = expect<_, T>(timeoutMs, errorMsg, predicate)
|
||||
|
||||
inline fun <reified T : Event> eventuallyExpect(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = eventuallyExpect<_, T>(timeoutMs, errorMsg, predicate)
|
||||
|
||||
inline fun <reified T : Event> assertNo(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = assertNo<_, T>(timeoutMs, errorMsg, predicate)
|
||||
|
||||
/*****
|
||||
* expect family of methods.
|
||||
* These methods fetch the next callback and assert it matches the conditions : type,
|
||||
* passed predicate. If no callback is received within the timeout, these methods fail.
|
||||
* expect family of methods, to support Java code
|
||||
*
|
||||
* See Expectable#expect
|
||||
*/
|
||||
@Suppress("SuspiciousEqualsCombination") // === and == combination is legit here
|
||||
@JvmOverloads
|
||||
fun <T : Event> expect(
|
||||
type: KClass<T>,
|
||||
network: Network = ANY_NETWORK,
|
||||
network: Network = AnyNetwork,
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
test: (T) -> Boolean = { true }
|
||||
) = expect<Event>(network, timeoutMs, errorMsg) {
|
||||
if (type.isInstance(it)) {
|
||||
test(it as T) // Cast can't fail since type.isInstance(it) and type: KClass<T>
|
||||
} else {
|
||||
fail("Expected callback ${type.simpleName}, got $it")
|
||||
}
|
||||
} as T
|
||||
): T = callbackTracker.expect(type, timeoutMs, errorMsg) {
|
||||
(network === AnyNetwork || it.network == network) && test(it)
|
||||
}
|
||||
|
||||
// Add a version of the standard expect method that takes a network.
|
||||
inline fun <reified T : Event> expect(
|
||||
network: Network = AnyNetwork,
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline test: (T) -> Boolean = { true }
|
||||
) = expect(T::class, network, timeoutMs, errorMsg, test)
|
||||
|
||||
inline fun <reified T : Event> expect(
|
||||
network: HasNetwork,
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline test: (T) -> Boolean = { true }
|
||||
) = expect(T::class, network.network, timeoutMs, errorMsg, test)
|
||||
|
||||
@JvmOverloads
|
||||
fun <T : Event> expect(
|
||||
|
|
@ -287,13 +329,11 @@ open class TestableNetworkCallback private constructor(
|
|||
// here. Note that @JvmOverloads give us the versions without the last arguments too, so
|
||||
// there is no need to explicitly define versions without the test predicate.
|
||||
// Without |network|
|
||||
@JvmOverloads
|
||||
fun <T : Event> expect(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long,
|
||||
errorMsg: String?,
|
||||
test: (T) -> Boolean = { true }
|
||||
) = expect(type, ANY_NETWORK, timeoutMs, errorMsg, test)
|
||||
) = expect(type, AnyNetwork, timeoutMs, errorMsg)
|
||||
|
||||
// Without |timeout|, in Network and HasNetwork versions
|
||||
@JvmOverloads
|
||||
|
|
@ -333,7 +373,7 @@ open class TestableNetworkCallback private constructor(
|
|||
type: KClass<T>,
|
||||
errorMsg: String?,
|
||||
test: (T) -> Boolean = { true }
|
||||
) = expect(type, ANY_NETWORK, defaultTimeoutMs, errorMsg, test)
|
||||
) = expect(type, AnyNetwork, defaultTimeoutMs, errorMsg, test)
|
||||
|
||||
// Without |network| or |errorMsg|
|
||||
@JvmOverloads
|
||||
|
|
@ -341,7 +381,7 @@ open class TestableNetworkCallback private constructor(
|
|||
type: KClass<T>,
|
||||
timeoutMs: Long,
|
||||
test: (T) -> Boolean = { true }
|
||||
) = expect(type, ANY_NETWORK, timeoutMs, null, test)
|
||||
) = expect(type, AnyNetwork, timeoutMs, null, test)
|
||||
|
||||
// Without |timeout| or |errorMsg|, in Network and HasNetwork versions
|
||||
fun <T : Event> expect(
|
||||
|
|
@ -360,37 +400,54 @@ open class TestableNetworkCallback private constructor(
|
|||
fun <T : Event> expect(
|
||||
type: KClass<T>,
|
||||
test: (T) -> Boolean
|
||||
) = expect(type, ANY_NETWORK, defaultTimeoutMs, null, test)
|
||||
) = expect(type, AnyNetwork, defaultTimeoutMs, null, test)
|
||||
|
||||
// Kotlin reified versions. Don't call methods above, or the predicate would need to be noinline
|
||||
inline fun <reified T : Event> expect(
|
||||
network: Network = ANY_NETWORK,
|
||||
/*****
|
||||
* eventuallyExpect family of methods, to support Java code
|
||||
*
|
||||
* See Expectable#eventuallyExpect
|
||||
*/
|
||||
@JvmOverloads
|
||||
fun <T : Event> eventuallyExpect(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
test: (T) -> Boolean = { true }
|
||||
) = (poll(timeoutMs) ?: failWithErrorReason(errorMsg,
|
||||
"Did not receive ${T::class.simpleName} after ${timeoutMs}ms"))
|
||||
.also {
|
||||
if (it !is T) {
|
||||
failWithErrorReason(
|
||||
errorMsg,
|
||||
"Expected callback ${T::class.simpleName}, got $it"
|
||||
)
|
||||
}
|
||||
if (ANY_NETWORK !== network && it.network != network) {
|
||||
failWithErrorReason(errorMsg, "Expected network $network for callback : $it")
|
||||
}
|
||||
if (!test(it)) {
|
||||
failWithErrorReason(errorMsg, "Callback doesn't match predicate : $it")
|
||||
}
|
||||
} as T
|
||||
predicate: (cb: T) -> Boolean = { true }
|
||||
) = callbackTracker.eventuallyExpect(type, timeoutMs, errorMsg = null, predicate)
|
||||
|
||||
inline fun <reified T : Event> expect(
|
||||
network: HasNetwork,
|
||||
// eventuallyExpect with a starting point.
|
||||
// TODO : remove these methods, their interface is not easy to use ; instead, use an
|
||||
// explicit out-of-order checking mechanism.
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T : Event> eventuallyExpect(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long,
|
||||
from: Int,
|
||||
predicate: (T) -> Boolean
|
||||
): T {
|
||||
val event = history.poll(timeoutMs, pos = from) {
|
||||
type.isInstance(it) && predicate(it as T)
|
||||
}
|
||||
if (null == event) {
|
||||
failWithErrorReason(
|
||||
null,
|
||||
"Callback ${type.simpleName} not received within ${timeoutMs}ms. Got\n" +
|
||||
history.prettyPrintBacktrace(before = 2, after = 2)
|
||||
)
|
||||
}
|
||||
return event as T
|
||||
}
|
||||
|
||||
fun <T : Event> eventuallyExpect(
|
||||
type: KClass<T>,
|
||||
from: Int,
|
||||
predicate: (T) -> Boolean
|
||||
): T = eventuallyExpect(type, timeoutMs = defaultTimeoutMs, from, predicate)
|
||||
|
||||
inline fun <reified T : Event> eventuallyExpect(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
test: (T) -> Boolean = { true }
|
||||
) = expect(network.network, timeoutMs, errorMsg, test)
|
||||
from: Int,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = eventuallyExpect(T::class, timeoutMs, from, predicate)
|
||||
|
||||
/*****
|
||||
* assertNoCallback family of methods.
|
||||
|
|
@ -400,59 +457,15 @@ open class TestableNetworkCallback private constructor(
|
|||
*/
|
||||
@JvmOverloads
|
||||
fun assertNoCallback(
|
||||
timeoutMs: Long = defaultNoCallbackTimeoutMs,
|
||||
timeoutMs: Long = defaultNoEventTimeoutMs,
|
||||
valid: (Event) -> Boolean = { true }
|
||||
) {
|
||||
waiterFunc.run()
|
||||
history.poll(timeoutMs) { valid(it) }?.let { fail("Expected no callback but got $it") }
|
||||
callbackTracker.assertNoCallback(timeoutMs, errorMsg = null, valid)
|
||||
}
|
||||
|
||||
fun assertNoCallback(valid: (Event) -> Boolean) =
|
||||
assertNoCallback(defaultNoCallbackTimeoutMs, valid)
|
||||
|
||||
/*****
|
||||
* eventuallyExpect family of methods.
|
||||
* These methods make sure a callback that matches the type/predicate is received eventually.
|
||||
* Any callback of the wrong type, or doesn't match the optional predicate, is ignored.
|
||||
* They fail if no callback matching the predicate is received within the timeout.
|
||||
*/
|
||||
inline fun <reified T : Event> eventuallyExpect(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
from: Int = mark,
|
||||
crossinline predicate: (T) -> Boolean = { true }
|
||||
): T = history.poll(timeoutMs, from) { it is T && predicate(it) }.also {
|
||||
assertNotNull(
|
||||
it,
|
||||
"Callback ${T::class} not received within ${timeoutMs}ms. " +
|
||||
"Got ${history.backtrace()}"
|
||||
)
|
||||
} as T
|
||||
|
||||
@JvmOverloads
|
||||
fun <T : Event> eventuallyExpect(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
predicate: (cb: T) -> Boolean = { true }
|
||||
) = history.poll(timeoutMs) { type.java.isInstance(it) && predicate(it as T) }.also {
|
||||
assertNotNull(
|
||||
it,
|
||||
"Callback ${type.java} not received within ${timeoutMs}ms. " +
|
||||
"Got ${history.backtrace()}"
|
||||
)
|
||||
} as T
|
||||
|
||||
fun <T : Event> eventuallyExpect(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
from: Int = mark,
|
||||
predicate: (cb: T) -> Boolean = { true }
|
||||
) = history.poll(timeoutMs, from) { type.java.isInstance(it) && predicate(it as T) }.also {
|
||||
assertNotNull(
|
||||
it,
|
||||
"Callback ${type.java} not received within ${timeoutMs}ms. " +
|
||||
"Got ${history.backtrace()}"
|
||||
)
|
||||
} as T
|
||||
assertNoCallback(defaultNoEventTimeoutMs, valid)
|
||||
|
||||
// Expects onAvailable and the callbacks that follow it. These are:
|
||||
// - onSuspended, iff the network was suspended when the callbacks fire.
|
||||
|
|
@ -639,5 +652,5 @@ open class TestableNetworkCallback private constructor(
|
|||
fun expectCaps(
|
||||
tmt: Long,
|
||||
valid: (NetworkCapabilities) -> Boolean
|
||||
) = expect<CapabilitiesChanged>(ANY_NETWORK, tmt) { valid(it.caps) }.caps
|
||||
) = expect<CapabilitiesChanged>(AnyNetwork, tmt) { valid(it.caps) }.caps
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,358 @@
|
|||
/*
|
||||
* Copyright (C) 2025 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("UNCHECKED_CAST") // cast is checked by type.isInstance throughout the file
|
||||
|
||||
package com.android.net.module.util
|
||||
|
||||
import com.android.testutils.failWithErrorReason
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
private const val DEFAULT_TIMEOUT = 30_000L // ms
|
||||
private const val DEFAULT_NO_EVENT_TIMEOUT = 200L // ms
|
||||
|
||||
/**
|
||||
* These classes, [Expectable] and [TestableCallback], are tools designed to simplify the testing
|
||||
* of asynchronous callbacks in your code.
|
||||
*
|
||||
* A **callback** is a piece of code that gets executed when a specific event happens (e.g., data
|
||||
* received, network disconnected). These utilities help you define, record, and then assert the
|
||||
* occurrence or non-occurrence of these events in your tests.
|
||||
*
|
||||
* To use these tools, your test class typically needs to:
|
||||
* 1. Define a **sealed class** for all possible events that your callback can produce. Each
|
||||
* specific event should be a `data class` subclass of this sealed event type. This ensures type
|
||||
* safety and clear event definitions.
|
||||
* Note : if there is only one event you can skip the sealed class and only have one data class
|
||||
* representing that event.
|
||||
* 2. Subclass [TestableCallback] and have your subclass implement the callback interface. If you
|
||||
* cannot subclass [TestableCallback] because the callback is not an interface, your subclass
|
||||
* will instead compose a [TestableCallback] which will allow for implementing [Expectable]
|
||||
* with no additional work.
|
||||
*
|
||||
*
|
||||
* ## How to Use: Two Main Scenarios
|
||||
*
|
||||
* ### Scenario 1: Testing an Interface callback (Recommended)
|
||||
*
|
||||
* If the callback you are testing is an **interface** (e.g., `NetworkOfferCallback`), then
|
||||
* your test callback class should **inherit directly from [TestableCallback]**. This gives you
|
||||
* all the `expect` and `assertNo` family of methods for free.
|
||||
*
|
||||
* **Example:** Testing a `TestedServiceCallback` interface with `onFirstAction` and
|
||||
* `onSecondAction` methods.
|
||||
* ```kotlin
|
||||
* // The interface you want to test
|
||||
* interface TestedServiceCallback {
|
||||
* fun onFirstAction(data: String)
|
||||
* fun onSecondAction(value: Int)
|
||||
* }
|
||||
*
|
||||
* class MyTestServiceCallback : TestableCallback<Event>(), TestedServiceCallback {
|
||||
* // Define all the possible events that can occur from this callback
|
||||
* sealed class Event {
|
||||
* data class FirstAction(val data: String) : ServiceEvent()
|
||||
* data class SecondAction(val value: Int) : ServiceEvent()
|
||||
* }
|
||||
*
|
||||
* // Implement the interface methods and record the events into the history
|
||||
* override fun onFirstAction(data: String) = history.add(FirstAction(data))
|
||||
* override fun onSecondAction(value: Int) = history.add(SecondAction(value))
|
||||
*
|
||||
* // You can add custom helper methods here if you want more functionality than the default
|
||||
* // expect/assertNo methods offer.
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* **In your test code, you can then:**
|
||||
* // Wait for a `FirstAction` event where the argument starts with "foo" to happen within the
|
||||
* // default timeout.
|
||||
* `myTestServiceCallback.expect<FirstAction>() { it.data.startsWith("foo") }`
|
||||
* // Wait for any `SecondAction` event for up to 500 milliseconds.
|
||||
* `myTestServiceCallback.expect<SecondAction>(timeoutMs = 500)`
|
||||
* // Make sure no `SecondAction` event has fired so far.
|
||||
* `myTestServiceCallback.assertNo<SecondAction>()
|
||||
* etc.
|
||||
*
|
||||
* ### Scenario 2: Testing a class callback (Only do this when inheritance isn't possible)
|
||||
*
|
||||
* If the callback you need to test is a **class** (not an interface), direct inheritance from
|
||||
* [TestableCallback] isn't possible. In this case, you will:
|
||||
* 1. **Embed** an instance of [TestableCallback] inside your test class.
|
||||
* 2. Declare that your test class **implements [Expectable] by delegating** to this embedded
|
||||
* [TestableCallback] instance. This means your class will use the embedded `TestableCallback`'s
|
||||
* functionality for event tracking.
|
||||
* ```kotlin
|
||||
* MyTestServiceCallback(internalEventTracker: TestableCallback<Event>)
|
||||
* : TestedServiceCallback, Expectable<Event> by internalEventTracker { ...
|
||||
* ```
|
||||
* 3. **Proxy** the `expect`, `eventuallyExpect`, and `assertNo` methods. This makes your test code
|
||||
* simpler by allowing you to write `expect<MySpecificEvent>()` instead of
|
||||
* `expect<_, MySpecificEvent>()`.
|
||||
*
|
||||
* **Example:** Testing a `TestedServiceCallback` class with `onFirstAction` and `onSecondAction`
|
||||
* methods.
|
||||
* ```kotlin
|
||||
* import com.android.net.module.util.assertNo
|
||||
* import com.android.net.module.util.expect
|
||||
* import com.android.net.module.util.eventuallyExpect
|
||||
*
|
||||
* // The class you want to test
|
||||
* open class TestedServiceCallback {
|
||||
* open fun onFirstAction(data: String)
|
||||
* open fun onSecondAction(value: Int)
|
||||
* }
|
||||
*
|
||||
* class MyTestServiceCallback(
|
||||
* // Embed a TestableCallback to handle the actual event tracking
|
||||
* private val internalEventTracker: TestableCallback<Event> = TestableCallback()
|
||||
* ) : TestedServiceCallback(), Expectable<Event> by internalEventTracker {
|
||||
*
|
||||
* // Define all the possible events that can occur from this callback
|
||||
* sealed class Event {
|
||||
* data class FirstAction(val data: String) : ServiceEvent()
|
||||
* data class SecondAction(val value: Int) : ServiceEvent()
|
||||
* }
|
||||
*
|
||||
* // Implement the interface methods and record the events into the history
|
||||
* override fun onFirstAction(data: String) = history.add(FirstAction(data))
|
||||
* override fun onSecondAction(value: Int) = history.add(SecondAction(value))
|
||||
*
|
||||
* // Proxy methods: These make it simpler to call expect/assertNo, avoiding 'expect<_, T>'
|
||||
* // They simply forward the call to the embedded internalEventTracker.
|
||||
* inline fun <reified T : Event> expect(
|
||||
* timeoutMs: Long = defaultTimeoutMs,
|
||||
* errorMsg: String? = null,
|
||||
* noinline predicate: (T) -> Boolean = { true }
|
||||
* ) = expect<_, T>(timeoutMs, errorMsg, predicate)
|
||||
*
|
||||
* inline fun <reified T : Event> eventuallyExpect(
|
||||
* timeoutMs: Long = defaultTimeoutMs,
|
||||
* errorMsg: String? = null,
|
||||
* noinline predicate: (T) -> Boolean = { true }
|
||||
* ) = eventuallyExpect<_, T>(timeoutMs, errorMsg, predicate)
|
||||
*
|
||||
* inline fun <reified T : Event> assertNo(
|
||||
* timeoutMs: Long = defaultTimeoutMs,
|
||||
* errorMsg: String? = null,
|
||||
* noinline predicate: (T) -> Boolean = { true }
|
||||
* ) = assertNo<_, T>(timeoutMs, errorMsg, predicate)
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
*
|
||||
* ### Explanation of proxy methods (for the curious)
|
||||
*
|
||||
* The `expect`, `eventuallyExpect`, and `assertNo` methods typically reside on
|
||||
* `TestableCallback<Event>`. When you inherit from `TestableCallback`, the type `Event` is
|
||||
* directly known, making calls like `expect<MySpecificEvent>()` straightforward.
|
||||
*
|
||||
* However, `Expectable` is an interface, and as such it cannot have member methods. The
|
||||
* `Expectable.expect*` family of methods are therefore extension methods with two type arguments :
|
||||
* one for the type argument of the receiver (`Event`), one for the concrete event type
|
||||
* (`FirstAction`) ; the former is required to provide the upper bound for the latter (otherwise
|
||||
* you could call `expect<String>()`).
|
||||
* For syntactic reasons, Kotlin's compiler will refuse to call a 2-argument method with only one
|
||||
* argument, even if it can infer the first type argument. The proxy methods (like the
|
||||
* `inline fun <reified T : Event> expect(...)`) solve this by providing a single-argument version
|
||||
* that calls the 2-type argument version instructing the compiler to infer the first argument
|
||||
* (`expect<_, T>` infers `_`). This lets you write `expect<MySpecificEvent>()`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An interface for classes on which the expect* and assertNo* family of methods can be called.
|
||||
*/
|
||||
// TODO : why do we have to specify `: Any` here ? Is that not the default ? If you remove
|
||||
// it then `KClass<T>` complains that T is not within its `Any` bounds,
|
||||
interface Expectable<E : Any> {
|
||||
val history: ArrayTrackRecord<E>.ReadHead
|
||||
val defaultTimeoutMs: Long
|
||||
val defaultNoEventTimeoutMs: Long
|
||||
|
||||
/*****
|
||||
* Expect an event immediately
|
||||
*
|
||||
* This method fetches the next callback and assert it matches the conditions : type,
|
||||
* passed predicate. If no callback is received within the timeout, this method fails.
|
||||
*/
|
||||
fun <T : E> expect(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
predicate: (T) -> Boolean = { true }
|
||||
): T
|
||||
|
||||
/*****
|
||||
* Expect that some event is received eventually.
|
||||
*
|
||||
* This method makes sure a callback that matches the type/predicate is received eventually.
|
||||
* Any callback of the wrong type, or doesn't match the optional predicate, is ignored.
|
||||
* It fails if no callback matching the predicate is received within the timeout.
|
||||
*/
|
||||
fun <T : E> eventuallyExpect(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
predicate: (T) -> Boolean = { true }
|
||||
): T
|
||||
|
||||
/*****
|
||||
* Assert no event matching a predicate was received.
|
||||
*
|
||||
* This method makes sure that no callback that matches the predicate was received.
|
||||
* If no predicate is given, it makes sure that no callback at all was received.
|
||||
*/
|
||||
fun <T : E> assertNo(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long = defaultNoEventTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
predicate: (T) -> Boolean = { true }
|
||||
)
|
||||
|
||||
fun assertNoCallback(
|
||||
timeoutMs: Long = defaultNoEventTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
predicate: (E) -> Boolean = { true }
|
||||
)
|
||||
}
|
||||
|
||||
inline fun <E : Any, reified T : E> Expectable<E>.expect(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = expect(T::class, timeoutMs, errorMsg, predicate)
|
||||
|
||||
inline fun <E : Any, reified T : E> Expectable<E>.eventuallyExpect(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = eventuallyExpect(T::class, timeoutMs, errorMsg, predicate)
|
||||
|
||||
inline fun <E : Any, reified T : E> Expectable<E>.assertNo(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = assertNo(T::class, timeoutMs, errorMsg, predicate)
|
||||
|
||||
/**
|
||||
* A base class for connectivity testable callbacks.
|
||||
*/
|
||||
open class TestableCallback<E : Any>(
|
||||
override val defaultTimeoutMs: Long = DEFAULT_TIMEOUT,
|
||||
override val defaultNoEventTimeoutMs: Long = DEFAULT_NO_EVENT_TIMEOUT
|
||||
) : Expectable<E> {
|
||||
override val history = ArrayTrackRecord<E>().newReadHead()
|
||||
val mark get() = history.mark
|
||||
|
||||
/**
|
||||
* Implementation of the expect<> family of methods. All other
|
||||
* methods eventually call this. They implement the Expectable<E>
|
||||
* interface.
|
||||
*/
|
||||
override fun <T : E> expect(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long,
|
||||
errorMsg: String?,
|
||||
predicate: (T) -> Boolean
|
||||
): T {
|
||||
val event = history.poll(timeoutMs)
|
||||
if (null == event) {
|
||||
failWithErrorReason(
|
||||
errorMsg,
|
||||
"Did not receive ${type.simpleName} after ${timeoutMs}ms"
|
||||
)
|
||||
}
|
||||
if (!type.isInstance(event)) {
|
||||
failWithErrorReason(
|
||||
errorMsg,
|
||||
"Expected callback ${type.simpleName}, got $event"
|
||||
)
|
||||
}
|
||||
event as T
|
||||
if (!predicate(event)) {
|
||||
failWithErrorReason(errorMsg, "Callback doesn't match predicate : $event")
|
||||
}
|
||||
return event
|
||||
}
|
||||
|
||||
override fun <T : E> eventuallyExpect(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long,
|
||||
errorMsg: String?,
|
||||
predicate: (T) -> Boolean,
|
||||
): T {
|
||||
val event = history.poll(timeoutMs) { type.isInstance(it) && predicate(it as T) }
|
||||
if (null == event) {
|
||||
failWithErrorReason(
|
||||
errorMsg,
|
||||
"Callback ${type.simpleName} not received within ${timeoutMs}ms. " +
|
||||
"Got \n${history.prettyPrintBacktrace(before = 4, after = 4)}"
|
||||
)
|
||||
}
|
||||
return event as T
|
||||
}
|
||||
|
||||
override fun assertNoCallback(
|
||||
timeoutMs: Long,
|
||||
errorMsg: String?,
|
||||
predicate: (E) -> Boolean,
|
||||
) {
|
||||
val mark = history.mark
|
||||
try {
|
||||
val event = history.poll(timeoutMs) { predicate(it) }
|
||||
if (null != event) {
|
||||
failWithErrorReason(
|
||||
errorMsg,
|
||||
"Expected no such callback but found $event"
|
||||
)
|
||||
}
|
||||
} finally {
|
||||
// Rewind so callers can expect a failure and continue later. For example, a caller
|
||||
// might want to assert no callback { interfaceName == "wlan1" } but then go on
|
||||
// to test that some other event took place, which would not be possible without this
|
||||
// rewind because it would have been skipped by the `poll` call above.
|
||||
history.rewind(mark)
|
||||
}
|
||||
}
|
||||
|
||||
override fun <T : E> assertNo(
|
||||
type: KClass<T>,
|
||||
timeoutMs: Long,
|
||||
errorMsg: String?,
|
||||
predicate: (T) -> Boolean,
|
||||
) = assertNoCallback(timeoutMs, errorMsg) { type.isInstance(it) && predicate(it as T) }
|
||||
|
||||
/**
|
||||
* Proxy methods to avoid having to write expect<_, T>, see comment at the top of this file.
|
||||
*/
|
||||
inline fun <reified T : E> expect(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = expect<_, T>(timeoutMs, errorMsg, predicate)
|
||||
|
||||
inline fun <reified T : E> eventuallyExpect(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = eventuallyExpect<_, T>(timeoutMs, errorMsg, predicate)
|
||||
|
||||
inline fun <reified T : E> assertNo(
|
||||
timeoutMs: Long = defaultTimeoutMs,
|
||||
errorMsg: String? = null,
|
||||
noinline predicate: (T) -> Boolean = { true }
|
||||
) = assertNo<_, T>(timeoutMs, errorMsg, predicate)
|
||||
}
|
||||
|
|
@ -345,6 +345,45 @@ class ArrayTrackRecord<E> : TrackRecord<E> {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a pretty-printed list of events.
|
||||
* @param before how many events before the last poll() operation to return
|
||||
* @param after how many events after the mark to return
|
||||
* @param width how many columns wide the string can be
|
||||
* @return a string to embed in an error message.
|
||||
*/
|
||||
fun prettyPrintBacktrace(before: Int = 0, after: Int = 0, width: Int = 300): String {
|
||||
val sb = StringBuilder()
|
||||
val stamp = slock.tryReadLock()
|
||||
if (0L == stamp) concurrentAccessDetected()
|
||||
val from = pollMark
|
||||
val to = mark
|
||||
val start = (from - before).coerceAtLeast(0)
|
||||
val end = (to + after).coerceAtMost(size - 1)
|
||||
|
||||
try {
|
||||
lock.withLock {
|
||||
for (i in start..end) {
|
||||
when (i) {
|
||||
from -> sb.append("< ")
|
||||
to -> sb.append("> ")
|
||||
else -> sb.append(" ")
|
||||
}
|
||||
sb.append(get(i).toString().safeSubstring(0..width))
|
||||
sb.append("\n")
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
slock.unlockRead(stamp)
|
||||
}
|
||||
if (from == size) {
|
||||
sb.append("<>\n")
|
||||
} else if (to == size) {
|
||||
sb.append("> \n")
|
||||
}
|
||||
return sb.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the first element after the mark or null. This never blocks.
|
||||
*
|
||||
|
|
@ -356,5 +395,7 @@ class ArrayTrackRecord<E> : TrackRecord<E> {
|
|||
}
|
||||
}
|
||||
|
||||
// Private helper
|
||||
// Private helpers
|
||||
private fun Condition.await(timeoutMs: Long) = this.await(timeoutMs, TimeUnit.MILLISECONDS)
|
||||
private fun String.safeSubstring(range: IntRange) =
|
||||
substring(range.start..range.endInclusive.coerceAtMost(length - 1))
|
||||
|
|
|
|||
|
|
@ -198,7 +198,7 @@ public class VpnTest {
|
|||
private static final String PRIVATE_DNS_MODE_PROVIDER_HOSTNAME = "hostname";
|
||||
private static final String PRIVATE_DNS_MODE_OPPORTUNISTIC = "opportunistic";
|
||||
private static final String PRIVATE_DNS_SPECIFIER_SETTING = "private_dns_specifier";
|
||||
private static final int NETWORK_CALLBACK_TIMEOUT_MS = 30_000;
|
||||
private static final long NETWORK_CALLBACK_TIMEOUT_MS = 30_000;
|
||||
|
||||
private static final LinkAddress TEST_IP4_DST_ADDR = new LinkAddress("198.51.100.1/24");
|
||||
private static final LinkAddress TEST_IP4_SRC_ADDR = new LinkAddress("198.51.100.2/24");
|
||||
|
|
@ -1945,18 +1945,18 @@ public class VpnTest {
|
|||
|
||||
expectVpnNetwork(defaultNetworkCallback);
|
||||
}, /* cleanup */ () -> {
|
||||
stopVpn();
|
||||
defaultNetworkCallback.eventuallyExpect(Event.LOST);
|
||||
}, /* cleanup */ () -> {
|
||||
runWithShellPermissionIdentity(() -> {
|
||||
mCM.setVpnDefaultForUids(session, new ArraySet<>());
|
||||
}, NETWORK_SETTINGS);
|
||||
// The default network of the app will be changed back to wifi when the VPN network
|
||||
// preference feature is disabled.
|
||||
defaultNetworkCallback.eventuallyExpect(Event.AVAILABLE,
|
||||
NETWORK_CALLBACK_TIMEOUT_MS,
|
||||
entry -> defaultNetwork.equals(entry.getNetwork()));
|
||||
});
|
||||
stopVpn();
|
||||
defaultNetworkCallback.eventuallyExpect(Event.LOST);
|
||||
}, /* cleanup */ () -> {
|
||||
runWithShellPermissionIdentity(() -> {
|
||||
mCM.setVpnDefaultForUids(session, new ArraySet<>());
|
||||
}, NETWORK_SETTINGS);
|
||||
// The default network of the app will be changed back to wifi when the VPN network
|
||||
// preference feature is disabled.
|
||||
defaultNetworkCallback.eventuallyExpect(Event.AVAILABLE,
|
||||
NETWORK_CALLBACK_TIMEOUT_MS,
|
||||
entry -> defaultNetwork.equals(entry.getNetwork()));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -318,7 +318,7 @@ public class ConnectivityManagerTest {
|
|||
private static final int MAX_KEEPALIVE_RETRY_COUNT = 3;
|
||||
private static final int MIN_KEEPALIVE_INTERVAL = 10;
|
||||
|
||||
private static final int NETWORK_CALLBACK_TIMEOUT_MS = 30_000;
|
||||
private static final long NETWORK_CALLBACK_TIMEOUT_MS = 30_000;
|
||||
// Timeout for waiting network to be validated.
|
||||
private static final int LISTEN_ACTIVITY_TIMEOUT_MS = 30_000;
|
||||
private static final int NO_CALLBACK_TIMEOUT_MS = 100;
|
||||
|
|
@ -481,11 +481,9 @@ public class ConnectivityManagerTest {
|
|||
// networkCallbackRule is the outer rule and will be cleaned up after this method.
|
||||
final TestableNetworkCallback callback =
|
||||
networkCallbackRule.registerDefaultNetworkCallback();
|
||||
assertNotNull("Couldn't restore Internet connectivity",
|
||||
callback.eventuallyExpect(Event.NETWORK_CAPS_UPDATED,
|
||||
NETWORK_CALLBACK_TIMEOUT_MS,
|
||||
entry -> ((Event.CapabilitiesChanged) entry)
|
||||
.getCaps().hasCapability(NET_CAPABILITY_VALIDATED)));
|
||||
callback.eventuallyExpect(Event.NETWORK_CAPS_UPDATED,
|
||||
NETWORK_CALLBACK_TIMEOUT_MS,
|
||||
entry -> entry.getCaps().hasCapability(NET_CAPABILITY_VALIDATED));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ import com.android.testutils.TestableNetworkCallback
|
|||
import com.android.testutils.TestableNetworkCallback.Event.Lost
|
||||
import com.android.testutils.TestableNetworkCallback.Event.Reserved
|
||||
import com.android.testutils.TestableNetworkCallback.Event.Unavailable
|
||||
import com.android.testutils.anyNetwork
|
||||
import com.android.testutils.AnyNetwork
|
||||
import com.android.testutils.waitForIdle
|
||||
import java.io.IOException
|
||||
import java.util.Optional
|
||||
|
|
@ -306,7 +306,7 @@ class CSL2capProviderTest : CSTest() {
|
|||
doReturn(true).`when`(btSocket).isConnected()
|
||||
acceptQueue.put(Optional.of(btSocket))
|
||||
|
||||
cb.expectAvailableCallbacks(anyNetwork(), validated = false)
|
||||
cb.expectAvailableCallbacks(AnyNetwork(), validated = false)
|
||||
cb.assertNoCallback()
|
||||
// Verify that packet forwarding was started.
|
||||
// TODO: stop mocking L2capPacketForwarder.
|
||||
|
|
@ -355,7 +355,7 @@ class CSL2capProviderTest : CSTest() {
|
|||
.build()
|
||||
val nr = REQUEST.copyWithSpecifier(specifier)
|
||||
val cb = requestNetwork(nr)
|
||||
cb.expectAvailableCallbacks(anyNetwork(), validated = false)
|
||||
cb.expectAvailableCallbacks(AnyNetwork(), validated = false)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -368,7 +368,7 @@ class CSL2capProviderTest : CSTest() {
|
|||
.build()
|
||||
var nr = REQUEST.copyWithSpecifier(specifier)
|
||||
val cb = requestNetwork(nr)
|
||||
cb.expectAvailableCallbacks(anyNetwork(), validated = false)
|
||||
cb.expectAvailableCallbacks(AnyNetwork(), validated = false)
|
||||
|
||||
specifier = L2capNetworkSpecifier.Builder()
|
||||
.setRole(ROLE_CLIENT)
|
||||
|
|
@ -391,10 +391,10 @@ class CSL2capProviderTest : CSTest() {
|
|||
.build()
|
||||
val nr = REQUEST.copyWithSpecifier(specifier)
|
||||
val cb = requestNetwork(nr)
|
||||
cb.expectAvailableCallbacks(anyNetwork(), validated = false)
|
||||
cb.expectAvailableCallbacks(AnyNetwork(), validated = false)
|
||||
|
||||
val cb2 = requestNetwork(nr)
|
||||
cb2.expectAvailableCallbacks(anyNetwork(), validated = false)
|
||||
cb2.expectAvailableCallbacks(AnyNetwork(), validated = false)
|
||||
}
|
||||
|
||||
/** Test to ensure onLost() is sent before onUnavailable() when the network is torn down. */
|
||||
|
|
@ -409,7 +409,7 @@ class CSL2capProviderTest : CSTest() {
|
|||
|
||||
val nr = REQUEST.copyWithSpecifier(specifier)
|
||||
val cb = requestNetwork(nr)
|
||||
cb.expectAvailableCallbacks(anyNetwork(), validated = false)
|
||||
cb.expectAvailableCallbacks(AnyNetwork(), validated = false)
|
||||
|
||||
// Capture the L2capPacketForwarder callback object to tear down the network.
|
||||
val handlerCaptor = ArgumentCaptor.forClass(Handler::class.java)
|
||||
|
|
|
|||
Loading…
Reference in a new issue