KGP - Fix flaky tests invoking javac through JDK APIs

Tests invoking javac APIs were flaky because ClasspathAnalyzerTest
was using Gradle's ProjectBuilder, which appends tools.jar to
the system class loader. Other tests do not do that, and they
invoke javac APIs directly.

In some executions, this causes some javac classes to be loaded
from the system class loader (the one patched by Gradle), while
some of them will be loaded by UrlClassLoader which points to tools.jar
in java.home. Having javac classes from different class loaders causes
java.lang.IllegalAccessError as package private access across class loaders
is not allowed. https://bugs.openjdk.java.net/browse/JDK-8068152 has more
information on this issue.

This change fixes the issue by fully removing usage of ProjectBuilder.

Test: ClasspathAnalyzerTest
This commit is contained in:
Ivan Gavrilovic
2021-10-29 17:02:43 +01:00
committed by Yahor Berdnikau
parent 4d208b529d
commit 0ee4e386be
2 changed files with 7 additions and 25 deletions
@@ -54,7 +54,7 @@ abstract class StructureTransformLegacyAction : TransformAction<TransformParamet
}
}
private fun transform(input: File, outputs: TransformOutputs) {
internal fun transform(input: File, outputs: TransformOutputs) {
val data = if (input.isDirectory) {
visitDirectory(input)
} else {
@@ -6,10 +6,6 @@
package org.jetbrains.kotlin.gradle.internal.kapt.incremental
import org.gradle.api.artifacts.transform.TransformOutputs
import org.gradle.api.artifacts.transform.TransformParameters
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.provider.Provider
import org.gradle.testfixtures.ProjectBuilder
import org.jetbrains.org.objectweb.asm.ClassWriter
import org.jetbrains.org.objectweb.asm.Opcodes
import org.junit.Assert.*
@@ -39,7 +35,7 @@ class ClasspathAnalyzerTest {
}
}
val outputs = TransformOutputsMock(tmp.newFolder())
StructureTransformTestAction(classesDir, tmp.newFolder("project")).transform(outputs)
transform(classesDir, outputs)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.createdOutputs.single())
assertEquals(setOf("test/A", "test/B"), data.classAbiHash.keys)
@@ -75,7 +71,7 @@ class ClasspathAnalyzerTest {
}
}
val outputs = TransformOutputsMock(tmp.newFolder())
StructureTransformTestAction(inputJar, tmp.newFolder("project")).transform(outputs)
transform(inputJar, outputs)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.createdOutputs.single())
assertEquals(setOf("test/A", "test/B"), data.classAbiHash.keys)
@@ -101,7 +97,7 @@ class ClasspathAnalyzerTest {
}
}
val outputsA = TransformOutputsMock(tmp.newFolder())
StructureTransformTestAction(jarA, tmp.newFolder("projectA")).transform(outputsA)
transform(jarA, outputsA)
val jarB = tmp.newFile("inputB.jar").also { jar ->
ZipOutputStream(jar.outputStream()).use {
@@ -115,17 +111,15 @@ class ClasspathAnalyzerTest {
}
}
val outputsB = TransformOutputsMock(tmp.newFolder())
StructureTransformTestAction(jarB, tmp.newFolder("projectB")).transform(outputsB)
transform(jarB, outputsB)
assertArrayEquals(outputsA.createdOutputs.single().readBytes(), outputsB.createdOutputs.single().readBytes())
}
@Test
fun emptyInput() {
val transformAction = StructureTransformTestAction(tmp.newFolder("input"), tmp.newFolder("project"))
val outputs = TransformOutputsMock(tmp.newFolder())
transformAction.transform(outputs)
transform(tmp.newFolder("input"), outputs)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.createdOutputs.single())
assertTrue(data.classAbiHash.isEmpty())
@@ -149,10 +143,8 @@ class ClasspathAnalyzerTest {
it.closeEntry()
}
}
val transformAction = StructureTransformTestAction(inputJar, tmp.newFolder("project"))
val outputs = TransformOutputsMock(tmp.newFolder())
transformAction.transform(outputs)
transform(inputJar, outputs)
val data = ClasspathEntryData.ClasspathEntrySerializer.loadFrom(outputs.createdOutputs.single())
assertEquals(setOf("test/A", "test/B", "test/C"), data.classAbiHash.keys)
@@ -166,16 +158,6 @@ class ClasspathAnalyzerTest {
}
}
class StructureTransformTestAction(val input: File, val projectDir: File) : StructureTransformAction() {
private val project = ProjectBuilder.builder().withProjectDir(projectDir).build()
override val inputArtifact: Provider<FileSystemLocation> = project.provider { project.objects.fileProperty().fileValue(input).get() }
override fun getParameters(): TransformParameters.None {
error("Should not be called")
}
}
class TransformOutputsMock(val outputDir: File) : TransformOutputs {
val createdOutputs = mutableListOf<File>()