All Downloads are FREE. Search and download functionalities are using the official Maven repository.

jvmMain.tech.skot.model.test.network.HttpMocker.kt Maven / Gradle / Ivy

package tech.skot.model.test.network

import io.ktor.client.engine.mock.*
import io.ktor.client.request.*
import io.ktor.http.*
import tech.skot.model.test.network.HttpResponse.Companion._404
import kotlin.test.assertEquals
import kotlin.test.assertTrue

class HttpResponse(
    val content: String = "",
    val status: HttpStatusCode = HttpStatusCode.Accepted,
    val headers: Headers = headersOf(HttpHeaders.ContentType, "application/json"),
    val then: (HttpMocker.() -> Unit)? = null
) {
    fun toRespondData(scope: MockRequestHandleScope): HttpResponseData {
        return scope.respond(
            content = content,
            status = status,
            headers = headers
        )
    }

    companion object {
        val _404 = HttpResponse(status = HttpStatusCode.NotFound)
    }
}


class HttpMocker() {
    var nextResponse: HttpResponse? = null
    val responsesForUrl: MutableMap = mutableMapOf()

    fun setResponseOk(encodedPath: String, content: String = "") {
        responsesForUrl[encodedPath] = HttpResponse(content = content)
    }

    fun setResponse400(encodedPath: String, content:String = "") {
        responsesForUrl[encodedPath] = HttpResponse(status = HttpStatusCode.BadRequest,content = content)
    }

    fun setResponse404(encodedPath: String) {
        responsesForUrl[encodedPath] = _404
    }

    fun setResponse500(encodedPath: String, content:String = "") {
        responsesForUrl[encodedPath] = HttpResponse(status = HttpStatusCode.InternalServerError,content = content)
    }

    val calls: MutableList = mutableListOf()

    fun init() {
        nextResponse = null
        responsesForUrl.clear()
        calls.clear()
    }

    suspend fun assertJustCalled(encodedPath: String, body: String? = null, rule: String = "") {
        assertTrue("$rule-> le dernier appel http doit être à $encodedPath") {
            calls.lastOrNull()?.url?.encodedPath == encodedPath
        }

        body?.let {
            assertEquals(
                message = "$rule-> l'appel à $encodedPath doit avoir le body demandé",
                expected = it,
                actual = calls.lastOrNull()?.body?.toByteReadPacket()?.readText()
            )
        }

    }

    suspend fun assertCalled(encodedPath:String, body:String? = null, rule:String = "") {
        assertTrue("$rule-> un appel à $encodedPath doit avoir été fait") {
            calls.any {
                it.url.encodedPath == encodedPath
            }
        }

        body?.let {
            assertEquals(
                message = "$rule-> l'appel à $encodedPath doit avoir le body demandé",
                expected = it,
                actual = calls.find { it.url.encodedPath == encodedPath }?.body?.toByteReadPacket()?.readText()
            )
        }
    }


}

val mockHttp: HttpMocker = HttpMocker()

val mockHttpEngine: MockEngine = MockEngine { request ->

    mockHttp.calls.add(request)
    val response = mockHttp.nextResponse ?: mockHttp.responsesForUrl[request.url.encodedPath]
    ?: throw Exception("Pas de réponse mockée définie pour ${request.url.encodedPath}")
    response?.let {
        it.then?.invoke(mockHttp)
        it.toRespondData(this)
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy