From 42a7b19b9f7c34faad5c72e48d3340b62ec5fb95 Mon Sep 17 00:00:00 2001 From: slam Date: Wed, 5 Jun 2024 01:11:06 +0800 Subject: [PATCH] test(api): Add unit test for Stream class - Added missing unit tests for the Stream class in the api module to ensure proper functionality and coverage. --- .../anthropic/api/messages/api/Delta.kt | 39 +++++++++++ .../api/messages/api/StreamMessageResponse.kt | 35 ---------- .../common/network/api/MockHttpClient.kt | 1 + .../api/ktor/DefaultHttpRequesterTest.kt | 8 +-- .../common/network/api/ktor/api/StreamTest.kt | 66 +++++++++++++++++++ 5 files changed, 108 insertions(+), 41 deletions(-) create mode 100644 anthropic-client/anthropic-client-core/src/commonMain/kotlin/com/tddworks/anthropic/api/messages/api/Delta.kt create mode 100644 common/src/jvmTest/kotlin/com/tddworks/common/network/api/ktor/api/StreamTest.kt diff --git a/anthropic-client/anthropic-client-core/src/commonMain/kotlin/com/tddworks/anthropic/api/messages/api/Delta.kt b/anthropic-client/anthropic-client-core/src/commonMain/kotlin/com/tddworks/anthropic/api/messages/api/Delta.kt new file mode 100644 index 0000000..ed09861 --- /dev/null +++ b/anthropic-client/anthropic-client-core/src/commonMain/kotlin/com/tddworks/anthropic/api/messages/api/Delta.kt @@ -0,0 +1,39 @@ +package com.tddworks.anthropic.api.messages.api + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +/** + * { + * "stop_reason": "end_turn", + * "stop_sequence": null, + * "usage": { + * "output_tokens": 15 + * } + * } + * or + * { + * "type": "text_delta", + * "text": "!" + * } + */ +@Serializable +data class Delta( + val type: String? = null, + val text: String? = null, + @SerialName("stop_reason") + val stopReason: String? = null, + @SerialName("stop_sequence") + val stopSequence: String? = null, + val usage: Usage? = null, +) { + companion object { + fun dummy() = Delta( + type = "text_delta", + text = "Hello", + stopReason = "end_turn", + stopSequence = null, + usage = Usage(outputTokens = 15) + ) + } +} \ No newline at end of file diff --git a/anthropic-client/anthropic-client-core/src/commonMain/kotlin/com/tddworks/anthropic/api/messages/api/StreamMessageResponse.kt b/anthropic-client/anthropic-client-core/src/commonMain/kotlin/com/tddworks/anthropic/api/messages/api/StreamMessageResponse.kt index afe5bbb..dbe5930 100644 --- a/anthropic-client/anthropic-client-core/src/commonMain/kotlin/com/tddworks/anthropic/api/messages/api/StreamMessageResponse.kt +++ b/anthropic-client/anthropic-client-core/src/commonMain/kotlin/com/tddworks/anthropic/api/messages/api/StreamMessageResponse.kt @@ -59,39 +59,4 @@ data class Ping( override val type: String, ) : StreamMessageResponse -/** - * { - * "stop_reason": "end_turn", - * "stop_sequence": null, - * "usage": { - * "output_tokens": 15 - * } - * } - * or - * { - * "type": "text_delta", - * "text": "!" - * } - */ -@Serializable -data class Delta( - val type: String? = null, - val text: String? = null, - @SerialName("stop_reason") - val stopReason: String? = null, - @SerialName("stop_sequence") - val stopSequence: String? = null, - val usage: Usage? = null, -) { - companion object { - fun dummy() = Delta( - type = "text_delta", - text = "Hello", - stopReason = "end_turn", - stopSequence = null, - usage = Usage(outputTokens = 15) - ) - } -} - diff --git a/common/src/jvmTest/kotlin/com/tddworks/common/network/api/MockHttpClient.kt b/common/src/jvmTest/kotlin/com/tddworks/common/network/api/MockHttpClient.kt index 4b866f6..3533d43 100644 --- a/common/src/jvmTest/kotlin/com/tddworks/common/network/api/MockHttpClient.kt +++ b/common/src/jvmTest/kotlin/com/tddworks/common/network/api/MockHttpClient.kt @@ -8,6 +8,7 @@ import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.* import io.ktor.http.* import io.ktor.serialization.kotlinx.* +import io.ktor.utils.io.* /** * See https://ktor.io/docs/http-client-testing.html#usage diff --git a/common/src/jvmTest/kotlin/com/tddworks/common/network/api/ktor/DefaultHttpRequesterTest.kt b/common/src/jvmTest/kotlin/com/tddworks/common/network/api/ktor/DefaultHttpRequesterTest.kt index ab8c20f..43b8eb1 100644 --- a/common/src/jvmTest/kotlin/com/tddworks/common/network/api/ktor/DefaultHttpRequesterTest.kt +++ b/common/src/jvmTest/kotlin/com/tddworks/common/network/api/ktor/DefaultHttpRequesterTest.kt @@ -7,23 +7,19 @@ import com.tddworks.common.network.api.ktor.api.streamRequest import com.tddworks.common.network.api.ktor.internal.DefaultHttpRequester import com.tddworks.common.network.api.ktor.internal.default import com.tddworks.common.network.api.ktor.internal.exception.* -import com.tddworks.common.network.api.ktor.internal.openAIAPIException import com.tddworks.common.network.api.mockHttpClient import com.tddworks.di.initKoin import io.ktor.client.* -import io.ktor.client.plugins.* import io.ktor.client.request.* -import io.ktor.client.statement.* import io.ktor.http.* import kotlinx.coroutines.runBlocking import kotlinx.coroutines.test.runTest -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Test import org.junit.jupiter.api.assertThrows import org.koin.test.junit5.AutoCloseKoinTest -import org.mockito.kotlin.doReturn -import org.mockito.kotlin.mock import kotlin.time.Duration.Companion.seconds class DefaultHttpRequesterTest : AutoCloseKoinTest() { diff --git a/common/src/jvmTest/kotlin/com/tddworks/common/network/api/ktor/api/StreamTest.kt b/common/src/jvmTest/kotlin/com/tddworks/common/network/api/ktor/api/StreamTest.kt new file mode 100644 index 0000000..2ddfcbe --- /dev/null +++ b/common/src/jvmTest/kotlin/com/tddworks/common/network/api/ktor/api/StreamTest.kt @@ -0,0 +1,66 @@ +package com.tddworks.common.network.api.ktor.api + +import app.cash.turbine.test +import com.tddworks.common.network.api.ktor.StreamResponse +import com.tddworks.common.network.api.ktor.internal.JsonLenient +import io.ktor.client.* +import io.ktor.client.engine.mock.* +import io.ktor.client.request.* +import io.ktor.http.* +import io.ktor.utils.io.* +import kotlinx.coroutines.flow.flow +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.json.Json +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.RegisterExtension +import org.koin.dsl.module +import org.koin.test.junit5.AutoCloseKoinTest +import org.koin.test.junit5.KoinTestExtension +import kotlin.test.assertEquals + +class StreamTest : AutoCloseKoinTest() { + + @JvmField + @RegisterExtension + val koinTestExtension = KoinTestExtension.create { + modules( + module { + single { JsonLenient } + }) + } + + @Test + fun `test streamEventsFrom with stream response`(): Unit = runBlocking { + val channel = ByteChannel(autoFlush = true) + val mockEngine = MockEngine { request -> + when (request.url.toString()) { + "http://example.com/stream" -> + respond( + content = channel, + status = HttpStatusCode.OK + ) + + else -> respond("", HttpStatusCode.NotFound) + } + } + + val client = HttpClient(mockEngine) + + val content = flow { + client.preparePost("http://example.com/stream").execute { + streamEventsFrom(it) + } + } + + channel.writeStringUtf8("Hello world!\n") + channel.writeStringUtf8("data: {\"content\": \"some-content-1\"}\n") + channel.writeStringUtf8("data: {\"content\": \"some-content-2\"}\n") + channel.writeStringUtf8("data: [DONE]\n") + content.test { + assertEquals(StreamResponse("some-content-1"), awaitItem()) + assertEquals(StreamResponse("some-content-2"), awaitItem()) + awaitComplete() + channel.close() + } + } +} \ No newline at end of file