Hi all, has anybody of you experience with testin...
# ktor
a
Hi all, has anybody of you experience with testing multipart uploads using the client's
MockEngine
? I want to test my client which is building a
MultiPartFormDataContent
using the
formData
builder (which by the way seems to lack support for appending files?). Now my problem is that the request body in the
MockEngine
is just a
MultiPartFormDataContent
only exposing properties of
OutgoingContent.WriteChannelContent
, which means I can only get the full body with all boundary strings and headers written in it. My current workaround is to more or less split the full body into somehow manageable parts, sadly all methods I could find for parsing
multipart/form-data
in ktor are either
internal
already or marked as deprecated as they will become
internal
in the future. Am I overlooking something or is ktor's api just lacking in this area as of now?
a
You can add
@OptIn(InternalAPI::class)
annotation to get rid of the internal API warning. Here is a complete example of the test:
Copy code
import io.ktor.client.*
import io.ktor.client.engine.mock.*
import io.ktor.client.request.forms.*
import io.ktor.http.*
import io.ktor.http.cio.*
import io.ktor.http.content.*
import io.ktor.util.*
import io.ktor.utils.io.*
import io.ktor.utils.io.core.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.runBlocking
import org.junit.Test
import java.io.File
import kotlin.test.assertEquals

class SomeTest {

    @OptIn(InternalAPI::class)
    @Test
    fun test(): Unit = runBlocking {
        val client = HttpClient(MockEngine) {
            engine {
                addHandler { request ->
                    val body = request.body as OutgoingContent.WriteChannelContent
                    val channel = GlobalScope.writer(<http://Dispatchers.IO|Dispatchers.IO>) { body.writeTo(channel) }.channel
                    val result = CIOMultipartDataBase(Dispatchers.Unconfined, channel, body.contentType.toString(), body.contentLength)
                    val parts = result.readAllParts()

                    val description = parts[0] as PartData.FormItem
                    assertEquals("description", description.name)
                    assertEquals("Ktor logo", description.value)

                    val file = parts[1] as PartData.FileItem
                    assertEquals("image", file.name)
                    assertEquals("wiki.txt", file.originalFileName)
                    assertEquals("", file.provider().readText())

                    respond("")
                }
            }
        }

        client.submitFormWithBinaryData<String>(
            url = "<http://localhost:8080/upload>",
            formData = formData {
                append("description", "Ktor logo")
                append("image", File("files/wiki.txt").readBytes(), Headers.build {
                    append(HttpHeaders.ContentType, "plain/text")
                    append(HttpHeaders.ContentDisposition, "filename=wiki.txt")
                })
            }
        )
    }
}
Also, I've created an issue KTOR-3349 to address this problem.
a
thanks