diff --git a/gradle.properties b/gradle.properties index e9180826..ade889c4 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,5 +1,5 @@ # -# Copyright 2015-2023 the original author or authors. +# Copyright 2015-2024 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. @@ -16,13 +16,13 @@ group=io.rsocket.kotlin version=0.16.0-SNAPSHOT #Kotlin -kotlin.js.compiler=ir kotlin.native.ignoreIncorrectDependencies=true kotlinx.atomicfu.enableJvmIrTransformation=true kotlinx.atomicfu.enableJsIrTransformation=true +kotlinx.atomicfu.enableNativeIrTransformations=true #Gradle +org.gradle.jvmargs=-Xmx2g org.gradle.parallel=true org.gradle.caching=true +org.gradle.configuration-cache=true org.gradle.configureondemand=true -org.gradle.jvmargs=-Xmx2g -org.gradle.vfs.watch=true diff --git a/gradle/libs.updates.gradle.kts b/gradle/libs.updates.gradle.kts index e9660a82..a0a82afe 100644 --- a/gradle/libs.updates.gradle.kts +++ b/gradle/libs.updates.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2015-2023 the original author or authors. + * Copyright 2015-2024 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. @@ -16,7 +16,7 @@ /** * run to check for dependencies: - * ./gradlew :dependencyUpdates --init-script gradle/libs.updates.gradle.kts --no-configure-on-demand + * ./gradlew dependencyUpdates --init-script gradle/libs.updates.gradle.kts --no-configuration-cache */ initscript { @@ -28,12 +28,9 @@ initscript { } } -allprojects { - println("Project: $name / ${rootProject.name}") +rootProject { apply() - - // for root project add dependency on included builds - if (name == "rsocket-kotlin") tasks.named("dependencyUpdates") { + tasks.named("dependencyUpdates") { gradle.includedBuilds.forEach { dependsOn(it.task(":dependencyUpdates")) } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f9d7dc5c..6955e3d4 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -1,12 +1,12 @@ [versions] -kotlinx-atomicfu = "0.20.2" -kotlinx-coroutines = "1.6.4" #1.7.0 needs ktor with 1.7.0... +kotlinx-atomicfu = "0.23.2" +kotlinx-coroutines = "1.8.0" kotlinx-benchmark = "0.4.8" -kotlinx-bcv = "0.13.1" +kotlinx-bcv = "0.14.0" -ktor = "2.3.0" +ktor = "2.3.8" -turbine = "0.12.3" #0.13.0 needs coroutines 1.7.0 +turbine = "1.0.0" rsocket-java = "1.1.3" @@ -14,6 +14,7 @@ jmh = "1.36" [libraries] kotlinx-coroutines-core = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" } +kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" } kotlinx-coroutines-reactor = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-reactor", version.ref = "kotlinx-coroutines" } kotlinx-atomicfu = { module = "org.jetbrains.kotlinx:atomicfu", version.ref = "kotlinx-atomicfu" } diff --git a/gradle/plugins/build-logic/src/main/kotlin/rsocket.multiplatform.gradle.kts b/gradle/plugins/build-logic/src/main/kotlin/rsocket.multiplatform.gradle.kts index 5d55807e..ed170ca3 100644 --- a/gradle/plugins/build-logic/src/main/kotlin/rsocket.multiplatform.gradle.kts +++ b/gradle/plugins/build-logic/src/main/kotlin/rsocket.multiplatform.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2015-2023 the original author or authors. + * Copyright 2015-2024 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. @@ -14,8 +14,6 @@ * limitations under the License. */ -import org.jetbrains.kotlin.gradle.* - plugins { kotlin("multiplatform") id("build-parameters") @@ -24,9 +22,6 @@ plugins { kotlin { jvmToolchain(8) - @OptIn(ExperimentalKotlinGradlePluginApi::class) - targetHierarchy.default() - targets.configureEach { compilations.configureEach { compilerOptions.configure { @@ -44,6 +39,5 @@ kotlin { } val buildParameters = the() - -tasks.matching { it.name.endsWith("test", ignoreCase = true) }.configureEach { onlyIf { !buildParameters.skip.test } } -tasks.matching { it.name.startsWith("link", ignoreCase = true) }.configureEach { onlyIf { !buildParameters.skip.link } } +if (buildParameters.skip.test) tasks.matching { it.name.endsWith("test", ignoreCase = true) }.configureEach { onlyIf { false } } +if (buildParameters.skip.link) tasks.matching { it.name.startsWith("link", ignoreCase = true) }.configureEach { onlyIf { false } } diff --git a/gradle/plugins/kotlin-version-catalog/src/main/kotlin/kotlin-version-catalog.settings.gradle.kts b/gradle/plugins/kotlin-version-catalog/src/main/kotlin/kotlin-version-catalog.settings.gradle.kts index eecb3cf2..f116b18e 100644 --- a/gradle/plugins/kotlin-version-catalog/src/main/kotlin/kotlin-version-catalog.settings.gradle.kts +++ b/gradle/plugins/kotlin-version-catalog/src/main/kotlin/kotlin-version-catalog.settings.gradle.kts @@ -1,5 +1,5 @@ /* - * Copyright 2015-2023 the original author or authors. + * Copyright 2015-2024 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. @@ -18,7 +18,7 @@ plugins { id("build-parameters") } -val kotlinVersion = "1.8.21" +val kotlinVersion = "1.9.22" val kotlinVersionOverride = the().useKotlin.orNull?.takeIf(String::isNotBlank) if (kotlinVersionOverride != null) logger.lifecycle("Kotlin version override: $kotlinVersionOverride") diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index c1962a79..d64cd491 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 37aef8d3..35796a42 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,23 @@ +# +# Copyright 2015-2024 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. +# + distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index aeb74cbb..b7b7382b 100755 --- a/gradlew +++ b/gradlew @@ -1,13 +1,13 @@ #!/bin/sh # -# Copyright © 2015-2021 the original authors. +# Copyright 2015-2024 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 # -# https://www.apache.org/licenses/LICENSE-2.0 +# 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, @@ -83,7 +83,8 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -130,10 +131,13 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. @@ -141,7 +145,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -149,7 +153,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -198,11 +202,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/gradlew.bat b/gradlew.bat index 93e3f59f..25da30db 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -43,11 +43,11 @@ set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 if %ERRORLEVEL% equ 0 goto execute -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail @@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe if exist "%JAVA_EXE%" goto execute -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 goto fail diff --git a/rsocket-core/api/rsocket-core.api b/rsocket-core/api/rsocket-core.api index 5ca8819d..95c6e159 100644 --- a/rsocket-core/api/rsocket-core.api +++ b/rsocket-core/api/rsocket-core.api @@ -315,6 +315,7 @@ public final class io/rsocket/kotlin/core/WellKnownMimeType : java/lang/Enum, io public static final field VideoH264 Lio/rsocket/kotlin/core/WellKnownMimeType; public static final field VideoH265 Lio/rsocket/kotlin/core/WellKnownMimeType; public static final field VideoVp8 Lio/rsocket/kotlin/core/WellKnownMimeType; + public static fun getEntries ()Lkotlin/enums/EnumEntries; public fun getIdentifier ()B public fun getText ()Ljava/lang/String; public fun toString ()Ljava/lang/String; @@ -383,6 +384,7 @@ public final class io/rsocket/kotlin/logging/LoggingLevel : java/lang/Enum { public static final field INFO Lio/rsocket/kotlin/logging/LoggingLevel; public static final field TRACE Lio/rsocket/kotlin/logging/LoggingLevel; public static final field WARN Lio/rsocket/kotlin/logging/LoggingLevel; + public static fun getEntries ()Lkotlin/enums/EnumEntries; public static fun valueOf (Ljava/lang/String;)Lio/rsocket/kotlin/logging/LoggingLevel; public static fun values ()[Lio/rsocket/kotlin/logging/LoggingLevel; } @@ -581,6 +583,7 @@ public final class io/rsocket/kotlin/metadata/ZipkinTracingMetadata$Kind : java/ public static final field NotSampled Lio/rsocket/kotlin/metadata/ZipkinTracingMetadata$Kind; public static final field Sample Lio/rsocket/kotlin/metadata/ZipkinTracingMetadata$Kind; public static final field Unspecified Lio/rsocket/kotlin/metadata/ZipkinTracingMetadata$Kind; + public static fun getEntries ()Lkotlin/enums/EnumEntries; public static fun valueOf (Ljava/lang/String;)Lio/rsocket/kotlin/metadata/ZipkinTracingMetadata$Kind; public static fun values ()[Lio/rsocket/kotlin/metadata/ZipkinTracingMetadata$Kind; } @@ -728,6 +731,7 @@ public final class io/rsocket/kotlin/metadata/security/WellKnowAuthType : java/l public static final field Bearer Lio/rsocket/kotlin/metadata/security/WellKnowAuthType; public static final field Companion Lio/rsocket/kotlin/metadata/security/WellKnowAuthType$Companion; public static final field Simple Lio/rsocket/kotlin/metadata/security/WellKnowAuthType; + public static fun getEntries ()Lkotlin/enums/EnumEntries; public fun getIdentifier ()B public fun getText ()Ljava/lang/String; public fun toString ()Ljava/lang/String; diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/KeepAliveHandler.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/KeepAliveHandler.kt index 4a9a3ce6..15c94b1e 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/KeepAliveHandler.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/KeepAliveHandler.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -22,25 +22,27 @@ import io.rsocket.kotlin.frame.* import io.rsocket.kotlin.keepalive.* import kotlinx.atomicfu.* import kotlinx.coroutines.* +import kotlin.time.* internal class KeepAliveHandler( private val keepAlive: KeepAlive, - private val sender: FrameSender + private val sender: FrameSender, ) { - private val lastMark = atomic(currentMillis()) // mark initial timestamp for keepalive + private val initial = TimeSource.Monotonic.markNow() + private fun currentDelayMillis() = initial.elapsedNow().inWholeMilliseconds + + private val lastMark = atomic(currentDelayMillis()) // mark initial timestamp for keepalive suspend fun mark(frame: KeepAliveFrame) { - lastMark.value = currentMillis() + lastMark.value = currentDelayMillis() if (frame.respond) sender.sendKeepAlive(false, 0, frame.data) } suspend fun tick() { delay(keepAlive.intervalMillis.toLong()) - if (currentMillis() - lastMark.value >= keepAlive.maxLifetimeMillis) + if (currentDelayMillis() - lastMark.value >= keepAlive.maxLifetimeMillis) throw RSocketError.ConnectionError("No keep-alive for ${keepAlive.maxLifetimeMillis} ms") sender.sendKeepAlive(true, 0, ByteReadPacket.Empty) } } - -internal expect fun currentMillis(): Long diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/RequestFlow.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/RequestFlow.kt index 8694293a..31a34e96 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/RequestFlow.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/RequestFlow.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -44,7 +44,7 @@ internal suspend inline fun FlowCollector.emitAllWithRequestN( ) { val collector = object : RequestFlowCollector(this, strategy) { override suspend fun onRequest(n: Int) { - @OptIn(ExperimentalCoroutinesApi::class) + @OptIn(DelicateCoroutinesApi::class) if (!channel.isClosedForReceive) onRequest(n) } } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/FrameHandler.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/FrameHandler.kt index 3ac33d79..6d78f54d 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/FrameHandler.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/FrameHandler.kt @@ -106,6 +106,7 @@ internal abstract class ResponderFrameHandler : FrameHandler(), SendFrameHandler } } +@Suppress("DEPRECATION") private object NoPool : ObjectPool { override val capacity: Int get() = error("should not be called") diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/RequesterRequestChannelFrameHandler.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/RequesterRequestChannelFrameHandler.kt index 709438f9..27b9b3e0 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/RequesterRequestChannelFrameHandler.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/RequesterRequestChannelFrameHandler.kt @@ -67,7 +67,7 @@ internal class RequesterRequestChannelFrameHandler( return isCancelled } - @OptIn(ExperimentalCoroutinesApi::class) + @OptIn(DelicateCoroutinesApi::class) override fun onSendComplete() { if (channel.isClosedForSend) streamsStorage.remove(id) } diff --git a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/ResponderRequestChannelFrameHandler.kt b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/ResponderRequestChannelFrameHandler.kt index c73c2b0b..ac98537b 100644 --- a/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/ResponderRequestChannelFrameHandler.kt +++ b/rsocket-core/src/commonMain/kotlin/io/rsocket/kotlin/internal/handler/ResponderRequestChannelFrameHandler.kt @@ -64,7 +64,7 @@ internal class ResponderRequestChannelFrameHandler( } override fun onSendComplete() { - @OptIn(ExperimentalCoroutinesApi::class) + @OptIn(DelicateCoroutinesApi::class) if (channel.isClosedForSend) streamsStorage.remove(id) } diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/ConnectionEstablishmentTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/ConnectionEstablishmentTest.kt index ec32c646..db037c66 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/ConnectionEstablishmentTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/ConnectionEstablishmentTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2023 the original author or authors. + * Copyright 2015-2024 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. @@ -27,6 +27,7 @@ import kotlinx.coroutines.* import kotlin.test.* class ConnectionEstablishmentTest : SuspendTest, TestWithLeakCheck { + @Ignore // it will be rewritten anyway @Test fun responderRejectSetup() = test { val errorMessage = "error" diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ErrorFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ErrorFrameTest.kt index e3c8559d..49322bbe 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ErrorFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/ErrorFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -16,7 +16,6 @@ package io.rsocket.kotlin.frame -import io.ktor.util.* import io.ktor.utils.io.core.* import io.rsocket.kotlin.* import io.rsocket.kotlin.test.* @@ -31,12 +30,12 @@ class ErrorFrameTest : TestWithLeakCheck { val frame = ErrorFrame(1, RSocketError.ApplicationError("d")) val bytes = frame.toPacketWithLength().readBytes() - assertEquals(dump, hex(bytes)) + assertEquals(dump, bytes.toHexString()) } @Test fun testDecoding() { - val packet = packet(hex(dump)) + val packet = packet(dump.hexToByteArray()) val frame = packet.toFrameWithLength() assertTrue(frame is ErrorFrame) diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/KeepAliveFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/KeepAliveFrameTest.kt index 13f24d62..f0236131 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/KeepAliveFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/KeepAliveFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -16,7 +16,6 @@ package io.rsocket.kotlin.frame -import io.ktor.util.* import io.ktor.utils.io.core.* import io.rsocket.kotlin.test.* import kotlin.test.* @@ -29,12 +28,12 @@ class KeepAliveFrameTest : TestWithLeakCheck { val frame = KeepAliveFrame(true, 0, packet("d")) val bytes = frame.toPacketWithLength().readBytes() - assertEquals(dump, hex(bytes)) + assertEquals(dump, bytes.toHexString()) } @Test fun testDecoding() { - val packet = packet(hex(dump)) + val packet = packet(dump.hexToByteArray()) val frame = packet.toFrameWithLength() assertTrue(frame is KeepAliveFrame) diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestNFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestNFrameTest.kt index 7e442480..0582afe9 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestNFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestNFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -16,7 +16,6 @@ package io.rsocket.kotlin.frame -import io.ktor.util.* import io.ktor.utils.io.core.* import io.rsocket.kotlin.test.* import kotlin.test.* @@ -30,12 +29,12 @@ class RequestNFrameTest : TestWithLeakCheck { val frame = RequestNFrame(1, 5) val bytes = frame.toPacketWithLength().readBytes() - assertEquals(dump, hex(bytes)) + assertEquals(dump, bytes.toHexString()) } @Test fun testDecoding() { - val packet = packet(hex(dump)) + val packet = packet(dump.hexToByteArray()) val frame = packet.toFrameWithLength() assertTrue(frame is RequestNFrame) diff --git a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestStreamFrameTest.kt b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestStreamFrameTest.kt index 0221aac7..0e115967 100644 --- a/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestStreamFrameTest.kt +++ b/rsocket-core/src/commonTest/kotlin/io/rsocket/kotlin/frame/RequestStreamFrameTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -16,7 +16,6 @@ package io.rsocket.kotlin.frame -import io.ktor.util.* import io.ktor.utils.io.core.* import io.rsocket.kotlin.payload.* import io.rsocket.kotlin.test.* @@ -30,13 +29,13 @@ class RequestStreamFrameTest : TestWithLeakCheck { val frame = RequestStreamFrame(1, 1, payload("d", "md")) val bytes = frame.toPacketWithLength().readBytes() - assertEquals(dump, hex(bytes)) + assertEquals(dump, bytes.toHexString()) } @Test fun testDecoding() { val dump = "000010000000011900000000010000026d6464" - val frame = packet(hex(dump)).toFrameWithLength() + val frame = packet(dump.hexToByteArray()).toFrameWithLength() assertTrue(frame is RequestFrame) assertEquals(FrameType.RequestStream, frame.type) @@ -55,13 +54,13 @@ class RequestStreamFrameTest : TestWithLeakCheck { val frame = RequestStreamFrame(1, 1, Payload(packet("d"), ByteReadPacket.Empty)) val bytes = frame.toPacketWithLength().readBytes() - assertEquals(dump, hex(bytes)) + assertEquals(dump, bytes.toHexString()) } @Test fun testDecodingWithEmptyMetadata() { val dump = "00000e0000000119000000000100000064" - val frame = packet(hex(dump)).toFrameWithLength() + val frame = packet(dump.hexToByteArray()).toFrameWithLength() assertTrue(frame is RequestFrame) assertEquals(FrameType.RequestStream, frame.type) @@ -80,13 +79,13 @@ class RequestStreamFrameTest : TestWithLeakCheck { val frame = RequestStreamFrame(1, 1, payload("d")) val bytes = frame.toPacketWithLength().readBytes() - assertEquals(dump, hex(bytes)) + assertEquals(dump, bytes.toHexString()) } @Test fun testDecodingWithNullMetadata() { val dump = "00000b0000000118000000000164" - val frame = packet(hex(dump)).toFrameWithLength() + val frame = packet(dump.hexToByteArray()).toFrameWithLength() assertTrue(frame is RequestFrame) assertEquals(FrameType.RequestStream, frame.type) diff --git a/rsocket-core/src/jsMain/kotlin/io/rsocket/kotlin/internal/currentMillis.kt b/rsocket-core/src/jsMain/kotlin/io/rsocket/kotlin/internal/currentMillis.kt deleted file mode 100644 index d0b7c469..00000000 --- a/rsocket-core/src/jsMain/kotlin/io/rsocket/kotlin/internal/currentMillis.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2015-2022 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.internal - -import kotlin.js.* - -internal actual fun currentMillis(): Long = Date.now().toLong() diff --git a/rsocket-core/src/jvmMain/kotlin/io/rsocket/kotlin/internal/currentMillis.kt b/rsocket-core/src/jvmMain/kotlin/io/rsocket/kotlin/internal/currentMillis.kt deleted file mode 100644 index 03c343bf..00000000 --- a/rsocket-core/src/jvmMain/kotlin/io/rsocket/kotlin/internal/currentMillis.kt +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2015-2022 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.internal - -internal actual fun currentMillis(): Long = System.currentTimeMillis() diff --git a/rsocket-core/src/nativeMain/kotlin/io/rsocket/kotlin/internal/currentMillis.kt b/rsocket-core/src/nativeMain/kotlin/io/rsocket/kotlin/internal/currentMillis.kt deleted file mode 100644 index 9c4648b0..00000000 --- a/rsocket-core/src/nativeMain/kotlin/io/rsocket/kotlin/internal/currentMillis.kt +++ /dev/null @@ -1,21 +0,0 @@ -/* - * Copyright 2015-2022 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.internal - -import kotlin.system.* - -internal actual fun currentMillis(): Long = getTimeMillis() diff --git a/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/BufferPool.kt b/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/BufferPool.kt index 1b157aff..ff5f10c2 100644 --- a/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/BufferPool.kt +++ b/rsocket-internal-io/src/commonMain/kotlin/io/rsocket/kotlin/internal/io/BufferPool.kt @@ -21,6 +21,7 @@ import io.ktor.utils.io.core.internal.* import io.ktor.utils.io.pool.* import kotlin.jvm.* +@Suppress("DEPRECATION") @JvmInline public value class BufferPool( @PublishedApi diff --git a/rsocket-test/build.gradle.kts b/rsocket-test/build.gradle.kts index 82ad0ee3..8aa48c22 100644 --- a/rsocket-test/build.gradle.kts +++ b/rsocket-test/build.gradle.kts @@ -14,13 +14,20 @@ * limitations under the License. */ +import org.jetbrains.kotlin.gradle.* + plugins { id("rsocket.template.test") id("rsocket.target.all") id("kotlinx-atomicfu") } +@OptIn(ExperimentalKotlinGradlePluginApi::class) kotlin { + compilerOptions { + freeCompilerArgs.add("-Xexpect-actual-classes") + } + sourceSets { commonMain { dependencies { @@ -28,7 +35,7 @@ kotlin { api(projects.rsocketCore) implementation(projects.rsocketInternalIo) - api(libs.ktor.utils) + api(libs.kotlinx.coroutines.test) api(libs.turbine) } } diff --git a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/InUseTrackingPool.kt b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/InUseTrackingPool.kt index ac5b3c1c..7a4dbc56 100644 --- a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/InUseTrackingPool.kt +++ b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/InUseTrackingPool.kt @@ -26,6 +26,7 @@ import kotlin.test.* val InUseTrackingPool: BufferPool = BufferPool(InUseTrackingPoolInstance) +@Suppress("DEPRECATION") private object InUseTrackingPoolInstance : ObjectPool, SynchronizedObject() { override val capacity: Int get() = BufferPool.capacity private val inUse = mutableSetOf() @@ -125,7 +126,7 @@ private object InUseTrackingPoolInstance : ObjectPool, Synchronized } private class IdentityWrapper( - private val instance: ChunkBuffer, + private val instance: Any, val throwable: Throwable?, ) { override fun equals(other: Any?): Boolean { @@ -136,9 +137,6 @@ private class IdentityWrapper( override fun hashCode(): Int = identityHashCode(instance) } -//TODO leak tracking don't work on JS in SuspendTest -// due to `hack`, that to run `suspend` tests on JS, we return `Promise`, for which kotlin JS test runner will subscribe -// in such cases `AfterTest` will be called just after `Promise` returned, and not when it resolved interface TestWithLeakCheck { @BeforeTest diff --git a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Packets.kt b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Packets.kt index 3f3d4651..ed9657fd 100644 --- a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Packets.kt +++ b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Packets.kt @@ -16,7 +16,6 @@ package io.rsocket.kotlin.test -import io.ktor.util.* import io.ktor.utils.io.core.* import io.rsocket.kotlin.payload.* import kotlin.test.* @@ -32,5 +31,5 @@ fun payload(data: ByteArray, metadata: ByteArray? = null): Payload = Payload(pac fun payload(data: String, metadata: String? = null): Payload = Payload(packet(data), metadata?.let(::packet)) fun assertBytesEquals(expected: ByteArray?, actual: ByteArray?) { - assertEquals(expected?.let(::hex), actual?.let(::hex)) + assertEquals(expected?.toHexString(), actual?.toHexString()) } diff --git a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/SuspendTest.kt b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/SuspendTest.kt index ee7d26cd..60e0277b 100644 --- a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/SuspendTest.kt +++ b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/SuspendTest.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -17,6 +17,7 @@ package io.rsocket.kotlin.test import kotlinx.coroutines.* +import kotlinx.coroutines.test.* import kotlin.coroutines.* import kotlin.time.* import kotlin.time.Duration.Companion.minutes @@ -40,18 +41,19 @@ interface SuspendTest { fun test( timeout: Duration = testTimeout, block: suspend CoroutineScope.() -> Unit, - ) = runTest { + ) = runTest(timeout = 10.minutes) { + withContext(Dispatchers.Default) { + val beforeError = runPhase("BEFORE", beforeTimeout) { before() } - val beforeError = runPhase("BEFORE", beforeTimeout) { before() } - - val testError = when (beforeError) { //don't run test if before failed - null -> runPhase("RUN", timeout, block) - else -> null - } + val testError = when (beforeError) { //don't run test if before failed + null -> runPhase("RUN", timeout, block) + else -> null + } - val afterError = runPhase("AFTER", afterTimeout) { after() } + val afterError = runPhase("AFTER", afterTimeout) { after() } - handleErrors(testError, listOf(beforeError, afterError)) + handleErrors(testError, listOf(beforeError, afterError)) + } } //suppresses errors if more than one @@ -61,6 +63,7 @@ interface SuspendTest { if (other.isEmpty()) return handleErrors(other.first(), other.drop(1)) } + else -> { other.forEach { it?.let(error::addSuppressed) } throw error @@ -75,10 +78,12 @@ interface SuspendTest { println("[TEST] $tag completed in ${result.duration}") null } + is TestResult.Failed -> { println("[TEST] $tag failed in ${result.duration} with error: ${result.cause.stackTraceToString()}") result.cause } + is TestResult.Timeout -> { println("[TEST] $tag failed by timeout: ${result.timeout}") result.cause diff --git a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Test.common.kt b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Test.common.kt index 63c8b809..337ccd36 100644 --- a/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Test.common.kt +++ b/rsocket-test/src/commonMain/kotlin/io/rsocket/kotlin/test/Test.common.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -18,8 +18,6 @@ package io.rsocket.kotlin.test import kotlinx.coroutines.* -internal expect fun runTest(block: suspend CoroutineScope.() -> Unit) - expect annotation class IgnoreJs() expect annotation class IgnoreJvm() expect annotation class IgnoreNative() diff --git a/rsocket-test/src/jsMain/kotlin/io/rsocket/kotlin/test/Test.kt b/rsocket-test/src/jsMain/kotlin/io/rsocket/kotlin/test/Test.kt index 901077e5..06142344 100644 --- a/rsocket-test/src/jsMain/kotlin/io/rsocket/kotlin/test/Test.kt +++ b/rsocket-test/src/jsMain/kotlin/io/rsocket/kotlin/test/Test.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -18,8 +18,6 @@ package io.rsocket.kotlin.test import kotlinx.coroutines.* -internal actual fun runTest(block: suspend CoroutineScope.() -> Unit): dynamic = GlobalScope.promise(block = block) - actual typealias IgnoreJs = kotlin.test.Ignore actual annotation class IgnoreJvm diff --git a/rsocket-test/src/jvmMain/kotlin/io/rsocket/kotlin/test/Test.kt b/rsocket-test/src/jvmMain/kotlin/io/rsocket/kotlin/test/Test.kt index 6df29a3f..e86c5bec 100644 --- a/rsocket-test/src/jvmMain/kotlin/io/rsocket/kotlin/test/Test.kt +++ b/rsocket-test/src/jvmMain/kotlin/io/rsocket/kotlin/test/Test.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -18,8 +18,6 @@ package io.rsocket.kotlin.test import kotlinx.coroutines.* -internal actual fun runTest(block: suspend CoroutineScope.() -> Unit): Unit = runBlocking(block = block) - actual annotation class IgnoreJs actual typealias IgnoreJvm = org.junit.Ignore diff --git a/rsocket-test/src/nativeMain/kotlin/io/rsocket/kotlin/test/Test.kt b/rsocket-test/src/nativeMain/kotlin/io/rsocket/kotlin/test/Test.kt index 4e960a57..3b97c4c1 100644 --- a/rsocket-test/src/nativeMain/kotlin/io/rsocket/kotlin/test/Test.kt +++ b/rsocket-test/src/nativeMain/kotlin/io/rsocket/kotlin/test/Test.kt @@ -1,5 +1,5 @@ /* - * Copyright 2015-2022 the original author or authors. + * Copyright 2015-2024 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. @@ -17,14 +17,14 @@ package io.rsocket.kotlin.test import kotlinx.coroutines.* +import kotlin.experimental.* import kotlin.native.* -internal actual fun runTest(block: suspend CoroutineScope.() -> Unit) = runBlocking(block = block) - actual annotation class IgnoreJs actual annotation class IgnoreJvm actual typealias IgnoreNative = kotlin.test.Ignore actual val anotherDispatcher: CoroutineDispatcher get() = newSingleThreadContext("another") +@OptIn(ExperimentalNativeApi::class) actual fun identityHashCode(instance: Any): Int = instance.identityHashCode()