1
0
mirror of https://github.com/square/okhttp.git synced 2025-12-25 00:01:02 +03:00

Add more n-i-t tests from okhttp (#6387)

This commit is contained in:
Yuri Schimke
2020-11-03 19:56:29 +00:00
committed by GitHub
parent f17dedf628
commit 4677beea96
20 changed files with 242 additions and 49 deletions

View File

@@ -25,6 +25,7 @@ dependencies {
implementation project(':mockwebserver-junit5')
implementation deps.bndResolve
implementation deps.junit5Api
implementation deps.junit5JupiterParams
implementation("org.graalvm.nativeimage:svm:20.2.0") {
// https://youtrack.jetbrains.com/issue/KT-29513
@@ -44,6 +45,7 @@ animalsniffer {
if (!properties.containsKey('android.injected.invoked.from.ide')) {
sourceSets {
// Not included in IDE as this confuses Intellij for obvious reasons.
main.java.srcDirs += project.file("../okhttp/src/test/java")
main.java.srcDirs += project.file("../okhttp-brotli/src/test/java")
main.java.srcDirs += project.file("../okhttp-dnsoverhttps/src/test/java")
main.java.srcDirs += project.file("../okhttp-logging-interceptor/src/test/java")
@@ -64,6 +66,7 @@ graal {
option "-H:+ReportExceptionStackTraces"
option "-H:+TraceClassInitialization"
option "--initialize-at-build-time=kotlin.text.Charsets"
option "-H:EnableURLProtocols=http,https"
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
// May be possible without, but autodetection is problematic on Windows 10

View File

@@ -19,10 +19,23 @@ import org.junit.platform.engine.TestExecutionResult
import org.junit.platform.launcher.TestExecutionListener
import org.junit.platform.launcher.TestIdentifier
import org.junit.platform.launcher.TestPlan
import java.io.OutputStream
import java.io.PrintStream
object DotListener: TestExecutionListener {
private var originalSystemErr: PrintStream? = null
private var originalSystemOut: PrintStream? = null
private var testCount = 0
override fun executionSkipped(testIdentifier: TestIdentifier, reason: String) {
System.err.print("-")
printStatus("-")
}
private fun printStatus(s: String) {
if (++testCount % 80 == 0) {
printStatus("\n")
}
originalSystemErr?.print(s)
}
override fun executionFinished(
@@ -31,14 +44,31 @@ object DotListener: TestExecutionListener {
) {
if (!testIdentifier.isContainer) {
when (testExecutionResult.status!!) {
TestExecutionResult.Status.ABORTED -> System.err.print("E")
TestExecutionResult.Status.FAILED -> System.err.print("F")
TestExecutionResult.Status.SUCCESSFUL -> System.err.print(".")
TestExecutionResult.Status.ABORTED -> printStatus("E")
TestExecutionResult.Status.FAILED -> printStatus("F")
TestExecutionResult.Status.SUCCESSFUL -> printStatus(".")
}
}
}
override fun testPlanExecutionFinished(testPlan: TestPlan) {
System.err.println()
originalSystemErr?.println()
}
fun install() {
originalSystemOut = System.out
originalSystemErr = System.err
System.setOut(object: PrintStream(OutputStream.nullOutputStream()) {})
System.setErr(object: PrintStream(OutputStream.nullOutputStream()) {})
}
fun uninstall() {
originalSystemOut.let {
System.setOut(it)
}
originalSystemErr.let {
System.setErr(it)
}
}
}

View File

@@ -19,6 +19,21 @@ import org.junit.jupiter.engine.descriptor.ClassBasedTestDescriptor
import org.junit.platform.engine.discovery.DiscoverySelectors
import java.io.File
// TODO move to junit5 tags
val avoidedTests = setOf(
"okhttp3.BouncyCastleTest",
"okhttp3.ConscryptTest",
"okhttp3.CorrettoTest",
"okhttp3.OpenJSSETest",
"okhttp3.internal.platform.Jdk8WithJettyBootPlatformTest",
"okhttp3.internal.platform.Jdk9PlatformTest",
"okhttp3.internal.platform.PlatformTest",
"okhttp3.internal.platform.android.AndroidSocketAdapterTest",
"okhttp3.osgi.OsgiTest",
"okhttp3.CookiesTest", // hanging
"okhttp3.WholeOperationTimeoutTest", // hanging
)
/**
* Run periodically to refresh the known set of working tests.
*
@@ -28,6 +43,10 @@ fun main() {
val knownTestFile = File("native-image-tests/src/main/resources/testlist.txt")
val testSelector = DiscoverySelectors.selectPackage("okhttp3")
val testClasses = findTests(listOf(testSelector))
.filter { it.isContainer }.mapNotNull { (it as? ClassBasedTestDescriptor)?.testClass }
knownTestFile.writeText(testClasses.joinToString("\n") { it.name })
.filter { it.isContainer }
.mapNotNull { (it as? ClassBasedTestDescriptor)?.testClass?.name }
.filterNot { it in avoidedTests }
.sorted()
.distinct()
knownTestFile.writeText(testClasses.joinToString("\n"))
}

View File

@@ -30,6 +30,7 @@ import org.junit.platform.launcher.core.LauncherConfig
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder
import org.junit.platform.launcher.core.LauncherFactory
import org.junit.platform.launcher.listeners.SummaryGeneratingListener
import java.io.File
import java.io.PrintWriter
import kotlin.system.exitProcess
@@ -37,10 +38,11 @@ import kotlin.system.exitProcess
* Graal main method to run tests with minimal reflection and automatic settings.
* Uses the test list in native-image-tests/src/main/resources/testlist.txt.
*/
fun main() {
fun main(vararg args: String) {
System.setProperty("junit.jupiter.extensions.autodetection.enabled", "true")
val selectors = testSelectors()
val inputFile = if (args.isNotEmpty()) File(args[0]) else null
val selectors = testSelectors(inputFile)
val summaryListener = SummaryGeneratingListener()
val treeListener = treeListener()
@@ -58,7 +60,13 @@ fun main() {
val request: LauncherDiscoveryRequest = buildRequest(selectors)
launcher.execute(request)
DotListener.install()
try {
launcher.execute(request)
} finally {
DotListener.uninstall()
}
val summary = summaryListener.summary
summary.printTo(PrintWriter(System.out))
@@ -75,17 +83,21 @@ fun buildTestEngine(): TestEngine = JupiterTestEngine()
* Returns a fixed set of test classes from testlist.txt, skipping any not found in the
* current classpath. The IDE runs with less classes to avoid conflicting module ownership.
*/
fun testSelectors(): List<DiscoverySelector> {
fun testSelectors(inputFile: File? = null): List<DiscoverySelector> {
val sampleTestClass = SampleTest::class.java
return sampleTestClass.getResource("/testlist.txt")
.readText()
.lines()
val lines =
inputFile?.readLines() ?: sampleTestClass.getResource("/testlist.txt").readText().lines()
val flatClassnameList = lines
.filter { it.isNotBlank() }
return flatClassnameList
.mapNotNull {
try {
selectClass(Class.forName(it, false, sampleTestClass.classLoader))
} catch (cnfe: ClassNotFoundException) {
// ignored
println("Missing test class: $cnfe")
null
}
}

View File

@@ -25,18 +25,22 @@ class TestRegistration : Feature {
override fun beforeAnalysis(access: Feature.BeforeAnalysisAccess) {
registerKnownTests(access)
val listener = Class.forName("org.junit.platform.console.tasks.TreePrintingListener")
registerJupiterClasses(access)
}
private fun registerJupiterClasses(access: Feature.BeforeAnalysisAccess) {
registerStandardClass(access, "org.junit.jupiter.params.ParameterizedTestExtension")
registerStandardClass(access, "org.junit.platform.console.tasks.TreePrintingListener")
registerStandardClass(access,
"org.junit.jupiter.engine.extension.TimeoutExtension\$ExecutorResource")
}
private fun registerStandardClass(access: Feature.BeforeAnalysisAccess, name: String) {
val listener = access.findClassByName(name)
RuntimeReflection.register(listener)
listener.declaredConstructors.forEach {
RuntimeReflection.register(it)
}
val timeoutResource =
Class.forName("org.junit.jupiter.engine.extension.TimeoutExtension\$ExecutorResource")
RuntimeReflection.register(timeoutResource)
timeoutResource.declaredConstructors.forEach {
RuntimeReflection.register(it)
}
}
private fun registerKnownTests(access: Feature.BeforeAnalysisAccess) {
@@ -47,7 +51,7 @@ class TestRegistration : Feature {
if (testClass != null) {
access.registerAsUsed(testClass)
registerTest(testClass)
registerTest(access, testClass)
}
} catch (e: Exception) {
// If you throw an exception here then native image building fails half way through
@@ -58,7 +62,8 @@ class TestRegistration : Feature {
}
}
private fun registerTest(java: Class<*>) {
private fun registerTest(access: Feature.BeforeAnalysisAccess, java: Class<*>) {
access.registerAsUsed(java)
RuntimeReflection.register(java)
java.constructors.forEach {
RuntimeReflection.register(it)

View File

@@ -1,8 +1,78 @@
okhttp3.sse.internal.EventSourceHttpTest
okhttp3.AddressTest
okhttp3.CacheControlTest
okhttp3.CacheCorruptionTest
okhttp3.CacheTest
okhttp3.CallKotlinTest
okhttp3.CallTest
okhttp3.CertificateChainCleanerTest
okhttp3.CertificatePinnerKotlinTest
okhttp3.CertificatePinnerTest
okhttp3.CipherSuiteTest
okhttp3.ConnectionCoalescingTest
okhttp3.ConnectionReuseTest
okhttp3.ConnectionSpecTest
okhttp3.CookieTest
okhttp3.DispatcherTest
okhttp3.DuplexTest
okhttp3.EventListenerTest
okhttp3.FormBodyTest
okhttp3.HandshakeTest
okhttp3.HeadersKotlinTest
okhttp3.HeadersTest
okhttp3.InsecureForHostTest
okhttp3.InterceptorTest
okhttp3.KotlinDeprecationErrorTest
okhttp3.KotlinSourceModernTest
okhttp3.MultipartBodyTest
okhttp3.MultipartReaderTest
okhttp3.OkHttpClientTest
okhttp3.OkHttpTest
okhttp3.ProtocolTest
okhttp3.PublicInternalApiTest
okhttp3.RequestTest
okhttp3.ResponseBodyTest
okhttp3.ResponseTest
okhttp3.SampleTest
okhttp3.ServerTruncatesRequestTest
okhttp3.SocksProxyTest
okhttp3.URLConnectionTest
okhttp3.brotli.BrotliInterceptorJavaApiTest
okhttp3.brotli.BrotliInterceptorTest
okhttp3.dnsoverhttps.DnsOverHttpsTest
okhttp3.internal.UtilTest
okhttp3.internal.authenticator.JavaNetAuthenticatorTest
okhttp3.internal.cache.DiskLruCacheTest
okhttp3.internal.cache2.FileOperatorTest
okhttp3.internal.cache2.RelayTest
okhttp3.internal.concurrent.TaskLoggerTest
okhttp3.internal.concurrent.TaskRunnerRealBackendTest
okhttp3.internal.concurrent.TaskRunnerTest
okhttp3.internal.connection.ConnectionPoolTest
okhttp3.internal.connection.ConnectionSpecSelectorTest
okhttp3.internal.connection.RouteExceptionTest
okhttp3.internal.connection.RouteSelectorTest
okhttp3.internal.http.CancelTest
okhttp3.internal.http.HttpDateTest
okhttp3.internal.http.StatusLineTest
okhttp3.internal.http.ThreadInterruptTest
okhttp3.internal.http2.FrameLogTest
okhttp3.internal.http2.HpackTest
okhttp3.internal.http2.Http2ConnectionTest
okhttp3.internal.http2.Http2Test
okhttp3.internal.http2.HttpOverHttp2Test
okhttp3.internal.http2.HuffmanTest
okhttp3.internal.io.FileSystemTest
okhttp3.internal.publicsuffix.PublicSuffixDatabaseTest
okhttp3.internal.tls.CertificatePinnerChainValidationTest
okhttp3.internal.tls.ClientAuthTest
okhttp3.internal.tls.HostnameVerifierTest
okhttp3.internal.ws.MessageDeflaterInflaterTest
okhttp3.internal.ws.RealWebSocketTest
okhttp3.internal.ws.WebSocketExtensionsTest
okhttp3.internal.ws.WebSocketHttpTest
okhttp3.internal.ws.WebSocketReaderTest
okhttp3.internal.ws.WebSocketWriterTest
okhttp3.logging.HttpLoggingInterceptorTest
okhttp3.logging.IsProbablyUtf8Test
okhttp3.logging.LoggingEventListenerTest
okhttp3.logging.HttpLoggingInterceptorTest
okhttp3.dnsoverhttps.DnsOverHttpsTest
okhttp3.brotli.BrotliInterceptorJavaApiTest
okhttp3.SampleTest
okhttp3.sse.internal.EventSourceHttpTest

View File

@@ -22,8 +22,8 @@ import java.net.UnknownHostException
import java.util.Arrays
import okhttp3.internal.http2.Header
import okio.Buffer
import org.junit.Assume.assumeFalse
import org.junit.Assume.assumeNoException
import org.junit.jupiter.api.Assumptions.assumeFalse
import org.junit.jupiter.api.Assumptions.assumeTrue
object TestUtil {
@JvmField
@@ -93,13 +93,13 @@ object TestUtil {
try {
InetAddress.getByName("www.google.com")
} catch (uhe: UnknownHostException) {
assumeNoException(uhe)
assumeTrue(false, "requires network")
}
}
@JvmStatic
fun assumeNotWindows() {
assumeFalse("This test fails on Windows.", windows)
assumeFalse(windows, "This test fails on Windows.")
}
@JvmStatic

View File

@@ -0,0 +1,43 @@
/*
* Copyright (C) 2019 Square, Inc.
*
* 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 okhttp3.internal
import okhttp3.Cache
import okhttp3.Dispatcher
import okhttp3.Response
import okhttp3.internal.connection.Exchange
import okhttp3.internal.connection.RealCall
import okhttp3.internal.connection.RealConnection
import okhttp3.internal.io.FileSystem
import java.io.File
fun buildCache(file: File, maxSize: Long, fileSystem: FileSystem): Cache {
return Cache(file, maxSize, fileSystem)
}
var RealConnection.idleAtNsAccessor
get() = idleAtNs
set(value) {
idleAtNs = value
}
val Response.exchange
get() = this.exchange
val Exchange.connection
get() = this.connection
fun Dispatcher.finished(call: RealCall.AsyncCall) = this.finished(call)

View File

@@ -579,7 +579,7 @@ internal fun <E> MutableList<E>.addIfAbsent(element: E) {
}
@JvmField
internal val assertionsEnabled = OkHttpClient::class.java.desiredAssertionStatus()
val assertionsEnabled = OkHttpClient::class.java.desiredAssertionStatus()
/**
* Returns the string "OkHttp" unless the library has been shaded for inclusion in another library,
@@ -592,14 +592,14 @@ internal val okHttpName =
OkHttpClient::class.java.name.removePrefix("okhttp3.").removeSuffix("Client")
@Suppress("NOTHING_TO_INLINE")
internal inline fun Any.assertThreadHoldsLock() {
inline fun Any.assertThreadHoldsLock() {
if (assertionsEnabled && !Thread.holdsLock(this)) {
throw AssertionError("Thread ${Thread.currentThread().name} MUST hold lock on $this")
}
}
@Suppress("NOTHING_TO_INLINE")
internal inline fun Any.assertThreadDoesntHoldLock() {
inline fun Any.assertThreadDoesntHoldLock() {
if (assertionsEnabled && Thread.holdsLock(this)) {
throw AssertionError("Thread ${Thread.currentThread().name} MUST NOT hold lock on $this")
}

View File

@@ -84,7 +84,7 @@ import okio.buffer
* @param valueCount the number of values per cache entry. Must be positive.
* @param maxSize the maximum number of bytes this cache should use to store.
*/
class DiskLruCache internal constructor(
class DiskLruCache(
internal val fileSystem: FileSystem,
/** Returns the directory where this cache stores its data. */

View File

@@ -467,7 +467,7 @@ class RealCall(
internal fun redactedUrl(): String = originalRequest.url.redact()
internal inner class AsyncCall(
inner class AsyncCall(
private val responseCallback: Callback
) : Runnable {
@Volatile var callsPerHost = AtomicInteger(0)

View File

@@ -140,7 +140,7 @@ class RealConnection(
val calls = mutableListOf<Reference<RealCall>>()
/** Timestamp when `allocations.size()` reached zero. Also assigned upon initial connection. */
internal var idleAtNs = Long.MAX_VALUE
var idleAtNs = Long.MAX_VALUE
/**
* Returns true if this is an HTTP/2 connection. Such connections can be used in multiple HTTP
@@ -747,7 +747,7 @@ class RealConnection(
companion object {
private const val NPE_THROW_WITH_NULL = "throw with null exception"
private const val MAX_TUNNEL_ATTEMPTS = 21
internal const val IDLE_CONNECTION_HEALTHY_NS = 10_000_000_000 // 10 seconds.
const val IDLE_CONNECTION_HEALTHY_NS = 10_000_000_000 // 10 seconds.
fun newTestConnection(
connectionPool: RealConnectionPool,

View File

@@ -66,7 +66,7 @@ private val BROWSER_COMPATIBLE_DATE_FORMATS =
arrayOfNulls<DateFormat>(BROWSER_COMPATIBLE_DATE_FORMAT_STRINGS.size)
/** Returns the date for this string, or null if the value couldn't be parsed. */
internal fun String.toHttpDateOrNull(): Date? {
fun String.toHttpDateOrNull(): Date? {
if (isEmpty()) return null
val position = ParsePosition(0)
@@ -103,4 +103,4 @@ internal fun String.toHttpDateOrNull(): Date? {
}
/** Returns the string for this date. */
internal fun Date.toHttpDateString(): String = STANDARD_DATE_FORMAT.get().format(this)
fun Date.toHttpDateString(): String = STANDARD_DATE_FORMAT.get().format(this)

View File

@@ -0,0 +1,5 @@
{
"resources": [
{"pattern": "publicsuffixes.gz"}
]
}

View File

@@ -28,6 +28,7 @@ import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLSession
import mockwebserver3.MockResponse
import mockwebserver3.MockWebServer
import okhttp3.internal.buildCache
import okhttp3.internal.io.InMemoryFileSystem
import okhttp3.testing.PlatformRule
import okhttp3.tls.internal.TlsUtil.localhost
@@ -55,7 +56,7 @@ class CacheCorruptionTest(
platform.assumeNotOpenJSSE()
platform.assumeNotBouncyCastle()
server.protocolNegotiationEnabled = false
cache = Cache(File("/cache/"), Int.MAX_VALUE.toLong(), fileSystem)
cache = buildCache(File("/cache/"), Int.MAX_VALUE.toLong(), fileSystem)
client = clientTestRule.newClientBuilder()
.cache(cache)
.cookieJar(JavaNetCookieJar(cookieManager))

View File

@@ -191,11 +191,9 @@ class CallKotlinTest(
// Capture the connection so that we can later make it stale.
var connection: RealConnection? = null
client = client.newBuilder()
.addNetworkInterceptor(object : Interceptor {
override fun intercept(chain: Interceptor.Chain): Response {
connection = chain.connection() as RealConnection
return chain.proceed(chain.request())
}
.addNetworkInterceptor(Interceptor { chain ->
connection = chain.connection() as RealConnection
chain.proceed(chain.request())
})
.build()

View File

@@ -32,6 +32,7 @@ import mockwebserver3.MockWebServer;
import mockwebserver3.RecordedRequest;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.RegisterExtension;
import static java.net.CookiePolicy.ACCEPT_ORIGINAL_SERVER;
@@ -41,6 +42,7 @@ import static org.assertj.core.data.Offset.offset;
import static org.junit.Assert.fail;
/** Derived from Android's CookiesTest. */
@Timeout(30)
public class CookiesTest {
@RegisterExtension public final OkHttpClientTestRule clientTestRule = new OkHttpClientTestRule();

View File

@@ -31,6 +31,8 @@ import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.RegisterExtension
import org.openjsse.sun.security.ssl.SSLSocketFactoryImpl
import org.openjsse.sun.security.ssl.SSLSocketImpl
import okhttp3.internal.exchange
import okhttp3.internal.connection
class OpenJSSETest(
val server: MockWebServer

View File

@@ -20,6 +20,7 @@ import java.util.concurrent.RejectedExecutionException
import java.util.concurrent.TimeUnit
import okhttp3.internal.connection.RealCall
import org.assertj.core.api.Assertions.assertThat
import okhttp3.internal.finished
internal class RecordingExecutor(
private val dispatcherTest: DispatcherTest

View File

@@ -28,11 +28,13 @@ import okhttp3.testing.Flaky;
import okio.BufferedSink;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.api.extension.RegisterExtension;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.Assert.fail;
@Timeout(30)
public final class WholeOperationTimeoutTest {
/** A large response body. Smaller bodies might successfully read after the socket is closed! */
private static final String BIG_ENOUGH_BODY = TestUtil.repeat('a', 64 * 1024);