debug information test: instantiate a single thread for all tests under same test class

This commit is contained in:
Jiaxiang Chen
2019-09-11 16:37:25 -07:00
committed by max-kammerer
parent 0a2812f83b
commit 2c78f1fe85
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.codegen.debugInformation
import com.intellij.openapi.util.SystemInfo
import com.intellij.util.PathUtil
import com.intellij.util.SystemProperties
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.TestProcessServer
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.lang.IllegalStateException
import java.net.URLClassLoader
@@ -32,88 +37,99 @@ import kotlin.properties.Delegates
abstract class AbstractSteppingTest : CodegenTestCase() {
private companion object {
private const val DEBUG_ADDRESS = "127.0.0.1"
private const val MAIN_CLASS = "org.jetbrains.kotlin.test.clientserver.TestProcessServer"
private const val TEST_CLASS = "TestKt"
private const val BOX_METHOD = "box"
private const val LINENUMBER_PREFIX = "// LINENUMBERS"
companion object {
const val DEBUG_ADDRESS = "127.0.0.1"
const val MAIN_CLASS = "org.jetbrains.kotlin.test.clientserver.TestProcessServer"
const val TEST_CLASS = "TestKt"
const val BOX_METHOD = "box"
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
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()
@Before
public override fun setUp() {
super.setUp()
}
open 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(
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 {
}
@After
public override fun tearDown() {
super.tearDown()
}
@@ -146,9 +162,9 @@ abstract class AbstractSteppingTest : CodegenTestCase() {
classFileFactory.writeAllTo(classesDir)
try {
doTest(lineNumbers, classesDir, virtualMachine!!, classBuilderFactory, classFileFactory, generationState)
doTest(lineNumbers, classesDir, virtualMachine, classBuilderFactory, classFileFactory, generationState)
} finally {
//process.destroy()
}
} finally {
tempDirForTest.deleteRecursively()
@@ -200,18 +216,20 @@ abstract class AbstractSteppingTest : CodegenTestCase() {
is VMDeathEvent, is VMDisconnectEvent -> {
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 MethodEntryEvent -> {
if (!shouldRecordSteps && event.location().method().name() == BOX_METHOD) {
val stepReq = manager.createStepRequest(event.thread(), StepRequest.STEP_LINE, StepRequest.STEP_INTO)
stepReq.setSuspendPolicy(SUSPEND_NONE)
stepReq.addClassExclusionFilter("java.*")
stepReq.addClassExclusionFilter("sun.*")
stepReq.addClassExclusionFilter("kotlin.*")
stepReq.enable()
if (manager.stepRequests().isEmpty()) {
val stepReq = manager.createStepRequest(event.thread(), StepRequest.STEP_LINE, StepRequest.STEP_INTO)
stepReq.setSuspendPolicy(SUSPEND_NONE)
stepReq.addClassExclusionFilter("java.*")
stepReq.addClassExclusionFilter("sun.*")
stepReq.addClassExclusionFilter("kotlin.*")
}
manager.stepRequests().map { it.enable() }
shouldRecordSteps = true
loggedEvents.add(event)
}
@@ -227,6 +245,7 @@ abstract class AbstractSteppingTest : CodegenTestCase() {
}
is MethodExitEvent -> {
if (event.location().method().name() == BOX_METHOD) {
manager.stepRequests().map { it.disable() }
break@vmLoop
}
}
@@ -244,12 +263,6 @@ abstract class AbstractSteppingTest : CodegenTestCase() {
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
get() = relativePath.substringBeforeLast(".class")