Skip to content

Commit 6f77457

Browse files
committed
Tests for KMP + Android support
1 parent beb9b35 commit 6f77457

File tree

111 files changed

+2325
-248
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

111 files changed

+2325
-248
lines changed

gradle-plugin/src/test/kotlin/kotlinx/rpc/GrpcKmpProjectTest.kt

Lines changed: 689 additions & 181 deletions
Large diffs are not rendered by default.

gradle-plugin/src/test/kotlin/kotlinx/rpc/base/BaseTest.kt

Lines changed: 37 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -35,27 +35,43 @@ class VersionsEnv(
3535
val (major, minor, patch) = kotlin.split(".").map { it.toInt() }
3636
KotlinVersion(major, minor, patch)
3737
}
38+
39+
val androidSemver = run {
40+
val (major, minor, patch) = android.split(".").map { it.toInt() }
41+
KotlinVersion(major, minor, patch)
42+
}
3843
}
3944

4045
internal object KtVersion {
4146
val v2_2_20 = KotlinVersion(2, 2, 20)
4247
val v2_0_0 = KotlinVersion(2, 0, 0)
4348
}
4449

50+
typealias VersionsPredicate = VersionsEnv.() -> Boolean
51+
52+
internal fun VersionsEnv.testTestsForAndroidKmpLibExist(): Boolean {
53+
return androidSemver.isAtLeast(8, 10, 0)
54+
}
55+
4556
private val GradleVersions = listOf(
4657
VersionsEnv("9.2.1", "2.2.21", "8.13.1"),
47-
VersionsEnv("8.14.1", "2.2.0", "8.6.1"),
58+
VersionsEnv("8.14.1", "2.2.0", "8.10.0"),
4859
VersionsEnv("8.8", "2.0.0", "8.4.0"),
4960
)
5061

51-
internal fun BaseTest.runWithAllGradleVersions(body: (VersionsEnv) -> Unit): Stream<DynamicTest> {
52-
return GradleVersions.stream().map {
53-
setupTest(it)
54-
55-
DynamicTest.dynamicTest("Gradle ${it.gradle}, Kotlin ${it.kotlin}") {
56-
body(it)
62+
internal fun BaseTest.runWithGradleVersions(
63+
predicate: VersionsPredicate = { true },
64+
body: (VersionsEnv) -> Unit,
65+
): Stream<DynamicTest> {
66+
return GradleVersions.stream()
67+
.filter { predicate(it) }
68+
.map { versions ->
69+
setupTest(versions)
70+
71+
DynamicTest.dynamicTest("Gradle ${versions.gradle}, KGP ${versions.kotlin}, AGP ${versions.android}") {
72+
body(versions)
73+
}
5774
}
58-
}
5975
}
6076

6177
@OptIn(ExperimentalPathApi::class)
@@ -65,6 +81,7 @@ abstract class BaseTest {
6581
private lateinit var testMethodName: String
6682
private lateinit var baseDir: Path
6783
private lateinit var projectDir: Path
84+
private lateinit var testKitDir: Path
6885

6986
@BeforeEach
7087
protected fun setup(testInfo: TestInfo) {
@@ -84,7 +101,10 @@ abstract class BaseTest {
84101
}
85102

86103
fun setupTest(versions: VersionsEnv) {
87-
val versioned = baseDir.resolve(versions.gradle.replace(".", "_"))
104+
val gradleDir = versions.gradle.replace(".", "_")
105+
testKitDir = TEST_KIT_PATH.resolve(gradleDir)
106+
107+
val versioned = baseDir.resolve(gradleDir)
88108

89109
projectDir = versioned.resolve(PROJECT_DIR)
90110
val buildCacheDir = versioned.resolve(BUILD_CACHE_DIR)
@@ -128,11 +148,13 @@ abstract class BaseTest {
128148
settingsFile.appendText("\ninclude(\":$project\")")
129149
}
130150

131-
println("""
151+
println(
152+
"""
132153
Setup project '$projectName'
133154
- in directory: ${projectDir.absolutePathString()}
134155
- from directory: ${testTemplateDirectory.absolutePathString()}
135-
""".trimIndent())
156+
""".trimIndent()
157+
)
136158
}
137159

138160
private fun runGradleInternal(
@@ -143,8 +165,9 @@ abstract class BaseTest {
143165
): BuildResult {
144166
val gradleRunner = GradleRunner.create()
145167
.withProjectDir(projectDir.absolute().toFile())
146-
.withTestKitDir(TEST_KIT_PATH.absolute().toFile())
168+
.withTestKitDir(testKitDir.absolute().toFile())
147169
.withGradleVersion(versions.gradle)
170+
.forwardOutput()
148171
.withArguments(
149172
listOfNotNull(
150173
task,
@@ -153,28 +176,14 @@ abstract class BaseTest {
153176
"-Dorg.gradle.kotlin.dsl.scriptCompilationAvoidance=false",
154177
*args,
155178
)
156-
).apply {
157-
if (forwardOutput) {
158-
forwardOutput()
159-
}
160-
}
179+
)
161180

162181
println("Running Gradle task '$task' with arguments: [${args.joinToString()}]")
163182
return gradleRunner.body()
164183
}
165184

166185
protected fun <T : TestEnv> runTest(testEnv: T, body: T.() -> Unit) {
167-
try {
168-
testEnv.body()
169-
} finally {
170-
val output = testEnv.latestBuild?.output
171-
if (output != null) {
172-
println("Latest gradle build output:")
173-
println(output)
174-
} else {
175-
println("No gradle build output available")
176-
}
177-
}
186+
testEnv.body()
178187
}
179188

180189
open inner class TestEnv(
@@ -221,9 +230,6 @@ abstract class BaseTest {
221230
}
222231

223232
companion object {
224-
private val forwardOutput = System.getProperty("gradle.test.forward.output")
225-
?.toBooleanStrictOrNull() ?: false
226-
227233
private val nameRegex = Regex("[ .,-]")
228234

229235
private val TEST_PROJECTS_PATH = Path.of("build", "gradle-test")

gradle-plugin/src/test/kotlin/kotlinx/rpc/base/GrpcBaseTest.kt

Lines changed: 65 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,10 @@ abstract class GrpcBaseTest : BaseTest() {
3333
runNonExistentTask(generateBufGenYaml(set))
3434
}
3535

36-
protected fun runGrpcTest(test: GrpcTestEnv.() -> Unit): Stream<DynamicTest> = runWithAllGradleVersions {
36+
protected fun runGrpcTest(
37+
versionsPredicate: VersionsPredicate = { true },
38+
test: GrpcTestEnv.() -> Unit,
39+
): Stream<DynamicTest> = runWithGradleVersions(versionsPredicate) {
3740
runTest(GrpcTestEnv(it), test)
3841
}
3942

@@ -148,7 +151,7 @@ abstract class GrpcBaseTest : BaseTest() {
148151
protoSources.walk().forEach {
149152
val pathString = it.relativeTo(protoSources).pathString
150153
if (it.isRegularFile() && it.extension == "proto" && pathString !in included) {
151-
fail("File '${it}' in '$protoSources' is not expected")
154+
fail("File '${it.relativeTo(protoSources)}' in '$protoSources' is not expected")
152155
}
153156
}
154157
}
@@ -376,13 +379,13 @@ abstract class GrpcBaseTest : BaseTest() {
376379
fun generateBufGenYaml(sourceSet: SSets) = "generateBufGenYaml${sourceSet.capital}"
377380

378381
val mainSourceSet: SSets = when (type) {
379-
Type.Kmp -> SSetsKmp.commonMain
382+
Type.Kmp -> SSetsKmp.Default.commonMain
380383
Type.Jvm -> SSetsJvm.main
381384
Type.Android -> SSetsAndroid.Default.main
382385
}
383386

384387
val testSourceSet: SSets = when (type) {
385-
Type.Kmp -> SSetsKmp.commonTest
388+
Type.Kmp -> SSetsKmp.Default.commonTest
386389
Type.Jvm -> SSetsJvm.test
387390
Type.Android -> SSetsAndroid.Default.test
388391
}
@@ -454,32 +457,74 @@ abstract class GrpcBaseTest : BaseTest() {
454457
}
455458
}
456459

457-
enum class SSetsKmp(override val minKotlin: KotlinVersion = KtVersion.v2_0_0) : SSets {
458-
commonMain, commonTest,
459-
jvmMain, jvmTest,
460-
androidMain, androidTest,
461-
webMain(KtVersion.v2_2_20), webTest(KtVersion.v2_2_20),
462-
jsMain, jsTest,
463-
nativeMain, nativeTest,
464-
appleMain, appleTest,
465-
macosMain, macosTest,
466-
macosArm64Main, macosArm64Test,
467-
;
460+
sealed interface SSetsKmp : SSets {
461+
enum class Default(override val minKotlin: KotlinVersion = KtVersion.v2_0_0) : SSetsKmp {
462+
commonMain, commonTest,
463+
jvmMain, jvmTest,
464+
webMain(KtVersion.v2_2_20), webTest(KtVersion.v2_2_20),
465+
jsMain, jsTest,
466+
nativeMain, nativeTest,
467+
appleMain, appleTest,
468+
macosMain, macosTest,
469+
macosArm64Main, macosArm64Test,
470+
;
468471

469-
override fun all(): List<SSets> {
470-
return entries
472+
override fun all(): List<SSets> {
473+
return entries
474+
}
475+
}
476+
477+
enum class AndroidKmpLib(override val minKotlin: KotlinVersion = KtVersion.v2_0_0) : SSetsKmp {
478+
commonMain, commonTest,
479+
jvmMain, jvmTest,
480+
androidMain, androidHostTest, androidDeviceTest,
481+
;
482+
483+
override fun all(): List<SSets> {
484+
return entries
485+
}
486+
}
487+
488+
enum class LegacyAndroid(override val minKotlin: KotlinVersion = KtVersion.v2_0_0) : SSetsKmp {
489+
commonMain, commonTest,
490+
jvmMain, jvmTest,
491+
492+
// kmp, non-executable
493+
androidMain,
494+
androidUnitTest, androidInstrumentedTest,
495+
496+
// kmp, executable
497+
androidDebug, androidRelease,
498+
androidUnitTestDebug, androidUnitTestRelease,
499+
androidInstrumentedTestDebug,
500+
501+
// legacy, non-executable
502+
main, test,
503+
testFixtures, testFixturesDebug, testFixturesRelease,
504+
androidTest,
505+
506+
debug, release,
507+
testDebug, testRelease,
508+
androidTestDebug,
509+
;
510+
511+
override fun all(): List<SSets> {
512+
return entries
513+
}
471514
}
472515
}
473516

474517
sealed interface SSetsAndroid : SSets {
475518
enum class Default(override val minKotlin: KotlinVersion = KtVersion.v2_0_0) : SSetsAndroid {
519+
// non-executable
476520
main, test,
477-
androidTest, testFixtures,
521+
testFixtures, testFixturesDebug, testFixturesRelease,
522+
androidTest,
478523

524+
// executable
479525
debug, release,
480-
androidTestDebug,
481-
testFixturesDebug, testFixturesRelease,
482526
testDebug, testRelease,
527+
androidTestDebug,
483528
;
484529

485530
override fun all(): List<SSets> {

gradle-plugin/src/test/resources/projects/GrpcAndroidProjectTest/buf_tasks_default/build.gradle.kts

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
* Copyright 2023-2025 JetBrains s.r.o and contributors. Use of this source code is governed by the Apache 2.0 license.
33
*/
44

5+
import kotlinx.rpc.buf.*
6+
import kotlinx.rpc.buf.tasks.*
7+
import kotlinx.rpc.protoc.*
58
import org.gradle.api.DefaultTask
69
import org.gradle.api.GradleException
710
import org.gradle.kotlin.dsl.version
8-
import kotlinx.rpc.buf.tasks.*
9-
import kotlinx.rpc.buf.*
10-
import kotlinx.rpc.protoc.*
1111
import javax.inject.Inject
1212

1313
plugins {
@@ -43,11 +43,18 @@ fun Iterable<DefaultTask>.toNames() = map { it.name }.toSet()
4343
fun assertTasks(
4444
tag: String,
4545
tasks: Iterable<DefaultTask>,
46-
vararg expected: String,
46+
vararg expected: String?,
4747
) {
4848
val names = tasks.toNames()
49-
if (expected.toSet() != names) {
50-
throw GradleException("[$tag] Expected: ${expected.toSet()}, actual: $names")
49+
val expectedSet = expected.filterNotNull().toSet()
50+
if (expectedSet != names) {
51+
throw GradleException(
52+
"""
53+
[$tag] Expected: ${expectedSet}, actual: $names
54+
Missing: ${expectedSet - names}
55+
Extra: ${names - expectedSet}
56+
""".trimIndent()
57+
)
5158
}
5259
}
5360

@@ -89,8 +96,32 @@ tasks.register("test_tasks") {
8996
)
9097

9198
assertTasks("nonTestTasks testTasks", genTasks.nonTestTasks().testTasks())
92-
assertTasks("matchingSourceSet main", genTasks.matchingSourceSet("main"))
93-
assertTasks("matchingSourceSet test", genTasks.matchingSourceSet("test"))
99+
100+
assertTasks(
101+
"matchingSourceSet main", genTasks.matchingSourceSet("main"),
102+
"bufGenerateDebug",
103+
"bufGenerateRelease",
104+
)
105+
106+
assertTasks(
107+
"matchingSourceSet test", genTasks.matchingSourceSet("test"),
108+
"bufGenerateTestDebug",
109+
"bufGenerateTestRelease",
110+
)
111+
112+
assertTasks(
113+
"matchingSourceSet androidTest", genTasks.matchingSourceSet("androidTest"),
114+
"bufGenerateAndroidTestDebug",
115+
)
116+
117+
assertTasks(
118+
"gen all android", genTasks.androidTasks(),
119+
"bufGenerateAndroidTestDebug",
120+
"bufGenerateTestDebug",
121+
"bufGenerateTestRelease",
122+
"bufGenerateDebug",
123+
"bufGenerateRelease",
124+
)
94125

95126
assertTasks(
96127
"matchingSourceSet debug",

0 commit comments

Comments
 (0)