1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.testutils
18 
19 import android.net.ConnectivityManager.NetworkCallback
20 import android.net.LinkProperties
21 import android.net.LocalNetworkInfo
22 import android.net.Network
23 import android.net.NetworkCapabilities
24 import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
25 import android.util.Log
26 import com.android.net.module.util.ArrayTrackRecord
27 import com.android.testutils.RecorderCallback.CallbackEntry.Available
28 import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus
29 import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatusInt
30 import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged
31 import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged
32 import com.android.testutils.RecorderCallback.CallbackEntry.LocalInfoChanged
33 import com.android.testutils.RecorderCallback.CallbackEntry.Losing
34 import com.android.testutils.RecorderCallback.CallbackEntry.Lost
35 import com.android.testutils.RecorderCallback.CallbackEntry.Resumed
36 import com.android.testutils.RecorderCallback.CallbackEntry.Suspended
37 import com.android.testutils.RecorderCallback.CallbackEntry.Unavailable
38 import kotlin.reflect.KClass
39 import kotlin.test.assertEquals
40 import kotlin.test.assertNotNull
41 import kotlin.test.fail
42 
43 object NULL_NETWORK : Network(-1)
44 object ANY_NETWORK : Network(-2)
anyNetworknull45 fun anyNetwork() = ANY_NETWORK
46 
47 open class RecorderCallback private constructor(
48     private val backingRecord: ArrayTrackRecord<CallbackEntry>
49 ) : NetworkCallback() {
50     public constructor() : this(ArrayTrackRecord())
51     protected constructor(src: RecorderCallback?) : this(src?.backingRecord ?: ArrayTrackRecord())
52 
53     private val TAG = this::class.simpleName
54 
55     sealed class CallbackEntry {
56         // To get equals(), hashcode(), componentN() etc for free, the child classes of
57         // this class are data classes. But while data classes can inherit from other classes,
58         // they may only have visible members in the constructors, so they couldn't declare
59         // a constructor with a non-val arg to pass to CallbackEntry. Instead, force all
60         // subclasses to implement a `network' property, which can be done in a data class
61         // constructor by specifying override.
62         abstract val network: Network
63 
64         data class Available(override val network: Network) : CallbackEntry()
65         data class CapabilitiesChanged(
66             override val network: Network,
67             val caps: NetworkCapabilities
68         ) : CallbackEntry()
69         data class LinkPropertiesChanged(
70             override val network: Network,
71             val lp: LinkProperties
72         ) : CallbackEntry()
73         data class LocalInfoChanged(
74             override val network: Network,
75             val info: LocalNetworkInfo
76         ) : CallbackEntry()
77         data class Suspended(override val network: Network) : CallbackEntry()
78         data class Resumed(override val network: Network) : CallbackEntry()
79         data class Losing(override val network: Network, val maxMsToLive: Int) : CallbackEntry()
80         data class Lost(override val network: Network) : CallbackEntry()
81         data class Unavailable private constructor(
82             override val network: Network
83         ) : CallbackEntry() {
84             constructor() : this(NULL_NETWORK)
85         }
86         data class BlockedStatus(
87             override val network: Network,
88             val blocked: Boolean
89         ) : CallbackEntry()
90         data class BlockedStatusInt(
91             override val network: Network,
92             val reason: Int
93         ) : CallbackEntry()
94 
95         // Convenience constants for expecting a type
96         companion object {
97             @JvmField
98             val AVAILABLE = Available::class
99             @JvmField
100             val NETWORK_CAPS_UPDATED = CapabilitiesChanged::class
101             @JvmField
102             val LINK_PROPERTIES_CHANGED = LinkPropertiesChanged::class
103             @JvmField
104             val LOCAL_INFO_CHANGED = LocalInfoChanged::class
105             @JvmField
106             val SUSPENDED = Suspended::class
107             @JvmField
108             val RESUMED = Resumed::class
109             @JvmField
110             val LOSING = Losing::class
111             @JvmField
112             val LOST = Lost::class
113             @JvmField
114             val UNAVAILABLE = Unavailable::class
115             @JvmField
116             val BLOCKED_STATUS = BlockedStatus::class
117             @JvmField
118             val BLOCKED_STATUS_INT = BlockedStatusInt::class
119         }
120     }
121 
122     val history = backingRecord.newReadHead()
123     val mark get() = history.mark
124 
125     override fun onAvailable(network: Network) {
126         Log.d(TAG, "onAvailable $network")
127         history.add(Available(network))
128     }
129 
130     // PreCheck is not used in the tests today. For backward compatibility with existing tests that
131     // expect the callbacks not to record this, do not listen to PreCheck here.
132 
133     override fun onCapabilitiesChanged(network: Network, caps: NetworkCapabilities) {
134         Log.d(TAG, "onCapabilitiesChanged $network $caps")
135         history.add(CapabilitiesChanged(network, caps))
136     }
137 
138     override fun onLinkPropertiesChanged(network: Network, lp: LinkProperties) {
139         Log.d(TAG, "onLinkPropertiesChanged $network $lp")
140         history.add(LinkPropertiesChanged(network, lp))
141     }
142 
143     override fun onLocalNetworkInfoChanged(network: Network, info: LocalNetworkInfo) {
144         Log.d(TAG, "onLocalNetworkInfoChanged $network $info")
145         history.add(LocalInfoChanged(network, info))
146     }
147 
148     override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
149         Log.d(TAG, "onBlockedStatusChanged $network $blocked")
150         history.add(BlockedStatus(network, blocked))
151     }
152 
153     // Cannot do:
154     // fun onBlockedStatusChanged(network: Network, blocked: Int) {
155     // because on S, that needs to be "override fun", and on R, that cannot be "override fun".
156     override fun onNetworkSuspended(network: Network) {
157         Log.d(TAG, "onNetworkSuspended $network $network")
158         history.add(Suspended(network))
159     }
160 
161     override fun onNetworkResumed(network: Network) {
162         Log.d(TAG, "$network onNetworkResumed $network")
163         history.add(Resumed(network))
164     }
165 
166     override fun onLosing(network: Network, maxMsToLive: Int) {
167         Log.d(TAG, "onLosing $network $maxMsToLive")
168         history.add(Losing(network, maxMsToLive))
169     }
170 
171     override fun onLost(network: Network) {
172         Log.d(TAG, "onLost $network")
173         history.add(Lost(network))
174     }
175 
176     override fun onUnavailable() {
177         Log.d(TAG, "onUnavailable")
178         history.add(Unavailable())
179     }
180 }
181 
182 private const val DEFAULT_TIMEOUT = 30_000L // ms
183 private const val DEFAULT_NO_CALLBACK_TIMEOUT = 200L // ms
<lambda>null184 private val NOOP = Runnable {}
185 
186 /**
187  * See comments on the public constructor below for a description of the arguments.
188  */
189 open class TestableNetworkCallback private constructor(
190     src: TestableNetworkCallback?,
191     val defaultTimeoutMs: Long = DEFAULT_TIMEOUT,
192     val defaultNoCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT,
193     val waiterFunc: Runnable = NOOP // "() -> Unit" would forbid calling with a void func from Java
194 ) : RecorderCallback(src) {
195     /**
196      * Construct a testable network callback.
197      * @param timeoutMs the default timeout for expecting a callback. Default 30 seconds. This
198      *                  should be long in most cases, because the success case doesn't incur
199      *                  the wait.
200      * @param noCallbackTimeoutMs the timeout for expecting that no callback is received. Default
201      *                            200ms. Because the success case does incur the timeout, this
202      *                            should be short in most cases, but not so short as to frequently
203      *                            time out before an incorrect callback is received.
204      * @param waiterFunc a function to use before asserting no callback. For some specific tests,
205      *                   it is useful to run test-specific code before asserting no callback to
206      *                   increase the likelihood that a spurious callback is correctly detected.
207      *                   As an example, a unit test using mock loopers may want to use this to
208      *                   make sure the loopers are drained before asserting no callback, since
209      *                   one of them may cause a callback to be called. @see ConnectivityServiceTest
210      *                   for such an example.
211      */
212     @JvmOverloads
213     constructor(
214         timeoutMs: Long = DEFAULT_TIMEOUT,
215         noCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT,
216         waiterFunc: Runnable = NOOP
217     ) : this(null, timeoutMs, noCallbackTimeoutMs, waiterFunc)
218 
createLinkedCopynull219     fun createLinkedCopy() = TestableNetworkCallback(
220         this,
221         defaultTimeoutMs,
222         defaultNoCallbackTimeoutMs,
223         waiterFunc
224     )
225 
226     // The last available network, or null if any network was lost since the last call to
227     // onAvailable. TODO : fix this by fixing the tests that rely on this behavior
228     val lastAvailableNetwork: Network?
229         get() = when (val it = history.lastOrNull { it is Available || it is Lost }) {
230             is Available -> it.network
231             else -> null
232         }
233 
234     /**
235      * Get the next callback or null if timeout.
236      *
237      * With no argument, this method waits out the default timeout. To wait forever, pass
238      * Long.MAX_VALUE.
239      */
240     @JvmOverloads
<lambda>null241     fun poll(timeoutMs: Long = defaultTimeoutMs, predicate: (CallbackEntry) -> Boolean = { true }) =
242             history.poll(timeoutMs, predicate)
243 
244     /*****
245      * expect family of methods.
246      * These methods fetch the next callback and assert it matches the conditions : type,
247      * passed predicate. If no callback is received within the timeout, these methods fail.
248      */
249     @JvmOverloads
expectnull250     fun <T : CallbackEntry> expect(
251         type: KClass<T>,
252         network: Network = ANY_NETWORK,
253         timeoutMs: Long = defaultTimeoutMs,
254         errorMsg: String? = null,
255         test: (T) -> Boolean = { true }
<lambda>null256     ) = expect<CallbackEntry>(network, timeoutMs, errorMsg) {
257         if (type.isInstance(it)) {
258             test(it as T) // Cast can't fail since type.isInstance(it) and type: KClass<T>
259         } else {
260             fail("Expected callback ${type.simpleName}, got $it")
261         }
262     } as T
263 
264     @JvmOverloads
expectnull265     fun <T : CallbackEntry> expect(
266         type: KClass<T>,
267         network: HasNetwork,
268         timeoutMs: Long = defaultTimeoutMs,
269         errorMsg: String? = null,
270         test: (T) -> Boolean = { true }
271     ) = expect(type, network.network, timeoutMs, errorMsg, test)
272 
273     // Java needs an explicit overload to let it omit arguments in the middle, so define these
274     // here. Note that @JvmOverloads give us the versions without the last arguments too, so
275     // there is no need to explicitly define versions without the test predicate.
276     // Without |network|
277     @JvmOverloads
expectnull278     fun <T : CallbackEntry> expect(
279         type: KClass<T>,
280         timeoutMs: Long,
281         errorMsg: String?,
282         test: (T) -> Boolean = { true }
283     ) = expect(type, ANY_NETWORK, timeoutMs, errorMsg, test)
284 
285     // Without |timeout|, in Network and HasNetwork versions
286     @JvmOverloads
expectnull287     fun <T : CallbackEntry> expect(
288         type: KClass<T>,
289         network: Network,
290         errorMsg: String?,
291         test: (T) -> Boolean = { true }
292     ) = expect(type, network, defaultTimeoutMs, errorMsg, test)
293 
294     @JvmOverloads
expectnull295     fun <T : CallbackEntry> expect(
296         type: KClass<T>,
297         network: HasNetwork,
298         errorMsg: String?,
299         test: (T) -> Boolean = { true }
300     ) = expect(type, network.network, defaultTimeoutMs, errorMsg, test)
301 
302     // Without |errorMsg|, in Network and HasNetwork versions
303     @JvmOverloads
expectnull304     fun <T : CallbackEntry> expect(
305         type: KClass<T>,
306         network: Network,
307         timeoutMs: Long,
308         test: (T) -> Boolean
309     ) = expect(type, network, timeoutMs, null, test)
310 
311     @JvmOverloads
312     fun <T : CallbackEntry> expect(
313         type: KClass<T>,
314         network: HasNetwork,
315         timeoutMs: Long,
316         test: (T) -> Boolean
317     ) = expect(type, network.network, timeoutMs, null, test)
318 
319     // Without |network| or |timeout|
320     @JvmOverloads
321     fun <T : CallbackEntry> expect(
322         type: KClass<T>,
323         errorMsg: String?,
324         test: (T) -> Boolean = { true }
325     ) = expect(type, ANY_NETWORK, defaultTimeoutMs, errorMsg, test)
326 
327     // Without |network| or |errorMsg|
328     @JvmOverloads
expectnull329     fun <T : CallbackEntry> expect(
330         type: KClass<T>,
331         timeoutMs: Long,
332         test: (T) -> Boolean = { true }
333     ) = expect(type, ANY_NETWORK, timeoutMs, null, test)
334 
335     // Without |timeout| or |errorMsg|, in Network and HasNetwork versions
336     @JvmOverloads
expectnull337     fun <T : CallbackEntry> expect(
338         type: KClass<T>,
339         network: Network,
340         test: (T) -> Boolean
341     ) = expect(type, network, defaultTimeoutMs, null, test)
342 
343     @JvmOverloads
344     fun <T : CallbackEntry> expect(
345         type: KClass<T>,
346         network: HasNetwork,
347         test: (T) -> Boolean
348     ) = expect(type, network.network, defaultTimeoutMs, null, test)
349 
350     // Without |network| or |timeout| or |errorMsg|
351     @JvmOverloads
352     fun <T : CallbackEntry> expect(
353         type: KClass<T>,
354         test: (T) -> Boolean
355     ) = expect(type, ANY_NETWORK, defaultTimeoutMs, null, test)
356 
357     // Kotlin reified versions. Don't call methods above, or the predicate would need to be noinline
358     inline fun <reified T : CallbackEntry> expect(
359         network: Network = ANY_NETWORK,
360         timeoutMs: Long = defaultTimeoutMs,
361         errorMsg: String? = null,
362         test: (T) -> Boolean = { true }
363     ) = (poll(timeoutMs) ?: failWithErrorReason(errorMsg,
364         "Did not receive ${T::class.simpleName} after ${timeoutMs}ms"))
<lambda>null365             .also {
366                 if (it !is T) {
367                     failWithErrorReason(
368                         errorMsg,
369                         "Expected callback ${T::class.simpleName}, got $it"
370                     )
371                 }
372                 if (ANY_NETWORK !== network && it.network != network) {
373                     failWithErrorReason(errorMsg, "Expected network $network for callback : $it")
374                 }
375                 if (!test(it)) {
376                     failWithErrorReason(errorMsg, "Callback doesn't match predicate : $it")
377                 }
378             } as T
379 
380     // "Nothing" is the return type to declare a function never returns a value.
failWithErrorReasonnull381     fun failWithErrorReason(errorMsg: String?, errorReason: String): Nothing {
382         val message = if (errorMsg != null) "$errorMsg : $errorReason" else errorReason
383         fail(message)
384     }
385 
expectnull386     inline fun <reified T : CallbackEntry> expect(
387         network: HasNetwork,
388         timeoutMs: Long = defaultTimeoutMs,
389         errorMsg: String? = null,
390         test: (T) -> Boolean = { true }
391     ) = expect(network.network, timeoutMs, errorMsg, test)
392 
393     /*****
394      * assertNoCallback family of methods.
395      * These methods make sure that no callback that matches the predicate was received.
396      * If no predicate is given, they make sure that no callback at all was received.
397      * These methods run the waiter func given in the constructor if any.
398      */
399     @JvmOverloads
assertNoCallbacknull400     fun assertNoCallback(
401         timeoutMs: Long = defaultNoCallbackTimeoutMs,
402         valid: (CallbackEntry) -> Boolean = { true }
403     ) {
404         waiterFunc.run()
<lambda>null405         history.poll(timeoutMs) { valid(it) }?.let { fail("Expected no callback but got $it") }
406     }
407 
assertNoCallbacknull408     fun assertNoCallback(valid: (CallbackEntry) -> Boolean) =
409             assertNoCallback(defaultNoCallbackTimeoutMs, valid)
410 
411     /*****
412      * eventuallyExpect family of methods.
413      * These methods make sure a callback that matches the type/predicate is received eventually.
414      * Any callback of the wrong type, or doesn't match the optional predicate, is ignored.
415      * They fail if no callback matching the predicate is received within the timeout.
416      */
417     inline fun <reified T : CallbackEntry> eventuallyExpect(
418         timeoutMs: Long = defaultTimeoutMs,
419         from: Int = mark,
420         crossinline predicate: (T) -> Boolean = { true }
<lambda>null421     ): T = history.poll(timeoutMs, from) { it is T && predicate(it) }.also {
422         assertNotNull(
423             it,
424             "Callback ${T::class} not received within ${timeoutMs}ms. " +
425                 "Got ${history.backtrace()}"
426         )
427     } as T
428 
429     @JvmOverloads
eventuallyExpectnull430     fun <T : CallbackEntry> eventuallyExpect(
431         type: KClass<T>,
432         timeoutMs: Long = defaultTimeoutMs,
433         predicate: (cb: T) -> Boolean = { true }
<lambda>null434     ) = history.poll(timeoutMs) { type.java.isInstance(it) && predicate(it as T) }.also {
435         assertNotNull(
436             it,
437             "Callback ${type.java} not received within ${timeoutMs}ms. " +
438                 "Got ${history.backtrace()}"
439         )
440     } as T
441 
eventuallyExpectnull442     fun <T : CallbackEntry> eventuallyExpect(
443         type: KClass<T>,
444         timeoutMs: Long = defaultTimeoutMs,
445         from: Int = mark,
446         predicate: (cb: T) -> Boolean = { true }
<lambda>null447     ) = history.poll(timeoutMs, from) { type.java.isInstance(it) && predicate(it as T) }.also {
448         assertNotNull(
449             it,
450             "Callback ${type.java} not received within ${timeoutMs}ms. " +
451                 "Got ${history.backtrace()}"
452         )
453     } as T
454 
455     // Expects onAvailable and the callbacks that follow it. These are:
456     // - onSuspended, iff the network was suspended when the callbacks fire.
457     // - onCapabilitiesChanged.
458     // - onLinkPropertiesChanged.
459     // - onBlockedStatusChanged.
460     //
461     // @param network the network to expect the callbacks on.
462     // @param suspended whether to expect a SUSPENDED callback.
463     // @param validated the expected value of the VALIDATED capability in the
464     //        onCapabilitiesChanged callback.
465     // @param tmt how long to wait for the callbacks.
466     @JvmOverloads
expectAvailableCallbacksnull467     fun expectAvailableCallbacks(
468         net: Network,
469         suspended: Boolean = false,
470         validated: Boolean? = true,
471         blocked: Boolean = false,
472         upstream: Network? = null,
473         tmt: Long = defaultTimeoutMs
474     ) {
475         expectAvailableCallbacksCommon(net, suspended, validated, upstream, tmt)
476         expect<BlockedStatus>(net, tmt) { it.blocked == blocked }
477     }
478 
479     // For backward compatibility, add a method that allows callers to specify a timeout but
480     // no upstream.
expectAvailableCallbacksnull481     fun expectAvailableCallbacks(
482         net: Network,
483         suspended: Boolean = false,
484         validated: Boolean? = true,
485         blocked: Boolean = false,
486         tmt: Long = defaultTimeoutMs
487     ) = expectAvailableCallbacks(net, suspended, validated, blocked, upstream = null, tmt = tmt)
488 
489     fun expectAvailableCallbacks(
490         net: Network,
491         suspended: Boolean,
492         validated: Boolean,
493         blockedReason: Int,
494         upstream: Network? = null,
495         tmt: Long
496     ) {
497         expectAvailableCallbacksCommon(net, suspended, validated, upstream, tmt)
498         expect<BlockedStatusInt>(net) { it.reason == blockedReason }
499     }
500 
501     // For backward compatibility, add a method that allows callers to specify a timeout but
502     // no upstream.
expectAvailableCallbacksnull503     fun expectAvailableCallbacks(
504             net: Network,
505             suspended: Boolean = false,
506             validated: Boolean = true,
507             blockedReason: Int,
508             tmt: Long = defaultTimeoutMs
509     ) = expectAvailableCallbacks(net, suspended, validated, blockedReason, upstream = null, tmt)
510 
511     private fun expectAvailableCallbacksCommon(
512         net: Network,
513         suspended: Boolean,
514         validated: Boolean?,
515         upstream: Network?,
516         tmt: Long
517     ) {
518         expect<Available>(net, tmt)
519         if (suspended) {
520             expect<Suspended>(net, tmt)
521         }
522         val caps = expect<CapabilitiesChanged>(net, tmt) {
523             validated == null || validated == it.caps.hasCapability(NET_CAPABILITY_VALIDATED)
524         }.caps
525         expect<LinkPropertiesChanged>(net, tmt)
526         if (caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK)) {
527             expect<LocalInfoChanged>(net, tmt) { it.info.upstreamNetwork == upstream }
528         }
529     }
530 
531     // Backward compatibility for existing Java code. Use named arguments instead and remove all
532     // these when there is no user left.
expectAvailableAndSuspendedCallbacksnull533     fun expectAvailableAndSuspendedCallbacks(
534         net: Network,
535         validated: Boolean,
536         tmt: Long = defaultTimeoutMs
537     ) = expectAvailableCallbacks(net, suspended = true, validated = validated, tmt = tmt)
538 
539     // Expects the available callbacks (where the onCapabilitiesChanged must contain the
540     // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the
541     // one we just sent.
542     // TODO: this is likely a bug. Fix it and remove this method.
543     fun expectAvailableDoubleValidatedCallbacks(net: Network, tmt: Long = defaultTimeoutMs) {
544         val mark = history.mark
545         expectAvailableCallbacks(net, tmt = tmt)
546         val firstCaps = history.poll(tmt, mark) { it is CapabilitiesChanged }
547         assertEquals(firstCaps, expect<CapabilitiesChanged>(net, tmt))
548     }
549 
550     // Expects the available callbacks where the onCapabilitiesChanged must not have validated,
551     // then expects another onCapabilitiesChanged that has the validated bit set. This is used
552     // when a network connects and satisfies a callback, and then immediately validates.
expectAvailableThenValidatedCallbacksnull553     fun expectAvailableThenValidatedCallbacks(net: Network, tmt: Long = defaultTimeoutMs) {
554         expectAvailableCallbacks(net, validated = false, tmt = tmt)
555         expectCaps(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) }
556     }
557 
expectAvailableThenValidatedCallbacksnull558     fun expectAvailableThenValidatedCallbacks(
559         net: Network,
560         blockedReason: Int,
561         tmt: Long = defaultTimeoutMs
562     ) {
563         expectAvailableCallbacks(
564             net,
565             validated = false,
566             suspended = false,
567             blockedReason = blockedReason,
568             tmt = tmt
569         )
570         expectCaps(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) }
571     }
572 
573     // Temporary Java compat measure : have MockNetworkAgent implement this so that all existing
574     // calls with networkAgent can be routed through here without moving MockNetworkAgent.
575     // TODO: clean this up, remove this method.
576     interface HasNetwork {
577         val network: Network
578     }
579 
580     @JvmOverloads
expectAvailableCallbacksnull581     fun expectAvailableCallbacks(
582         n: HasNetwork,
583         suspended: Boolean,
584         validated: Boolean,
585         blocked: Boolean,
586         upstream: Network? = null,
587         timeoutMs: Long
588     ) = expectAvailableCallbacks(n.network, suspended, validated, blocked, upstream, timeoutMs)
589 
590     fun expectAvailableAndSuspendedCallbacks(n: HasNetwork, expectValidated: Boolean) {
591         expectAvailableAndSuspendedCallbacks(n.network, expectValidated)
592     }
593 
expectAvailableCallbacksValidatednull594     fun expectAvailableCallbacksValidated(n: HasNetwork) {
595         expectAvailableCallbacks(n.network)
596     }
597 
expectAvailableCallbacksValidatedAndBlockednull598     fun expectAvailableCallbacksValidatedAndBlocked(n: HasNetwork) {
599         expectAvailableCallbacks(n.network, blocked = true)
600     }
601 
expectAvailableCallbacksUnvalidatednull602     fun expectAvailableCallbacksUnvalidated(n: HasNetwork) {
603         expectAvailableCallbacks(n.network, validated = false)
604     }
605 
expectAvailableCallbacksUnvalidatedAndBlockednull606     fun expectAvailableCallbacksUnvalidatedAndBlocked(n: HasNetwork) {
607         expectAvailableCallbacks(n.network, validated = false, blocked = true)
608     }
609 
expectAvailableDoubleValidatedCallbacksnull610     fun expectAvailableDoubleValidatedCallbacks(n: HasNetwork) {
611         expectAvailableDoubleValidatedCallbacks(n.network, defaultTimeoutMs)
612     }
613 
expectAvailableThenValidatedCallbacksnull614     fun expectAvailableThenValidatedCallbacks(n: HasNetwork) {
615         expectAvailableThenValidatedCallbacks(n.network, defaultTimeoutMs)
616     }
617 
618     @JvmOverloads
expectCapsnull619     fun expectCaps(
620         n: HasNetwork,
621         tmt: Long = defaultTimeoutMs,
622         valid: (NetworkCapabilities) -> Boolean = { true }
<lambda>null623     ) = expect<CapabilitiesChanged>(n.network, tmt) { valid(it.caps) }.caps
624 
625     @JvmOverloads
expectCapsnull626     fun expectCaps(
627         n: Network,
628         tmt: Long = defaultTimeoutMs,
629         valid: (NetworkCapabilities) -> Boolean
630     ) = expect<CapabilitiesChanged>(n, tmt) { valid(it.caps) }.caps
631 
expectCapsnull632     fun expectCaps(
633         n: HasNetwork,
634         valid: (NetworkCapabilities) -> Boolean
635     ) = expect<CapabilitiesChanged>(n.network) { valid(it.caps) }.caps
636 
expectCapsnull637     fun expectCaps(
638         tmt: Long,
639         valid: (NetworkCapabilities) -> Boolean
640     ) = expect<CapabilitiesChanged>(ANY_NETWORK, tmt) { valid(it.caps) }.caps
641 }
642