diff options
author | Polina Koval <kovalp@google.com> | 2022-02-24 10:34:27 +0300 |
---|---|---|
committer | Polina Koval <kovalp@google.com> | 2022-03-02 17:48:26 +0000 |
commit | 558bf658c9155db4db39188aebcd9113692b0e6d (patch) | |
tree | 0eb33d6c16344e577ccaff08cdc7273229eca1da /android/testSrc | |
parent | f7fff88732b166a447adaf7036212346c4e94791 (diff) | |
download | idea-558bf658c9155db4db39188aebcd9113692b0e6d.tar.gz |
Introduce RunnableClientsService instead of direct usage of RunnableClient
Bug: n/a
Test: n/a refactoring
Change-Id: I9a7dec860e17fe60f2047965b1164d1235fc7c0b
Diffstat (limited to 'android/testSrc')
-rw-r--r-- | android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidActivityConfigurationExecutorTest.kt | 8 | ||||
-rw-r--r-- | android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidComplicationConfigurationExecutorTest.kt | 8 | ||||
-rw-r--r-- | android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidTileConfigurationExecutorTest.kt | 6 | ||||
-rw-r--r-- | android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidWatchFaceConfigurationExecutorTest.kt | 6 | ||||
-rw-r--r-- | android/testSrc/com/android/tools/idea/run/configuration/execution/RunnableClientService.kt (renamed from android/testSrc/com/android/tools/idea/run/configuration/execution/RunnableClient.kt) | 86 | ||||
-rw-r--r-- | android/testSrc/com/android/tools/idea/run/debug/AndroidJavaDebuggerTest.kt | 65 |
6 files changed, 97 insertions, 82 deletions
diff --git a/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidActivityConfigurationExecutorTest.kt b/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidActivityConfigurationExecutorTest.kt index 46c640bdd8d..3cc36d1b8c5 100644 --- a/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidActivityConfigurationExecutorTest.kt +++ b/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidActivityConfigurationExecutorTest.kt @@ -79,14 +79,14 @@ internal class AndroidActivityConfigurationExecutorTest : AndroidConfigurationEx val startCommand = "am start -n com.example.app/com.example.app.Component -a android.intent.action.MAIN -c android.intent.category.LAUNCHER -D" val stopCommand = "am force-stop com.example.app" - val runnableClient = RunnableClient(appId, testRootDisposable) + val runnableClientsService = RunnableClientsService(testRootDisposable) val startActivityCommandHandler: CommandHandler = { device, _ -> - runnableClient.startClient(device) + runnableClientsService.startClient(device, appId) } - val stopActivityCommandHandler: CommandHandler = { _, _ -> - runnableClient.stopClient() + val stopActivityCommandHandler: CommandHandler = { device, _ -> + runnableClientsService.stopClient(device, appId) } val device = getMockDevice(mapOf( diff --git a/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidComplicationConfigurationExecutorTest.kt b/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidComplicationConfigurationExecutorTest.kt index 85acf3821ab..7ac6e0034d6 100644 --- a/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidComplicationConfigurationExecutorTest.kt +++ b/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidComplicationConfigurationExecutorTest.kt @@ -171,15 +171,15 @@ class AndroidComplicationConfigurationExecutorTest : AndroidConfigurationExecuto setDebugAppBroadcast to "Broadcast completed: result=1" ).toCommandHandlers() - val runnableClient = RunnableClient(appId, testRootDisposable) + val runnableClientsService = RunnableClientsService(testRootDisposable) val setWatchFaceCommandHandler: CommandHandler = { device, receiver -> - runnableClient.startClient(device) + runnableClientsService.startClient(device, appId) receiver.addOutput("Broadcast completed: result=1") } - val unsetWatchFaceCommandHandler: CommandHandler = { _, receiver -> - runnableClient.stopClient() + val unsetWatchFaceCommandHandler: CommandHandler = { device, receiver -> + runnableClientsService.stopClient(device, appId) receiver.addOutput("Broadcast completed: result=1") } diff --git a/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidTileConfigurationExecutorTest.kt b/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidTileConfigurationExecutorTest.kt index f31adf94238..551aa5047a0 100644 --- a/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidTileConfigurationExecutorTest.kt +++ b/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidTileConfigurationExecutorTest.kt @@ -133,7 +133,7 @@ class AndroidTileConfigurationExecutorTest : AndroidConfigurationExecutorBaseTes // Executor we test. val executor = Mockito.spy(AndroidTileConfigurationExecutor(env)) - val runnableClient = RunnableClient(appId, testRootDisposable) + val runnableClientsService = RunnableClientsService(testRootDisposable) val commandHandlers = mapOf( checkVersion to "Broadcast completed: result=1, data=\"3\"", @@ -142,12 +142,12 @@ class AndroidTileConfigurationExecutorTest : AndroidConfigurationExecutorBaseTes ).toCommandHandlers() val addTileCommandHandler: CommandHandler = { device, receiver -> - runnableClient.startClient(device) + runnableClientsService.startClient(device, appId) receiver.addOutput("Broadcast completed: result=1, Index=[101]") } val removeTileCommandHandler: CommandHandler = { device, receiver -> - runnableClient.stopClient() + runnableClientsService.stopClient(device, appId) receiver.addOutput("Broadcast completed: result=1") } diff --git a/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidWatchFaceConfigurationExecutorTest.kt b/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidWatchFaceConfigurationExecutorTest.kt index d72cb2dc9c2..a0edb2cb141 100644 --- a/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidWatchFaceConfigurationExecutorTest.kt +++ b/android/testSrc/com/android/tools/idea/run/configuration/execution/AndroidWatchFaceConfigurationExecutorTest.kt @@ -104,16 +104,16 @@ class AndroidWatchFaceConfigurationExecutorTest : AndroidConfigurationExecutorBa "Broadcast completed: result=1, data=\"3\"", ).toCommandHandlers() - val runnableClient = RunnableClient(appId, testRootDisposable) + val runnableClientsService = RunnableClientsService(testRootDisposable) val setWatchFaceCommandHandler: CommandHandler = { device, receiver -> - runnableClient.startClient(device) + runnableClientsService.startClient(device, appId) receiver.addOutput("Broadcasting: Intent { act=com.google.android.wearable.app.DEBUG_SURFACE flg=0x400000 (has extras) }\n" + "Broadcast completed: result=1, data=\"Favorite Id=[2] Runtime=[1]\"") } val unsetWatchFaceCommandHandler: CommandHandler = { device, receiver -> - runnableClient.stopClient() + runnableClientsService.stopClient(device, appId) receiver.addOutput("Broadcast completed: result=1") } diff --git a/android/testSrc/com/android/tools/idea/run/configuration/execution/RunnableClient.kt b/android/testSrc/com/android/tools/idea/run/configuration/execution/RunnableClientService.kt index 3684320bbd3..d3b52694fbd 100644 --- a/android/testSrc/com/android/tools/idea/run/configuration/execution/RunnableClient.kt +++ b/android/testSrc/com/android/tools/idea/run/configuration/execution/RunnableClientService.kt @@ -22,6 +22,7 @@ import com.android.ddmlib.internal.ClientImpl import com.android.sdklib.AndroidVersion import com.android.tools.idea.run.DeploymentApplicationService import com.google.common.util.concurrent.ThreadFactoryBuilder +import com.intellij.concurrency.AsyncFutureResultImpl import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager import com.intellij.testFramework.replaceService @@ -38,10 +39,41 @@ import java.util.concurrent.atomic.AtomicBoolean * Adds Client with given appId on IDevice. * * Client become available via [DeploymentApplicationService] and opens a connection for debug when [startClient] is invoked. - * Client closes connection and "removed" from device when [stopClient] is invoked. + * Client closes connection and "removed" from [DeploymentApplicationService] device when [stopClient] is invoked. */ -internal class RunnableClient(private val appId: String, val disposable: Disposable) { - private lateinit var client: Client +internal class RunnableClientsService(testDisposable: Disposable) { + private val deviceToRunnableClients: MutableMap<IDevice, MutableMap<String, RunnableClient>> = mutableMapOf() + private val deploymentApplicationService = TestDeploymentApplicationService() + + init { + ApplicationManager.getApplication() + .replaceService(DeploymentApplicationService::class.java, deploymentApplicationService, testDisposable) + } + + fun stop() { + deviceToRunnableClients.entries.forEach { (device, clients) -> + clients.keys.forEach { appId -> stopClient(device, appId) } + } + } + + fun startClient(device: IDevice, appId: String): Client { + val clients = deviceToRunnableClients.computeIfAbsent(device) { mutableMapOf() } + val runnableClient = RunnableClient.start(device, appId) + clients[appId] = runnableClient + deploymentApplicationService.addClient(device, appId, runnableClient.client) + return runnableClient.client + } + + fun stopClient(device: IDevice, appId: String) { + val runnableClient = deviceToRunnableClients[device]?.get(appId) ?: throw RuntimeException("Client is not started") + runnableClient.stopClient() + deploymentApplicationService.removeClient(device, appId) + deviceToRunnableClients[device]!!.remove(appId) + } +} + +private class RunnableClient private constructor(private val device: IDevice, private val appId: String) { + lateinit var client: Client private val clientSocket: ServerSocket = ServerSocket() private val isRunning = AtomicBoolean() var task: Future<*>? = null @@ -50,12 +82,20 @@ internal class RunnableClient(private val appId: String, val disposable: Disposa .setNameFormat("runnable-client-%d") .build()) + companion object { + fun start(device: IDevice, appId: String): RunnableClient { + val runnableClient = RunnableClient(device, appId) + runnableClient.doStartClient() + return runnableClient + } + } + init { clientSocket.reuseAddress = true clientSocket.bind(InetSocketAddress(InetAddress.getLoopbackAddress(), 0)) } - fun startClient(device: IDevice) { + private fun doStartClient() { // Do not reuse RunnableClient assert(!this::client.isInitialized) client = createMockClient(device, clientSocket.localPort) @@ -76,22 +116,6 @@ internal class RunnableClient(private val appId: String, val disposable: Disposa clientSocket.close() } } - - val testDeploymentApplicationService = object : DeploymentApplicationService { - override fun findClient(iDevice: IDevice, applicationId: String): List<Client> { - if (device == iDevice && applicationId == appId) { - return listOf(client) - } - return emptyList() - } - - override fun getVersion(iDevice: IDevice): Future<AndroidVersion> { - throw RuntimeException("Not implemented for test") - } - } - - ApplicationManager.getApplication() - .replaceService(DeploymentApplicationService::class.java, testDeploymentApplicationService, disposable) } fun stopClient() { @@ -116,4 +140,26 @@ internal class RunnableClient(private val appId: String, val disposable: Disposa return mockClient } +} + +private class TestDeploymentApplicationService : DeploymentApplicationService { + + private val deviceToClients: MutableMap<IDevice, MutableMap<String, Client>> = mutableMapOf() + + fun addClient(device: IDevice, appId: String, client: Client) { + val clients = deviceToClients.computeIfAbsent(device) { mutableMapOf() } + clients[appId] = client + } + + fun removeClient(device: IDevice, appId: String) { + deviceToClients[device]?.remove(appId) + } + + override fun findClient(iDevice: IDevice, applicationId: String): List<Client> { + return deviceToClients[iDevice]?.get(applicationId)?.let { listOf(it) } ?: emptyList() + } + + override fun getVersion(iDevice: IDevice): Future<AndroidVersion> { + return AsyncFutureResultImpl() + } }
\ No newline at end of file diff --git a/android/testSrc/com/android/tools/idea/run/debug/AndroidJavaDebuggerTest.kt b/android/testSrc/com/android/tools/idea/run/debug/AndroidJavaDebuggerTest.kt index f340d4935c8..0acaeb5f86b 100644 --- a/android/testSrc/com/android/tools/idea/run/debug/AndroidJavaDebuggerTest.kt +++ b/android/testSrc/com/android/tools/idea/run/debug/AndroidJavaDebuggerTest.kt @@ -16,11 +16,10 @@ package com.android.tools.idea.run.debug import com.android.ddmlib.Client -import com.android.ddmlib.ClientData import com.android.ddmlib.IDevice -import com.android.ddmlib.internal.ClientImpl import com.android.testutils.MockitoKt.eq import com.android.tools.idea.flags.StudioFlags +import com.android.tools.idea.run.configuration.execution.RunnableClientsService import com.android.tools.idea.run.editor.AndroidJavaDebugger import com.google.common.truth.Truth.assertThat import com.intellij.codeInsight.JavaCodeInsightTestCase @@ -34,10 +33,6 @@ import com.intellij.execution.runners.ExecutionEnvironmentBuilder import com.intellij.execution.runners.GenericProgramRunner import org.junit.Test import org.mockito.Mockito -import java.net.InetAddress -import java.net.InetSocketAddress -import java.net.ServerSocket -import java.util.concurrent.TimeUnit import javax.swing.Icon /** @@ -47,22 +42,21 @@ import javax.swing.Icon */ class AndroidJavaDebuggerTest : JavaCodeInsightTestCase() { private val APP_PACKAGE = "com.android.example" - private val PID = 1111 - private lateinit var clientSocket: ServerSocket + private lateinit var client: Client + private lateinit var runnableClientsService: RunnableClientsService private lateinit var executionEnvironment: ExecutionEnvironment override fun setUp() { super.setUp() StudioFlags.NEW_EXECUTION_FLOW_FOR_JAVA_DEBUGGER.override(true) executionEnvironment = createFakeExecutionEnvironment() - clientSocket = ServerSocket() - clientSocket.reuseAddress = true - clientSocket.bind(InetSocketAddress(InetAddress.getLoopbackAddress(), 0)) + runnableClientsService = RunnableClientsService(testRootDisposable) + client = runnableClientsService.startClient(Mockito.mock(IDevice::class.java), APP_PACKAGE) } override fun tearDown() { - clientSocket.close() + runnableClientsService.stop() StudioFlags.NEW_EXECUTION_FLOW_FOR_JAVA_DEBUGGER.clearOverride() super.tearDown() } @@ -87,46 +81,38 @@ class AndroidJavaDebuggerTest : JavaCodeInsightTestCase() { @Test fun test() { - val port = clientSocket.localPort - val mockClient = createMockClient(Mockito.mock(IDevice::class.java), port) - - val session = attachJavaDebuggerToClient(myProject, mockClient, executionEnvironment, null).blockingGet(1000) + val session = attachJavaDebuggerToClient(myProject, client, executionEnvironment, null).blockingGet(1000) assertThat(session).isNotNull() assertThat(session!!.sessionName).isEqualTo("myConfiguration") } @Test fun testCallback() { - val port = clientSocket.localPort - val mockClient = createMockClient(Mockito.mock(IDevice::class.java), port) - var callbackCount = 0 val onDebugProcessStarted: () -> Unit = { callbackCount++ } - val session = attachJavaDebuggerToClient(myProject, mockClient, executionEnvironment, onDebugProcessStarted = onDebugProcessStarted).blockingGet(1000) + val session = attachJavaDebuggerToClient(myProject, client, executionEnvironment, + onDebugProcessStarted = onDebugProcessStarted).blockingGet(1000) assertThat(session).isNotNull() assertThat(callbackCount).isEqualTo(1) } @Test fun testSessionName() { - val port = clientSocket.localPort - val mockClient = createMockClient(Mockito.mock(IDevice::class.java), port) - - val session = attachJavaDebuggerToClientAndShowTab(myProject, mockClient).blockingGet(1000) + val session = attachJavaDebuggerToClientAndShowTab(myProject, client).blockingGet(1000) assertThat(session).isNotNull() - assertThat(session!!.sessionName).isEqualTo("Android Debugger (pid: 1111, debug port: $port)") + assertThat(client.debuggerListenPort).isAtLeast(0) + assertThat(client.clientData.pid).isAtLeast(0) + assertThat(session!!.sessionName).isEqualTo("Android Debugger (pid: ${client.clientData.pid}, debug port: ${client.debuggerListenPort})") } @Test fun testKillAppOnDestroy() { - val port = clientSocket.localPort - val mockDevice = Mockito.mock(IDevice::class.java) - val mockClient = createMockClient(mockDevice, port) + val mockDevice = client.device - val session = attachJavaDebuggerToClient(myProject, mockClient, executionEnvironment).blockingGet(1000)!! + val session = attachJavaDebuggerToClient(myProject, client, executionEnvironment).blockingGet(1000)!! session.debugProcess.processHandler.destroyProcess() session.debugProcess.processHandler.waitFor() Thread.sleep(100) @@ -135,27 +121,10 @@ class AndroidJavaDebuggerTest : JavaCodeInsightTestCase() { @Test fun testVMExitedNotifierIsInvoked() { - val port = clientSocket.localPort - val mockClient = createMockClient(Mockito.mock(IDevice::class.java), port) - - val session = attachJavaDebuggerToClient(myProject, mockClient, executionEnvironment).blockingGet(1000)!! + val session = attachJavaDebuggerToClient(myProject, client, executionEnvironment).blockingGet(1000)!! session.debugProcess.processHandler.detachProcess() session.debugProcess.processHandler.waitFor() - Mockito.verify(mockClient, Mockito.times(1)).notifyVmMirrorExited() - } - - private fun createMockClient(mockDevice: IDevice, debugPort: Int): Client { - val mockClientData = Mockito.mock(ClientData::class.java) - Mockito.`when`(mockClientData.pid).thenReturn(PID) - Mockito.`when`(mockClientData.packageName).thenReturn(APP_PACKAGE) - Mockito.`when`(mockClientData.clientDescription).thenReturn(APP_PACKAGE) - - val mockClient = Mockito.mock(Client::class.java) - Mockito.`when`(mockClient.clientData).thenReturn(mockClientData) - Mockito.`when`(mockClient.debuggerListenPort).thenReturn(debugPort) - Mockito.`when`(mockClient.device).thenReturn(mockDevice) - - return mockClient + Mockito.verify(client, Mockito.times(1)).notifyVmMirrorExited() } }
\ No newline at end of file |