[rdct-tests]: GTW-6006 coroutine based test framework

- No additional wait in case of failure the first time. It is always better to set correct timeouts from the start.
- Add ActionName utils

GitOrigin-RevId: d27f24efdaf82e4ea47b951555c80dcd06228221
This commit is contained in:
Anastasia Katsman
2023-08-24 19:17:38 +02:00
committed by intellij-monorepo-bot
parent 6de23f326b
commit ced900d7e0
11 changed files with 244 additions and 190 deletions

View File

@@ -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<String?>, val title: String, val expectBlockedEdt: Boolean)
class AgentAction(val title: String, val timeout: Duration, val fromEdt: Boolean, val action: suspend (AgentContext) -> String?)

View File

@@ -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()
}

View File

@@ -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<AgentAction>, LinkedList<AgentAction>>
fun initAgent(agent: AgentInfo): Queue<AgentAction>
fun performInit(method: Method)
}

View File

@@ -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<String?> {
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<String?>
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
}
}

View File

@@ -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)
}

View File

@@ -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 <T> 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 <T> 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)

View File

@@ -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 <T> 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()
}

View File

@@ -56,6 +56,10 @@ class DistributedTestBridgeModel private constructor(
val syncCall: RdCall<Unit, Unit> get() = _syncCall
//methods
//initializer
init {
_syncCall.async = true
}
init {
bindableChildren.add("syncCall" to _syncCall)
}

View File

@@ -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<Unit, Boolean>,
private val _closeProjectIfOpened: RdCall<Unit, Boolean>,
private val _runNextAction: RdCall<Unit, String?>,
private val _runNextActionBackground: RdCall<Unit, String?>,
private val _requestFocus: RdCall<String, Boolean>,
private val _makeScreenshot: RdCall<String, Boolean>,
private val _isResponding: RdCall<Unit, Boolean>
@@ -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<Boolean?> get() = _ready
val sendException: IAsyncSignal<RdTestSessionException> get() = _sendException
val shutdown: ISignal<Unit> get() = _shutdown
val shutdown: IAsyncSignal<Unit> get() = _shutdown
val showNotification: ISignal<String> get() = _showNotification
val closeProject: RdCall<Unit, Boolean> get() = _closeProject
val closeProjectIfOpened: RdCall<Unit, Boolean> get() = _closeProjectIfOpened
val runNextAction: RdCall<Unit, String?> get() = _runNextAction
val runNextActionBackground: RdCall<Unit, String?> get() = _runNextActionBackground
val requestFocus: RdCall<String, Boolean> get() = _requestFocus
val makeScreenshot: RdCall<String, Boolean> get() = _makeScreenshot
val isResponding: RdCall<Unit, Boolean> 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<Unit, Boolean>(FrameworkMarshallers.Void, FrameworkMarshallers.Bool),
RdCall<Unit, Boolean>(FrameworkMarshallers.Void, FrameworkMarshallers.Bool),
RdCall<Unit, String?>(FrameworkMarshallers.Void, __StringNullableSerializer),
RdCall<Unit, String?>(FrameworkMarshallers.Void, __StringNullableSerializer),
RdCall<String, Boolean>(FrameworkMarshallers.String, FrameworkMarshallers.Bool),
RdCall<String, Boolean>(FrameworkMarshallers.String, FrameworkMarshallers.Bool),
RdCall<Unit, Boolean>(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()

View File

@@ -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
}
}

View File

@@ -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 {