From 162113fbe98f21836d07833ccd963a7d0b8bbef0 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Tue, 21 Nov 2023 12:49:26 +0900 Subject: [PATCH 01/16] =?UTF-8?q?Refactor:=20=EA=B5=AC=ED=98=84=EA=B3=BC?= =?UTF-8?q?=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9C=A0=EC=97=B0?= =?UTF-8?q?=ED=95=98=EA=B2=8C=20=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=B4,?= =?UTF-8?q?=20=EC=BB=B4=ED=8F=AC=EC=A7=80=EC=85=98=20=ED=8C=A8=ED=84=B4?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20RestTemplate=20=ED=99=9C=EC=9A=A9=20timeou?= =?UTF-8?q?t=20=EC=B2=98=EB=A6=AC=20=EC=9D=B4=EC=A0=84=EC=97=90=20?= =?UTF-8?q?=EC=9E=AC=EC=8B=9C=EB=8F=84=20=EC=A0=95=EC=B1=85=20=EC=84=A4?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 딱히 뚜렷한 테스트 시나리오 및 비즈니스 룰은 없기 때문에 우선은 가장 일반적인 수치를 활용 --- .../PaymentModuleConfiguration.kt | 2 +- .../TossPaymentsKeyInApprovalProcessor.kt | 5 ++--- .../tosspayments/TossPaymentsRestClient.kt | 18 ++++++++++++++++++ 3 files changed, 21 insertions(+), 4 deletions(-) create mode 100644 payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/PaymentModuleConfiguration.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/PaymentModuleConfiguration.kt index 5c8cf24..824582e 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/PaymentModuleConfiguration.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/PaymentModuleConfiguration.kt @@ -4,13 +4,13 @@ import org.collaborators.paymentslab.payment.infrastructure.jpa.PaymentOrderRepo import org.collaborators.paymentslab.payment.infrastructure.jpa.TossPaymentHistoryRepositoryAdapter import org.collaborators.paymentslab.payment.infrastructure.jpa.TossPaymentsRepositoryAdapter import org.collaborators.paymentslab.payment.infrastructure.kafka.DefaultStringKafkaTemplateWrapper -import org.collaborators.paymentslab.payment.infrastructure.kafka.StringKafkaTemplateWrapper import org.collaborators.paymentslab.payment.infrastructure.log.AsyncAppenderPaymentTransactionLogProcessor import org.collaborators.paymentslab.payment.infrastructure.tosspayments.* import org.springframework.context.annotation.Configuration import org.springframework.context.annotation.Import @Import(value = [ + TossPaymentsRestClient::class, PaymentPropertiesResolver::class, TossPaymentsTransactionEventPublisher::class, TossPaymentsRepositoryAdapter::class, diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt index c566bf4..8a17467 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt @@ -13,12 +13,11 @@ import org.springframework.http.HttpStatus import org.springframework.http.MediaType import org.springframework.web.client.HttpClientErrorException import org.springframework.web.client.RestClientException -import org.springframework.web.client.RestTemplate import java.nio.charset.StandardCharsets import java.util.* class TossPaymentsKeyInApprovalProcessor( - private val restTemplate: RestTemplate, + private val restTemplate: TossPaymentsRestClient, private val paymentOrderRepository: PaymentOrderRepository, private val paymentsTransactionEventPublisher: TossPaymentsTransactionEventPublisher, private val paymentProperties: PaymentPropertiesResolver @@ -28,7 +27,7 @@ class TossPaymentsKeyInApprovalProcessor( var result = TossPaymentsApprovalResponse.preResponseOf(paymentOrder, dto) try { val request = createRequest(paymentOrder, dto) - val response = restTemplate.postForEntity("${paymentProperties.url}key-in", request, TossPaymentsApprovalResponse::class.java) + val response = restTemplate.postForEntity("${paymentProperties.url}key-in", request) if (response.statusCode == HttpStatus.OK && response.hasBody()) { paymentOrder.complete() result = response.body!! diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt new file mode 100644 index 0000000..5783cdf --- /dev/null +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt @@ -0,0 +1,18 @@ +package org.collaborators.paymentslab.payment.infrastructure.tosspayments + +import org.collaborator.paymentlab.common.domain.RestClient +import org.springframework.http.HttpEntity +import org.springframework.http.ResponseEntity +import org.springframework.web.client.RestTemplate + +class TossPaymentsRestClient( + private val restTemplate: RestTemplate, + private val paymentProperties: PaymentPropertiesResolver +): RestClient { + override fun postForEntity( + url: String, + request: HttpEntity + ): ResponseEntity { + return restTemplate.postForEntity("${paymentProperties.url}key-in", request, TossPaymentsApprovalResponse::class.java) + } +} \ No newline at end of file From b0112901282381536a0250c5d187623660847c86 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Tue, 21 Nov 2023 12:49:51 +0900 Subject: [PATCH 02/16] =?UTF-8?q?Feat:=20=EB=8B=A8=EA=B8=B0=EC=84=B1=20?= =?UTF-8?q?=EB=84=A4=ED=8A=B8=EC=9B=8C=ED=81=AC=20=EC=A7=80=EC=97=B0?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20time=20out=20=EC=98=88=EC=99=B8=EA=B0=80?= =?UTF-8?q?=20=EB=B0=9C=EC=83=9D=ED=95=98=EB=8A=94=20=EC=83=81=ED=99=A9?= =?UTF-8?q?=EC=9D=84=20=ED=94=BC=ED=95=98=EA=B8=B0=EC=9C=84=ED=95=B4,=20?= =?UTF-8?q?=20Resilience4j=EC=9D=84=20=ED=99=9C=EC=9A=A9=ED=95=9C=20jitter?= =?UTF-8?q?=20=EC=95=8C=EA=B3=A0=EB=A6=AC=EC=A6=98=20=EA=B8=B0=EB=B0=98?= =?UTF-8?q?=EC=9D=98=20retry=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 4 +++ .../paymentslab/config/RestTemplateConfig.kt | 11 ++++++-- .../config/resilience4j/Resilience4jConfig.kt | 28 +++++++++++++++++++ common/build.gradle.kts | 1 + .../paymentlab/common/domain/RestClient.kt | 8 ++++++ 5 files changed, 49 insertions(+), 3 deletions(-) create mode 100644 app/src/main/kotlin/org/collaborators/paymentslab/config/resilience4j/Resilience4jConfig.kt create mode 100644 common/src/main/kotlin/org/collaborator/paymentlab/common/domain/RestClient.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 9ca3e51..e059c94 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -53,6 +53,10 @@ dependencies { /** kafka **/ implementation("org.springframework.kafka:spring-kafka") + + /** resilience4j **/ + implementation("io.github.resilience4j:resilience4j-spring-boot3:2.1.0") + implementation("io.github.resilience4j:resilience4j-all") } tasks { diff --git a/app/src/main/kotlin/org/collaborators/paymentslab/config/RestTemplateConfig.kt b/app/src/main/kotlin/org/collaborators/paymentslab/config/RestTemplateConfig.kt index cf2d599..ad7b011 100644 --- a/app/src/main/kotlin/org/collaborators/paymentslab/config/RestTemplateConfig.kt +++ b/app/src/main/kotlin/org/collaborators/paymentslab/config/RestTemplateConfig.kt @@ -7,21 +7,26 @@ import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.SerializationFeature import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer +import org.springframework.boot.web.client.RestTemplateBuilder import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.converter.json.Jackson2ObjectMapperBuilder import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter import org.springframework.web.client.RestTemplate +import java.time.Duration import java.time.LocalDateTime import java.time.format.DateTimeFormatter @Configuration class RestTemplateConfig { + @Bean fun restTemplate(): RestTemplate { - val restTemplate = RestTemplate() - restTemplate.messageConverters.add(0, MappingJackson2HttpMessageConverter(configureObjectMapper().build())) - return restTemplate + return RestTemplateBuilder() + .setConnectTimeout(Duration.ofSeconds(5)) + .setReadTimeout(Duration.ofSeconds(5)) + .messageConverters(MappingJackson2HttpMessageConverter(configureObjectMapper().build())) + .build() } // JSR310 diff --git a/app/src/main/kotlin/org/collaborators/paymentslab/config/resilience4j/Resilience4jConfig.kt b/app/src/main/kotlin/org/collaborators/paymentslab/config/resilience4j/Resilience4jConfig.kt new file mode 100644 index 0000000..6af9b53 --- /dev/null +++ b/app/src/main/kotlin/org/collaborators/paymentslab/config/resilience4j/Resilience4jConfig.kt @@ -0,0 +1,28 @@ +package org.collaborators.paymentslab.config.resilience4j + +import io.github.resilience4j.common.retry.configuration.RetryConfigCustomizer +import io.github.resilience4j.core.IntervalFunction +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration + +private const val TOSS_PAYMENTS_APPROVAL = "tossPaymentsApprovalProcessor" +private const val INITIAL_INTERVAL = 1000L +private const val MULTIPLIER = 2.0 +private const val RANDOMIZATION_FACTOR = 0.6 +private const val MAX_RETRIES = 4 + +@Configuration +class Resilience4jConfig { + @Bean + fun retryConfigCustomizer(): RetryConfigCustomizer { + val jitterBackoffFunction + = IntervalFunction.ofExponentialRandomBackoff(INITIAL_INTERVAL, MULTIPLIER, RANDOMIZATION_FACTOR) + + return RetryConfigCustomizer + .of(TOSS_PAYMENTS_APPROVAL) { + it.maxAttempts(MAX_RETRIES) + .intervalFunction(jitterBackoffFunction) + .build() + } + } +} \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 57e92e9..19f995d 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,4 +1,5 @@ dependencies { + implementation("org.springframework:spring-web:6.0.7") implementation("org.reflections:reflections:0.10.2") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") diff --git a/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/RestClient.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/RestClient.kt new file mode 100644 index 0000000..8c740a2 --- /dev/null +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/RestClient.kt @@ -0,0 +1,8 @@ +package org.collaborator.paymentlab.common.domain + +import org.springframework.http.HttpEntity +import org.springframework.http.ResponseEntity + +interface RestClient { + fun postForEntity(url: String, request: HttpEntity): ResponseEntity +} \ No newline at end of file From 27de8ccbeb559d1962686f768ead58c43c9d289c Mon Sep 17 00:00:00 2001 From: wanniDev Date: Tue, 21 Nov 2023 12:51:57 +0900 Subject: [PATCH 03/16] =?UTF-8?q?Remove:=20=EC=82=AC=EC=9A=A9=ED=95=98?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EB=8A=94=20resilence4j=20dependency=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 1 - 1 file changed, 1 deletion(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index e059c94..3d093e6 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -56,7 +56,6 @@ dependencies { /** resilience4j **/ implementation("io.github.resilience4j:resilience4j-spring-boot3:2.1.0") - implementation("io.github.resilience4j:resilience4j-all") } tasks { From 1588743995da57e2dd01fa8dd26010baa4e4fa77 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Mon, 27 Nov 2023 12:54:48 +0900 Subject: [PATCH 04/16] =?UTF-8?q?Test:=20=EC=B9=B4=ED=94=84=EC=B9=B4=20?= =?UTF-8?q?=EC=A3=BC=ED=82=A4=ED=8D=BC,=20=EB=B8=8C=EB=A1=9C=EC=BB=A4?= =?UTF-8?q?=EC=84=9C=EB=B2=84=EA=B0=80=20=EB=9D=84=EC=9B=8C=EC=A7=80?= =?UTF-8?q?=EC=A7=80=20=EC=95=8A=EC=95=84=EB=8F=84=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8A=94=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=20=EA=B5=AC=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/build.gradle.kts | 3 + .../kafka/EnableKafkaKotlinTests.kt | 181 ++++++++++++++++++ .../payment/infrastructure/kafka/Hello.kt | 35 ++++ .../infrastructure/kafka/KafkaTestConfig.kt | 165 ++++++++++++++++ 4 files changed, 384 insertions(+) create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/EnableKafkaKotlinTests.kt create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/Hello.kt create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/KafkaTestConfig.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 3d093e6..945cd1d 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -53,6 +53,9 @@ dependencies { /** kafka **/ implementation("org.springframework.kafka:spring-kafka") + /** kafka test **/ + implementation("org.springframework.kafka:spring-kafka-test") + implementation("org.testcontainers:kafka:1.19.3") /** resilience4j **/ implementation("io.github.resilience4j:resilience4j-spring-boot3:2.1.0") diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/EnableKafkaKotlinTests.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/EnableKafkaKotlinTests.kt new file mode 100644 index 0000000..0d1fb35 --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/EnableKafkaKotlinTests.kt @@ -0,0 +1,181 @@ +package org.collaborators.paymentslab.payment.infrastructure.kafka + +import org.apache.kafka.clients.consumer.Consumer +import org.apache.kafka.clients.consumer.ConsumerConfig +import org.apache.kafka.clients.consumer.ConsumerRecord +import org.apache.kafka.clients.consumer.ConsumerRecords +import org.apache.kafka.clients.producer.ProducerConfig +import org.apache.kafka.common.serialization.StringDeserializer +import org.apache.kafka.common.serialization.StringSerializer +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.kafka.annotation.EnableKafka +import org.springframework.kafka.annotation.KafkaListener +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory +import org.springframework.kafka.core.ConsumerFactory +import org.springframework.kafka.core.DefaultKafkaConsumerFactory +import org.springframework.kafka.core.DefaultKafkaProducerFactory +import org.springframework.kafka.core.KafkaTemplate +import org.springframework.kafka.core.ProducerFactory +import org.springframework.kafka.listener.* +import org.springframework.kafka.test.EmbeddedKafkaBroker +import org.springframework.kafka.test.context.EmbeddedKafka +import org.springframework.test.annotation.DirtiesContext +import org.springframework.test.context.junit.jupiter.SpringJUnitConfig +import java.lang.Exception +import java.util.concurrent.CountDownLatch + +@SpringJUnitConfig +@DirtiesContext +@EmbeddedKafka(topics = ["kotlinTestTopic1", "kotlinBatchTestTopic1", "kotlinTestTopic2", "kotlinBatchTestTopic2"]) +abstract class EnableKafkaKotlinTests { + + @Autowired + protected lateinit var config: Config + + @Autowired + protected lateinit var template: KafkaTemplate + + @Configuration + @EnableKafka + class Config { + + @Volatile + lateinit var received: String + + @Volatile + lateinit var batchReceived: String + + @Volatile + var error: Boolean = false + + @Volatile + var batchError: Boolean = false + + val latch1 = CountDownLatch(1) + + val latch2 = CountDownLatch(1) + + val batchLatch1 = CountDownLatch(1) + + val batchLatch2 = CountDownLatch(1) + + @Value("\${" + EmbeddedKafkaBroker.SPRING_EMBEDDED_KAFKA_BROKERS + "}") + private lateinit var brokerAddresses: String + + @Bean + fun kafkaProducerFactory(): ProducerFactory { + val configs = HashMap() + configs[ProducerConfig.BOOTSTRAP_SERVERS_CONFIG] = this.brokerAddresses + configs[ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG] = StringSerializer::class.java + configs[ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG] = StringSerializer::class.java + return DefaultKafkaProducerFactory(configs) + } + + @Bean + fun kafkaConsumerFactory(): ConsumerFactory { + val configs = HashMap() + configs[ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG] = this.brokerAddresses + configs[ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java + configs[ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java + configs[ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG] = false + configs[ConsumerConfig.AUTO_OFFSET_RESET_CONFIG] = "earliest" + return DefaultKafkaConsumerFactory(configs) + } + + @Bean + fun kafkaTemplate(): KafkaTemplate { + return KafkaTemplate(kafkaProducerFactory()) + } + + val errorHandler = object: CommonErrorHandler { + override fun handleOne( + thrownException: Exception, + record: ConsumerRecord<*, *>, + consumer: Consumer<*, *>, + container: MessageListenerContainer + ): Boolean { + error = true + latch2.countDown() + return true + } + + override fun handleBatch( + thrownException: Exception, + recs: ConsumerRecords<*, *>, + consumer: Consumer<*, *>, + container: MessageListenerContainer, + invokeListener: Runnable + ) { + if (!recs.isEmpty) { + batchError = true; + batchLatch2.countDown() + } + } + } + + @Bean + fun kafkaListenerContainerFactory(): ConcurrentKafkaListenerContainerFactory { + val factory: ConcurrentKafkaListenerContainerFactory + = ConcurrentKafkaListenerContainerFactory() + factory.consumerFactory = kafkaConsumerFactory() + factory.setCommonErrorHandler(errorHandler) + return factory + } + + @Bean + fun kafkaBatchListenerContainerFactory(): ConcurrentKafkaListenerContainerFactory { + val factory: ConcurrentKafkaListenerContainerFactory + = ConcurrentKafkaListenerContainerFactory() + factory.isBatchListener = true + factory.consumerFactory = kafkaConsumerFactory() + factory.setCommonErrorHandler(errorHandler) + return factory + } + + @KafkaListener(id = "kotlin", topics = ["kotlinTestTopic1"], containerFactory = "kafkaListenerContainerFactory") + fun listen(value: String) { + this.received = value + this.latch1.countDown() + } + + @KafkaListener(id = "kotlin-batch", topics = ["kotlinBatchTestTopic1"], containerFactory = "kafkaBatchListenerContainerFactory") + fun batchListen(values: List>) { + this.batchReceived = values.first().value() + this.batchLatch1.countDown() + } + + @Bean + fun checkedEx(kafkaListenerContainerFactory : ConcurrentKafkaListenerContainerFactory) : + ConcurrentMessageListenerContainer { + + val container = kafkaListenerContainerFactory.createContainer("kotlinTestTopic2") + container.containerProperties.setGroupId("checkedEx") + container.containerProperties.messageListener = MessageListener { + if (it.value() == "fail") { + throw Exception("checked") + } + } + return container; + } + + @Bean + fun batchCheckedEx(kafkaBatchListenerContainerFactory : + ConcurrentKafkaListenerContainerFactory) : + ConcurrentMessageListenerContainer { + + val container = kafkaBatchListenerContainerFactory.createContainer("kotlinBatchTestTopic2") + container.containerProperties.setGroupId("batchCheckedEx") + container.containerProperties.messageListener = BatchMessageListener { + if (it.first().value() == "fail") { + throw Exception("checked") + } + } + return container; + } + + } + +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/Hello.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/Hello.kt new file mode 100644 index 0000000..ce6c583 --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/Hello.kt @@ -0,0 +1,35 @@ +package org.collaborators.paymentslab.payment.infrastructure.kafka + +import org.assertj.core.api.Assertions +import org.junit.jupiter.api.Test +import java.util.concurrent.TimeUnit + +class Hello: EnableKafkaKotlinTests() { + @Test + fun `test listener`() { + this.template.send("kotlinTestTopic1", "foo") + Assertions.assertThat(this.config.latch1.await(10, TimeUnit.SECONDS)).isTrue() + Assertions.assertThat(this.config.received).isEqualTo("foo") + } + + @Test + fun `test checkedEx`() { + this.template.send("kotlinTestTopic2", "fail") + Assertions.assertThat(this.config.latch2.await(10, TimeUnit.SECONDS)).isTrue() + Assertions.assertThat(this.config.error).isTrue() + } + + @Test + fun `test batch listener`() { + this.template.send("kotlinBatchTestTopic1", "foo") + Assertions.assertThat(this.config.batchLatch1.await(10, TimeUnit.SECONDS)).isTrue() + Assertions.assertThat(this.config.batchReceived).isEqualTo("foo") + } + + @Test + fun `test batch checkedEx`() { + this.template.send("kotlinBatchTestTopic2", "fail") + Assertions.assertThat(this.config.batchLatch2.await(10, TimeUnit.SECONDS)).isTrue() + Assertions.assertThat(this.config.batchError).isTrue() + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/KafkaTestConfig.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/KafkaTestConfig.kt new file mode 100644 index 0000000..b34bdfe --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/KafkaTestConfig.kt @@ -0,0 +1,165 @@ +package org.collaborators.paymentslab.payment.infrastructure.kafka + +import org.apache.kafka.clients.consumer.Consumer +import org.apache.kafka.clients.consumer.ConsumerConfig +import org.apache.kafka.clients.consumer.ConsumerRecord +import org.apache.kafka.clients.consumer.ConsumerRecords +import org.apache.kafka.clients.producer.ProducerConfig +import org.apache.kafka.common.serialization.StringDeserializer +import org.apache.kafka.common.serialization.StringSerializer +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.kafka.annotation.EnableKafka +import org.springframework.kafka.annotation.KafkaListener +import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory +import org.springframework.kafka.core.* +import org.springframework.kafka.listener.BatchMessageListener +import org.springframework.kafka.listener.CommonErrorHandler +import org.springframework.kafka.listener.ConcurrentMessageListenerContainer +import org.springframework.kafka.listener.MessageListener +import org.springframework.kafka.listener.MessageListenerContainer +import org.springframework.kafka.test.EmbeddedKafkaBroker +import java.lang.Exception +import java.util.concurrent.CountDownLatch + +@Configuration +@EnableKafka +class KafkaTestConfig { + + @Volatile + lateinit var received: String + + @Volatile + lateinit var batchReceived: String + + @Volatile + var error: Boolean = false + + @Volatile + var batchError: Boolean = false + + val latch1 = CountDownLatch(1) + + val latch2 = CountDownLatch(1) + + val batchLatch1 = CountDownLatch(1) + + val batchLatch2 = CountDownLatch(1) + + @Value("\${" + EmbeddedKafkaBroker.SPRING_EMBEDDED_KAFKA_BROKERS + "}") + private lateinit var brokerAddresses: String + + @Bean + fun kpf(): ProducerFactory { + val configs = HashMap() + configs[ProducerConfig.BOOTSTRAP_SERVERS_CONFIG] = this.brokerAddresses + configs[ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG] = StringSerializer::class.java + configs[ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG] = StringSerializer::class.java + return DefaultKafkaProducerFactory(configs) + } + + @Bean + fun kcf(): ConsumerFactory { + val configs = HashMap() + configs[ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG] = this.brokerAddresses + configs[ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java + configs[ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java + configs[ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG] = false + configs[ConsumerConfig.AUTO_OFFSET_RESET_CONFIG] = "earliest" + return DefaultKafkaConsumerFactory(configs) + } + + @Bean + fun kt(): KafkaTemplate { + return KafkaTemplate(kpf()) + } + + val eh = object: CommonErrorHandler { + override fun handleOne( + thrownException: Exception, + record: ConsumerRecord<*, *>, + consumer: Consumer<*, *>, + container: MessageListenerContainer + ): Boolean { + error = true + latch2.countDown() + return true + } + + override fun handleBatch( + thrownException: Exception, + recs: ConsumerRecords<*, *>, + consumer: Consumer<*, *>, + container: MessageListenerContainer, + invokeListener: Runnable + ) { + if (!recs.isEmpty) { + batchError = true; + batchLatch2.countDown() + } + } + } + + @Bean + fun kafkaListenerContainerFactory(): ConcurrentKafkaListenerContainerFactory { + val factory: ConcurrentKafkaListenerContainerFactory + = ConcurrentKafkaListenerContainerFactory() + factory.consumerFactory = kcf() + factory.setCommonErrorHandler(eh) + return factory + } + + @Bean + fun kafkaBatchListenerContainerFactory(): ConcurrentKafkaListenerContainerFactory { + val factory: ConcurrentKafkaListenerContainerFactory + = ConcurrentKafkaListenerContainerFactory() + factory.isBatchListener = true + factory.consumerFactory = kcf() + factory.setCommonErrorHandler(eh) + return factory + } + + @KafkaListener(id = "kotlin", topics = ["kotlinTestTopic1"], containerFactory = "kafkaListenerContainerFactory") + fun listen(value: String) { + this.received = value + this.latch1.countDown() + } + + @KafkaListener(id = "kotlin-batch", topics = ["kotlinBatchTestTopic1"], containerFactory = "kafkaBatchListenerContainerFactory") + fun batchListen(values: List>) { + this.batchReceived = values.first().value() + this.batchLatch1.countDown() + } + + @Bean + fun checkedEx(kafkaListenerContainerFactory : ConcurrentKafkaListenerContainerFactory) : + ConcurrentMessageListenerContainer { + + val container = kafkaListenerContainerFactory.createContainer("kotlinTestTopic2") + container.containerProperties.setGroupId("checkedEx") + container.containerProperties.messageListener = MessageListener { + if (it.value() == "fail") { + throw Exception("checked") + } + } + return container; + } + + @Bean + fun batchCheckedEx(kafkaBatchListenerContainerFactory : + ConcurrentKafkaListenerContainerFactory + ) : + ConcurrentMessageListenerContainer { + + val container = kafkaBatchListenerContainerFactory.createContainer("kotlinBatchTestTopic2") + container.containerProperties.setGroupId("batchCheckedEx") + container.containerProperties.messageListener = BatchMessageListener { + if (it.first().value() == "fail") { + throw Exception("checked") + } + } + return container + } + +} \ No newline at end of file From bbfcba875698f1b69a52317b08d8a659f419acd0 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Mon, 27 Nov 2023 23:53:06 +0900 Subject: [PATCH 05/16] =?UTF-8?q?Refactor:=20KafkaTemplateWrapper=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=ED=95=98=EA=B3=A0=20=EC=8A=A4=ED=94=84?= =?UTF-8?q?=EB=A7=81=20kafka=20test=EB=A1=9C=20=EB=8C=80=EC=B2=B4=ED=95=98?= =?UTF-8?q?=EC=97=AC=20kafkaTemplate=EB=A5=BC=20=EA=B7=B8=EB=8C=80?= =?UTF-8?q?=EB=A1=9C=20=EC=82=AC=EC=9A=A9=ED=95=98=EB=8A=94=20=EB=B0=A9?= =?UTF-8?q?=ED=96=A5=EC=9C=BC=EB=A1=9C=20=EC=A0=84=ED=99=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit dip를 활용하여, 라이브러리 코드를 직접 사용하지 않게하면, 테스트 코드를 작성하기 쉽게 하여 개발자가 작성한 코드를 레거시 코드가 되지 않게 해준다. 하지만, kafkaTemplate의 경우, 스프링 진영에서 제공하는 embededKafka 환경을 통해, 직접 카프카 브로커 서버를 의존하지 않고도 충분히 테스트를 위한 mock 브로커 서버를 제공해준다. --- .../paymentslab/AbstractApiTest.kt | 21 +- .../kafka/EnableKafkaKotlinTests.kt | 181 ------------------ .../payment/infrastructure/kafka/Hello.kt | 35 ---- .../infrastructure/kafka/KafkaTestConfig.kt | 165 ---------------- .../PaymentModuleConfiguration.kt | 4 +- .../DefaultStringKafkaTemplateWrapper.kt | 11 -- .../TossPaymentsTransactionEventPublisher.kt | 8 +- 7 files changed, 12 insertions(+), 413 deletions(-) delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/EnableKafkaKotlinTests.kt delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/Hello.kt delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/KafkaTestConfig.kt delete mode 100644 payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/DefaultStringKafkaTemplateWrapper.kt diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt index 2fa5313..a7840d6 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt @@ -8,19 +8,16 @@ import org.collaborator.paymentlab.common.URI_SCHEME import org.collaborators.paymentslab.account.domain.Account import org.collaborators.paymentslab.account.domain.PasswordEncrypt import org.collaborators.paymentslab.account.domain.TokenGenerator -import org.collaborators.paymentslab.payment.infrastructure.kafka.StringKafkaTemplateWrapper -import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.kotlin.any -import org.mockito.kotlin.doNothing import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest -import org.springframework.boot.test.mock.mockito.MockBean -import org.springframework.kafka.core.KafkaTemplate +import org.springframework.kafka.core.* +import org.springframework.kafka.listener.* +import org.springframework.kafka.test.context.EmbeddedKafka import org.springframework.restdocs.RestDocumentationExtension import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor import org.springframework.restdocs.operation.preprocess.Preprocessors @@ -31,12 +28,14 @@ import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc @TestInstance(TestInstance.Lifecycle.PER_CLASS) +@EmbeddedKafka(partitions = 1, brokerProperties = ["listeners=PLAINTEXT://localhost:29092"], ports = [9092]) @AutoConfigureMockMvc @AutoConfigureRestDocs(uriScheme = URI_SCHEME, uriHost = URI_HOST, uriPort = URI_PORT) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @ExtendWith(RestDocumentationExtension::class) @ActiveProfiles("test") abstract class AbstractApiTest { + @Autowired protected lateinit var mockMvc: MockMvc @@ -48,9 +47,8 @@ abstract class AbstractApiTest { @Autowired lateinit var encrypt: PasswordEncrypt - @MockBean - protected lateinit var stringKafkaTemplateWrapper: StringKafkaTemplateWrapper - + @Autowired + protected lateinit var kafkaTemplate: KafkaTemplate @Value("\${uri.scheme}") protected lateinit var scheme: String @@ -64,11 +62,6 @@ abstract class AbstractApiTest { @Value("\${admin.key}") protected lateinit var adminKey: String - @BeforeEach - fun setUp() { - doNothing().`when`(stringKafkaTemplateWrapper).send(any(), any()) - } - protected fun testEntityForRegister(email: String): Account { val account = Account.register( email, diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/EnableKafkaKotlinTests.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/EnableKafkaKotlinTests.kt deleted file mode 100644 index 0d1fb35..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/EnableKafkaKotlinTests.kt +++ /dev/null @@ -1,181 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure.kafka - -import org.apache.kafka.clients.consumer.Consumer -import org.apache.kafka.clients.consumer.ConsumerConfig -import org.apache.kafka.clients.consumer.ConsumerRecord -import org.apache.kafka.clients.consumer.ConsumerRecords -import org.apache.kafka.clients.producer.ProducerConfig -import org.apache.kafka.common.serialization.StringDeserializer -import org.apache.kafka.common.serialization.StringSerializer -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.kafka.annotation.EnableKafka -import org.springframework.kafka.annotation.KafkaListener -import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory -import org.springframework.kafka.core.ConsumerFactory -import org.springframework.kafka.core.DefaultKafkaConsumerFactory -import org.springframework.kafka.core.DefaultKafkaProducerFactory -import org.springframework.kafka.core.KafkaTemplate -import org.springframework.kafka.core.ProducerFactory -import org.springframework.kafka.listener.* -import org.springframework.kafka.test.EmbeddedKafkaBroker -import org.springframework.kafka.test.context.EmbeddedKafka -import org.springframework.test.annotation.DirtiesContext -import org.springframework.test.context.junit.jupiter.SpringJUnitConfig -import java.lang.Exception -import java.util.concurrent.CountDownLatch - -@SpringJUnitConfig -@DirtiesContext -@EmbeddedKafka(topics = ["kotlinTestTopic1", "kotlinBatchTestTopic1", "kotlinTestTopic2", "kotlinBatchTestTopic2"]) -abstract class EnableKafkaKotlinTests { - - @Autowired - protected lateinit var config: Config - - @Autowired - protected lateinit var template: KafkaTemplate - - @Configuration - @EnableKafka - class Config { - - @Volatile - lateinit var received: String - - @Volatile - lateinit var batchReceived: String - - @Volatile - var error: Boolean = false - - @Volatile - var batchError: Boolean = false - - val latch1 = CountDownLatch(1) - - val latch2 = CountDownLatch(1) - - val batchLatch1 = CountDownLatch(1) - - val batchLatch2 = CountDownLatch(1) - - @Value("\${" + EmbeddedKafkaBroker.SPRING_EMBEDDED_KAFKA_BROKERS + "}") - private lateinit var brokerAddresses: String - - @Bean - fun kafkaProducerFactory(): ProducerFactory { - val configs = HashMap() - configs[ProducerConfig.BOOTSTRAP_SERVERS_CONFIG] = this.brokerAddresses - configs[ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG] = StringSerializer::class.java - configs[ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG] = StringSerializer::class.java - return DefaultKafkaProducerFactory(configs) - } - - @Bean - fun kafkaConsumerFactory(): ConsumerFactory { - val configs = HashMap() - configs[ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG] = this.brokerAddresses - configs[ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java - configs[ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java - configs[ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG] = false - configs[ConsumerConfig.AUTO_OFFSET_RESET_CONFIG] = "earliest" - return DefaultKafkaConsumerFactory(configs) - } - - @Bean - fun kafkaTemplate(): KafkaTemplate { - return KafkaTemplate(kafkaProducerFactory()) - } - - val errorHandler = object: CommonErrorHandler { - override fun handleOne( - thrownException: Exception, - record: ConsumerRecord<*, *>, - consumer: Consumer<*, *>, - container: MessageListenerContainer - ): Boolean { - error = true - latch2.countDown() - return true - } - - override fun handleBatch( - thrownException: Exception, - recs: ConsumerRecords<*, *>, - consumer: Consumer<*, *>, - container: MessageListenerContainer, - invokeListener: Runnable - ) { - if (!recs.isEmpty) { - batchError = true; - batchLatch2.countDown() - } - } - } - - @Bean - fun kafkaListenerContainerFactory(): ConcurrentKafkaListenerContainerFactory { - val factory: ConcurrentKafkaListenerContainerFactory - = ConcurrentKafkaListenerContainerFactory() - factory.consumerFactory = kafkaConsumerFactory() - factory.setCommonErrorHandler(errorHandler) - return factory - } - - @Bean - fun kafkaBatchListenerContainerFactory(): ConcurrentKafkaListenerContainerFactory { - val factory: ConcurrentKafkaListenerContainerFactory - = ConcurrentKafkaListenerContainerFactory() - factory.isBatchListener = true - factory.consumerFactory = kafkaConsumerFactory() - factory.setCommonErrorHandler(errorHandler) - return factory - } - - @KafkaListener(id = "kotlin", topics = ["kotlinTestTopic1"], containerFactory = "kafkaListenerContainerFactory") - fun listen(value: String) { - this.received = value - this.latch1.countDown() - } - - @KafkaListener(id = "kotlin-batch", topics = ["kotlinBatchTestTopic1"], containerFactory = "kafkaBatchListenerContainerFactory") - fun batchListen(values: List>) { - this.batchReceived = values.first().value() - this.batchLatch1.countDown() - } - - @Bean - fun checkedEx(kafkaListenerContainerFactory : ConcurrentKafkaListenerContainerFactory) : - ConcurrentMessageListenerContainer { - - val container = kafkaListenerContainerFactory.createContainer("kotlinTestTopic2") - container.containerProperties.setGroupId("checkedEx") - container.containerProperties.messageListener = MessageListener { - if (it.value() == "fail") { - throw Exception("checked") - } - } - return container; - } - - @Bean - fun batchCheckedEx(kafkaBatchListenerContainerFactory : - ConcurrentKafkaListenerContainerFactory) : - ConcurrentMessageListenerContainer { - - val container = kafkaBatchListenerContainerFactory.createContainer("kotlinBatchTestTopic2") - container.containerProperties.setGroupId("batchCheckedEx") - container.containerProperties.messageListener = BatchMessageListener { - if (it.first().value() == "fail") { - throw Exception("checked") - } - } - return container; - } - - } - -} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/Hello.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/Hello.kt deleted file mode 100644 index ce6c583..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/Hello.kt +++ /dev/null @@ -1,35 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure.kafka - -import org.assertj.core.api.Assertions -import org.junit.jupiter.api.Test -import java.util.concurrent.TimeUnit - -class Hello: EnableKafkaKotlinTests() { - @Test - fun `test listener`() { - this.template.send("kotlinTestTopic1", "foo") - Assertions.assertThat(this.config.latch1.await(10, TimeUnit.SECONDS)).isTrue() - Assertions.assertThat(this.config.received).isEqualTo("foo") - } - - @Test - fun `test checkedEx`() { - this.template.send("kotlinTestTopic2", "fail") - Assertions.assertThat(this.config.latch2.await(10, TimeUnit.SECONDS)).isTrue() - Assertions.assertThat(this.config.error).isTrue() - } - - @Test - fun `test batch listener`() { - this.template.send("kotlinBatchTestTopic1", "foo") - Assertions.assertThat(this.config.batchLatch1.await(10, TimeUnit.SECONDS)).isTrue() - Assertions.assertThat(this.config.batchReceived).isEqualTo("foo") - } - - @Test - fun `test batch checkedEx`() { - this.template.send("kotlinBatchTestTopic2", "fail") - Assertions.assertThat(this.config.batchLatch2.await(10, TimeUnit.SECONDS)).isTrue() - Assertions.assertThat(this.config.batchError).isTrue() - } -} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/KafkaTestConfig.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/KafkaTestConfig.kt deleted file mode 100644 index b34bdfe..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/KafkaTestConfig.kt +++ /dev/null @@ -1,165 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure.kafka - -import org.apache.kafka.clients.consumer.Consumer -import org.apache.kafka.clients.consumer.ConsumerConfig -import org.apache.kafka.clients.consumer.ConsumerRecord -import org.apache.kafka.clients.consumer.ConsumerRecords -import org.apache.kafka.clients.producer.ProducerConfig -import org.apache.kafka.common.serialization.StringDeserializer -import org.apache.kafka.common.serialization.StringSerializer -import org.springframework.beans.factory.annotation.Value -import org.springframework.context.annotation.Bean -import org.springframework.context.annotation.Configuration -import org.springframework.kafka.annotation.EnableKafka -import org.springframework.kafka.annotation.KafkaListener -import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory -import org.springframework.kafka.core.* -import org.springframework.kafka.listener.BatchMessageListener -import org.springframework.kafka.listener.CommonErrorHandler -import org.springframework.kafka.listener.ConcurrentMessageListenerContainer -import org.springframework.kafka.listener.MessageListener -import org.springframework.kafka.listener.MessageListenerContainer -import org.springframework.kafka.test.EmbeddedKafkaBroker -import java.lang.Exception -import java.util.concurrent.CountDownLatch - -@Configuration -@EnableKafka -class KafkaTestConfig { - - @Volatile - lateinit var received: String - - @Volatile - lateinit var batchReceived: String - - @Volatile - var error: Boolean = false - - @Volatile - var batchError: Boolean = false - - val latch1 = CountDownLatch(1) - - val latch2 = CountDownLatch(1) - - val batchLatch1 = CountDownLatch(1) - - val batchLatch2 = CountDownLatch(1) - - @Value("\${" + EmbeddedKafkaBroker.SPRING_EMBEDDED_KAFKA_BROKERS + "}") - private lateinit var brokerAddresses: String - - @Bean - fun kpf(): ProducerFactory { - val configs = HashMap() - configs[ProducerConfig.BOOTSTRAP_SERVERS_CONFIG] = this.brokerAddresses - configs[ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG] = StringSerializer::class.java - configs[ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG] = StringSerializer::class.java - return DefaultKafkaProducerFactory(configs) - } - - @Bean - fun kcf(): ConsumerFactory { - val configs = HashMap() - configs[ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG] = this.brokerAddresses - configs[ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java - configs[ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG] = StringDeserializer::class.java - configs[ConsumerConfig.ENABLE_AUTO_COMMIT_CONFIG] = false - configs[ConsumerConfig.AUTO_OFFSET_RESET_CONFIG] = "earliest" - return DefaultKafkaConsumerFactory(configs) - } - - @Bean - fun kt(): KafkaTemplate { - return KafkaTemplate(kpf()) - } - - val eh = object: CommonErrorHandler { - override fun handleOne( - thrownException: Exception, - record: ConsumerRecord<*, *>, - consumer: Consumer<*, *>, - container: MessageListenerContainer - ): Boolean { - error = true - latch2.countDown() - return true - } - - override fun handleBatch( - thrownException: Exception, - recs: ConsumerRecords<*, *>, - consumer: Consumer<*, *>, - container: MessageListenerContainer, - invokeListener: Runnable - ) { - if (!recs.isEmpty) { - batchError = true; - batchLatch2.countDown() - } - } - } - - @Bean - fun kafkaListenerContainerFactory(): ConcurrentKafkaListenerContainerFactory { - val factory: ConcurrentKafkaListenerContainerFactory - = ConcurrentKafkaListenerContainerFactory() - factory.consumerFactory = kcf() - factory.setCommonErrorHandler(eh) - return factory - } - - @Bean - fun kafkaBatchListenerContainerFactory(): ConcurrentKafkaListenerContainerFactory { - val factory: ConcurrentKafkaListenerContainerFactory - = ConcurrentKafkaListenerContainerFactory() - factory.isBatchListener = true - factory.consumerFactory = kcf() - factory.setCommonErrorHandler(eh) - return factory - } - - @KafkaListener(id = "kotlin", topics = ["kotlinTestTopic1"], containerFactory = "kafkaListenerContainerFactory") - fun listen(value: String) { - this.received = value - this.latch1.countDown() - } - - @KafkaListener(id = "kotlin-batch", topics = ["kotlinBatchTestTopic1"], containerFactory = "kafkaBatchListenerContainerFactory") - fun batchListen(values: List>) { - this.batchReceived = values.first().value() - this.batchLatch1.countDown() - } - - @Bean - fun checkedEx(kafkaListenerContainerFactory : ConcurrentKafkaListenerContainerFactory) : - ConcurrentMessageListenerContainer { - - val container = kafkaListenerContainerFactory.createContainer("kotlinTestTopic2") - container.containerProperties.setGroupId("checkedEx") - container.containerProperties.messageListener = MessageListener { - if (it.value() == "fail") { - throw Exception("checked") - } - } - return container; - } - - @Bean - fun batchCheckedEx(kafkaBatchListenerContainerFactory : - ConcurrentKafkaListenerContainerFactory - ) : - ConcurrentMessageListenerContainer { - - val container = kafkaBatchListenerContainerFactory.createContainer("kotlinBatchTestTopic2") - container.containerProperties.setGroupId("batchCheckedEx") - container.containerProperties.messageListener = BatchMessageListener { - if (it.first().value() == "fail") { - throw Exception("checked") - } - } - return container - } - -} \ No newline at end of file diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/PaymentModuleConfiguration.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/PaymentModuleConfiguration.kt index 824582e..5a6ff65 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/PaymentModuleConfiguration.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/PaymentModuleConfiguration.kt @@ -3,7 +3,6 @@ package org.collaborators.paymentslab.payment.infrastructure import org.collaborators.paymentslab.payment.infrastructure.jpa.PaymentOrderRepositoryAdapter import org.collaborators.paymentslab.payment.infrastructure.jpa.TossPaymentHistoryRepositoryAdapter import org.collaborators.paymentslab.payment.infrastructure.jpa.TossPaymentsRepositoryAdapter -import org.collaborators.paymentslab.payment.infrastructure.kafka.DefaultStringKafkaTemplateWrapper import org.collaborators.paymentslab.payment.infrastructure.log.AsyncAppenderPaymentTransactionLogProcessor import org.collaborators.paymentslab.payment.infrastructure.tosspayments.* import org.springframework.context.annotation.Configuration @@ -21,8 +20,7 @@ import org.springframework.context.annotation.Import TossPaymentsValidator::class, TossPaymentsKeyInApprovalProcessor::class, TossPaymentsPaymentOrderProcessor::class, - AsyncAppenderPaymentTransactionLogProcessor::class, - DefaultStringKafkaTemplateWrapper::class + AsyncAppenderPaymentTransactionLogProcessor::class ]) @Configuration class PaymentModuleConfiguration \ No newline at end of file diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/DefaultStringKafkaTemplateWrapper.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/DefaultStringKafkaTemplateWrapper.kt deleted file mode 100644 index bb49db6..0000000 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/DefaultStringKafkaTemplateWrapper.kt +++ /dev/null @@ -1,11 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure.kafka - -import org.springframework.kafka.core.KafkaTemplate - -class DefaultStringKafkaTemplateWrapper( - private val kafkaTemplate: KafkaTemplate -): StringKafkaTemplateWrapper { - override fun send(topic: String, data: String) { - kafkaTemplate.send(topic, data) - } -} \ No newline at end of file diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsTransactionEventPublisher.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsTransactionEventPublisher.kt index 42e2473..82a69a9 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsTransactionEventPublisher.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsTransactionEventPublisher.kt @@ -8,12 +8,12 @@ import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository import org.collaborators.paymentslab.payment.domain.repository.TossPaymentsRepository import org.collaborators.paymentslab.payment.infrastructure.getCurrentAccount -import org.collaborators.paymentslab.payment.infrastructure.kafka.StringKafkaTemplateWrapper import org.collaborators.paymentslab.payment.infrastructure.log.AsyncAppenderPaymentTransactionLogProcessor import org.collaborators.paymentslab.payment.infrastructure.tosspayments.exception.InvalidPaymentOrderException +import org.springframework.kafka.core.KafkaTemplate class TossPaymentsTransactionEventPublisher( - private val stringKafkaTemplateWrapper: StringKafkaTemplateWrapper, + private val kafkaTemplate: KafkaTemplate, private val asyncLogProcessor: AsyncAppenderPaymentTransactionLogProcessor, private val tossPaymentsRepository: TossPaymentsRepository, private val paymentOrderRepository: PaymentOrderRepository, @@ -31,7 +31,7 @@ class TossPaymentsTransactionEventPublisher( asyncLogProcessor.process(it as PaymentResultEvent) val eventWithClassType = DomainEventTypeParser.parseSimpleName(objectMapper.writeValueAsString(it), it::class.java) - stringKafkaTemplateWrapper.send(paymentProperties.paymentTransactionTopicName, eventWithClassType) + kafkaTemplate.send(paymentProperties.paymentTransactionTopicName, eventWithClassType) } } @@ -46,7 +46,7 @@ class TossPaymentsTransactionEventPublisher( paymentOrder.ready() paymentOrder.pollAllEvents().forEach { asyncLogProcessor.process(it as PaymentOrderRecordEvent) - stringKafkaTemplateWrapper.send(paymentProperties.paymentTransactionTopicName, objectMapper.writeValueAsString(it)) + kafkaTemplate.send(paymentProperties.paymentTransactionTopicName, objectMapper.writeValueAsString(it)) } } } \ No newline at end of file From 3cbe5f8934a74717393103c46521e5d164f1c020 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Tue, 28 Nov 2023 12:38:49 +0900 Subject: [PATCH 06/16] =?UTF-8?q?Test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=B9=8C=EB=93=9C=20=EC=86=8D=EB=8F=84=EB=A5=BC=20=EB=86=92?= =?UTF-8?q?=EC=9D=B4=EA=B8=B0=EC=9C=84=ED=95=B4,=20h2=EB=A5=BC=20=EC=9D=98?= =?UTF-8?q?=EC=A1=B4=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8A=94=20inMemoryRepo?= =?UTF-8?q?sitory=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InMemoryPaymentOrderRepository.kt | 12 ++++++ .../InMemoryPaymentOrderRepositoryAdapter.kt | 20 ++++++++++ .../inmemory/core/IdGenerator.kt | 5 +++ .../inmemory/core/IdGeneratorFactory.kt | 11 ++++++ .../inmemory/core/Identified.kt | 5 +++ .../inmemory/core/InMemoryRepository.kt | 37 +++++++++++++++++++ .../core/SequentialLongIdGenerator.kt | 9 +++++ 7 files changed, 99 insertions(+) create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepository.kt create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepositoryAdapter.kt create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGenerator.kt create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGeneratorFactory.kt create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/Identified.kt create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/InMemoryRepository.kt create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/SequentialLongIdGenerator.kt diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepository.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepository.kt new file mode 100644 index 0000000..00d947e --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepository.kt @@ -0,0 +1,12 @@ +package org.collaborators.paymentslab.payment.infrastructure.inmemory + +import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder +import org.collaborators.paymentslab.payment.infrastructure.inmemory.core.IdGenerator +import org.collaborators.paymentslab.payment.infrastructure.inmemory.core.IdGeneratorFactory +import org.collaborators.paymentslab.payment.infrastructure.inmemory.core.InMemoryRepository +import org.springframework.stereotype.Component +import java.util.concurrent.ConcurrentHashMap + +@Component +class InMemoryPaymentOrderRepository: InMemoryRepository(Long::class.java) { +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepositoryAdapter.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepositoryAdapter.kt new file mode 100644 index 0000000..9c38a25 --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepositoryAdapter.kt @@ -0,0 +1,20 @@ +package org.collaborators.paymentslab.payment.infrastructure.inmemory + +import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder +import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository +import org.springframework.context.annotation.Profile +import org.springframework.stereotype.Repository + +@Repository +@Profile(value = ["test"]) +class InMemoryPaymentOrderRepositoryAdapter( + private val inMemoryPaymentOrderRepository: InMemoryPaymentOrderRepository +): PaymentOrderRepository { + override fun save(entity: PaymentOrder): PaymentOrder { + return inMemoryPaymentOrderRepository.save(entity) + } + + override fun findById(id: Long): PaymentOrder { + return inMemoryPaymentOrderRepository.findById(id)!! + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGenerator.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGenerator.kt new file mode 100644 index 0000000..f2006bc --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGenerator.kt @@ -0,0 +1,5 @@ +package org.collaborators.paymentslab.payment.infrastructure.inmemory.core + +interface IdGenerator { + fun generateId(): T +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGeneratorFactory.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGeneratorFactory.kt new file mode 100644 index 0000000..71c3420 --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGeneratorFactory.kt @@ -0,0 +1,11 @@ +package org.collaborators.paymentslab.payment.infrastructure.inmemory.core + +class IdGeneratorFactory { + companion object { + fun create(idClass: Class): IdGenerator { + if (idClass.name == Long::class.java.name) + return SequentialLongIdGenerator() as IdGenerator + else throw UnsupportedOperationException() + } + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/Identified.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/Identified.kt new file mode 100644 index 0000000..861ae55 --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/Identified.kt @@ -0,0 +1,5 @@ +package org.collaborators.paymentslab.payment.infrastructure.inmemory.core + +interface Identified { + fun getId(): ID +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/InMemoryRepository.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/InMemoryRepository.kt new file mode 100644 index 0000000..c0e119f --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/InMemoryRepository.kt @@ -0,0 +1,37 @@ +package org.collaborators.paymentslab.payment.infrastructure.inmemory.core + +import jakarta.persistence.Id +import org.collaborator.paymentlab.common.domain.AbstractAggregateRoot +import java.util.concurrent.ConcurrentHashMap + +abstract class InMemoryRepository, ID>(idTypeParameter: Class) { + private val storage: MutableMap = ConcurrentHashMap() + private val idGenerator: IdGenerator = IdGeneratorFactory.create(idTypeParameter) + + fun findById(id: ID): T? { + if (id == null) throw AssertionError() + return storage[id] + } + + fun save(entity: T): T { + if (entity.id() == null) { + val newId: ID = idGenerator.generateId() + assignNewId(newId, entity) + } + storage[entity.id()!!] = entity + return entity + } + + private fun assignNewId(id: ID, entity: T) { + for (field in entity::class.java.declaredFields) { + if (field.isAnnotationPresent(Id::class.java)) { + field.isAccessible = true + try { + field[entity] = id + } catch (e: IllegalAccessException) { + throw RuntimeException(e) + } + } + } + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/SequentialLongIdGenerator.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/SequentialLongIdGenerator.kt new file mode 100644 index 0000000..0721c6f --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/SequentialLongIdGenerator.kt @@ -0,0 +1,9 @@ +package org.collaborators.paymentslab.payment.infrastructure.inmemory.core + +class SequentialLongIdGenerator: IdGenerator { + private var sequence = 1L; + + override fun generateId(): Long { + return this.sequence++ + } +} \ No newline at end of file From cfc54c3f2bf84fbf1f0e1b0b2379def7ea3d3903 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Tue, 28 Nov 2023 12:42:19 +0900 Subject: [PATCH 07/16] =?UTF-8?q?Refactor:=20Entity=EC=9D=98=20=EA=B3=B5?= =?UTF-8?q?=ED=86=B5=EC=9A=94=EC=86=8C=20id=EB=A5=BC=20AbstractAggregateRo?= =?UTF-8?q?ot=EC=97=90=EC=84=9C=20=EA=B3=B5=ED=86=B5=EC=9C=BC=EB=A1=9C=20?= =?UTF-8?q?=EC=A1=B0=ED=9A=8C=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Entity는 도메인 종류에 상관없이 각 객체를 식별할 수 있는 id 필드가 있기도 하지만, 이렇게 공통 요소를 공통 추상 클래스에 분류해놓으면 테스트를 위한 코드나 공통 유틸코드등을 작성하기가 좀 더 용이해진다. --- .../paymentslab/account/domain/Account.kt | 8 ++++-- .../common/domain/AbstractAggregateRoot.kt | 4 ++- .../payment/domain/PaymentOrderRecordEvent.kt | 2 +- .../payment/domain/entity/PaymentOrder.kt | 8 ++++-- .../payment/domain/entity/TossPayments.kt | 8 ++++-- .../jpa/PaymentOrderRepositoryAdapter.kt | 2 ++ .../TossPaymentsKeyInApprovalProcessor.kt | 6 ++--- .../tosspayments/TossPaymentsProcessor.kt | 26 +++++++++---------- .../tosspayments/TossPaymentsRestClient.kt | 7 +++-- .../tosspayments/TossPaymentsValidator.kt | 6 ++--- 10 files changed, 46 insertions(+), 31 deletions(-) diff --git a/account-api/account-domain/src/main/kotlin/org/collaborators/paymentslab/account/domain/Account.kt b/account-api/account-domain/src/main/kotlin/org/collaborators/paymentslab/account/domain/Account.kt index 7a3a79b..99232ee 100644 --- a/account-api/account-domain/src/main/kotlin/org/collaborators/paymentslab/account/domain/Account.kt +++ b/account-api/account-domain/src/main/kotlin/org/collaborators/paymentslab/account/domain/Account.kt @@ -12,7 +12,7 @@ import java.util.* @Table(name = "ACCOUNTS") class Account protected constructor( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Long? = null, + private val id: Long? = null, var accountKey: String = KeyGenerator.generate("act_"), var email: String, var username: String, @@ -27,7 +27,7 @@ class Account protected constructor( @ElementCollection(fetch = FetchType.EAGER) @Enumerated(EnumType.STRING) var roles: MutableSet = hashSetOf(Role.USER) -): AbstractAggregateRoot() { +): AbstractAggregateRoot() { init { generateEmailCheckToken() @@ -36,6 +36,10 @@ class Account protected constructor( var password: String? = null private set + override fun id(): Long? { + return this.id + } + companion object { fun register( email: String, encodedPassword: String, username: String, phoneNumber: String, diff --git a/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/AbstractAggregateRoot.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/AbstractAggregateRoot.kt index 8bc695f..e86f88a 100644 --- a/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/AbstractAggregateRoot.kt +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/AbstractAggregateRoot.kt @@ -2,9 +2,11 @@ package org.collaborator.paymentlab.common.domain import java.util.Collections -abstract class AbstractAggregateRoot { +abstract class AbstractAggregateRoot { private val events = mutableListOf() + abstract fun id(): T? + protected fun registerEvent(domainEvent: DomainEvent) { this.events.add(domainEvent) } diff --git a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/PaymentOrderRecordEvent.kt b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/PaymentOrderRecordEvent.kt index 856514f..6554d59 100644 --- a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/PaymentOrderRecordEvent.kt +++ b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/PaymentOrderRecordEvent.kt @@ -13,7 +13,7 @@ class PaymentOrderRecordEvent( private val typeSimpleName: String = PaymentOrderRecordEvent::class.simpleName!! ): DomainEvent { constructor(paymentOrder: PaymentOrder): this( - paymentOrder.id!!, + paymentOrder.id()!!, paymentOrder.accountId, paymentOrder.status.name, Date.from(paymentOrder.createAt.atZone(ZoneId.systemDefault()).toInstant()) diff --git a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentOrder.kt b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentOrder.kt index e5e0716..3d16ff5 100644 --- a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentOrder.kt +++ b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentOrder.kt @@ -18,10 +18,14 @@ class PaymentOrder protected constructor( var status: PaymentsStatus, @Column(nullable = false) val createAt: LocalDateTime = LocalDateTime.now(), -): AbstractAggregateRoot() { +): AbstractAggregateRoot() { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Long? = null + private val id: Long? = null + + override fun id(): Long? { + return this.id + } fun ready() { this.status = PaymentsStatus.READY diff --git a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/TossPayments.kt b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/TossPayments.kt index be3b14a..c177b22 100644 --- a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/TossPayments.kt +++ b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/TossPayments.kt @@ -27,10 +27,10 @@ class TossPayments protected constructor( private val createdAt: LocalDateTime? = null, @UpdateTimestamp private val modifiedAt: LocalDateTime? = null -): AbstractAggregateRoot() { +): AbstractAggregateRoot() { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - var id: Long? = null + val id: Long? = null @Column(nullable = false) var accountId: Long? = null @@ -43,6 +43,10 @@ class TossPayments protected constructor( payMethod: PayMethod ) : this(info, cancelInfo, cardInfo, status, payMethod, null, null) + override fun id(): Long { + return this.id!! + } + fun resultOf(accountId: Long, paymentsStatus: PaymentsStatus) { this.accountId = accountId this.status = paymentsStatus.name diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/jpa/PaymentOrderRepositoryAdapter.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/jpa/PaymentOrderRepositoryAdapter.kt index c9c8629..5eb2b37 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/jpa/PaymentOrderRepositoryAdapter.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/jpa/PaymentOrderRepositoryAdapter.kt @@ -3,8 +3,10 @@ package org.collaborators.paymentslab.payment.infrastructure.jpa import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository import org.collaborators.paymentslab.payment.infrastructure.tosspayments.exception.PaymentOrderNotFoundException +import org.springframework.context.annotation.Profile +@Profile(value = ["!test"]) class PaymentOrderRepositoryAdapter( private val jpaPaymentOrderRepository: JpaPaymentOrderRepository ): PaymentOrderRepository { diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt index 8a17467..be3cf36 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt @@ -17,7 +17,7 @@ import java.nio.charset.StandardCharsets import java.util.* class TossPaymentsKeyInApprovalProcessor( - private val restTemplate: TossPaymentsRestClient, + private val tossPaymentsRestClient: TossPaymentsRestClient, private val paymentOrderRepository: PaymentOrderRepository, private val paymentsTransactionEventPublisher: TossPaymentsTransactionEventPublisher, private val paymentProperties: PaymentPropertiesResolver @@ -27,7 +27,7 @@ class TossPaymentsKeyInApprovalProcessor( var result = TossPaymentsApprovalResponse.preResponseOf(paymentOrder, dto) try { val request = createRequest(paymentOrder, dto) - val response = restTemplate.postForEntity("${paymentProperties.url}key-in", request) + val response = tossPaymentsRestClient.keyIn("${paymentProperties.url}key-in", request) if (response.statusCode == HttpStatus.OK && response.hasBody()) { paymentOrder.complete() result = response.body!! @@ -51,7 +51,7 @@ class TossPaymentsKeyInApprovalProcessor( headers.contentType = MediaType.APPLICATION_JSON val account = getCurrentAccount() - val idempotencyKey = "po_${paymentOrder.id}_acc_${account.id}}" + val idempotencyKey = "po_${paymentOrder.id()}_acc_${account.id}}" headers.set("Idempotency-Key", String(Base64.getEncoder().encode(idempotencyKey.toByteArray(StandardCharsets.ISO_8859_1)))) return HttpEntity(dto, headers) diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt index 9e0faee..7f41249 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt @@ -26,18 +26,18 @@ open class TossPaymentsProcessor( tossPaymentsValidator.validate(paymentOrder, amount, orderName) - tossPaymentsKeyInApprovalProcessor.approval( - paymentOrder, - TossPaymentsKeyInDto( - amount, - orderId, - orderName, - cardNumber, - cardExpirationYear, - cardExpirationMonth, - cardPassword, - customerIdentityNumber - ) - ) +// tossPaymentsKeyInApprovalProcessor.approval( +// paymentOrder, +// TossPaymentsKeyInDto( +// amount, +// orderId, +// orderName, +// cardNumber, +// cardExpirationYear, +// cardExpirationMonth, +// cardPassword, +// customerIdentityNumber +// ) +// ) } } \ No newline at end of file diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt index 5783cdf..9fd91a9 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt @@ -6,13 +6,12 @@ import org.springframework.http.ResponseEntity import org.springframework.web.client.RestTemplate class TossPaymentsRestClient( - private val restTemplate: RestTemplate, - private val paymentProperties: PaymentPropertiesResolver + private val restTemplate: RestTemplate ): RestClient { - override fun postForEntity( + override fun keyIn( url: String, request: HttpEntity ): ResponseEntity { - return restTemplate.postForEntity("${paymentProperties.url}key-in", request, TossPaymentsApprovalResponse::class.java) + return restTemplate.postForEntity(url, request, TossPaymentsApprovalResponse::class.java) } } \ No newline at end of file diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsValidator.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsValidator.kt index d9be584..4da17d6 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsValidator.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsValidator.kt @@ -28,19 +28,19 @@ class TossPaymentsValidator { private fun checkAccountId(paymentOrder: PaymentOrder, accountId: Long) { if (paymentOrder.accountId != accountId) { - logAndThrow("invalid accountId from paymentOrderId ${paymentOrder.id}", InvalidPaymentOrderAccountIdException()) + logAndThrow("invalid accountId from paymentOrderId ${paymentOrder.id()}", InvalidPaymentOrderAccountIdException()) } } private fun checkPaymentDetails(paymentOrder: PaymentOrder, amount: Int, orderName: String) { if (paymentOrder.amount != amount || paymentOrder.orderName != orderName || !PaymentsStatus.isInRange(paymentOrder.status)) { - logAndThrow("invalid amount from paymentOrderId ${paymentOrder.id}", InvalidPaymentOrderException()) + logAndThrow("invalid amount from paymentOrderId ${paymentOrder.id()}", InvalidPaymentOrderException()) } } private fun checkPaymentStatus(paymentOrder: PaymentOrder) { statusToException[paymentOrder.status]?.let { - logAndThrow("already ${paymentOrder.status.name.lowercase(Locale.getDefault())} paymentOrderId ${paymentOrder.id}", it) + logAndThrow("already ${paymentOrder.status.name.lowercase(Locale.getDefault())} paymentOrderId ${paymentOrder.id()}", it) } } From e9251bd58a1e862e2b1ac0302ea1d4429f3e4555 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Tue, 28 Nov 2023 12:45:59 +0900 Subject: [PATCH 08/16] =?UTF-8?q?Refactor:=20key-in=20=EC=9A=94=EC=B2=AD?= =?UTF-8?q?=EC=97=90=20=EC=82=AC=EC=9A=A9=EB=90=98=EB=8A=94=20rest=20?= =?UTF-8?q?=ED=81=B4=EB=9D=BC=EC=9D=B4=EC=96=B8=ED=8A=B8=EC=97=90=20url?= =?UTF-8?q?=EC=9D=84=20=EC=9D=98=EC=A1=B4=EC=84=B1=EC=9D=84=20=EA=B0=90?= =?UTF-8?q?=EC=B6=94=EC=A7=80=20=EC=95=8A=EA=B8=B0=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=ED=95=A8=EC=88=98=EC=9D=98=20=ED=8C=8C=EB=9D=BC=EB=AF=B8?= =?UTF-8?q?=ED=84=B0=EB=A1=9C=20=EC=A0=84=EB=8B=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 의존성을 감추면 코드의 의도를 파악하기가 어려워진다. 또한 테스트 코드 작성의 난이도를 높인다. --- .../payment/presentation/PaymentApiTest.kt | 26 +++++++++---------- .../paymentlab/common/domain/RestClient.kt | 2 +- .../kafka/StringKafkaTemplateWrapper.kt | 5 ---- 3 files changed, 14 insertions(+), 19 deletions(-) delete mode 100644 payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/StringKafkaTemplateWrapper.kt diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt index d3d4a27..345e151 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt @@ -43,7 +43,7 @@ class PaymentApiTest @Autowired constructor( val requestDto = MockPayments.testTossPaymentsRequest val paymentOrder = PaymentOrder.newInstance( - account.id!!, + account.id()!!, requestDto.orderName, requestDto.amount ) @@ -54,7 +54,7 @@ class PaymentApiTest @Autowired constructor( this.mockMvc.perform( RestDocumentationRequestBuilders - .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id) + .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id()) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content(reqBody) @@ -79,7 +79,7 @@ class PaymentApiTest @Autowired constructor( val requestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest val paymentOrder = PaymentOrder.newInstance( - account.id!!, + account.id()!!, requestDto.orderName, requestDto.amount ) @@ -90,7 +90,7 @@ class PaymentApiTest @Autowired constructor( this.mockMvc.perform( RestDocumentationRequestBuilders - .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id) + .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id()) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content(reqBody) @@ -116,7 +116,7 @@ class PaymentApiTest @Autowired constructor( val requestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest val paymentOrder = PaymentOrder.newInstance( - account.id!!, + account.id()!!, requestDto.orderName, requestDto.amount ) @@ -155,7 +155,7 @@ class PaymentApiTest @Autowired constructor( val requestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest val paymentOrder = PaymentOrder.newInstance( - account.id!!, + account.id()!!, requestDto.orderName, requestDto.amount ) @@ -166,7 +166,7 @@ class PaymentApiTest @Autowired constructor( this.mockMvc.perform( RestDocumentationRequestBuilders - .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id) + .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id()) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content(reqBody) @@ -192,7 +192,7 @@ class PaymentApiTest @Autowired constructor( val requestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest val paymentOrder = PaymentOrder.newInstance( - account.id!!, + account.id()!!, requestDto.orderName, requestDto.amount, PaymentsStatus.CANCELED @@ -204,7 +204,7 @@ class PaymentApiTest @Autowired constructor( this.mockMvc.perform( RestDocumentationRequestBuilders - .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id) + .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id()) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content(reqBody) @@ -230,7 +230,7 @@ class PaymentApiTest @Autowired constructor( val wrongRequestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest val paymentOrder = PaymentOrder.newInstance( - account.id!!, + account.id()!!, "originOrderName", wrongRequestDto.amount ) @@ -241,7 +241,7 @@ class PaymentApiTest @Autowired constructor( this.mockMvc.perform( RestDocumentationRequestBuilders - .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id) + .post("$V1_TOSS_PAYMENTS/$KEY_IN_PAYMENT_ORDER_ID", paymentOrder.id()) .contentType(MediaType.APPLICATION_JSON) .accept(MediaType.APPLICATION_JSON) .content(reqBody) @@ -270,7 +270,7 @@ class PaymentApiTest @Autowired constructor( paymentHistoryRepository.save( PaymentHistory.newInstanceFrom( - entity.id!!, + entity.id()!!, LocalDateTime.now(), "ord_202306172137299642490491", "테스트결제", @@ -324,7 +324,7 @@ class PaymentApiTest @Autowired constructor( val entity = accountRepository.save(account) val tokens = tokenGenerator.generate(account.email, setOf(Role.USER)) - val reqBody = objectMapper.writeValueAsString(PaymentOrderRequest(entity.id!!, "테스트 주문상품", 10)) + val reqBody = objectMapper.writeValueAsString(PaymentOrderRequest(entity.id()!!, "테스트 주문상품", 10)) this.mockMvc.perform( RestDocumentationRequestBuilders diff --git a/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/RestClient.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/RestClient.kt index 8c740a2..5d103be 100644 --- a/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/RestClient.kt +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/domain/RestClient.kt @@ -4,5 +4,5 @@ import org.springframework.http.HttpEntity import org.springframework.http.ResponseEntity interface RestClient { - fun postForEntity(url: String, request: HttpEntity): ResponseEntity + fun keyIn(url: String, request: HttpEntity): ResponseEntity } \ No newline at end of file diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/StringKafkaTemplateWrapper.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/StringKafkaTemplateWrapper.kt deleted file mode 100644 index 2795160..0000000 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/kafka/StringKafkaTemplateWrapper.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure.kafka - -interface StringKafkaTemplateWrapper { - fun send(topic: String, data: String) -} \ No newline at end of file From 6fef0b83cb4c6b07c2868f8ca617963607df4543 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Fri, 1 Dec 2023 00:17:40 +0900 Subject: [PATCH 09/16] =?UTF-8?q?Refactor=20:=20=ED=85=8C=EC=8A=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=99=98=EA=B2=BD=EC=97=90=EC=84=9C=20PG=20?= =?UTF-8?q?=EC=8A=B9=EC=9D=B8=20=EC=9A=94=EC=B2=AD=EC=9D=84=20=EC=9C=A0?= =?UTF-8?q?=EC=97=B0=ED=95=98=EA=B2=8C=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=ED=95=A0=20=EC=88=98=20=EC=9E=88=EB=8F=84=EB=A1=9D,=20restTemp?= =?UTF-8?q?late=EC=9D=84=20RestClient=20=EC=9D=B8=ED=84=B0=ED=8E=98?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=20=EA=B5=AC=ED=98=84=EC=B2=B4=EB=A1=9C=20?= =?UTF-8?q?=EC=BB=B4=ED=8F=AC=EC=A7=80=EC=85=98=20=ED=8C=A8=ED=84=B4=20?= =?UTF-8?q?=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- account-api/account-domain/build.gradle.kts | 1 - .../security/JwtAuthenticationFilter.kt | 2 +- .../InMemoryPaymentOrderRepository.kt | 9 +++ .../InMemoryPaymentOrderRepositoryAdapter.kt | 5 +- .../TestTossPaymentsRestClient.kt | 61 +++++++++++++++++++ .../InMemoryPaymentOrderRepository.kt | 12 ---- .../inmemory/core/IdGenerator.kt | 5 -- .../inmemory/core/Identified.kt | 5 -- .../payment/presentation/PaymentApiTest.kt | 4 +- .../presentation/mock/MockPaymentService.kt | 41 ------------- common/build.gradle.kts | 1 + .../common/inmemory/core/IdGenerator.kt | 5 ++ .../inmemory/core/IdGeneratorFactory.kt | 2 +- .../common/inmemory/core/Identified.kt | 5 ++ .../inmemory/core/InMemoryRepository.kt | 2 +- .../core/SequentialLongIdGenerator.kt | 2 +- .../payment/application/PaymentService.kt | 1 - payment-api/payment-domain/build.gradle.kts | 1 - .../TossPaymentsKeyInApprovalProcessor.kt | 3 +- .../tosspayments/TossPaymentsProcessor.kt | 26 ++++---- .../tosspayments/TossPaymentsRestClient.kt | 4 ++ 21 files changed, 108 insertions(+), 89 deletions(-) create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepository.kt rename app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/{inmemory => }/InMemoryPaymentOrderRepositoryAdapter.kt (69%) create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/TestTossPaymentsRestClient.kt delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepository.kt delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGenerator.kt delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/Identified.kt delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPaymentService.kt create mode 100644 common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/IdGenerator.kt rename {app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure => common/src/main/kotlin/org/collaborator/paymentlab/common}/inmemory/core/IdGeneratorFactory.kt (80%) create mode 100644 common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/Identified.kt rename {app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure => common/src/main/kotlin/org/collaborator/paymentlab/common}/inmemory/core/InMemoryRepository.kt (94%) rename {app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure => common/src/main/kotlin/org/collaborator/paymentlab/common}/inmemory/core/SequentialLongIdGenerator.kt (68%) diff --git a/account-api/account-domain/build.gradle.kts b/account-api/account-domain/build.gradle.kts index 2db04d4..0fb6a26 100644 --- a/account-api/account-domain/build.gradle.kts +++ b/account-api/account-domain/build.gradle.kts @@ -1,6 +1,5 @@ dependencies { implementation(project(":common")) - implementation("jakarta.persistence:jakarta.persistence-api:3.1.0") implementation("org.hibernate:hibernate-core:6.1.7.Final") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") diff --git a/app/src/main/kotlin/org/collaborators/paymentslab/config/security/JwtAuthenticationFilter.kt b/app/src/main/kotlin/org/collaborators/paymentslab/config/security/JwtAuthenticationFilter.kt index 25c284c..1159dee 100644 --- a/app/src/main/kotlin/org/collaborators/paymentslab/config/security/JwtAuthenticationFilter.kt +++ b/app/src/main/kotlin/org/collaborators/paymentslab/config/security/JwtAuthenticationFilter.kt @@ -38,7 +38,7 @@ class JwtAuthenticationFilter( if (SecurityContextHolder.getContext().authentication == null) { val context = UsernamePasswordAuthenticationToken( - AuthenticatedUser(account.id!!, account.accountKey!!, account.roles), null, authorities(account.roles) + AuthenticatedUser(account.id()!!, account.accountKey!!, account.roles), null, authorities(account.roles) ) SecurityContextHolder.getContext().authentication = context } diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepository.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepository.kt new file mode 100644 index 0000000..8fe83ae --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepository.kt @@ -0,0 +1,9 @@ +package org.collaborators.paymentslab.payment.infrastructure + +import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder +import org.collaborator.paymentlab.common.inmemory.core.InMemoryRepository +import org.springframework.stereotype.Component + +@Component +class InMemoryPaymentOrderRepository: InMemoryRepository(Long::class.java) { +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepositoryAdapter.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepositoryAdapter.kt similarity index 69% rename from app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepositoryAdapter.kt rename to app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepositoryAdapter.kt index 9c38a25..e0a1db4 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepositoryAdapter.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepositoryAdapter.kt @@ -1,7 +1,8 @@ -package org.collaborators.paymentslab.payment.infrastructure.inmemory +package org.collaborators.paymentslab.payment.infrastructure import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository +import org.collaborators.paymentslab.payment.infrastructure.tosspayments.exception.PaymentOrderNotFoundException import org.springframework.context.annotation.Profile import org.springframework.stereotype.Repository @@ -15,6 +16,6 @@ class InMemoryPaymentOrderRepositoryAdapter( } override fun findById(id: Long): PaymentOrder { - return inMemoryPaymentOrderRepository.findById(id)!! + return inMemoryPaymentOrderRepository.findById(id) ?: throw PaymentOrderNotFoundException() } } \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/TestTossPaymentsRestClient.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/TestTossPaymentsRestClient.kt new file mode 100644 index 0000000..6f50469 --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/TestTossPaymentsRestClient.kt @@ -0,0 +1,61 @@ +package org.collaborators.paymentslab.payment.infrastructure + +import org.collaborator.paymentlab.common.domain.RestClient +import org.collaborators.paymentslab.payment.domain.entity.PaymentsStatus +import org.collaborators.paymentslab.payment.infrastructure.tosspayments.TossPaymentsApprovalResponse +import org.collaborators.paymentslab.payment.infrastructure.tosspayments.TossPaymentsCardInfoResponse +import org.collaborators.paymentslab.payment.infrastructure.tosspayments.TossPaymentsKeyInDto +import org.collaborators.paymentslab.payment.infrastructure.tosspayments.exception.TossPaymentsApiClientException +import org.collaborators.paymentslab.payment.presentation.mock.MockTossPaymentsErrorBody +import org.springframework.context.annotation.Profile +import org.springframework.http.HttpEntity +import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Component + +@Component +@Profile(value = ["test"]) +class TestTossPaymentsRestClient: RestClient { + override fun keyIn( + url: String, + request: HttpEntity + ): ResponseEntity { + val reqBody = request.body ?: throw NullPointerException() + + if (reqBody.cardNumber.length != 16 || !isDigits(reqBody.cardNumber)) + throw TossPaymentsApiClientException(MockTossPaymentsErrorBody.invalidCardNumber) + + return ResponseEntity.ok(TossPaymentsApprovalResponse( + mId = "tvivarepublica4", + lastTransactionKey = "2A441542485089863EB31F9B039FEFF8", + paymentKey = "4qjZblEopLBa5PzR0Arn9KeQDGJPxkVvmYnNeDMyW2G1OgwK", + orderId = reqBody.orderId, + orderName = reqBody.orderName, + taxExemptionAmount = 0, + status = PaymentsStatus.DONE.name, + useEscrow = false, + cultureExpense = false, + card = TossPaymentsCardInfoResponse( + issuerCode = "4V", + acquirerCode = "21", + number = reqBody.cardNumber, + installmentPlanMonths = 0, + isInterestFree = false, + approveNo = "00000000", + useCardPoint = false, + cardType = "미확인", + ownerType = "미확인", + acquireStatus = "READY", + amount = reqBody.amount + ) + )) + } + + private fun isDigits(cardNum: String): Boolean { + val arr = cardNum.toCharArray() + for (i in arr.indices) { + if (!Character.isDigit(arr[i])) + return false + } + return true + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepository.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepository.kt deleted file mode 100644 index 00d947e..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/InMemoryPaymentOrderRepository.kt +++ /dev/null @@ -1,12 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure.inmemory - -import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder -import org.collaborators.paymentslab.payment.infrastructure.inmemory.core.IdGenerator -import org.collaborators.paymentslab.payment.infrastructure.inmemory.core.IdGeneratorFactory -import org.collaborators.paymentslab.payment.infrastructure.inmemory.core.InMemoryRepository -import org.springframework.stereotype.Component -import java.util.concurrent.ConcurrentHashMap - -@Component -class InMemoryPaymentOrderRepository: InMemoryRepository(Long::class.java) { -} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGenerator.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGenerator.kt deleted file mode 100644 index f2006bc..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGenerator.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure.inmemory.core - -interface IdGenerator { - fun generateId(): T -} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/Identified.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/Identified.kt deleted file mode 100644 index 861ae55..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/Identified.kt +++ /dev/null @@ -1,5 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure.inmemory.core - -interface Identified { - fun getId(): ID -} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt index 345e151..6b1c176 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt @@ -15,8 +15,6 @@ import org.collaborators.paymentslab.payment.presentation.mock.MockPayments import org.collaborators.paymentslab.payment.presentation.request.PaymentOrderRequest import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test -import org.mockito.ArgumentMatchers.anyString -import org.mockito.kotlin.doNothing import org.springframework.beans.factory.annotation.Autowired import org.springframework.http.MediaType import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation @@ -357,7 +355,7 @@ class PaymentApiTest @Autowired constructor( @DisplayName("변조된 사용자 계정 id로 주문 결제 발행 api 테스트") fun testWithInvalidAccountGeneratePaymentOrder() { val account = testEntityForRegister("originalGeneratedPaymentOrder@gmail.com") - val originalUser = accountRepository.save(account) + accountRepository.save(account) val invalidAccountId = 9999L val tokens = tokenGenerator.generate(account.email, setOf(Role.USER)) val invalidPaymentOrderRequest = PaymentOrderRequest(invalidAccountId, "잘못된 테스트 주문상품", 10) diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPaymentService.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPaymentService.kt deleted file mode 100644 index 7ba9542..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPaymentService.kt +++ /dev/null @@ -1,41 +0,0 @@ -package org.collaborators.paymentslab.payment.presentation.mock - -import org.collaborators.paymentslab.payment.application.PaymentService -import org.collaborators.paymentslab.payment.application.command.TossPaymentsKeyInPayCommand -import org.collaborators.paymentslab.payment.domain.PaymentOrderProcessor -import org.collaborators.paymentslab.payment.domain.PaymentsProcessor -import org.collaborators.paymentslab.payment.domain.PaymentsQueryManager -import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository -import org.collaborators.paymentslab.payment.infrastructure.tosspayments.TossPaymentsValidator -import org.collaborators.paymentslab.payment.infrastructure.tosspayments.exception.TossPaymentsApiClientException -import org.springframework.context.annotation.Profile -import org.springframework.stereotype.Service -import org.springframework.transaction.annotation.Transactional - -@Service -@Profile(value = ["test"]) -@Transactional -class MockPaymentService( - private val paymentsProcessor: PaymentsProcessor, - private val paymentsQueryManager: PaymentsQueryManager, - private val paymentOrderRepository: PaymentOrderRepository, - private val tossPaymentsValidator: TossPaymentsValidator -): PaymentService(paymentsProcessor, paymentsQueryManager) { - override fun keyInPay(paymentOrderId: Long, command: TossPaymentsKeyInPayCommand) { - val paymentOrder = paymentOrderRepository.findById(paymentOrderId) - tossPaymentsValidator.validate(paymentOrder, command.amount, command.orderName) - - val cardNumber = command.cardNumber - if (cardNumber.length != 16 || !isDigits(cardNumber)) - throw TossPaymentsApiClientException(MockTossPaymentsErrorBody.invalidCardNumber) - } - - private fun isDigits(cardNum: String): Boolean { - val arr = cardNum.toCharArray() - for (i in arr.indices) { - if (!Character.isDigit(arr[i])) - return false - } - return true - } -} \ No newline at end of file diff --git a/common/build.gradle.kts b/common/build.gradle.kts index 19f995d..5cf53fd 100644 --- a/common/build.gradle.kts +++ b/common/build.gradle.kts @@ -1,4 +1,5 @@ dependencies { + implementation("jakarta.persistence:jakarta.persistence-api:3.1.0") implementation("org.springframework:spring-web:6.0.7") implementation("org.reflections:reflections:0.10.2") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") diff --git a/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/IdGenerator.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/IdGenerator.kt new file mode 100644 index 0000000..be1494b --- /dev/null +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/IdGenerator.kt @@ -0,0 +1,5 @@ +package org.collaborator.paymentlab.common.inmemory.core + +interface IdGenerator { + fun generateId(): T +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGeneratorFactory.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/IdGeneratorFactory.kt similarity index 80% rename from app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGeneratorFactory.kt rename to common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/IdGeneratorFactory.kt index 71c3420..04153ca 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/IdGeneratorFactory.kt +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/IdGeneratorFactory.kt @@ -1,4 +1,4 @@ -package org.collaborators.paymentslab.payment.infrastructure.inmemory.core +package org.collaborator.paymentlab.common.inmemory.core class IdGeneratorFactory { companion object { diff --git a/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/Identified.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/Identified.kt new file mode 100644 index 0000000..3f7a44c --- /dev/null +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/Identified.kt @@ -0,0 +1,5 @@ +package org.collaborator.paymentlab.common.inmemory.core + +interface Identified { + fun getId(): ID +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/InMemoryRepository.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/InMemoryRepository.kt similarity index 94% rename from app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/InMemoryRepository.kt rename to common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/InMemoryRepository.kt index c0e119f..5574ad4 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/InMemoryRepository.kt +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/InMemoryRepository.kt @@ -1,4 +1,4 @@ -package org.collaborators.paymentslab.payment.infrastructure.inmemory.core +package org.collaborator.paymentlab.common.inmemory.core import jakarta.persistence.Id import org.collaborator.paymentlab.common.domain.AbstractAggregateRoot diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/SequentialLongIdGenerator.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/SequentialLongIdGenerator.kt similarity index 68% rename from app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/SequentialLongIdGenerator.kt rename to common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/SequentialLongIdGenerator.kt index 0721c6f..1010f75 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/inmemory/core/SequentialLongIdGenerator.kt +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/SequentialLongIdGenerator.kt @@ -1,4 +1,4 @@ -package org.collaborators.paymentslab.payment.infrastructure.inmemory.core +package org.collaborator.paymentlab.common.inmemory.core class SequentialLongIdGenerator: IdGenerator { private var sequence = 1L; diff --git a/payment-api/payment-application/src/main/kotlin/org/collaborators/paymentslab/payment/application/PaymentService.kt b/payment-api/payment-application/src/main/kotlin/org/collaborators/paymentslab/payment/application/PaymentService.kt index b6f287c..be37c2c 100644 --- a/payment-api/payment-application/src/main/kotlin/org/collaborators/paymentslab/payment/application/PaymentService.kt +++ b/payment-api/payment-application/src/main/kotlin/org/collaborators/paymentslab/payment/application/PaymentService.kt @@ -13,7 +13,6 @@ import org.springframework.transaction.annotation.Propagation import org.springframework.transaction.annotation.Transactional @Service -@Profile(value = ["!test"]) @Transactional class PaymentService( private val paymentsProcessor: PaymentsProcessor, diff --git a/payment-api/payment-domain/build.gradle.kts b/payment-api/payment-domain/build.gradle.kts index 2db04d4..0fb6a26 100644 --- a/payment-api/payment-domain/build.gradle.kts +++ b/payment-api/payment-domain/build.gradle.kts @@ -1,6 +1,5 @@ dependencies { implementation(project(":common")) - implementation("jakarta.persistence:jakarta.persistence-api:3.1.0") implementation("org.hibernate:hibernate-core:6.1.7.Final") testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.2") testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.2") diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt index be3cf36..a89178e 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsKeyInApprovalProcessor.kt @@ -1,6 +1,7 @@ package org.collaborators.paymentslab.payment.infrastructure.tosspayments +import org.collaborator.paymentlab.common.domain.RestClient import org.collaborator.paymentlab.common.error.ErrorCode import org.collaborator.paymentlab.common.error.ServiceException import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder @@ -17,7 +18,7 @@ import java.nio.charset.StandardCharsets import java.util.* class TossPaymentsKeyInApprovalProcessor( - private val tossPaymentsRestClient: TossPaymentsRestClient, + private val tossPaymentsRestClient: RestClient, private val paymentOrderRepository: PaymentOrderRepository, private val paymentsTransactionEventPublisher: TossPaymentsTransactionEventPublisher, private val paymentProperties: PaymentPropertiesResolver diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt index 7f41249..9e0faee 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt @@ -26,18 +26,18 @@ open class TossPaymentsProcessor( tossPaymentsValidator.validate(paymentOrder, amount, orderName) -// tossPaymentsKeyInApprovalProcessor.approval( -// paymentOrder, -// TossPaymentsKeyInDto( -// amount, -// orderId, -// orderName, -// cardNumber, -// cardExpirationYear, -// cardExpirationMonth, -// cardPassword, -// customerIdentityNumber -// ) -// ) + tossPaymentsKeyInApprovalProcessor.approval( + paymentOrder, + TossPaymentsKeyInDto( + amount, + orderId, + orderName, + cardNumber, + cardExpirationYear, + cardExpirationMonth, + cardPassword, + customerIdentityNumber + ) + ) } } \ No newline at end of file diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt index 9fd91a9..98c3d7f 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsRestClient.kt @@ -1,10 +1,14 @@ package org.collaborators.paymentslab.payment.infrastructure.tosspayments import org.collaborator.paymentlab.common.domain.RestClient +import org.springframework.context.annotation.Profile import org.springframework.http.HttpEntity import org.springframework.http.ResponseEntity +import org.springframework.stereotype.Component import org.springframework.web.client.RestTemplate +@Component +@Profile(value = ["!test"]) class TossPaymentsRestClient( private val restTemplate: RestTemplate ): RestClient { From 49ee73458a5907824d790ce0e77aec75a9f3f9ca Mon Sep 17 00:00:00 2001 From: wanniDev Date: Sun, 3 Dec 2023 19:58:56 +0900 Subject: [PATCH 10/16] =?UTF-8?q?Test:=20=EA=B3=84=EC=A0=95=20=EB=8F=84?= =?UTF-8?q?=EB=A9=94=EC=9D=B8=20h2=20=EB=8D=B0=EC=9D=B4=ED=84=B0=EB=B2=A0?= =?UTF-8?q?=EC=9D=B4=EC=8A=A4=EC=99=80=20=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../jpa/AccountRepositoryAdapter.kt | 2 + .../InMemoryAccountRepository.kt | 13 ++++++ .../InMemoryAccountRepositoryAdapter.kt | 41 +++++++++++++++++++ .../inmemory/core/InMemoryRepository.kt | 4 ++ 4 files changed, 60 insertions(+) create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt create mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt diff --git a/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/jpa/AccountRepositoryAdapter.kt b/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/jpa/AccountRepositoryAdapter.kt index fbd3a67..be0f410 100644 --- a/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/jpa/AccountRepositoryAdapter.kt +++ b/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/jpa/AccountRepositoryAdapter.kt @@ -4,7 +4,9 @@ import org.collaborator.paymentlab.common.error.ErrorCode import org.collaborator.paymentlab.common.error.ResourceNotFoundException import org.collaborators.paymentslab.account.domain.Account import org.collaborators.paymentslab.account.domain.AccountRepository +import org.springframework.context.annotation.Profile +@Profile(value = ["!test"]) class AccountRepositoryAdapter( private val jpaAccountRepository: JpaAccountRepository ): AccountRepository { diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt new file mode 100644 index 0000000..91cbc2a --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt @@ -0,0 +1,13 @@ +package org.collaborators.paymentslab.account.infrastructure + +import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder +import org.collaborator.paymentlab.common.inmemory.core.InMemoryRepository +import org.collaborators.paymentslab.account.domain.Account +import org.springframework.stereotype.Component + +@Component +class InMemoryAccountRepository: InMemoryRepository(Long::class.java) { + fun findByAccountKey(accountKey: String): Account { + return findAll().first { it.accountKey == accountKey } + } +} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt new file mode 100644 index 0000000..6119fd4 --- /dev/null +++ b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt @@ -0,0 +1,41 @@ +package org.collaborators.paymentslab.account.infrastructure + +import org.collaborator.paymentlab.common.error.ErrorCode +import org.collaborator.paymentlab.common.error.ResourceNotFoundException +import org.collaborators.paymentslab.account.domain.Account +import org.collaborators.paymentslab.account.domain.AccountRepository +import org.springframework.context.annotation.Profile +import org.springframework.stereotype.Repository +import javax.security.auth.login.AccountNotFoundException + +@Repository +@Profile(value = ["test"]) +class InMemoryAccountRepositoryAdapter( + private val inMemoryAccountRepository: InMemoryAccountRepository +): AccountRepository { + override fun existByEmail(email: String): Boolean { + return inMemoryAccountRepository.findAll().any { it.email == email } + } + + override fun existByPhoneNumber(phoneNumber: String): Boolean { + return inMemoryAccountRepository.findAll().any { it.phoneNumber == phoneNumber } + } + + override fun save(account: Account): Account { + return inMemoryAccountRepository.save(account) + } + + override fun findByEmail(email: String): Account { + if (!existByEmail(email)) + throw ResourceNotFoundException(ErrorCode.ACCOUNT_NOT_FOUND) + return inMemoryAccountRepository.findAll().first { it.email == email } + } + + override fun findById(accountId: String): Account { + return inMemoryAccountRepository.findByAccountKey(accountId) + } + + override fun existByUsername(username: String): Boolean { + return inMemoryAccountRepository.findAll().any { it.username == username } + } +} \ No newline at end of file diff --git a/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/InMemoryRepository.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/InMemoryRepository.kt index 5574ad4..4a4e2d5 100644 --- a/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/InMemoryRepository.kt +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/InMemoryRepository.kt @@ -22,6 +22,10 @@ abstract class InMemoryRepository, ID>(idTypeParam return entity } + fun findAll(): List { + return storage.values.toList() + } + private fun assignNewId(id: ID, entity: T) { for (field in entity::class.java.declaredFields) { if (field.isAnnotationPresent(Id::class.java)) { From cdd44480f6168cd441440ce9433f18344a20227f Mon Sep 17 00:00:00 2001 From: wanniDev Date: Tue, 5 Dec 2023 00:20:22 +0900 Subject: [PATCH 11/16] =?UTF-8?q?Refactor:=20=EC=A2=80=20=EB=8D=94=20?= =?UTF-8?q?=EA=B0=80=EB=B3=8D=EA=B3=A0=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20?= =?UTF-8?q?=EB=AA=85=EC=84=B8=ED=99=94=ED=95=98=EA=B8=B0=20=ED=8E=B8?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EA=B2=8C=20=EA=B0=9C=EC=84=A0=ED=95=98?= =?UTF-8?q?=EA=B8=B0=20=EC=9C=84=ED=95=B4,=20accout=20=EB=8F=84=EB=A9=94?= =?UTF-8?q?=EC=9D=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94=EB=93=9C?= =?UTF-8?q?=EC=97=90=20=EC=82=AC=EC=9A=A9=EB=90=98=EB=8A=94=20repository?= =?UTF-8?q?=20=EB=B9=88=EC=9D=84=20mockBean=20=ED=99=9C=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../paymentslab/account/domain/Account.kt | 2 +- .../jpa/AccountRepositoryAdapter.kt | 3 +- .../paymentslab/AbstractApiTest.kt | 5 ++ .../InMemoryAccountRepository.kt | 3 -- .../InMemoryAccountRepositoryAdapter.kt | 6 +-- .../presentation/AuthenticationApiTest.kt | 51 +++++++++++-------- .../presentation/MockAuthentication.kt | 51 +++++++++++++++++++ .../payment/presentation/PaymentApiTest.kt | 2 +- 8 files changed, 91 insertions(+), 32 deletions(-) diff --git a/account-api/account-domain/src/main/kotlin/org/collaborators/paymentslab/account/domain/Account.kt b/account-api/account-domain/src/main/kotlin/org/collaborators/paymentslab/account/domain/Account.kt index 99232ee..9feaa5b 100644 --- a/account-api/account-domain/src/main/kotlin/org/collaborators/paymentslab/account/domain/Account.kt +++ b/account-api/account-domain/src/main/kotlin/org/collaborators/paymentslab/account/domain/Account.kt @@ -12,7 +12,7 @@ import java.util.* @Table(name = "ACCOUNTS") class Account protected constructor( @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private val id: Long? = null, + var id: Long? = null, var accountKey: String = KeyGenerator.generate("act_"), var email: String, var username: String, diff --git a/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/jpa/AccountRepositoryAdapter.kt b/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/jpa/AccountRepositoryAdapter.kt index be0f410..911f815 100644 --- a/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/jpa/AccountRepositoryAdapter.kt +++ b/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/jpa/AccountRepositoryAdapter.kt @@ -4,9 +4,8 @@ import org.collaborator.paymentlab.common.error.ErrorCode import org.collaborator.paymentlab.common.error.ResourceNotFoundException import org.collaborators.paymentslab.account.domain.Account import org.collaborators.paymentslab.account.domain.AccountRepository -import org.springframework.context.annotation.Profile -@Profile(value = ["!test"]) + class AccountRepositoryAdapter( private val jpaAccountRepository: JpaAccountRepository ): AccountRepository { diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt index a7840d6..5ec80cf 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt @@ -6,6 +6,7 @@ import org.collaborator.paymentlab.common.URI_HOST import org.collaborator.paymentlab.common.URI_PORT import org.collaborator.paymentlab.common.URI_SCHEME import org.collaborators.paymentslab.account.domain.Account +import org.collaborators.paymentslab.account.domain.AccountRepository import org.collaborators.paymentslab.account.domain.PasswordEncrypt import org.collaborators.paymentslab.account.domain.TokenGenerator import org.junit.jupiter.api.TestInstance @@ -15,6 +16,7 @@ import org.springframework.beans.factory.annotation.Value import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc import org.springframework.boot.test.context.SpringBootTest +import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.kafka.core.* import org.springframework.kafka.listener.* import org.springframework.kafka.test.context.EmbeddedKafka @@ -62,6 +64,9 @@ abstract class AbstractApiTest { @Value("\${admin.key}") protected lateinit var adminKey: String + @MockBean + protected lateinit var accountRepository: AccountRepository + protected fun testEntityForRegister(email: String): Account { val account = Account.register( email, diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt index 91cbc2a..b5d1b5d 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt @@ -1,11 +1,8 @@ package org.collaborators.paymentslab.account.infrastructure -import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder import org.collaborator.paymentlab.common.inmemory.core.InMemoryRepository import org.collaborators.paymentslab.account.domain.Account -import org.springframework.stereotype.Component -@Component class InMemoryAccountRepository: InMemoryRepository(Long::class.java) { fun findByAccountKey(accountKey: String): Account { return findAll().first { it.accountKey == accountKey } diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt index 6119fd4..10684a5 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt @@ -4,12 +4,8 @@ import org.collaborator.paymentlab.common.error.ErrorCode import org.collaborator.paymentlab.common.error.ResourceNotFoundException import org.collaborators.paymentslab.account.domain.Account import org.collaborators.paymentslab.account.domain.AccountRepository -import org.springframework.context.annotation.Profile -import org.springframework.stereotype.Repository -import javax.security.auth.login.AccountNotFoundException -@Repository -@Profile(value = ["test"]) + class InMemoryAccountRepositoryAdapter( private val inMemoryAccountRepository: InMemoryAccountRepository ): AccountRepository { diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/AuthenticationApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/AuthenticationApiTest.kt index 05dcbe2..6931902 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/AuthenticationApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/AuthenticationApiTest.kt @@ -1,15 +1,16 @@ package org.collaborators.paymentslab.account.presentation import org.collaborator.paymentlab.common.* +import org.collaborator.paymentlab.common.error.ErrorCode +import org.collaborator.paymentlab.common.error.ResourceNotFoundException import org.collaborators.paymentslab.AbstractApiTest -import org.collaborators.paymentslab.account.domain.Account -import org.collaborators.paymentslab.account.domain.AccountRepository import org.collaborators.paymentslab.account.presentation.request.LoginAccountRequest import org.collaborators.paymentslab.account.presentation.request.RegisterAccountRequest import org.collaborators.paymentslab.account.presentation.request.RegisterAdminAccountRequest import org.collaborators.paymentslab.account.presentation.request.RegisterConfirmRequest import org.junit.jupiter.api.* -import org.springframework.beans.factory.annotation.Autowired +import org.mockito.kotlin.any +import org.mockito.kotlin.given import org.springframework.http.MediaType import org.springframework.restdocs.headers.HeaderDocumentation.headerWithName import org.springframework.restdocs.headers.HeaderDocumentation.requestHeaders @@ -22,15 +23,18 @@ import org.springframework.restdocs.payload.PayloadDocumentation.* import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status -class AuthenticationApiTest @Autowired constructor( - private val accountRepository: AccountRepository -) : AbstractApiTest() { +class AuthenticationApiTest : AbstractApiTest() { @Test @DisplayName("회원가입 api 동작") fun registerTest() { val requestDto = RegisterAccountRequest("hello@gmail.com", "qwer1234", "helloUsername", "010-1234-5678") val reqBody = this.objectMapper.writeValueAsString(requestDto) + val mockMember = MockAuthentication.mockUserAccountFrom(requestDto) + given(accountRepository.existByEmail(mockMember.email)).willReturn(false) + given(accountRepository.save(any())).willReturn(mockMember) + given(accountRepository.findByEmail(any())).willReturn(mockMember) + this.mockMvc.perform( RestDocumentationRequestBuilders .post("$V1_AUTH/$REGISTER") @@ -70,6 +74,11 @@ class AuthenticationApiTest @Autowired constructor( RegisterAdminAccountRequest("helloAdmin@gmail.com", "qwer1234", "helloUsername", "010-1234-5678", adminKey) val reqBody = this.objectMapper.writeValueAsString(requestDto) + val mockMember = MockAuthentication.mockAdminAccountFrom(requestDto) + given(accountRepository.existByEmail(mockMember.email)).willReturn(false) + given(accountRepository.save(any())).willReturn(mockMember) + given(accountRepository.findByEmail(any())).willReturn(mockMember) + this.mockMvc.perform( RestDocumentationRequestBuilders .post("$V1_AUTH/$REGISTER_ADMIN") @@ -190,9 +199,9 @@ class AuthenticationApiTest @Autowired constructor( @Test @DisplayName("회원가입 검증 api 동작 테스트") fun confirmTest() { - val registered = accountRepository.save(Account.register("hello2@gmail.com", - encrypt.encode("qqqwww123"), "hello2", "010-1234-1234")) - val account = accountRepository.findByEmail(registered.email) + val account = MockAuthentication.mockUserAccount() + given(accountRepository.save(any())).willReturn(account) + given(accountRepository.findByEmail(any())).willReturn(account) val requestDto = RegisterConfirmRequest(account.emailCheckToken!!, account.email) val reqBody = this.objectMapper.writeValueAsString(requestDto) @@ -224,10 +233,11 @@ class AuthenticationApiTest @Autowired constructor( @Test @DisplayName("로그인 api 동작 테스트") fun loginTest() { - val registered = testEntityForRegister("hello3@gmail.com") - val account = accountRepository.save(registered) + val account = MockAuthentication.mockUserAccount() + given(accountRepository.save(any())).willReturn(account) + given(accountRepository.findByEmail(any())).willReturn(account) - val requestDto = LoginAccountRequest(account.email, "qqqwww123") + val requestDto = LoginAccountRequest(account.email, MockAuthentication.testPlainPassword) val reqBody = this.objectMapper.writeValueAsString(requestDto) this.mockMvc.perform( @@ -270,11 +280,10 @@ class AuthenticationApiTest @Autowired constructor( @Test @DisplayName("잘못된 로그인 api 에러 테스트") fun loginErrorTest() { - val registered = accountRepository.save(Account.register("invalid@gmail.com", - encrypt.encode("qqqwww123"), "hello2", "010-1234-1234")) - val account = accountRepository.findByEmail(registered.email) + val account = MockAuthentication.mockUserAccount() + given(accountRepository.findByEmail(any())).willReturn(account) - val requestDto = LoginAccountRequest(account.email, "wrongpassword123") + val requestDto = LoginAccountRequest(account.email, MockAuthentication.testWrongPlainPassword) val reqBody = this.objectMapper.writeValueAsString(requestDto) this.mockMvc.perform( @@ -305,10 +314,11 @@ class AuthenticationApiTest @Autowired constructor( @Test @DisplayName("토큰 재발급 api 테스트") fun reIssuanceTest() { - val registered = testEntityForRegister("hello4@gmail.com") - val account = accountRepository.save(registered) + val account = MockAuthentication.mockUserAccount() val tokens = tokenGenerator.generate(account.email, account.roles) + given(accountRepository.findByEmail(any())).willReturn(account) + this.mockMvc.perform( RestDocumentationRequestBuilders .post("$V1_AUTH/$RE_ISSUANCE") @@ -344,8 +354,9 @@ class AuthenticationApiTest @Autowired constructor( @Test @DisplayName("회원 등록이 안된 사용자의 토큰으로 재발급 실패 api 테스트") fun notRegisteredReIssuanceTest() { - val registered = testEntityForRegister("nouser123@gmail.com") - val tokens = tokenGenerator.generate(registered.email, registered.roles) + val account = MockAuthentication.mockUserAccount() + given(accountRepository.findByEmail(MockAuthentication.testWrongReissuerEmail)).willThrow(ResourceNotFoundException(ErrorCode.ACCOUNT_NOT_FOUND)) + val tokens = tokenGenerator.generate(MockAuthentication.testWrongReissuerEmail, account.roles) this.mockMvc.perform( RestDocumentationRequestBuilders diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt index 1fd9e29..0e25c23 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt @@ -1,6 +1,57 @@ package org.collaborators.paymentslab.account.presentation +import org.collaborators.paymentslab.account.domain.Account +import org.collaborators.paymentslab.account.presentation.request.RegisterAccountRequest +import org.collaborators.paymentslab.account.presentation.request.RegisterAdminAccountRequest + object MockAuthentication { val expiredAccessToken = "eyJhbGciOiJIUzI1NiJ9.eyJzY29wZXMiOlsiUk9MRV9VU0VSIl0sImVtYWlsIjoiaGVsbG9AZ21haWwuY29tIiwiaXNzIjoicGF5bWVudHNsYWIiLCJpYXQiOjE2ODUyNzE1OTIsImV4cCI6MTY4NTI3MzM5Mn0.92iGkI5ugZ4kJmOyThfoOGGGNSshWx5e0NCn0pMfexw" val expiredRefreshToken = "eyJhbGciOiJIUzI1NiJ9.eyJzY29wZXMiOlsiUk9MRV9VU0VSIl0sImVtYWlsIjoiaGVsbG9AZ21haWwuY29tIiwiaXNzIjoicGF5bWVudHNsYWIiLCJpYXQiOjE2ODUyODA3OTcsImV4cCI6MTY4NTI4MjU5N30.t9-Qb27MxTleqWVzfqyBouFg7LWndt67WW7Eoi-WXzM" + + val testPlainPassword = "Qwer!234" + val testEncrypyPassword = "\$2a\$10\$w5Idz2dN9FQFam1ZT3OoS.ZDlDom4dLfi6jQrukabcUHrGw8Ju49u" + val testWrongPlainPassword = "wrong" + val testWrongReissuerEmail = "nouser123@gmail.com" + + fun mockUserAccount(): Account { + val account = Account.register( + "hello2@gmail.com", + testEncrypyPassword, "hello2", "010-1234-1234" + ) + account.id = 1L + account.emailVerified = true + return account + } + + fun mockWrongUserAccount(): Account { + val account = Account.register( + testWrongReissuerEmail, + testEncrypyPassword, "hello2", "010-1234-1234" + ) + account.id = 2L + account.emailVerified = true + return account + } + + fun mockUserAccountFrom(registerAccountRequest: RegisterAccountRequest): Account { + val userAccount = Account.register( + registerAccountRequest.email, + registerAccountRequest.password, + registerAccountRequest.username, + registerAccountRequest.phoneNumber + ) + userAccount.id = 1L + return userAccount + } + + fun mockAdminAccountFrom(registerAccountRequest: RegisterAdminAccountRequest): Account { + val userAccount = Account.register( + registerAccountRequest.email, + registerAccountRequest.password, + registerAccountRequest.username, + registerAccountRequest.phoneNumber + ) + userAccount.id = 1L + return userAccount + } } \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt index 6b1c176..bb68cd9 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt @@ -27,7 +27,7 @@ import org.springframework.test.web.servlet.result.MockMvcResultMatchers import java.time.LocalDateTime class PaymentApiTest @Autowired constructor( - private val accountRepository: AccountRepository, +// private val accountRepository: AccountRepository, private val paymentHistoryRepository: PaymentHistoryRepository, private val paymentOrderRepository: PaymentOrderRepository ) : AbstractApiTest() { From c73a26a552c7695d59d91f44f5055ccf43a4b772 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Tue, 5 Dec 2023 20:57:11 +0900 Subject: [PATCH 12/16] =?UTF-8?q?Refactor:=20=EC=A2=80=20=EB=8D=94=20?= =?UTF-8?q?=EA=B0=80=EB=B3=8D=EA=B3=A0=20=EA=B8=B0=EB=8A=A5=EC=9D=84=20?= =?UTF-8?q?=EB=AA=85=ED=99=95=ED=95=98=EA=B2=8C=20=EB=AA=85=EC=84=B8?= =?UTF-8?q?=ED=99=94=ED=95=98=EA=B8=B0=20=EC=9C=84=ED=95=B4=20=EA=B8=B0?= =?UTF-8?q?=EC=A1=B4=20payment=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=EC=97=90=20mockBean=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../paymentslab/AbstractApiTest.kt | 8 ++ .../presentation/MockAuthentication.kt | 12 ++ .../payment/presentation/PaymentApiTest.kt | 132 +++++++----------- .../payment/presentation/mock/MockPayments.kt | 61 ++++++++ .../payment/domain/entity/PaymentHistory.kt | 2 +- .../payment/domain/entity/PaymentOrder.kt | 7 +- 6 files changed, 139 insertions(+), 83 deletions(-) diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt index 5ec80cf..87729f1 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt @@ -9,6 +9,8 @@ import org.collaborators.paymentslab.account.domain.Account import org.collaborators.paymentslab.account.domain.AccountRepository import org.collaborators.paymentslab.account.domain.PasswordEncrypt import org.collaborators.paymentslab.account.domain.TokenGenerator +import org.collaborators.paymentslab.payment.domain.repository.PaymentHistoryRepository +import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.extension.ExtendWith import org.springframework.beans.factory.annotation.Autowired @@ -67,6 +69,12 @@ abstract class AbstractApiTest { @MockBean protected lateinit var accountRepository: AccountRepository + @MockBean + protected lateinit var paymentHistoryRepository: PaymentHistoryRepository + + @MockBean + protected lateinit var paymentOrderRepository: PaymentOrderRepository + protected fun testEntityForRegister(email: String): Account { val account = Account.register( email, diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt index 0e25c23..bce5113 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt @@ -1,5 +1,6 @@ package org.collaborators.paymentslab.account.presentation +import org.collaborator.paymentlab.common.Role import org.collaborators.paymentslab.account.domain.Account import org.collaborators.paymentslab.account.presentation.request.RegisterAccountRequest import org.collaborators.paymentslab.account.presentation.request.RegisterAdminAccountRequest @@ -23,6 +24,17 @@ object MockAuthentication { return account } + fun mockAdminAccount(): Account { + val account = Account.register( + "hello2@gmail.com", + testEncrypyPassword, "hello2", "010-1234-1234", hashSetOf(Role.USER, Role.ADMIN) + ) + account.id = 1L + account.emailVerified = true + return account + + } + fun mockWrongUserAccount(): Account { val account = Account.register( testWrongReissuerEmail, diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt index bb68cd9..85f515b 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt @@ -5,17 +5,19 @@ import org.collaborator.paymentlab.common.PAYMENT_ORDER import org.collaborator.paymentlab.common.Role import org.collaborator.paymentlab.common.V1_TOSS_PAYMENTS import org.collaborators.paymentslab.AbstractApiTest -import org.collaborators.paymentslab.account.domain.AccountRepository +import org.collaborators.paymentslab.account.presentation.MockAuthentication +import org.collaborators.paymentslab.payment.data.PageData import org.collaborators.paymentslab.payment.domain.entity.PaymentHistory import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder import org.collaborators.paymentslab.payment.domain.entity.PaymentsStatus -import org.collaborators.paymentslab.payment.domain.repository.PaymentHistoryRepository -import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository +import org.collaborators.paymentslab.payment.infrastructure.tosspayments.exception.PaymentOrderNotFoundException import org.collaborators.paymentslab.payment.presentation.mock.MockPayments import org.collaborators.paymentslab.payment.presentation.request.PaymentOrderRequest import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test -import org.springframework.beans.factory.annotation.Autowired +import org.mockito.Mock +import org.mockito.kotlin.any +import org.mockito.kotlin.given import org.springframework.http.MediaType import org.springframework.restdocs.mockmvc.MockMvcRestDocumentation import org.springframework.restdocs.mockmvc.RestDocumentationRequestBuilders @@ -26,26 +28,18 @@ import org.springframework.restdocs.payload.RequestFieldsSnippet import org.springframework.test.web.servlet.result.MockMvcResultMatchers import java.time.LocalDateTime -class PaymentApiTest @Autowired constructor( -// private val accountRepository: AccountRepository, - private val paymentHistoryRepository: PaymentHistoryRepository, - private val paymentOrderRepository: PaymentOrderRepository -) : AbstractApiTest() { +class PaymentApiTest: AbstractApiTest() { @Test @DisplayName("카드결제 api 동작") fun keyIn() { - val account = testEntityForAdminRegister("keyInTest@gmail.com") - accountRepository.save(account) + val account = MockAuthentication.mockAdminAccount() + given(accountRepository.findByEmail(any())).willReturn(account) val requestDto = MockPayments.testTossPaymentsRequest - val paymentOrder = PaymentOrder.newInstance( - account.id()!!, - requestDto.orderName, - requestDto.amount - ) - paymentOrderRepository.save(paymentOrder) + val paymentOrder = MockPayments.mockReadyPaymentOrder(account) + given(paymentOrderRepository.findById(paymentOrder.id()!!)).willReturn(paymentOrder) val reqBody = this.objectMapper.writeValueAsString(requestDto) val tokens = tokenGenerator.generate(account.email, setOf(Role.USER)) @@ -71,17 +65,13 @@ class PaymentApiTest @Autowired constructor( @Test @DisplayName("카드번호 입력에 숫자가 아닌 값이 입력되거나 총 16자가 아니면 에러가 발생한다.") fun cardNumErrorKeyIn() { - val account = testEntityForAdminRegister("keyInCardNumTest@gmail.com") - accountRepository.save(account) + val account = MockAuthentication.mockAdminAccount() + given(accountRepository.findByEmail(any())).willReturn(account) val requestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest - val paymentOrder = PaymentOrder.newInstance( - account.id()!!, - requestDto.orderName, - requestDto.amount - ) - paymentOrderRepository.save(paymentOrder) + val paymentOrder = MockPayments.mockReadyPaymentOrder(account) + given(paymentOrderRepository.findById(paymentOrder.id()!!)).willReturn(paymentOrder) val reqBody = this.objectMapper.writeValueAsString(requestDto) val tokens = tokenGenerator.generate(account.email, setOf(Role.USER)) @@ -108,17 +98,12 @@ class PaymentApiTest @Autowired constructor( @Test @DisplayName("주문 결제 정보가 존재하지 않는 주문 결제로 변조된 경우 결제 승인이 실패한다.") fun paymentError() { - val account = testEntityForAdminRegister("keyInWrongPaymentOrderTest@gmail.com") - accountRepository.save(account) + val account = MockAuthentication.mockAdminAccount() + given(accountRepository.findByEmail(any())).willReturn(account) - val requestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest + val requestDto = MockPayments.testTossPaymentsRequest - val paymentOrder = PaymentOrder.newInstance( - account.id()!!, - requestDto.orderName, - requestDto.amount - ) - paymentOrderRepository.save(paymentOrder) + given(paymentOrderRepository.findById(any())).willThrow(PaymentOrderNotFoundException()) val reqBody = this.objectMapper.writeValueAsString(requestDto) val tokens = tokenGenerator.generate(account.email, setOf(Role.USER)) @@ -145,19 +130,16 @@ class PaymentApiTest @Autowired constructor( @Test @DisplayName("주문 결제 정보의 소유자가 아닌 다른 사용자 계정으로 결제 승인을 요청할 경우 해당 결제 요청은 실패한다.") fun paymentWrongUserError() { - val account = testEntityForAdminRegister("keyInWrongUserTest@gmail.com") - val wrongAccount = testEntityForAdminRegister("wrongUser123@gmail.com") - accountRepository.save(account) - accountRepository.save(wrongAccount) + val account = MockAuthentication.mockAdminAccount() + val wrongAccount = MockAuthentication.mockWrongUserAccount() + given(accountRepository.findByEmail(any())).willReturn(account) val requestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest - val paymentOrder = PaymentOrder.newInstance( - account.id()!!, - requestDto.orderName, - requestDto.amount - ) - paymentOrderRepository.save(paymentOrder) + val paymentOrder = MockPayments.mockReadyPaymentOrder(account) + + val mockWrongPaymentsOrder = MockPayments.mockReadyPaymentOrder(wrongAccount) + given(paymentOrderRepository.findById(mockWrongPaymentsOrder.id()!!)).willReturn(mockWrongPaymentsOrder) val reqBody = this.objectMapper.writeValueAsString(requestDto) val wrongToken = tokenGenerator.generate(wrongAccount.email, setOf(Role.USER)) @@ -184,18 +166,13 @@ class PaymentApiTest @Autowired constructor( @Test @DisplayName("이미 결제 진행이 불가능한 주문 결제를 승인 요청할 경우 해당 요청은 실패한다.") fun paymentAlreadyDonePaymentOrderError() { - val account = testEntityForAdminRegister("keyInInvalidStatusTest@gmail.com") - accountRepository.save(account) + val account = MockAuthentication.mockAdminAccount() + given(accountRepository.findByEmail(any())).willReturn(account) val requestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest - val paymentOrder = PaymentOrder.newInstance( - account.id()!!, - requestDto.orderName, - requestDto.amount, - PaymentsStatus.CANCELED - ) - paymentOrderRepository.save(paymentOrder) + val paymentOrder = MockPayments.mockCanceledPaymentOrder(account) + given(paymentOrderRepository.findById(paymentOrder.id()!!)).willReturn(paymentOrder) val reqBody = this.objectMapper.writeValueAsString(requestDto) val wrongToken = tokenGenerator.generate(account.email, setOf(Role.USER)) @@ -222,17 +199,14 @@ class PaymentApiTest @Autowired constructor( @Test @DisplayName("변조된 결제요청 정보로 결제 승인 요청할 경우 해당 요청은 실패한다.") fun paymentInvalidPaymentOrderError() { - val account = testEntityForAdminRegister("keyInInvalidPaymentOrderTest@gmail.com") - accountRepository.save(account) + val account = MockAuthentication.mockAdminAccount() + given(accountRepository.findByEmail(any())).willReturn(account) val wrongRequestDto = MockPayments.invalidCardNumberTestTossPaymentsRequest - val paymentOrder = PaymentOrder.newInstance( - account.id()!!, - "originOrderName", - wrongRequestDto.amount - ) - paymentOrderRepository.save(paymentOrder) + val paymentOrder = MockPayments.mockReadyPaymentOrder(account) + val mutatedPaymentOrder = MockPayments.mockMutatedReadyPaymentOrder(account) + given(paymentOrderRepository.findById(paymentOrder.id()!!)).willReturn(mutatedPaymentOrder) val reqBody = this.objectMapper.writeValueAsString(wrongRequestDto) val wrongToken = tokenGenerator.generate(account.email, setOf(Role.USER)) @@ -261,21 +235,14 @@ class PaymentApiTest @Autowired constructor( @Test @DisplayName("사용자 계정별 카드결제 이력 조회 api") fun readHistoriesTest() { - val account = testEntityForAdminRegister("readHistoriesTest@gmail.com") - val entity = accountRepository.save(account) + val account = MockAuthentication.mockUserAccount() + given(accountRepository.findByEmail(any())).willReturn(account) val tokens = tokenGenerator.generate(account.email, setOf(Role.USER)) - paymentHistoryRepository.save( - PaymentHistory.newInstanceFrom( - entity.id()!!, - LocalDateTime.now(), - "ord_202306172137299642490491", - "테스트결제", - 10000, - "testPaymentKey", - "DONE" - )) + val paymentHistory = MockPayments.mockPaymentHistory(account) + val defaultPageData = PageData(0, 6, "DESC", listOf("id") ) + given(paymentHistoryRepository.findAllByAccountId(account.id()!!, defaultPageData)).willReturn(listOf(paymentHistory)) this.mockMvc.perform( RestDocumentationRequestBuilders @@ -318,11 +285,12 @@ class PaymentApiTest @Autowired constructor( @Test @DisplayName("주문 결제 발행 api 테스트") fun testGeneratePaymentOrder() { - val account = testEntityForRegister("generatePaymentOrder@gmail.com") - val entity = accountRepository.save(account) + val account = MockAuthentication.mockUserAccount() + given(accountRepository.findByEmail(any())).willReturn(account) val tokens = tokenGenerator.generate(account.email, setOf(Role.USER)) - val reqBody = objectMapper.writeValueAsString(PaymentOrderRequest(entity.id()!!, "테스트 주문상품", 10)) + val reqBody = objectMapper.writeValueAsString(PaymentOrderRequest(account.id()!!, "테스트 주문상품", 10)) + given(paymentOrderRepository.save(any())).willReturn(MockPayments.mockCreatedPaymentOrder(account)) this.mockMvc.perform( RestDocumentationRequestBuilders @@ -354,12 +322,14 @@ class PaymentApiTest @Autowired constructor( @Test @DisplayName("변조된 사용자 계정 id로 주문 결제 발행 api 테스트") fun testWithInvalidAccountGeneratePaymentOrder() { - val account = testEntityForRegister("originalGeneratedPaymentOrder@gmail.com") - accountRepository.save(account) - val invalidAccountId = 9999L - val tokens = tokenGenerator.generate(account.email, setOf(Role.USER)) - val invalidPaymentOrderRequest = PaymentOrderRequest(invalidAccountId, "잘못된 테스트 주문상품", 10) + val account = MockAuthentication.mockUserAccount() + given(accountRepository.findByEmail(any())).willReturn(account) + val wrongAccount = MockAuthentication.mockWrongUserAccount() + + val tokens = tokenGenerator.generate(wrongAccount.email, setOf(Role.USER)) + val invalidPaymentOrderRequest = PaymentOrderRequest(wrongAccount.id()!!, "잘못된 테스트 주문상품", 10) val reqBody = objectMapper.writeValueAsString(invalidPaymentOrderRequest) + given(paymentOrderRepository.save(any())).willReturn(MockPayments.mockMutatedReadyPaymentOrder(wrongAccount)) this.mockMvc.perform( RestDocumentationRequestBuilders diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPayments.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPayments.kt index d3987bb..6dab6d6 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPayments.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPayments.kt @@ -1,6 +1,10 @@ package org.collaborators.paymentslab.payment.presentation.mock +import org.collaborators.paymentslab.account.domain.Account +import org.collaborators.paymentslab.payment.domain.entity.PaymentHistory +import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder import org.collaborators.paymentslab.payment.presentation.request.TossPaymentsKeyInRequest +import java.time.LocalDateTime object MockPayments { val testTossPaymentsRequest = TossPaymentsKeyInRequest( @@ -22,4 +26,61 @@ object MockPayments { cardPassword = "12", customerIdentityNumber = "991212", ) + + fun mockPaymentHistory(account: Account): PaymentHistory { + val paymentHistory = PaymentHistory.newInstanceFrom( + account.id()!!, + LocalDateTime.now(), + "ord_202306172137299642490491", + "테스트결제", + 10000, + "testPaymentKey", + "DONE" + ) + paymentHistory.id = 1L + return paymentHistory + } + + fun mockMutatedReadyPaymentOrder(account: Account): PaymentOrder { + val paymentOrder = PaymentOrder.newInstance( + account.id ?: 1L, + testTossPaymentsRequest.orderName, + 20000 + ) + paymentOrder.id = 1L + paymentOrder.ready() + return paymentOrder + } + + fun mockCreatedPaymentOrder(account: Account): PaymentOrder { + val paymentOrder = PaymentOrder.newInstance( + account.id ?: 1L, + testTossPaymentsRequest.orderName, + testTossPaymentsRequest.amount + ) + paymentOrder.id = 1L + return paymentOrder + } + + fun mockReadyPaymentOrder(account: Account): PaymentOrder { + val paymentOrder = PaymentOrder.newInstance( + account.id ?: 1L, + testTossPaymentsRequest.orderName, + testTossPaymentsRequest.amount + ) + paymentOrder.id = 1L + paymentOrder.ready() + return paymentOrder + } + + fun mockCanceledPaymentOrder(account: Account): PaymentOrder { + val paymentOrder = PaymentOrder.newInstance( + account.id ?: 1L, + testTossPaymentsRequest.orderName, + testTossPaymentsRequest.amount + ) + paymentOrder.id = 1L + paymentOrder.cancel() + return paymentOrder + } } \ No newline at end of file diff --git a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentHistory.kt b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentHistory.kt index 53eeccf..116586e 100644 --- a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentHistory.kt +++ b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentHistory.kt @@ -27,7 +27,7 @@ class PaymentHistory protected constructor( ) { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - val id: Long? = null + var id: Long? = null companion object { private fun newInstanceFrom(event: PaymentOrderRecordEvent): PaymentHistory { diff --git a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentOrder.kt b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentOrder.kt index 3d16ff5..8555af2 100644 --- a/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentOrder.kt +++ b/payment-api/payment-domain/src/main/kotlin/org/collaborators/paymentslab/payment/domain/entity/PaymentOrder.kt @@ -21,7 +21,7 @@ class PaymentOrder protected constructor( ): AbstractAggregateRoot() { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - private val id: Long? = null + var id: Long? = null override fun id(): Long? { return this.id @@ -42,6 +42,11 @@ class PaymentOrder protected constructor( registerEvent(PaymentOrderRecordEvent(this)) } + fun cancel() { + this.status = PaymentsStatus.CANCELED + registerEvent(PaymentOrderRecordEvent(this)) + } + fun complete() { this.status = PaymentsStatus.DONE registerEvent(PaymentOrderRecordEvent(this)) From 4a510a016ddde9403fa7854831888cfdc84104f9 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Wed, 6 Dec 2023 12:12:17 +0900 Subject: [PATCH 13/16] =?UTF-8?q?Test:=20=ED=9A=A8=EC=9C=A8=EC=A0=81?= =?UTF-8?q?=EC=9D=B8=20=ED=85=8C=EC=8A=A4=ED=8A=B8=EB=A5=BC=20=EC=9C=84?= =?UTF-8?q?=ED=95=B4=20dev/prod=20=ED=99=98=EA=B2=BD=EC=9D=84=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC=ED=95=98=EC=97=AC=20=EB=B9=84=EC=A6=88=EB=8B=88?= =?UTF-8?q?=EC=8A=A4=20=EB=A1=9C=EC=A7=81=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=97=90=20=EC=A7=91=EC=A4=91=ED=95=98=EA=B3=A0,=20=EB=B6=88?= =?UTF-8?q?=ED=95=84=EC=9A=94=ED=95=9C=20embedded=20=EC=84=9C=EB=B2=84=20?= =?UTF-8?q?=ED=99=98=EA=B2=BD(h2,=20kafkaBroker)=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../paymentslab/AbstractApiTest.kt | 53 ++++++------------- 1 file changed, 16 insertions(+), 37 deletions(-) diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt index 87729f1..316488c 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt @@ -11,8 +11,12 @@ import org.collaborators.paymentslab.account.domain.PasswordEncrypt import org.collaborators.paymentslab.account.domain.TokenGenerator import org.collaborators.paymentslab.payment.domain.repository.PaymentHistoryRepository import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository +import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.extension.ExtendWith +import org.mockito.kotlin.any +import org.mockito.kotlin.doNothing +import org.mockito.kotlin.given import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs @@ -32,7 +36,6 @@ import org.springframework.test.context.ActiveProfiles import org.springframework.test.web.servlet.MockMvc @TestInstance(TestInstance.Lifecycle.PER_CLASS) -@EmbeddedKafka(partitions = 1, brokerProperties = ["listeners=PLAINTEXT://localhost:29092"], ports = [9092]) @AutoConfigureMockMvc @AutoConfigureRestDocs(uriScheme = URI_SCHEME, uriHost = URI_HOST, uriPort = URI_PORT) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) @@ -40,20 +43,6 @@ import org.springframework.test.web.servlet.MockMvc @ActiveProfiles("test") abstract class AbstractApiTest { - @Autowired - protected lateinit var mockMvc: MockMvc - - @Autowired - protected lateinit var objectMapper: ObjectMapper - - @Autowired - protected lateinit var tokenGenerator: TokenGenerator - - @Autowired lateinit var encrypt: PasswordEncrypt - - @Autowired - protected lateinit var kafkaTemplate: KafkaTemplate - @Value("\${uri.scheme}") protected lateinit var scheme: String @@ -66,6 +55,17 @@ abstract class AbstractApiTest { @Value("\${admin.key}") protected lateinit var adminKey: String + @Autowired + protected lateinit var mockMvc: MockMvc + + @Autowired + protected lateinit var tokenGenerator: TokenGenerator + + @Autowired lateinit var encrypt: PasswordEncrypt + + @MockBean + protected lateinit var kafkaTemplate: KafkaTemplate + @MockBean protected lateinit var accountRepository: AccountRepository @@ -75,28 +75,7 @@ abstract class AbstractApiTest { @MockBean protected lateinit var paymentOrderRepository: PaymentOrderRepository - protected fun testEntityForRegister(email: String): Account { - val account = Account.register( - email, - encrypt.encode("qqqwww123"), - "testName", - "010-1234-1234" - ) - account.completeRegister() - return account - } - - protected fun testEntityForAdminRegister(email: String): Account { - val account = Account.register( - email, - encrypt.encode("qqqwww123"), - "testName", - "010-1234-1234", - hashSetOf(Role.USER, Role.ADMIN) - ) - account.completeRegister() - return account - } + protected val objectMapper: ObjectMapper = ObjectMapper() protected fun getDocumentRequest(): OperationRequestPreprocessor { return Preprocessors.preprocessRequest( From 9439d6c33a7818ef941d45ecb8b465711e74a5a1 Mon Sep 17 00:00:00 2001 From: wanniDev Date: Wed, 6 Dec 2023 12:13:27 +0900 Subject: [PATCH 14/16] =?UTF-8?q?Remove:=20Mockito=EB=A1=9C=EB=8F=84=20?= =?UTF-8?q?=EC=B6=A9=EB=B6=84=ED=9E=88=20=EB=AA=A8=ED=82=B9=EC=9D=B4=20?= =?UTF-8?q?=EA=B0=80=EB=8A=A5=ED=95=98=EB=AF=80=EB=A1=9C=20=EC=8B=A4?= =?UTF-8?q?=EC=88=98=EB=A1=9C=20=EC=9D=B8=ED=95=9C=20=EC=83=9D=EC=82=B0?= =?UTF-8?q?=EC=84=B1=20=EC=A0=80=ED=95=98=EB=A5=BC=20=EC=95=BC=EA=B8=B0?= =?UTF-8?q?=EC=8B=9C=ED=82=AC=20=EC=88=98=20=EC=9E=88=EB=8A=94=20in-memory?= =?UTF-8?q?-repository=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../InMemoryAccountRepository.kt | 10 ----- .../InMemoryAccountRepositoryAdapter.kt | 37 ------------------- .../InMemoryPaymentOrderRepository.kt | 9 ----- .../InMemoryPaymentOrderRepositoryAdapter.kt | 21 ----------- 4 files changed, 77 deletions(-) delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepository.kt delete mode 100644 app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepositoryAdapter.kt diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt deleted file mode 100644 index b5d1b5d..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepository.kt +++ /dev/null @@ -1,10 +0,0 @@ -package org.collaborators.paymentslab.account.infrastructure - -import org.collaborator.paymentlab.common.inmemory.core.InMemoryRepository -import org.collaborators.paymentslab.account.domain.Account - -class InMemoryAccountRepository: InMemoryRepository(Long::class.java) { - fun findByAccountKey(accountKey: String): Account { - return findAll().first { it.accountKey == accountKey } - } -} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt deleted file mode 100644 index 10684a5..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/account/infrastructure/InMemoryAccountRepositoryAdapter.kt +++ /dev/null @@ -1,37 +0,0 @@ -package org.collaborators.paymentslab.account.infrastructure - -import org.collaborator.paymentlab.common.error.ErrorCode -import org.collaborator.paymentlab.common.error.ResourceNotFoundException -import org.collaborators.paymentslab.account.domain.Account -import org.collaborators.paymentslab.account.domain.AccountRepository - - -class InMemoryAccountRepositoryAdapter( - private val inMemoryAccountRepository: InMemoryAccountRepository -): AccountRepository { - override fun existByEmail(email: String): Boolean { - return inMemoryAccountRepository.findAll().any { it.email == email } - } - - override fun existByPhoneNumber(phoneNumber: String): Boolean { - return inMemoryAccountRepository.findAll().any { it.phoneNumber == phoneNumber } - } - - override fun save(account: Account): Account { - return inMemoryAccountRepository.save(account) - } - - override fun findByEmail(email: String): Account { - if (!existByEmail(email)) - throw ResourceNotFoundException(ErrorCode.ACCOUNT_NOT_FOUND) - return inMemoryAccountRepository.findAll().first { it.email == email } - } - - override fun findById(accountId: String): Account { - return inMemoryAccountRepository.findByAccountKey(accountId) - } - - override fun existByUsername(username: String): Boolean { - return inMemoryAccountRepository.findAll().any { it.username == username } - } -} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepository.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepository.kt deleted file mode 100644 index 8fe83ae..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepository.kt +++ /dev/null @@ -1,9 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure - -import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder -import org.collaborator.paymentlab.common.inmemory.core.InMemoryRepository -import org.springframework.stereotype.Component - -@Component -class InMemoryPaymentOrderRepository: InMemoryRepository(Long::class.java) { -} \ No newline at end of file diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepositoryAdapter.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepositoryAdapter.kt deleted file mode 100644 index e0a1db4..0000000 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/infrastructure/InMemoryPaymentOrderRepositoryAdapter.kt +++ /dev/null @@ -1,21 +0,0 @@ -package org.collaborators.paymentslab.payment.infrastructure - -import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder -import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository -import org.collaborators.paymentslab.payment.infrastructure.tosspayments.exception.PaymentOrderNotFoundException -import org.springframework.context.annotation.Profile -import org.springframework.stereotype.Repository - -@Repository -@Profile(value = ["test"]) -class InMemoryPaymentOrderRepositoryAdapter( - private val inMemoryPaymentOrderRepository: InMemoryPaymentOrderRepository -): PaymentOrderRepository { - override fun save(entity: PaymentOrder): PaymentOrder { - return inMemoryPaymentOrderRepository.save(entity) - } - - override fun findById(id: Long): PaymentOrder { - return inMemoryPaymentOrderRepository.findById(id) ?: throw PaymentOrderNotFoundException() - } -} \ No newline at end of file From 062cadbd26fe423b40f8b8b2e827b391c1e42bee Mon Sep 17 00:00:00 2001 From: wanniDev Date: Wed, 6 Dec 2023 13:17:58 +0900 Subject: [PATCH 15/16] =?UTF-8?q?Test:=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= =?UTF-8?q?=EC=9A=A9=20=EA=B2=B0=EC=A0=9C=20=EC=8A=B9=EC=9D=B8=EC=9A=94?= =?UTF-8?q?=EC=B2=AD=20=EB=AA=A9=20=EA=B0=9D=EC=B2=B4=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../payment/presentation/mock/MockPayments.kt | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPayments.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPayments.kt index 6dab6d6..744d490 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPayments.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/mock/MockPayments.kt @@ -1,8 +1,13 @@ package org.collaborators.paymentslab.payment.presentation.mock import org.collaborators.paymentslab.account.domain.Account +import org.collaborators.paymentslab.payment.application.command.TossPaymentsKeyInPayCommand import org.collaborators.paymentslab.payment.domain.entity.PaymentHistory import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder +import org.collaborators.paymentslab.payment.domain.entity.PaymentsStatus +import org.collaborators.paymentslab.payment.infrastructure.tosspayments.TossPaymentsApprovalResponse +import org.collaborators.paymentslab.payment.infrastructure.tosspayments.TossPaymentsCardInfoResponse +import org.collaborators.paymentslab.payment.infrastructure.tosspayments.TossPaymentsKeyInDto import org.collaborators.paymentslab.payment.presentation.request.TossPaymentsKeyInRequest import java.time.LocalDateTime @@ -83,4 +88,39 @@ object MockPayments { paymentOrder.cancel() return paymentOrder } + fun mockTossPaymentsKeyInDto(command: TossPaymentsKeyInPayCommand) = TossPaymentsKeyInDto( + command.amount, + command.orderId, + command.orderName, + command.cardNumber, + command.cardExpirationYear, + command.cardExpirationMonth, + command.cardPassword, + command.customerIdentityNumber + ) + + fun mockTossPaymentsApproval(reqBody: TossPaymentsKeyInDto) = TossPaymentsApprovalResponse( + mId = "tvivarepublica4", + lastTransactionKey = "2A441542485089863EB31F9B039FEFF8", + paymentKey = "4qjZblEopLBa5PzR0Arn9KeQDGJPxkVvmYnNeDMyW2G1OgwK", + orderId = reqBody.orderId, + orderName = reqBody.orderName, + taxExemptionAmount = 0, + status = PaymentsStatus.DONE.name, + useEscrow = false, + cultureExpense = false, + card = TossPaymentsCardInfoResponse( + issuerCode = "4V", + acquirerCode = "21", + number = reqBody.cardNumber, + installmentPlanMonths = 0, + isInterestFree = false, + approveNo = "00000000", + useCardPoint = false, + cardType = "미확인", + ownerType = "미확인", + acquireStatus = "READY", + amount = reqBody.amount + ) + ) } \ No newline at end of file From b927ad708f7c817b392aaf15c7a32bee51661c4e Mon Sep 17 00:00:00 2001 From: wanniDev Date: Wed, 6 Dec 2023 13:25:27 +0900 Subject: [PATCH 16/16] =?UTF-8?q?Refactor:=20merge=20=ED=95=98=EA=B8=B0?= =?UTF-8?q?=EC=A0=84=EC=97=90=20import,=20=EB=B3=80=EC=88=98=20=EC=A0=9C?= =?UTF-8?q?=EC=96=B4=EC=9E=90,=20=EB=B9=84=EC=96=B4=EC=9E=88=EB=8A=94=20?= =?UTF-8?q?=ED=81=B4=EB=9E=98=EC=8A=A4=20=EB=B3=B8=EB=AC=B8=20=EB=B8=94?= =?UTF-8?q?=EB=A1=9D=20=EC=A0=95=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../account/application/AccountService.kt | 1 - .../infrastructure/AccountModuleConfiguration.kt | 3 +-- .../account/presentation/AuthenticationApi.kt | 1 - .../paymentslab/config/security/SecurityConfig.kt | 1 - .../paymentslab/support/GlobalExceptionHandler.kt | 2 +- .../org/collaborators/paymentslab/AbstractApiTest.kt | 7 ------- .../account/presentation/MockAuthentication.kt | 12 ++++++------ .../payment/presentation/PaymentApiTest.kt | 5 ----- .../org/collaborator/paymentlab/common/Role.kt | 2 +- .../inmemory/core/SequentialLongIdGenerator.kt | 2 +- .../payment/application/PaymentService.kt | 3 --- .../infrastructure/jpa/JpaTossPaymentRepository.kt | 3 +-- .../tosspayments/TossPaymentsApprovalResponse.kt | 1 - .../tosspayments/TossPaymentsProcessor.kt | 2 -- .../InvalidPaymentOrderAccountIdException.kt | 2 +- 15 files changed, 12 insertions(+), 35 deletions(-) diff --git a/account-api/account-application/src/main/kotlin/org/collaborators/paymentslab/account/application/AccountService.kt b/account-api/account-application/src/main/kotlin/org/collaborators/paymentslab/account/application/AccountService.kt index a95a1bc..e0be823 100644 --- a/account-api/account-application/src/main/kotlin/org/collaborators/paymentslab/account/application/AccountService.kt +++ b/account-api/account-application/src/main/kotlin/org/collaborators/paymentslab/account/application/AccountService.kt @@ -3,7 +3,6 @@ package org.collaborators.paymentslab.account.application import org.collaborator.paymentlab.common.Role import org.collaborators.paymentslab.account.application.command.LoginAccount import org.collaborators.paymentslab.account.application.command.RegisterAccount -import org.collaborators.paymentslab.account.application.command.RegisterAdminAccount import org.collaborators.paymentslab.account.application.command.RegisterConfirm import org.collaborators.paymentslab.account.domain.* import org.slf4j.LoggerFactory diff --git a/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/AccountModuleConfiguration.kt b/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/AccountModuleConfiguration.kt index ab03da0..07426dc 100644 --- a/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/AccountModuleConfiguration.kt +++ b/account-api/account-infrastructure/src/main/kotlin/org/collaborators/paymentslab/account/infrastructure/AccountModuleConfiguration.kt @@ -27,5 +27,4 @@ import org.springframework.context.annotation.Import ] ) @Configuration -class AccountModuleConfiguration { -} \ No newline at end of file +class AccountModuleConfiguration \ No newline at end of file diff --git a/account-api/account-presentation/src/main/kotlin/org/collaborators/paymentslab/account/presentation/AuthenticationApi.kt b/account-api/account-presentation/src/main/kotlin/org/collaborators/paymentslab/account/presentation/AuthenticationApi.kt index 01889fc..e41e99f 100644 --- a/account-api/account-presentation/src/main/kotlin/org/collaborators/paymentslab/account/presentation/AuthenticationApi.kt +++ b/account-api/account-presentation/src/main/kotlin/org/collaborators/paymentslab/account/presentation/AuthenticationApi.kt @@ -6,7 +6,6 @@ import org.collaborator.paymentlab.common.result.ApiResult import org.collaborators.paymentslab.account.application.AccountService import org.collaborators.paymentslab.account.application.command.LoginAccount import org.collaborators.paymentslab.account.application.command.RegisterAccount -import org.collaborators.paymentslab.account.application.command.RegisterAdminAccount import org.collaborators.paymentslab.account.application.command.RegisterConfirm import org.collaborators.paymentslab.account.presentation.request.LoginAccountRequest import org.collaborators.paymentslab.account.presentation.request.RegisterAccountRequest diff --git a/app/src/main/kotlin/org/collaborators/paymentslab/config/security/SecurityConfig.kt b/app/src/main/kotlin/org/collaborators/paymentslab/config/security/SecurityConfig.kt index 2a32183..9be2c0a 100644 --- a/app/src/main/kotlin/org/collaborators/paymentslab/config/security/SecurityConfig.kt +++ b/app/src/main/kotlin/org/collaborators/paymentslab/config/security/SecurityConfig.kt @@ -9,7 +9,6 @@ import org.springframework.context.annotation.Import import org.springframework.context.annotation.Profile import org.springframework.http.HttpMethod.GET import org.springframework.http.HttpMethod.POST -import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity import org.springframework.security.config.annotation.web.builders.HttpSecurity import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity diff --git a/app/src/main/kotlin/org/collaborators/paymentslab/support/GlobalExceptionHandler.kt b/app/src/main/kotlin/org/collaborators/paymentslab/support/GlobalExceptionHandler.kt index 3935699..fec4f2d 100644 --- a/app/src/main/kotlin/org/collaborators/paymentslab/support/GlobalExceptionHandler.kt +++ b/app/src/main/kotlin/org/collaborators/paymentslab/support/GlobalExceptionHandler.kt @@ -102,7 +102,7 @@ class GlobalExceptionHandler(private val objectMapper: ObjectMapper): ErrorContr }.collect(Collectors.joining(" ")) } - private fun format(f: FieldError): String? { + private fun format(f: FieldError): String { return if (f.field == "password") { "Field : [" + f.field + "] " + "Reason: [" + f.defaultMessage + "]" } else "Field : [" + f.field + "] " + "Value: [" + f.rejectedValue + "]" diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt index 316488c..105a3fd 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/AbstractApiTest.kt @@ -1,22 +1,16 @@ package org.collaborators.paymentslab import com.fasterxml.jackson.databind.ObjectMapper -import org.collaborator.paymentlab.common.Role import org.collaborator.paymentlab.common.URI_HOST import org.collaborator.paymentlab.common.URI_PORT import org.collaborator.paymentlab.common.URI_SCHEME -import org.collaborators.paymentslab.account.domain.Account import org.collaborators.paymentslab.account.domain.AccountRepository import org.collaborators.paymentslab.account.domain.PasswordEncrypt import org.collaborators.paymentslab.account.domain.TokenGenerator import org.collaborators.paymentslab.payment.domain.repository.PaymentHistoryRepository import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository -import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.TestInstance import org.junit.jupiter.api.extension.ExtendWith -import org.mockito.kotlin.any -import org.mockito.kotlin.doNothing -import org.mockito.kotlin.given import org.springframework.beans.factory.annotation.Autowired import org.springframework.beans.factory.annotation.Value import org.springframework.boot.test.autoconfigure.restdocs.AutoConfigureRestDocs @@ -25,7 +19,6 @@ import org.springframework.boot.test.context.SpringBootTest import org.springframework.boot.test.mock.mockito.MockBean import org.springframework.kafka.core.* import org.springframework.kafka.listener.* -import org.springframework.kafka.test.context.EmbeddedKafka import org.springframework.restdocs.RestDocumentationExtension import org.springframework.restdocs.operation.preprocess.OperationRequestPreprocessor import org.springframework.restdocs.operation.preprocess.Preprocessors diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt b/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt index bce5113..a81fd74 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/account/presentation/MockAuthentication.kt @@ -6,13 +6,13 @@ import org.collaborators.paymentslab.account.presentation.request.RegisterAccoun import org.collaborators.paymentslab.account.presentation.request.RegisterAdminAccountRequest object MockAuthentication { - val expiredAccessToken = "eyJhbGciOiJIUzI1NiJ9.eyJzY29wZXMiOlsiUk9MRV9VU0VSIl0sImVtYWlsIjoiaGVsbG9AZ21haWwuY29tIiwiaXNzIjoicGF5bWVudHNsYWIiLCJpYXQiOjE2ODUyNzE1OTIsImV4cCI6MTY4NTI3MzM5Mn0.92iGkI5ugZ4kJmOyThfoOGGGNSshWx5e0NCn0pMfexw" - val expiredRefreshToken = "eyJhbGciOiJIUzI1NiJ9.eyJzY29wZXMiOlsiUk9MRV9VU0VSIl0sImVtYWlsIjoiaGVsbG9AZ21haWwuY29tIiwiaXNzIjoicGF5bWVudHNsYWIiLCJpYXQiOjE2ODUyODA3OTcsImV4cCI6MTY4NTI4MjU5N30.t9-Qb27MxTleqWVzfqyBouFg7LWndt67WW7Eoi-WXzM" + const val expiredAccessToken = "eyJhbGciOiJIUzI1NiJ9.eyJzY29wZXMiOlsiUk9MRV9VU0VSIl0sImVtYWlsIjoiaGVsbG9AZ21haWwuY29tIiwiaXNzIjoicGF5bWVudHNsYWIiLCJpYXQiOjE2ODUyNzE1OTIsImV4cCI6MTY4NTI3MzM5Mn0.92iGkI5ugZ4kJmOyThfoOGGGNSshWx5e0NCn0pMfexw" + const val expiredRefreshToken = "eyJhbGciOiJIUzI1NiJ9.eyJzY29wZXMiOlsiUk9MRV9VU0VSIl0sImVtYWlsIjoiaGVsbG9AZ21haWwuY29tIiwiaXNzIjoicGF5bWVudHNsYWIiLCJpYXQiOjE2ODUyODA3OTcsImV4cCI6MTY4NTI4MjU5N30.t9-Qb27MxTleqWVzfqyBouFg7LWndt67WW7Eoi-WXzM" - val testPlainPassword = "Qwer!234" - val testEncrypyPassword = "\$2a\$10\$w5Idz2dN9FQFam1ZT3OoS.ZDlDom4dLfi6jQrukabcUHrGw8Ju49u" - val testWrongPlainPassword = "wrong" - val testWrongReissuerEmail = "nouser123@gmail.com" + const val testPlainPassword = "Qwer!234" + const val testEncrypyPassword = "\$2a\$10\$w5Idz2dN9FQFam1ZT3OoS.ZDlDom4dLfi6jQrukabcUHrGw8Ju49u" + const val testWrongPlainPassword = "wrong" + const val testWrongReissuerEmail = "nouser123@gmail.com" fun mockUserAccount(): Account { val account = Account.register( diff --git a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt index 85f515b..777d5c0 100644 --- a/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt +++ b/app/src/test/kotlin/org/collaborators/paymentslab/payment/presentation/PaymentApiTest.kt @@ -7,15 +7,11 @@ import org.collaborator.paymentlab.common.V1_TOSS_PAYMENTS import org.collaborators.paymentslab.AbstractApiTest import org.collaborators.paymentslab.account.presentation.MockAuthentication import org.collaborators.paymentslab.payment.data.PageData -import org.collaborators.paymentslab.payment.domain.entity.PaymentHistory -import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder -import org.collaborators.paymentslab.payment.domain.entity.PaymentsStatus import org.collaborators.paymentslab.payment.infrastructure.tosspayments.exception.PaymentOrderNotFoundException import org.collaborators.paymentslab.payment.presentation.mock.MockPayments import org.collaborators.paymentslab.payment.presentation.request.PaymentOrderRequest import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.Test -import org.mockito.Mock import org.mockito.kotlin.any import org.mockito.kotlin.given import org.springframework.http.MediaType @@ -26,7 +22,6 @@ import org.springframework.restdocs.payload.JsonFieldType import org.springframework.restdocs.payload.PayloadDocumentation import org.springframework.restdocs.payload.RequestFieldsSnippet import org.springframework.test.web.servlet.result.MockMvcResultMatchers -import java.time.LocalDateTime class PaymentApiTest: AbstractApiTest() { diff --git a/common/src/main/kotlin/org/collaborator/paymentlab/common/Role.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/Role.kt index adce8fc..b184aae 100644 --- a/common/src/main/kotlin/org/collaborator/paymentlab/common/Role.kt +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/Role.kt @@ -11,7 +11,7 @@ enum class Role { companion object { fun findByRole(role: String): Role { return Arrays.stream(Role.values()) - .filter { r -> r.name.equals(role) } + .filter { r -> r.name == role } .findFirst() .orElseThrow { IllegalArgumentException() } } diff --git a/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/SequentialLongIdGenerator.kt b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/SequentialLongIdGenerator.kt index 1010f75..8b926e6 100644 --- a/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/SequentialLongIdGenerator.kt +++ b/common/src/main/kotlin/org/collaborator/paymentlab/common/inmemory/core/SequentialLongIdGenerator.kt @@ -1,7 +1,7 @@ package org.collaborator.paymentlab.common.inmemory.core class SequentialLongIdGenerator: IdGenerator { - private var sequence = 1L; + private var sequence = 1L override fun generateId(): Long { return this.sequence++ diff --git a/payment-api/payment-application/src/main/kotlin/org/collaborators/paymentslab/payment/application/PaymentService.kt b/payment-api/payment-application/src/main/kotlin/org/collaborators/paymentslab/payment/application/PaymentService.kt index be37c2c..e2bbf55 100644 --- a/payment-api/payment-application/src/main/kotlin/org/collaborators/paymentslab/payment/application/PaymentService.kt +++ b/payment-api/payment-application/src/main/kotlin/org/collaborators/paymentslab/payment/application/PaymentService.kt @@ -1,13 +1,10 @@ package org.collaborators.paymentslab.payment.application -import org.collaborators.paymentslab.payment.application.command.PaymentOrderCommand import org.collaborators.paymentslab.payment.application.command.TossPaymentsKeyInPayCommand import org.collaborators.paymentslab.payment.application.query.PaymentHistoryQuery import org.collaborators.paymentslab.payment.application.query.PaymentHistoryQueryQueryModel -import org.collaborators.paymentslab.payment.domain.PaymentOrderProcessor import org.collaborators.paymentslab.payment.domain.PaymentsProcessor import org.collaborators.paymentslab.payment.domain.PaymentsQueryManager -import org.springframework.context.annotation.Profile import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Propagation import org.springframework.transaction.annotation.Transactional diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/jpa/JpaTossPaymentRepository.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/jpa/JpaTossPaymentRepository.kt index 9a7f92d..83e8a71 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/jpa/JpaTossPaymentRepository.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/jpa/JpaTossPaymentRepository.kt @@ -3,5 +3,4 @@ package org.collaborators.paymentslab.payment.infrastructure.jpa import org.collaborators.paymentslab.payment.domain.entity.TossPayments import org.springframework.data.jpa.repository.JpaRepository -interface JpaTossPaymentRepository: JpaRepository { -} \ No newline at end of file +interface JpaTossPaymentRepository: JpaRepository \ No newline at end of file diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsApprovalResponse.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsApprovalResponse.kt index 8e12c0c..f593a5a 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsApprovalResponse.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsApprovalResponse.kt @@ -1,6 +1,5 @@ package org.collaborators.paymentslab.payment.infrastructure.tosspayments -import org.collaborators.paymentslab.payment.domain.TossPaymentsCardInfo import org.collaborators.paymentslab.payment.domain.entity.PaymentOrder import java.time.LocalDateTime diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt index 9e0faee..4d85998 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/TossPaymentsProcessor.kt @@ -2,8 +2,6 @@ package org.collaborators.paymentslab.payment.infrastructure.tosspayments import org.collaborators.paymentslab.payment.domain.PaymentsProcessor import org.collaborators.paymentslab.payment.domain.repository.PaymentOrderRepository -import org.springframework.transaction.annotation.Propagation -import org.springframework.transaction.annotation.Transactional open class TossPaymentsProcessor( private val tossPaymentsValidator: TossPaymentsValidator, diff --git a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/exception/InvalidPaymentOrderAccountIdException.kt b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/exception/InvalidPaymentOrderAccountIdException.kt index c255805..77e006b 100644 --- a/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/exception/InvalidPaymentOrderAccountIdException.kt +++ b/payment-api/payment-infrastructure/src/main/kotlin/org/collaborators/paymentslab/payment/infrastructure/tosspayments/exception/InvalidPaymentOrderAccountIdException.kt @@ -3,4 +3,4 @@ package org.collaborators.paymentslab.payment.infrastructure.tosspayments.except import org.collaborator.paymentlab.common.error.ErrorCode import org.collaborator.paymentlab.common.error.ServiceException -class InvalidPaymentOrderAccountIdException(): ServiceException(ErrorCode.INVALID_PAYMENT_ORDER_ACCOUNT_ID) \ No newline at end of file +class InvalidPaymentOrderAccountIdException : ServiceException(ErrorCode.INVALID_PAYMENT_ORDER_ACCOUNT_ID) \ No newline at end of file