mirror of
https://github.com/square/okhttp.git
synced 2025-11-24 18:41:06 +03:00
Idiomatic Kotlin in MockResponse.kt
This commit is contained in:
@@ -31,7 +31,8 @@ abstract class Dispatcher {
|
|||||||
* request bodies.
|
* request bodies.
|
||||||
*/
|
*/
|
||||||
open fun peek(): MockResponse {
|
open fun peek(): MockResponse {
|
||||||
return MockResponse().setSocketPolicy(SocketPolicy.KEEP_OPEN)
|
val mockResponse = MockResponse()
|
||||||
|
return mockResponse.apply { mockResponse.socketPolicy = SocketPolicy.KEEP_OPEN }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,7 +25,10 @@ import java.util.concurrent.TimeUnit
|
|||||||
|
|
||||||
/** A scripted response to be replayed by the mock web server. */
|
/** A scripted response to be replayed by the mock web server. */
|
||||||
class MockResponse : Cloneable {
|
class MockResponse : Cloneable {
|
||||||
private var status: String = ""
|
/** Returns the HTTP response line, such as "HTTP/1.1 200 OK". */
|
||||||
|
@set:JvmName("status")
|
||||||
|
var status: String = ""
|
||||||
|
|
||||||
private var headers = Headers.Builder()
|
private var headers = Headers.Builder()
|
||||||
private var trailers = Headers.Builder()
|
private var trailers = Headers.Builder()
|
||||||
|
|
||||||
@@ -36,8 +39,16 @@ class MockResponse : Cloneable {
|
|||||||
private var throttlePeriodAmount = 1L
|
private var throttlePeriodAmount = 1L
|
||||||
private var throttlePeriodUnit = TimeUnit.SECONDS
|
private var throttlePeriodUnit = TimeUnit.SECONDS
|
||||||
|
|
||||||
private var socketPolicy = SocketPolicy.KEEP_OPEN
|
@set:JvmName("socketPolicy")
|
||||||
private var http2ErrorCode = -1
|
var socketPolicy = SocketPolicy.KEEP_OPEN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) to be
|
||||||
|
* returned when resetting the stream.
|
||||||
|
* This is only valid with [SocketPolicy.RESET_STREAM_AT_START].
|
||||||
|
*/
|
||||||
|
@set:JvmName("http2ErrorCode")
|
||||||
|
var http2ErrorCode = -1
|
||||||
|
|
||||||
private var bodyDelayAmount = 0L
|
private var bodyDelayAmount = 0L
|
||||||
private var bodyDelayUnit = TimeUnit.MILLISECONDS
|
private var bodyDelayUnit = TimeUnit.MILLISECONDS
|
||||||
@@ -72,9 +83,21 @@ class MockResponse : Cloneable {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the HTTP response line, such as "HTTP/1.1 200 OK". */
|
@JvmName("-deprecated_getStatus")
|
||||||
|
@Deprecated(
|
||||||
|
message = "moved to var",
|
||||||
|
replaceWith = ReplaceWith(expression = "status"),
|
||||||
|
level = DeprecationLevel.WARNING)
|
||||||
fun getStatus(): String = status
|
fun getStatus(): String = status
|
||||||
|
|
||||||
|
@Deprecated(
|
||||||
|
message = "moved to var. Replace setStatus(...) with status(...) to fix Java",
|
||||||
|
replaceWith = ReplaceWith(expression = "apply { this.status = status }"),
|
||||||
|
level = DeprecationLevel.WARNING)
|
||||||
|
fun setStatus(status: String) = apply {
|
||||||
|
this.status = status
|
||||||
|
}
|
||||||
|
|
||||||
fun setResponseCode(code: Int): MockResponse {
|
fun setResponseCode(code: Int): MockResponse {
|
||||||
val reason = when (code) {
|
val reason = when (code) {
|
||||||
in 100..199 -> "Informational"
|
in 100..199 -> "Informational"
|
||||||
@@ -84,11 +107,7 @@ class MockResponse : Cloneable {
|
|||||||
in 500..599 -> "Server Error"
|
in 500..599 -> "Server Error"
|
||||||
else -> "Mock Response"
|
else -> "Mock Response"
|
||||||
}
|
}
|
||||||
return setStatus("HTTP/1.1 $code $reason")
|
return apply { status = "HTTP/1.1 $code $reason" }
|
||||||
}
|
|
||||||
|
|
||||||
fun setStatus(status: String) = apply {
|
|
||||||
this.status = status
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Returns the HTTP headers, such as "Content-Length: 0". */
|
/** Returns the HTTP headers, such as "Content-Length: 0". */
|
||||||
@@ -193,19 +212,32 @@ class MockResponse : Cloneable {
|
|||||||
fun setChunkedBody(body: String, maxChunkSize: Int): MockResponse =
|
fun setChunkedBody(body: String, maxChunkSize: Int): MockResponse =
|
||||||
setChunkedBody(Buffer().writeUtf8(body), maxChunkSize)
|
setChunkedBody(Buffer().writeUtf8(body), maxChunkSize)
|
||||||
|
|
||||||
|
@JvmName("-deprecated_getSocketPolicy")
|
||||||
|
@Deprecated(
|
||||||
|
message = "moved to var",
|
||||||
|
replaceWith = ReplaceWith(expression = "socketPolicy"),
|
||||||
|
level = DeprecationLevel.WARNING)
|
||||||
fun getSocketPolicy() = socketPolicy
|
fun getSocketPolicy() = socketPolicy
|
||||||
|
|
||||||
|
@Deprecated(
|
||||||
|
message = "moved to var. Replace setSocketPolicy(...) with socketPolicy(...) to fix Java",
|
||||||
|
replaceWith = ReplaceWith(expression = "apply { this.socketPolicy = socketPolicy }"),
|
||||||
|
level = DeprecationLevel.WARNING)
|
||||||
fun setSocketPolicy(socketPolicy: SocketPolicy) = apply {
|
fun setSocketPolicy(socketPolicy: SocketPolicy) = apply {
|
||||||
this.socketPolicy = socketPolicy
|
this.socketPolicy = socketPolicy
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@JvmName("-deprecated_getHttp2ErrorCode")
|
||||||
|
@Deprecated(
|
||||||
|
message = "moved to var",
|
||||||
|
replaceWith = ReplaceWith(expression = "http2ErrorCode"),
|
||||||
|
level = DeprecationLevel.WARNING)
|
||||||
fun getHttp2ErrorCode() = http2ErrorCode
|
fun getHttp2ErrorCode() = http2ErrorCode
|
||||||
|
|
||||||
/**
|
@Deprecated(
|
||||||
* Sets the [HTTP/2 error code](https://tools.ietf.org/html/rfc7540#section-7) to be
|
message = "moved to var. Replace setHttp2ErrorCode(...) with http2ErrorCode(...) to fix Java",
|
||||||
* returned when resetting the stream.
|
replaceWith = ReplaceWith(expression = "apply { this.http2ErrorCode = http2ErrorCode }"),
|
||||||
* This is only valid with [SocketPolicy.RESET_STREAM_AT_START].
|
level = DeprecationLevel.WARNING)
|
||||||
*/
|
|
||||||
fun setHttp2ErrorCode(http2ErrorCode: Int) = apply {
|
fun setHttp2ErrorCode(http2ErrorCode: Int) = apply {
|
||||||
this.http2ErrorCode = http2ErrorCode
|
this.http2ErrorCode = http2ErrorCode
|
||||||
}
|
}
|
||||||
@@ -264,7 +296,7 @@ class MockResponse : Cloneable {
|
|||||||
* This will overwrite any previously set status or body.
|
* This will overwrite any previously set status or body.
|
||||||
*/
|
*/
|
||||||
fun withWebSocketUpgrade(listener: WebSocketListener) = apply {
|
fun withWebSocketUpgrade(listener: WebSocketListener) = apply {
|
||||||
setStatus("HTTP/1.1 101 Switching Protocols")
|
status = "HTTP/1.1 101 Switching Protocols"
|
||||||
setHeader("Connection", "Upgrade")
|
setHeader("Connection", "Upgrade")
|
||||||
setHeader("Upgrade", "websocket")
|
setHeader("Upgrade", "websocket")
|
||||||
body = null
|
body = null
|
||||||
|
|||||||
@@ -370,7 +370,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val socketPolicy = dispatcher.peek().getSocketPolicy()
|
val socketPolicy = dispatcher.peek().socketPolicy
|
||||||
if (socketPolicy === DISCONNECT_AT_START) {
|
if (socketPolicy === DISCONNECT_AT_START) {
|
||||||
dispatchBookkeepingRequest(0, socket)
|
dispatchBookkeepingRequest(0, socket)
|
||||||
socket.close()
|
socket.close()
|
||||||
@@ -426,7 +426,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
|
|
||||||
@Throws(Exception::class)
|
@Throws(Exception::class)
|
||||||
fun handle() {
|
fun handle() {
|
||||||
val socketPolicy = dispatcher.peek().getSocketPolicy()
|
val socketPolicy = dispatcher.peek().socketPolicy
|
||||||
var protocol = Protocol.HTTP_1_1
|
var protocol = Protocol.HTTP_1_1
|
||||||
val socket: Socket
|
val socket: Socket
|
||||||
when {
|
when {
|
||||||
@@ -513,7 +513,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
val source = raw.source().buffer()
|
val source = raw.source().buffer()
|
||||||
val sink = raw.sink().buffer()
|
val sink = raw.sink().buffer()
|
||||||
while (true) {
|
while (true) {
|
||||||
val socketPolicy = dispatcher.peek().getSocketPolicy()
|
val socketPolicy = dispatcher.peek().socketPolicy
|
||||||
check(processOneRequest(raw, source, sink)) { "Tunnel without any CONNECT!" }
|
check(processOneRequest(raw, source, sink)) { "Tunnel without any CONNECT!" }
|
||||||
if (socketPolicy === UPGRADE_TO_SSL_AT_END) return
|
if (socketPolicy === UPGRADE_TO_SSL_AT_END) return
|
||||||
}
|
}
|
||||||
@@ -535,11 +535,11 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
requestQueue.add(request)
|
requestQueue.add(request)
|
||||||
|
|
||||||
val response = dispatcher.dispatch(request)
|
val response = dispatcher.dispatch(request)
|
||||||
if (response.getSocketPolicy() === DISCONNECT_AFTER_REQUEST) {
|
if (response.socketPolicy === DISCONNECT_AFTER_REQUEST) {
|
||||||
socket.close()
|
socket.close()
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if (response.getSocketPolicy() === NO_RESPONSE) {
|
if (response.socketPolicy === NO_RESPONSE) {
|
||||||
// This read should block until the socket is closed. (Because nobody is writing.)
|
// This read should block until the socket is closed. (Because nobody is writing.)
|
||||||
if (source.exhausted()) return false
|
if (source.exhausted()) return false
|
||||||
throw ProtocolException("unexpected data")
|
throw ProtocolException("unexpected data")
|
||||||
@@ -563,7 +563,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// See warnings associated with these socket policies in SocketPolicy.
|
// See warnings associated with these socket policies in SocketPolicy.
|
||||||
when (response.getSocketPolicy()) {
|
when (response.socketPolicy) {
|
||||||
DISCONNECT_AT_END -> {
|
DISCONNECT_AT_END -> {
|
||||||
socket.close()
|
socket.close()
|
||||||
return false
|
return false
|
||||||
@@ -644,7 +644,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val socketPolicy = dispatcher.peek().getSocketPolicy()
|
val socketPolicy = dispatcher.peek().socketPolicy
|
||||||
if (expectContinue && socketPolicy === EXPECT_CONTINUE || socketPolicy === CONTINUE_ALWAYS) {
|
if (expectContinue && socketPolicy === EXPECT_CONTINUE || socketPolicy === CONTINUE_ALWAYS) {
|
||||||
sink.writeUtf8("HTTP/1.1 100 Continue\r\n")
|
sink.writeUtf8("HTTP/1.1 100 Continue\r\n")
|
||||||
sink.writeUtf8("Content-Length: 0\r\n")
|
sink.writeUtf8("Content-Length: 0\r\n")
|
||||||
@@ -703,7 +703,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
.url("$scheme://$authority/")
|
.url("$scheme://$authority/")
|
||||||
.headers(request.headers)
|
.headers(request.headers)
|
||||||
.build()
|
.build()
|
||||||
val statusParts = response.getStatus().split(' ', limit = 3)
|
val statusParts = response.status.split(' ', limit = 3)
|
||||||
val fancyResponse = Response.Builder()
|
val fancyResponse = Response.Builder()
|
||||||
.code(Integer.parseInt(statusParts[1]))
|
.code(Integer.parseInt(statusParts[1]))
|
||||||
.message(statusParts[2])
|
.message(statusParts[2])
|
||||||
@@ -735,7 +735,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
private fun writeHttpResponse(socket: Socket, sink: BufferedSink, response: MockResponse) {
|
private fun writeHttpResponse(socket: Socket, sink: BufferedSink, response: MockResponse) {
|
||||||
sleepIfDelayed(response.getHeadersDelay(TimeUnit.MILLISECONDS))
|
sleepIfDelayed(response.getHeadersDelay(TimeUnit.MILLISECONDS))
|
||||||
sink.writeUtf8(response.getStatus())
|
sink.writeUtf8(response.status)
|
||||||
sink.writeUtf8("\r\n")
|
sink.writeUtf8("\r\n")
|
||||||
|
|
||||||
writeHeaders(sink, response.getHeaders())
|
writeHeaders(sink, response.getHeaders())
|
||||||
@@ -789,9 +789,9 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
|
|
||||||
val halfByteCount = byteCountNum / 2
|
val halfByteCount = byteCountNum / 2
|
||||||
val disconnectHalfway = if (isRequest) {
|
val disconnectHalfway = if (isRequest) {
|
||||||
policy.getSocketPolicy() === DISCONNECT_DURING_REQUEST_BODY
|
policy.socketPolicy === DISCONNECT_DURING_REQUEST_BODY
|
||||||
} else {
|
} else {
|
||||||
policy.getSocketPolicy() === DISCONNECT_DURING_RESPONSE_BODY
|
policy.socketPolicy === DISCONNECT_DURING_RESPONSE_BODY
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!socket.isClosed) {
|
while (!socket.isClosed) {
|
||||||
@@ -879,9 +879,9 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
@Throws(IOException::class)
|
@Throws(IOException::class)
|
||||||
override fun onStream(stream: Http2Stream) {
|
override fun onStream(stream: Http2Stream) {
|
||||||
val peekedResponse = dispatcher.peek()
|
val peekedResponse = dispatcher.peek()
|
||||||
if (peekedResponse.getSocketPolicy() === RESET_STREAM_AT_START) {
|
if (peekedResponse.socketPolicy === RESET_STREAM_AT_START) {
|
||||||
dispatchBookkeepingRequest(sequenceNumber.getAndIncrement(), socket)
|
dispatchBookkeepingRequest(sequenceNumber.getAndIncrement(), socket)
|
||||||
stream.close(ErrorCode.fromHttp2(peekedResponse.getHttp2ErrorCode())!!, null)
|
stream.close(ErrorCode.fromHttp2(peekedResponse.http2ErrorCode)!!, null)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -891,7 +891,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
|
|
||||||
val response: MockResponse = dispatcher.dispatch(request)
|
val response: MockResponse = dispatcher.dispatch(request)
|
||||||
|
|
||||||
if (response.getSocketPolicy() === DISCONNECT_AFTER_REQUEST) {
|
if (response.socketPolicy === DISCONNECT_AFTER_REQUEST) {
|
||||||
socket.close()
|
socket.close()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -902,7 +902,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
"and responded: $response protocol is $protocol")
|
"and responded: $response protocol is $protocol")
|
||||||
}
|
}
|
||||||
|
|
||||||
if (response.getSocketPolicy() === DISCONNECT_AT_END) {
|
if (response.socketPolicy === DISCONNECT_AT_END) {
|
||||||
val connection = stream.connection
|
val connection = stream.connection
|
||||||
connection.shutdown(ErrorCode.NO_ERROR)
|
connection.shutdown(ErrorCode.NO_ERROR)
|
||||||
}
|
}
|
||||||
@@ -933,7 +933,7 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
val headers = httpHeaders.build()
|
val headers = httpHeaders.build()
|
||||||
|
|
||||||
val peek = dispatcher.peek()
|
val peek = dispatcher.peek()
|
||||||
if (!readBody && peek.getSocketPolicy() === EXPECT_CONTINUE) {
|
if (!readBody && peek.socketPolicy === EXPECT_CONTINUE) {
|
||||||
val continueHeaders =
|
val continueHeaders =
|
||||||
listOf(Header(Header.RESPONSE_STATUS, "100 Continue".encodeUtf8()))
|
listOf(Header(Header.RESPONSE_STATUS, "100 Continue".encodeUtf8()))
|
||||||
stream.writeHeaders(continueHeaders, outFinished = false, flushHeaders = true)
|
stream.writeHeaders(continueHeaders, outFinished = false, flushHeaders = true)
|
||||||
@@ -964,13 +964,14 @@ class MockWebServer : ExternalResource(), Closeable {
|
|||||||
val settings = response.settings
|
val settings = response.settings
|
||||||
stream.connection.setSettings(settings)
|
stream.connection.setSettings(settings)
|
||||||
|
|
||||||
if (response.getSocketPolicy() === NO_RESPONSE) {
|
if (response.socketPolicy === NO_RESPONSE) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
val http2Headers = mutableListOf<Header>()
|
val http2Headers = mutableListOf<Header>()
|
||||||
val statusParts = response.getStatus().split(' ', limit = 3)
|
val statusParts = response.status.split(' ', limit = 3)
|
||||||
|
|
||||||
if (statusParts.size < 2) {
|
if (statusParts.size < 2) {
|
||||||
throw AssertionError("Unexpected status: ${response.getStatus()}")
|
throw AssertionError("Unexpected status: ${response.status}")
|
||||||
}
|
}
|
||||||
// TODO: constants for well-known header names.
|
// TODO: constants for well-known header names.
|
||||||
http2Headers.add(Header(Header.RESPONSE_STATUS, statusParts[1]))
|
http2Headers.add(Header(Header.RESPONSE_STATUS, statusParts[1]))
|
||||||
|
|||||||
@@ -81,8 +81,10 @@ open class QueueDispatcher : Dispatcher() {
|
|||||||
* Enqueued on shutdown to release threads waiting on [dispatch]. Note that this response
|
* Enqueued on shutdown to release threads waiting on [dispatch]. Note that this response
|
||||||
* isn't transmitted because the connection is closed before this response is returned.
|
* isn't transmitted because the connection is closed before this response is returned.
|
||||||
*/
|
*/
|
||||||
private val DEAD_LETTER = MockResponse()
|
private val DEAD_LETTER = run {
|
||||||
.setStatus("HTTP/1.1 $HTTP_UNAVAILABLE shutting down")
|
val mockResponse = MockResponse()
|
||||||
|
mockResponse.apply { mockResponse.status = "HTTP/1.1 $HTTP_UNAVAILABLE shutting down" }
|
||||||
|
}
|
||||||
|
|
||||||
private val logger = Logger.getLogger(QueueDispatcher::class.java.name)
|
private val logger = Logger.getLogger(QueueDispatcher::class.java.name)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -682,10 +682,10 @@ class KotlinSourceModernTest {
|
|||||||
@Test @Ignore
|
@Test @Ignore
|
||||||
fun mockResponse() {
|
fun mockResponse() {
|
||||||
var mockResponse: MockResponse = MockResponse()
|
var mockResponse: MockResponse = MockResponse()
|
||||||
var status: String = mockResponse.getStatus()
|
var status: String = mockResponse.status
|
||||||
status = mockResponse.getStatus()
|
status = mockResponse.status
|
||||||
mockResponse = mockResponse.setStatus("")
|
mockResponse = mockResponse.apply { mockResponse.status = "" }
|
||||||
mockResponse.setStatus("")
|
mockResponse.status = ""
|
||||||
mockResponse = mockResponse.setResponseCode(0)
|
mockResponse = mockResponse.setResponseCode(0)
|
||||||
var headers: Headers = mockResponse.getHeaders()
|
var headers: Headers = mockResponse.getHeaders()
|
||||||
headers = mockResponse.getHeaders()
|
headers = mockResponse.getHeaders()
|
||||||
@@ -705,13 +705,14 @@ class KotlinSourceModernTest {
|
|||||||
mockResponse.setBody(Buffer())
|
mockResponse.setBody(Buffer())
|
||||||
mockResponse = mockResponse.setChunkedBody(Buffer(), 0)
|
mockResponse = mockResponse.setChunkedBody(Buffer(), 0)
|
||||||
mockResponse = mockResponse.setChunkedBody("", 0)
|
mockResponse = mockResponse.setChunkedBody("", 0)
|
||||||
var socketPolicy: SocketPolicy = mockResponse.getSocketPolicy()
|
var socketPolicy: SocketPolicy = mockResponse.socketPolicy
|
||||||
socketPolicy = mockResponse.getSocketPolicy()
|
socketPolicy = mockResponse.socketPolicy
|
||||||
mockResponse = mockResponse.setSocketPolicy(SocketPolicy.KEEP_OPEN)
|
mockResponse = mockResponse.apply { mockResponse.socketPolicy = SocketPolicy.KEEP_OPEN }
|
||||||
var http2ErrorCode: Int = mockResponse.getHttp2ErrorCode()
|
mockResponse.socketPolicy = SocketPolicy.KEEP_OPEN
|
||||||
http2ErrorCode = mockResponse.getHttp2ErrorCode()
|
var http2ErrorCode: Int = mockResponse.http2ErrorCode
|
||||||
mockResponse = mockResponse.setHttp2ErrorCode(0)
|
http2ErrorCode = mockResponse.http2ErrorCode
|
||||||
mockResponse.setHttp2ErrorCode(0)
|
mockResponse = mockResponse.apply { mockResponse.http2ErrorCode = 0 }
|
||||||
|
mockResponse.http2ErrorCode = 0
|
||||||
mockResponse = mockResponse.throttleBody(0L, 0L, TimeUnit.SECONDS)
|
mockResponse = mockResponse.throttleBody(0L, 0L, TimeUnit.SECONDS)
|
||||||
var throttleBytesPerPeriod: Long = mockResponse.throttleBytesPerPeriod
|
var throttleBytesPerPeriod: Long = mockResponse.throttleBytesPerPeriod
|
||||||
throttleBytesPerPeriod = mockResponse.throttleBytesPerPeriod
|
throttleBytesPerPeriod = mockResponse.throttleBytesPerPeriod
|
||||||
|
|||||||
Reference in New Issue
Block a user