1
0
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:
Masaru Nomura
2019-05-30 02:04:18 -04:00
parent 4258c913b3
commit 1294e11fc5
5 changed files with 85 additions and 48 deletions

View File

@@ -31,7 +31,8 @@ abstract class Dispatcher {
* request bodies.
*/
open fun peek(): MockResponse {
return MockResponse().setSocketPolicy(SocketPolicy.KEEP_OPEN)
val mockResponse = MockResponse()
return mockResponse.apply { mockResponse.socketPolicy = SocketPolicy.KEEP_OPEN }
}
/**

View File

@@ -25,7 +25,10 @@ import java.util.concurrent.TimeUnit
/** A scripted response to be replayed by the mock web server. */
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 trailers = Headers.Builder()
@@ -36,8 +39,16 @@ class MockResponse : Cloneable {
private var throttlePeriodAmount = 1L
private var throttlePeriodUnit = TimeUnit.SECONDS
private var socketPolicy = SocketPolicy.KEEP_OPEN
private var http2ErrorCode = -1
@set:JvmName("socketPolicy")
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 bodyDelayUnit = TimeUnit.MILLISECONDS
@@ -72,9 +83,21 @@ class MockResponse : Cloneable {
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
@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 {
val reason = when (code) {
in 100..199 -> "Informational"
@@ -84,11 +107,7 @@ class MockResponse : Cloneable {
in 500..599 -> "Server Error"
else -> "Mock Response"
}
return setStatus("HTTP/1.1 $code $reason")
}
fun setStatus(status: String) = apply {
this.status = status
return apply { status = "HTTP/1.1 $code $reason" }
}
/** Returns the HTTP headers, such as "Content-Length: 0". */
@@ -193,19 +212,32 @@ class MockResponse : Cloneable {
fun setChunkedBody(body: String, maxChunkSize: Int): MockResponse =
setChunkedBody(Buffer().writeUtf8(body), maxChunkSize)
@JvmName("-deprecated_getSocketPolicy")
@Deprecated(
message = "moved to var",
replaceWith = ReplaceWith(expression = "socketPolicy"),
level = DeprecationLevel.WARNING)
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 {
this.socketPolicy = socketPolicy
}
@JvmName("-deprecated_getHttp2ErrorCode")
@Deprecated(
message = "moved to var",
replaceWith = ReplaceWith(expression = "http2ErrorCode"),
level = DeprecationLevel.WARNING)
fun getHttp2ErrorCode() = http2ErrorCode
/**
* 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].
*/
@Deprecated(
message = "moved to var. Replace setHttp2ErrorCode(...) with http2ErrorCode(...) to fix Java",
replaceWith = ReplaceWith(expression = "apply { this.http2ErrorCode = http2ErrorCode }"),
level = DeprecationLevel.WARNING)
fun setHttp2ErrorCode(http2ErrorCode: Int) = apply {
this.http2ErrorCode = http2ErrorCode
}
@@ -264,7 +296,7 @@ class MockResponse : Cloneable {
* This will overwrite any previously set status or body.
*/
fun withWebSocketUpgrade(listener: WebSocketListener) = apply {
setStatus("HTTP/1.1 101 Switching Protocols")
status = "HTTP/1.1 101 Switching Protocols"
setHeader("Connection", "Upgrade")
setHeader("Upgrade", "websocket")
body = null

View File

@@ -370,7 +370,7 @@ class MockWebServer : ExternalResource(), Closeable {
return
}
val socketPolicy = dispatcher.peek().getSocketPolicy()
val socketPolicy = dispatcher.peek().socketPolicy
if (socketPolicy === DISCONNECT_AT_START) {
dispatchBookkeepingRequest(0, socket)
socket.close()
@@ -426,7 +426,7 @@ class MockWebServer : ExternalResource(), Closeable {
@Throws(Exception::class)
fun handle() {
val socketPolicy = dispatcher.peek().getSocketPolicy()
val socketPolicy = dispatcher.peek().socketPolicy
var protocol = Protocol.HTTP_1_1
val socket: Socket
when {
@@ -513,7 +513,7 @@ class MockWebServer : ExternalResource(), Closeable {
val source = raw.source().buffer()
val sink = raw.sink().buffer()
while (true) {
val socketPolicy = dispatcher.peek().getSocketPolicy()
val socketPolicy = dispatcher.peek().socketPolicy
check(processOneRequest(raw, source, sink)) { "Tunnel without any CONNECT!" }
if (socketPolicy === UPGRADE_TO_SSL_AT_END) return
}
@@ -535,11 +535,11 @@ class MockWebServer : ExternalResource(), Closeable {
requestQueue.add(request)
val response = dispatcher.dispatch(request)
if (response.getSocketPolicy() === DISCONNECT_AFTER_REQUEST) {
if (response.socketPolicy === DISCONNECT_AFTER_REQUEST) {
socket.close()
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.)
if (source.exhausted()) return false
throw ProtocolException("unexpected data")
@@ -563,7 +563,7 @@ class MockWebServer : ExternalResource(), Closeable {
}
// See warnings associated with these socket policies in SocketPolicy.
when (response.getSocketPolicy()) {
when (response.socketPolicy) {
DISCONNECT_AT_END -> {
socket.close()
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) {
sink.writeUtf8("HTTP/1.1 100 Continue\r\n")
sink.writeUtf8("Content-Length: 0\r\n")
@@ -703,7 +703,7 @@ class MockWebServer : ExternalResource(), Closeable {
.url("$scheme://$authority/")
.headers(request.headers)
.build()
val statusParts = response.getStatus().split(' ', limit = 3)
val statusParts = response.status.split(' ', limit = 3)
val fancyResponse = Response.Builder()
.code(Integer.parseInt(statusParts[1]))
.message(statusParts[2])
@@ -735,7 +735,7 @@ class MockWebServer : ExternalResource(), Closeable {
@Throws(IOException::class)
private fun writeHttpResponse(socket: Socket, sink: BufferedSink, response: MockResponse) {
sleepIfDelayed(response.getHeadersDelay(TimeUnit.MILLISECONDS))
sink.writeUtf8(response.getStatus())
sink.writeUtf8(response.status)
sink.writeUtf8("\r\n")
writeHeaders(sink, response.getHeaders())
@@ -789,9 +789,9 @@ class MockWebServer : ExternalResource(), Closeable {
val halfByteCount = byteCountNum / 2
val disconnectHalfway = if (isRequest) {
policy.getSocketPolicy() === DISCONNECT_DURING_REQUEST_BODY
policy.socketPolicy === DISCONNECT_DURING_REQUEST_BODY
} else {
policy.getSocketPolicy() === DISCONNECT_DURING_RESPONSE_BODY
policy.socketPolicy === DISCONNECT_DURING_RESPONSE_BODY
}
while (!socket.isClosed) {
@@ -879,9 +879,9 @@ class MockWebServer : ExternalResource(), Closeable {
@Throws(IOException::class)
override fun onStream(stream: Http2Stream) {
val peekedResponse = dispatcher.peek()
if (peekedResponse.getSocketPolicy() === RESET_STREAM_AT_START) {
if (peekedResponse.socketPolicy === RESET_STREAM_AT_START) {
dispatchBookkeepingRequest(sequenceNumber.getAndIncrement(), socket)
stream.close(ErrorCode.fromHttp2(peekedResponse.getHttp2ErrorCode())!!, null)
stream.close(ErrorCode.fromHttp2(peekedResponse.http2ErrorCode)!!, null)
return
}
@@ -891,7 +891,7 @@ class MockWebServer : ExternalResource(), Closeable {
val response: MockResponse = dispatcher.dispatch(request)
if (response.getSocketPolicy() === DISCONNECT_AFTER_REQUEST) {
if (response.socketPolicy === DISCONNECT_AFTER_REQUEST) {
socket.close()
return
}
@@ -902,7 +902,7 @@ class MockWebServer : ExternalResource(), Closeable {
"and responded: $response protocol is $protocol")
}
if (response.getSocketPolicy() === DISCONNECT_AT_END) {
if (response.socketPolicy === DISCONNECT_AT_END) {
val connection = stream.connection
connection.shutdown(ErrorCode.NO_ERROR)
}
@@ -933,7 +933,7 @@ class MockWebServer : ExternalResource(), Closeable {
val headers = httpHeaders.build()
val peek = dispatcher.peek()
if (!readBody && peek.getSocketPolicy() === EXPECT_CONTINUE) {
if (!readBody && peek.socketPolicy === EXPECT_CONTINUE) {
val continueHeaders =
listOf(Header(Header.RESPONSE_STATUS, "100 Continue".encodeUtf8()))
stream.writeHeaders(continueHeaders, outFinished = false, flushHeaders = true)
@@ -964,13 +964,14 @@ class MockWebServer : ExternalResource(), Closeable {
val settings = response.settings
stream.connection.setSettings(settings)
if (response.getSocketPolicy() === NO_RESPONSE) {
if (response.socketPolicy === NO_RESPONSE) {
return
}
val http2Headers = mutableListOf<Header>()
val statusParts = response.getStatus().split(' ', limit = 3)
val statusParts = response.status.split(' ', limit = 3)
if (statusParts.size < 2) {
throw AssertionError("Unexpected status: ${response.getStatus()}")
throw AssertionError("Unexpected status: ${response.status}")
}
// TODO: constants for well-known header names.
http2Headers.add(Header(Header.RESPONSE_STATUS, statusParts[1]))

View File

@@ -81,8 +81,10 @@ open class QueueDispatcher : Dispatcher() {
* 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.
*/
private val DEAD_LETTER = MockResponse()
.setStatus("HTTP/1.1 $HTTP_UNAVAILABLE shutting down")
private val DEAD_LETTER = run {
val mockResponse = MockResponse()
mockResponse.apply { mockResponse.status = "HTTP/1.1 $HTTP_UNAVAILABLE shutting down" }
}
private val logger = Logger.getLogger(QueueDispatcher::class.java.name)
}

View File

@@ -682,10 +682,10 @@ class KotlinSourceModernTest {
@Test @Ignore
fun mockResponse() {
var mockResponse: MockResponse = MockResponse()
var status: String = mockResponse.getStatus()
status = mockResponse.getStatus()
mockResponse = mockResponse.setStatus("")
mockResponse.setStatus("")
var status: String = mockResponse.status
status = mockResponse.status
mockResponse = mockResponse.apply { mockResponse.status = "" }
mockResponse.status = ""
mockResponse = mockResponse.setResponseCode(0)
var headers: Headers = mockResponse.getHeaders()
headers = mockResponse.getHeaders()
@@ -705,13 +705,14 @@ class KotlinSourceModernTest {
mockResponse.setBody(Buffer())
mockResponse = mockResponse.setChunkedBody(Buffer(), 0)
mockResponse = mockResponse.setChunkedBody("", 0)
var socketPolicy: SocketPolicy = mockResponse.getSocketPolicy()
socketPolicy = mockResponse.getSocketPolicy()
mockResponse = mockResponse.setSocketPolicy(SocketPolicy.KEEP_OPEN)
var http2ErrorCode: Int = mockResponse.getHttp2ErrorCode()
http2ErrorCode = mockResponse.getHttp2ErrorCode()
mockResponse = mockResponse.setHttp2ErrorCode(0)
mockResponse.setHttp2ErrorCode(0)
var socketPolicy: SocketPolicy = mockResponse.socketPolicy
socketPolicy = mockResponse.socketPolicy
mockResponse = mockResponse.apply { mockResponse.socketPolicy = SocketPolicy.KEEP_OPEN }
mockResponse.socketPolicy = SocketPolicy.KEEP_OPEN
var http2ErrorCode: Int = mockResponse.http2ErrorCode
http2ErrorCode = mockResponse.http2ErrorCode
mockResponse = mockResponse.apply { mockResponse.http2ErrorCode = 0 }
mockResponse.http2ErrorCode = 0
mockResponse = mockResponse.throttleBody(0L, 0L, TimeUnit.SECONDS)
var throttleBytesPerPeriod: Long = mockResponse.throttleBytesPerPeriod
throttleBytesPerPeriod = mockResponse.throttleBytesPerPeriod