From 1eec26f38472a6d4bfe04ab93f55110ae9b2cd6a Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Tue, 27 Oct 2026 19:39:44 +0200 Subject: [PATCH 1/2] Housekeeping: Replace mockserver with wiremock --- .../cache/functional/ProxyCacheHostSpec.kt | 11 +-- .../cache/functional/SecondaryCacheSpec.kt | 22 ++--- .../testcontainers/ContainerDependencies.kt | 4 +- .../client/WebCacheContainerClient.kt | 99 +++++++++++-------- .../container/WebCacheContainer.kt | 13 ++- 5 files changed, 84 insertions(+), 65 deletions(-) diff --git a/src/test/kotlin/org/prebid/cache/functional/ProxyCacheHostSpec.kt b/src/test/kotlin/org/prebid/cache/functional/ProxyCacheHostSpec.kt index e00d176..d1f8dd6 100644 --- a/src/test/kotlin/org/prebid/cache/functional/ProxyCacheHostSpec.kt +++ b/src/test/kotlin/org/prebid/cache/functional/ProxyCacheHostSpec.kt @@ -9,8 +9,6 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldContain import io.ktor.client.statement.bodyAsText import io.ktor.http.contentType -import org.mockserver.model.MediaType.APPLICATION_JSON_UTF_8 -import org.mockserver.model.MediaType.APPLICATION_XML import org.prebid.cache.functional.mapper.objectMapper import org.prebid.cache.functional.model.request.MediaType.JSON import org.prebid.cache.functional.model.request.MediaType.XML @@ -25,6 +23,7 @@ import org.prebid.cache.functional.util.getRandomUuid import org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR import org.springframework.http.HttpStatus.NOT_FOUND import org.springframework.http.HttpStatus.OK +import org.springframework.http.MediaType class ProxyCacheHostSpec : ShouldSpec({ @@ -109,8 +108,8 @@ class ProxyCacheHostSpec : ShouldSpec({ // then: PBC called proxy cache host webCacheContainerClient.getProxyCacheHostRecordedRequestCount() shouldBe initialProxyCacheHostRequestCount + 1 - val proxyCacheHostRequest = webCacheContainerClient.getProxyCacheHostRecordedRequests()!!.last() - proxyCacheHostRequest.queryStringParameters?.containsEntry("uuid", requestUuid) shouldBe true + val proxyCacheHostRequest = webCacheContainerClient.getProxyCacheHostRecordedRequests().last() + proxyCacheHostRequest.queryParameter("uuid").containsValue(requestUuid) shouldBe true } should("return a response body as a plain String requested from proxy cache host") { @@ -127,8 +126,8 @@ class ProxyCacheHostSpec : ShouldSpec({ should("return a response body as a JSON or XML object requested from proxy cache host") { forAll( - row(TransferValue.getDefaultJsonValue(), APPLICATION_JSON_UTF_8, JSON), - row(TransferValue.getDefaultXmlValue(), APPLICATION_XML, XML) + row(TransferValue.getDefaultJsonValue(), MediaType.APPLICATION_JSON, JSON), + row(TransferValue.getDefaultXmlValue(), MediaType.APPLICATION_XML, XML) ) { proxyCacheResponseBody, proxyCacheResponseMediaType, prebidCacheResponseMediaType -> // given: Proxy cache host response is set up to return a JSON response body webCacheContainerClient.setProxyCacheHostResponse( diff --git a/src/test/kotlin/org/prebid/cache/functional/SecondaryCacheSpec.kt b/src/test/kotlin/org/prebid/cache/functional/SecondaryCacheSpec.kt index a1aa745..8da90cf 100644 --- a/src/test/kotlin/org/prebid/cache/functional/SecondaryCacheSpec.kt +++ b/src/test/kotlin/org/prebid/cache/functional/SecondaryCacheSpec.kt @@ -58,11 +58,11 @@ class SecondaryCacheSpec : ShouldSpec({ // and: Request to secondary cache was sent val secondaryCacheRecordedRequests = webCacheContainerClient.getSecondaryCacheRecordedRequests(requestObject.puts[0].key!!) - secondaryCacheRecordedRequests?.size shouldBe 1 + secondaryCacheRecordedRequests.size shouldBe 1 // and: Request contained secondaryCache=yes query parameter - secondaryCacheRecordedRequests!!.first().queryStringParameters - ?.containsEntry("secondaryCache", "yes") shouldBe true + secondaryCacheRecordedRequests.first() + .queryParameter("secondaryCache").containsValue("yes") shouldBe true // and: Secondary cache request body matched to the Prebid Cache request object val secondaryCacheRequest = @@ -88,11 +88,11 @@ class SecondaryCacheSpec : ShouldSpec({ // and: Request to secondary cache was sent val secondaryCacheRecordedRequests = webCacheContainerClient.getSecondaryCacheRecordedRequests(requestObject.puts[0].key!!) - secondaryCacheRecordedRequests?.size shouldBe 1 + secondaryCacheRecordedRequests.size shouldBe 1 // and: Secondary cache request 'expiry' parameter matches to the PBC request 'ttlseconds' parameter val secondaryCacheRequest = - objectMapper.readValue(secondaryCacheRecordedRequests!!.first().bodyAsString, RequestObject::class.java) + objectMapper.readValue(secondaryCacheRecordedRequests.first().bodyAsString, RequestObject::class.java) secondaryCacheRequest.puts.size shouldBe 1 secondaryCacheRequest.puts[0].expiry shouldBe requestObject.puts[0].ttlseconds } @@ -115,11 +115,11 @@ class SecondaryCacheSpec : ShouldSpec({ // and: Request to secondary cache was sent val secondaryCacheRecordedRequests = webCacheContainerClient.getSecondaryCacheRecordedRequests(requestObject.puts[0].key!!) - secondaryCacheRecordedRequests?.size shouldBe 1 + secondaryCacheRecordedRequests.size shouldBe 1 // and: Secondary cache request 'expiry' parameter matches to the Prebid Cache 'cache.expiry.sec' config property val secondaryCacheRequest = - objectMapper.readValue(secondaryCacheRecordedRequests!!.first().bodyAsString, RequestObject::class.java) + objectMapper.readValue(secondaryCacheRecordedRequests.first().bodyAsString, RequestObject::class.java) secondaryCacheRequest.puts.size shouldBe 1 secondaryCacheRequest.puts[0].expiry shouldBe specPrebidCacheConfig["cache.expiry.sec"]?.toLong() } @@ -145,11 +145,11 @@ class SecondaryCacheSpec : ShouldSpec({ // and: Request to secondary cache was sent val secondaryCacheRecordedRequests = webCacheContainerClient.getSecondaryCacheRecordedRequests(requestObject.puts[0].key!!) - secondaryCacheRecordedRequests?.size shouldBe 1 + secondaryCacheRecordedRequests.size shouldBe 1 // and: Secondary cache request 'expiry' parameter matches to the Prebid Cache 'cache.max.expiry' config property val secondaryCacheRequest = - objectMapper.readValue(secondaryCacheRecordedRequests!!.first().bodyAsString, RequestObject::class.java) + objectMapper.readValue(secondaryCacheRecordedRequests.first().bodyAsString, RequestObject::class.java) secondaryCacheRequest.puts.size shouldBe 1 secondaryCacheRequest.puts[0].expiry shouldBe configCacheMaxExpiry } @@ -175,11 +175,11 @@ class SecondaryCacheSpec : ShouldSpec({ // and: Request to secondary cache was sent val secondaryCacheRecordedRequests = webCacheContainerClient.getSecondaryCacheRecordedRequests(requestObject.puts[0].key!!) - secondaryCacheRecordedRequests?.size shouldBe 1 + secondaryCacheRecordedRequests.size shouldBe 1 // and: Secondary cache request 'expiry' parameter matches to the Prebid Cache 'cache.min.expiry' config property val secondaryCacheRequest = - objectMapper.readValue(secondaryCacheRecordedRequests!!.first().bodyAsString, RequestObject::class.java) + objectMapper.readValue(secondaryCacheRecordedRequests.first().bodyAsString, RequestObject::class.java) secondaryCacheRequest.puts.size shouldBe 1 secondaryCacheRequest.puts[0].expiry shouldBe configCacheMinExpiry } diff --git a/src/test/kotlin/org/prebid/cache/functional/testcontainers/ContainerDependencies.kt b/src/test/kotlin/org/prebid/cache/functional/testcontainers/ContainerDependencies.kt index 8dc07c1..bcc799d 100644 --- a/src/test/kotlin/org/prebid/cache/functional/testcontainers/ContainerDependencies.kt +++ b/src/test/kotlin/org/prebid/cache/functional/testcontainers/ContainerDependencies.kt @@ -15,7 +15,7 @@ abstract class ContainerDependencies { private const val aerospikeImageName = "aerospike:ce-8.1.2.2" private const val apacheIgniteImageName = "apacheignite/ignite:2.18.0" private const val prebidCacheImageName = "prebid-cache:latest" - private const val mockServerImageVersion = "mockserver/mockserver:5.15.0" + private const val wireMockImageVersion = "wiremock/wiremock:3.13.0" private val launchContainers = System.getProperty("launchContainers")?.toBoolean() ?: true @@ -24,7 +24,7 @@ abstract class ContainerDependencies { val aerospikeContainer: AerospikeContainer = AerospikeContainer(aerospikeImageName).withNetwork(network) val apacheIgniteContainer: ApacheIgniteContainer = ApacheIgniteContainer(apacheIgniteImageName).withNetwork(network) val webCacheContainer: WebCacheContainer = - WebCacheContainer(DockerImageName.parse(mockServerImageVersion)).withNetwork(network) as WebCacheContainer + WebCacheContainer(DockerImageName.parse(wireMockImageVersion)).withNetwork(network) as WebCacheContainer val prebidCacheContainerPool = PrebidCacheContainerPool(prebidCacheImageName) fun startCacheServerContainers() { diff --git a/src/test/kotlin/org/prebid/cache/functional/testcontainers/client/WebCacheContainerClient.kt b/src/test/kotlin/org/prebid/cache/functional/testcontainers/client/WebCacheContainerClient.kt index fba295e..c26179f 100644 --- a/src/test/kotlin/org/prebid/cache/functional/testcontainers/client/WebCacheContainerClient.kt +++ b/src/test/kotlin/org/prebid/cache/functional/testcontainers/client/WebCacheContainerClient.kt @@ -1,67 +1,80 @@ package org.prebid.cache.functional.testcontainers.client -import org.mockserver.client.MockServerClient -import org.mockserver.matchers.Times -import org.mockserver.mock.Expectation -import org.mockserver.model.HttpRequest -import org.mockserver.model.HttpRequest.request -import org.mockserver.model.HttpResponse.response -import org.mockserver.model.JsonPathBody.jsonPath -import org.mockserver.model.MediaType -import org.mockserver.model.MediaType.APPLICATION_JSON_UTF_8 +import com.github.tomakehurst.wiremock.client.WireMock +import com.github.tomakehurst.wiremock.client.WireMock.aResponse +import com.github.tomakehurst.wiremock.client.WireMock.get +import com.github.tomakehurst.wiremock.client.WireMock.getRequestedFor +import com.github.tomakehurst.wiremock.client.WireMock.matchingJsonPath +import com.github.tomakehurst.wiremock.client.WireMock.post +import com.github.tomakehurst.wiremock.client.WireMock.postRequestedFor +import com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo +import com.github.tomakehurst.wiremock.stubbing.Scenario +import com.github.tomakehurst.wiremock.stubbing.StubMapping +import com.github.tomakehurst.wiremock.verification.LoggedRequest +import java.util.UUID import org.prebid.cache.functional.testcontainers.container.WebCacheContainer.Companion.WEB_CACHE_PATH -import org.springframework.http.HttpMethod.GET -import org.springframework.http.HttpMethod.POST import org.springframework.http.HttpStatus import org.springframework.http.HttpStatus.OK +import org.springframework.http.MediaType class WebCacheContainerClient(mockServerHost: String, mockServerPort: Int) { - private val mockServerClient: MockServerClient + private val wireMockClient = WireMock(mockServerHost, mockServerPort) + private var proxyCacheHostStub: StubMapping? = null - init { - mockServerClient = MockServerClient(mockServerHost, mockServerPort) - } - - fun getProxyCacheHostRecordedRequests(): Array? = - mockServerClient.retrieveRecordedRequests(getProxyCacheHostRequest()) + fun getProxyCacheHostRecordedRequests(): List = + wireMockClient.find(getProxyCacheHostRequest()) fun getProxyCacheHostRecordedRequestCount(): Int = - getProxyCacheHostRecordedRequests()?.size ?: 0 + getProxyCacheHostRecordedRequests().size fun setProxyCacheHostResponse( httpStatus: HttpStatus = OK, - body: String = "", - mediaType: MediaType = APPLICATION_JSON_UTF_8 - ): Array? = - mockServerClient.`when`(getProxyCacheHostRequest(), Times.exactly(1)) - .respond( - response().withStatusCode(httpStatus.value()) - .withBody(body, mediaType) - ) + body: String = "{}", + mediaType: MediaType = MediaType.APPLICATION_JSON + ): StubMapping { + proxyCacheHostStub?.let { wireMockClient.removeStubMapping(it) } + + return wireMockClient.register( + get(urlPathEqualTo("/$WEB_CACHE_PATH")) + .inScenario("proxy-cache-host-${UUID.randomUUID()}") + .whenScenarioStateIs(Scenario.STARTED) + .willReturn( + aResponse() + .withStatus(httpStatus.value()) + .withBody(body) + .withHeader("Content-Type", mediaType.toString()) + .withHeader("Connection", "close") + ) + .willSetStateTo("CONSUMED") + ).also { proxyCacheHostStub = it } + } - fun getSecondaryCacheRecordedRequests(uuidKey: String): Array? { + fun getSecondaryCacheRecordedRequests(uuidKey: String): List { val secondaryCacheRequest = getSecondaryCacheRequest(uuidKey) - waitUntil({ mockServerClient.retrieveRecordedRequests(secondaryCacheRequest)!!.isNotEmpty() }) - return mockServerClient.retrieveRecordedRequests(secondaryCacheRequest) + waitUntil({ wireMockClient.find(secondaryCacheRequest).isNotEmpty() }) + return wireMockClient.find(secondaryCacheRequest) } - fun initSecondaryCacheResponse(): Array? = - mockServerClient.`when`(getSecondaryCacheRequest()) - .respond(response().withStatusCode(OK.value())) + fun initSecondaryCacheResponse(): StubMapping = + wireMockClient.register( + post(urlPathEqualTo("/$WEB_CACHE_PATH")) + .willReturn( + aResponse() + .withStatus(OK.value()) + .withHeader("Connection", "close") + ) + ) - private fun getProxyCacheHostRequest(): HttpRequest = - request().withMethod(GET.name()) - .withPath("/$WEB_CACHE_PATH") + private fun getProxyCacheHostRequest() = + getRequestedFor(urlPathEqualTo("/$WEB_CACHE_PATH")) - private fun getSecondaryCacheRequest(): HttpRequest = - request().withMethod(POST.name()) - .withPath("/$WEB_CACHE_PATH") + private fun getSecondaryCacheRequest() = + postRequestedFor(urlPathEqualTo("/$WEB_CACHE_PATH")) - private fun getSecondaryCacheRequest(uuidKey: String): HttpRequest = - request().withMethod(POST.name()) - .withPath("/$WEB_CACHE_PATH") - .withBody(jsonPath("\$.puts[?(@.key == '$uuidKey')]")) + private fun getSecondaryCacheRequest(uuidKey: String) = + getSecondaryCacheRequest() + .withRequestBody(matchingJsonPath("$.puts[?(@.key == '$uuidKey')]")) private fun waitUntil(closure: () -> Boolean, timeoutMs: Long = 5000, pollInterval: Long = 100) { val startTime = System.currentTimeMillis() diff --git a/src/test/kotlin/org/prebid/cache/functional/testcontainers/container/WebCacheContainer.kt b/src/test/kotlin/org/prebid/cache/functional/testcontainers/container/WebCacheContainer.kt index 99da3c1..ed9c46b 100644 --- a/src/test/kotlin/org/prebid/cache/functional/testcontainers/container/WebCacheContainer.kt +++ b/src/test/kotlin/org/prebid/cache/functional/testcontainers/container/WebCacheContainer.kt @@ -1,14 +1,21 @@ package org.prebid.cache.functional.testcontainers.container -import org.testcontainers.containers.MockServerContainer +import org.testcontainers.containers.GenericContainer import org.testcontainers.utility.DockerImageName -class WebCacheContainer(dockerImageName: DockerImageName) : MockServerContainer(dockerImageName) { +class WebCacheContainer(dockerImageName: DockerImageName) : GenericContainer(dockerImageName) { fun getContainerHost(): String = networkAliases.first() + init { + withExposedPorts(PORT) + } + + val serverPort: Int + get() = getMappedPort(PORT) + companion object { - const val PORT = MockServerContainer.PORT + const val PORT = 8080 const val WEB_CACHE_PATH = "cache" } } From e5f35de226d1ae48ed09531045c144acf6ad1b4b Mon Sep 17 00:00:00 2001 From: osulzhenko Date: Tue, 27 Oct 2026 20:49:57 +0200 Subject: [PATCH 2/2] Housekeeping: Replace mockserver with wiremock --- pom.xml | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/pom.xml b/pom.xml index 073f468..fc0211b 100644 --- a/pom.xml +++ b/pom.xml @@ -67,7 +67,6 @@ 2.4.0 1.11.0 1.21.4 - 5.15.0 2.3.13 2.16.1 0.44.0 @@ -213,18 +212,6 @@ ${testcontainers.version} test - - org.testcontainers - mockserver - ${testcontainers.version} - test - - - org.mock-server - mockserver-client-java - ${mockserver-client.version} - test - io.ktor ktor-client-core-jvm