mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-03-22 15:19:59 +07:00
[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:
committed by
intellij-monorepo-bot
parent
6de23f326b
commit
ced900d7e0
@@ -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?)
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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)
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user