diff --git a/.github/workflows/gradle-main.yml b/.github/workflows/gradle-main.yml index 5a31413a3..a9664d656 100644 --- a/.github/workflows/gradle-main.yml +++ b/.github/workflows/gradle-main.yml @@ -78,7 +78,7 @@ jobs: dependencies-cache-enabled: false configuration-cache-enabled: false - name: Test rsocket-transport-ktor module - if: matrix.target != 'mingwX64' && matrix.target != 'jsIrNode' && matrix.target != 'jsIrBrowser' && matrix.target != 'jsLegacyNode' && matrix.target != 'jsLegacyBrowser' && (success() || failure()) + if: matrix.target != 'mingwX64' && (success() || failure()) timeout-minutes: 10 uses: gradle/gradle-build-action@v1 with: diff --git a/.github/workflows/gradle-pr.yml b/.github/workflows/gradle-pr.yml index 52c5995ab..34b370f16 100644 --- a/.github/workflows/gradle-pr.yml +++ b/.github/workflows/gradle-pr.yml @@ -73,7 +73,7 @@ jobs: dependencies-cache-enabled: false configuration-cache-enabled: false - name: Test rsocket-transport-ktor module - if: matrix.target != 'mingwX64' && matrix.target != 'jsIrNode' && matrix.target != 'jsIrBrowser' && matrix.target != 'jsLegacyNode' && matrix.target != 'jsLegacyBrowser' && (success() || failure()) + if: matrix.target != 'mingwX64' && (success() || failure()) timeout-minutes: 10 uses: gradle/gradle-build-action@v1 with: diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml index cbb9c0c74..9f9ddc1b4 100644 --- a/.github/workflows/run-tests.yml +++ b/.github/workflows/run-tests.yml @@ -72,7 +72,7 @@ jobs: dependencies-cache-enabled: false configuration-cache-enabled: false - name: Test rsocket-transport-ktor module - if: matrix.target != 'mingwX64' && matrix.target != 'jsIrNode' && matrix.target != 'jsIrBrowser' && matrix.target != 'jsLegacyNode' && matrix.target != 'jsLegacyBrowser' && (success() || failure()) + if: matrix.target != 'mingwX64' && (success() || failure()) timeout-minutes: 10 uses: gradle/gradle-build-action@v1 with: diff --git a/build.gradle.kts b/build.gradle.kts index fb20ca1b7..6447c1dd0 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -63,8 +63,9 @@ subprojects { //targets configuration extensions.configure { val isAutoConfigurable = project.name.startsWith("rsocket") //manual config of others - val jvmOnly = project.name == "rsocket-transport-ktor-server" //server is jvm only - + val jvmOnly = + project.name == "rsocket-transport-ktor-server" || //server is jvm only + project.name == "rsocket-test-server" //windows target isn't supported by ktor-network val supportMingw = project.name != "rsocket-transport-ktor" && project.name != "rsocket-transport-ktor-client" @@ -140,7 +141,7 @@ subprojects { //common configuration extensions.configure { - val isTestProject = project.name == "rsocket-test" + val isTestProject = project.name == "rsocket-test" || project.name == "rsocket-test-server" val isLibProject = project.name.startsWith("rsocket") val isPlaygroundProject = project.name == "playground" val isExampleProject = "examples" in project.path diff --git a/examples/multiplatform-chat/build.gradle.kts b/examples/multiplatform-chat/build.gradle.kts index 822cdbe29..e229c3c1e 100644 --- a/examples/multiplatform-chat/build.gradle.kts +++ b/examples/multiplatform-chat/build.gradle.kts @@ -80,7 +80,7 @@ kotlin { val clientJsMain by getting { dependsOn(clientMain) dependencies { - implementation("io.ktor:ktor-client-js:$ktorVersion") + implementation("io.ktor:ktor-client-core:$ktorVersion") } } diff --git a/playground/build.gradle.kts b/playground/build.gradle.kts index 63d299690..bd81ccd28 100644 --- a/playground/build.gradle.kts +++ b/playground/build.gradle.kts @@ -46,6 +46,8 @@ kotlin { implementation(project(":rsocket-core")) implementation(project(":rsocket-transport-local")) implementation(project(":rsocket-transport-ktor-client")) + + implementation("io.ktor:ktor-client-core:$ktorVersion") //for WS support } } val jvmMain by getting { @@ -56,10 +58,5 @@ kotlin { implementation("io.ktor:ktor-server-cio:$ktorVersion") } } - val jsMain by getting { - dependencies { - implementation("io.ktor:ktor-client-js:$ktorVersion") //for WS support - } - } } } diff --git a/rsocket-test/rsocket-test-server/build.gradle.kts b/rsocket-test/rsocket-test-server/build.gradle.kts new file mode 100644 index 000000000..5fd31fcba --- /dev/null +++ b/rsocket-test/rsocket-test-server/build.gradle.kts @@ -0,0 +1,87 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import org.jetbrains.kotlin.gradle.plugin.mpp.* +import java.io.* +import java.net.* + +plugins { + kotlin("multiplatform") +} + +val ktorVersion: String by rootProject + +kotlin { + sourceSets { + val jvmMain by getting { + dependencies { + implementation(project(":rsocket-test")) + implementation(project(":rsocket-transport-ktor-server")) + + implementation("io.ktor:ktor-server-cio:$ktorVersion") + } + } + } +} + +open class RSocketTestServer : DefaultTask() { + @Internal + var server: Closeable? = null + private set + + @Internal + lateinit var classpath: FileCollection + + @TaskAction + fun exec() { + try { + println("[TestServer] start") + val loader = URLClassLoader(classpath.map { it.toURI().toURL() }.toTypedArray(), ClassLoader.getSystemClassLoader()) + server = loader.loadClass("io.rsocket.kotlin.test.server.AppKt").getMethod("start").invoke(null) as Closeable + println("[TestServer] started") + } catch (cause: Throwable) { + println("[TestServer] failed: ${cause.message}") + cause.printStackTrace() + } + } +} + +val startTestServer by tasks.registering(RSocketTestServer::class) { + dependsOn(tasks["jvmJar"]) + classpath = (kotlin.targets["jvm"].compilations["test"] as KotlinJvmCompilation).runtimeDependencyFiles +} + +val testTasks = setOf( + "jsLegacyNodeTest", + "jsIrNodeTest", + "jsLegacyBrowserTest", + "jsIrBrowserTest", +) + +rootProject.allprojects { + if (name == "rsocket-transport-ktor") { + tasks.matching { it.name in testTasks }.all { + dependsOn(startTestServer) + } + } +} + +gradle.buildFinished { + startTestServer.get().server?.run { + close() + println("[TestServer] stop") + } +} diff --git a/rsocket-test/rsocket-test-server/src/jvmMain/kotlin/io/rsocket/kotlin/test/server/App.kt b/rsocket-test/rsocket-test-server/src/jvmMain/kotlin/io/rsocket/kotlin/test/server/App.kt new file mode 100644 index 000000000..904b77c5d --- /dev/null +++ b/rsocket-test/rsocket-test-server/src/jvmMain/kotlin/io/rsocket/kotlin/test/server/App.kt @@ -0,0 +1,75 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.rsocket.kotlin.test.server + +import io.ktor.application.* +import io.ktor.routing.* +import io.ktor.server.cio.* +import io.ktor.server.engine.* +import io.ktor.websocket.* +import io.rsocket.kotlin.core.* +import io.rsocket.kotlin.test.* +import io.rsocket.kotlin.transport.ktor.* +import io.rsocket.kotlin.transport.ktor.server.* +import kotlinx.coroutines.* +import java.io.* + +fun main() { + start().await() +} + +fun start(): TestServer { + val server = TestServer() + server.start() + return server +} + +class TestServer : Closeable { + private val job = Job() + private var wsServer: ApplicationEngine? = null + private val rSocketServer = RSocketServer { +// loggerFactory = PrintLogger.withLevel(LoggingLevel.DEBUG) + } + + fun start(): Unit = runCatching { + val scope = CoroutineScope(job) + + //start TCP server + rSocketServer.bindIn(scope, TcpServerTransport(port = 8000)) { TestRSocket() } + + //start WS server + wsServer = scope.embeddedServer(CIO, port = 9000) { + install(WebSockets) + install(RSocketSupport) { server = rSocketServer } + + routing { + rSocket { TestRSocket() } + } + }.start() + + Thread.sleep(1000) //await start + }.onFailure { close() }.getOrThrow() + + fun await() { + runBlocking { job.join() } + } + + override fun close() { + runBlocking { job.cancelAndJoin() } + wsServer?.stop(0, 1000) + } +} diff --git a/rsocket-transport-ktor/build.gradle.kts b/rsocket-transport-ktor/build.gradle.kts index 01e2e152a..8c289a3e6 100644 --- a/rsocket-transport-ktor/build.gradle.kts +++ b/rsocket-transport-ktor/build.gradle.kts @@ -58,3 +58,5 @@ kotlin { } description = "Ktor RSocket transport implementations (TCP, Websocket)" + +evaluationDependsOn(":rsocket-test-server") diff --git a/rsocket-transport-ktor/src/jsTest/kotlin/io/rsocket/kotlin/transport/ktor/ClientWebSocketTransportTest.kt b/rsocket-transport-ktor/src/jsTest/kotlin/io/rsocket/kotlin/transport/ktor/ClientWebSocketTransportTest.kt new file mode 100644 index 000000000..2285574a1 --- /dev/null +++ b/rsocket-transport-ktor/src/jsTest/kotlin/io/rsocket/kotlin/transport/ktor/ClientWebSocketTransportTest.kt @@ -0,0 +1,43 @@ +/* + * Copyright 2015-2020 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.rsocket.kotlin.transport.ktor + +import io.ktor.client.* +import io.ktor.client.engine.js.* +import io.ktor.client.features.websocket.* +import io.rsocket.kotlin.test.* +import io.rsocket.kotlin.transport.ktor.client.* +import kotlinx.coroutines.* + +class ClientWebSocketTransportTest : TransportTest() { + + private val httpClient = HttpClient(Js) { + install(WebSockets) + install(RSocketSupport) { connector = CONNECTOR } + } + + override suspend fun before() { + client = httpClient.rSocket(port = 9000) + } + + override suspend fun after() { + super.after() + httpClient.close() + httpClient.coroutineContext.job.cancelAndJoin() + } + +} diff --git a/settings.gradle.kts b/settings.gradle.kts index be056ed4b..207278e2d 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -62,6 +62,8 @@ include("playground") include("rsocket-core") include("rsocket-test") +include("rsocket-test-server") +project(":rsocket-test-server").projectDir = file("rsocket-test/rsocket-test-server") include("rsocket-transport-local")