From d640d7d52e99ea024accc1bf8a84d2f9ec953f0c Mon Sep 17 00:00:00 2001 From: jangjunha Date: Wed, 13 Sep 2023 19:52:41 +0900 Subject: [PATCH] test: add consumer test for order-service at order-history-service --- ftgo-api-gateway/build.gradle | 1 + ftgo-order-history-service/build.gradle | 4 + .../OrderHistoryServiceMain.kt | 5 + ...derHistoryServiceMessagingConfiguration.kt | 2 - .../OrderServicePactTest.kt | 180 ++++++++++++++++++ .../api/events/OrderAuthorized.kt | 10 +- .../order_service/api/events/OrderRejected.kt | 10 +- 7 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 ftgo-order-history-service/src/test/kotlin/me/jangjunha/ftgo/order_history_service/OrderServicePactTest.kt diff --git a/ftgo-api-gateway/build.gradle b/ftgo-api-gateway/build.gradle index 7faea92..faceb6f 100644 --- a/ftgo-api-gateway/build.gradle +++ b/ftgo-api-gateway/build.gradle @@ -49,5 +49,6 @@ tasks.named('test') { systemProperty("pact.provider.version", System.getenv("GIT_COMMIT") ?: "") systemProperty("pact.provider.tag", System.getenv("GIT_BRANCH") ?: "") systemProperty("pact.provider.branch", System.getenv("GIT_BRANCH") ?: "") + systemProperty("pactbroker.consumerversionselectors.rawjson", "[{\"mainBranch\":true}]") systemProperty("pact.verifier.publishResults", System.getenv("PACT_BROKER_PUBLISH_VERIFICATION_RESULTS") == null ? "false" : "true") } diff --git a/ftgo-order-history-service/build.gradle b/ftgo-order-history-service/build.gradle index a989172..cdfe42e 100644 --- a/ftgo-order-history-service/build.gradle +++ b/ftgo-order-history-service/build.gradle @@ -29,6 +29,10 @@ dependencies { implementation project(':ftgo-order-service-api') testImplementation "org.springframework.boot:spring-boot-starter-test:$springBootVersion" + testImplementation "io.eventuate.tram.core:eventuate-tram-spring-in-memory" + testImplementation "com.ninja-squad:springmockk:4.0.0" + testImplementation 'au.com.dius.pact.consumer:junit5:4.6.2' + testImplementation 'org.jetbrains.kotlin:kotlin-test-junit5' developmentOnly "org.springframework.boot:spring-boot-devtools:$springBootVersion" } diff --git a/ftgo-order-history-service/src/main/kotlin/me/jangjunha/ftgo/order_history_service/OrderHistoryServiceMain.kt b/ftgo-order-history-service/src/main/kotlin/me/jangjunha/ftgo/order_history_service/OrderHistoryServiceMain.kt index 178ea9f..5ce33d5 100644 --- a/ftgo-order-history-service/src/main/kotlin/me/jangjunha/ftgo/order_history_service/OrderHistoryServiceMain.kt +++ b/ftgo-order-history-service/src/main/kotlin/me/jangjunha/ftgo/order_history_service/OrderHistoryServiceMain.kt @@ -1,10 +1,15 @@ package me.jangjunha.ftgo.order_history_service +import io.eventuate.tram.spring.consumer.kafka.EventuateTramKafkaMessageConsumerConfiguration import org.springframework.boot.autoconfigure.SpringBootApplication import org.springframework.boot.runApplication +import org.springframework.context.annotation.Import import org.springframework.shell.command.annotation.EnableCommand @SpringBootApplication +@Import(value = [ + EventuateTramKafkaMessageConsumerConfiguration::class, +]) @EnableCommand(OrderHistoryCli::class) class OrderHistoryServiceApplication diff --git a/ftgo-order-history-service/src/main/kotlin/me/jangjunha/ftgo/order_history_service/messaging/OrderHistoryServiceMessagingConfiguration.kt b/ftgo-order-history-service/src/main/kotlin/me/jangjunha/ftgo/order_history_service/messaging/OrderHistoryServiceMessagingConfiguration.kt index 5d36b6f..916be1f 100644 --- a/ftgo-order-history-service/src/main/kotlin/me/jangjunha/ftgo/order_history_service/messaging/OrderHistoryServiceMessagingConfiguration.kt +++ b/ftgo-order-history-service/src/main/kotlin/me/jangjunha/ftgo/order_history_service/messaging/OrderHistoryServiceMessagingConfiguration.kt @@ -3,7 +3,6 @@ package me.jangjunha.ftgo.order_history_service.messaging import io.eventuate.tram.events.subscriber.DomainEventDispatcher import io.eventuate.tram.events.subscriber.DomainEventDispatcherFactory import io.eventuate.tram.spring.consumer.common.TramNoopDuplicateMessageDetectorConfiguration -import io.eventuate.tram.spring.consumer.kafka.EventuateTramKafkaMessageConsumerConfiguration import io.eventuate.tram.spring.events.common.TramEventsCommonAutoConfiguration import io.eventuate.tram.spring.events.subscriber.TramEventSubscriberConfiguration import io.eventuate.tram.spring.messaging.common.TramMessagingCommonAutoConfiguration @@ -18,7 +17,6 @@ import org.springframework.context.annotation.Import @Import(value = [ TramNoopDuplicateMessageDetectorConfiguration::class, TramEventSubscriberConfiguration::class, - EventuateTramKafkaMessageConsumerConfiguration::class, TramMessagingCommonAutoConfiguration::class, TramEventsCommonAutoConfiguration::class, ]) diff --git a/ftgo-order-history-service/src/test/kotlin/me/jangjunha/ftgo/order_history_service/OrderServicePactTest.kt b/ftgo-order-history-service/src/test/kotlin/me/jangjunha/ftgo/order_history_service/OrderServicePactTest.kt new file mode 100644 index 0000000..dac5b77 --- /dev/null +++ b/ftgo-order-history-service/src/test/kotlin/me/jangjunha/ftgo/order_history_service/OrderServicePactTest.kt @@ -0,0 +1,180 @@ +package me.jangjunha.ftgo.order_history_service + +import au.com.dius.pact.consumer.MessagePactBuilder +import au.com.dius.pact.consumer.dsl.PactDslJsonBody +import au.com.dius.pact.consumer.junit5.PactConsumerTestExt +import au.com.dius.pact.consumer.junit5.PactTestFor +import au.com.dius.pact.consumer.junit5.ProviderType +import au.com.dius.pact.core.model.PactSpecVersion +import au.com.dius.pact.core.model.annotations.Pact +import au.com.dius.pact.core.model.messaging.Message +import au.com.dius.pact.core.model.messaging.MessagePact +import com.ninjasquad.springmockk.MockkBean +import com.ninjasquad.springmockk.SpykBean +import io.eventuate.tram.events.subscriber.DomainEventDispatcher +import io.eventuate.tram.events.subscriber.DomainEventEnvelope +import io.eventuate.tram.messaging.common.MessageImpl +import io.eventuate.tram.spring.inmemory.TramInMemoryCommonConfiguration +import io.mockk.every +import io.mockk.slot +import me.jangjunha.ftgo.common.Money +import me.jangjunha.ftgo.order_history_service.messaging.OrderHistoryEventHandlers +import me.jangjunha.ftgo.order_history_service.messaging.OrderHistoryServiceMessagingConfiguration +import me.jangjunha.ftgo.order_service.api.OrderDetails +import me.jangjunha.ftgo.order_service.api.events.OrderAuthorized +import me.jangjunha.ftgo.order_service.api.events.OrderCreated +import me.jangjunha.ftgo.order_service.api.events.OrderRejected +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.extension.ExtendWith +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.autoconfigure.EnableAutoConfiguration +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.context.annotation.Configuration +import org.springframework.context.annotation.Import +import java.util.* + + +@ExtendWith(PactConsumerTestExt::class) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@PactTestFor(providerName = "ftgo-order-service", providerType = ProviderType.ASYNCH, pactVersion = PactSpecVersion.V3) +class OrderServicePactTest { + + @SpykBean + lateinit var orderHistoryEventHandlers: OrderHistoryEventHandlers + + @MockkBean(relaxed = true) + lateinit var orderHistoryDAO: OrderHistoryDAO + + @Autowired + lateinit var domainEventDispatcher: DomainEventDispatcher + + @Pact(consumer = "ftgo-order-history-service") + fun orderCreatedEvent(builder: MessagePactBuilder): MessagePact = builder + .expectsToReceive("`OrderCreated` event") + .withMetadata( + mapOf( + Pair("event-aggregate-type", "me.jangjunha.ftgo.order_service.domain.Order"), + Pair("event-type", "me.jangjunha.ftgo.order_service.api.events.OrderCreated"), + Pair("event-aggregate-id", "6f2d06a3-5dd2-4096-8644-6084d64eae35"), + Pair("ID", ""), + ) + ) + .withContent( + PactDslJsonBody() + .`object`( + "orderDetails", PactDslJsonBody() + .`object`("orderTotal", PactDslJsonBody().numberType("amount", 5000)) + .uuid("restaurantId", "97e3c4c2-f336-4435-9314-ad1a633495df") + .uuid("consumerId", "627a9a8a-41af-4daf-a968-00ffc80b53ad") + .eachLike("lineItems") + .numberType("quantity", 2) + .stringType("menuItemId", "americano") + .stringType("name", "Americano") + .`object`("price", PactDslJsonBody().numberType("amount", 2500)) + .closeObject()!! + .closeArray()!! + ) + .stringType("deliveryAddress", "서울시 강남구 테헤란로 1") + .stringType("restaurantName", "A Cafe") + ) + .toPact() + + @Test + @PactTestFor(pactMethod = "orderCreatedEvent") + fun testConsumeOrderCreatedEvent(messages: List) { + val arg = slot>() + every { orderHistoryEventHandlers["handleOrderCreated"](capture(arg)) } returns Unit + + val rawMessage = messages[0] + val message = MessageImpl(rawMessage.contentsAsString(), rawMessage.metadata.mapValues { it.value.toString() }) + domainEventDispatcher.messageHandler(message) + + assert(arg.isCaptured) + assert(arg.captured.aggregateType == "me.jangjunha.ftgo.order_service.domain.Order") + assert(arg.captured.aggregateId == "6f2d06a3-5dd2-4096-8644-6084d64eae35") + assert( + arg.captured.event == OrderCreated( + OrderDetails( + listOf( + OrderDetails.LineItem(2, "americano", "Americano", Money("2500")), + ), + Money("5000"), + UUID.fromString("97e3c4c2-f336-4435-9314-ad1a633495df"), + UUID.fromString("627a9a8a-41af-4daf-a968-00ffc80b53ad"), + ), + "서울시 강남구 테헤란로 1", + "A Cafe", + ) + ) + } + + @Pact(consumer = "ftgo-order-history-service") + fun orderAuthorizedEvent(builder: MessagePactBuilder): MessagePact = builder + .expectsToReceive("`OrderAuthorized` event") + .withMetadata( + mapOf( + Pair("event-aggregate-type", "me.jangjunha.ftgo.order_service.domain.Order"), + Pair("event-type", "me.jangjunha.ftgo.order_service.api.events.OrderAuthorized"), + Pair("event-aggregate-id", "6f2d06a3-5dd2-4096-8644-6084d64eae35"), + Pair("ID", ""), + ) + ) + .withContent(PactDslJsonBody()) + .toPact() + + @Test + @PactTestFor(pactMethod = "orderAuthorizedEvent") + fun testConsumeOrderAuthorizedEvent(messages: List) { + val arg = slot>() + every { orderHistoryEventHandlers["handleOrderAuthorized"](capture(arg)) } returns Unit + + val rawMessage = messages[0] + val message = MessageImpl(rawMessage.contentsAsString(), rawMessage.metadata.mapValues { it.value.toString() }) + domainEventDispatcher.messageHandler(message) + + assert(arg.isCaptured) + assert(arg.captured.aggregateType == "me.jangjunha.ftgo.order_service.domain.Order") + assert(arg.captured.aggregateId == "6f2d06a3-5dd2-4096-8644-6084d64eae35") + assert(arg.captured.event == OrderAuthorized()) + } + + @Pact(consumer = "ftgo-order-history-service") + fun orderRejectedEvent(builder: MessagePactBuilder): MessagePact = builder + .expectsToReceive("`OrderRejected` event") + .withMetadata( + mapOf( + Pair("event-aggregate-type", "me.jangjunha.ftgo.order_service.domain.Order"), + Pair("event-type", "me.jangjunha.ftgo.order_service.api.events.OrderRejected"), + Pair("event-aggregate-id", "6f2d06a3-5dd2-4096-8644-6084d64eae35"), + Pair("ID", ""), + ) + ) + .withContent(PactDslJsonBody()) + .toPact() + + @Test + @PactTestFor(pactMethod = "orderRejectedEvent") + fun testConsumeOrderRejectedEvent(messages: List) { + val arg = slot>() + every { orderHistoryEventHandlers["handleOrderRejected"](capture(arg)) } returns Unit + + val rawMessage = messages[0] + val message = MessageImpl(rawMessage.contentsAsString(), rawMessage.metadata.mapValues { it.value.toString() }) + domainEventDispatcher.messageHandler(message) + + assert(arg.isCaptured) + assert(arg.captured.aggregateType == "me.jangjunha.ftgo.order_service.domain.Order") + assert(arg.captured.aggregateId == "6f2d06a3-5dd2-4096-8644-6084d64eae35") + assert(arg.captured.event == OrderRejected()) + } + + @Configuration + @EnableAutoConfiguration + @Import( + value = [ + OrderHistoryServiceMessagingConfiguration::class, + TramInMemoryCommonConfiguration::class, + ] + ) + class TestConfiguration +} diff --git a/ftgo-order-service-api/src/main/kotlin/me/jangjunha/ftgo/order_service/api/events/OrderAuthorized.kt b/ftgo-order-service-api/src/main/kotlin/me/jangjunha/ftgo/order_service/api/events/OrderAuthorized.kt index c58db6a..1c7f9a3 100644 --- a/ftgo-order-service-api/src/main/kotlin/me/jangjunha/ftgo/order_service/api/events/OrderAuthorized.kt +++ b/ftgo-order-service-api/src/main/kotlin/me/jangjunha/ftgo/order_service/api/events/OrderAuthorized.kt @@ -1,3 +1,11 @@ package me.jangjunha.ftgo.order_service.api.events -class OrderAuthorized: OrderDomainEvent +import org.apache.commons.lang.builder.EqualsBuilder +import org.apache.commons.lang.builder.HashCodeBuilder + +class OrderAuthorized : OrderDomainEvent { + + override fun equals(other: Any?): Boolean = EqualsBuilder.reflectionEquals(this, other) + + override fun hashCode(): Int = HashCodeBuilder.reflectionHashCode(this) +} diff --git a/ftgo-order-service-api/src/main/kotlin/me/jangjunha/ftgo/order_service/api/events/OrderRejected.kt b/ftgo-order-service-api/src/main/kotlin/me/jangjunha/ftgo/order_service/api/events/OrderRejected.kt index 01ef42d..77e8f4b 100644 --- a/ftgo-order-service-api/src/main/kotlin/me/jangjunha/ftgo/order_service/api/events/OrderRejected.kt +++ b/ftgo-order-service-api/src/main/kotlin/me/jangjunha/ftgo/order_service/api/events/OrderRejected.kt @@ -1,3 +1,11 @@ package me.jangjunha.ftgo.order_service.api.events -class OrderRejected: OrderDomainEvent +import org.apache.commons.lang.builder.EqualsBuilder +import org.apache.commons.lang.builder.HashCodeBuilder + +class OrderRejected: OrderDomainEvent { + + override fun equals(other: Any?): Boolean = EqualsBuilder.reflectionEquals(this, other) + + override fun hashCode(): Int = HashCodeBuilder.reflectionHashCode(this) +}