Make ShellCommandTest call real messenger
By calling real messenger, and only mocking the service API, we are
making sure that the messenger works as expected
Bug: 391437857
Test: atest ServiceBluetoothRoboTests
Flag: TEST_ONLY
Change-Id: I3c106fa0011ddfb829dc6a8cd0f9b2e823e9d394
diff --git a/service/Android.bp b/service/Android.bp
index af08d30..28ef86c 100644
--- a/service/Android.bp
+++ b/service/Android.bp
@@ -147,10 +147,12 @@
"src/BluetoothRestrictionTest.kt",
"src/Log.kt",
"src/LogTest.kt",
+ "src/PermissionChecker.kt",
"src/RadioModeListener.kt",
"src/RadioModeListenerTest.kt",
"src/RolePermissionListener.kt",
"src/RolePermissionListenerTest.kt",
+ "src/ServiceMessenger.kt",
"src/SharingRestriction.kt",
"src/SharingRestrictionTest.kt",
"src/ShellCommand.kt",
@@ -171,10 +173,11 @@
"bluetooth-proto-enums-java-gen",
"bluetooth_flags_java_lib",
"flag-junit",
+ "inline-mockito-robolectric-prebuilt",
"kotlin-test",
"kotlinx_coroutines",
"kotlinx_coroutines_test",
- "mockito-robolectric-prebuilt",
+ "mockito-kotlin-nodeps",
"modules-utils-preconditions",
"modules-utils-shell-command-handler",
"platform-test-annotations",
@@ -187,6 +190,7 @@
"PlatformProperties",
"framework-annotations-lib",
"framework-statsd.stubs.module_lib",
+ "service-bluetooth.change-ids",
],
jacoco: {
diff --git a/service/src/ShellCommandTest.kt b/service/src/ShellCommandTest.kt
index 6af7cc0..a10fac3 100644
--- a/service/src/ShellCommandTest.kt
+++ b/service/src/ShellCommandTest.kt
@@ -17,23 +17,18 @@
package com.android.server.bluetooth.test
import android.bluetooth.IBluetoothManager
-import android.bluetooth.IBluetoothManagerCallback
import android.bluetooth.State
-import android.content.AttributionSource
import android.os.Binder
-import android.os.Handler
import android.os.HandlerThread
-import android.os.IBinder
-import android.os.Message
-import android.os.Messenger
import android.os.ParcelFileDescriptor
import android.os.Process
-import android.os.RemoteException
import android.platform.test.flag.junit.SetFlagsRule
import androidx.test.filters.SmallTest
import com.android.bluetooth.flags.Flags
+import com.android.server.bluetooth.BluetoothManagerServiceApi
+import com.android.server.bluetooth.PermissionChecker
+import com.android.server.bluetooth.ServiceMessenger
import com.android.server.bluetooth.ShellCommand
-import com.android.server.bluetooth.SystemServiceMessage
import com.android.tests.bluetooth.FlagsWrapper
import com.google.common.truth.Truth.assertThat
import org.junit.After
@@ -43,6 +38,12 @@
import org.junit.Test
import org.junit.rules.TestName
import org.junit.runner.RunWith
+import org.mockito.kotlin.any
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.verify
+import org.mockito.kotlin.whenever
import org.robolectric.ParameterizedRobolectricTestRunner
import org.robolectric.ParameterizedRobolectricTestRunner.Parameters
import org.robolectric.shadows.ShadowBinder
@@ -53,7 +54,10 @@
@get:Rule val mSetFlagsRule: SetFlagsRule = SetFlagsRule(flags.flags)
@get:Rule val testName = TestName()
- private lateinit var testBinder: FakeBinder
+ private val mockApi: BluetoothManagerServiceApi = mock()
+ private val mockPermissionChecker: PermissionChecker = mock()
+ private val mockBinder: IBluetoothManager.Stub = mock()
+
private val testWaitForState: (Int) -> Boolean = {
waitForStateCalledWith = it
returnValue
@@ -62,16 +66,17 @@
private lateinit var shellCommand: ShellCommand
private lateinit var outPipe: Array<ParcelFileDescriptor>
+ private lateinit var handlerThread: HandlerThread
@Before
fun setUp() {
- testBinder = FakeBinder()
- testBinder.returnValue = returnValue
-
waitForStateCalledWith = null
outPipe = ParcelFileDescriptor.createPipe()
+ handlerThread = HandlerThread("ShellCommandTestHandler").apply { start() }
- shellCommand = ShellCommand(testBinder, testBinder.messenger, testWaitForState)
+ val serviceMessenger =
+ ServiceMessenger(handlerThread.looper, mockPermissionChecker, mockApi)
+ shellCommand = ShellCommand(mockBinder, serviceMessenger.messenger, testWaitForState)
shellCommand.init(
Binder(),
@@ -81,12 +86,25 @@
arrayOf(),
-1,
)
+
+ // Mock API and Binder calls to return the parameterized value
+ doReturn(returnValue).whenever(mockApi).enable(any(), any())
+ doReturn(returnValue).whenever(mockApi).enableBle(any(), any())
+ doReturn(returnValue).whenever(mockApi).enableNoAutoConnect(any())
+ doReturn(returnValue).whenever(mockApi).disable(any(), any())
+ doReturn(returnValue).whenever(mockApi).disableBle(any(), any())
+ doReturn(returnValue).whenever(mockApi).factoryReset(any())
+ doReturn(returnValue).whenever(mockBinder).enable(any())
+ doReturn(returnValue).whenever(mockBinder).disable(any(), any())
+ doReturn(returnValue).whenever(mockBinder).enableBle(any(), any())
+ doReturn(returnValue).whenever(mockBinder).disableBle(any(), any())
+ doReturn(returnValue).whenever(mockBinder).factoryReset(any())
}
@After
fun tearDown() {
outPipe.forEach { it.close() }
- testBinder.cleanup()
+ handlerThread.quitSafely()
}
@Test
@@ -108,11 +126,9 @@
fun onCommand_enable() {
assertThat(shellCommand.onCommand("enable")).isEqualTo(if (returnValue) 0 else -1)
if (Flags.systemServerMessenger()) {
- assertThat(testBinder.enableMessageReceived).isTrue()
- assertThat(testBinder.enableCalled).isFalse()
+ verify(mockApi).enable(any(), any())
} else {
- assertThat(testBinder.enableMessageReceived).isFalse()
- assertThat(testBinder.enableCalled).isTrue()
+ verify(mockBinder).enable(any())
}
}
@@ -121,11 +137,9 @@
ShadowBinder.setCallingUid(Process.ROOT_UID)
assertThat(shellCommand.onCommand("enableBle")).isEqualTo(if (returnValue) 0 else -1)
if (Flags.systemServerMessenger()) {
- assertThat(testBinder.enableBleMessageReceived).isTrue()
- assertThat(testBinder.enableBleCalledWithBinder).isNull()
+ verify(mockApi).enableBle(any(), eq(mockBinder))
} else {
- assertThat(testBinder.enableBleMessageReceived).isFalse()
- assertThat(testBinder.enableBleCalledWithBinder).isSameInstanceAs(testBinder)
+ verify(mockBinder).enableBle(any(), eq(mockBinder))
}
}
@@ -133,11 +147,9 @@
fun onCommand_disable() {
assertThat(shellCommand.onCommand("disable")).isEqualTo(if (returnValue) 0 else -1)
if (Flags.systemServerMessenger()) {
- assertThat(testBinder.disableMessageReceived).isTrue()
- assertThat(testBinder.disableCalledWithPersist).isNull()
+ verify(mockApi).disable(any(), eq(true))
} else {
- assertThat(testBinder.disableMessageReceived).isFalse()
- assertThat(testBinder.disableCalledWithPersist).isTrue()
+ verify(mockBinder).disable(any(), eq(true))
}
}
@@ -146,11 +158,9 @@
ShadowBinder.setCallingUid(Process.ROOT_UID)
assertThat(shellCommand.onCommand("disableBle")).isEqualTo(if (returnValue) 0 else -1)
if (Flags.systemServerMessenger()) {
- assertThat(testBinder.disableBleMessageReceived).isTrue()
- assertThat(testBinder.disableBleCalledWithBinder).isNull()
+ verify(mockApi).disableBle(any(), eq(mockBinder))
} else {
- assertThat(testBinder.disableBleMessageReceived).isFalse()
- assertThat(testBinder.disableBleCalledWithBinder).isSameInstanceAs(testBinder)
+ verify(mockBinder).disableBle(any(), eq(mockBinder))
}
}
@@ -168,11 +178,9 @@
assertThat(shellCommand.onCommand("factoryReset")).isEqualTo(if (returnValue) 0 else -1)
if (Flags.systemServerMessenger()) {
- assertThat(testBinder.factoryResetMessageReceived).isTrue()
- assertThat(testBinder.factoryResetCalled).isFalse()
+ verify(mockApi).factoryReset(any())
} else {
- assertThat(testBinder.factoryResetMessageReceived).isFalse()
- assertThat(testBinder.factoryResetCalled).isTrue()
+ verify(mockBinder).factoryReset(any())
}
}
@@ -196,128 +204,6 @@
assertThat(waitForStateCalledWith).isNull()
}
- class FakeBinder : IBluetoothManager.Stub() {
- var returnValue: Boolean = true
-
- var enableCalled: Boolean = false
- var disableCalledWithPersist: Boolean? = null
- var enableBleCalledWithBinder: IBinder? = null
- var disableBleCalledWithBinder: IBinder? = null
- var factoryResetCalled: Boolean = false
-
- var enableMessageReceived = false
- var disableMessageReceived = false
- var enableBleMessageReceived = false
- var disableBleMessageReceived = false
- var factoryResetMessageReceived = false
-
- private val handlerThread = HandlerThread("FakeBinderHandler").apply { start() }
-
- private val handler =
- object : Handler(handlerThread.looper) {
- override fun handleMessage(msg: Message) {
- val reply = Message.obtain()
- when (val received = msg.obj) {
- is SystemServiceMessage.Enable -> {
- if (received.bleToken != null) {
- enableBleMessageReceived = true
- } else {
- enableMessageReceived = true
- }
- reply.obj =
- SystemServiceMessage.Enable.Reply().apply { value = returnValue }
- }
- is SystemServiceMessage.Disable -> {
- if (received.bleToken != null) {
- disableBleMessageReceived = true
- } else {
- disableMessageReceived = true
- }
- reply.obj =
- SystemServiceMessage.Disable.Reply().apply { value = returnValue }
- }
- is SystemServiceMessage.FactoryReset -> {
- factoryResetMessageReceived = true
- reply.obj =
- SystemServiceMessage.FactoryReset.Reply().apply {
- value = returnValue
- }
- }
- else -> {
- super.handleMessage(msg)
- return
- }
- }
-
- try {
- msg.replyTo?.send(reply)
- } catch (e: RemoteException) {
- // Ignore
- }
- }
- }
-
- val messenger = Messenger(handler)
-
- fun cleanup() {
- handlerThread.quitSafely()
- }
-
- override fun getServiceMessenger() = if (Flags.systemServerMessenger()) messenger else null
-
- override fun enable(source: AttributionSource): Boolean {
- enableCalled = true
- return returnValue
- }
-
- override fun disable(source: AttributionSource, persist: Boolean): Boolean {
- disableCalledWithPersist = persist
- return returnValue
- }
-
- override fun enableBle(source: AttributionSource, token: IBinder): Boolean {
- enableBleCalledWithBinder = token
- return returnValue
- }
-
- override fun disableBle(source: AttributionSource, token: IBinder): Boolean {
- disableBleCalledWithBinder = token
- return returnValue
- }
-
- override fun factoryReset(source: AttributionSource): Boolean {
- factoryResetCalled = true
- return returnValue
- }
-
- // Other method that we do not care about
- override fun registerAdapter(callback: IBluetoothManagerCallback) = null
-
- override fun unregisterAdapter(callback: IBluetoothManagerCallback) {}
-
- override fun getState() = State.OFF
-
- override fun getAddress(source: AttributionSource) = null
-
- override fun getName(source: AttributionSource) = null
-
- override fun isHearingAidProfileSupported() = false
-
- override fun isBleScanAvailable() = false
-
- override fun setBtHciSnoopLogMode(mode: Int) = 0
-
- override fun getBtHciSnoopLogMode() = 0
-
- override fun isAutoOnSupported() = false
-
- override fun isAutoOnEnabled() = false
-
- override fun setAutoOnEnabled(status: Boolean) {}
-
- override fun enableNoAutoConnect(source: AttributionSource) = false
- }
-
companion object {
@JvmStatic
@Parameters(name = "{0}|{1}")