Skip to content

Commit

Permalink
Merge branch 'main' into renovate/ktor-monorepo
Browse files Browse the repository at this point in the history
  • Loading branch information
e5l authored Nov 25, 2024
2 parents 960b45c + d783338 commit fc139e1
Show file tree
Hide file tree
Showing 10 changed files with 130 additions and 87 deletions.
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jetty-alpn-boot = "8.1.13.v20181017"
jetty-alpn-openjdk8 = "9.4.56.v20240826"

tomcat = "9.0.97"
tomcat-jakarta = "10.1.33"
tomcat-jakarta = "10.1.31"

apache = "4.1.5"
apache5 = "5.3.1"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import io.ktor.client.request.*
import io.ktor.client.statement.*
import io.ktor.client.tests.utils.*
import io.ktor.http.*
import io.ktor.util.PlatformUtils
import io.ktor.utils.io.*
import io.ktor.utils.io.CancellationException
import kotlinx.coroutines.*
Expand Down Expand Up @@ -169,6 +170,9 @@ class HttpTimeoutTest : ClientLoader() {

@Test
fun testGetWithSeparateReceive() = clientTests {
// https://youtrack.jetbrains.com/issue/KTOR-7847/Investigate-Flaky-timeout-tests-on-linuxX64
if (PlatformUtils.IS_NATIVE) return@clientTests

config {
install(HttpTimeout) { requestTimeoutMillis = 2000 }
}
Expand All @@ -185,7 +189,10 @@ class HttpTimeoutTest : ClientLoader() {
}

@Test
fun testGetWithSeparateReceivePerRequestAttributes() = clientTests(retries = 5) {
fun testGetWithSeparateReceivePerRequestAttributes() = clientTests {
// https://youtrack.jetbrains.com/issue/KTOR-7847/Investigate-Flaky-timeout-tests-on-linuxX64
if (PlatformUtils.IS_NATIVE) return@clientTests

config {
install(HttpTimeout)
}
Expand All @@ -205,6 +212,9 @@ class HttpTimeoutTest : ClientLoader() {

@Test
fun testGetRequestTimeoutWithSeparateReceive() = clientTests(listOf("Js"), retries = 5) {
// https://youtrack.jetbrains.com/issue/KTOR-7847/Investigate-Flaky-timeout-tests-on-linuxX64
if (PlatformUtils.IS_NATIVE) return@clientTests

config {
install(HttpTimeout) { requestTimeoutMillis = 2000 }
}
Expand All @@ -222,24 +232,25 @@ class HttpTimeoutTest : ClientLoader() {
}

@Test
fun testGetRequestTimeoutWithSeparateReceivePerRequestAttributes() =
clientTests(listOf("Js", "Curl", "Darwin", "DarwinLegacy")) {
config {
install(HttpTimeout)
}
fun testGetRequestTimeoutWithSeparateReceivePerRequestAttributes() = clientTests(
listOf("Js", "Curl", "Darwin", "DarwinLegacy")
) {
config {
install(HttpTimeout)
}

test { client ->
val response = client.prepareRequest("$TEST_URL/with-stream") {
method = HttpMethod.Get
parameter("delay", 10000)
test { client ->
val response = client.prepareRequest("$TEST_URL/with-stream") {
method = HttpMethod.Get
parameter("delay", 10000)

timeout { requestTimeoutMillis = 2000 }
}.body<ByteReadChannel>()
assertFailsWith<CancellationException> {
response.readUTF8Line()
}
timeout { requestTimeoutMillis = 2000 }
}.body<ByteReadChannel>()
assertFailsWith<CancellationException> {
response.readUTF8Line()
}
}
}

@Test
fun testGetAfterTimeout() = clientTests(listOf("Curl", "Js", "Darwin", "DarwinLegacy")) {
Expand All @@ -263,31 +274,17 @@ class HttpTimeoutTest : ClientLoader() {
}

@Test
fun testGetStream() = clientTests(retries = 5) {
config {
install(HttpTimeout) { requestTimeoutMillis = 1000 }
}

test { client ->
val responseBody: String = client.get("$TEST_URL/with-stream") {
parameter("delay", 10)
}.body()
fun testGetStream() = clientTests(retries = 10) {
// https://youtrack.jetbrains.com/issue/KTOR-7847/Investigate-Flaky-timeout-tests-on-linuxX64
if (PlatformUtils.IS_NATIVE) return@clientTests

assertEquals("Text", responseBody)
}
}

@Test
fun testGetStreamPerRequestAttributes() = clientTests(retries = 5) {
config {
install(HttpTimeout)
install(HttpTimeout) { requestTimeoutMillis = 1000 }
}

test { client ->
val responseBody: String = client.get("$TEST_URL/with-stream") {
parameter("delay", 10)

timeout { requestTimeoutMillis = 1000 }
}.body()

assertEquals("Text", responseBody)
Expand Down Expand Up @@ -328,7 +325,7 @@ class HttpTimeoutTest : ClientLoader() {

// Js can't configure test timeout in browser
@Test
fun testRedirect() = clientTests(listOf("js")) {
fun testRedirect() = clientTests(listOf("js"), retries = 5) {
config {
install(HttpTimeout) { requestTimeoutMillis = 10000 }
}
Expand Down Expand Up @@ -439,8 +436,7 @@ class HttpTimeoutTest : ClientLoader() {
assertFails {
try {
client.get("http://localhost:11").body<String>()
} catch (_: ConnectTimeoutException) {
/* Ignore. */
} catch (_: ConnectTimeoutException) {/* Ignore. */
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import kotlin.test.*
class LoggingMockedTests {

@Test
fun testLogResponseWithException() = testWithEngine(MockEngine) {
fun testLogResponseWithException() = testWithEngine(MockEngine, retries = 5) {
val testLogger = TestLogger(
"REQUEST: ${URLBuilder.origin}",
"METHOD: HttpMethod(value=GET)",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,7 @@ class WebSocketTest : ClientLoader() {
}

@Test
fun testAuthenticationWithValidInitialToken() = clientTests(ENGINES_WITHOUT_WS + "Js", retries = 5) {
fun testAuthenticationWithValidInitialToken() = clientTests(ENGINES_WITHOUT_WS + "Js" + "Darwin", retries = 5) {
config {
install(WebSockets)

Expand Down
8 changes: 6 additions & 2 deletions ktor-network/jvm/src/io/ktor/network/sockets/SocketImpl.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ internal class SocketImpl<out S : SocketChannel>(
if (channel.finishConnect()) {
// TCP has a well known self-connect problem, which client can connect to the client itself
// without any program listen on the port.
if (selfConnect()) {
if (inetSelfConnect()) {
if (java7NetworkApisAvailable) {
channel.close()
} else {
Expand All @@ -74,7 +74,7 @@ internal class SocketImpl<out S : SocketChannel>(
interestOp(SelectInterest.CONNECT, state)
}

private fun selfConnect(): Boolean {
private fun inetSelfConnect(): Boolean {
val localAddress = if (java7NetworkApisAvailable) {
channel.localAddress
} else {
Expand All @@ -93,6 +93,10 @@ internal class SocketImpl<out S : SocketChannel>(
val localInetSocketAddress = localAddress as? java.net.InetSocketAddress
val remoteInetSocketAddress = remoteAddress as? java.net.InetSocketAddress

if (localInetSocketAddress == null && remoteInetSocketAddress == null) {
return false
}

val localHostAddress = localInetSocketAddress?.address?.hostAddress ?: ""
val remoteHostAddress = remoteInetSocketAddress?.address?.hostAddress ?: ""
val isRemoteAnyLocalAddress = remoteInetSocketAddress?.address?.isAnyLocalAddress ?: false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,33 @@

package io.ktor.server.test.base

import kotlinx.coroutines.*
import kotlinx.coroutines.test.*
import kotlin.time.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.TestResult
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

expect abstract class BaseTest() {
open val timeout: Duration

open fun beforeTest()
open fun afterTest()

fun collectUnhandledException(error: Throwable) // TODO: better name?
fun runTest(block: suspend CoroutineScope.() -> Unit): TestResult
fun runTest(timeout: Duration, block: suspend CoroutineScope.() -> Unit): TestResult
fun runTest(timeout: Duration = 60.seconds, block: suspend CoroutineScope.() -> Unit): TestResult
}

fun BaseTest.runTest(
retry: Int,
timeout: Duration = this.timeout,
block: suspend CoroutineScope.() -> Unit
): TestResult {
lateinit var lastCause: Throwable
repeat(retry) {
try {
return runTest(timeout, block)
} catch (cause: Throwable) {
lastCause = cause
}
}
throw lastCause
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,11 @@
package io.ktor.server.test.base

import io.ktor.test.dispatcher.*
import kotlinx.coroutines.*
import kotlinx.coroutines.test.*
import kotlin.test.*
import kotlin.time.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.test.TestResult
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

@Suppress("FunctionName")
actual abstract class BaseTest actual constructor() {
actual open val timeout: Duration = 10.seconds

Expand All @@ -21,8 +19,10 @@ actual abstract class BaseTest actual constructor() {
errors.add(error)
}

@AfterTest
fun _verifyErrors() {
actual open fun beforeTest() {
}

actual open fun afterTest() {
if (errors.isEmpty()) return

val error = UnhandledErrorsException(
Expand All @@ -36,11 +36,17 @@ actual abstract class BaseTest actual constructor() {
throw error // suppressed exceptions print wrong in idea
}

actual fun runTest(block: suspend CoroutineScope.() -> Unit): TestResult =
runTestWithRealTime(timeout = timeout, testBody = block)

actual fun runTest(timeout: Duration, block: suspend CoroutineScope.() -> Unit): TestResult =
runTestWithRealTime(timeout = timeout, testBody = block)
actual fun runTest(
timeout: Duration,
block: suspend CoroutineScope.() -> Unit
): TestResult = runTestWithRealTime(timeout = timeout) {
beforeTest()
try {
block()
} finally {
afterTest()
}
}
}

private class UnhandledErrorsException(override val message: String) : Exception()
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,15 @@ package io.ktor.server.test.base

import io.ktor.junit.*
import io.ktor.test.dispatcher.*
import kotlinx.coroutines.*
import kotlinx.coroutines.debug.junit5.*
import kotlinx.coroutines.test.*
import org.junit.jupiter.api.*
import java.lang.reflect.*
import kotlinx.coroutines.CoroutineName
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.debug.junit5.CoroutinesTimeout
import kotlinx.coroutines.test.TestResult
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.TestInfo
import java.lang.reflect.Method
import java.util.*
import kotlin.time.*
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds

@CoroutinesTimeout(5 * 60 * 1000)
Expand All @@ -33,18 +35,26 @@ actual abstract class BaseTest actual constructor() {
testName = method.map { it.name }.orElse(testInfo.displayName)
}

@AfterEach
fun throwErrors() {
actual open fun afterTest() {
errorCollector.throwErrorIfPresent()
}

actual open fun beforeTest() {
}

actual fun collectUnhandledException(error: Throwable) {
errorCollector += error
}

actual fun runTest(block: suspend CoroutineScope.() -> Unit): TestResult =
runTestWithRealTime(CoroutineName("test-$testName"), timeout, block)

actual fun runTest(timeout: Duration, block: suspend CoroutineScope.() -> Unit): TestResult =
runTestWithRealTime(CoroutineName("test-$testName"), timeout, block)
actual fun runTest(
timeout: Duration,
block: suspend CoroutineScope.() -> Unit
): TestResult = runTestWithRealTime(CoroutineName("test-$testName"), timeout) {
beforeTest()
try {
block()
} finally {
afterTest()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,9 @@ actual abstract class EngineTestBase<
System.getProperty("host.test.timeout.seconds")?.toLong()?.seconds ?: 4.minutes
}

@BeforeEach
fun setUpBase() {
override fun beforeTest() {
super.beforeTest()

val method = testMethod.orElseThrow { AssertionError("Method $testName not found") }

if (method.isAnnotationPresent(Http2Only::class.java)) {
Expand All @@ -95,8 +96,7 @@ actual abstract class EngineTestBase<
testLog.trace("Starting server on port $port (SSL $sslPort)")
}

@AfterEach
fun tearDownBase() {
override fun afterTest() {
try {
allConnections.forEach { it.disconnect() }
testLog.trace("Disposing server on port $port (SSL $sslPort)")
Expand All @@ -105,6 +105,7 @@ actual abstract class EngineTestBase<
testJob.cancel()
FreePorts.recycle(port)
FreePorts.recycle(sslPort)
super.afterTest()
}
}

Expand Down
Loading

0 comments on commit fc139e1

Please sign in to comment.