Refactor: Add RestoreEthernetRule for ethernet tests
This is a no-op, test only refactoring.
Move ethernet state management logic from EthernetManagerTest into a
dedicated JUnit test rule, RestoreEthernetRule. This new rule is
responsible for saving the initial ethernet state, allowing tests to
enable or disable it, and restoring the original state upon test
completion. This refactoring simplifies EthernetManagerTest and
promotes code reuse.
Flag: EXEMPT EXEMPT test only refacotring
Test: atest NetworkStaticLibTests:com.android.testutils.RestoreEthernetRuleTest \
CtsNetTestCases:android.net.cts.EthernetManagerTest --update-device
Bug: 410731080
Change-Id: If3dd869d6af4e0c659386621fb5d92012aa574d1
This commit is contained in:
parent
7e816d5d07
commit
9f6a566d89
3 changed files with 231 additions and 57 deletions
|
|
@ -17,6 +17,7 @@ android_library {
|
|||
defaults: ["framework-connectivity-test-defaults"],
|
||||
static_libs: [
|
||||
"androidx.test.rules",
|
||||
"mockito-kotlin2",
|
||||
"mockito-target-extended-minus-junit4",
|
||||
"netd-client",
|
||||
"net-tests-utils",
|
||||
|
|
|
|||
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* 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.os.Build
|
||||
import org.junit.Test
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runner.RunWith
|
||||
import org.junit.runners.model.Statement
|
||||
import org.mockito.kotlin.any
|
||||
import org.mockito.kotlin.doAnswer
|
||||
import org.mockito.kotlin.doCallRealMethod
|
||||
import org.mockito.kotlin.doReturn
|
||||
import org.mockito.kotlin.inOrder
|
||||
import org.mockito.kotlin.mock
|
||||
import org.mockito.kotlin.never
|
||||
import org.mockito.kotlin.verify
|
||||
|
||||
// EthernetManager#addEthernetStateListener is not supported before T.
|
||||
@DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.S_V2)
|
||||
@RunWith(DevSdkIgnoreRunner::class)
|
||||
class RestoreEthernetRuleTest {
|
||||
private val mockStatement = mock<Statement>()
|
||||
private val mockDescription = mock<Description>()
|
||||
|
||||
private val rule = mock<RestoreEthernetRule> {
|
||||
on { setEthernetEnabled(any()) } doAnswer { }
|
||||
on { apply(any(), any()) }.thenCallRealMethod()
|
||||
}
|
||||
|
||||
private fun doTestApply_stateUnchanged(initialState: Boolean) {
|
||||
doReturn(initialState, initialState).`when`(rule).isEthernetEnabled()
|
||||
|
||||
rule.apply(mockStatement, mockDescription).evaluate()
|
||||
|
||||
verify(mockStatement).evaluate()
|
||||
verify(rule, never()).setEthernetEnabled(any())
|
||||
}
|
||||
|
||||
private fun doTestApply_restoresInitialState(initialState: Boolean) {
|
||||
doReturn(initialState, !initialState).`when`(rule).isEthernetEnabled()
|
||||
|
||||
rule.apply(mockStatement, mockDescription).evaluate()
|
||||
|
||||
val inOrder = inOrder(mockStatement, rule)
|
||||
inOrder.verify(mockStatement).evaluate()
|
||||
inOrder.verify(rule).setEthernetEnabled(initialState)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testApply_stateUnchanged_wasEnabled() = doTestApply_stateUnchanged(initialState = true)
|
||||
|
||||
@Test
|
||||
fun testApply_stateUnchanged_wasDisabled() = doTestApply_stateUnchanged(initialState = false)
|
||||
|
||||
@Test
|
||||
fun testApply_restoresInitialState_wasEnabled() =
|
||||
doTestApply_restoresInitialState(initialState = true)
|
||||
|
||||
@Test
|
||||
fun testApply_restoresInitialState_wasDisabled() =
|
||||
doTestApply_restoresInitialState(initialState = false)
|
||||
|
||||
@Test(expected = IllegalArgumentException::class)
|
||||
fun testSetEthernetEnabled_throwsWhenDisablingWithAdbOverEthernet() {
|
||||
doReturn(true).`when`(rule).isAdbOverEthernet()
|
||||
// Override the default mock behavior for setEthernetEnabled().
|
||||
// The test needs to call the real method to verify that it throws an exception.
|
||||
doCallRealMethod().`when`(rule).setEthernetEnabled(false)
|
||||
|
||||
rule.setEthernetEnabled(false)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,115 @@
|
|||
/*
|
||||
* 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.Manifest.permission.NETWORK_SETTINGS
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.net.EthernetManager
|
||||
import android.net.EthernetManager.ETHERNET_STATE_DISABLED
|
||||
import android.net.EthernetManager.ETHERNET_STATE_ENABLED
|
||||
import android.os.SystemProperties
|
||||
import com.android.testutils.TestEthernetStateListener.EthernetStateChanged
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.util.concurrent.Executor
|
||||
import org.junit.rules.TestRule
|
||||
import org.junit.runner.Description
|
||||
import org.junit.runners.model.Statement
|
||||
|
||||
/**
|
||||
* A JUnit rule to save and restore ethernet state during tests.
|
||||
*
|
||||
* This rule ensures that the ethernet state (enabled/disabled) is returned to its original
|
||||
* value after each test. It also provides a utility method to change the state and wait for
|
||||
* the change to be applied.
|
||||
*
|
||||
* This rule requires shell permissions to function correctly.
|
||||
*/
|
||||
open class RestoreEthernetRule(private val context: Context) : TestRule {
|
||||
// Callers should ensure isEthernetSupported() before invoking anything needs
|
||||
// the EthernetManager instance. Otherwise, this would throw.
|
||||
private val em by lazy { context.getSystemService(EthernetManager::class.java)!! }
|
||||
private val inlineExecutor = Executor { r -> r.run() }
|
||||
|
||||
override fun apply(base: Statement, description: Description): Statement {
|
||||
return object : Statement() {
|
||||
override fun evaluate() {
|
||||
val wasEnabled = isEthernetEnabled()
|
||||
try {
|
||||
base.evaluate()
|
||||
} finally {
|
||||
if (wasEnabled != isEthernetEnabled()) {
|
||||
setEthernetEnabled(wasEnabled)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ethernet enabled state and waits for the change to be confirmed.
|
||||
*
|
||||
* @param enabled The desired ethernet state.
|
||||
*/
|
||||
@SuppressLint("MissingPermission")
|
||||
open fun setEthernetEnabled(enabled: Boolean) {
|
||||
if (isAdbOverEthernet() && !enabled) {
|
||||
throw IllegalArgumentException("Ethernet should not be disabled when adb over ethernet")
|
||||
}
|
||||
val listener = TestEthernetStateListener()
|
||||
em.addEthernetStateListener(inlineExecutor, listener)
|
||||
try {
|
||||
runAsShell(NETWORK_SETTINGS) { em.setEthernetEnabled(enabled) }
|
||||
listener.eventuallyExpect<EthernetStateChanged> {
|
||||
it.state == if (enabled) ETHERNET_STATE_ENABLED else ETHERNET_STATE_DISABLED
|
||||
}
|
||||
} finally {
|
||||
em.removeEthernetStateListener(listener)
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
open fun isAdbOverEthernet(): Boolean {
|
||||
// If no ethernet interface is available, adb is not connected over ethernet.
|
||||
val ifaces = runAsShell(NETWORK_SETTINGS) { em.interfaceList }
|
||||
if (ifaces.isEmpty()) return false
|
||||
|
||||
// cuttlefish is special and does not connect adb over ethernet.
|
||||
if (SystemProperties.get("ro.product.board", "") == "cutf") return false
|
||||
|
||||
// Check if adb is connected over the network.
|
||||
return (SystemProperties.getInt("persist.adb.tcp.port", -1) > -1 ||
|
||||
SystemProperties.getInt("service.adb.tcp.port", -1) > -1)
|
||||
}
|
||||
|
||||
open fun isEthernetSupported() = context.getSystemService(EthernetManager::class.java) != null
|
||||
|
||||
@SuppressLint("MissingPermission")
|
||||
open fun isEthernetEnabled(): Boolean {
|
||||
val listener = TestEthernetStateListener()
|
||||
runAsShell(NETWORK_SETTINGS) {
|
||||
em.addEthernetStateListener(inlineExecutor, listener)
|
||||
}
|
||||
try {
|
||||
val event = listener.expect<EthernetStateChanged>()
|
||||
return event.state == ETHERNET_STATE_ENABLED
|
||||
} finally {
|
||||
runAsShell(NETWORK_SETTINGS) {
|
||||
em.removeEthernetStateListener(listener)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in a new issue