aboutsummaryrefslogtreecommitdiff
path: root/integration-testing
diff options
context:
space:
mode:
authorColin Cross <ccross@android.com>2023-08-04 01:34:39 +0000
committerColin Cross <ccross@android.com>2023-08-04 19:01:49 +0000
commit901b58e236e3382985d30ac03b9912fd6fee4927 (patch)
treef0b6d402c7830108016238a214ef5a036e77acd8 /integration-testing
parent8fa7fa92f3dce21ab73b36b67c3c96c6314d84de (diff)
downloadkotlinx.coroutines-901b58e236e3382985d30ac03b9912fd6fee4927.tar.gz
Reland^3: kotlinx.coroutines to 1.7.2
This reverts commit 8fa7fa92f3dce21ab73b36b67c3c96c6314d84de. Bug: 290933559 Test: atest SystemUITests Change-Id: Iee27834b03229a0e10f408c34ba0a1e7d31f6c03
Diffstat (limited to 'integration-testing')
-rw-r--r--integration-testing/README.md12
-rw-r--r--integration-testing/build.gradle64
-rw-r--r--integration-testing/gradle.properties6
-rw-r--r--integration-testing/settings.gradle9
-rw-r--r--integration-testing/smokeTest/build.gradle9
-rw-r--r--integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt21
-rw-r--r--integration-testing/src/jvmCoreTest/kotlin/Jdk8InCoreIntegration.kt21
-rw-r--r--integration-testing/src/jvmCoreTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt (renamed from integration-testing/src/withGuavaTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt)15
-rw-r--r--integration-testing/src/mavenTest/kotlin/MavenPublicationAtomicfuValidator.kt41
-rw-r--r--integration-testing/src/mavenTest/kotlin/MavenPublicationMetaInfValidator.kt70
-rw-r--r--integration-testing/src/mavenTest/kotlin/MavenPublicationVersionValidator.kt1
11 files changed, 230 insertions, 39 deletions
diff --git a/integration-testing/README.md b/integration-testing/README.md
index 0ede9b25..0218b23c 100644
--- a/integration-testing/README.md
+++ b/integration-testing/README.md
@@ -3,11 +3,13 @@
This is a supplementary project that provides integration tests.
The tests are the following:
-* `MavenPublicationValidator` depends on the published artifacts and tests artifacts binary content and absence of atomicfu in the classpath.
-* `CoreAgentTest` checks that `kotlinx-coroutines-core` can be run as a Java agent.
-* `DebugAgentTest` checks that the coroutine debugger can be run as a Java agent.
-* `smokeTest` builds the test project that depends on coroutines.
+* `mavenTest` depends on the published artifacts and tests artifacts binary content for absence of atomicfu in the classpath.
+* `jvmCoreTest` miscellaneous tests that check the behaviour of `kotlinx-coroutines-core` dependency in a smoke manner.
+* `coreAgentTest` checks that `kotlinx-coroutines-core` can be run as a Java agent.
+* `debugAgentTest` checks that the coroutine debugger can be run as a Java agent.
+* `debugDynamicAgentTest` checks that `kotlinx-coroutines-debug` agent can self-attach dynamically to JVM as a standalone dependency.
+* `smokeTest` builds the multiplatform test project that depends on coroutines.
The `integration-testing` project is expected to be in a subdirectory of the main `kotlinx.coroutines` project.
-To run all the available tests: `cd integration-testing` + `./gradlew check`.
+To run all the available tests: `./gradlew publishToMavenLocal` + `cd integration-testing` + `./gradlew check`.
diff --git a/integration-testing/build.gradle b/integration-testing/build.gradle
index 985a40ed..26ee9d99 100644
--- a/integration-testing/build.gradle
+++ b/integration-testing/build.gradle
@@ -2,13 +2,54 @@
* Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
-import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
+
+buildscript {
+
+ /*
+ * These property group is used to build kotlinx.coroutines against Kotlin compiler snapshot.
+ * How does it work:
+ * When build_snapshot_train is set to true, kotlin_version property is overridden with kotlin_snapshot_version,
+ * atomicfu_version is overwritten by TeamCity environment (AFU is built with snapshot and published to mavenLocal
+ * as previous step or the snapshot build).
+ * Additionally, mavenLocal and Sonatype snapshots are added to repository list and stress tests are disabled.
+ * DO NOT change the name of these properties without adapting kotlinx.train build chain.
+ */
+ def prop = rootProject.properties['build_snapshot_train']
+ ext.build_snapshot_train = prop != null && prop != ""
+ if (build_snapshot_train) {
+ ext.kotlin_version = rootProject.properties['kotlin_snapshot_version']
+ if (kotlin_version == null) {
+ throw new IllegalArgumentException("'kotlin_snapshot_version' should be defined when building with snapshot compiler")
+ }
+ }
+ ext.native_targets_enabled = rootProject.properties['disable_native_targets'] == null
+
+ // Determine if any project dependency is using a snapshot version
+ ext.using_snapshot_version = build_snapshot_train
+ rootProject.properties.each { key, value ->
+ if (key.endsWith("_version") && value instanceof String && value.endsWith("-SNAPSHOT")) {
+ println("NOTE: USING SNAPSHOT VERSION: $key=$value")
+ ext.using_snapshot_version = true
+ }
+ }
+
+ if (using_snapshot_version) {
+ repositories {
+ mavenLocal()
+ maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
+ }
+ }
+
+}
plugins {
- id "org.jetbrains.kotlin.jvm"
+ id "org.jetbrains.kotlin.jvm" version "$kotlin_version"
}
repositories {
+ if (build_snapshot_train) {
+ maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
+ }
mavenLocal()
mavenCentral()
}
@@ -20,11 +61,13 @@ java {
dependencies {
testImplementation "org.jetbrains.kotlin:kotlin-test:$kotlin_version"
+ testImplementation "org.ow2.asm:asm:$asm_version"
+ implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
}
sourceSets {
- // Test that relies on Guava to reflectively check all Throwable subclasses in coroutines
- withGuavaTest {
+ // An assortment of tests for behavior of the core coroutines module on JVM
+ jvmCoreTest {
kotlin
compileClasspath += sourceSets.test.runtimeClasspath
runtimeClasspath += sourceSets.test.runtimeClasspath
@@ -57,7 +100,7 @@ sourceSets {
}
}
- // Checks that kotlinx-coroutines-debug agent can self-attach dynamically to JVM as standalone dependency
+ // Checks that kotlinx-coroutines-debug agent can self-attach dynamically to JVM as a standalone dependency
debugDynamicAgentTest {
kotlin
compileClasspath += sourceSets.test.runtimeClasspath
@@ -87,9 +130,9 @@ compileDebugAgentTestKotlin {
}
}
-task withGuavaTest(type: Test) {
+task jvmCoreTest(type: Test) {
environment "version", coroutines_version
- def sourceSet = sourceSets.withGuavaTest
+ def sourceSet = sourceSets.jvmCoreTest
testClassesDirs = sourceSet.output.classesDirs
classpath = sourceSet.runtimeClasspath
}
@@ -129,5 +172,10 @@ compileTestKotlin {
}
check {
- dependsOn([withGuavaTest, debugDynamicAgentTest, mavenTest, debugAgentTest, coreAgentTest, 'smokeTest:build'])
+ dependsOn([jvmCoreTest, debugDynamicAgentTest, mavenTest, debugAgentTest, coreAgentTest, 'smokeTest:build'])
+}
+compileKotlin {
+ kotlinOptions {
+ jvmTarget = "1.8"
+ }
}
diff --git a/integration-testing/gradle.properties b/integration-testing/gradle.properties
index 1038d817..30b2b5ed 100644
--- a/integration-testing/gradle.properties
+++ b/integration-testing/gradle.properties
@@ -1,4 +1,6 @@
-kotlin_version=1.6.21
-coroutines_version=1.6.4-SNAPSHOT
+kotlin_version=1.8.20
+coroutines_version=1.7.2-SNAPSHOT
+asm_version=9.3
kotlin.code.style=official
+kotlin.mpp.stability.nowarn=true
diff --git a/integration-testing/settings.gradle b/integration-testing/settings.gradle
index 67336c98..8584c05a 100644
--- a/integration-testing/settings.gradle
+++ b/integration-testing/settings.gradle
@@ -1,15 +1,8 @@
pluginManagement {
- resolutionStrategy {
- eachPlugin {
- if (requested.id.id == "org.jetbrains.kotlin.multiplatform" || requested.id.id == "org.jetbrains.kotlin.jvm") {
- useModule("org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version")
- }
- }
- }
-
repositories {
mavenCentral()
maven { url "https://plugins.gradle.org/m2/" }
+ maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
mavenLocal()
}
}
diff --git a/integration-testing/smokeTest/build.gradle b/integration-testing/smokeTest/build.gradle
index b200bb2f..26cd02b6 100644
--- a/integration-testing/smokeTest/build.gradle
+++ b/integration-testing/smokeTest/build.gradle
@@ -6,6 +6,7 @@ repositories {
// Coroutines from the outer project are published by previous CI buils step
mavenLocal()
mavenCentral()
+ maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
}
kotlin {
@@ -40,4 +41,12 @@ kotlin {
}
}
}
+ targets {
+ configure([]) {
+ tasks.getByName(compilations.main.compileKotlinTaskName).kotlinOptions {
+ jvmTarget = "1.8"
+ }
+ }
+ }
}
+
diff --git a/integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt b/integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt
index 84886a18..ab207e09 100644
--- a/integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt
+++ b/integration-testing/src/debugAgentTest/kotlin/PrecompiledDebugProbesTest.kt
@@ -16,10 +16,9 @@ class PrecompiledDebugProbesTest {
@Test
fun testClassFileContent() {
val clz = Class.forName("kotlin.coroutines.jvm.internal.DebugProbesKt")
- val className: String = clz.getName()
- val classFileResourcePath = className.replace(".", "/") + ".class"
- val stream = clz.classLoader.getResourceAsStream(classFileResourcePath)!!
- val array = stream.readBytes()
+ val classFileResourcePath = clz.name.replace(".", "/") + ".class"
+ val array = clz.classLoader.getResourceAsStream(classFileResourcePath).use { it.readBytes() }
+ assertJava8Compliance(array)
// we expect the integration testing project to be in a subdirectory of the main kotlinx.coroutines project
val base = File("").absoluteFile.parentFile
val probes = File(base, "kotlinx-coroutines-core/jvm/resources/DebugProbesKt.bin")
@@ -31,8 +30,20 @@ class PrecompiledDebugProbesTest {
assertTrue(
array.contentEquals(binContent),
"Compiled DebugProbesKt.class does not match the file shipped as a resource in kotlinx-coroutines-core. " +
- "Typically it happens because of the Kotlin version update (-> binary metadata). In that case, run the same test with -Poverwrite.probes=true."
+ "Typically it happens because of the Kotlin version update (-> binary metadata). " +
+ "In that case, run the same test with -Poverwrite.probes=true."
)
}
}
+
+ private fun assertJava8Compliance(classBytes: ByteArray) {
+ DataInputStream(classBytes.inputStream()).use {
+ val magic: Int = it.readInt()
+ if (magic != -0x35014542) throw IllegalArgumentException("Not a valid class!")
+ val minor: Int = it.readUnsignedShort()
+ val major: Int = it.readUnsignedShort()
+ assertEquals(52, major)
+ assertEquals(0, minor)
+ }
+ }
}
diff --git a/integration-testing/src/jvmCoreTest/kotlin/Jdk8InCoreIntegration.kt b/integration-testing/src/jvmCoreTest/kotlin/Jdk8InCoreIntegration.kt
new file mode 100644
index 00000000..91eef7e2
--- /dev/null
+++ b/integration-testing/src/jvmCoreTest/kotlin/Jdk8InCoreIntegration.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2016-2022 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+package kotlinx.coroutines
+
+import kotlinx.coroutines.future.*
+import org.junit.Test
+import kotlin.test.*
+
+/*
+ * Integration test that ensures signatures from both the jdk8 and the core source sets of the kotlinx-coroutines-core subproject are used.
+ */
+class Jdk8InCoreIntegration {
+
+ @Test
+ fun testFuture() = runBlocking<Unit> {
+ val future = future { yield(); 42 }
+ future.whenComplete { r, _ -> assertEquals(42, r) }
+ assertEquals(42, future.await())
+ }
+}
diff --git a/integration-testing/src/withGuavaTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt b/integration-testing/src/jvmCoreTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt
index fefcc005..7253658e 100644
--- a/integration-testing/src/withGuavaTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt
+++ b/integration-testing/src/jvmCoreTest/kotlin/ListAllCoroutineThrowableSubclassesTest.kt
@@ -7,6 +7,8 @@ package kotlinx.coroutines
import com.google.common.reflect.*
import kotlinx.coroutines.*
import org.junit.Test
+import java.io.Serializable
+import java.lang.reflect.Modifier
import kotlin.test.*
class ListAllCoroutineThrowableSubclassesTest {
@@ -25,19 +27,28 @@ class ListAllCoroutineThrowableSubclassesTest {
"kotlinx.coroutines.JobCancellationException",
"kotlinx.coroutines.internal.UndeliveredElementException",
"kotlinx.coroutines.CompletionHandlerException",
- "kotlinx.coroutines.DiagnosticCoroutineContextException",
+ "kotlinx.coroutines.internal.DiagnosticCoroutineContextException",
+ "kotlinx.coroutines.internal.ExceptionSuccessfullyProcessed",
"kotlinx.coroutines.CoroutinesInternalError",
"kotlinx.coroutines.channels.ClosedSendChannelException",
"kotlinx.coroutines.channels.ClosedReceiveChannelException",
"kotlinx.coroutines.flow.internal.ChildCancelledException",
"kotlinx.coroutines.flow.internal.AbortFlowException",
- )
+ )
@Test
fun testThrowableSubclassesAreSerializable() {
val classes = ClassPath.from(this.javaClass.classLoader)
.getTopLevelClassesRecursive("kotlinx.coroutines");
val throwables = classes.filter { Throwable::class.java.isAssignableFrom(it.load()) }.map { it.toString() }
+ for (throwable in throwables) {
+ for (field in throwable.javaClass.declaredFields) {
+ if (Modifier.isStatic(field.modifiers)) continue
+ val type = field.type
+ assertTrue(type.isPrimitive || Serializable::class.java.isAssignableFrom(type),
+ "Throwable $throwable has non-serializable field $field")
+ }
+ }
assertEquals(knownThrowables.sorted(), throwables.sorted())
}
}
diff --git a/integration-testing/src/mavenTest/kotlin/MavenPublicationAtomicfuValidator.kt b/integration-testing/src/mavenTest/kotlin/MavenPublicationAtomicfuValidator.kt
index dbb1921d..13bac015 100644
--- a/integration-testing/src/mavenTest/kotlin/MavenPublicationAtomicfuValidator.kt
+++ b/integration-testing/src/mavenTest/kotlin/MavenPublicationAtomicfuValidator.kt
@@ -4,12 +4,17 @@
package kotlinx.coroutines.validator
-import org.junit.*
-import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.objectweb.asm.*
+import org.objectweb.asm.ClassReader.*
+import org.objectweb.asm.ClassWriter.*
+import org.objectweb.asm.Opcodes.*
import java.util.jar.*
+import kotlin.test.*
class MavenPublicationAtomicfuValidator {
private val ATOMIC_FU_REF = "Lkotlinx/atomicfu/".toByteArray()
+ private val KOTLIN_METADATA_DESC = "Lkotlin/Metadata;"
@Test
fun testNoAtomicfuInClasspath() {
@@ -34,19 +39,39 @@ class MavenPublicationAtomicfuValidator {
for (e in entries()) {
if (!e.name.endsWith(".class")) continue
val bytes = getInputStream(e).use { it.readBytes() }
- loop@for (i in 0 until bytes.size - ATOMIC_FU_REF.size) {
- for (j in 0 until ATOMIC_FU_REF.size) {
- if (bytes[i + j] != ATOMIC_FU_REF[j]) continue@loop
- }
+ // The atomicfu compiler plugin does not remove atomic properties from metadata,
+ // so for now we check that there are no ATOMIC_FU_REF left in the class bytecode excluding metadata.
+ // This may be reverted after the fix in the compiler plugin transformer (for Kotlin 1.8.0).
+ val outBytes = bytes.eraseMetadata()
+ if (outBytes.checkBytes()) {
foundClasses += e.name // report error at the end with all class names
- break@loop
}
}
if (foundClasses.isNotEmpty()) {
error("Found references to atomicfu in jar file $name in the following class files: ${
- foundClasses.joinToString("") { "\n\t\t" + it }
+ foundClasses.joinToString("") { "\n\t\t" + it }
}")
}
close()
}
+
+ private fun ByteArray.checkBytes(): Boolean {
+ loop@for (i in 0 until this.size - ATOMIC_FU_REF.size) {
+ for (j in 0 until ATOMIC_FU_REF.size) {
+ if (this[i + j] != ATOMIC_FU_REF[j]) continue@loop
+ }
+ return true
+ }
+ return false
+ }
+
+ private fun ByteArray.eraseMetadata(): ByteArray {
+ val cw = ClassWriter(COMPUTE_MAXS or COMPUTE_FRAMES)
+ ClassReader(this).accept(object : ClassVisitor(ASM9, cw) {
+ override fun visitAnnotation(descriptor: String?, visible: Boolean): AnnotationVisitor? {
+ return if (descriptor == KOTLIN_METADATA_DESC) null else super.visitAnnotation(descriptor, visible)
+ }
+ }, SKIP_FRAMES)
+ return cw.toByteArray()
+ }
}
diff --git a/integration-testing/src/mavenTest/kotlin/MavenPublicationMetaInfValidator.kt b/integration-testing/src/mavenTest/kotlin/MavenPublicationMetaInfValidator.kt
new file mode 100644
index 00000000..8ed2b823
--- /dev/null
+++ b/integration-testing/src/mavenTest/kotlin/MavenPublicationMetaInfValidator.kt
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2016-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
+ */
+
+package kotlinx.coroutines.validator
+
+import org.junit.Test
+import org.objectweb.asm.*
+import org.objectweb.asm.ClassReader.*
+import org.objectweb.asm.ClassWriter.*
+import org.objectweb.asm.Opcodes.*
+import java.util.jar.*
+import kotlin.test.*
+
+class MavenPublicationMetaInfValidator {
+
+ @Test
+ fun testMetaInfCoreStructure() {
+ val clazz = Class.forName("kotlinx.coroutines.Job")
+ JarFile(clazz.protectionDomain.codeSource.location.file).checkMetaInfStructure(
+ setOf(
+ "MANIFEST.MF",
+ "kotlinx-coroutines-core.kotlin_module",
+ "com.android.tools/proguard/coroutines.pro",
+ "com.android.tools/r8/coroutines.pro",
+ "proguard/coroutines.pro",
+ "versions/9/module-info.class",
+ "kotlinx_coroutines_core.version"
+ )
+ )
+ }
+
+ @Test
+ fun testMetaInfAndroidStructure() {
+ val clazz = Class.forName("kotlinx.coroutines.android.HandlerDispatcher")
+ JarFile(clazz.protectionDomain.codeSource.location.file).checkMetaInfStructure(
+ setOf(
+ "MANIFEST.MF",
+ "kotlinx-coroutines-android.kotlin_module",
+ "services/kotlinx.coroutines.CoroutineExceptionHandler",
+ "services/kotlinx.coroutines.internal.MainDispatcherFactory",
+ "com.android.tools/r8-from-1.6.0/coroutines.pro",
+ "com.android.tools/r8-upto-3.0.0/coroutines.pro",
+ "com.android.tools/proguard/coroutines.pro",
+ "proguard/coroutines.pro",
+ "versions/9/module-info.class",
+ "kotlinx_coroutines_android.version"
+ )
+ )
+ }
+
+ private fun JarFile.checkMetaInfStructure(expected: Set<String>) {
+ val actual = HashSet<String>()
+ for (e in entries()) {
+ if (e.isDirectory() || !e.realName.contains("META-INF")) {
+ continue
+ }
+ val partialName = e.realName.substringAfter("META-INF/")
+ actual.add(partialName)
+ }
+
+ if (actual != expected) {
+ val intersection = actual.intersect(expected)
+ val mismatch = actual.subtract(intersection) + expected.subtract(intersection)
+ fail("Mismatched files: " + mismatch)
+ }
+
+ close()
+ }
+}
diff --git a/integration-testing/src/mavenTest/kotlin/MavenPublicationVersionValidator.kt b/integration-testing/src/mavenTest/kotlin/MavenPublicationVersionValidator.kt
index da87d4cc..11529d2d 100644
--- a/integration-testing/src/mavenTest/kotlin/MavenPublicationVersionValidator.kt
+++ b/integration-testing/src/mavenTest/kotlin/MavenPublicationVersionValidator.kt
@@ -4,7 +4,6 @@
package kotlinx.coroutines.validator
-import org.junit.*
import org.junit.Test
import java.util.jar.*
import kotlin.test.*