import org.jetbrains.kotlin.ideaExt.idea plugins { kotlin("jvm") id("jps-compatible") } project.configureJvmToolchain(JdkMajorVersion.JDK_11_0) dependencies { testImplementation(kotlinStdlib()) testImplementation(commonDependency("org.jetbrains.kotlin:kotlin-reflect")) { isTransitive = false } testImplementation(intellijCore()) testImplementation(commonDependency("commons-lang:commons-lang")) testImplementation(commonDependency("org.jetbrains.teamcity:serviceMessages")) testImplementation(project(":kotlin-compiler-runner-unshaded")) testImplementation(projectTests(":compiler:tests-common")) testImplementation(projectTests(":compiler:tests-common-new")) testImplementation(projectTests(":compiler:test-infrastructure")) testImplementation(projectTests(":generators:test-generator")) testApiJUnit5() testRuntimeOnly(commonDependency("org.jetbrains.intellij.deps:trove4j")) testRuntimeOnly(commonDependency("org.jetbrains.intellij.deps.fastutil:intellij-deps-fastutil")) } val generationRoot = projectDir.resolve("tests-gen") sourceSets { "main" { none() } "test" { projectDefault() java.srcDirs(generationRoot.name) } } if (kotlinBuildProperties.isInJpsBuildIdeaSync) { apply(plugin = "idea") idea { module.generatedSourceDirs.addAll(listOf(generationRoot)) } } enum class TestProperty(shortName: String) { // Use a separate Gradle property to pass Kotlin/Native home to tests: "kotlin.internal.native.test.nativeHome". // Don't use "kotlin.native.home" and similar properties for this purpose, as these properties may have undesired // effect on other Gradle tasks (ex: :kotlin-native:dist) that might be executed along with test task. KOTLIN_NATIVE_HOME("nativeHome"), COMPILER_CLASSPATH("compilerClasspath"), TEST_TARGET("target"), TEST_MODE("mode"), FORCE_STANDALONE("forceStandalone"), COMPILE_ONLY("compileOnly"), OPTIMIZATION_MODE("optimizationMode"), MEMORY_MODEL("memoryModel"), USE_THREAD_STATE_CHECKER("useThreadStateChecker"), GC_TYPE("gcType"), GC_SCHEDULER("gcScheduler"), CACHE_MODE("cacheMode"), EXECUTION_TIMEOUT("executionTimeout"), SANITIZER("sanitizer"); private val propertyName = "kotlin.internal.native.test.$shortName" fun setUpFromGradleProperty(task: Test, defaultValue: () -> String? = { null }) { val propertyValue = readGradleProperty(task) ?: defaultValue() if (propertyValue != null) task.systemProperty(propertyName, propertyValue) } fun readGradleProperty(task: Test): String? = task.project.findProperty(propertyName)?.toString() } fun nativeTest(taskName: String, vararg tags: String) = projectTest( taskName, jUnitMode = JUnitMode.JUnit5, maxHeapSizeMb = 3072 // Extra heap space for Kotlin/Native compiler. ) { group = "verification" if (kotlinBuildProperties.isKotlinNativeEnabled) { workingDir = rootDir outputs.upToDateWhen { // Don't treat any test task as up-to-date, no matter what. // Note: this project should contain only test tasks, including ones that build binaries, and ones that run binaries. false } // Effectively remove the limit for the amount of stack trace elements in Throwable. jvmArgs("-XX:MaxJavaStackTraceDepth=1000000") // Double the stack size. This is needed to compile some marginal tests with extra-deep IR tree, which requires a lot of stack frames // for visiting it. Example: codegen/box/strings/concatDynamicWithConstants.kt // Such tests are successfully compiled in old test infra with the default 1 MB stack just by accident. New test infra requires ~55 // additional stack frames more compared to the old one because of another launcher, etc. and it turns out this is not enough. jvmArgs("-Xss2m") val availableCpuCores: Int = Runtime.getRuntime().availableProcessors() if (!kotlinBuildProperties.isTeamcityBuild && minOf(kotlinBuildProperties.junit5NumberOfThreadsForParallelExecution ?: 16, availableCpuCores) > 4 ) { logger.info("$path JIT C2 compiler has been disabled") jvmArgs("-XX:TieredStopAtLevel=1") // Disable C2 if there are more than 4 CPUs at the host machine. } TestProperty.KOTLIN_NATIVE_HOME.setUpFromGradleProperty(this) { val testTarget = TestProperty.TEST_TARGET.readGradleProperty(this) dependsOn(if (testTarget != null) ":kotlin-native:${testTarget}CrossDist" else ":kotlin-native:dist") project(":kotlin-native").projectDir.resolve("dist").absolutePath } TestProperty.COMPILER_CLASSPATH.setUpFromGradleProperty(this) { val customNativeHome = TestProperty.KOTLIN_NATIVE_HOME.readGradleProperty(this) if (customNativeHome != null) { file(customNativeHome).resolve("konan/lib/kotlin-native-compiler-embeddable.jar").absolutePath } else { val kotlinNativeCompilerEmbeddable = configurations.detachedConfiguration(dependencies.project(":kotlin-native-compiler-embeddable")) dependsOn(kotlinNativeCompilerEmbeddable) kotlinNativeCompilerEmbeddable.files.joinToString(";") } } // Pass Gradle properties as JVM properties so test process can read them. TestProperty.TEST_TARGET.setUpFromGradleProperty(this) TestProperty.TEST_MODE.setUpFromGradleProperty(this) TestProperty.FORCE_STANDALONE.setUpFromGradleProperty(this) TestProperty.COMPILE_ONLY.setUpFromGradleProperty(this) TestProperty.OPTIMIZATION_MODE.setUpFromGradleProperty(this) TestProperty.MEMORY_MODEL.setUpFromGradleProperty(this) TestProperty.USE_THREAD_STATE_CHECKER.setUpFromGradleProperty(this) TestProperty.GC_TYPE.setUpFromGradleProperty(this) TestProperty.GC_SCHEDULER.setUpFromGradleProperty(this) TestProperty.CACHE_MODE.setUpFromGradleProperty(this) TestProperty.EXECUTION_TIMEOUT.setUpFromGradleProperty(this) TestProperty.SANITIZER.setUpFromGradleProperty(this) // Pass the current Gradle task name so test can use it in logging. environment("GRADLE_TASK_NAME", path) useJUnitPlatform { includeTags(*tags) } doFirst { logger.info( buildString { appendLine("$path parallel test execution parameters:") append(" Available CPU cores = $availableCpuCores") systemProperties.filterKeys { it.startsWith("junit.jupiter") }.toSortedMap().forEach { (key, value) -> append("\n $key = $value") } } ) } } else doFirst { throw GradleException( """ Can't run task $path. The Kotlin/Native part of the project is currently disabled. Make sure that "kotlin.native.enabled" is set to "true" in local.properties file, or is passed as a Gradle command-line parameter via "-Pkotlin.native.enabled=true". """.trimIndent() ) } } // Tasks that run different sorts of tests. Most frequent use case: running specific tests at TeamCity. val infrastructureTest = nativeTest("infrastructureTest", "infrastructure") val codegenBoxTest = nativeTest("codegenBoxTest", "codegen") val stdlibTest = nativeTest("stdlibTest", "stdlib") val kotlinTestLibraryTest = nativeTest("kotlinTestLibraryTest", "kotlin-test") val klibAbiTest = nativeTest("klibAbiTest", "klib-abi") val klibBinaryCompatibilityTest = nativeTest("klibBinaryCompatibilityTest", "klib-binary-compatibility") // "test" task is created by convention. We can't just remove it. Let's enable it in developer's environment, so it can be used // to run any test from IDE or from console, but disable it at TeamCity where it is not supposed to be ever used. val test by nativeTest("test" /* no tags */).apply { if (kotlinBuildProperties.isTeamcityBuild) { configure { doFirst { throw GradleException("Task $path is not supposed to be executed in TeamCity environment") } } } } val generateTests by generator("org.jetbrains.kotlin.generators.tests.GenerateNativeTestsKt") { javaLauncher.set(project.getToolchainLauncherFor(JdkMajorVersion.JDK_11_0)) dependsOn(":compiler:generateTestData") }