debug information test: instantiate a single thread for all tests under same test class
This commit is contained in:
committed by
max-kammerer
parent
0a2812f83b
commit
2c78f1fe85
+105
-92
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.codegen.debugInformation
|
package org.jetbrains.kotlin.codegen.debugInformation
|
||||||
|
|
||||||
|
import com.intellij.openapi.util.SystemInfo
|
||||||
import com.intellij.util.PathUtil
|
import com.intellij.util.PathUtil
|
||||||
import com.intellij.util.SystemProperties
|
import com.intellij.util.SystemProperties
|
||||||
import com.sun.jdi.VirtualMachine
|
import com.sun.jdi.VirtualMachine
|
||||||
@@ -25,6 +26,10 @@ import org.jetbrains.kotlin.test.KotlinTestUtils
|
|||||||
import org.jetbrains.kotlin.test.clientserver.getGeneratedClass
|
import org.jetbrains.kotlin.test.clientserver.getGeneratedClass
|
||||||
import org.jetbrains.kotlin.test.clientserver.TestProcessServer
|
import org.jetbrains.kotlin.test.clientserver.TestProcessServer
|
||||||
import org.jetbrains.kotlin.test.clientserver.TestProxy
|
import org.jetbrains.kotlin.test.clientserver.TestProxy
|
||||||
|
import org.junit.After
|
||||||
|
import org.junit.AfterClass
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.BeforeClass
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.lang.IllegalStateException
|
import java.lang.IllegalStateException
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
@@ -32,88 +37,99 @@ import kotlin.properties.Delegates
|
|||||||
|
|
||||||
abstract class AbstractSteppingTest : CodegenTestCase() {
|
abstract class AbstractSteppingTest : CodegenTestCase() {
|
||||||
|
|
||||||
private companion object {
|
companion object {
|
||||||
private const val DEBUG_ADDRESS = "127.0.0.1"
|
const val DEBUG_ADDRESS = "127.0.0.1"
|
||||||
private const val MAIN_CLASS = "org.jetbrains.kotlin.test.clientserver.TestProcessServer"
|
const val MAIN_CLASS = "org.jetbrains.kotlin.test.clientserver.TestProcessServer"
|
||||||
private const val TEST_CLASS = "TestKt"
|
const val TEST_CLASS = "TestKt"
|
||||||
private const val BOX_METHOD = "box"
|
const val BOX_METHOD = "box"
|
||||||
private const val LINENUMBER_PREFIX = "// LINENUMBERS"
|
const val LINENUMBER_PREFIX = "// LINENUMBERS"
|
||||||
|
var proxyPort = 0
|
||||||
|
lateinit var process: Process
|
||||||
|
lateinit var virtualMachine: VirtualMachine
|
||||||
|
|
||||||
|
@BeforeClass
|
||||||
|
@JvmStatic
|
||||||
|
fun setUpTest() {
|
||||||
|
val debugPort = startDebuggeeProcess()
|
||||||
|
virtualMachine = attachDebugger(debugPort)
|
||||||
|
setUpVM(virtualMachine)
|
||||||
|
|
||||||
|
val reader = process.inputStream.bufferedReader()
|
||||||
|
reader.readLine()
|
||||||
|
proxyPort = reader.readLine()
|
||||||
|
.split("port ")
|
||||||
|
.last()
|
||||||
|
.trim()
|
||||||
|
.toInt()
|
||||||
|
reader.close()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun setUpVM(virtualMachine: VirtualMachine) {
|
||||||
|
val manager = virtualMachine.eventRequestManager()
|
||||||
|
|
||||||
|
val methodEntryReq = manager.createMethodEntryRequest()
|
||||||
|
methodEntryReq.addClassFilter(TEST_CLASS)
|
||||||
|
methodEntryReq.setSuspendPolicy(SUSPEND_ALL)
|
||||||
|
methodEntryReq.enable()
|
||||||
|
|
||||||
|
val methodExitReq = manager.createMethodExitRequest()
|
||||||
|
methodExitReq.addClassFilter(TEST_CLASS)
|
||||||
|
methodExitReq.setSuspendPolicy(SUSPEND_NONE)
|
||||||
|
methodExitReq.enable()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun startDebuggeeProcess(): Int {
|
||||||
|
val classpath = listOf(
|
||||||
|
PathUtil.getJarPathForClass(TestProcessServer::class.java),
|
||||||
|
PathUtil.getJarPathForClass(Delegates::class.java) // Add Kotlin runtime JAR
|
||||||
|
)
|
||||||
|
|
||||||
|
val javaExecutablePath = findJavaExecutable().absolutePath
|
||||||
|
val command = arrayOf(
|
||||||
|
if (SystemInfo.isWindows) "\"$javaExecutablePath\"" else javaExecutablePath,
|
||||||
|
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=127.0.0.1:0",
|
||||||
|
"-ea",
|
||||||
|
"-classpath", classpath.joinToString(File.pathSeparator),
|
||||||
|
MAIN_CLASS,
|
||||||
|
TestProcessServer.DEBUG_TEST
|
||||||
|
)
|
||||||
|
|
||||||
|
process = ProcessBuilder(*command).start()
|
||||||
|
return process.inputStream.bufferedReader().readLine()
|
||||||
|
.split("address:")
|
||||||
|
.last()
|
||||||
|
.trim()
|
||||||
|
.toInt()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun attachDebugger(port: Int): VirtualMachine {
|
||||||
|
val connector = SocketAttachingConnector()
|
||||||
|
return connector.attach(connector.defaultArguments().toMutableMap().apply {
|
||||||
|
getValue("port").setValue("$port")
|
||||||
|
getValue("hostname").setValue(DEBUG_ADDRESS)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun findJavaExecutable(): File {
|
||||||
|
val javaBin = File(SystemProperties.getJavaHome(), "bin")
|
||||||
|
return File(javaBin, "java.exe").takeIf { it.exists() }
|
||||||
|
?: File(javaBin, "java").also { assert(it.exists()) }
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
@JvmStatic
|
||||||
|
fun tearDownTest() {
|
||||||
|
process.destroy()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var proxyPort = 0
|
@Before
|
||||||
|
public override fun setUp() {
|
||||||
private var process: Process? = null
|
|
||||||
|
|
||||||
private var virtualMachine: VirtualMachine? = null
|
|
||||||
|
|
||||||
override fun setUp() {
|
|
||||||
val debugPort = startDebuggeeProcess()
|
|
||||||
virtualMachine = attachDebugger(debugPort)
|
|
||||||
setUpVM(virtualMachine!!)
|
|
||||||
|
|
||||||
val reader = process!!.inputStream.bufferedReader()
|
|
||||||
reader.readLine()
|
|
||||||
proxyPort = reader.readLine()
|
|
||||||
.split("port ")
|
|
||||||
.last()
|
|
||||||
.trim()
|
|
||||||
.toInt()
|
|
||||||
reader.close()
|
|
||||||
|
|
||||||
super.setUp()
|
super.setUp()
|
||||||
}
|
}
|
||||||
|
|
||||||
open fun setUpVM(virtualMachine: VirtualMachine) {
|
@After
|
||||||
val manager = virtualMachine.eventRequestManager()
|
public override fun tearDown() {
|
||||||
|
|
||||||
val methodEntryReq = manager.createMethodEntryRequest()
|
|
||||||
methodEntryReq.addClassFilter(TEST_CLASS)
|
|
||||||
methodEntryReq.setSuspendPolicy(SUSPEND_ALL)
|
|
||||||
methodEntryReq.enable()
|
|
||||||
|
|
||||||
val methodExitReq = manager.createMethodExitRequest()
|
|
||||||
methodExitReq.addClassFilter(TEST_CLASS)
|
|
||||||
methodExitReq.setSuspendPolicy(SUSPEND_NONE)
|
|
||||||
methodExitReq.enable()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun startDebuggeeProcess(): Int{
|
|
||||||
val classpath = listOf(
|
|
||||||
System.getProperty("java.class.path"),
|
|
||||||
PathUtil.getJarPathForClass(Delegates::class.java) // Add Kotlin runtime JAR
|
|
||||||
)
|
|
||||||
|
|
||||||
val command = arrayOf(
|
|
||||||
findJavaExecutable().absolutePath,
|
|
||||||
"-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=127.0.0.1:0",
|
|
||||||
"-ea",
|
|
||||||
"-classpath", classpath.joinToString(File.pathSeparator),
|
|
||||||
MAIN_CLASS,
|
|
||||||
TestProcessServer.DEBUG_TEST
|
|
||||||
)
|
|
||||||
|
|
||||||
process = ProcessBuilder(*command).start()
|
|
||||||
return process!!.inputStream.bufferedReader().readLine()
|
|
||||||
.split("address:")
|
|
||||||
.last()
|
|
||||||
.trim()
|
|
||||||
.toInt()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun attachDebugger(port: Int): VirtualMachine {
|
|
||||||
val connector = SocketAttachingConnector()
|
|
||||||
return connector.attach(connector.defaultArguments().toMutableMap().apply {
|
|
||||||
getValue("port").setValue("$port")
|
|
||||||
getValue("hostname").setValue(DEBUG_ADDRESS)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun tearDown() {
|
|
||||||
try {
|
|
||||||
process!!.destroy()
|
|
||||||
} finally {
|
|
||||||
|
|
||||||
}
|
|
||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -146,9 +162,9 @@ abstract class AbstractSteppingTest : CodegenTestCase() {
|
|||||||
classFileFactory.writeAllTo(classesDir)
|
classFileFactory.writeAllTo(classesDir)
|
||||||
|
|
||||||
try {
|
try {
|
||||||
doTest(lineNumbers, classesDir, virtualMachine!!, classBuilderFactory, classFileFactory, generationState)
|
doTest(lineNumbers, classesDir, virtualMachine, classBuilderFactory, classFileFactory, generationState)
|
||||||
} finally {
|
} finally {
|
||||||
//process.destroy()
|
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
tempDirForTest.deleteRecursively()
|
tempDirForTest.deleteRecursively()
|
||||||
@@ -200,18 +216,20 @@ abstract class AbstractSteppingTest : CodegenTestCase() {
|
|||||||
is VMDeathEvent, is VMDisconnectEvent -> {
|
is VMDeathEvent, is VMDisconnectEvent -> {
|
||||||
break@vmLoop
|
break@vmLoop
|
||||||
}
|
}
|
||||||
// We start VM with option suspend=n, in case VMStartEvent is still received, discard.
|
// We start VM with option 'suspend=n', in case VMStartEvent is still received, discard.
|
||||||
is VMStartEvent -> {
|
is VMStartEvent -> {
|
||||||
|
|
||||||
}
|
}
|
||||||
is MethodEntryEvent -> {
|
is MethodEntryEvent -> {
|
||||||
if (!shouldRecordSteps && event.location().method().name() == BOX_METHOD) {
|
if (!shouldRecordSteps && event.location().method().name() == BOX_METHOD) {
|
||||||
val stepReq = manager.createStepRequest(event.thread(), StepRequest.STEP_LINE, StepRequest.STEP_INTO)
|
if (manager.stepRequests().isEmpty()) {
|
||||||
stepReq.setSuspendPolicy(SUSPEND_NONE)
|
val stepReq = manager.createStepRequest(event.thread(), StepRequest.STEP_LINE, StepRequest.STEP_INTO)
|
||||||
stepReq.addClassExclusionFilter("java.*")
|
stepReq.setSuspendPolicy(SUSPEND_NONE)
|
||||||
stepReq.addClassExclusionFilter("sun.*")
|
stepReq.addClassExclusionFilter("java.*")
|
||||||
stepReq.addClassExclusionFilter("kotlin.*")
|
stepReq.addClassExclusionFilter("sun.*")
|
||||||
stepReq.enable()
|
stepReq.addClassExclusionFilter("kotlin.*")
|
||||||
|
}
|
||||||
|
manager.stepRequests().map { it.enable() }
|
||||||
shouldRecordSteps = true
|
shouldRecordSteps = true
|
||||||
loggedEvents.add(event)
|
loggedEvents.add(event)
|
||||||
}
|
}
|
||||||
@@ -227,6 +245,7 @@ abstract class AbstractSteppingTest : CodegenTestCase() {
|
|||||||
}
|
}
|
||||||
is MethodExitEvent -> {
|
is MethodExitEvent -> {
|
||||||
if (event.location().method().name() == BOX_METHOD) {
|
if (event.location().method().name() == BOX_METHOD) {
|
||||||
|
manager.stepRequests().map { it.disable() }
|
||||||
break@vmLoop
|
break@vmLoop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -244,12 +263,6 @@ abstract class AbstractSteppingTest : CodegenTestCase() {
|
|||||||
TestCase.assertEquals(expectedLineNumbers, actualLineNumbers.joinToString(" "))
|
TestCase.assertEquals(expectedLineNumbers, actualLineNumbers.joinToString(" "))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun findJavaExecutable(): File {
|
|
||||||
val javaBin = File(SystemProperties.getJavaHome(), "bin")
|
|
||||||
return File(javaBin, "java.exe").takeIf { it.exists() }
|
|
||||||
?: File(javaBin, "java").also { assert(it.exists()) }
|
|
||||||
}
|
|
||||||
|
|
||||||
internal val OutputFile.internalName
|
internal val OutputFile.internalName
|
||||||
get() = relativePath.substringBeforeLast(".class")
|
get() = relativePath.substringBeforeLast(".class")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user