Add support for tests mute-in database in JUnit 5.
^KT-45744 In Progress
This commit is contained in:
committed by
TeamCityServer
parent
7ffdafe791
commit
8b393910d3
@@ -97,6 +97,7 @@ dependencies {
|
|||||||
|
|
||||||
testCompile(intellijDep()) { includeJars("platform-util-ui", "platform-concurrency", "platform-objectSerializer") }
|
testCompile(intellijDep()) { includeJars("platform-util-ui", "platform-concurrency", "platform-objectSerializer") }
|
||||||
testCompile(intellijDep()) { includeJars("platform-ide-util-io") }
|
testCompile(intellijDep()) { includeJars("platform-ide-util-io") }
|
||||||
|
testApiJUnit5()
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>> {
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.test
|
|||||||
import junit.framework.TestCase
|
import junit.framework.TestCase
|
||||||
import org.jetbrains.kotlin.test.mutes.*
|
import org.jetbrains.kotlin.test.mutes.*
|
||||||
import org.junit.internal.runners.statements.InvokeMethod
|
import org.junit.internal.runners.statements.InvokeMethod
|
||||||
|
import org.junit.jupiter.api.extension.*
|
||||||
import org.junit.runner.Runner
|
import org.junit.runner.Runner
|
||||||
import org.junit.runner.notification.RunNotifier
|
import org.junit.runner.notification.RunNotifier
|
||||||
import org.junit.runners.BlockJUnit4ClassRunner
|
import org.junit.runners.BlockJUnit4ClassRunner
|
||||||
@@ -16,6 +17,7 @@ import org.junit.runners.model.Statement
|
|||||||
import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters
|
import org.junit.runners.parameterized.BlockJUnit4ClassRunnerWithParameters
|
||||||
import org.junit.runners.parameterized.ParametersRunnerFactory
|
import org.junit.runners.parameterized.ParametersRunnerFactory
|
||||||
import org.junit.runners.parameterized.TestWithParameters
|
import org.junit.runners.parameterized.TestWithParameters
|
||||||
|
import java.lang.reflect.Method
|
||||||
|
|
||||||
internal fun wrapWithMuteInDatabase(testCase: TestCase, f: () -> Unit): (() -> Unit)? {
|
internal fun wrapWithMuteInDatabase(testCase: TestCase, f: () -> Unit): (() -> Unit)? {
|
||||||
return wrapWithMuteInDatabase(testCase.javaClass, testCase.name, f)
|
return wrapWithMuteInDatabase(testCase.javaClass, testCase.name, f)
|
||||||
@@ -95,3 +97,102 @@ fun TestCase.runTest(test: () -> Unit) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
annotation class WithMutedInDatabaseRunTest
|
annotation class WithMutedInDatabaseRunTest
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension for JUnit 5 tests adding mute-in database support to ignore flaky/failed tests.
|
||||||
|
*
|
||||||
|
* Just add it to the test class or test method.
|
||||||
|
*/
|
||||||
|
@Target(AnnotationTarget.CLASS, AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.FUNCTION)
|
||||||
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
|
@ExtendWith(MuteInCondition::class, MuteInTestWatcher::class, MuteInInvocationInterceptor::class)
|
||||||
|
annotation class WithMuteInDatabase
|
||||||
|
|
||||||
|
private val ExtensionContext.testClassNullable get() = testClass.orElseGet { null }
|
||||||
|
private val ExtensionContext.testMethodNullable get() = testMethod.orElseGet { null }
|
||||||
|
|
||||||
|
class MuteInCondition : ExecutionCondition {
|
||||||
|
override fun evaluateExecutionCondition(
|
||||||
|
context: ExtensionContext
|
||||||
|
): ConditionEvaluationResult {
|
||||||
|
val testClass = context.testClassNullable
|
||||||
|
val testMethod = context.testMethodNullable
|
||||||
|
|
||||||
|
return if (testClass != null &&
|
||||||
|
testMethod != null &&
|
||||||
|
isMutedInDatabaseWithLog(testClass, testMethod.name)
|
||||||
|
) {
|
||||||
|
ConditionEvaluationResult.disabled("Muted")
|
||||||
|
} else {
|
||||||
|
enabled
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private val enabled = ConditionEvaluationResult.enabled("Not found in mute-in database")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MuteInTestWatcher : TestWatcher {
|
||||||
|
override fun testFailed(
|
||||||
|
context: ExtensionContext,
|
||||||
|
cause: Throwable
|
||||||
|
) {
|
||||||
|
val testClass = context.testClassNullable
|
||||||
|
val testMethod = context.testMethodNullable
|
||||||
|
if (testClass != null &&
|
||||||
|
testMethod != null
|
||||||
|
) {
|
||||||
|
DO_AUTO_MUTE?.muteTest(
|
||||||
|
testKey(testClass, testMethod.name)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MuteInInvocationInterceptor : InvocationInterceptor {
|
||||||
|
override fun interceptTestTemplateMethod(
|
||||||
|
invocation: InvocationInterceptor.Invocation<Void>,
|
||||||
|
invocationContext: ReflectiveInvocationContext<Method>,
|
||||||
|
extensionContext: ExtensionContext
|
||||||
|
) {
|
||||||
|
interceptWithMuteInDatabase(invocation, extensionContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun interceptTestMethod(
|
||||||
|
invocation: InvocationInterceptor.Invocation<Void>,
|
||||||
|
invocationContext: ReflectiveInvocationContext<Method>,
|
||||||
|
extensionContext: ExtensionContext
|
||||||
|
) {
|
||||||
|
interceptWithMuteInDatabase(invocation, extensionContext)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun interceptWithMuteInDatabase(
|
||||||
|
invocation: InvocationInterceptor.Invocation<Void>,
|
||||||
|
extensionContext: ExtensionContext
|
||||||
|
) {
|
||||||
|
val testClass = extensionContext.testClassNullable
|
||||||
|
val testMethod = extensionContext.testMethodNullable
|
||||||
|
if (testClass != null &&
|
||||||
|
testMethod != null
|
||||||
|
) {
|
||||||
|
val mutedTest = getMutedTest(testClass, testMethod.name)
|
||||||
|
if (mutedTest != null &&
|
||||||
|
isPresentedInDatabaseWithoutFailMarker(mutedTest)
|
||||||
|
) {
|
||||||
|
if (mutedTest.isFlaky) {
|
||||||
|
invocation.proceed()
|
||||||
|
return
|
||||||
|
} else {
|
||||||
|
invertMutedTestResultWithLog(
|
||||||
|
f = { invocation.proceed() },
|
||||||
|
testKey = testKey(testMethod.declaringClass, mutedTest.methodKey)
|
||||||
|
)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
invocation.proceed()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+2
@@ -11,6 +11,7 @@ import org.gradle.internal.impldep.org.junit.platform.commons.support.Annotation
|
|||||||
import org.gradle.util.GradleVersion
|
import org.gradle.util.GradleVersion
|
||||||
import org.jetbrains.kotlin.gradle.KOTLIN_VERSION
|
import org.jetbrains.kotlin.gradle.KOTLIN_VERSION
|
||||||
import org.jetbrains.kotlin.gradle.utils.minSupportedGradleVersion
|
import org.jetbrains.kotlin.gradle.utils.minSupportedGradleVersion
|
||||||
|
import org.jetbrains.kotlin.test.WithMuteInDatabase
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import org.junit.jupiter.api.TestInstance
|
import org.junit.jupiter.api.TestInstance
|
||||||
@@ -28,6 +29,7 @@ import kotlin.streams.asStream
|
|||||||
* Base class for all Kotlin Gradle plugin integration tests.
|
* Base class for all Kotlin Gradle plugin integration tests.
|
||||||
*/
|
*/
|
||||||
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
|
||||||
|
@WithMuteInDatabase
|
||||||
abstract class KGPBaseTest {
|
abstract class KGPBaseTest {
|
||||||
open val defaultBuildOptions = BuildOptions()
|
open val defaultBuildOptions = BuildOptions()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user