Store mute tests database in the code instead of build server

This commit is contained in:
Nikolay Krasko
2019-10-22 20:39:21 +03:00
parent edc1fa3ae8
commit 01d3b8d9c4
4 changed files with 116 additions and 1 deletions
@@ -30,6 +30,7 @@ import junit.framework.TestCase;
import kotlin.Unit;
import kotlin.collections.CollectionsKt;
import kotlin.collections.SetsKt;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.functions.Function1;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -711,6 +712,11 @@ public class KotlinTestUtils {
runTestImpl(testWithCustomIgnoreDirective(test, TargetBackend.ANY, IGNORE_BACKEND_DIRECTIVE_PREFIX), testCase, testDataFile);
}
public static void runTest(@NotNull TestCase testCase, @NotNull Function0 test) {
//noinspection unchecked
MuteWithDatabaseKt.runTest(testCase, test);
}
// In this test runner version the `testDataFile` parameter is annotated by `TestDataFile`.
// So only file paths passed to this parameter will be used in navigation actions, like "Navigate to testdata" and "Related Symbol..."
public static void runTest(DoTest test, TargetBackend targetBackend, @TestDataFile String testDataFile) throws Exception {
@@ -0,0 +1,104 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.test
import junit.framework.TestCase
import java.io.File
private class MutedTest(
val key: String,
val issue: String?,
val hasFailFile: Boolean
) {
val methodName = key.substringAfterLast(".", "").also {
if (it.isEmpty()) throw IllegalArgumentException("Can't get method name")
}
val classNameKey = key.substringBeforeLast(".", "").also {
if (it.isEmpty()) throw IllegalArgumentException("Can't get class name")
}
val simpleClassName = classNameKey.substringAfterLast(".")
}
private class MutedSet(muted: List<MutedTest>) {
// Method name -> Simple class name -> List of muted tests
private val cache: Map<String, Map<String, List<MutedTest>>> =
muted
.groupBy { it.methodName } // Method name -> List of muted tests
.mapValues { (_, tests) -> tests.groupBy { it.simpleClassName } }
fun mutedTest(testCase: TestCase): MutedTest? {
val mutedTests = cache[testCase.name]?.get(testCase.javaClass.simpleName) ?: return null
return mutedTests.singleOrNull { mutedTest ->
testCase.javaClass.canonicalName.endsWith(mutedTest.classNameKey)
}
}
}
private fun loadMutedSet(file: File): MutedSet {
if (!file.exists()) {
System.err.println("Can't find mute file: ${file.absolutePath}")
return MutedSet(listOf())
}
try {
val testLines = file.readLines()
.asSequence()
.map { it.trim() }
.filter { it.isNotEmpty() }
.toList()
val mutedTests = testLines.drop(1).map { parseMutedTest(it) }
return MutedSet(mutedTests)
} catch (ex: Throwable) {
throw ParseError("Couldn't parse file with muted tests: $file", cause = ex)
}
}
private fun parseMutedTest(str: String): MutedTest {
val components = str.splitToSequence(",").map { it.trim() }.toList()
val key = components.getOrNull(0) ?: throw ParseError("Test key is absent (1 column): $str")
val issue = components.getOrNull(1)
val hasFailFile = when (val stateStr = components.getOrNull(2)) {
"MUTE", "", null -> false
"FAIL" -> true
else -> throw ParseError("Invalid state (`$stateStr`), MUTE, FAIL or empty are expected: $str")
}
return MutedTest(key, issue, hasFailFile)
}
private class ParseError(message: String, override val cause: Throwable? = null) : IllegalArgumentException(message)
private val mutedSet by lazy { loadMutedSet(File("tests/mute.csv")) }
internal fun isMutedInDatabase(testCase: TestCase): Boolean {
val mutedTest = mutedSet.mutedTest(testCase)
return mutedTest != null && !mutedTest.hasFailFile
}
internal fun wrapWithMuteInDatabase(testCase: TestCase, f: () -> Unit): () -> Unit {
if (!isMutedInDatabase(testCase)) return f
return { MUTED_DO_TEST_LAMBDA(testCase) }
}
internal val MUTED_DO_TEST_LAMBDA = { testCase: TestCase ->
System.err.println("MUTED TEST: ${testCase::class.java.name}.${testCase.name}")
}
internal class MutedDoTest(val testCase: TestCase) : KotlinTestUtils.DoTest {
override fun invoke(filePath: String) {
MUTED_DO_TEST_LAMBDA(testCase)
}
}
fun TestCase.runTest(test: () -> Unit) {
wrapWithMuteInDatabase(this, test).invoke()
}
@@ -18,6 +18,10 @@ annotation class MuteExtraSuffix(val value: String = "")
@Throws(Exception::class)
fun testWithMuteInFile(test: DoTest, testCase: TestCase): DoTest {
if (isMutedInDatabase(testCase)) {
return MutedDoTest(testCase)
}
val extraSuffix = testCase.javaClass.getAnnotation(MuteExtraSuffix::class.java)?.value ?: ""
return testWithMuteInFile(test, extraSuffix)
}
@@ -30,7 +34,7 @@ fun testWithMuteInFile(test: DoTest, extraSuffix: String): DoTest {
val isMutedWithFile = isMutedWithFile(testDataFile, extraSuffix)
if (isMutedWithFile && !RUN_MUTED_TESTS) {
System.err.println("IGNORED TEST: $filePath")
System.err.println("MUTED TEST: $filePath")
return
}
+1
View File
@@ -0,0 +1 @@
Test key, Issue, State (optional: MUTE or FAIL)
1 Test key Issue State (optional: MUTE or FAIL)