diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/AgentAction.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/AgentAction.kt index 259eb0747db5..a8957178b0f6 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/AgentAction.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/AgentAction.kt @@ -1,6 +1,5 @@ package com.intellij.remoteDev.tests -import com.jetbrains.rd.framework.impl.RdTask import org.jetbrains.annotations.ApiStatus import kotlin.time.Duration @@ -8,4 +7,4 @@ import kotlin.time.Duration * Represents a single test action in a distributed test */ @ApiStatus.Internal -class AgentAction(val action: (AgentContext) -> RdTask, val title: String, val expectBlockedEdt: Boolean) \ No newline at end of file +class AgentAction(val title: String, val timeout: Duration, val fromEdt: Boolean, val action: suspend (AgentContext) -> String?) \ No newline at end of file diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/DistributedTestBridge.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/DistributedTestBridge.kt index c6d753a18c8f..a0ba0c6b4271 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/DistributedTestBridge.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/DistributedTestBridge.kt @@ -20,6 +20,5 @@ interface DistributedTestBridge { * in protocol `IDE` <-> `IDE` because test framework works via * different protocol `IDE` <-> `Test Process` */ - fun syncProtocolEvents() - + suspend fun syncProtocolEvents() } \ No newline at end of file diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/DistributedTestPlayer.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/DistributedTestPlayer.kt index 456032552bc4..9286d037f9fe 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/DistributedTestPlayer.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/DistributedTestPlayer.kt @@ -2,7 +2,7 @@ package com.intellij.remoteDev.tests import org.jetbrains.annotations.ApiStatus import java.lang.reflect.Method -import java.util.* +import java.util.Queue /** * This internal interface should be implemented by distributed tests @@ -10,7 +10,7 @@ import java.util.* */ @ApiStatus.Internal interface DistributedTestPlayer { - fun initAgent(agent: AgentInfo): Pair, LinkedList> + fun initAgent(agent: AgentInfo): Queue fun performInit(method: Method) } diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/DistributedTestHost.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/DistributedTestHost.kt index fd40909ec89e..85b29fd061e9 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/DistributedTestHost.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/DistributedTestHost.kt @@ -4,7 +4,7 @@ import com.intellij.codeWithMe.ClientId import com.intellij.codeWithMe.ClientId.Companion.isLocal import com.intellij.diagnostic.DebugLogManager import com.intellij.diagnostic.LoadingState -import com.intellij.ide.IdeEventQueue +import com.intellij.diagnostic.enableCoroutineDump import com.intellij.ide.impl.ProjectUtil import com.intellij.notification.Notification import com.intellij.notification.NotificationType @@ -24,15 +24,12 @@ import com.intellij.remoteDev.tests.modelGenerated.RdTestSession import com.intellij.remoteDev.tests.modelGenerated.distributedTestModel import com.intellij.ui.WinFocusStealer import com.intellij.util.ui.ImageUtil -import com.intellij.util.ui.UIUtil import com.jetbrains.rd.framework.* -import com.jetbrains.rd.framework.impl.RdTask -import com.jetbrains.rd.framework.util.launch +import com.jetbrains.rd.framework.util.setSuspend import com.jetbrains.rd.util.lifetime.EternalLifetime import com.jetbrains.rd.util.lifetime.Lifetime -import com.jetbrains.rd.util.measureTimeMillis import com.jetbrains.rd.util.reactive.viewNotNull -import com.jetbrains.rd.util.threading.SynchronousScheduler +import com.jetbrains.rd.util.threading.asRdScheduler import kotlinx.coroutines.* import org.jetbrains.annotations.ApiStatus import org.jetbrains.annotations.TestOnly @@ -43,11 +40,10 @@ import java.io.File import java.net.InetAddress import java.time.LocalDateTime import java.time.format.DateTimeFormatter -import java.util.concurrent.ExecutionException -import java.util.concurrent.TimeoutException import javax.imageio.ImageIO import kotlin.reflect.full.createInstance import kotlin.time.Duration.Companion.milliseconds +import kotlin.time.Duration.Companion.minutes @TestOnly @ApiStatus.Internal @@ -100,20 +96,10 @@ open class DistributedTestHost(coroutineScope: CoroutineScope) { } } - private fun Application.flushQueueFromAnyThread() { - LOG.info("Flush queue...") - if (isDispatchThread) { - // Flush all events to process pending protocol events and other things - // before actual test method execution - IdeEventQueue.getInstance().flushQueue() - } - else { - UIUtil.pump() - } - } - + @OptIn(ExperimentalCoroutinesApi::class) private fun createProtocol(hostAddress: InetAddress, port: Int) { LOG.info("Creating protocol...") + enableCoroutineDump() // EternalLifetime.createNested() is used intentionally to make sure logger session's lifetime is not terminated before the actual application stop. val lifetime = EternalLifetime.createNested() @@ -151,139 +137,103 @@ open class DistributedTestHost(coroutineScope: CoroutineScope) { // Tell test we are running it inside an agent val agentInfo = AgentInfo(session.agentInfo, session.testClassName, session.testMethodName) - val (queue, bgQueue) = testClassObject.initAgent(agentInfo) + val queue = testClassObject.initAgent(agentInfo) // Play test method val testMethod = testClass.getMethod(session.testMethodName) testClassObject.performInit(testMethod) testMethod.invoke(testClassObject) - fun runAction(agentAction: AgentAction): RdTask { - val actionTitle = agentAction.title - val expectBlockedEdt = agentAction.expectBlockedEdt + // Advice for processing events + session.runNextAction.setSuspend(handlerScheduler = Dispatchers.Default.asRdScheduler) { _, _ -> + val action = queue.remove() + val actionTitle = action.title + val timeout = action.timeout + val requestFocus = action.fromEdt try { assert(ClientId.current.isLocal) { "ClientId '${ClientId.current}' should be local when test method starts" } - LOG.info("'$actionTitle': preparing to start action on ${Thread.currentThread().name}, " + - "expectBlockedEdt=$expectBlockedEdt") + LOG.info("'$actionTitle': received action execution request") - if (app.isDispatchThread) { - projectOrNull?.let { + val dispatcher = if (action.fromEdt) Dispatchers.EDT else Dispatchers.Default + return@setSuspend withContext(dispatcher) { + if (action.fromEdt) { // Sync state across all IDE agents to maintain proper order in protocol events - LOG.info("'$actionTitle': Sync protocol events before execution...") - val elapsedSync = measureTimeMillis { - DistributedTestBridge.getInstance().syncProtocolEvents() + // we don't wat to sync state in case of bg task, as it may be launched with blocked UI thread + runLogged("'$actionTitle': Sync protocol events before execution") { + withTimeout(3.minutes) { + DistributedTestBridge.getInstance().syncProtocolEvents() + } } - LOG.info("'$actionTitle': Protocol state sync completed in ${elapsedSync}ms") } + + if (!app.isHeadlessEnvironment && isNotRdHost && requestFocus) { + requestFocus(actionTitle) + } + + showNotification("${session.agentInfo.id}: $actionTitle") + + val agentContext = when (session.agentInfo.agentType) { + RdAgentType.HOST -> HostAgentContextImpl(session.agentInfo, protocol) + RdAgentType.CLIENT -> ClientAgentContextImpl(session.agentInfo, protocol) + RdAgentType.GATEWAY -> GatewayAgentContextImpl(session.agentInfo, protocol) + } + + val result = runLogged(actionTitle, timeout) { + action.action(agentContext) + } + + // Assert state + assertLoggerFactory() + + result } - - if (!expectBlockedEdt) { - app.flushQueueFromAnyThread() - } - - if (!app.isHeadlessEnvironment && isNotRdHost && app.isDispatchThread) { - requestFocus(actionTitle) - } - - showNotification("${session.agentInfo.id}: $actionTitle") - - val agentContext = when (session.agentInfo.agentType) { - RdAgentType.HOST -> HostAgentContextImpl(session.agentInfo, protocol, lifetime) - RdAgentType.CLIENT -> ClientAgentContextImpl(session.agentInfo, protocol, lifetime) - RdAgentType.GATEWAY -> GatewayAgentContextImpl(session.agentInfo, protocol, lifetime) - } - - // Execute test method - lateinit var result: RdTask - LOG.info("'$actionTitle': starting action") - val elapsedAction = measureTimeMillis { - result = agentAction.action.invoke(agentContext) - } - LOG.info("'$actionTitle': completed action in ${elapsedAction}ms") - - // Assert state - assertLoggerFactory() - - return result } catch (ex: Throwable) { - val msg = "${session.agentInfo.id}: ${actionTitle.let { "'$it' " }}hasn't finished successfully" - LOG.warn(msg, ex) + LOG.warn("${session.agentInfo.id}: ${actionTitle.let { "'$it' " }}hasn't finished successfully", ex) if (!app.isHeadlessEnvironment && isNotRdHost) { - runBlockingCancellable { - lifetime.launch(Dispatchers.EDT + ModalityState.any().asContextElement()) { // even if there is a modal window opened - makeScreenshot(actionTitle) - } - } + makeScreenshot(actionTitle) } - return RdTask.faulted(AssertionError(msg, ex)) + throw ex } } - - // Advice for processing events - session.runNextAction.set { _, _ -> - runAction(queue.remove()) - } - - // Special handler to be used in - session.runNextActionBackground.set(SynchronousScheduler, SynchronousScheduler) { _, _ -> - runAction(bgQueue.remove()) - } } - session.isResponding.set { _, _ -> + session.isResponding.setSuspend(handlerScheduler = Dispatchers.Default.asRdScheduler) { _, _ -> LOG.info("Answering for session is responding...") - RdTask.fromResult(true) + true } - session.closeProject.set { _, _ -> - when (projectOrNull) { - null -> - return@set RdTask.faulted(IllegalStateException("${session.agentInfo.id}: Nothing to close")) - else -> { - LOG.info("Close project...") - try { + session.closeProjectIfOpened.setSuspend(handlerScheduler = Dispatchers.Default.asRdScheduler) { _, _ -> + runLogged("Close project if it is opened") { + projectOrNull?.let { + withContext(Dispatchers.EDT + ModalityState.any().asContextElement() + NonCancellable) { ProjectManagerEx.getInstanceEx().forceCloseProject(project) - return@set RdTask.fromResult(true) - } - catch (e: Exception) { - LOG.warn("Error on project closing", e) - return@set RdTask.fromResult(false) } + } ?: true + } + } + + session.shutdown.adviseOn(lifetime, Dispatchers.Default.asRdScheduler) { + runBlockingCancellable { + withContext(Dispatchers.EDT + ModalityState.any().asContextElement() + NonCancellable) { + LOG.info("Shutting down the application...") + app.exit(true, true, false) } } } - session.closeProjectIfOpened.set { _, _ -> - LOG.info("Close project if it is opened...") - projectOrNull?.let { - try { - ProjectManagerEx.getInstanceEx().forceCloseProject(project) - return@set RdTask.fromResult(true) - } - catch (e: Exception) { - LOG.warn("Error on project closing", e) - return@set RdTask.fromResult(false) - } - } ?: return@set RdTask.fromResult(true) - + session.requestFocus.setSuspend(handlerScheduler = Dispatchers.Default.asRdScheduler) { _, actionTitle -> + withContext(Dispatchers.EDT) { + requestFocus(actionTitle) + } } - session.shutdown.advise(lifetime) { - LOG.info("Shutdown application...") - app.exit(true, true, false) + session.makeScreenshot.setSuspend(handlerScheduler = Dispatchers.Default.asRdScheduler) { _, fileName -> + makeScreenshot(fileName) } - session.requestFocus.set { actionTitle -> - return@set requestFocus(actionTitle) - } - - session.makeScreenshot.set { fileName -> - return@set makeScreenshot(fileName) - } - - session.showNotification.advise(sessionLifetime) { actionTitle -> + session.showNotification.advise(lifetime) { actionTitle -> showNotification("${session.agentInfo.id}: $actionTitle") } @@ -344,40 +294,26 @@ open class DistributedTestHost(coroutineScope: CoroutineScope) { } } - private fun makeScreenshot(actionName: String): Boolean { - if (ApplicationManager.getApplication().isHeadlessEnvironment) { - LOG.warn("Can't make screenshot on application in headless mode.") - return false + private fun screenshotFile(actionName: String, suffix: String? = null, timeStampString: String): File { + var fileName = getActionNameAsFileNameSubstring(actionName) + + if (suffix != null) { + fileName += suffix } - val timeNow = LocalDateTime.now() - val buildStartTimeString = timeNow.format(DateTimeFormatter.ofPattern("HHmmss")) - val maxActionLength = 30 + fileName += "_at_$timeStampString" - fun screenshotFile(suffix: String? = null): File { - var fileName = - actionName - .replace("[^a-zA-Z.]".toRegex(), "_") - .replace("_+".toRegex(), "_") - .take(maxActionLength) - - if (suffix != null) { - fileName += suffix - } - - fileName += "_at_$buildStartTimeString" - - if (!fileName.endsWith(".png")) { - fileName += ".png" - } - return File(PathManager.getLogPath()).resolve(fileName) + if (!fileName.endsWith(".png")) { + fileName += ".png" } + return File(PathManager.getLogPath()).resolve(fileName) + } - fun makeScreenshotOfComponent(screenshotFile: File, component: Component) { - LOG.info("Making screenshot of ${component}") + private suspend fun makeScreenshotOfComponent(screenshotFile: File, component: Component) { + runLogged("Making screenshot of ${component}") { val img = ImageUtil.createImage(component.width, component.height, BufferedImage.TYPE_INT_ARGB) component.printAll(img.createGraphics()) - ApplicationManager.getApplication().executeOnPooledThread { + withContext(Dispatchers.IO + NonCancellable) { try { ImageIO.write(img, "png", screenshotFile) LOG.info("Screenshot is saved at: $screenshotFile") @@ -387,29 +323,38 @@ open class DistributedTestHost(coroutineScope: CoroutineScope) { } } } + } - try { - val windows = Window.getWindows().filter { it.height != 0 && it.width != 0 }.filter { it.isShowing } - windows.forEachIndexed { index, window -> - val screenshotFile = if (window.isFocusAncestor()) { - screenshotFile("_${index}_focusedWindow") - } - else { - screenshotFile("_$index") - } - makeScreenshotOfComponent(screenshotFile, window) - } + private suspend fun makeScreenshot(actionName: String): Boolean { + if (ApplicationManager.getApplication().isHeadlessEnvironment) { + LOG.warn("Can't make screenshot on application in headless mode.") + return false } - catch (e: Throwable) { - when (e) { - is InterruptedException, is ExecutionException, is TimeoutException -> LOG.info(e) - else -> { + + return runLogged("'$actionName': Making screenshot") { + withContext(Dispatchers.EDT + ModalityState.any().asContextElement() + NonCancellable) { // even if there is a modal window opened + val timeNow = LocalDateTime.now() + val timeStampString = timeNow.format(DateTimeFormatter.ofPattern("HHmmss")) + + return@withContext try { + val windows = Window.getWindows().filter { it.height != 0 && it.width != 0 }.filter { it.isShowing } + windows.forEachIndexed { index, window -> + val screenshotFile = if (window.isFocusAncestor()) { + screenshotFile(actionName, "_${index}_focusedWindow", timeStampString) + } + else { + screenshotFile(actionName, "_$index", timeStampString) + } + makeScreenshotOfComponent(screenshotFile, window) + } + true + } + catch (e: Throwable) { LOG.warn("Test action 'makeScreenshot' hasn't finished successfully", e) - return false + false } } } - return true } } diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/utils/GetActionNameAsFileNameSubstring.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/utils/GetActionNameAsFileNameSubstring.kt new file mode 100644 index 000000000000..a7e7a4e5cc19 --- /dev/null +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/utils/GetActionNameAsFileNameSubstring.kt @@ -0,0 +1,14 @@ +package com.intellij.remoteDev.tests.impl + +import org.jetbrains.annotations.ApiStatus + +private val maxActionLength = 30 + +@ApiStatus.Internal +fun getActionNameAsFileNameSubstring(actionName: String): String { + + return actionName + .replace("[^a-zA-Z.]".toRegex(), "_") + .replace("_+".toRegex(), "_") + .take(maxActionLength) +} \ No newline at end of file diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/utils/RunLogged.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/utils/RunLogged.kt new file mode 100644 index 000000000000..4798d7fa3546 --- /dev/null +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/utils/RunLogged.kt @@ -0,0 +1,51 @@ +package com.intellij.remoteDev.tests.impl + +import com.intellij.openapi.diagnostic.Logger +import org.jetbrains.annotations.ApiStatus +import org.jetbrains.annotations.TestOnly +import kotlin.time.Duration +import kotlin.time.ExperimentalTime +import kotlin.time.measureTimedValue +import kotlin.time.Duration.Companion.seconds +import kotlin.time.DurationUnit + +// it is easier to sort out logs from just testFramework +private val LOG = Logger.getInstance(RdctTestFrameworkLoggerCategory.category) + +@OptIn(ExperimentalTime::class) +@TestOnly +@ApiStatus.Internal +suspend fun runLogged(actionTitle: String, timeout: Duration? = null, action: suspend () -> T): T { + val (result, passedTime) = measureTimedValue { + if (timeout != null) { + LOG.info("'$actionTitle': starting with $timeout timeout on ${Thread.currentThread()}") + withTimeoutDumping(actionTitle, timeout) { + action() + } + } + else { + LOG.info("'$actionTitle': starting on ${Thread.currentThread()}") + action() + } + } + val resultString = if (result != null && result !is Unit) " with result '$result'" else "" + LOG.info("'$actionTitle': finished in ${passedTime.customToString}$resultString") + return result +} + +@OptIn(ExperimentalTime::class) +fun runLoggedBlocking(actionTitle: String, action: () -> T): T { + LOG.info("'$actionTitle': starting on ${Thread.currentThread()}") + val (result, passedTime) = measureTimedValue { + action() + } + + val resultString = if (result != null && result !is Unit) " with result '$result'" else "" + LOG.info("'$actionTitle': finished in ${passedTime.customToString}$resultString") + return result +} + +val Duration.customToString: String + get() = + if (minus(1.seconds).isNegative()) "< 1s" + else toString(unit = DurationUnit.SECONDS, decimals = 1) \ No newline at end of file diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/utils/WithTimeoutDumping.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/utils/WithTimeoutDumping.kt new file mode 100644 index 000000000000..6eef14d4e7e7 --- /dev/null +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/impl/utils/WithTimeoutDumping.kt @@ -0,0 +1,42 @@ +package com.intellij.remoteDev.tests.impl + +import com.intellij.diagnostic.dumpCoroutines +import kotlinx.coroutines.CoroutineName +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.TimeoutCancellationException +import kotlinx.coroutines.async +import kotlinx.coroutines.coroutineScope +import kotlinx.coroutines.launch +import kotlinx.coroutines.withTimeout +import org.jetbrains.annotations.ApiStatus +import java.util.concurrent.TimeoutException +import kotlin.coroutines.coroutineContext +import kotlin.time.Duration + +@ApiStatus.Internal +suspend fun withTimeoutDumping(title: String, + timeout: Duration, + failMessageProducer: (() -> String)? = null, + action: suspend () -> T): T { + val outerScope = CoroutineScope(coroutineContext + CoroutineName(title)) + + val deferred = outerScope.async { action() } + coroutineScope { + launch { + try { + withTimeout(timeout) { deferred.await() } + } + catch (e: TimeoutCancellationException) { + val coroutinesDump = dumpCoroutines(outerScope) + deferred.cancel(e) + throw TimeoutException("$title: Has not finished in $timeout.\n" + + "------------\n" + + "CoroutineDump:\n" + + coroutinesDump + "\n" + + "------------" + + failMessageProducer?.invoke()?.let { "\n$it" }.orEmpty()) + } + } + } + return deferred.await() +} \ No newline at end of file diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestBridgeModel.Generated.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestBridgeModel.Generated.kt index 0131f087266e..2fe6a09f4a24 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestBridgeModel.Generated.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestBridgeModel.Generated.kt @@ -56,6 +56,10 @@ class DistributedTestBridgeModel private constructor( val syncCall: RdCall get() = _syncCall //methods //initializer + init { + _syncCall.async = true + } + init { bindableChildren.add("syncCall" to _syncCall) } diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestModel.Generated.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestModel.Generated.kt index bef02efa0de4..01f959ad5671 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestModel.Generated.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelGenerated/DistributedTestModel.Generated.kt @@ -54,7 +54,7 @@ class DistributedTestModel private constructor( private val __RdTestSessionNullableSerializer = RdTestSession.nullable() - const val serializationHash = -5486389130943254851L + const val serializationHash = -5352657358741472348L } override val serializersOwner: ISerializersOwner get() = DistributedTestModel @@ -219,7 +219,6 @@ class RdTestSession private constructor( private val _closeProject: RdCall, private val _closeProjectIfOpened: RdCall, private val _runNextAction: RdCall, - private val _runNextActionBackground: RdCall, private val _requestFocus: RdCall, private val _makeScreenshot: RdCall, private val _isResponding: RdCall @@ -244,11 +243,10 @@ class RdTestSession private constructor( val _closeProject = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, FrameworkMarshallers.Bool) val _closeProjectIfOpened = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, FrameworkMarshallers.Bool) val _runNextAction = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, __StringNullableSerializer) - val _runNextActionBackground = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, __StringNullableSerializer) val _requestFocus = RdCall.read(ctx, buffer, FrameworkMarshallers.String, FrameworkMarshallers.Bool) val _makeScreenshot = RdCall.read(ctx, buffer, FrameworkMarshallers.String, FrameworkMarshallers.Bool) val _isResponding = RdCall.read(ctx, buffer, FrameworkMarshallers.Void, FrameworkMarshallers.Bool) - return RdTestSession(agentInfo, testClassName, testMethodName, traceCategories, debugCategories, _ready, _sendException, _shutdown, _showNotification, _closeProject, _closeProjectIfOpened, _runNextAction, _runNextActionBackground, _requestFocus, _makeScreenshot, _isResponding).withId(_id) + return RdTestSession(agentInfo, testClassName, testMethodName, traceCategories, debugCategories, _ready, _sendException, _shutdown, _showNotification, _closeProject, _closeProjectIfOpened, _runNextAction, _requestFocus, _makeScreenshot, _isResponding).withId(_id) } override fun write(ctx: SerializationCtx, buffer: AbstractBuffer, value: RdTestSession) { @@ -265,7 +263,6 @@ class RdTestSession private constructor( RdCall.write(ctx, buffer, value._closeProject) RdCall.write(ctx, buffer, value._closeProjectIfOpened) RdCall.write(ctx, buffer, value._runNextAction) - RdCall.write(ctx, buffer, value._runNextActionBackground) RdCall.write(ctx, buffer, value._requestFocus) RdCall.write(ctx, buffer, value._makeScreenshot) RdCall.write(ctx, buffer, value._isResponding) @@ -278,12 +275,11 @@ class RdTestSession private constructor( //fields val ready: IProperty get() = _ready val sendException: IAsyncSignal get() = _sendException - val shutdown: ISignal get() = _shutdown + val shutdown: IAsyncSignal get() = _shutdown val showNotification: ISignal get() = _showNotification val closeProject: RdCall get() = _closeProject val closeProjectIfOpened: RdCall get() = _closeProjectIfOpened val runNextAction: RdCall get() = _runNextAction - val runNextActionBackground: RdCall get() = _runNextActionBackground val requestFocus: RdCall get() = _requestFocus val makeScreenshot: RdCall get() = _makeScreenshot val isResponding: RdCall get() = _isResponding @@ -295,6 +291,13 @@ class RdTestSession private constructor( init { _sendException.async = true + _shutdown.async = true + _closeProject.async = true + _closeProjectIfOpened.async = true + _runNextAction.async = true + _requestFocus.async = true + _makeScreenshot.async = true + _isResponding.async = true } init { @@ -305,7 +308,6 @@ class RdTestSession private constructor( bindableChildren.add("closeProject" to _closeProject) bindableChildren.add("closeProjectIfOpened" to _closeProjectIfOpened) bindableChildren.add("runNextAction" to _runNextAction) - bindableChildren.add("runNextActionBackground" to _runNextActionBackground) bindableChildren.add("requestFocus" to _requestFocus) bindableChildren.add("makeScreenshot" to _makeScreenshot) bindableChildren.add("isResponding" to _isResponding) @@ -331,7 +333,6 @@ class RdTestSession private constructor( RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Bool), RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Bool), RdCall(FrameworkMarshallers.Void, __StringNullableSerializer), - RdCall(FrameworkMarshallers.Void, __StringNullableSerializer), RdCall(FrameworkMarshallers.String, FrameworkMarshallers.Bool), RdCall(FrameworkMarshallers.String, FrameworkMarshallers.Bool), RdCall(FrameworkMarshallers.Void, FrameworkMarshallers.Bool) @@ -355,7 +356,6 @@ class RdTestSession private constructor( print("closeProject = "); _closeProject.print(printer); println() print("closeProjectIfOpened = "); _closeProjectIfOpened.print(printer); println() print("runNextAction = "); _runNextAction.print(printer); println() - print("runNextActionBackground = "); _runNextActionBackground.print(printer); println() print("requestFocus = "); _requestFocus.print(printer); println() print("makeScreenshot = "); _makeScreenshot.print(printer); println() print("isResponding = "); _isResponding.print(printer); println() @@ -377,7 +377,6 @@ class RdTestSession private constructor( _closeProject.deepClonePolymorphic(), _closeProjectIfOpened.deepClonePolymorphic(), _runNextAction.deepClonePolymorphic(), - _runNextActionBackground.deepClonePolymorphic(), _requestFocus.deepClonePolymorphic(), _makeScreenshot.deepClonePolymorphic(), _isResponding.deepClonePolymorphic() diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestBridgeModel.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestBridgeModel.kt index 621a3e26ff9c..4869cfc54551 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestBridgeModel.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestBridgeModel.kt @@ -1,7 +1,9 @@ package com.intellij.remoteDev.tests.modelSources -import com.jetbrains.rd.generator.nova.* -import com.jetbrains.rd.generator.nova.PredefinedType.* +import com.jetbrains.rd.generator.nova.Ext +import com.jetbrains.rd.generator.nova.PredefinedType.void +import com.jetbrains.rd.generator.nova.async +import com.jetbrains.rd.generator.nova.call /** * Model to bind client <-> server agents during test session @@ -10,6 +12,6 @@ import com.jetbrains.rd.generator.nova.PredefinedType.* object DistributedTestBridgeModel : Ext(TestRoot) { init { - call("syncCall", void, void) + call("syncCall", void, void).async } } diff --git a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestModel.kt b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestModel.kt index e5927b9c1cf6..8a9bff8f3046 100644 --- a/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestModel.kt +++ b/platform/remoteDev-util/src/com/intellij/remoteDev/tests/modelSources/DistributedTestModel.kt @@ -58,15 +58,14 @@ object DistributedTestModel : Ext(TestRoot) { field("debugCategories", immutableList(string)) property("ready", bool.nullable) signal("sendException", RdTestSessionException).async - signal("shutdown", void) + signal("shutdown", void).async signal("showNotification", string) - call("closeProject", void, bool) - call("closeProjectIfOpened", void, bool) - call("runNextAction", void, string.nullable) - call("runNextActionBackground", void, string.nullable) - call("requestFocus", string, bool) - call("makeScreenshot", string, bool) - call("isResponding", void, bool) + call("closeProject", void, bool).async + call("closeProjectIfOpened", void, bool).async + call("runNextAction", void, string.nullable).async + call("requestFocus", string, bool).async + call("makeScreenshot", string, bool).async + call("isResponding", void, bool).async } init {