diff options
Diffstat (limited to 'common/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt')
-rw-r--r-- | common/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt | 474 |
1 files changed, 0 insertions, 474 deletions
diff --git a/common/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt b/common/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt deleted file mode 100644 index e838bdc5..00000000 --- a/common/tests/unit/src/com/android/testutils/TestableNetworkCallbackTest.kt +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Copyright (C) 2022 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.testutils - -import android.annotation.SuppressLint -import android.net.LinkAddress -import android.net.LinkProperties -import android.net.Network -import android.net.NetworkCapabilities -import com.android.testutils.RecorderCallback.CallbackEntry -import com.android.testutils.RecorderCallback.CallbackEntry.Available -import com.android.testutils.RecorderCallback.CallbackEntry.BlockedStatus -import com.android.testutils.RecorderCallback.CallbackEntry.CapabilitiesChanged -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.AVAILABLE -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.BLOCKED_STATUS -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LINK_PROPERTIES_CHANGED -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOSING -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.LOST -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.NETWORK_CAPS_UPDATED -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.RESUMED -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.SUSPENDED -import com.android.testutils.RecorderCallback.CallbackEntry.Companion.UNAVAILABLE -import com.android.testutils.RecorderCallback.CallbackEntry.LinkPropertiesChanged -import kotlin.reflect.KClass -import kotlin.test.assertEquals -import kotlin.test.assertFails -import kotlin.test.assertNull -import kotlin.test.assertTrue -import kotlin.test.fail -import org.junit.Assume.assumeTrue -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.JUnit4 - -const val SHORT_TIMEOUT_MS = 20L -const val DEFAULT_LINGER_DELAY_MS = 30000 -const val NOT_METERED = NetworkCapabilities.NET_CAPABILITY_NOT_METERED -const val WIFI = NetworkCapabilities.TRANSPORT_WIFI -const val CELLULAR = NetworkCapabilities.TRANSPORT_CELLULAR -const val TEST_INTERFACE_NAME = "testInterfaceName" - -@RunWith(JUnit4::class) -@SuppressLint("NewApi") // Uses hidden APIs, which the linter would identify as missing APIs. -class TestableNetworkCallbackTest { - private lateinit var mCallback: TestableNetworkCallback - - private fun makeHasNetwork(netId: Int) = object : TestableNetworkCallback.HasNetwork { - override val network: Network = Network(netId) - } - - @Before - fun setUp() { - mCallback = TestableNetworkCallback() - } - - @Test - fun testLastAvailableNetwork() { - // Make sure there is no last available network at first, then the last available network - // is returned after onAvailable is called. - val net2097 = Network(2097) - assertNull(mCallback.lastAvailableNetwork) - mCallback.onAvailable(net2097) - assertEquals(mCallback.lastAvailableNetwork, net2097) - - // Make sure calling onCapsChanged/onLinkPropertiesChanged don't affect the last available - // network. - mCallback.onCapabilitiesChanged(net2097, NetworkCapabilities()) - mCallback.onLinkPropertiesChanged(net2097, LinkProperties()) - assertEquals(mCallback.lastAvailableNetwork, net2097) - - // Make sure onLost clears the last available network. - mCallback.onLost(net2097) - assertNull(mCallback.lastAvailableNetwork) - - // Do the same but with a different network after onLost : make sure the last available - // network is the new one, not the original one. - val net2098 = Network(2098) - mCallback.onAvailable(net2098) - mCallback.onCapabilitiesChanged(net2098, NetworkCapabilities()) - mCallback.onLinkPropertiesChanged(net2098, LinkProperties()) - assertEquals(mCallback.lastAvailableNetwork, net2098) - - // Make sure onAvailable changes the last available network even if onLost was not called. - val net2099 = Network(2099) - mCallback.onAvailable(net2099) - assertEquals(mCallback.lastAvailableNetwork, net2099) - - // For legacy reasons, lastAvailableNetwork is null as soon as any is lost, not necessarily - // the last available one. Check that behavior. - mCallback.onLost(net2098) - assertNull(mCallback.lastAvailableNetwork) - - // Make sure that losing the really last available one still results in null. - mCallback.onLost(net2099) - assertNull(mCallback.lastAvailableNetwork) - - // Make sure multiple onAvailable in a row then onLost still results in null. - mCallback.onAvailable(net2097) - mCallback.onAvailable(net2098) - mCallback.onAvailable(net2099) - mCallback.onLost(net2097) - assertNull(mCallback.lastAvailableNetwork) - } - - @Test - fun testAssertNoCallback() { - mCallback.assertNoCallback(SHORT_TIMEOUT_MS) - mCallback.onAvailable(Network(100)) - assertFails { mCallback.assertNoCallback(SHORT_TIMEOUT_MS) } - val net = Network(101) - mCallback.assertNoCallback { it is Available } - mCallback.onAvailable(net) - // Expect no blocked status change. Receive other callback does not fail the test. - mCallback.assertNoCallback { it is BlockedStatus } - mCallback.onBlockedStatusChanged(net, true) - assertFails { mCallback.assertNoCallback { it is BlockedStatus } } - mCallback.onBlockedStatusChanged(net, false) - mCallback.onCapabilitiesChanged(net, NetworkCapabilities()) - assertFails { mCallback.assertNoCallback { it is CapabilitiesChanged } } - } - - @Test - fun testCapabilitiesWithAndWithout() { - val net = Network(101) - val matcher = makeHasNetwork(101) - val meteredNc = NetworkCapabilities() - val unmeteredNc = NetworkCapabilities().addCapability(NOT_METERED) - // Check that expecting caps (with or without) fails when no callback has been received. - assertFails { - mCallback.expectCaps(matcher, SHORT_TIMEOUT_MS) { it.hasCapability(NOT_METERED) } - } - assertFails { - mCallback.expectCaps(matcher, SHORT_TIMEOUT_MS) { !it.hasCapability(NOT_METERED) } - } - - // Add NOT_METERED and check that With succeeds and Without fails. - mCallback.onCapabilitiesChanged(net, unmeteredNc) - mCallback.expectCaps(matcher) { it.hasCapability(NOT_METERED) } - mCallback.onCapabilitiesChanged(net, unmeteredNc) - assertFails { - mCallback.expectCaps(matcher, SHORT_TIMEOUT_MS) { !it.hasCapability(NOT_METERED) } - } - - // Don't add NOT_METERED and check that With fails and Without succeeds. - mCallback.onCapabilitiesChanged(net, meteredNc) - assertFails { - mCallback.expectCaps(matcher, SHORT_TIMEOUT_MS) { it.hasCapability(NOT_METERED) } - } - mCallback.onCapabilitiesChanged(net, meteredNc) - mCallback.expectCaps(matcher) { !it.hasCapability(NOT_METERED) } - } - - @Test - fun testExpectWithPredicate() { - val net = Network(193) - val netCaps = NetworkCapabilities().addTransportType(CELLULAR) - // Check that expecting callbackThat anything fails when no callback has been received. - assertFails { mCallback.expect<CallbackEntry>(timeoutMs = SHORT_TIMEOUT_MS) { true } } - - // Basic test for true and false - mCallback.onAvailable(net) - mCallback.expect<Available> { true } - mCallback.onAvailable(net) - assertFails { mCallback.expect<CallbackEntry>(timeoutMs = SHORT_TIMEOUT_MS) { false } } - - // Try a positive and a negative case - mCallback.onBlockedStatusChanged(net, true) - mCallback.expect<CallbackEntry> { cb -> cb is BlockedStatus && cb.blocked } - mCallback.onCapabilitiesChanged(net, netCaps) - assertFails { mCallback.expect<CallbackEntry>(timeoutMs = SHORT_TIMEOUT_MS) { cb -> - cb is CapabilitiesChanged && cb.caps.hasTransport(WIFI) - } } - } - - @Test - fun testExpectCaps() { - val net = Network(101) - val netCaps = NetworkCapabilities().addCapability(NOT_METERED).addTransportType(WIFI) - // Check that expecting capabilitiesThat anything fails when no callback has been received. - assertFails { mCallback.expectCaps(net, SHORT_TIMEOUT_MS) { true } } - - // Basic test for true and false - mCallback.onCapabilitiesChanged(net, netCaps) - mCallback.expectCaps(net) { true } - mCallback.onCapabilitiesChanged(net, netCaps) - assertFails { mCallback.expectCaps(net, SHORT_TIMEOUT_MS) { false } } - - // Try a positive and a negative case - mCallback.onCapabilitiesChanged(net, netCaps) - mCallback.expectCaps(net) { - it.hasCapability(NOT_METERED) && it.hasTransport(WIFI) && !it.hasTransport(CELLULAR) - } - mCallback.onCapabilitiesChanged(net, netCaps) - assertFails { mCallback.expectCaps(net, SHORT_TIMEOUT_MS) { it.hasTransport(CELLULAR) } } - - // Try a matching callback on the wrong network - mCallback.onCapabilitiesChanged(net, netCaps) - assertFails { - mCallback.expectCaps(Network(100), SHORT_TIMEOUT_MS) { true } - } - } - - @Test - fun testLinkPropertiesCallbacks() { - val net = Network(112) - val linkAddress = LinkAddress("fe80::ace:d00d/64") - val mtu = 1984 - val linkProps = LinkProperties().apply { - this.mtu = mtu - interfaceName = TEST_INTERFACE_NAME - addLinkAddress(linkAddress) - } - - // Check that expecting linkPropsThat anything fails when no callback has been received. - assertFails { mCallback.expect<LinkPropertiesChanged>(net, SHORT_TIMEOUT_MS) { true } } - - // Basic test for true and false - mCallback.onLinkPropertiesChanged(net, linkProps) - mCallback.expect<LinkPropertiesChanged>(net) { true } - mCallback.onLinkPropertiesChanged(net, linkProps) - assertFails { mCallback.expect<LinkPropertiesChanged>(net, SHORT_TIMEOUT_MS) { false } } - - // Try a positive and negative case - mCallback.onLinkPropertiesChanged(net, linkProps) - mCallback.expect<LinkPropertiesChanged>(net) { - it.lp.interfaceName == TEST_INTERFACE_NAME && - it.lp.linkAddresses.contains(linkAddress) && - it.lp.mtu == mtu - } - mCallback.onLinkPropertiesChanged(net, linkProps) - assertFails { mCallback.expect<LinkPropertiesChanged>(net, SHORT_TIMEOUT_MS) { - it.lp.interfaceName != TEST_INTERFACE_NAME - } } - - // Try a matching callback on the wrong network - mCallback.onLinkPropertiesChanged(net, linkProps) - assertFails { mCallback.expect<LinkPropertiesChanged>(Network(114), SHORT_TIMEOUT_MS) { - it.lp.interfaceName == TEST_INTERFACE_NAME - } } - } - - @Test - fun testExpect() { - val net = Network(103) - // Test expectCallback fails when nothing was sent. - assertFails { mCallback.expect<BlockedStatus>(net, SHORT_TIMEOUT_MS) } - - // Test onAvailable is seen and can be expected - mCallback.onAvailable(net) - mCallback.expect<Available>(net, SHORT_TIMEOUT_MS) - - // Test onAvailable won't return calls with a different network - mCallback.onAvailable(Network(106)) - assertFails { mCallback.expect<Available>(net, SHORT_TIMEOUT_MS) } - - // Test onAvailable won't return calls with a different callback - mCallback.onAvailable(net) - assertFails { mCallback.expect<BlockedStatus>(net, SHORT_TIMEOUT_MS) } - } - - @Test - 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 } - - // Method with all arguments (version that takes a Network) - mCallback.expect(AVAILABLE, ANY_NETWORK, 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") - - // 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) - - // 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) - - // Java overload for omitting all four arguments. - mCallback.expect(AVAILABLE) - - // Same orders as above, but versions that take a HasNetwork. Except overloads that - // were already tested because they omitted the Network argument - mCallback.expect(AVAILABLE, hn, 10, "error") { true } - mCallback.expect(AVAILABLE, hn, "error") { true } - mCallback.expect(AVAILABLE, hn, 10) { true } - mCallback.expect(AVAILABLE, hn, 10, "error") - - mCallback.expect(AVAILABLE, hn) { true } - mCallback.expect(AVAILABLE, hn, "error") - mCallback.expect(AVAILABLE, hn, 10) - - mCallback.expect(AVAILABLE, hn) - - // Same as above but for reified versions. - mCallback.expect<Available>(ANY_NETWORK, 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>(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> { true } - mCallback.expect<Available>(errorMsg = "error") - mCallback.expect<Available>(timeoutMs = 10) - mCallback.expect<Available>(network = ANY_NETWORK) - mCallback.expect<Available>() - - mCallback.expect<Available>(hn, 10, "error") { true } - mCallback.expect<Available>(network = hn, errorMsg = "error") { true } - mCallback.expect<Available>(network = hn, timeoutMs = 10) { true } - mCallback.expect<Available>(network = hn, timeoutMs = 10, errorMsg = "error") - - mCallback.expect<Available>(network = hn) { true } - mCallback.expect<Available>(network = hn, errorMsg = "error") - mCallback.expect<Available>(network = hn, timeoutMs = 10) - - mCallback.expect<Available>(network = hn) - } - - @Test - fun testExpectClass() { - val net = Network(1) - mCallback.onAvailable(net) - assertFails { mCallback.expect(LOST, net) } - } - - @Test - fun testPoll() { - assertNull(mCallback.poll(SHORT_TIMEOUT_MS)) - TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1, - threadTransform = { cb -> cb.createLinkedCopy() }, spec = """ - sleep; onAvailable(133) | poll(2) = Available(133) time 1..4 - | poll(1) = null - onCapabilitiesChanged(108) | poll(1) = CapabilitiesChanged(108) time 0..3 - onBlockedStatus(199) | poll(1) = BlockedStatus(199) time 0..3 - """) - } - - @Test - fun testEventuallyExpect() { - // TODO: Current test does not verify the inline one. Also verify the behavior after - // aligning two eventuallyExpect() - val net1 = Network(100) - val net2 = Network(101) - mCallback.onAvailable(net1) - mCallback.onCapabilitiesChanged(net1, NetworkCapabilities()) - mCallback.onLinkPropertiesChanged(net1, LinkProperties()) - mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED) { - net1.equals(it.network) - } - // No further new callback. Expect no callback. - assertFails { mCallback.eventuallyExpect(LINK_PROPERTIES_CHANGED, SHORT_TIMEOUT_MS) } - - // Verify no predicate set. - mCallback.onAvailable(net2) - mCallback.onLinkPropertiesChanged(net2, LinkProperties()) - mCallback.onBlockedStatusChanged(net1, false) - mCallback.eventuallyExpect(BLOCKED_STATUS) { net1.equals(it.network) } - // Verify no callback received if the callback does not happen. - assertFails { mCallback.eventuallyExpect(LOSING, SHORT_TIMEOUT_MS) } - } - - @Test - fun testEventuallyExpectOnMultiThreads() { - TNCInterpreter.interpretTestSpec(initial = mCallback, lineShift = 1, - threadTransform = { cb -> cb.createLinkedCopy() }, spec = """ - onAvailable(100) | eventually(CapabilitiesChanged(100), 1) fails - sleep ; onCapabilitiesChanged(100) | eventually(CapabilitiesChanged(100), 3) - onAvailable(101) ; onBlockedStatus(101) | eventually(BlockedStatus(100), 2) fails - onSuspended(100) ; sleep ; onLost(100) | eventually(Lost(100), 3) - """) - } -} - -private object TNCInterpreter : ConcurrentInterpreter<TestableNetworkCallback>(interpretTable) - -val EntryList = CallbackEntry::class.sealedSubclasses.map { it.simpleName }.joinToString("|") -private fun callbackEntryFromString(name: String): KClass<out CallbackEntry> { - return CallbackEntry::class.sealedSubclasses.first { it.simpleName == name } -} - -@SuppressLint("NewApi") // Uses hidden APIs, which the linter would identify as missing APIs. -private val interpretTable = listOf<InterpretMatcher<TestableNetworkCallback>>( - // Interpret "Available(xx)" as "call to onAvailable with netId xx", and likewise for - // all callback types. This is implemented above by enumerating the subclasses of - // CallbackEntry and reading their simpleName. - Regex("""(.*)\s+=\s+($EntryList)\((\d+)\)""") to { i, cb, t -> - val record = i.interpret(t.strArg(1), cb) - assertTrue(callbackEntryFromString(t.strArg(2)).isInstance(record)) - // Strictly speaking testing for is CallbackEntry is useless as it's been tested above - // but the compiler can't figure things out from the isInstance call. It does understand - // from the assertTrue(is CallbackEntry) that this is true, which allows to access - // the 'network' member below. - assertTrue(record is CallbackEntry) - assertEquals(record.network.netId, t.intArg(3)) - }, - // Interpret "onAvailable(xx)" as calling "onAvailable" with a netId of xx, and likewise for - // all callback types. NetworkCapabilities and LinkProperties just get an empty object - // as their argument. Losing gets the default linger timer. Blocked gets false. - Regex("""on($EntryList)\((\d+)\)""") to { i, cb, t -> - val net = Network(t.intArg(2)) - when (t.strArg(1)) { - "Available" -> cb.onAvailable(net) - // PreCheck not used in tests. Add it here if it becomes useful. - "CapabilitiesChanged" -> cb.onCapabilitiesChanged(net, NetworkCapabilities()) - "LinkPropertiesChanged" -> cb.onLinkPropertiesChanged(net, LinkProperties()) - "Suspended" -> cb.onNetworkSuspended(net) - "Resumed" -> cb.onNetworkResumed(net) - "Losing" -> cb.onLosing(net, DEFAULT_LINGER_DELAY_MS) - "Lost" -> cb.onLost(net) - "Unavailable" -> cb.onUnavailable() - "BlockedStatus" -> cb.onBlockedStatusChanged(net, false) - else -> fail("Unknown callback type") - } - }, - Regex("""poll\((\d+)\)""") to { i, cb, t -> cb.poll(t.timeArg(1)) }, - // Interpret "eventually(Available(xx), timeout)" as calling eventuallyExpect that expects - // CallbackEntry.AVAILABLE with netId of xx within timeout*INTERPRET_TIME_UNIT timeout, and - // likewise for all callback types. - Regex("""eventually\(($EntryList)\((\d+)\),\s+(\d+)\)""") to { i, cb, t -> - val net = Network(t.intArg(2)) - val timeout = t.timeArg(3) - when (t.strArg(1)) { - "Available" -> cb.eventuallyExpect(AVAILABLE, timeout) { net == it.network } - "Suspended" -> cb.eventuallyExpect(SUSPENDED, timeout) { net == it.network } - "Resumed" -> cb.eventuallyExpect(RESUMED, timeout) { net == it.network } - "Losing" -> cb.eventuallyExpect(LOSING, timeout) { net == it.network } - "Lost" -> cb.eventuallyExpect(LOST, timeout) { net == it.network } - "Unavailable" -> cb.eventuallyExpect(UNAVAILABLE, timeout) { net == it.network } - "BlockedStatus" -> cb.eventuallyExpect(BLOCKED_STATUS, timeout) { net == it.network } - "CapabilitiesChanged" -> - cb.eventuallyExpect(NETWORK_CAPS_UPDATED, timeout) { net == it.network } - "LinkPropertiesChanged" -> - cb.eventuallyExpect(LINK_PROPERTIES_CHANGED, timeout) { net == it.network } - else -> fail("Unknown callback type") - } - } -) |