[test][debugger] make reading of std{out,err} asynchroneous

- this fix issue on big amount data in stdout or stderr, making program hanging on waiting when appear some room in stdout/stderr buffer

[test][debugger] DevToolsSecurity check and stdio/stderr async processing
This commit is contained in:
Vasily Levchenko
2020-06-29 13:28:46 +02:00
parent c1f0a6048b
commit a92e428289
4 changed files with 67 additions and 12 deletions
+1
View File
@@ -51,6 +51,7 @@ repositories {
} }
dependencies { dependencies {
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.7'
cli_bc project(path: ':backend.native', configuration: 'cli_bc') cli_bc project(path: ':backend.native', configuration: 'cli_bc')
def updateTestData = true def updateTestData = true
if (project.hasProperty("kotlinProjectPath")) { if (project.hasProperty("kotlinProjectPath")) {
@@ -15,6 +15,7 @@ object DistProperties {
private val konancDriver = if (HostManager.host.family == Family.MINGW) "konanc.bat" else "konanc" private val konancDriver = if (HostManager.host.family == Family.MINGW) "konanc.bat" else "konanc"
val konanc: Path = dist.resolve("bin/$konancDriver") val konanc: Path = dist.resolve("bin/$konancDriver")
val lldb: Path = Paths.get("lldb") val lldb: Path = Paths.get("lldb")
val devToolsSecurity: Path = Paths.get("DevToolsSecurity")
val lldbPrettyPrinters: Path = dist.resolve("tools/konan_lldb.py") val lldbPrettyPrinters: Path = dist.resolve("tools/konan_lldb.py")
private fun requireProp(name: String): String private fun requireProp(name: String): String
@@ -5,9 +5,18 @@
package org.jetbrains.kotlin.native.test.debugger package org.jetbrains.kotlin.native.test.debugger
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.async
import kotlinx.coroutines.runBlocking
import org.jetbrains.kotlin.cli.bc.K2Native import org.jetbrains.kotlin.cli.bc.K2Native
import java.io.ByteArrayOutputStream
import java.io.InputStream
import java.io.StringReader
import java.lang.StringBuilder
import java.nio.file.Files import java.nio.file.Files
import java.nio.file.Path import java.nio.file.Path
import java.time.temporal.ChronoUnit
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
class ToolDriver( class ToolDriver(
@@ -31,7 +40,7 @@ class ToolDriver(
} }
fun runLldb(program: Path, commands: List<String>): String { fun runLldb(program: Path, commands: List<String>): String {
val args = listOf("-o", "command script import \"$lldbPrettyPrinters\"") + val args = listOf("-b", "-o", "command script import \"$lldbPrettyPrinters\"") +
commands.flatMap { listOf("-o", it) } commands.flatMap { listOf("-o", it) }
return subprocess(lldb, program.toString(), "-b", *args.toTypedArray()) return subprocess(lldb, program.toString(), "-b", *args.toTypedArray())
.thrownIfFailed() .thrownIfFailed()
@@ -63,15 +72,41 @@ data class ProcessOutput(
fun subprocess(program: Path, vararg args: String): ProcessOutput { fun subprocess(program: Path, vararg args: String): ProcessOutput {
val start = System.currentTimeMillis() val start = System.currentTimeMillis()
val process = ProcessBuilder(program.toString(), *args).start() val process = ProcessBuilder(program.toString(), *args).start()
val outReader = process.inputStream.bufferedReader() val out = GlobalScope.async(Dispatchers.IO) {
val errReader = process.errorStream.bufferedReader() readStream(process, process.inputStream.buffered())
}
val timeout = 5L
if (!process.waitFor(timeout, TimeUnit.MINUTES)) { val err = GlobalScope.async(Dispatchers.IO) {
process.destroy() readStream(process, process.errorStream.buffered())
error("$program is running for more then $timeout minutes") }
return runBlocking {
try {
val status = process.waitFor(5L, TimeUnit.MINUTES)
if (!status) {
out.cancel()
err.cancel()
error("$program timeouted")
}
}catch (e:Exception) {
out.cancel()
err.cancel()
error(e)
}
ProcessOutput(program, process, out.await(), err.await(), System.currentTimeMillis() - start)
} }
val stdout = outReader.readText() }
val stderr = errReader.readText()
return ProcessOutput(program, process, stdout, stderr, System.currentTimeMillis() - start) private fun readStream(process: Process, stream: InputStream): String {
var size = 4096
val buffer = ByteArray(size) { 0 }
val sunk = ByteArrayOutputStream()
while (true) {
size = stream.read(buffer, 0, buffer.size)
if (size < 0 && !process.isAlive)
break
if (size > 0)
sunk.write(buffer, 0, size)
}
return String(sunk.toByteArray())
} }
@@ -62,6 +62,15 @@ fun lldbTest(@Language("kotlin") programText: String, lldbSession: String) {
return return
} }
if (!isOsxDevToolsEnabled) {
println("""Development tools aren't available.
|Please consider to execute:
| ${DistProperties.devToolsSecurity} -enable
|or
| csrutil disable
|to run lldb tests""".trimMargin())
return
}
val lldbSessionSpec = LldbSessionSpecification.parse(lldbSession) val lldbSessionSpec = LldbSessionSpecification.parse(lldbSession)
val tmpdir = Files.createTempDirectory("debugger_test") val tmpdir = Files.createTempDirectory("debugger_test")
@@ -76,6 +85,15 @@ fun lldbTest(@Language("kotlin") programText: String, lldbSession: String) {
lldbSessionSpec.match(result) lldbSessionSpec.match(result)
} }
private val isOsxDevToolsEnabled: Boolean by lazy {
//TODO: add OSX checks.
val rawStatus = subprocess(DistProperties.devToolsSecurity, "-status")
println("> status: $rawStatus")
val r = Regex("^.*\\ (enabled|disabled).$")
r.find(rawStatus.stdout)?.destructured?.component1() == "enabled"
}
private val haveLldb: Boolean by lazy { private val haveLldb: Boolean by lazy {
val lldbVersion = try { val lldbVersion = try {
subprocess(DistProperties.lldb, "-version") subprocess(DistProperties.lldb, "-version")