From cca5d3b18e57b54deb61e2c618c0f5c5ffb6116f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?O=C4=9Fuzhan=20Soykan?= Date: Tue, 14 Feb 2023 16:54:40 +0100 Subject: [PATCH] ObjectMapper is the first class citizen for ser/de #34 (#35) * ObjectMapper is the first class citizen for ser/de #34 * add byConfiguring * apply ktlint * add elasticsearch to the coverage --- .editorconfig | 2 +- build.gradle.kts | 2 +- buildSrc/src/main/kotlin/coverage.gradle.kts | 1 + gradle/libs.versions.toml | 3 +- .../testing/e2e/couchbase/CouchbaseSystem.kt | 29 +++++-------- .../e2e/elasticsearch/ElasticsearchSystem.kt | 6 +-- .../testing/e2e/http/DefaultHttpSystem.kt | 22 +++++----- .../stove/testing/e2e/kafka/KafkaSystem.kt | 18 ++++---- .../e2e/kafka/intercepting/CommonOps.kt | 6 +-- .../intercepting/TestSystemInterceptor.kt | 4 +- .../testing/e2e/wiremock/WireMockSystem.kt | 29 +++++++------ .../testing/e2e/httpmock/HttpMockSystem.kt | 12 +++--- .../e2e/serialization/StoveJsonSerializer.kt | 42 ------------------- .../e2e/serialization/StoveObjectMapper.kt | 11 +++++ .../stove/testing/e2e/kafka/KafkaSystem.kt | 15 +++++-- 15 files changed, 84 insertions(+), 118 deletions(-) delete mode 100644 lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/serialization/StoveJsonSerializer.kt create mode 100644 lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/serialization/StoveObjectMapper.kt diff --git a/.editorconfig b/.editorconfig index 7820296e..22a40a83 100644 --- a/.editorconfig +++ b/.editorconfig @@ -2,7 +2,7 @@ root = true [*] insert_final_newline = true -disabled_rules = no-wildcard-imports, filename, import-ordering +ktlint_disabled_rules = no-wildcard-imports, filename, import-ordering [{*.kt,*.kts}] ij_kotlin_code_style_defaults = KOTLIN_OFFICIAL diff --git a/build.gradle.kts b/build.gradle.kts index b6899f72..4ad9643f 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -6,7 +6,7 @@ plugins { kotlin("jvm").version(libs.versions.kotlin) alias(libs.plugins.dokka) alias(libs.plugins.ktlint) - alias(libs.plugins.palantirGitVersioning) + alias(libs.plugins.gitVersioning) id("stove-publishing") apply false id("coverage") java diff --git a/buildSrc/src/main/kotlin/coverage.gradle.kts b/buildSrc/src/main/kotlin/coverage.gradle.kts index 13fa06a6..09971c96 100644 --- a/buildSrc/src/main/kotlin/coverage.gradle.kts +++ b/buildSrc/src/main/kotlin/coverage.gradle.kts @@ -7,6 +7,7 @@ plugins { dependencies { jacocoAggregation(project(":lib:stove-testing-e2e")) jacocoAggregation(project(":lib:stove-testing-e2e-couchbase")) + jacocoAggregation(project(":lib:stove-testing-e2e-elasticsearch")) jacocoAggregation(project(":lib:stove-testing-e2e-http")) jacocoAggregation(project(":lib:stove-testing-e2e-kafka")) jacocoAggregation(project(":lib:stove-testing-e2e-wiremock")) diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index f3e0b022..fb015487 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -76,6 +76,5 @@ ktlint = { id = "org.jlleitschuh.gradle.ktlint", version = "11.2.0" } dokka = { id = "org.jetbrains.dokka", version.ref = "dokka" } knit = { id = "org.jetbrains.kotlinx:kotlinx-knit", version.ref = "knit" } kover = { id = "org.jetbrains.kotlinx.kover", version.ref = "kover" } -gitVersioning = { id = "me.qoomon.git-versioning", version = "6.4.0" } -palantirGitVersioning = { id = "com.palantir.git-version", version = "1.0.0" } +gitVersioning = { id = "com.palantir.git-version", version = "1.0.0" } diff --git a/lib/stove-testing-e2e-couchbase/src/main/kotlin/com/trendyol/stove/testing/e2e/couchbase/CouchbaseSystem.kt b/lib/stove-testing-e2e-couchbase/src/main/kotlin/com/trendyol/stove/testing/e2e/couchbase/CouchbaseSystem.kt index 4130780b..dc710c8a 100644 --- a/lib/stove-testing-e2e-couchbase/src/main/kotlin/com/trendyol/stove/testing/e2e/couchbase/CouchbaseSystem.kt +++ b/lib/stove-testing-e2e-couchbase/src/main/kotlin/com/trendyol/stove/testing/e2e/couchbase/CouchbaseSystem.kt @@ -5,19 +5,20 @@ package com.trendyol.stove.testing.e2e.couchbase import arrow.core.getOrElse import com.couchbase.client.core.msg.kv.DurabilityLevel.PERSIST_TO_MAJORITY import com.couchbase.client.java.* -import com.couchbase.client.java.codec.JsonSerializer +import com.couchbase.client.java.codec.JacksonJsonSerializer import com.couchbase.client.java.env.ClusterEnvironment import com.couchbase.client.java.json.JsonObject +import com.couchbase.client.java.json.JsonValueModule import com.couchbase.client.java.kv.InsertOptions import com.couchbase.client.java.query.QueryScanConsistency.REQUEST_PLUS +import com.fasterxml.jackson.databind.ObjectMapper import com.trendyol.stove.functional.Try import com.trendyol.stove.functional.recover import com.trendyol.stove.testing.e2e.containers.DEFAULT_REGISTRY import com.trendyol.stove.testing.e2e.containers.withProvidedRegistry import com.trendyol.stove.testing.e2e.couchbase.ClusterExtensions.executeQueryAs import com.trendyol.stove.testing.e2e.database.DocumentDatabaseSystem -import com.trendyol.stove.testing.e2e.serialization.StoveJacksonJsonSerializer -import com.trendyol.stove.testing.e2e.serialization.StoveJsonSerializer +import com.trendyol.stove.testing.e2e.serialization.StoveObjectMapper import com.trendyol.stove.testing.e2e.system.TestSystem import com.trendyol.stove.testing.e2e.system.abstractions.ConfiguresExposedConfiguration import com.trendyol.stove.testing.e2e.system.abstractions.ExposedConfiguration @@ -31,7 +32,6 @@ import org.slf4j.Logger import org.slf4j.LoggerFactory import org.testcontainers.couchbase.BucketDefinition import org.testcontainers.couchbase.CouchbaseContainer -import kotlin.jvm.internal.Reflection import kotlin.reflect.KClass data class CouchbaseExposedConfiguration( @@ -45,7 +45,7 @@ data class CouchbaseSystemOptions( val defaultBucket: String, val registry: String = DEFAULT_REGISTRY, override val configureExposedConfiguration: (CouchbaseExposedConfiguration) -> List = { _ -> listOf() }, - val jsonSerializer: StoveJsonSerializer = StoveJacksonJsonSerializer(), + val objectMapper: ObjectMapper = StoveObjectMapper.byConfiguring { registerModule(JsonValueModule()) }, ) : SystemOptions, ConfiguresExposedConfiguration fun TestSystem.withCouchbase( @@ -82,7 +82,7 @@ class CouchbaseSystem internal constructor( private lateinit var collection: ReactiveCollection private lateinit var exposedConfiguration: CouchbaseExposedConfiguration - private val objectMapper: StoveJsonSerializer = context.options.jsonSerializer + private val objectMapper: ObjectMapper = context.options.objectMapper private val logger: Logger = LoggerFactory.getLogger(javaClass) override suspend fun run() { @@ -119,8 +119,8 @@ class CouchbaseSystem internal constructor( val result = cluster.executeQueryAs(query) { queryOptions -> queryOptions.scanConsistency(REQUEST_PLUS) } val objects = result - .map { objectMapper.serialize(it) } - .map { objectMapper.deserialize(it, clazz) } + .map { objectMapper.writeValueAsString(it) } + .map { objectMapper.readValue(it, clazz.java) } assertion(objects) return this @@ -157,7 +157,7 @@ class CouchbaseSystem internal constructor( .collection(collection) .insert( id, - JsonObject.fromJson(objectMapper.serialize(instance)), + JsonObject.fromJson(objectMapper.writeValueAsString(instance)), InsertOptions.insertOptions().durability(PERSIST_TO_MAJORITY) ) .awaitSingle() @@ -184,7 +184,7 @@ class CouchbaseSystem internal constructor( private fun createCluster(exposedConfiguration: CouchbaseExposedConfiguration): ReactiveCluster = ClusterEnvironment.builder() - .jsonSerializer(jsonSerializer()) + .jsonSerializer(JacksonJsonSerializer.create(objectMapper)) .build() .let { Cluster.connect( @@ -194,13 +194,4 @@ class CouchbaseSystem internal constructor( .environment(it) ).reactive() } - - private fun jsonSerializer(): JsonSerializer = object : JsonSerializer { - override fun serialize(input: Any): ByteArray = objectMapper.serializeAsBytes(input) - - override fun deserialize( - target: Class, - input: ByteArray, - ): T = objectMapper.deserialize(input, Reflection.getOrCreateKotlinClass(target)) as T - } } diff --git a/lib/stove-testing-e2e-elasticsearch/src/main/kotlin/com/trendyol/stove/testing/e2e/elasticsearch/ElasticsearchSystem.kt b/lib/stove-testing-e2e-elasticsearch/src/main/kotlin/com/trendyol/stove/testing/e2e/elasticsearch/ElasticsearchSystem.kt index ca20a8cd..896d483d 100644 --- a/lib/stove-testing-e2e-elasticsearch/src/main/kotlin/com/trendyol/stove/testing/e2e/elasticsearch/ElasticsearchSystem.kt +++ b/lib/stove-testing-e2e-elasticsearch/src/main/kotlin/com/trendyol/stove/testing/e2e/elasticsearch/ElasticsearchSystem.kt @@ -12,11 +12,11 @@ import co.elastic.clients.elasticsearch.core.DeleteRequest import co.elastic.clients.elasticsearch.core.SearchRequest import co.elastic.clients.json.jackson.JacksonJsonpMapper import co.elastic.clients.transport.rest_client.RestClientTransport +import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.trendyol.stove.testing.e2e.containers.withProvidedRegistry import com.trendyol.stove.testing.e2e.database.DocumentDatabaseSystem -import com.trendyol.stove.testing.e2e.serialization.StoveJacksonJsonSerializer -import com.trendyol.stove.testing.e2e.serialization.StoveJsonSerializer +import com.trendyol.stove.testing.e2e.serialization.StoveObjectMapper import com.trendyol.stove.testing.e2e.system.TestSystem import com.trendyol.stove.testing.e2e.system.abstractions.* import org.apache.http.HttpHost @@ -34,7 +34,7 @@ data class ElasticsearchSystemOptions( val defaultIndex: DefaultIndex, val containerOptions: ContainerOptions = ContainerOptions(), override val configureExposedConfiguration: (ElasticSearchExposedConfiguration) -> List = { _ -> listOf() }, - val jsonSerializer: StoveJsonSerializer = StoveJacksonJsonSerializer(), + val objectMapper: ObjectMapper = StoveObjectMapper.Default, ) : SystemOptions, ConfiguresExposedConfiguration { internal val migrationCollection: MigrationCollection = MigrationCollection() diff --git a/lib/stove-testing-e2e-http/src/main/kotlin/com/trendyol/stove/testing/e2e/http/DefaultHttpSystem.kt b/lib/stove-testing-e2e-http/src/main/kotlin/com/trendyol/stove/testing/e2e/http/DefaultHttpSystem.kt index e9cdbff1..8b51f408 100644 --- a/lib/stove-testing-e2e-http/src/main/kotlin/com/trendyol/stove/testing/e2e/http/DefaultHttpSystem.kt +++ b/lib/stove-testing-e2e-http/src/main/kotlin/com/trendyol/stove/testing/e2e/http/DefaultHttpSystem.kt @@ -4,9 +4,9 @@ package com.trendyol.stove.testing.e2e.http import arrow.core.Option import arrow.core.getOrElse -import com.trendyol.stove.testing.e2e.serialization.StoveJacksonJsonSerializer -import com.trendyol.stove.testing.e2e.serialization.StoveJsonSerializer -import com.trendyol.stove.testing.e2e.serialization.deserialize +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue +import com.trendyol.stove.testing.e2e.serialization.StoveObjectMapper import com.trendyol.stove.testing.e2e.system.TestSystem import com.trendyol.stove.testing.e2e.system.abstractions.SystemNotRegisteredException import com.trendyol.stove.testing.e2e.system.abstractions.SystemOptions @@ -22,19 +22,19 @@ import java.time.Duration import kotlinx.coroutines.future.await import kotlin.reflect.KClass -data class HttpClientSystemOptions(val jsonSerializer: StoveJsonSerializer = StoveJacksonJsonSerializer()) : SystemOptions +data class HttpClientSystemOptions(val objectMapper: ObjectMapper = StoveObjectMapper.Default) : SystemOptions @Deprecated( "This method is deprecated, going to be removed", replaceWith = ReplaceWith("withHttpClient()", "com.trendyol.stove.testing.e2e.http.TestSystem") ) -fun TestSystem.withDefaultHttp(jsonSerializer: StoveJsonSerializer = StoveJacksonJsonSerializer()): TestSystem { +fun TestSystem.withDefaultHttp(jsonSerializer: ObjectMapper = StoveObjectMapper.Default): TestSystem { this.getOrRegister(DefaultHttpSystem(this, jsonSerializer)) return this } fun TestSystem.withHttpClient(options: HttpClientSystemOptions = HttpClientSystemOptions()): TestSystem { - this.getOrRegister(DefaultHttpSystem(this, options.jsonSerializer)) + this.getOrRegister(DefaultHttpSystem(this, options.objectMapper)) return this } @@ -54,7 +54,7 @@ fun TestSystem.http(): DefaultHttpSystem = class DefaultHttpSystem( override val testSystem: TestSystem, - private val json: StoveJsonSerializer, + private val objectMapper: ObjectMapper, ) : HttpSystem { private val httpClient: HttpClient = httpClient() @@ -72,7 +72,7 @@ class DefaultHttpSystem( token.map { request.setHeader(Headers.Authentication, Headers.bearer(it)) } body.fold( ifEmpty = { request.POST(BodyPublishers.noBody()) }, - ifSome = { request.POST(BodyPublishers.ofString(json.serialize(it))) } + ifSome = { request.POST(BodyPublishers.ofString(objectMapper.writeValueAsString(it))) } ) }.let { expect(deserialize(it, clazz)); this } @@ -85,7 +85,7 @@ class DefaultHttpSystem( token.map { request.setHeader(Headers.Authentication, Headers.bearer(it)) } body.fold( ifEmpty = { request.POST(BodyPublishers.noBody()) }, - ifSome = { request.POST(BodyPublishers.ofString(json.serialize(it))) } + ifSome = { request.POST(BodyPublishers.ofString(objectMapper.writeValueAsString(it))) } ) }.let { expect(StoveHttpResponse(it.statusCode(), it.headers().map())); this } @@ -107,7 +107,7 @@ class DefaultHttpSystem( ): DefaultHttpSystem = httpClient.send(uri) { request -> token.map { request.setHeader(Headers.Authentication, Headers.bearer(it)) } request.GET() - }.let { expect(json.deserialize(it.body())); this } + }.let { expect(objectMapper.readValue(it.body())); this } override suspend fun getResponse( uri: String, @@ -145,7 +145,7 @@ class DefaultHttpSystem( clazz: KClass, ): TExpected = when { clazz.java.isAssignableFrom(String::class.java) -> String(it.body()) as TExpected - else -> json.deserialize(it.body(), clazz) + else -> objectMapper.readValue(it.body(), clazz.java) } override fun close() {} diff --git a/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/KafkaSystem.kt b/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/KafkaSystem.kt index a7dadd5e..b543138d 100644 --- a/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/KafkaSystem.kt +++ b/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/KafkaSystem.kt @@ -4,14 +4,14 @@ package com.trendyol.stove.testing.e2e.kafka import arrow.core.Option import arrow.core.getOrElse +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.module.kotlin.readValue import com.trendyol.stove.testing.e2e.containers.DEFAULT_REGISTRY import com.trendyol.stove.testing.e2e.containers.withProvidedRegistry import com.trendyol.stove.testing.e2e.kafka.intercepting.InterceptionOptions import com.trendyol.stove.testing.e2e.kafka.intercepting.TestSystemKafkaInterceptor import com.trendyol.stove.testing.e2e.messaging.MessagingSystem -import com.trendyol.stove.testing.e2e.serialization.StoveJacksonJsonSerializer -import com.trendyol.stove.testing.e2e.serialization.StoveJsonSerializer -import com.trendyol.stove.testing.e2e.serialization.deserialize +import com.trendyol.stove.testing.e2e.serialization.StoveObjectMapper import com.trendyol.stove.testing.e2e.system.TestSystem import com.trendyol.stove.testing.e2e.system.abstractions.* import io.github.nomisRev.kafka.Admin @@ -40,7 +40,7 @@ data class KafkaSystemOptions( val registry: String = DEFAULT_REGISTRY, val ports: List = listOf(9092, 9093), val errorTopicSuffixes: List = listOf("error", "errorTopic", "retry", "retryTopic"), - val jsonSerializer: StoveJsonSerializer = StoveJacksonJsonSerializer(), + val objectMapper: ObjectMapper = StoveObjectMapper.Default, override val configureExposedConfiguration: (KafkaExposedConfiguration) -> List = { _ -> listOf() }, ) : SystemOptions, ConfiguresExposedConfiguration @@ -115,7 +115,7 @@ class KafkaSystem( override suspend fun afterRun() { interceptor = TestSystemKafkaInterceptor( adminClient, - StoveJacksonJsonSerializer(), + context.options.objectMapper, InterceptionOptions(errorTopicSuffixes = context.options.errorTopicSuffixes) ) subscribeToAllConsumer = SubscribeToAll( @@ -178,19 +178,19 @@ class KafkaSystem( } class StoveKafkaValueDeserializer : Deserializer { - private val jsonSerializer = StoveJacksonJsonSerializer() + private val objectMapper = StoveObjectMapper.Default @Suppress("UNCHECKED_CAST") override fun deserialize( topic: String, data: ByteArray, - ): T = jsonSerializer.deserialize(data) as T + ): T = objectMapper.readValue(data) as T } class StoveKafkaValueSerializer : Serializer { - private val jsonSerializer = StoveJacksonJsonSerializer() + private val objectMapper = StoveObjectMapper.Default override fun serialize( topic: String, data: T, - ): ByteArray = jsonSerializer.serializeAsBytes(data) + ): ByteArray = objectMapper.writeValueAsBytes(data) } diff --git a/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/intercepting/CommonOps.kt b/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/intercepting/CommonOps.kt index 05577716..62eb4f37 100644 --- a/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/intercepting/CommonOps.kt +++ b/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/intercepting/CommonOps.kt @@ -4,9 +4,9 @@ import arrow.core.Option import arrow.core.align import arrow.core.handleErrorWith import arrow.core.toOption +import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper import com.trendyol.stove.testing.e2e.kafka.KafkaSystem -import com.trendyol.stove.testing.e2e.serialization.StoveJsonSerializer import java.util.UUID import java.util.concurrent.ConcurrentMap import kotlinx.coroutines.TimeoutCancellationException @@ -27,7 +27,7 @@ data class KafkaAssertion( internal interface CommonOps : RecordsAssertions { val exceptions: ConcurrentMap - val serde: StoveJsonSerializer + val serde: ObjectMapper val adminClient: Admin suspend fun (() -> Collection).waitUntilConditionMet( @@ -60,7 +60,7 @@ internal interface CommonOps : RecordsAssertions { clazz: KClass, ): Result = runCatching { when (json) { - is String -> serde.deserialize(json, clazz) + is String -> serde.readValue(json, clazz.java) else -> jacksonObjectMapper().convertValue(json, clazz.java) } } diff --git a/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/intercepting/TestSystemInterceptor.kt b/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/intercepting/TestSystemInterceptor.kt index efe654dd..40f74c4e 100644 --- a/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/intercepting/TestSystemInterceptor.kt +++ b/lib/stove-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/intercepting/TestSystemInterceptor.kt @@ -1,6 +1,6 @@ package com.trendyol.stove.testing.e2e.kafka.intercepting -import com.trendyol.stove.testing.e2e.serialization.StoveJsonSerializer +import com.fasterxml.jackson.databind.ObjectMapper import java.util.UUID import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentMap @@ -12,7 +12,7 @@ import org.slf4j.LoggerFactory class TestSystemKafkaInterceptor( override val adminClient: Admin, - override val serde: StoveJsonSerializer, + override val serde: ObjectMapper, private val options: InterceptionOptions, ) : ConsumingOps, CommonOps, AutoCloseable { diff --git a/lib/stove-testing-e2e-wiremock/src/main/kotlin/com/trendyol/stove/testing/e2e/wiremock/WireMockSystem.kt b/lib/stove-testing-e2e-wiremock/src/main/kotlin/com/trendyol/stove/testing/e2e/wiremock/WireMockSystem.kt index 9cb99462..cb6bfde8 100644 --- a/lib/stove-testing-e2e-wiremock/src/main/kotlin/com/trendyol/stove/testing/e2e/wiremock/WireMockSystem.kt +++ b/lib/stove-testing-e2e-wiremock/src/main/kotlin/com/trendyol/stove/testing/e2e/wiremock/WireMockSystem.kt @@ -3,7 +3,7 @@ package com.trendyol.stove.testing.e2e.wiremock import arrow.core.None import arrow.core.Option import arrow.core.getOrElse -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper +import com.fasterxml.jackson.databind.ObjectMapper import com.github.tomakehurst.wiremock.WireMockServer import com.github.tomakehurst.wiremock.client.MappingBuilder import com.github.tomakehurst.wiremock.client.ResponseDefinitionBuilder @@ -17,8 +17,7 @@ import com.github.tomakehurst.wiremock.matching.ContainsPattern import com.github.tomakehurst.wiremock.stubbing.ServeEvent import com.github.tomakehurst.wiremock.stubbing.StubMapping import com.trendyol.stove.testing.e2e.httpmock.HttpMockSystem -import com.trendyol.stove.testing.e2e.serialization.StoveJacksonJsonSerializer -import com.trendyol.stove.testing.e2e.serialization.StoveJsonSerializer +import com.trendyol.stove.testing.e2e.serialization.StoveObjectMapper import com.trendyol.stove.testing.e2e.system.TestSystem import com.trendyol.stove.testing.e2e.system.abstractions.RunAware import com.trendyol.stove.testing.e2e.system.abstractions.SystemNotRegisteredException @@ -37,7 +36,7 @@ data class WireMockSystemOptions( val removeStubAfterRequestMatched: Boolean = false, val afterStubRemoved: AfterStubRemoved = { _, _, _ -> }, val afterRequest: AfterRequestHandler = { _, _, _ -> }, - val jsonSerializer: StoveJsonSerializer = StoveJacksonJsonSerializer(jacksonObjectMapper()), + val jsonSerializer: ObjectMapper = StoveObjectMapper.Default, ) : SystemOptions fun TestSystem.withWireMock( @@ -67,7 +66,7 @@ data class WireMockContext( val afterRequest: AfterRequestHandler, - val stoveJsonSerializer: StoveJsonSerializer, + val objectMapper: ObjectMapper, ) fun TestSystem.wiremock(): WireMockSystem = @@ -82,7 +81,7 @@ class WireMockSystem( private val stubLog: ConcurrentMap = ConcurrentHashMap() private var wireMock: WireMockServer - private val json: StoveJsonSerializer = ctx.stoveJsonSerializer + private val json: ObjectMapper = ctx.objectMapper init { val stoveExtensions = mutableListOf() @@ -139,7 +138,7 @@ class WireMockSystem( val res = aResponse() .withStatus(statusCode) .withHeader("Content-Type", "application/json; charset=UTF-8") - responseBody.map { res.withBody(json.serializeAsBytes(it)) } + responseBody.map { res.withBody(json.writeValueAsBytes(it)) } val req = WireMock.put(WireMock.urlEqualTo(url)) configureBodyAndMetadata(req, metadata, requestBody) val stub = wireMock.stubFor(req.willReturn(res).withId(UUID.randomUUID())) @@ -177,7 +176,7 @@ class WireMockSystem( override fun mockPutConfigure( url: String, - configure: (MappingBuilder, StoveJsonSerializer) -> MappingBuilder, + configure: (MappingBuilder, ObjectMapper) -> MappingBuilder, ): WireMockSystem { val req = WireMock.put(WireMock.urlEqualTo(url)) val stub = wireMock.stubFor(configure(req, json).withId(UUID.randomUUID())) @@ -187,7 +186,7 @@ class WireMockSystem( override fun mockGetConfigure( url: String, - configure: (MappingBuilder, StoveJsonSerializer) -> MappingBuilder, + configure: (MappingBuilder, ObjectMapper) -> MappingBuilder, ): WireMockSystem { val req = WireMock.get(WireMock.urlEqualTo(url)) val stub = wireMock.stubFor(configure(req, json).withId(UUID.randomUUID())) @@ -197,7 +196,7 @@ class WireMockSystem( override fun mockHeadConfigure( url: String, - configure: (MappingBuilder, StoveJsonSerializer) -> MappingBuilder, + configure: (MappingBuilder, ObjectMapper) -> MappingBuilder, ): WireMockSystem { val req = WireMock.head(WireMock.urlEqualTo(url)) val stub = wireMock.stubFor(configure(req, json).withId(UUID.randomUUID())) @@ -207,7 +206,7 @@ class WireMockSystem( override fun mockDeleteConfigure( url: String, - configure: (MappingBuilder, StoveJsonSerializer) -> MappingBuilder, + configure: (MappingBuilder, ObjectMapper) -> MappingBuilder, ): WireMockSystem { val req = WireMock.delete(WireMock.urlEqualTo(url)) val stub = wireMock.stubFor(configure(req, json).withId(UUID.randomUUID())) @@ -217,7 +216,7 @@ class WireMockSystem( override fun mockPostConfigure( url: String, - configure: (MappingBuilder, StoveJsonSerializer) -> MappingBuilder, + configure: (MappingBuilder, ObjectMapper) -> MappingBuilder, ): WireMockSystem { val req = WireMock.post(WireMock.urlEqualTo(url)) val stub = wireMock.stubFor(configure(req, json).withId(UUID.randomUUID())) @@ -242,7 +241,7 @@ class WireMockSystem( ValidationResult( "${it.method.value()} ${it.url}", it.bodyAsString, - json.serialize(it.queryParams) + json.writeValueAsString(it.queryParams) ).toString() } throw AssertionError( @@ -262,7 +261,7 @@ class WireMockSystem( body.map { request.withRequestBody( equalToJson( - json.serialize(it), + json.writeValueAsString(it), true, false ) @@ -277,7 +276,7 @@ class WireMockSystem( val mockResponse = aResponse() .withStatus(statusCode) .withHeader("Content-Type", "application/json; charset=UTF-8") - responseBody.map { mockResponse.withBody(json.serializeAsBytes(it)) } + responseBody.map { mockResponse.withBody(json.writeValueAsBytes(it)) } return mockResponse } } diff --git a/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/httpmock/HttpMockSystem.kt b/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/httpmock/HttpMockSystem.kt index 3e930f55..bb0dc9b4 100644 --- a/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/httpmock/HttpMockSystem.kt +++ b/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/httpmock/HttpMockSystem.kt @@ -2,7 +2,7 @@ package com.trendyol.stove.testing.e2e.httpmock import arrow.core.None import arrow.core.Option -import com.trendyol.stove.testing.e2e.serialization.StoveJsonSerializer +import com.fasterxml.jackson.databind.ObjectMapper import com.trendyol.stove.testing.e2e.system.abstractions.PluggedSystem import com.trendyol.stove.testing.e2e.system.abstractions.ValidatedSystem @@ -67,7 +67,7 @@ interface HttpMockSystem : PluggedSystem, ValidatedSystem */ fun mockPostConfigure( url: String, - configure: (TRequestBuilder, StoveJsonSerializer) -> TRequestBuilder, + configure: (TRequestBuilder, ObjectMapper) -> TRequestBuilder, ): HttpMockSystem /** @@ -75,7 +75,7 @@ interface HttpMockSystem : PluggedSystem, ValidatedSystem */ fun mockGetConfigure( url: String, - configure: (TRequestBuilder, StoveJsonSerializer) -> TRequestBuilder, + configure: (TRequestBuilder, ObjectMapper) -> TRequestBuilder, ): HttpMockSystem /** @@ -83,7 +83,7 @@ interface HttpMockSystem : PluggedSystem, ValidatedSystem */ fun mockHeadConfigure( url: String, - configure: (TRequestBuilder, StoveJsonSerializer) -> TRequestBuilder, + configure: (TRequestBuilder, ObjectMapper) -> TRequestBuilder, ): HttpMockSystem /** @@ -91,7 +91,7 @@ interface HttpMockSystem : PluggedSystem, ValidatedSystem */ fun mockDeleteConfigure( url: String, - configure: (TRequestBuilder, StoveJsonSerializer) -> TRequestBuilder, + configure: (TRequestBuilder, ObjectMapper) -> TRequestBuilder, ): HttpMockSystem /** @@ -99,6 +99,6 @@ interface HttpMockSystem : PluggedSystem, ValidatedSystem */ fun mockPutConfigure( url: String, - configure: (TRequestBuilder, StoveJsonSerializer) -> TRequestBuilder, + configure: (TRequestBuilder, ObjectMapper) -> TRequestBuilder, ): HttpMockSystem } diff --git a/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/serialization/StoveJsonSerializer.kt b/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/serialization/StoveJsonSerializer.kt deleted file mode 100644 index 0ab59ab5..00000000 --- a/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/serialization/StoveJsonSerializer.kt +++ /dev/null @@ -1,42 +0,0 @@ -package com.trendyol.stove.testing.e2e.serialization - -import com.fasterxml.jackson.databind.ObjectMapper -import com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS -import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper -import kotlin.reflect.KClass - -interface StoveJsonSerializer { - fun serialize(value: Any): String - fun serializeAsBytes(value: Any): ByteArray - - fun deserialize( - string: String, - clazz: KClass, - ): T - - fun deserialize( - value: ByteArray, - clazz: KClass, - ): T -} - -inline fun StoveJsonSerializer.deserialize(json: String): T = this.deserialize(json, T::class) -inline fun StoveJsonSerializer.deserialize(value: ByteArray): T = this.deserialize(value, T::class) - -class StoveJacksonJsonSerializer( - private val objectMapper: ObjectMapper = jacksonObjectMapper().disable(FAIL_ON_EMPTY_BEANS), -) : StoveJsonSerializer { - override fun serialize(value: Any): String = objectMapper.writeValueAsString(value) - - override fun serializeAsBytes(value: Any): ByteArray = objectMapper.writeValueAsBytes(value) - - override fun deserialize( - string: String, - clazz: KClass, - ): T = objectMapper.readValue(string, clazz.java) - - override fun deserialize( - value: ByteArray, - clazz: KClass, - ): T = objectMapper.readValue(value, clazz.java) -} diff --git a/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/serialization/StoveObjectMapper.kt b/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/serialization/StoveObjectMapper.kt new file mode 100644 index 00000000..19839a05 --- /dev/null +++ b/lib/stove-testing-e2e/src/main/kotlin/com/trendyol/stove/testing/e2e/serialization/StoveObjectMapper.kt @@ -0,0 +1,11 @@ +package com.trendyol.stove.testing.e2e.serialization + +import com.fasterxml.jackson.databind.ObjectMapper +import com.fasterxml.jackson.databind.SerializationFeature.FAIL_ON_EMPTY_BEANS +import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper + +object StoveObjectMapper { + val Default: ObjectMapper = jacksonObjectMapper().disable(FAIL_ON_EMPTY_BEANS) + + fun byConfiguring(configurer: ObjectMapper.() -> ObjectMapper): ObjectMapper = configurer(Default) +} diff --git a/starters/spring/stove-spring-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/KafkaSystem.kt b/starters/spring/stove-spring-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/KafkaSystem.kt index f5ec26d6..570e1cdf 100644 --- a/starters/spring/stove-spring-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/KafkaSystem.kt +++ b/starters/spring/stove-spring-testing-e2e-kafka/src/main/kotlin/com/trendyol/stove/testing/e2e/kafka/KafkaSystem.kt @@ -8,8 +8,14 @@ import com.trendyol.stove.testing.e2e.containers.DEFAULT_REGISTRY import com.trendyol.stove.testing.e2e.containers.withProvidedRegistry import com.trendyol.stove.testing.e2e.messaging.AssertsPublishing import com.trendyol.stove.testing.e2e.messaging.MessagingSystem +import com.trendyol.stove.testing.e2e.serialization.StoveObjectMapper import com.trendyol.stove.testing.e2e.system.TestSystem -import com.trendyol.stove.testing.e2e.system.abstractions.* +import com.trendyol.stove.testing.e2e.system.abstractions.ConfiguresExposedConfiguration +import com.trendyol.stove.testing.e2e.system.abstractions.ExposedConfiguration +import com.trendyol.stove.testing.e2e.system.abstractions.ExposesConfiguration +import com.trendyol.stove.testing.e2e.system.abstractions.RunnableSystemWithContext +import com.trendyol.stove.testing.e2e.system.abstractions.SystemNotRegisteredException +import com.trendyol.stove.testing.e2e.system.abstractions.SystemOptions import kotlinx.coroutines.coroutineScope import kotlinx.coroutines.future.await import org.apache.kafka.clients.producer.ProducerRecord @@ -28,11 +34,13 @@ data class KafkaExposedConfiguration( data class KafkaSystemOptions( val registry: String = DEFAULT_REGISTRY, val ports: List = listOf(9092, 9093), + val objectMapper: ObjectMapper = StoveObjectMapper.Default, override val configureExposedConfiguration: (KafkaExposedConfiguration) -> List = { _ -> listOf() }, ) : SystemOptions, ConfiguresExposedConfiguration data class KafkaContext( val container: KafkaContainer, + val jsonSerializer: ObjectMapper, val configureExposedConfiguration: (KafkaExposedConfiguration) -> List, ) @@ -40,7 +48,7 @@ fun TestSystem.withKafka( options: KafkaSystemOptions = KafkaSystemOptions(), ): TestSystem = withProvidedRegistry("confluentinc/cp-kafka:latest", options.registry) { KafkaContainer(it).withExposedPorts(*options.ports.toTypedArray()).withEmbeddedZookeeper() -}.let { getOrRegister(KafkaSystem(this, KafkaContext(it, options.configureExposedConfiguration))) } +}.let { getOrRegister(KafkaSystem(this, KafkaContext(it, options.objectMapper, options.configureExposedConfiguration))) } .let { this } fun TestSystem.kafka(): KafkaSystem = @@ -51,7 +59,7 @@ class KafkaSystem( private val context: KafkaContext, ) : MessagingSystem, AssertsPublishing, RunnableSystemWithContext, ExposesConfiguration { private lateinit var applicationContext: ApplicationContext - private lateinit var objectMapper: ObjectMapper + private val objectMapper = context.jsonSerializer private lateinit var kafkaTemplate: KafkaTemplate val getInterceptor = { applicationContext.getBean(TestSystemKafkaInterceptor::class.java) } @@ -61,7 +69,6 @@ class KafkaSystem( override suspend fun afterRun(context: ApplicationContext) { applicationContext = context - objectMapper = context.getBean("objectMapper", ObjectMapper::class.java) kafkaTemplate = context.getBean() kafkaTemplate.setProducerListener(getInterceptor()) }