1
0
mirror of https://github.com/square/okhttp.git synced 2026-01-12 10:23:16 +03:00
This commit is contained in:
Jesse Wilson
2025-11-14 13:59:48 -05:00
parent d36592abe4
commit 4a4cea49c4
5 changed files with 184 additions and 7 deletions

View File

@@ -33,6 +33,7 @@ buildscript {
repositories {
mavenCentral()
mavenLocal()
gradlePluginPortal()
google()
}
@@ -55,6 +56,7 @@ allprojects {
repositories {
mavenCentral()
mavenLocal()
google()
}

View File

@@ -20,6 +20,7 @@ plugins {
repositories {
mavenCentral()
mavenLocal()
gradlePluginPortal()
}

View File

@@ -1,9 +1,9 @@
[versions]
agp = "8.13.0"
agp = "8.12.0"
biz-aQute-bnd = "7.1.0"
checkStyle = "12.1.1"
com-squareup-moshi = "1.15.2"
com-squareup-okio = "3.16.2"
com-squareup-okio = "3.17.0-SNAPSHOT"
de-mannodermaus-junit5 = "1.9.0"
graalvm = "25.0.1"
#noinspection UnusedVersionCatalogEntry

View File

@@ -11,12 +11,15 @@ import java.net.ServerSocket
import java.time.Duration
import java.time.Instant
import java.util.concurrent.Executors
import java.util.concurrent.TimeUnit
import kotlin.test.assertFailsWith
import kotlinx.coroutines.runBlocking
import okhttp3.Call
import okhttp3.Dns
import okhttp3.EventListener
import okhttp3.OkHttpClient
import okhttp3.Request
import okio.AsyncTimeout
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.Test
@@ -29,9 +32,9 @@ class ReproduceOkHttpIssueTest {
val proxyHost = "unresponsive-proxy-host"
// 2. Set Timeouts
val callTimeout = Duration.ofSeconds(3)
val connectTimeout = Duration.ofSeconds(1)
val readTimeout = Duration.ofSeconds(2)
val callTimeout = Duration.ofSeconds(3 * 2)
val connectTimeout = Duration.ofSeconds(1 * 2)
val readTimeout = Duration.ofSeconds(2 * 2)
// 3. Build the Client with the Custom Dns
var client = OkHttpClient.Builder()
@@ -63,8 +66,13 @@ class ReproduceOkHttpIssueTest {
@AfterEach
fun close() {
executorService.shutdownNow()
stallingServer.stop()
Thread.interrupted()
try {
executorService.shutdownNow()
stallingServer.stop()
} catch (e: Exception) {
e.printStackTrace()
}
}
@Test
@@ -102,6 +110,165 @@ class ReproduceOkHttpIssueTest {
}
}
class TestTimeout(
val name: String,
val thread: Thread = Thread.currentThread(),
) : AsyncTimeout() {
override fun timedOut() {
thread.interrupt()
}
override fun toString(): String {
return name
}
}
var recordingStart = 0L
val testStart = System.nanoTime()
fun sleepUntil(time: Long) {
val currentElapsed = (System.nanoTime() - testStart)
val targetElapsed = time - recordingStart
val nanos = targetElapsed - currentElapsed
val ms = nanos / 1_000_000L
val ns = nanos - (ms * 1_000_000L)
if (ms > 0L || nanos > 0) {
Thread.sleep(ms, ns.toInt())
}
}
/** Annoyingly this does what we want. */
@Test
@Throws(InterruptedException::class)
fun perfectTest() {
val T1 = TestTimeout("T1")
T1.timeout(3000000000, TimeUnit.NANOSECONDS)
val T2 = TestTimeout("T2")
T2.timeout(10000000000, TimeUnit.NANOSECONDS)
val T3 = TestTimeout("T3")
T3.timeout(2000000000, TimeUnit.NANOSECONDS)
val T4 = TestTimeout("T4")
T4.timeout(10000000000, TimeUnit.NANOSECONDS)
val T5 = TestTimeout("T5")
T5.timeout(2000000000, TimeUnit.NANOSECONDS)
// sleepUntil(0)
T1.enter()
sleepUntil(21_021_375)
T2.enter()
sleepUntil(43_177_042)
T2.exit()
sleepUntil(46_650_750)
T2.enter()
sleepUntil(50_056_459)
T2.exit()
sleepUntil(53_838_167)
T3.enter()
sleepUntil(81_087_334)
T3.exit()
sleepUntil(2_000_000_000)
T4.enter()
sleepUntil(2_169_520_000)
T4.exit()
sleepUntil(2_175_734_375)
T4.enter()
sleepUntil(2_182_283_250)
T4.exit()
sleepUntil(2_188_262_042)
T5.enter()
sleepUntil(2_195_482_917)
T5.exit()
assertFailsWith<InterruptedException> {
sleepUntil(3_500_000_000)
}
T1.exit()
}
/** Annoyingly this does what we want. */
@Test
@Throws(InterruptedException::class)
fun failingTest() {
val T1 = TestTimeout("T1")
T1.timeout(3000000000, TimeUnit.NANOSECONDS)
val T2 = TestTimeout("T2")
T2.timeout(10000000000, TimeUnit.NANOSECONDS)
val T3 = TestTimeout("T3")
T3.timeout(2000000000, TimeUnit.NANOSECONDS)
val T4 = TestTimeout("T4")
T4.timeout(10000000000, TimeUnit.NANOSECONDS)
val T5 = TestTimeout("T5")
T5.timeout(2000000000, TimeUnit.NANOSECONDS)
recordingStart = 48037384402166
sleepUntil(48037384402166)
T1.enter()
sleepUntil(48037410711791)
T2.enter()
sleepUntil(48037429544208)
T2.exit()
sleepUntil(48037432485375)
T2.enter()
sleepUntil(48037435469416)
T2.exit()
sleepUntil(48037438890625)
T3.enter()
//calling timedOut 48037482781291 on null
sleepUntil(48037484109708)
T3.exit()
sleepUntil(48039554055708)
T4.enter()
sleepUntil(48039558740333)
T4.exit()
sleepUntil(48039562572583)
T4.enter()
sleepUntil(48039566864625)
T4.exit()
sleepUntil(48039570599375)
T5.enter()
//calling timedOut 48039574546166 on null
sleepUntil(48039575464541)
T5.exit()
//calling timedOut 48040398250541 on null
//calling timedOut 48040401757166 on T1 // took too long?
assertFailsWith<InterruptedException> {
sleepUntil(1_000_000_000 + 48040415361958) // this should time out, but too late?
}
T1.exit()
}
@Test
@Throws(InterruptedException::class)
fun tff() {
executorService.submit { stallingServer.start(8080) }
Thread.sleep(2000)
val startTime = Instant.now()
try {
runBlocking { client.newCall(request).executeAsync() }.use { response ->
println("Call Succeeded unexpectedly.")
}
} catch (e: Exception) {
val totalTime = Duration.between(startTime, Instant.now())
println("--- TEST RESULT ---")
println("Exception: " + e.javaClass.getName() + ": " + e.message)
println("Total Time: $totalTime")
println("Expected Time (Call Timeout): $callTimeout")
println("Observed Time (2 x Read Timeout): " + readTimeout.multipliedBy(2))
assertThat(totalTime).isLessThan(readTimeout.multipliedBy(2))
}
}
class StallingServer {
private lateinit var serverSocket: ServerSocket

View File

@@ -70,3 +70,10 @@ if (androidHome != null || sdkDir != null) {
}
enableFeaturePreview("TYPESAFE_PROJECT_ACCESSORS")
//includeBuild("/Users/jwilson/Development/okio") {
// dependencySubstitution {
// substitute(module("com.squareup.okio:okio"))
// .using(project(":okio"))
// }
//}