Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Engine tests: use compilations to share logic between ktor/default engines #5216

Merged
merged 2 commits into from
Sep 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 19 additions & 8 deletions build-logic/src/main/kotlin/Mpp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,9 @@ fun Project.configureMpp(
}

/**
* Current Graph is something like so
* Current Graph is something like so:
*
* ```mermaid
* graph TB
* commonMain --> concurrentMain
* commonMain --> linuxMain
Expand All @@ -158,21 +159,19 @@ fun Project.configureMpp(
* appleMain --> tvosX64
* appleMain --> tvosSimulatorArm64
*
*
* commonTest --> kotlinCodegenTest
* commonTest --> jvmJavaCodeGen
* kotlinCodegenTest --> macOsArm64Test
* kotlinCodegenTest --> jvmTest
* kotlinCodegenTest --> jsTest
*
*
*
* classDef kotlinPurple fill:#A97BFF,stroke:#333,stroke-width:2px,color:#333
* classDef javaOrange fill:#b07289,stroke:#333,stroke-width:2px,color:#333
* classDef gray fill:#AAA,stroke:#333,stroke-width:2px,color:#333
* class kotlinCodegenTest gray
* class jvmJavaCodeGen,macOsArm64Test,jvmTest,jsTest kotlinPurple
* class commonTest javaOrange
* ```
*/
private fun KotlinMultiplatformExtension.configureSourceSetGraph() {
val hasAppleTarget = targets.any {
Expand Down Expand Up @@ -201,12 +200,12 @@ private fun KotlinMultiplatformExtension.configureSourceSetGraph() {
}
}

val kotlinCodegentTest = sourceSets.create("kotlinCodegenTest")
val kotlinCodegenTest = sourceSets.create("kotlinCodegenTest")

kotlinCodegentTest.dependsOn(sourceSets.getByName("commonTest"))
kotlinCodegenTest.dependsOn(sourceSets.getByName("commonTest"))

targets.forEach {
sourceSets.findByName("${it.name}Test")?.dependsOn(kotlinCodegentTest)
sourceSets.findByName("${it.name}Test")?.dependsOn(kotlinCodegenTest)
}
}

Expand All @@ -218,6 +217,18 @@ private fun KotlinMultiplatformExtension.addTestDependencies() {
}
}

/**
* Registers a new testRun that substitutes the Kotlin models by the Java models.
* Because they have the same JVM API, this is transparent to all tests that are in `kotlinCodegenTest` that work the same for Kotlin
* & Java models.
*
* - For Kotlin models, `kotlinCodegenTest` is directly in the sourceSet graph and generated models are wired to the source set
* - For Java models, `kotlinCodegenTest` is not in the sourceSet graph. The generated models are wired to the separate `javaCodegen`
* source set. Then the contents of `kotlinCodegenTest/kotlin` is sourced directly
*
* This breaks IDE support because now `kotlinCodegenTest/kotlin` is used from 2 different places so clicking a model there, it's impossible
* to tell which model it is. We could expect/actual all of the model APIs but that'd be a lot of very manual work
*/
fun Project.registerJavaCodegenTestTask() {
val kotlin = kotlinExtension
check(kotlin is KotlinMultiplatformExtension) {
Expand Down Expand Up @@ -250,5 +261,5 @@ fun Project.registerJavaCodegenTestTask() {
}
}

tasks.named("build").dependsOn(task)
tasks.named("allTests").dependsOn(task)
}
57 changes: 54 additions & 3 deletions tests/engine/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@

import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTargetWithHostTests
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget

plugins {
id("org.jetbrains.kotlin.multiplatform")
id("apollo.test")
Expand All @@ -9,19 +14,65 @@ apolloTest {

kotlin {
sourceSets {
findByName("commonMain")?.apply {
getByName("commonMain").apply {
dependencies {
implementation(libs.apollo.runtime)
implementation(libs.apollo.engine.ktor)
}
}

findByName("commonTest")?.apply {
val commonTest = getByName("commonTest").apply {
dependencies {
implementation(libs.apollo.mockserver)
implementation(libs.apollo.testingsupport)
implementation(libs.turbine)
}
}

val ktorTest = create("ktorTest") {
dependsOn(commonTest)
dependencies {
implementation(libs.apollo.engine.ktor)
}
}
val defaultTest = create("defaultTest") {
dependsOn(commonTest)
}

targets.all {
val defaultTestCompilation = compilations.findByName("test")
if (defaultTestCompilation != null) {
defaultTestCompilation.defaultSourceSet.dependsOn(defaultTest)

when (this ) {
is KotlinJvmTarget -> {
val ktorTestCompilation = compilations.create("ktorTest").apply {
defaultSourceSet.dependsOn(ktorTest)
}
testRuns.create("ktor") {
setExecutionSourceFrom(ktorTestCompilation)
}
}
is KotlinJsIrTarget -> {
val ktorTestCompilation = compilations.create("ktorTest").apply {
defaultSourceSet.dependsOn(ktorTest)
}
testRuns.create("ktor") {
setExecutionSourceFrom(ktorTestCompilation)
}
}
is KotlinNativeTargetWithHostTests -> {
val ktorTestCompilation = compilations.create("ktorTest").apply {
defaultSourceSet.dependsOn(ktorTest)
}
binaries.test("integration") {
compilation = ktorTestCompilation
}
testRuns.create("ktor") {
setExecutionSourceFrom(binaries.getTest("integration", DEBUG))
}
}
}
}
}
}
}
7 changes: 2 additions & 5 deletions tests/engine/src/commonTest/kotlin/GzipTest.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@

import com.apollographql.apollo3.mockserver.MockResponse
import com.apollographql.apollo3.mockserver.MockServer
import com.apollographql.apollo3.network.http.DefaultHttpEngine
import com.apollographql.apollo3.network.http.HttpEngine
import com.apollographql.apollo3.network.http.KtorHttpEngine
import com.apollographql.apollo3.network.http.get
import com.apollographql.apollo3.testing.internal.runTest
import okio.Buffer
Expand Down Expand Up @@ -51,8 +51,5 @@ class GzipTest {
}

@Test
fun gzipTestDefault() = gzipTest(DefaultHttpEngine())

@Test
fun gzipTestKtor() = gzipTest(KtorHttpEngine())
fun gzipTest() = gzipTest(DefaultHttpEngine())
}
30 changes: 6 additions & 24 deletions tests/engine/src/commonTest/kotlin/HttpEngineTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@ import com.apollographql.apollo3.exception.ApolloException
import com.apollographql.apollo3.mockserver.MockResponse
import com.apollographql.apollo3.mockserver.MockServer
import com.apollographql.apollo3.mockserver.enqueue
import com.apollographql.apollo3.network.http.DefaultHttpEngine
import com.apollographql.apollo3.network.http.HttpEngine
import com.apollographql.apollo3.network.http.KtorHttpEngine
import com.apollographql.apollo3.testing.internal.runTest
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down Expand Up @@ -37,10 +35,7 @@ class HttpEngineTest {
}

@Test
fun errorWithBodyDefault() = errorWithBody(DefaultHttpEngine())

@Test
fun errorWithBodyKtor() = errorWithBody(KtorHttpEngine())
fun errorWithBody() = errorWithBody(httpEngine())

private fun headers(httpEngine: HttpEngine) = runTest(before = { setUp() }, after = { tearDown() }) {
mockServer.enqueue(
Expand All @@ -65,10 +60,7 @@ class HttpEngineTest {
}

@Test
fun headersDefault() = headers(DefaultHttpEngine())

@Test
fun headersKtor() = headers(KtorHttpEngine())
fun headers() = headers(httpEngine())

private fun post(httpEngine: HttpEngine) = runTest(before = { setUp() }, after = { tearDown() }) {
mockServer.enqueue(
Expand All @@ -90,10 +82,7 @@ class HttpEngineTest {
}

@Test
fun postDefault() = post(DefaultHttpEngine())

@Test
fun postKtor() = post(KtorHttpEngine())
fun post() = post(httpEngine())

private fun connectTimeout(httpEngine: HttpEngine) = runTest(before = { setUp() }, after = { tearDown() }) {
assertFailsWith<ApolloException> {
Expand All @@ -103,11 +92,8 @@ class HttpEngineTest {
}

@Test
fun connectTimeoutDefault() = connectTimeout(DefaultHttpEngine(500))

@Test
fun connectTimeoutKtor() = connectTimeout(KtorHttpEngine(500))

fun connectTimeout() = connectTimeout(httpEngine(500))

private fun readTimeout(httpEngine: HttpEngine) = runTest(before = { setUp() }, after = { tearDown() }) {
mockServer.enqueue(
MockResponse.Builder()
Expand All @@ -122,9 +108,5 @@ class HttpEngineTest {
}

@Test
fun readTimeoutDefault() = readTimeout(DefaultHttpEngine(500))

@Test
fun readTimeoutKtor() = readTimeout(KtorHttpEngine(500))

fun readTimeout() = readTimeout(httpEngine(500))
}
34 changes: 9 additions & 25 deletions tests/engine/src/commonTest/kotlin/WebSocketEngineTest.kt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

import app.cash.turbine.test
import com.apollographql.apollo3.api.http.HttpHeader
import com.apollographql.apollo3.exception.ApolloException
Expand All @@ -7,11 +8,9 @@ import com.apollographql.apollo3.mockserver.WebSocketMockServer
import com.apollographql.apollo3.mockserver.WebSocketMockServer.WebSocketEvent
import com.apollographql.apollo3.mpp.Platform
import com.apollographql.apollo3.mpp.platform
import com.apollographql.apollo3.network.ws.DefaultWebSocketEngine
import com.apollographql.apollo3.network.ws.KtorWebSocketEngine
import com.apollographql.apollo3.network.ws.WebSocketEngine
import com.apollographql.apollo3.testing.internal.runTest
import io.ktor.utils.io.core.toByteArray
import okio.Buffer
import okio.ByteString.Companion.encodeUtf8
import kotlin.test.Test
import kotlin.test.assertEquals
Expand Down Expand Up @@ -49,10 +48,7 @@ class WebSocketEngineTest {
}

@Test
fun textFramesDefault() = textFrames(DefaultWebSocketEngine())

@Test
fun textFramesKtor() = textFrames(KtorWebSocketEngine())
fun textFrames() = textFrames(webSocketEngine())

private fun binaryFrames(webSocketEngine: WebSocketEngine) = runTest {
if (platform() == Platform.Js) return@runTest // JS doesn't have a WebSocketMockServer yet
Expand Down Expand Up @@ -82,11 +78,10 @@ class WebSocketEngineTest {
webSocketServer.close()
}

@Test
fun binaryFramesDefault() = binaryFrames(DefaultWebSocketEngine())
private fun String.toByteArray() = Buffer().writeUtf8(this).readByteArray()

@Test
fun binaryFramesKtor() = binaryFrames(KtorWebSocketEngine())
fun binaryFrames() = binaryFrames(webSocketEngine())

private fun serverCloseNicely(webSocketEngine: WebSocketEngine, checkCodeAndReason: Boolean = true) = runTest {
if (platform() == Platform.Js) return@runTest // JS doesn't have a WebSocketMockServer yet
Expand Down Expand Up @@ -115,14 +110,9 @@ class WebSocketEngineTest {
}

@Test
fun serverCloseNicelyDefault() = serverCloseNicely(DefaultWebSocketEngine())

@Test
fun serverCloseNicelyKtor() = serverCloseNicely(
webSocketEngine = KtorWebSocketEngine(),

fun serverCloseNicely() = serverCloseNicely(webSocketEngine(),
// On Apple, the close code and reason are not available - https://youtrack.jetbrains.com/issue/KTOR-6198
checkCodeAndReason = platform() != Platform.Native
checkCodeAndReason = !isKtor || platform() != Platform.Native
)

private fun serverCloseAbruptly(webSocketEngine: WebSocketEngine) = runTest {
Expand All @@ -143,10 +133,7 @@ class WebSocketEngineTest {
}

@Test
fun serverCloseAbruptlyDefault() = serverCloseAbruptly(DefaultWebSocketEngine())

@Test
fun serverCloseAbruptlyKtor() = serverCloseAbruptly(KtorWebSocketEngine())
fun serverCloseAbruptly() = serverCloseAbruptly(webSocketEngine())

private fun headers(webSocketEngine: WebSocketEngine) = runTest {
if (platform() == Platform.Js) return@runTest // JS doesn't have a WebSocketMockServer yet
Expand All @@ -170,8 +157,5 @@ class WebSocketEngineTest {
}

@Test
fun headersDefault() = headers(DefaultWebSocketEngine())

@Test
fun headersKtor() = headers(KtorWebSocketEngine())
fun headers() = headers(webSocketEngine())
}
6 changes: 6 additions & 0 deletions tests/engine/src/commonTest/kotlin/engines.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import com.apollographql.apollo3.network.http.HttpEngine
import com.apollographql.apollo3.network.ws.WebSocketEngine

expect fun httpEngine(timeoutMillis: Long = 60_000): HttpEngine
expect fun webSocketEngine(): WebSocketEngine
expect val isKtor: Boolean
15 changes: 15 additions & 0 deletions tests/engine/src/defaultTest/kotlin/engines.default.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@

import com.apollographql.apollo3.network.http.DefaultHttpEngine
import com.apollographql.apollo3.network.http.HttpEngine
import com.apollographql.apollo3.network.ws.DefaultWebSocketEngine
import com.apollographql.apollo3.network.ws.WebSocketEngine

actual fun httpEngine(timeoutMillis: Long): HttpEngine {
return DefaultHttpEngine(timeoutMillis)
}

actual fun webSocketEngine(): WebSocketEngine {
return DefaultWebSocketEngine()
}

actual val isKtor = false
14 changes: 14 additions & 0 deletions tests/engine/src/ktorTest/kotlin/engines.ktor.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import com.apollographql.apollo3.network.http.HttpEngine
import com.apollographql.apollo3.network.http.KtorHttpEngine
import com.apollographql.apollo3.network.ws.KtorWebSocketEngine
import com.apollographql.apollo3.network.ws.WebSocketEngine

actual fun httpEngine(timeoutMillis: Long): HttpEngine {
return KtorHttpEngine(timeoutMillis)
}

actual fun webSocketEngine(): WebSocketEngine {
return KtorWebSocketEngine()
}

actual val isKtor = true
Loading