Kotlin multiplatform: JobCancellationException: Parent job is Completed

Viewed 1476

I try to write a kotlin multiplatform library (android and ios) that uses ktor. Thereby I experience some issues with kotlins coroutines:

When writing tests I always get kotlinx.coroutines.JobCancellationException: Parent job is Completed; job=JobImpl{Completed}@... exception.

I use ktors mock engine for my tests:

client = HttpClient(MockEngine) 
{
    engine 
    {
         addHandler 
         { request ->
             // Create response object
         }
     }
}

A sample method (commonMain module) using ktor. All methods in my library are written in a similar way. The exception occures if client.get is called.

suspend fun getData(): Either<Exception, String> = coroutineScope 
{
     // Exception occurs in this line:
     val response: HttpResponse = client.get { url("https://www.google.com") }

     return if (response.status == HttpStatusCode.OK) 
     {
         (response.readText() as T).right()
     } 
     else 
     {
        Exception("Error").left()
     }
}

A sample unit test (commonTest module) for the above method. The assertTrue statement is never called since the exception is thrown before.

@Test
fun getDataTest() = runTest 
{
    val result = getData()
    assertTrue(result.isRight())
}

Actual implementation of runTest in androidTest and iosTest modules.

actual fun<T> runTest(block: suspend () -> T) { runBlocking { block() } }

I thought when I use coroutineScope, it waits until all child coroutines are done. What am I doing wrong and how can I fix this exception?

3 Answers

you can't cache HttpClient of CIO in client variable and reuse, It would be best if change the following code in your implementation.

val client:HttpClient get() = HttpClient(MockEngine) {
    engine {
         addHandler { request ->
             // Create response object
         }
     }
}

The problem is that you cannot use the same instance of the HttpClient. My ej:

HttpClient(CIO) {
                install(JsonFeature) {
                    serializer = GsonSerializer()
                }
            }.use { client ->
                return@use client.request("URL") {
                    method = HttpMethod.Get
                }
            }
Related