Refactor: Introduce TestableCallback for EthernetStateListener
The monolithic EthernetStateListener has been refactored and split into two specialized test classes: - TestInterfaceStateListener: For interface state callbacks. - TestEthernetStateListener: For ethernet state callbacks. Both new classes now extend TestableCallback, providing a standardized and more robust way to manage and verify listener interactions in unit tests. This improves testability and clarity of test code. This is a no-op, test-only change. Flag: EXEMPT refactor Test: atest CtsNetTestCases:android.net.cts.EthernetManagerTest Bug: 410731080 Change-Id: I667e3607954dcb073b2732b16bedfbc71a70bb39
This commit is contained in:
parent
bb75ed8900
commit
4c7ba24f57
2 changed files with 203 additions and 214 deletions
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.android.testutils
|
||||
|
||||
import android.net.EthernetManager.ETHERNET_STATE_DISABLED
|
||||
import android.net.EthernetManager.ETHERNET_STATE_ENABLED
|
||||
import android.net.EthernetManager.InterfaceStateListener
|
||||
import android.net.EthernetManager.ROLE_CLIENT
|
||||
import android.net.EthernetManager.ROLE_NONE
|
||||
import android.net.EthernetManager.ROLE_SERVER
|
||||
import android.net.EthernetManager.STATE_ABSENT
|
||||
import android.net.EthernetManager.STATE_LINK_DOWN
|
||||
import android.net.EthernetManager.STATE_LINK_UP
|
||||
import android.net.IpConfiguration
|
||||
import com.android.net.module.util.ArrayTrackRecord
|
||||
import com.android.net.module.util.TrackRecord
|
||||
import java.util.function.IntConsumer
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotNull
|
||||
import kotlin.test.assertNull
|
||||
|
||||
private const val TIMEOUT_MS = 10_000L
|
||||
private const val NO_CALLBACK_TIMEOUT_MS = 500L
|
||||
|
||||
private val DEFAULT_IP_CONFIGURATION = IpConfiguration(
|
||||
IpConfiguration.IpAssignment.DHCP,
|
||||
IpConfiguration.ProxySettings.NONE,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
/**
|
||||
* A listener for both ethernet interface state and ethernet feature state.
|
||||
*
|
||||
* This class can be used to track both onInterfaceStateChanged and onEthernetStateChanged
|
||||
* callbacks from EthernetManager.
|
||||
*/
|
||||
open class EthernetStateListener private constructor(
|
||||
private val history: ArrayTrackRecord<Event>
|
||||
) : InterfaceStateListener, IntConsumer, TrackRecord<EthernetStateListener.Event> by history {
|
||||
constructor() : this(ArrayTrackRecord())
|
||||
|
||||
val events = history.newReadHead()
|
||||
|
||||
sealed class Event {
|
||||
data class InterfaceStateChanged(
|
||||
val iface: String,
|
||||
val state: Int,
|
||||
val role: Int,
|
||||
val configuration: IpConfiguration?
|
||||
) : Event() {
|
||||
override fun toString(): String {
|
||||
val stateString = when (state) {
|
||||
STATE_ABSENT -> "STATE_ABSENT"
|
||||
STATE_LINK_UP -> "STATE_LINK_UP"
|
||||
STATE_LINK_DOWN -> "STATE_LINK_DOWN"
|
||||
else -> state.toString()
|
||||
}
|
||||
val roleString = when (role) {
|
||||
ROLE_NONE -> "ROLE_NONE"
|
||||
ROLE_CLIENT -> "ROLE_CLIENT"
|
||||
ROLE_SERVER -> "ROLE_SERVER"
|
||||
else -> role.toString()
|
||||
}
|
||||
return ("InterfaceStateChanged(iface=$iface, state=$stateString, " +
|
||||
"role=$roleString, ipConfig=$configuration)")
|
||||
}
|
||||
}
|
||||
|
||||
data class EthernetStateChanged(val state: Int) : Event() {
|
||||
override fun toString(): String {
|
||||
val stateString = when (state) {
|
||||
ETHERNET_STATE_ENABLED -> "ETHERNET_STATE_ENABLED"
|
||||
ETHERNET_STATE_DISABLED -> "ETHERNET_STATE_DISABLED"
|
||||
else -> state.toString()
|
||||
}
|
||||
return "EthernetStateChanged(state=$stateString)"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInterfaceStateChanged(
|
||||
iface: String,
|
||||
state: Int,
|
||||
role: Int,
|
||||
cfg: IpConfiguration?
|
||||
) {
|
||||
add(Event.InterfaceStateChanged(iface, state, role, cfg))
|
||||
}
|
||||
|
||||
override fun accept(state: Int) {
|
||||
add(Event.EthernetStateChanged(state))
|
||||
}
|
||||
|
||||
fun <T : Event> expectCallback(expected: T): T {
|
||||
val event = events.poll(TIMEOUT_MS)
|
||||
assertEquals(expected, event)
|
||||
return event as T
|
||||
}
|
||||
|
||||
fun expectCallback(ifaceName: String, state: Int, role: Int) {
|
||||
expectCallback(createChangeEvent(ifaceName, state, role))
|
||||
}
|
||||
|
||||
fun expectCallback(state: Int) {
|
||||
expectCallback(Event.EthernetStateChanged(state))
|
||||
}
|
||||
|
||||
private fun createChangeEvent(iface: String, state: Int, role: Int) =
|
||||
Event.InterfaceStateChanged(
|
||||
iface,
|
||||
state,
|
||||
role,
|
||||
if (state != STATE_ABSENT) DEFAULT_IP_CONFIGURATION else null
|
||||
)
|
||||
|
||||
fun eventuallyExpect(expected: Event) {
|
||||
val cb = events.poll(TIMEOUT_MS) { it == expected }
|
||||
assertNotNull(cb, "Never received expected $expected. Received: ${events.backtrace()}")
|
||||
}
|
||||
|
||||
fun eventuallyExpect(ifaceName: String, state: Int, role: Int) {
|
||||
eventuallyExpect(createChangeEvent(ifaceName, state, role))
|
||||
}
|
||||
|
||||
fun eventuallyExpect(state: Int) {
|
||||
eventuallyExpect(Event.EthernetStateChanged(state))
|
||||
}
|
||||
|
||||
fun assertNoCallback() {
|
||||
val cb = events.poll(NO_CALLBACK_TIMEOUT_MS)
|
||||
assertNull(cb, "Expected no callback but got $cb")
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
package com.android.testutils
|
||||
|
||||
import android.net.EthernetManager.ETHERNET_STATE_DISABLED
|
||||
import android.net.EthernetManager.ETHERNET_STATE_ENABLED
|
||||
import android.net.EthernetManager.InterfaceStateListener
|
||||
import android.net.EthernetManager.ROLE_CLIENT
|
||||
import android.net.EthernetManager.ROLE_NONE
|
||||
import android.net.EthernetManager.ROLE_SERVER
|
||||
import android.net.EthernetManager.STATE_ABSENT
|
||||
import android.net.EthernetManager.STATE_LINK_DOWN
|
||||
import android.net.EthernetManager.STATE_LINK_UP
|
||||
import android.net.IpConfiguration
|
||||
import com.android.net.module.util.TestableCallback
|
||||
import com.android.testutils.TestEthernetStateListener.EthernetStateChanged
|
||||
import com.android.testutils.TestInterfaceStateListener.InterfaceStateChanged
|
||||
import java.util.function.IntConsumer
|
||||
|
||||
private val DEFAULT_IP_CONFIGURATION = IpConfiguration(
|
||||
IpConfiguration.IpAssignment.DHCP,
|
||||
IpConfiguration.ProxySettings.NONE,
|
||||
null,
|
||||
null
|
||||
)
|
||||
|
||||
/**
|
||||
* A test listener for interface state.
|
||||
*/
|
||||
class TestInterfaceStateListener : TestableCallback<InterfaceStateChanged>(),
|
||||
InterfaceStateListener {
|
||||
data class InterfaceStateChanged(
|
||||
val iface: String,
|
||||
val state: Int,
|
||||
val role: Int,
|
||||
val configuration: IpConfiguration?
|
||||
) {
|
||||
override fun toString(): String {
|
||||
val stateString = when (state) {
|
||||
STATE_ABSENT -> "STATE_ABSENT"
|
||||
STATE_LINK_UP -> "STATE_LINK_UP"
|
||||
STATE_LINK_DOWN -> "STATE_LINK_DOWN"
|
||||
else -> state.toString()
|
||||
}
|
||||
val roleString = when (role) {
|
||||
ROLE_NONE -> "ROLE_NONE"
|
||||
ROLE_CLIENT -> "ROLE_CLIENT"
|
||||
ROLE_SERVER -> "ROLE_SERVER"
|
||||
else -> role.toString()
|
||||
}
|
||||
return ("InterfaceStateChanged(iface=$iface, state=$stateString, " +
|
||||
"role=$roleString, ipConfig=$configuration)")
|
||||
}
|
||||
}
|
||||
|
||||
override fun onInterfaceStateChanged(
|
||||
iface: String,
|
||||
state: Int,
|
||||
role: Int,
|
||||
configuration: IpConfiguration?,
|
||||
) {
|
||||
history.add(InterfaceStateChanged(iface, state, role, configuration))
|
||||
}
|
||||
|
||||
fun expectInterfaceStateChanged(
|
||||
iface: String,
|
||||
state: Int,
|
||||
role: Int,
|
||||
timeoutMs: Long = defaultTimeoutMs
|
||||
): InterfaceStateChanged = expect(timeoutMs = timeoutMs) {
|
||||
val expectedConfig = if (state != STATE_ABSENT) DEFAULT_IP_CONFIGURATION else null
|
||||
it.iface == iface && it.state == state && it.role == role &&
|
||||
it.configuration == expectedConfig
|
||||
}
|
||||
|
||||
fun eventuallyExpectInterfaceStateChanged(
|
||||
iface: String,
|
||||
state: Int,
|
||||
role: Int,
|
||||
timeoutMs: Long = defaultTimeoutMs
|
||||
): InterfaceStateChanged = eventuallyExpect(timeoutMs = timeoutMs) {
|
||||
val expectedConfig = if (state != STATE_ABSENT) DEFAULT_IP_CONFIGURATION else null
|
||||
it.iface == iface && it.state == state && it.role == role &&
|
||||
it.configuration == expectedConfig
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A test listener for ethernet state.
|
||||
*/
|
||||
class TestEthernetStateListener : TestableCallback<EthernetStateChanged>(), IntConsumer {
|
||||
data class EthernetStateChanged(val state: Int) {
|
||||
override fun toString(): String {
|
||||
val stateString = when (state) {
|
||||
ETHERNET_STATE_ENABLED -> "ETHERNET_STATE_ENABLED"
|
||||
ETHERNET_STATE_DISABLED -> "ETHERNET_STATE_DISABLED"
|
||||
else -> state.toString()
|
||||
}
|
||||
return "EthernetStateChanged(state=$stateString)"
|
||||
}
|
||||
}
|
||||
|
||||
override fun accept(state: Int) {
|
||||
history.add(EthernetStateChanged(state))
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue