[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.configurationcache.extensions.serviceOf
|
||||||
import org.gradle.kotlin.dsl.create
|
import org.gradle.kotlin.dsl.create
|
||||||
import org.gradle.testfixtures.ProjectBuilder
|
import org.gradle.testfixtures.ProjectBuilder
|
||||||
|
import org.gradle.tooling.internal.adapter.ProtocolToModelAdapter
|
||||||
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
|
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.KotlinPm20PluginWrapper
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinIosX64Variant
|
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinIosX64Variant
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinLinuxX64Variant
|
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 org.junit.Test
|
||||||
import java.io.*
|
import java.io.*
|
||||||
import java.net.URLClassLoader
|
import java.net.URLClassLoader
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.*
|
||||||
import kotlin.test.assertNotEquals
|
|
||||||
import kotlin.test.assertSame
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This test is designed to test if serialized models can still be deserialized with a older (minimal supported)
|
* 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()
|
project.evaluate()
|
||||||
|
|
||||||
testDeserializeCompatibility(buildModel(project))
|
val model = buildModel(project)
|
||||||
}
|
val deserializedModel = deserializeModelWithBackwardsCompatibleClasses(model)
|
||||||
|
|
||||||
private fun buildModel(project: Project): IdeaKotlinProjectModel {
|
/* Use reflection magic (aka ProtocolToModelAdapter) to proxy the deserialized model */
|
||||||
return project.serviceOf<ToolingModelBuilderRegistry>().getBuilder(IdeaKotlinProjectModel::class.java.name)
|
run {
|
||||||
.buildAll(IdeaKotlinProjectModel::class.java.name, project) as IdeaKotlinProjectModel
|
val adaptedDeserializedModel = ProtocolToModelAdapter().adapt(IdeaKotlinProjectModel::class.java, deserializedModel)
|
||||||
}
|
|
||||||
|
|
||||||
private fun testDeserializeCompatibility(model: IdeaKotlinProjectModel) {
|
val mainModule = adaptedDeserializedModel.modules.firstOrNull { it.moduleIdentifier.moduleClassifier == null }
|
||||||
val serializedModel = ByteArrayOutputStream().run {
|
?: fail("Missing main module")
|
||||||
ObjectOutputStream(this).use { stream -> stream.writeObject(model) }
|
|
||||||
toByteArray()
|
|
||||||
}
|
|
||||||
|
|
||||||
val backwardsCompatibilityTestClassLoader = getClassLoaderForBackwardsCompatibilityTest()
|
val testModule = adaptedDeserializedModel.modules.firstOrNull { it.moduleIdentifier.moduleClassifier == "test" }
|
||||||
val backwardsCompatibilityObjectInputStream = object : ObjectInputStream(ByteArrayInputStream(serializedModel)) {
|
?: fail("Missing test module")
|
||||||
override fun resolveClass(desc: ObjectStreamClass): Class<*> {
|
|
||||||
return backwardsCompatibilityTestClassLoader.loadClass(desc.name)
|
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<*>>(
|
@OptIn(ExternalVariantApi::class)
|
||||||
model.javaClass, backwardsCompatibilityModel.javaClass,
|
@Test
|
||||||
"Expected deserialized model java class to be different from origin"
|
fun `test - attaching serializable models`() {
|
||||||
)
|
data class RetainedModel(val id: Int) : Serializable
|
||||||
|
data class UnretainedModel(val id: Int)
|
||||||
|
|
||||||
assertEquals(
|
val retainedModelKey = KotlinExternalModelKey<RetainedModel>(serializable())
|
||||||
model.javaClass.name, backwardsCompatibilityModel.javaClass.name,
|
val unretainedModelKey = KotlinExternalModelKey<UnretainedModel>()
|
||||||
"Expected deserialized model to be same java class as origin"
|
|
||||||
)
|
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") }
|
.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