KotlinToolingMetadata: Handle incompatible schemaVersions during json parsing
This commit is contained in:
committed by
TeamCityServer
parent
0406659ac8
commit
37aedba7ef
+7
-1
@@ -118,8 +118,14 @@ fun KotlinToolingMetadata.Companion.parseJsonOrThrow(value: String): KotlinTooli
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun JsonObject.toKotlinToolingMetadataOrThrow(): KotlinToolingMetadata {
|
private fun JsonObject.toKotlinToolingMetadataOrThrow(): KotlinToolingMetadata {
|
||||||
|
val schemaVersion = SchemaVersion.parseStringOrThrow(getOrThrow("schemaVersion").asString)
|
||||||
|
if (!SchemaVersion.current.isCompatible(schemaVersion)) {
|
||||||
|
throw IllegalArgumentException(
|
||||||
|
"Incompatible schemaVersion='$schemaVersion' found. Current schemaVersion='${SchemaVersion.current}'"
|
||||||
|
)
|
||||||
|
}
|
||||||
return KotlinToolingMetadata(
|
return KotlinToolingMetadata(
|
||||||
schemaVersion = getOrThrow("schemaVersion").asString,
|
schemaVersion = schemaVersion.toString(),
|
||||||
buildSystem = getOrThrow("buildSystem").asString,
|
buildSystem = getOrThrow("buildSystem").asString,
|
||||||
buildSystemVersion = getOrThrow("buildSystemVersion").asString,
|
buildSystemVersion = getOrThrow("buildSystemVersion").asString,
|
||||||
buildPlugin = getOrThrow("buildPlugin").asString,
|
buildPlugin = getOrThrow("buildPlugin").asString,
|
||||||
|
|||||||
+45
@@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.tooling
|
||||||
|
|
||||||
|
internal data class SchemaVersion(val major: Int, val minor: Int, val patch: Int) : Comparable<SchemaVersion> {
|
||||||
|
override fun compareTo(other: SchemaVersion): Int {
|
||||||
|
(this.major - other.major).takeIf { it != 0 }?.let { return it }
|
||||||
|
(this.minor - other.minor).takeIf { it != 0 }?.let { return it }
|
||||||
|
return this.patch - other.patch
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "$major.$minor.$patch"
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
val current by lazy { SchemaVersion.parseStringOrThrow(KotlinToolingMetadata.currentSchemaVersion) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun SchemaVersion.Companion.parseStringOrThrow(schemaVersion: String): SchemaVersion {
|
||||||
|
fun throwIllegalSchemaVersion(): Nothing = throw IllegalArgumentException(
|
||||||
|
"Illegal schemaVersion $schemaVersion. Expected {major}.{minor}.{patch}"
|
||||||
|
)
|
||||||
|
|
||||||
|
val parts = schemaVersion.split(".")
|
||||||
|
if (parts.size != 3) throwIllegalSchemaVersion()
|
||||||
|
|
||||||
|
return SchemaVersion(
|
||||||
|
major = parts[0].toIntOrNull() ?: throwIllegalSchemaVersion(),
|
||||||
|
minor = parts[1].toIntOrNull() ?: throwIllegalSchemaVersion(),
|
||||||
|
patch = parts[2].toIntOrNull() ?: throwIllegalSchemaVersion()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun SchemaVersion.isCompatible(to: SchemaVersion): Boolean {
|
||||||
|
if (this.major != to.major) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return (this.minor >= to.minor)
|
||||||
|
}
|
||||||
+27
-2
@@ -24,10 +24,11 @@ class DeserializationFailureTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `sample2 missing build pluginVersion`() {
|
fun `sample2 missing buildPluginVersion`() {
|
||||||
@Language("JSON") val json =
|
@Language("JSON") val json =
|
||||||
"""
|
"""
|
||||||
{
|
{
|
||||||
|
"schemaVersion": ${SchemaVersion.current},
|
||||||
"buildSystem": "Gradle",
|
"buildSystem": "Gradle",
|
||||||
"buildSystemVersion": "6.7",
|
"buildSystemVersion": "6.7",
|
||||||
"buildPlugin": "org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper",
|
"buildPlugin": "org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper",
|
||||||
@@ -45,6 +46,30 @@ class DeserializationFailureTest {
|
|||||||
"Expected parsing failure, because of missing pluginVersion. Actual: $result"
|
"Expected parsing failure, because of missing pluginVersion. Actual: $result"
|
||||||
)
|
)
|
||||||
|
|
||||||
assertFailsWith<IllegalArgumentException> { KotlinToolingMetadata.parseJsonOrThrow(json) }
|
val exception = assertFailsWith<IllegalArgumentException> { KotlinToolingMetadata.parseJsonOrThrow(json) }
|
||||||
|
assertTrue(
|
||||||
|
"buildPluginVersion" in exception.message.orEmpty(),
|
||||||
|
"Expected 'buildPluginVersion' mentioned in error message\n${exception.message}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `sample3 incompatible schemaVersion`() {
|
||||||
|
val majorUpgradeVersion = SchemaVersion.current.copy(major = SchemaVersion.current.major + 1)
|
||||||
|
val metadataString = KotlinToolingMetadata(
|
||||||
|
schemaVersion = majorUpgradeVersion.toString(),
|
||||||
|
buildSystem = "",
|
||||||
|
buildSystemVersion = "",
|
||||||
|
buildPlugin = "",
|
||||||
|
buildPluginVersion = "",
|
||||||
|
projectSettings = KotlinToolingMetadata.ProjectSettings(false, false),
|
||||||
|
projectTargets = emptyList()
|
||||||
|
).toJsonString()
|
||||||
|
|
||||||
|
val exception = assertFailsWith<IllegalArgumentException> { KotlinToolingMetadata.parseJsonOrThrow(metadataString) }
|
||||||
|
assertTrue(
|
||||||
|
majorUpgradeVersion.toString() in exception.message.orEmpty(),
|
||||||
|
"Expected bad schemaVersion mentioned in error message\n${exception.message}"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.tooling
|
||||||
|
|
||||||
|
import kotlin.test.*
|
||||||
|
|
||||||
|
class SchemaVersionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `compare same version`() {
|
||||||
|
assertTrue(SchemaVersion(1, 0, 0) <= SchemaVersion(1, 0, 0), "Expected 1.0.0 <= 1.0.0")
|
||||||
|
assertTrue(SchemaVersion(1, 0, 0) >= SchemaVersion(1, 0, 0), "Expected 1.0.0 >= 1.0.0")
|
||||||
|
assertFalse(SchemaVersion(1, 0, 0) > SchemaVersion(1, 0, 0), "*NOT* Expected 1.0.0 > 1.0.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `compare higher version`() {
|
||||||
|
assertTrue(SchemaVersion(2, 2, 2) > SchemaVersion(2, 2, 1))
|
||||||
|
assertTrue(SchemaVersion(2, 2, 2) > SchemaVersion(2, 1, 2))
|
||||||
|
assertTrue(SchemaVersion(2, 2, 2) > SchemaVersion(1, 3, 3))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `compare lower version`() {
|
||||||
|
assertTrue(SchemaVersion(2, 2, 2) < SchemaVersion(2, 2, 3))
|
||||||
|
assertTrue(SchemaVersion(2, 2, 2) < SchemaVersion(2, 3, 1))
|
||||||
|
assertTrue(SchemaVersion(2, 2, 2) < SchemaVersion(3, 1, 1))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun parseSchemaVersion() {
|
||||||
|
assertEquals(
|
||||||
|
SchemaVersion(2, 15, 100), SchemaVersion.parseStringOrThrow("2.15.100")
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
SchemaVersion(0, 0, 0), SchemaVersion.parseStringOrThrow("0.0.0")
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
SchemaVersion(1, 0, 0), SchemaVersion.parseStringOrThrow("1.0.0")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `parseSchemaVersion failure`() {
|
||||||
|
assertFailsWith<IllegalArgumentException> { SchemaVersion.parseStringOrThrow("1.0") }
|
||||||
|
assertFailsWith<IllegalArgumentException> { SchemaVersion.parseStringOrThrow("1.0.0.0") }
|
||||||
|
assertFailsWith<IllegalArgumentException> { SchemaVersion.parseStringOrThrow("a.b.c") }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toString and parse`() {
|
||||||
|
assertEquals(
|
||||||
|
SchemaVersion(1, 0, 0), SchemaVersion.parseStringOrThrow(SchemaVersion(1, 0, 0).toString())
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
SchemaVersion(28, 100, 900), SchemaVersion.parseStringOrThrow(SchemaVersion(28, 100, 900).toString())
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun isCompatible() {
|
||||||
|
assertTrue(SchemaVersion(1, 1, 0).isCompatible(SchemaVersion(1, 0, 0)))
|
||||||
|
assertTrue(SchemaVersion(1, 0, 0).isCompatible(SchemaVersion(1, 0, 0)))
|
||||||
|
assertFalse(SchemaVersion(1, 0, 0).isCompatible(SchemaVersion(1, 1, 0)))
|
||||||
|
assertFalse(SchemaVersion(1, 0, 0).isCompatible(SchemaVersion(2, 0, 0)))
|
||||||
|
assertFalse(SchemaVersion(2, 0, 0).isCompatible(SchemaVersion(1, 0, 0)))
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user