[KPM] Implement test - attaching serializable models
KT-51262 KT-51220
This commit is contained in:
committed by
Space
parent
1787d18faa
commit
9e19e3efa7
+88
-32
@@ -12,7 +12,12 @@ import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.configurationcache.extensions.serviceOf
|
||||
import org.gradle.kotlin.dsl.create
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.gradle.tooling.internal.adapter.ProtocolToModelAdapter
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
|
||||
import org.jetbrains.kotlin.gradle.kpm.KotlinExternalModelKey
|
||||
import org.jetbrains.kotlin.gradle.kpm.KotlinExternalModelSerializer.Companion.serializable
|
||||
import org.jetbrains.kotlin.gradle.kpm.external.ExternalVariantApi
|
||||
import org.jetbrains.kotlin.gradle.kpm.external.external
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPm20PluginWrapper
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinIosX64Variant
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinLinuxX64Variant
|
||||
@@ -21,9 +26,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.jvm
|
||||
import org.junit.Test
|
||||
import java.io.*
|
||||
import java.net.URLClassLoader
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNotEquals
|
||||
import kotlin.test.assertSame
|
||||
import kotlin.test.*
|
||||
|
||||
/**
|
||||
* This test is designed to test if serialized models can still be deserialized with a older (minimal supported)
|
||||
@@ -55,42 +58,59 @@ class BackwardsCompatibilityDeserializationTest {
|
||||
}
|
||||
project.evaluate()
|
||||
|
||||
testDeserializeCompatibility(buildModel(project))
|
||||
}
|
||||
val model = buildModel(project)
|
||||
val deserializedModel = deserializeModelWithBackwardsCompatibleClasses(model)
|
||||
|
||||
private fun buildModel(project: Project): IdeaKotlinProjectModel {
|
||||
return project.serviceOf<ToolingModelBuilderRegistry>().getBuilder(IdeaKotlinProjectModel::class.java.name)
|
||||
.buildAll(IdeaKotlinProjectModel::class.java.name, project) as IdeaKotlinProjectModel
|
||||
}
|
||||
/* Use reflection magic (aka ProtocolToModelAdapter) to proxy the deserialized model */
|
||||
run {
|
||||
val adaptedDeserializedModel = ProtocolToModelAdapter().adapt(IdeaKotlinProjectModel::class.java, deserializedModel)
|
||||
|
||||
private fun testDeserializeCompatibility(model: IdeaKotlinProjectModel) {
|
||||
val serializedModel = ByteArrayOutputStream().run {
|
||||
ObjectOutputStream(this).use { stream -> stream.writeObject(model) }
|
||||
toByteArray()
|
||||
}
|
||||
val mainModule = adaptedDeserializedModel.modules.firstOrNull { it.moduleIdentifier.moduleClassifier == null }
|
||||
?: fail("Missing main module")
|
||||
|
||||
val backwardsCompatibilityTestClassLoader = getClassLoaderForBackwardsCompatibilityTest()
|
||||
val backwardsCompatibilityObjectInputStream = object : ObjectInputStream(ByteArrayInputStream(serializedModel)) {
|
||||
override fun resolveClass(desc: ObjectStreamClass): Class<*> {
|
||||
return backwardsCompatibilityTestClassLoader.loadClass(desc.name)
|
||||
val testModule = adaptedDeserializedModel.modules.firstOrNull { it.moduleIdentifier.moduleClassifier == "test" }
|
||||
?: fail("Missing test module")
|
||||
|
||||
listOf(mainModule, testModule).forEach { module ->
|
||||
assertEquals(
|
||||
model.modules.flatMap { it.fragments }.map { it.name }.toSet(),
|
||||
module.fragments.map { it.name }.toSet(),
|
||||
"Expected all fragment names to be present"
|
||||
)
|
||||
}
|
||||
}
|
||||
val backwardsCompatibilityModel = backwardsCompatibilityObjectInputStream.readObject()
|
||||
assertSame(
|
||||
backwardsCompatibilityModel.javaClass.classLoader,
|
||||
backwardsCompatibilityTestClassLoader,
|
||||
"Expected deserialized model being loaded by 'backwardsCompatibilityTestClassLoader'"
|
||||
)
|
||||
}
|
||||
|
||||
assertNotEquals<Class<*>>(
|
||||
model.javaClass, backwardsCompatibilityModel.javaClass,
|
||||
"Expected deserialized model java class to be different from origin"
|
||||
)
|
||||
@OptIn(ExternalVariantApi::class)
|
||||
@Test
|
||||
fun `test - attaching serializable models`() {
|
||||
data class RetainedModel(val id: Int) : Serializable
|
||||
data class UnretainedModel(val id: Int)
|
||||
|
||||
assertEquals(
|
||||
model.javaClass.name, backwardsCompatibilityModel.javaClass.name,
|
||||
"Expected deserialized model to be same java class as origin"
|
||||
)
|
||||
val retainedModelKey = KotlinExternalModelKey<RetainedModel>(serializable())
|
||||
val unretainedModelKey = KotlinExternalModelKey<UnretainedModel>()
|
||||
|
||||
val project = ProjectBuilder.builder().build() as ProjectInternal
|
||||
project.plugins.apply(KotlinPm20PluginWrapper::class.java)
|
||||
|
||||
/* Setup example project */
|
||||
val kotlinExtension = project.extensions.getByType(KotlinPm20ProjectExtension::class.java)
|
||||
kotlinExtension.main.common.external[retainedModelKey] = RetainedModel(2411)
|
||||
kotlinExtension.main.common.external[unretainedModelKey] = UnretainedModel(510)
|
||||
|
||||
val model = buildModel(project)
|
||||
val deserializedModel = deserializeModelWithBackwardsCompatibleClasses(model)
|
||||
val adaptedDeserializedModel = ProtocolToModelAdapter().adapt(IdeaKotlinProjectModel::class.java, deserializedModel)
|
||||
|
||||
val mainModule = adaptedDeserializedModel.modules.find { it.moduleIdentifier.moduleClassifier == null }
|
||||
?: fail("Missing main module")
|
||||
|
||||
val commonFragment = mainModule.fragments.find { it.name == "common" }
|
||||
?: fail("Missing common fragment")
|
||||
|
||||
assertEquals(1, commonFragment.external.ids.size)
|
||||
assertEquals(RetainedModel(2411), commonFragment.external[retainedModelKey])
|
||||
assertNull(commonFragment.external[unretainedModelKey])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,3 +127,39 @@ private fun getClasspathForBackwardsCompatibilityTest(): List<File> {
|
||||
.onEach { file -> if (!file.exists()) println("[WARNING] Missing $file") }
|
||||
}
|
||||
|
||||
private fun buildModel(project: Project): IdeaKotlinProjectModel {
|
||||
return project.serviceOf<ToolingModelBuilderRegistry>().getBuilder(IdeaKotlinProjectModel::class.java.name)
|
||||
.buildAll(IdeaKotlinProjectModel::class.java.name, project) as IdeaKotlinProjectModel
|
||||
}
|
||||
|
||||
private fun deserializeModelWithBackwardsCompatibleClasses(model: IdeaKotlinProjectModel): Any {
|
||||
val serializedModel = ByteArrayOutputStream().run {
|
||||
ObjectOutputStream(this).use { stream -> stream.writeObject(model) }
|
||||
toByteArray()
|
||||
}
|
||||
|
||||
val backwardsCompatibilityTestClassLoader = getClassLoaderForBackwardsCompatibilityTest()
|
||||
val backwardsCompatibilityObjectInputStream = object : ObjectInputStream(ByteArrayInputStream(serializedModel)) {
|
||||
override fun resolveClass(desc: ObjectStreamClass): Class<*> {
|
||||
return backwardsCompatibilityTestClassLoader.loadClass(desc.name)
|
||||
}
|
||||
}
|
||||
val backwardsCompatibilityModel = backwardsCompatibilityObjectInputStream.use { it.readObject() }
|
||||
assertSame(
|
||||
backwardsCompatibilityModel.javaClass.classLoader,
|
||||
backwardsCompatibilityTestClassLoader,
|
||||
"Expected deserialized model being loaded by 'backwardsCompatibilityTestClassLoader'"
|
||||
)
|
||||
|
||||
assertNotEquals<Class<*>>(
|
||||
model.javaClass, backwardsCompatibilityModel.javaClass,
|
||||
"Expected deserialized model java class to be different from origin"
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
model.javaClass.name, backwardsCompatibilityModel.javaClass.name,
|
||||
"Expected deserialized model to be same java class as origin"
|
||||
)
|
||||
|
||||
return backwardsCompatibilityModel
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user