Add version interceptor.

This interceptor add version param to request and peeks into response
to parse server version.

Signed-off-by: Yahor Berdnikau <egorr.berd@gmail.com>
This commit is contained in:
Yahor Berdnikau 2017-12-02 19:08:30 +01:00
parent 1c56d6459b
commit c76d25e1ba
3 changed files with 154 additions and 0 deletions

View File

@ -0,0 +1,74 @@
package org.moire.ultrasonic.api.subsonic.interceptors
import okhttp3.Interceptor
import okhttp3.mockwebserver.MockResponse
import org.amshove.kluent.`should contain`
import org.amshove.kluent.`should equal`
import org.junit.Test
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
import org.moire.ultrasonic.api.subsonic.enqueueResponse
import kotlin.LazyThreadSafetyMode.NONE
/**
* Integration test for [VersionInterceptor].
*/
class VersionInterceptorTest : BaseInterceptorTest() {
private val initialProtocolVersion = SubsonicAPIVersions.V1_1_0
private var updatedProtocolVersion = SubsonicAPIVersions.V1_1_0
override val interceptor: Interceptor by lazy(NONE) {
VersionInterceptor(initialProtocolVersion) {
updatedProtocolVersion = it
}
}
@Test
fun `Should add initial protocol version to request`() {
mockWebServerRule.enqueueResponse("ping_ok.json")
val request = createRequest {}
client.newCall(request).execute()
val requestLine = mockWebServerRule.mockWebServer.takeRequest().requestLine
requestLine `should contain` "v=${initialProtocolVersion.restApiVersion}"
}
@Test
fun `Should update version from response`() {
mockWebServerRule.enqueueResponse("ping_ok.json")
client.newCall(createRequest {}).execute()
(interceptor as VersionInterceptor).protocolVersion `should equal` SubsonicAPIVersions.V1_13_0
}
@Test
fun `Should not update version if response json doesn't contain version`() {
mockWebServerRule.enqueueResponse("non_subsonic_response.json")
client.newCall(createRequest {}).execute()
(interceptor as VersionInterceptor).protocolVersion `should equal` initialProtocolVersion
}
@Test
fun `Should not update version on non-json response`() {
mockWebServerRule.mockWebServer.enqueue(MockResponse()
.setBody("asdqwnekjnqwkjen")
.setHeader("Content-Type", "application/octet-stream"))
client.newCall(createRequest {}).execute()
(interceptor as VersionInterceptor).protocolVersion `should equal` initialProtocolVersion
}
@Test
fun `Should notify notifier on version change`() {
mockWebServerRule.enqueueResponse("ping_ok.json")
client.newCall(createRequest {}).execute()
updatedProtocolVersion `should equal` SubsonicAPIVersions.V1_13_0
}
}

View File

@ -0,0 +1,3 @@
{
"none" : "some"
}

View File

@ -0,0 +1,77 @@
package org.moire.ultrasonic.api.subsonic.interceptors
import com.fasterxml.jackson.core.JsonFactory
import com.fasterxml.jackson.core.JsonParseException
import com.fasterxml.jackson.core.JsonToken
import okhttp3.Interceptor
import okhttp3.Interceptor.Chain
import okhttp3.Response
import org.moire.ultrasonic.api.subsonic.SubsonicAPIVersions
import java.io.IOException
private const val DEFAULT_PEEK_BYTE_COUNT = 100L
/**
* Special [Interceptor] that adds client supported version to request and tries to update it
* from server response.
*
* Optionally [notifier] will be invoked on version change.
*
* @author Yahor Berdnikau
*/
internal class VersionInterceptor(
internal var protocolVersion: SubsonicAPIVersions,
private val notifier: (SubsonicAPIVersions) -> Unit = {}) : Interceptor {
private val jsonFactory = JsonFactory()
override fun intercept(chain: Chain): okhttp3.Response {
val originalRequest = chain.request()
val newRequest = originalRequest.newBuilder()
.url(originalRequest
.url()
.newBuilder()
.addQueryParameter("v", protocolVersion.restApiVersion)
.build())
.build()
val response = chain.proceed(newRequest)
if (response.isSuccessful) {
val isJson = response.body()?.contentType()?.subtype()?.equals("json", true) ?: false
if (isJson) {
tryUpdateProtocolVersion(response)
}
}
return response
}
private fun tryUpdateProtocolVersion(response: Response) {
val content = response.peekBody(DEFAULT_PEEK_BYTE_COUNT)
.byteStream().bufferedReader().readText()
try {
val jsonReader = jsonFactory.createParser(content)
jsonReader.nextToken()
if (jsonReader.currentToken == JsonToken.START_OBJECT) {
while (jsonReader.currentName != "version" &&
jsonReader.currentToken != null) {
jsonReader.nextToken()
}
val versionStr = jsonReader.nextTextValue()
if (versionStr != null) {
try {
protocolVersion = SubsonicAPIVersions.fromApiVersion(versionStr)
notifier(protocolVersion)
} catch (e: IllegalArgumentException) {
// no-op
}
}
}
} catch (io: IOException) {
// no-op
} catch (parse: JsonParseException) {
// no-op
}
}
}