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 private val DEFAULT_TAG = RecorderCallback::class.simpleName
48     ?: fail("Could not determine class name")
49 
50 open class RecorderCallback private constructor(
51     private val backingRecord: ArrayTrackRecord<CallbackEntry>,
52     val logTag: String
53 ) : NetworkCallback() {
54     public constructor(logTag: String = DEFAULT_TAG) : this(ArrayTrackRecord(), logTag)
55     protected constructor(src: RecorderCallback?, logTag: String) : this(
56         src?.backingRecord ?: ArrayTrackRecord(),
57         logTag
58     )
59 
60     sealed class CallbackEntry {
61         // To get equals(), hashcode(), componentN() etc for free, the child classes of
62         // this class are data classes. But while data classes can inherit from other classes,
63         // they may only have visible members in the constructors, so they couldn't declare
64         // a constructor with a non-val arg to pass to CallbackEntry. Instead, force all
65         // subclasses to implement a `network' property, which can be done in a data class
66         // constructor by specifying override.
67         abstract val network: Network
68 
69         data class Available(override val network: Network) : CallbackEntry()
70         data class CapabilitiesChanged(
71             override val network: Network,
72             val caps: NetworkCapabilities
73         ) : CallbackEntry()
74         data class LinkPropertiesChanged(
75             override val network: Network,
76             val lp: LinkProperties
77         ) : CallbackEntry()
78         data class LocalInfoChanged(
79             override val network: Network,
80             val info: LocalNetworkInfo
81         ) : CallbackEntry()
82         data class Suspended(override val network: Network) : CallbackEntry()
83         data class Resumed(override val network: Network) : CallbackEntry()
84         data class Losing(override val network: Network, val maxMsToLive: Int) : CallbackEntry()
85         data class Lost(override val network: Network) : CallbackEntry()
86         data class Unavailable private constructor(
87             override val network: Network
88         ) : CallbackEntry() {
89             constructor() : this(NULL_NETWORK)
90         }
91         data class BlockedStatus(
92             override val network: Network,
93             val blocked: Boolean
94         ) : CallbackEntry()
95         data class BlockedStatusInt(
96             override val network: Network,
97             val reason: Int
98         ) : CallbackEntry()
99 
100         // Convenience constants for expecting a type
101         companion object {
102             @JvmField
103             val AVAILABLE = Available::class
104             @JvmField
105             val NETWORK_CAPS_UPDATED = CapabilitiesChanged::class
106             @JvmField
107             val LINK_PROPERTIES_CHANGED = LinkPropertiesChanged::class
108             @JvmField
109             val LOCAL_INFO_CHANGED = LocalInfoChanged::class
110             @JvmField
111             val SUSPENDED = Suspended::class
112             @JvmField
113             val RESUMED = Resumed::class
114             @JvmField
115             val LOSING = Losing::class
116             @JvmField
117             val LOST = Lost::class
118             @JvmField
119             val UNAVAILABLE = Unavailable::class
120             @JvmField
121             val BLOCKED_STATUS = BlockedStatus::class
122             @JvmField
123             val BLOCKED_STATUS_INT = BlockedStatusInt::class
124         }
125     }
126 
127     val history = backingRecord.newReadHead()
128     val mark get() = history.mark
129 
130     override fun onAvailable(network: Network) {
131         Log.d(logTag, "onAvailable $network")
132         history.add(Available(network))
133     }
134 
135     // PreCheck is not used in the tests today. For backward compatibility with existing tests that
136     // expect the callbacks not to record this, do not listen to PreCheck here.
137 
138     override fun onCapabilitiesChanged(network: Network, caps: NetworkCapabilities) {
139         Log.d(logTag, "onCapabilitiesChanged $network $caps")
140         history.add(CapabilitiesChanged(network, caps))
141     }
142 
143     override fun onLinkPropertiesChanged(network: Network, lp: LinkProperties) {
144         Log.d(logTag, "onLinkPropertiesChanged $network $lp")
145         history.add(LinkPropertiesChanged(network, lp))
146     }
147 
148     override fun onLocalNetworkInfoChanged(network: Network, info: LocalNetworkInfo) {
149         Log.d(logTag, "onLocalNetworkInfoChanged $network $info")
150         history.add(LocalInfoChanged(network, info))
151     }
152 
153     override fun onBlockedStatusChanged(network: Network, blocked: Boolean) {
154         Log.d(logTag, "onBlockedStatusChanged $network $blocked")
155         history.add(BlockedStatus(network, blocked))
156     }
157 
158     // Cannot do:
159     // fun onBlockedStatusChanged(network: Network, blocked: Int) {
160     // because on S, that needs to be "override fun", and on R, that cannot be "override fun".
161     override fun onNetworkSuspended(network: Network) {
162         Log.d(logTag, "onNetworkSuspended $network $network")
163         history.add(Suspended(network))
164     }
165 
166     override fun onNetworkResumed(network: Network) {
167         Log.d(logTag, "$network onNetworkResumed $network")
168         history.add(Resumed(network))
169     }
170 
171     override fun onLosing(network: Network, maxMsToLive: Int) {
172         Log.d(logTag, "onLosing $network $maxMsToLive")
173         history.add(Losing(network, maxMsToLive))
174     }
175 
176     override fun onLost(network: Network) {
177         Log.d(logTag, "onLost $network")
178         history.add(Lost(network))
179     }
180 
181     override fun onUnavailable() {
182         Log.d(logTag, "onUnavailable")
183         history.add(Unavailable())
184     }
185 }
186 
187 private const val DEFAULT_TIMEOUT = 30_000L // ms
188 private const val DEFAULT_NO_CALLBACK_TIMEOUT = 200L // ms
<lambda>null189 private val NOOP = Runnable {}
190 
191 /**
192  * See comments on the public constructor below for a description of the arguments.
193  */
194 open class TestableNetworkCallback private constructor(
195     src: TestableNetworkCallback?,
196     val defaultTimeoutMs: Long,
197     val defaultNoCallbackTimeoutMs: Long,
198     val waiterFunc: Runnable,
199     logTag: String
200 ) : RecorderCallback(src, logTag) {
201     /**
202      * Construct a testable network callback.
203      * @param timeoutMs the default timeout for expecting a callback. Default 30 seconds. This
204      *                  should be long in most cases, because the success case doesn't incur
205      *                  the wait.
206      * @param noCallbackTimeoutMs the timeout for expecting that no callback is received. Default
207      *                            200ms. Because the success case does incur the timeout, this
208      *                            should be short in most cases, but not so short as to frequently
209      *                            time out before an incorrect callback is received.
210      * @param waiterFunc a function to use before asserting no callback. For some specific tests,
211      *                   it is useful to run test-specific code before asserting no callback to
212      *                   increase the likelihood that a spurious callback is correctly detected.
213      *                   As an example, a unit test using mock loopers may want to use this to
214      *                   make sure the loopers are drained before asserting no callback, since
215      *                   one of them may cause a callback to be called. @see ConnectivityServiceTest
216      *                   for such an example.
217      */
218     @JvmOverloads
219     constructor(
220         timeoutMs: Long = DEFAULT_TIMEOUT,
221         noCallbackTimeoutMs: Long = DEFAULT_NO_CALLBACK_TIMEOUT,
222         waiterFunc: Runnable = NOOP, // "() -> Unit" would forbid calling with a void func from Java
223         logTag: String = DEFAULT_TAG
224     ) : this(null, timeoutMs, noCallbackTimeoutMs, waiterFunc, logTag)
225 
createLinkedCopynull226     fun createLinkedCopy() = TestableNetworkCallback(
227         this,
228         defaultTimeoutMs,
229         defaultNoCallbackTimeoutMs,
230         waiterFunc,
231         logTag
232     )
233 
234     // The last available network, or null if any network was lost since the last call to
235     // onAvailable. TODO : fix this by fixing the tests that rely on this behavior
236     val lastAvailableNetwork: Network?
237         get() = when (val it = history.lastOrNull { it is Available || it is Lost }) {
238             is Available -> it.network
239             else -> null
240         }
241 
242     /**
243      * Get the next callback or null if timeout.
244      *
245      * With no argument, this method waits out the default timeout. To wait forever, pass
246      * Long.MAX_VALUE.
247      */
248     @JvmOverloads
<lambda>null249     fun poll(timeoutMs: Long = defaultTimeoutMs, predicate: (CallbackEntry) -> Boolean = { true }) =
250             history.poll(timeoutMs, predicate)
251 
252     /*****
253      * expect family of methods.
254      * These methods fetch the next callback and assert it matches the conditions : type,
255      * passed predicate. If no callback is received within the timeout, these methods fail.
256      */
257     @JvmOverloads
expectnull258     fun <T : CallbackEntry> expect(
259         type: KClass<T>,
260         network: Network = ANY_NETWORK,
261         timeoutMs: Long = defaultTimeoutMs,
262         errorMsg: String? = null,
263         test: (T) -> Boolean = { true }
<lambda>null264     ) = expect<CallbackEntry>(network, timeoutMs, errorMsg) {
265         if (type.isInstance(it)) {
266             test(it as T) // Cast can't fail since type.isInstance(it) and type: KClass<T>
267         } else {
268             fail("Expected callback ${type.simpleName}, got $it")
269         }
270     } as T
271 
272     @JvmOverloads
expectnull273     fun <T : CallbackEntry> expect(
274         type: KClass<T>,
275         network: HasNetwork,
276         timeoutMs: Long = defaultTimeoutMs,
277         errorMsg: String? = null,
278         test: (T) -> Boolean = { true }
279     ) = expect(type, network.network, timeoutMs, errorMsg, test)
280 
281     // Java needs an explicit overload to let it omit arguments in the middle, so define these
282     // here. Note that @JvmOverloads give us the versions without the last arguments too, so
283     // there is no need to explicitly define versions without the test predicate.
284     // Without |network|
285     @JvmOverloads
expectnull286     fun <T : CallbackEntry> expect(
287         type: KClass<T>,
288         timeoutMs: Long,
289         errorMsg: String?,
290         test: (T) -> Boolean = { true }
291     ) = expect(type, ANY_NETWORK, timeoutMs, errorMsg, test)
292 
293     // Without |timeout|, in Network and HasNetwork versions
294     @JvmOverloads
expectnull295     fun <T : CallbackEntry> expect(
296         type: KClass<T>,
297         network: Network,
298         errorMsg: String?,
299         test: (T) -> Boolean = { true }
300     ) = expect(type, network, defaultTimeoutMs, errorMsg, test)
301 
302     @JvmOverloads
expectnull303     fun <T : CallbackEntry> expect(
304         type: KClass<T>,
305         network: HasNetwork,
306         errorMsg: String?,
307         test: (T) -> Boolean = { true }
308     ) = expect(type, network.network, defaultTimeoutMs, errorMsg, test)
309 
310     // Without |errorMsg|, in Network and HasNetwork versions
311     @JvmOverloads
expectnull312     fun <T : CallbackEntry> expect(
313         type: KClass<T>,
314         network: Network,
315         timeoutMs: Long,
316         test: (T) -> Boolean
317     ) = expect(type, network, timeoutMs, null, test)
318 
319     @JvmOverloads
320     fun <T : CallbackEntry> expect(
321         type: KClass<T>,
322         network: HasNetwork,
323         timeoutMs: Long,
324         test: (T) -> Boolean
325     ) = expect(type, network.network, timeoutMs, null, test)
326 
327     // Without |network| or |timeout|
328     @JvmOverloads
329     fun <T : CallbackEntry> expect(
330         type: KClass<T>,
331         errorMsg: String?,
332         test: (T) -> Boolean = { true }
333     ) = expect(type, ANY_NETWORK, defaultTimeoutMs, errorMsg, test)
334 
335     // Without |network| or |errorMsg|
336     @JvmOverloads
expectnull337     fun <T : CallbackEntry> expect(
338         type: KClass<T>,
339         timeoutMs: Long,
340         test: (T) -> Boolean = { true }
341     ) = expect(type, ANY_NETWORK, timeoutMs, null, test)
342 
343     // Without |timeout| or |errorMsg|, in Network and HasNetwork versions
344     @JvmOverloads
expectnull345     fun <T : CallbackEntry> expect(
346         type: KClass<T>,
347         network: Network,
348         test: (T) -> Boolean
349     ) = expect(type, network, defaultTimeoutMs, null, test)
350 
351     @JvmOverloads
352     fun <T : CallbackEntry> expect(
353         type: KClass<T>,
354         network: HasNetwork,
355         test: (T) -> Boolean
356     ) = expect(type, network.network, defaultTimeoutMs, null, test)
357 
358     // Without |network| or |timeout| or |errorMsg|
359     @JvmOverloads
360     fun <T : CallbackEntry> expect(
361         type: KClass<T>,
362         test: (T) -> Boolean
363     ) = expect(type, ANY_NETWORK, defaultTimeoutMs, null, test)
364 
365     // Kotlin reified versions. Don't call methods above, or the predicate would need to be noinline
366     inline fun <reified T : CallbackEntry> expect(
367         network: Network = ANY_NETWORK,
368         timeoutMs: Long = defaultTimeoutMs,
369         errorMsg: String? = null,
370         test: (T) -> Boolean = { true }
371     ) = (poll(timeoutMs) ?: failWithErrorReason(errorMsg,
372         "Did not receive ${T::class.simpleName} after ${timeoutMs}ms"))
<lambda>null373             .also {
374                 if (it !is T) {
375                     failWithErrorReason(
376                         errorMsg,
377                         "Expected callback ${T::class.simpleName}, got $it"
378                     )
379                 }
380                 if (ANY_NETWORK !== network && it.network != network) {
381                     failWithErrorReason(errorMsg, "Expected network $network for callback : $it")
382                 }
383                 if (!test(it)) {
384                     failWithErrorReason(errorMsg, "Callback doesn't match predicate : $it")
385                 }
386             } as T
387 
388     // "Nothing" is the return type to declare a function never returns a value.
failWithErrorReasonnull389     fun failWithErrorReason(errorMsg: String?, errorReason: String): Nothing {
390         val message = if (errorMsg != null) "$errorMsg : $errorReason" else errorReason
391         fail(message)
392     }
393 
expectnull394     inline fun <reified T : CallbackEntry> expect(
395         network: HasNetwork,
396         timeoutMs: Long = defaultTimeoutMs,
397         errorMsg: String? = null,
398         test: (T) -> Boolean = { true }
399     ) = expect(network.network, timeoutMs, errorMsg, test)
400 
401     /*****
402      * assertNoCallback family of methods.
403      * These methods make sure that no callback that matches the predicate was received.
404      * If no predicate is given, they make sure that no callback at all was received.
405      * These methods run the waiter func given in the constructor if any.
406      */
407     @JvmOverloads
assertNoCallbacknull408     fun assertNoCallback(
409         timeoutMs: Long = defaultNoCallbackTimeoutMs,
410         valid: (CallbackEntry) -> Boolean = { true }
411     ) {
412         waiterFunc.run()
<lambda>null413         history.poll(timeoutMs) { valid(it) }?.let { fail("Expected no callback but got $it") }
414     }
415 
assertNoCallbacknull416     fun assertNoCallback(valid: (CallbackEntry) -> Boolean) =
417             assertNoCallback(defaultNoCallbackTimeoutMs, valid)
418 
419     /*****
420      * eventuallyExpect family of methods.
421      * These methods make sure a callback that matches the type/predicate is received eventually.
422      * Any callback of the wrong type, or doesn't match the optional predicate, is ignored.
423      * They fail if no callback matching the predicate is received within the timeout.
424      */
425     inline fun <reified T : CallbackEntry> eventuallyExpect(
426         timeoutMs: Long = defaultTimeoutMs,
427         from: Int = mark,
428         crossinline predicate: (T) -> Boolean = { true }
<lambda>null429     ): T = history.poll(timeoutMs, from) { it is T && predicate(it) }.also {
430         assertNotNull(
431             it,
432             "Callback ${T::class} not received within ${timeoutMs}ms. " +
433                 "Got ${history.backtrace()}"
434         )
435     } as T
436 
437     @JvmOverloads
eventuallyExpectnull438     fun <T : CallbackEntry> eventuallyExpect(
439         type: KClass<T>,
440         timeoutMs: Long = defaultTimeoutMs,
441         predicate: (cb: T) -> Boolean = { true }
<lambda>null442     ) = history.poll(timeoutMs) { type.java.isInstance(it) && predicate(it as T) }.also {
443         assertNotNull(
444             it,
445             "Callback ${type.java} not received within ${timeoutMs}ms. " +
446                 "Got ${history.backtrace()}"
447         )
448     } as T
449 
eventuallyExpectnull450     fun <T : CallbackEntry> eventuallyExpect(
451         type: KClass<T>,
452         timeoutMs: Long = defaultTimeoutMs,
453         from: Int = mark,
454         predicate: (cb: T) -> Boolean = { true }
<lambda>null455     ) = history.poll(timeoutMs, from) { type.java.isInstance(it) && predicate(it as T) }.also {
456         assertNotNull(
457             it,
458             "Callback ${type.java} not received within ${timeoutMs}ms. " +
459                 "Got ${history.backtrace()}"
460         )
461     } as T
462 
463     // Expects onAvailable and the callbacks that follow it. These are:
464     // - onSuspended, iff the network was suspended when the callbacks fire.
465     // - onCapabilitiesChanged.
466     // - onLinkPropertiesChanged.
467     // - onBlockedStatusChanged.
468     //
469     // @param network the network to expect the callbacks on.
470     // @param suspended whether to expect a SUSPENDED callback.
471     // @param validated the expected value of the VALIDATED capability in the
472     //        onCapabilitiesChanged callback.
473     // @param tmt how long to wait for the callbacks.
474     @JvmOverloads
expectAvailableCallbacksnull475     fun expectAvailableCallbacks(
476         net: Network,
477         suspended: Boolean = false,
478         validated: Boolean? = true,
479         blocked: Boolean = false,
480         upstream: Network? = null,
481         tmt: Long = defaultTimeoutMs
482     ) {
483         expectAvailableCallbacksCommon(net, suspended, validated, upstream, tmt)
484         expect<BlockedStatus>(net, tmt) { it.blocked == blocked }
485     }
486 
487     // For backward compatibility, add a method that allows callers to specify a timeout but
488     // no upstream.
expectAvailableCallbacksnull489     fun expectAvailableCallbacks(
490         net: Network,
491         suspended: Boolean = false,
492         validated: Boolean? = true,
493         blocked: Boolean = false,
494         tmt: Long = defaultTimeoutMs
495     ) = expectAvailableCallbacks(net, suspended, validated, blocked, upstream = null, tmt = tmt)
496 
497     fun expectAvailableCallbacks(
498         net: Network,
499         suspended: Boolean,
500         validated: Boolean,
501         blockedReason: Int,
502         upstream: Network? = null,
503         tmt: Long
504     ) {
505         expectAvailableCallbacksCommon(net, suspended, validated, upstream, tmt)
506         expect<BlockedStatusInt>(net) { it.reason == blockedReason }
507     }
508 
509     // For backward compatibility, add a method that allows callers to specify a timeout but
510     // no upstream.
expectAvailableCallbacksnull511     fun expectAvailableCallbacks(
512             net: Network,
513             suspended: Boolean = false,
514             validated: Boolean = true,
515             blockedReason: Int,
516             tmt: Long = defaultTimeoutMs
517     ) = expectAvailableCallbacks(net, suspended, validated, blockedReason, upstream = null, tmt)
518 
519     private fun expectAvailableCallbacksCommon(
520         net: Network,
521         suspended: Boolean,
522         validated: Boolean?,
523         upstream: Network?,
524         tmt: Long
525     ) {
526         expect<Available>(net, tmt)
527         if (suspended) {
528             expect<Suspended>(net, tmt)
529         }
530         val caps = expect<CapabilitiesChanged>(net, tmt) {
531             validated == null || validated == it.caps.hasCapability(NET_CAPABILITY_VALIDATED)
532         }.caps
533         expect<LinkPropertiesChanged>(net, tmt)
534         if (caps.hasCapability(NetworkCapabilities.NET_CAPABILITY_LOCAL_NETWORK)) {
535             expect<LocalInfoChanged>(net, tmt) { it.info.upstreamNetwork == upstream }
536         }
537     }
538 
539     // Backward compatibility for existing Java code. Use named arguments instead and remove all
540     // these when there is no user left.
expectAvailableAndSuspendedCallbacksnull541     fun expectAvailableAndSuspendedCallbacks(
542         net: Network,
543         validated: Boolean,
544         tmt: Long = defaultTimeoutMs
545     ) = expectAvailableCallbacks(net, suspended = true, validated = validated, tmt = tmt)
546 
547     // Expects the available callbacks (where the onCapabilitiesChanged must contain the
548     // VALIDATED capability), plus another onCapabilitiesChanged which is identical to the
549     // one we just sent.
550     // TODO: this is likely a bug. Fix it and remove this method.
551     fun expectAvailableDoubleValidatedCallbacks(net: Network, tmt: Long = defaultTimeoutMs) {
552         val mark = history.mark
553         expectAvailableCallbacks(net, tmt = tmt)
554         val firstCaps = history.poll(tmt, mark) { it is CapabilitiesChanged }
555         assertEquals(firstCaps, expect<CapabilitiesChanged>(net, tmt))
556     }
557 
558     // Expects the available callbacks where the onCapabilitiesChanged must not have validated,
559     // then expects another onCapabilitiesChanged that has the validated bit set. This is used
560     // when a network connects and satisfies a callback, and then immediately validates.
expectAvailableThenValidatedCallbacksnull561     fun expectAvailableThenValidatedCallbacks(net: Network, tmt: Long = defaultTimeoutMs) {
562         expectAvailableCallbacks(net, validated = false, tmt = tmt)
563         expectCaps(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) }
564     }
565 
expectAvailableThenValidatedCallbacksnull566     fun expectAvailableThenValidatedCallbacks(
567         net: Network,
568         blockedReason: Int,
569         tmt: Long = defaultTimeoutMs
570     ) {
571         expectAvailableCallbacks(
572             net,
573             validated = false,
574             suspended = false,
575             blockedReason = blockedReason,
576             tmt = tmt
577         )
578         expectCaps(net, tmt) { it.hasCapability(NET_CAPABILITY_VALIDATED) }
579     }
580 
581     // Temporary Java compat measure : have MockNetworkAgent implement this so that all existing
582     // calls with networkAgent can be routed through here without moving MockNetworkAgent.
583     // TODO: clean this up, remove this method.
584     interface HasNetwork {
585         val network: Network
586     }
587 
588     @JvmOverloads
expectAvailableCallbacksnull589     fun expectAvailableCallbacks(
590         n: HasNetwork,
591         suspended: Boolean,
592         validated: Boolean,
593         blocked: Boolean,
594         upstream: Network? = null,
595         timeoutMs: Long
596     ) = expectAvailableCallbacks(n.network, suspended, validated, blocked, upstream, timeoutMs)
597 
598     fun expectAvailableAndSuspendedCallbacks(n: HasNetwork, expectValidated: Boolean) {
599         expectAvailableAndSuspendedCallbacks(n.network, expectValidated)
600     }
601 
expectAvailableCallbacksValidatednull602     fun expectAvailableCallbacksValidated(n: HasNetwork) {
603         expectAvailableCallbacks(n.network)
604     }
605 
expectAvailableCallbacksValidatedAndBlockednull606     fun expectAvailableCallbacksValidatedAndBlocked(n: HasNetwork) {
607         expectAvailableCallbacks(n.network, blocked = true)
608     }
609 
expectAvailableCallbacksUnvalidatednull610     fun expectAvailableCallbacksUnvalidated(n: HasNetwork) {
611         expectAvailableCallbacks(n.network, validated = false)
612     }
613 
expectAvailableCallbacksUnvalidatedAndBlockednull614     fun expectAvailableCallbacksUnvalidatedAndBlocked(n: HasNetwork) {
615         expectAvailableCallbacks(n.network, validated = false, blocked = true)
616     }
617 
expectAvailableDoubleValidatedCallbacksnull618     fun expectAvailableDoubleValidatedCallbacks(n: HasNetwork) {
619         expectAvailableDoubleValidatedCallbacks(n.network, defaultTimeoutMs)
620     }
621 
expectAvailableThenValidatedCallbacksnull622     fun expectAvailableThenValidatedCallbacks(n: HasNetwork) {
623         expectAvailableThenValidatedCallbacks(n.network, defaultTimeoutMs)
624     }
625 
626     @JvmOverloads
expectCapsnull627     fun expectCaps(
628         n: HasNetwork,
629         tmt: Long = defaultTimeoutMs,
630         valid: (NetworkCapabilities) -> Boolean = { true }
<lambda>null631     ) = expect<CapabilitiesChanged>(n.network, tmt) { valid(it.caps) }.caps
632 
633     @JvmOverloads
expectCapsnull634     fun expectCaps(
635         n: Network,
636         tmt: Long = defaultTimeoutMs,
637         valid: (NetworkCapabilities) -> Boolean
638     ) = expect<CapabilitiesChanged>(n, tmt) { valid(it.caps) }.caps
639 
expectCapsnull640     fun expectCaps(
641         n: HasNetwork,
642         valid: (NetworkCapabilities) -> Boolean
643     ) = expect<CapabilitiesChanged>(n.network) { valid(it.caps) }.caps
644 
expectCapsnull645     fun expectCaps(
646         tmt: Long,
647         valid: (NetworkCapabilities) -> Boolean
648     ) = expect<CapabilitiesChanged>(ANY_NETWORK, tmt) { valid(it.caps) }.caps
649 }
650