[Test] Parallelize test generation
This commit is contained in:
committed by
Space Team
parent
0d04e170b1
commit
bb8a46c3a0
+10
-8
@@ -8,26 +8,28 @@ package org.jetbrains.kotlin.generators.impl
|
|||||||
import org.jetbrains.kotlin.generators.InconsistencyChecker
|
import org.jetbrains.kotlin.generators.InconsistencyChecker
|
||||||
import org.jetbrains.kotlin.generators.InconsistencyChecker.Companion.inconsistencyChecker
|
import org.jetbrains.kotlin.generators.InconsistencyChecker.Companion.inconsistencyChecker
|
||||||
import org.jetbrains.kotlin.generators.TestGroupSuite
|
import org.jetbrains.kotlin.generators.TestGroupSuite
|
||||||
|
import org.jetbrains.kotlin.generators.forEachTestClassParallel
|
||||||
import org.jetbrains.kotlin.generators.testGroupSuite
|
import org.jetbrains.kotlin.generators.testGroupSuite
|
||||||
|
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
|
||||||
|
|
||||||
fun generateTestGroupSuite(
|
fun generateTestGroupSuite(
|
||||||
args: Array<String>,
|
args: Array<String>,
|
||||||
|
mainClassName: String? = TestGeneratorUtil.getMainClassName(),
|
||||||
init: TestGroupSuite.() -> Unit
|
init: TestGroupSuite.() -> Unit
|
||||||
) {
|
) {
|
||||||
generateTestGroupSuite(InconsistencyChecker.hasDryRunArg(args), init)
|
generateTestGroupSuite(InconsistencyChecker.hasDryRunArg(args), mainClassName, init)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateTestGroupSuite(
|
fun generateTestGroupSuite(
|
||||||
dryRun: Boolean = false,
|
dryRun: Boolean = false,
|
||||||
init: TestGroupSuite.() -> Unit
|
mainClassName: String? = TestGeneratorUtil.getMainClassName(),
|
||||||
|
init: TestGroupSuite.() -> Unit,
|
||||||
) {
|
) {
|
||||||
val suite = testGroupSuite(init)
|
val suite = testGroupSuite(init)
|
||||||
for (testGroup in suite.testGroups) {
|
suite.forEachTestClassParallel { testClass ->
|
||||||
for (testClass in testGroup.testClasses) {
|
val (changed, testSourceFilePath) = TestGeneratorImpl.generateAndSave(testClass, dryRun, mainClassName)
|
||||||
val (changed, testSourceFilePath) = TestGeneratorImpl.generateAndSave(testClass, dryRun)
|
if (changed) {
|
||||||
if (changed) {
|
inconsistencyChecker(dryRun).add(testSourceFilePath)
|
||||||
inconsistencyChecker(dryRun).add(testSourceFilePath)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-5
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.generators.TestGenerator
|
|||||||
import org.jetbrains.kotlin.generators.TestGroup
|
import org.jetbrains.kotlin.generators.TestGroup
|
||||||
import org.jetbrains.kotlin.generators.model.*
|
import org.jetbrains.kotlin.generators.model.*
|
||||||
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil
|
import org.jetbrains.kotlin.generators.util.GeneratorsFileUtil
|
||||||
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil.getMainClassName
|
|
||||||
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
|
import org.jetbrains.kotlin.test.JUnit3RunnerWithInners
|
||||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||||
import org.jetbrains.kotlin.test.TestMetadata
|
import org.jetbrains.kotlin.test.TestMetadata
|
||||||
@@ -31,14 +30,15 @@ private val METHOD_GENERATORS = listOf(
|
|||||||
)
|
)
|
||||||
|
|
||||||
object TestGeneratorImpl : TestGenerator(METHOD_GENERATORS) {
|
object TestGeneratorImpl : TestGenerator(METHOD_GENERATORS) {
|
||||||
override fun generateAndSave(testClass: TestGroup.TestClass, dryRun: Boolean): GenerationResult {
|
override fun generateAndSave(testClass: TestGroup.TestClass, dryRun: Boolean, mainClassName: String?): GenerationResult {
|
||||||
val generatorInstance = TestGeneratorImplInstance(
|
val generatorInstance = TestGeneratorImplInstance(
|
||||||
testClass.baseDir,
|
testClass.baseDir,
|
||||||
testClass.suiteTestClassName,
|
testClass.suiteTestClassName,
|
||||||
testClass.baseTestClassName,
|
testClass.baseTestClassName,
|
||||||
testClass.testModels,
|
testClass.testModels,
|
||||||
testClass.useJunit4,
|
testClass.useJunit4,
|
||||||
methodGenerators
|
methodGenerators,
|
||||||
|
mainClassName,
|
||||||
)
|
)
|
||||||
return generatorInstance.generateAndSave(dryRun)
|
return generatorInstance.generateAndSave(dryRun)
|
||||||
}
|
}
|
||||||
@@ -50,7 +50,8 @@ private class TestGeneratorImplInstance(
|
|||||||
baseTestClassFqName: String,
|
baseTestClassFqName: String,
|
||||||
private val testClassModels: Collection<TestClassModel>,
|
private val testClassModels: Collection<TestClassModel>,
|
||||||
private val useJunit4: Boolean,
|
private val useJunit4: Boolean,
|
||||||
private val methodGenerators: Map<MethodModel.Kind, MethodGenerator<*>>
|
private val methodGenerators: Map<MethodModel.Kind, MethodGenerator<*>>,
|
||||||
|
private val mainClassName: String?
|
||||||
) {
|
) {
|
||||||
companion object {
|
companion object {
|
||||||
private val GENERATED_FILES = HashSet<String>()
|
private val GENERATED_FILES = HashSet<String>()
|
||||||
@@ -147,7 +148,7 @@ private class TestGeneratorImplInstance(
|
|||||||
p.println("import java.io.File;")
|
p.println("import java.io.File;")
|
||||||
p.println("import java.util.regex.Pattern;")
|
p.println("import java.util.regex.Pattern;")
|
||||||
p.println()
|
p.println()
|
||||||
p.println("/** This class is generated by {@link ", getMainClassName(), "}. DO NOT MODIFY MANUALLY */")
|
p.println("/** This class is generated by {@link ", mainClassName, "}. DO NOT MODIFY MANUALLY */")
|
||||||
|
|
||||||
generateSuppressAllWarnings(p)
|
generateSuppressAllWarnings(p)
|
||||||
|
|
||||||
|
|||||||
+8
-2
@@ -5,9 +5,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.test.generators
|
package org.jetbrains.kotlin.test.generators
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
|
||||||
|
import java.util.stream.Stream
|
||||||
|
|
||||||
fun main(args: Array<String>) {
|
fun main(args: Array<String>) {
|
||||||
System.setProperty("java.awt.headless", "true")
|
System.setProperty("java.awt.headless", "true")
|
||||||
|
// Determine main class name while still on main thread.
|
||||||
|
val mainClassName = TestGeneratorUtil.getMainClassName()
|
||||||
|
|
||||||
generateJUnit3CompilerTests(args)
|
Stream.of(::generateJUnit3CompilerTests, ::generateJUnit5CompilerTests)
|
||||||
generateJUnit5CompilerTests(args)
|
.parallel()
|
||||||
|
.forEach { it.invoke(args, mainClassName) }
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -50,10 +50,10 @@ import org.jetbrains.kotlin.test.TargetBackend
|
|||||||
import org.jetbrains.kotlin.test.utils.CUSTOM_TEST_DATA_EXTENSION_PATTERN
|
import org.jetbrains.kotlin.test.utils.CUSTOM_TEST_DATA_EXTENSION_PATTERN
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeBindingTest
|
import org.jetbrains.kotlin.types.AbstractTypeBindingTest
|
||||||
|
|
||||||
fun generateJUnit3CompilerTests(args: Array<String>) {
|
fun generateJUnit3CompilerTests(args: Array<String>, mainClassName: String?) {
|
||||||
val excludedCustomTestdataPattern = CUSTOM_TEST_DATA_EXTENSION_PATTERN
|
val excludedCustomTestdataPattern = CUSTOM_TEST_DATA_EXTENSION_PATTERN
|
||||||
|
|
||||||
generateTestGroupSuite(args) {
|
generateTestGroupSuite(args, mainClassName) {
|
||||||
testGroup("compiler/tests-gen", "compiler/testData") {
|
testGroup("compiler/tests-gen", "compiler/testData") {
|
||||||
testClass<AbstractDiagnosticsTestWithJsStdLibAndBackendCompilation> {
|
testClass<AbstractDiagnosticsTestWithJsStdLibAndBackendCompilation> {
|
||||||
model("diagnostics/testsWithJsStdLibAndBackendCompilation")
|
model("diagnostics/testsWithJsStdLibAndBackendCompilation")
|
||||||
|
|||||||
+2
-2
@@ -17,10 +17,10 @@ import org.jetbrains.kotlin.test.utils.CUSTOM_TEST_DATA_EXTENSION_PATTERN
|
|||||||
import org.jetbrains.kotlin.visualizer.fir.AbstractFirVisualizerTest
|
import org.jetbrains.kotlin.visualizer.fir.AbstractFirVisualizerTest
|
||||||
import org.jetbrains.kotlin.visualizer.psi.AbstractPsiVisualizerTest
|
import org.jetbrains.kotlin.visualizer.psi.AbstractPsiVisualizerTest
|
||||||
|
|
||||||
fun generateJUnit5CompilerTests(args: Array<String>) {
|
fun generateJUnit5CompilerTests(args: Array<String>, mainClassName: String?) {
|
||||||
val excludedCustomTestdataPattern = CUSTOM_TEST_DATA_EXTENSION_PATTERN
|
val excludedCustomTestdataPattern = CUSTOM_TEST_DATA_EXTENSION_PATTERN
|
||||||
|
|
||||||
generateTestGroupSuiteWithJUnit5(args) {
|
generateTestGroupSuiteWithJUnit5(args, mainClassName) {
|
||||||
testGroup(testsRoot = "compiler/tests-common-new/tests-gen", testDataRoot = "compiler/testData") {
|
testGroup(testsRoot = "compiler/tests-common-new/tests-gen", testDataRoot = "compiler/testData") {
|
||||||
testClass<AbstractDiagnosticTest> {
|
testClass<AbstractDiagnosticTest> {
|
||||||
model("diagnostics/tests", pattern = "^(.*)\\.kts?$", excludedPattern = excludedCustomTestdataPattern)
|
model("diagnostics/tests", pattern = "^(.*)\\.kts?$", excludedPattern = excludedCustomTestdataPattern)
|
||||||
|
|||||||
+3
-1
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.generators
|
package org.jetbrains.kotlin.generators
|
||||||
|
|
||||||
|
import java.util.Collections
|
||||||
|
|
||||||
interface InconsistencyChecker {
|
interface InconsistencyChecker {
|
||||||
fun add(affectedFile: String)
|
fun add(affectedFile: String)
|
||||||
|
|
||||||
@@ -18,7 +20,7 @@ interface InconsistencyChecker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
object DefaultInconsistencyChecker : InconsistencyChecker {
|
object DefaultInconsistencyChecker : InconsistencyChecker {
|
||||||
private val files = mutableListOf<String>()
|
private val files = Collections.synchronizedList(mutableListOf<String>())
|
||||||
|
|
||||||
override fun add(affectedFile: String) {
|
override fun add(affectedFile: String) {
|
||||||
files.add(affectedFile)
|
files.add(affectedFile)
|
||||||
|
|||||||
+15
-9
@@ -5,26 +5,32 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.generators
|
package org.jetbrains.kotlin.generators
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
|
||||||
|
|
||||||
fun generateTestGroupSuiteWithJUnit5(
|
fun generateTestGroupSuiteWithJUnit5(
|
||||||
args: Array<String>,
|
args: Array<String>,
|
||||||
|
// Main class name can only be determined when running on the main thread.
|
||||||
|
// If this call is not made on the main thread, the main class name must be injected.
|
||||||
|
mainClassName: String? = TestGeneratorUtil.getMainClassName(),
|
||||||
additionalMethodGenerators: List<MethodGenerator<Nothing>> = emptyList(),
|
additionalMethodGenerators: List<MethodGenerator<Nothing>> = emptyList(),
|
||||||
init: TestGroupSuite.() -> Unit
|
init: TestGroupSuite.() -> Unit,
|
||||||
) {
|
) {
|
||||||
generateTestGroupSuiteWithJUnit5(InconsistencyChecker.hasDryRunArg(args), additionalMethodGenerators, init)
|
generateTestGroupSuiteWithJUnit5(InconsistencyChecker.hasDryRunArg(args), mainClassName, additionalMethodGenerators, init)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun generateTestGroupSuiteWithJUnit5(
|
fun generateTestGroupSuiteWithJUnit5(
|
||||||
dryRun: Boolean = false,
|
dryRun: Boolean = false,
|
||||||
|
// See above
|
||||||
|
mainClassName: String? = TestGeneratorUtil.getMainClassName(),
|
||||||
additionalMethodGenerators: List<MethodGenerator<Nothing>> = emptyList(),
|
additionalMethodGenerators: List<MethodGenerator<Nothing>> = emptyList(),
|
||||||
init: TestGroupSuite.() -> Unit
|
init: TestGroupSuite.() -> Unit,
|
||||||
) {
|
) {
|
||||||
val suite = TestGroupSuite(ReflectionBasedTargetBackendComputer).apply(init)
|
val suite = TestGroupSuite(ReflectionBasedTargetBackendComputer).apply(init)
|
||||||
for (testGroup in suite.testGroups) {
|
suite.forEachTestClassParallel { testClass ->
|
||||||
for (testClass in testGroup.testClasses) {
|
val (changed, testSourceFilePath) = NewTestGeneratorImpl(additionalMethodGenerators)
|
||||||
val (changed, testSourceFilePath) = NewTestGeneratorImpl(additionalMethodGenerators).generateAndSave(testClass, dryRun)
|
.generateAndSave(testClass, dryRun, mainClassName)
|
||||||
if (changed) {
|
if (changed) {
|
||||||
InconsistencyChecker.inconsistencyChecker(dryRun).add(testSourceFilePath)
|
InconsistencyChecker.inconsistencyChecker(dryRun).add(testSourceFilePath)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-4
@@ -75,13 +75,14 @@ class NewTestGeneratorImpl(
|
|||||||
println("@SuppressWarnings(\"all\")")
|
println("@SuppressWarnings(\"all\")")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun generateAndSave(testClass: TestGroup.TestClass, dryRun: Boolean): GenerationResult {
|
override fun generateAndSave(testClass: TestGroup.TestClass, dryRun: Boolean, mainClassName: String?): GenerationResult {
|
||||||
val generatorInstance = TestGeneratorInstance(
|
val generatorInstance = TestGeneratorInstance(
|
||||||
testClass.baseDir,
|
testClass.baseDir,
|
||||||
testClass.suiteTestClassName,
|
testClass.suiteTestClassName,
|
||||||
testClass.baseTestClassName,
|
testClass.baseTestClassName,
|
||||||
testClass.testModels,
|
testClass.testModels,
|
||||||
methodGenerators
|
methodGenerators,
|
||||||
|
mainClassName,
|
||||||
)
|
)
|
||||||
return generatorInstance.generateAndSave(dryRun)
|
return generatorInstance.generateAndSave(dryRun)
|
||||||
}
|
}
|
||||||
@@ -91,7 +92,8 @@ class NewTestGeneratorImpl(
|
|||||||
suiteTestClassFqName: String,
|
suiteTestClassFqName: String,
|
||||||
baseTestClassFqName: String,
|
baseTestClassFqName: String,
|
||||||
private val testClassModels: Collection<TestClassModel>,
|
private val testClassModels: Collection<TestClassModel>,
|
||||||
private val methodGenerators: Map<MethodModel.Kind, MethodGenerator<*>>
|
private val methodGenerators: Map<MethodModel.Kind, MethodGenerator<*>>,
|
||||||
|
private val mainClassName: String?
|
||||||
) {
|
) {
|
||||||
private val baseTestClassPackage: String = baseTestClassFqName.substringBeforeLast('.', "")
|
private val baseTestClassPackage: String = baseTestClassFqName.substringBeforeLast('.', "")
|
||||||
private val baseTestClassName: String = baseTestClassFqName.substringAfterLast('.', baseTestClassFqName)
|
private val baseTestClassName: String = baseTestClassFqName.substringAfterLast('.', baseTestClassFqName)
|
||||||
@@ -154,7 +156,7 @@ class NewTestGeneratorImpl(
|
|||||||
p.println("import java.io.File;")
|
p.println("import java.io.File;")
|
||||||
p.println("import java.util.regex.Pattern;")
|
p.println("import java.util.regex.Pattern;")
|
||||||
p.println()
|
p.println()
|
||||||
p.println("/** This class is generated by {@link ", getMainClassName(), "}. DO NOT MODIFY MANUALLY */")
|
p.println("/** This class is generated by {@link ", mainClassName, "}. DO NOT MODIFY MANUALLY */")
|
||||||
|
|
||||||
p.generateSuppressAllWarnings()
|
p.generateSuppressAllWarnings()
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
|
|||||||
import org.jetbrains.kotlin.generators.util.extractTagsFromDirectory
|
import org.jetbrains.kotlin.generators.util.extractTagsFromDirectory
|
||||||
import org.jetbrains.kotlin.test.TargetBackend
|
import org.jetbrains.kotlin.test.TargetBackend
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.concurrent.ForkJoinPool
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
|
|
||||||
@@ -19,6 +20,14 @@ fun testGroupSuite(
|
|||||||
return TestGroupSuite(DefaultTargetBackendComputer).apply(init)
|
return TestGroupSuite(DefaultTargetBackendComputer).apply(init)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun TestGroupSuite.forEachTestClassParallel(f: (TestGroup.TestClass) -> Unit) {
|
||||||
|
testGroups
|
||||||
|
.parallelStream()
|
||||||
|
.flatMap { it.testClasses.stream() }
|
||||||
|
.sorted(compareByDescending { it.testModels.sumOf { it.methods.size } })
|
||||||
|
.forEach(f)
|
||||||
|
}
|
||||||
|
|
||||||
class TestGroupSuite(val targetBackendComputer: TargetBackendComputer) {
|
class TestGroupSuite(val targetBackendComputer: TargetBackendComputer) {
|
||||||
private val _testGroups = mutableListOf<TestGroup>()
|
private val _testGroups = mutableListOf<TestGroup>()
|
||||||
val testGroups: List<TestGroup>
|
val testGroups: List<TestGroup>
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ abstract class TestGenerator(
|
|||||||
protected val methodGenerators: Map<MethodModel.Kind, MethodGenerator<*>> =
|
protected val methodGenerators: Map<MethodModel.Kind, MethodGenerator<*>> =
|
||||||
methodGenerators.associateBy { it.kind }.withDefault { error("Generator for method with kind $it not found") }
|
methodGenerators.associateBy { it.kind }.withDefault { error("Generator for method with kind $it not found") }
|
||||||
|
|
||||||
abstract fun generateAndSave(testClass: TestGroup.TestClass, dryRun: Boolean): GenerationResult
|
abstract fun generateAndSave(testClass: TestGroup.TestClass, dryRun: Boolean, mainClassName: String?): GenerationResult
|
||||||
|
|
||||||
data class GenerationResult(val newFileGenerated: Boolean, val testSourceFilePath: String)
|
data class GenerationResult(val newFileGenerated: Boolean, val testSourceFilePath: String)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -36,6 +36,7 @@ object TestGeneratorUtil {
|
|||||||
return escapeForJavaIdentifier(file.name).replaceFirstChar(Char::uppercaseChar)
|
return escapeForJavaIdentifier(file.name).replaceFirstChar(Char::uppercaseChar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Must be called on the main thread, otherwise returns the root class of the worker thread. */
|
||||||
fun getMainClassName(): String? =
|
fun getMainClassName(): String? =
|
||||||
Throwable().stackTrace.lastOrNull()?.className
|
Throwable().stackTrace.lastOrNull()?.className
|
||||||
}
|
}
|
||||||
|
|||||||
+9
-9
@@ -7,24 +7,24 @@ package org.jetbrains.kotlin.project.model.infra.generate
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.generators.*
|
import org.jetbrains.kotlin.generators.*
|
||||||
import org.jetbrains.kotlin.generators.model.*
|
import org.jetbrains.kotlin.generators.model.*
|
||||||
|
import org.jetbrains.kotlin.generators.util.TestGeneratorUtil
|
||||||
import org.jetbrains.kotlin.project.model.infra.KpmCoreCasesTestRunner
|
import org.jetbrains.kotlin.project.model.infra.KpmCoreCasesTestRunner
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
fun generateKpmTestCases(
|
fun generateKpmTestCases(
|
||||||
dryRun: Boolean = false,
|
dryRun: Boolean = false,
|
||||||
init: TestGroupSuite.() -> Unit
|
init: TestGroupSuite.() -> Unit,
|
||||||
) {
|
) {
|
||||||
val suite = TestGroupSuite(DefaultTargetBackendComputer).apply {
|
val suite = TestGroupSuite(DefaultTargetBackendComputer).apply {
|
||||||
init()
|
init()
|
||||||
}
|
}
|
||||||
for (testGroup in suite.testGroups) {
|
val mainClassName = TestGeneratorUtil.getMainClassName()
|
||||||
for (testClass in testGroup.testClasses) {
|
suite.forEachTestClassParallel { testClass ->
|
||||||
val (changed, testSourceFilePath) = NewTestGeneratorImpl(
|
val (changed, testSourceFilePath) = NewTestGeneratorImpl(
|
||||||
listOf(KpmCoreCaseTestMethodGenerator)
|
listOf(KpmCoreCaseTestMethodGenerator)
|
||||||
).generateAndSave(testClass, dryRun)
|
).generateAndSave(testClass, dryRun, mainClassName)
|
||||||
if (changed) {
|
if (changed) {
|
||||||
InconsistencyChecker.inconsistencyChecker(dryRun).add(testSourceFilePath)
|
InconsistencyChecker.inconsistencyChecker(dryRun).add(testSourceFilePath)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user