[K/N] Apply execution timeout to tests
This commit is contained in:
committed by
Space Team
parent
89be94f123
commit
0457001a87
@@ -14,6 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
@file:OptIn(kotlin.time.ExperimentalTime::class)
|
||||
package org.jetbrains.kotlin
|
||||
|
||||
import com.google.gson.annotations.Expose
|
||||
@@ -35,6 +36,10 @@ import java.time.LocalDateTime
|
||||
import java.time.format.DateTimeFormatter
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.DurationUnit
|
||||
import kotlin.time.toDuration
|
||||
|
||||
/**
|
||||
* A replacement of the standard `exec {}`
|
||||
* @see org.gradle.api.Project.exec
|
||||
@@ -56,6 +61,7 @@ private fun Executor.service(project: Project) = object: ExecutorService {
|
||||
val request = ExecuteRequest(
|
||||
executableAbsolutePath = execSpec.executable,
|
||||
args = execSpec.args,
|
||||
timeout = 15.toDuration(DurationUnit.MINUTES),
|
||||
).apply {
|
||||
execSpec.standardInput?.let {
|
||||
stdin = it
|
||||
|
||||
@@ -243,7 +243,10 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable {
|
||||
|stdout: $stdOut
|
||||
|stderr: $stdErr
|
||||
""".trimMargin())
|
||||
check(exitCode == expectedExitStatus ?: 0) { "Execution of $testExecName failed with exit code: $exitCode " }
|
||||
val timeoutMessage = if (exitCode == -1) {
|
||||
"WARNING: probably a timeout\n"
|
||||
} else ""
|
||||
check(exitCode == expectedExitStatus ?: 0) { "${timeoutMessage}Execution of $testExecName failed with exit code: $exitCode " }
|
||||
}
|
||||
|
||||
private fun validateBitcodeEmbedding(frameworkBinary: String) {
|
||||
@@ -269,4 +272,4 @@ open class FrameworkTest : DefaultTask(), KonanTestExecutable {
|
||||
}
|
||||
|
||||
private val xcode by lazy { Xcode.findCurrent() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,6 +334,9 @@ open class KonanLocalTest : KonanTest() {
|
||||
exitCode + other.exitCode)
|
||||
|
||||
private fun ProcessOutput.check() {
|
||||
val timeoutMessage = if (exitCode == -1) {
|
||||
"WARNING: probably a timeout\n"
|
||||
} else ""
|
||||
val exitCodeMismatch = !expectedExitStatusChecker(exitCode)
|
||||
if (exitCodeMismatch) {
|
||||
val message = if (expectedExitStatus != null)
|
||||
@@ -342,7 +345,7 @@ open class KonanLocalTest : KonanTest() {
|
||||
"Actual exit status doesn't match with exit status checker: $exitCode"
|
||||
check(expectedFail) {
|
||||
"""
|
||||
|Test failed. $message
|
||||
|${timeoutMessage}Test failed. $message
|
||||
|stdout:
|
||||
|$stdOut
|
||||
|stderr:
|
||||
@@ -358,7 +361,7 @@ open class KonanLocalTest : KonanTest() {
|
||||
val message = goldenData?.let { goldenData -> "Expected output: $goldenData, actual output: $output" }
|
||||
?: "Actual output doesn't match with output checker: $output"
|
||||
|
||||
check(expectedFail) { "Test failed. $message" }
|
||||
check(expectedFail) { "${timeoutMessage}Test failed. $message" }
|
||||
println("Expected failure. $message")
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.konan.target.TargetDomainObjectContainer
|
||||
import org.jetbrains.kotlin.konan.target.TargetWithSanitizer
|
||||
import org.jetbrains.kotlin.testing.native.GoogleTestExtension
|
||||
import org.jetbrains.kotlin.utils.capitalized
|
||||
import java.time.Duration
|
||||
import javax.inject.Inject
|
||||
|
||||
private fun String.snakeCaseToUpperCamelCase() = split('_').joinToString(separator = "") { it.capitalized }
|
||||
@@ -602,6 +603,7 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) :
|
||||
filter.set(project.findProperty("gtest_filter") as? String)
|
||||
tsanSuppressionsFile.set(project.layout.projectDirectory.file("tsan_suppressions.txt"))
|
||||
this.target.set(target)
|
||||
this.executionTimeout.set(Duration.ofMinutes(30)) // The tests binaries are big.
|
||||
|
||||
usesService(runGTestSemaphore)
|
||||
}
|
||||
@@ -647,4 +649,4 @@ open class CompileToBitcodePlugin : Plugin<Project> {
|
||||
project.apply<GitClangFormatPlugin>()
|
||||
project.extensions.create<CompileToBitcodeExtension>("bitcode", project)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@file:OptIn(kotlin.time.ExperimentalTime::class)
|
||||
package org.jetbrains.kotlin.cpp
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
@@ -15,7 +16,9 @@ import org.gradle.workers.WorkParameters
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.jetbrains.kotlin.native.executors.*
|
||||
import org.jetbrains.kotlin.konan.target.*
|
||||
import java.time.Duration
|
||||
import javax.inject.Inject
|
||||
import kotlin.time.toKotlinDuration
|
||||
|
||||
private abstract class RunGTestJob : WorkAction<RunGTestJob.Parameters> {
|
||||
interface Parameters : WorkParameters {
|
||||
@@ -29,6 +32,7 @@ private abstract class RunGTestJob : WorkAction<RunGTestJob.Parameters> {
|
||||
// TODO: Figure out a way to pass KonanTarget, but it is used as a key into PlatformManager,
|
||||
// so object identity matters, and platform managers are different between project and worker sides.
|
||||
val targetName: Property<String>
|
||||
val executionTimeout: Property<Duration>
|
||||
}
|
||||
|
||||
// The `Executor` is created for every `RunGTest` task execution. It's okay, testing tasks are few-ish and big.
|
||||
@@ -59,6 +63,7 @@ private abstract class RunGTestJob : WorkAction<RunGTestJob.Parameters> {
|
||||
tsanSuppressionsFile.orNull?.also {
|
||||
this.environment.put("TSAN_OPTIONS", "suppressions=${it.asFile.absolutePath}")
|
||||
}
|
||||
this.timeout = executionTimeout.get().toKotlinDuration()
|
||||
}).assertSuccess()
|
||||
|
||||
reportFile.asFile.get().parentFile.mkdirs()
|
||||
@@ -135,6 +140,12 @@ abstract class RunGTest : DefaultTask() {
|
||||
@get:Input
|
||||
abstract val target: Property<KonanTarget>
|
||||
|
||||
/**
|
||||
* Timeout for the test run.
|
||||
*/
|
||||
@get:Input
|
||||
abstract val executionTimeout: Property<Duration>
|
||||
|
||||
@TaskAction
|
||||
fun run() {
|
||||
val workQueue = workerExecutor.noIsolation()
|
||||
@@ -148,6 +159,7 @@ abstract class RunGTest : DefaultTask() {
|
||||
tsanSuppressionsFile.set(this@RunGTest.tsanSuppressionsFile)
|
||||
platformManager.set(project.extensions.getByType<PlatformManager>())
|
||||
targetName.set(this@RunGTest.target.get().name)
|
||||
executionTimeout.set(this@RunGTest.executionTimeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.native.executors
|
||||
|
||||
import java.io.*
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.ExperimentalTime
|
||||
|
||||
private class CloseProtectedOutputStream(stream : OutputStream) : FilterOutputStream(stream) {
|
||||
override fun close() {
|
||||
@@ -52,7 +51,7 @@ data class ExecuteRequest(
|
||||
/**
|
||||
* Bound execution time of the process. By default it's [Duration.INFINITE] meaning it's unbounded.
|
||||
*/
|
||||
val timeout: Duration = Duration.INFINITE
|
||||
var timeout: Duration = Duration.INFINITE
|
||||
) {
|
||||
/**
|
||||
* Create a copy of this [ExecuteRequest], modify the copy by running [block] on it, and return that copy.
|
||||
@@ -76,7 +75,13 @@ data class ExecuteResponse(
|
||||
* @throws IllegalStateException if [exitCode] is not 0.
|
||||
*/
|
||||
fun assertSuccess(): ExecuteResponse {
|
||||
check(exitCode == 0) { "Exited with code $exitCode" }
|
||||
check(exitCode == 0) {
|
||||
if (exitCode == null) {
|
||||
"Timed out in $executionTime"
|
||||
} else {
|
||||
"Exited with code $exitCode in $executionTime"
|
||||
}
|
||||
}
|
||||
return this
|
||||
}
|
||||
}
|
||||
@@ -95,4 +100,4 @@ interface Executor {
|
||||
* Run the process and wait for its completion.
|
||||
*/
|
||||
fun execute(request: ExecuteRequest): ExecuteResponse
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user