I’m writing some unit tests for a class with a dep...
# multiplatform
m
I’m writing some unit tests for a class with a dependency for
Ktor
HttpClient
. Tests work just fine on Android, but on iOS getting:
kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlinx.coroutines.test.TestScopeImpl@338a688
I pretty much copy+pasted the ktor test sample. Source in comments. Any tips would be welcome 👍
👀 1
Failing test:
Copy code
class ApiClient(engine: HttpClientEngine) {
    private val httpClient = HttpClient(engine)

    suspend fun getIp(): String = httpClient.get("<https://api.ipify.org/?format=json>")
}

class ApiClientTest {
    @Test
    fun sampleClientTest() = runTest {
        val mockEngine = MockEngine { request ->
            respond(
                content = ByteReadChannel("""{"ip":"127.0.0.1"}"""),
                status = HttpStatusCode.OK,
                headers = headersOf(HttpHeaders.ContentType, "application/json")
            )
        }
        val apiClient2 = ApiClient(mockEngine)

        assertTrue(apiClient2.getIp().contains("127.0.0.1"))
    }
}
Source: https://github.com/ktorio/ktor-documentation/blob/main/codeSnippets/snippets/client-testing-mock/src/test/kotlin/ApplicationTest.kt Stacktrace:
Copy code
kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlinx.coroutines.test.TestScopeImpl@b4a041f8
kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlinx.coroutines.test.TestScopeImpl@b4a041f8
	at kotlin.Throwable#<init>(/Users/teamcity1/teamcity_work/6326934d18cfe24e/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Throwable.kt:24)
	at kotlin.Exception#<init>(/Users/teamcity1/teamcity_work/6326934d18cfe24e/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:23)
	at kotlin.RuntimeException#<init>(/Users/teamcity1/teamcity_work/6326934d18cfe24e/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/Exceptions.kt:34)
	at kotlin.native.concurrent.InvalidMutabilityException#<init>(/Users/teamcity1/teamcity_work/6326934d18cfe24e/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Freezing.kt:24)
	at <global>.ThrowInvalidMutabilityException(/Users/teamcity1/teamcity_work/6326934d18cfe24e/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/native/concurrent/Internal.kt:109)
	at <global>.MutationCheck(Unknown Source)
	at kotlinx.coroutines.test.TestScopeImpl.<set-finished>#internal(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestScope.kt:169)
	at kotlinx.coroutines.test.TestScopeImpl#leave(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestScope.kt:195)
	at kotlinx.coroutines.test.runTest$<anonymous>_3$<anonymous>_4#internal(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestBuilders.kt:167)
	at kotlinx.coroutines.test.$runTest$<anonymous>_3$<anonymous>_4$FUNCTION_REFERENCE$2.invoke#internal(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestBuilders.kt:167)
	at kotlinx.coroutines.test.$runTestCoroutineCOROUTINE$0#invokeSuspend(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestBuilders.kt:233)
	at kotlinx.coroutines.test#runTestCoroutine(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestBuilders.kt:198)
	at kotlinx.coroutines.test.$runTest$<anonymous>_3COROUTINE$1.invokeSuspend#internal(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestBuilders.kt:167)
	at kotlinx.coroutines.test.$runTest$<anonymous>_3COROUTINE$1.invoke#internal(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestBuilders.kt:166)
	at kotlinx.coroutines.test.$createTestResult$lambda-0COROUTINE$6.invokeSuspend#internal(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/native/src/TestBuilders.kt:13)
	at kotlin.coroutines.native.internal.BaseContinuationImpl#resumeWith(/Users/teamcity1/teamcity_work/6326934d18cfe24e/kotlin/kotlin-native/runtime/src/main/kotlin/kotlin/coroutines/ContinuationImpl.kt:30)
	at kotlinx.coroutines.DispatchedTask#run(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/native/src/Debug.kt:17)
	at kotlinx.coroutines.EventLoopImplBase#processNextEvent(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/common/src/EventLoop.common.kt:281)
	at kotlinx.coroutines#runEventLoop(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/native/src/Builders.kt:87)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking#internal(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/native/src/Builders.kt:74)
	at kotlinx.coroutines#runBlocking(/Users/teamcity1/teamcity_work/6326934d18cfe24e/kotlin/libraries/stdlib/src/kotlin/contracts/ContractBuilder.kt:56)
	at kotlinx.coroutines#runBlocking$default(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-core/native/src/Builders.kt:35)
	at kotlinx.coroutines.test#createTestResult(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/native/src/TestBuilders.kt:12)
	at kotlinx.coroutines.test#runTest__at__kotlinx.coroutines.test.TestScope(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestBuilders.kt:166)
	at kotlinx.coroutines.test#runTest(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestBuilders.kt:154)
	at kotlinx.coroutines.test#runTest$default(/opt/buildAgent/work/44ec6e850d5c63f0/kotlinx-coroutines-test/common/src/TestBuilders.kt:147)
Some versions: • ktor & ktor-client-mock:
1.6.3
• coroutines-test:
1.6.0
• kotlin version:
1.6.10
Looks like this could be the same issue: https://youtrack.jetbrains.com/issue/KTOR-3612 Any workarounds for this one yet?
j
Have you considered enabling use of the new K/N memory model?
m
Nope, actually haven’t. The apps are already in production and working fine with the old model, so haven’t seen much of a need to update
j
One thing to bear in mind is that I believe
native-mt
coroutines will be at least deprecated in Kotlin 1.7
m
Ah, right. Didn’t know that. So, I guess it’s a pretty big sign for those who haven’t by then updated to the new MM?
j
actually I think it's stronger than that....I think word "decomissioned" was used https://twitter.com/joreilly/status/1472925676999262208?s=20&amp;t=tKWbW6WfsFwddofdPPK0Qw
Ktor 2.0 for example is using new MM as are an increasing number of 3rd party libraries
m
Good info, thanks 👍 I’ve recently not followed the progress, I guess a lot has happened in a few months 😅. Based on duration between the previous releases for Kotlin, I’d assume that 1.7 might not be that far away then anymore
Thanks for the youtube link, the wording definitely makes it sound like the migration should be done by 1.7
Well, I guess I’ll stick with the old MM, seeing that at the moment above is the only issue. Thanks again for the information 👍