Java 26392 Move modules to patterns-module (#15060)

* JAVA-26392 Move axon module and ddd module to patterns-modules

* JAVA-26292 Move ddd-contexts to patterns-module
This commit is contained in:
anuragkumawat
2023-10-27 15:57:32 +05:30
committed by GitHub
parent 16b931c4df
commit 1028ab97c4
146 changed files with 23 additions and 28 deletions
@@ -0,0 +1,136 @@
package com.baeldung.axon.commandmodel;
import com.baeldung.axon.commandmodel.order.OrderAggregate;
import com.baeldung.axon.coreapi.commands.AddProductCommand;
import com.baeldung.axon.coreapi.commands.ConfirmOrderCommand;
import com.baeldung.axon.coreapi.commands.CreateOrderCommand;
import com.baeldung.axon.coreapi.commands.DecrementProductCountCommand;
import com.baeldung.axon.coreapi.commands.IncrementProductCountCommand;
import com.baeldung.axon.coreapi.commands.ShipOrderCommand;
import com.baeldung.axon.coreapi.events.OrderConfirmedEvent;
import com.baeldung.axon.coreapi.events.OrderCreatedEvent;
import com.baeldung.axon.coreapi.events.OrderShippedEvent;
import com.baeldung.axon.coreapi.events.ProductAddedEvent;
import com.baeldung.axon.coreapi.events.ProductCountDecrementedEvent;
import com.baeldung.axon.coreapi.events.ProductCountIncrementedEvent;
import com.baeldung.axon.coreapi.events.ProductRemovedEvent;
import com.baeldung.axon.coreapi.exceptions.DuplicateOrderLineException;
import com.baeldung.axon.coreapi.exceptions.OrderAlreadyConfirmedException;
import com.baeldung.axon.coreapi.exceptions.UnconfirmedOrderException;
import org.axonframework.test.aggregate.AggregateTestFixture;
import org.axonframework.test.aggregate.FixtureConfiguration;
import org.axonframework.test.matchers.Matchers;
import org.junit.jupiter.api.*;
import java.util.UUID;
class OrderAggregateUnitTest {
private static final String ORDER_ID = UUID.randomUUID()
.toString();
private static final String PRODUCT_ID = UUID.randomUUID()
.toString();
private FixtureConfiguration<OrderAggregate> fixture;
@BeforeEach
void setUp() {
fixture = new AggregateTestFixture<>(OrderAggregate.class);
}
@Test
void giveNoPriorActivity_whenCreateOrderCommand_thenShouldPublishOrderCreatedEvent() {
fixture.givenNoPriorActivity()
.when(new CreateOrderCommand(ORDER_ID))
.expectEvents(new OrderCreatedEvent(ORDER_ID));
}
@Test
void givenOrderCreatedEvent_whenAddProductCommand_thenShouldPublishProductAddedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID))
.when(new AddProductCommand(ORDER_ID, PRODUCT_ID))
.expectEvents(new ProductAddedEvent(ORDER_ID, PRODUCT_ID));
}
@Test
void givenOrderCreatedEventAndProductAddedEvent_whenAddProductCommandForSameProductId_thenShouldThrowDuplicateOrderLineException() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID))
.when(new AddProductCommand(ORDER_ID, PRODUCT_ID))
.expectException(DuplicateOrderLineException.class)
.expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(PRODUCT_ID)));
}
@Test
void givenOrderCreatedEventAndProductAddedEvent_whenIncrementProductCountCommand_thenShouldPublishProductCountIncrementedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID))
.when(new IncrementProductCountCommand(ORDER_ID, PRODUCT_ID))
.expectEvents(new ProductCountIncrementedEvent(ORDER_ID, PRODUCT_ID));
}
@Test
void givenOrderCreatedEventProductAddedEventAndProductCountIncrementedEvent_whenDecrementProductCountCommand_thenShouldPublishProductCountDecrementedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID), new ProductCountIncrementedEvent(ORDER_ID, PRODUCT_ID))
.when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID))
.expectEvents(new ProductCountDecrementedEvent(ORDER_ID, PRODUCT_ID));
}
@Test
void givenOrderCreatedEventAndProductAddedEvent_whenDecrementProductCountCommand_thenShouldPublishProductRemovedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID))
.when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID))
.expectEvents(new ProductRemovedEvent(ORDER_ID, PRODUCT_ID));
}
@Test
void givenOrderCreatedEvent_whenConfirmOrderCommand_thenShouldPublishOrderConfirmedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID))
.when(new ConfirmOrderCommand(ORDER_ID))
.expectEvents(new OrderConfirmedEvent(ORDER_ID));
}
@Test
void givenOrderCreatedEventAndOrderConfirmedEvent_whenConfirmOrderCommand_thenExpectNoEvents() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID))
.when(new ConfirmOrderCommand(ORDER_ID))
.expectNoEvents();
}
@Test
void givenOrderCreatedEvent_whenShipOrderCommand_thenShouldThrowUnconfirmedOrderException() {
fixture.given(new OrderCreatedEvent(ORDER_ID))
.when(new ShipOrderCommand(ORDER_ID))
.expectException(UnconfirmedOrderException.class);
}
@Test
void givenOrderCreatedEventAndOrderConfirmedEvent_whenShipOrderCommand_thenShouldPublishOrderShippedEvent() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID))
.when(new ShipOrderCommand(ORDER_ID))
.expectEvents(new OrderShippedEvent(ORDER_ID));
}
@Test
void givenOrderCreatedEventProductAndOrderConfirmedEvent_whenAddProductCommand_thenShouldThrowOrderAlreadyConfirmedException() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new OrderConfirmedEvent(ORDER_ID))
.when(new AddProductCommand(ORDER_ID, PRODUCT_ID))
.expectException(OrderAlreadyConfirmedException.class)
.expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID)));
}
@Test
void givenOrderCreatedEventProductAddedEventAndOrderConfirmedEvent_whenIncrementProductCountCommand_thenShouldThrowOrderAlreadyConfirmedException() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID), new OrderConfirmedEvent(ORDER_ID))
.when(new IncrementProductCountCommand(ORDER_ID, PRODUCT_ID))
.expectException(OrderAlreadyConfirmedException.class)
.expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID)));
}
@Test
void givenOrderCreatedEventProductAddedEventAndOrderConfirmedEvent_whenDecrementProductCountCommand_thenShouldThrowOrderAlreadyConfirmedException() {
fixture.given(new OrderCreatedEvent(ORDER_ID), new ProductAddedEvent(ORDER_ID, PRODUCT_ID), new OrderConfirmedEvent(ORDER_ID))
.when(new DecrementProductCountCommand(ORDER_ID, PRODUCT_ID))
.expectException(OrderAlreadyConfirmedException.class)
.expectExceptionMessage(Matchers.predicate(message -> ((String) message).contains(ORDER_ID)));
}
}
@@ -0,0 +1,188 @@
package com.baeldung.axon.gui;
import com.baeldung.axon.OrderApplication;
import com.baeldung.axon.querymodel.OrderResponse;
import com.baeldung.axon.querymodel.OrderStatusResponse;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.MediaType;
import org.springframework.http.client.reactive.ReactorClientHttpConnector;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.web.reactive.function.client.WebClient;
import org.springframework.web.reactive.function.client.WebClientResponseException;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;
import reactor.netty.http.client.HttpClient;
import reactor.test.StepVerifier;
import java.util.ArrayList;
import java.util.UUID;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest(classes = OrderApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
//marked as manual as the test is unstable on Jenkins due to low resources
class OrderRestEndpointManualTest {
@LocalServerPort
private int port;
@Test
@DirtiesContext
void givenCreateOrderCalled_whenCallingAllOrders_thenOneCreatedOrderIsReturned() {
WebClient client = WebClient.builder()
.clientConnector(httpConnector())
.build();
createRandomNewOrder(client);
StepVerifier.create(retrieveListResponse(client.get()
.uri("http://localhost:" + port + "/all-orders")))
.expectNextMatches(list -> 1 == list.size() && list.get(0)
.getOrderStatus() == OrderStatusResponse.CREATED)
.verifyComplete();
}
@Test
@DirtiesContext
void givenCreateOrderCalledThreeTimesAnd_whenCallingAllOrdersStreaming_thenTwoCreatedOrdersAreReturned() {
WebClient client = WebClient.builder()
.clientConnector(httpConnector())
.build();
for (int i = 0; i < 3; i++) {
createRandomNewOrder(client);
}
StepVerifier.create(retrieveStreamingResponse(client.get()
.uri("http://localhost:" + port + "/all-orders-streaming")))
.expectNextMatches(o -> o.getOrderStatus() == OrderStatusResponse.CREATED)
.expectNextMatches(o -> o.getOrderStatus() == OrderStatusResponse.CREATED)
.expectNextMatches(o -> o.getOrderStatus() == OrderStatusResponse.CREATED)
.verifyComplete();
}
@Test
@DirtiesContext
void givenRuleExistThatNeedConfirmationBeforeShipping_whenCallingShipUnconfirmed_thenErrorReturned() {
WebClient client = WebClient.builder()
.clientConnector(httpConnector())
.build();
StepVerifier.create(retrieveResponse(client.post()
.uri("http://localhost:" + port + "/ship-unconfirmed-order")))
.verifyError(WebClientResponseException.class);
}
@Test
@DirtiesContext
void givenShipOrderCalled_whenCallingAllShippedChairs_then234PlusOneIsReturned() {
WebClient client = WebClient.builder()
.clientConnector(httpConnector())
.build();
verifyVoidPost(client, "http://localhost:" + port + "/ship-order");
StepVerifier.create(retrieveIntegerResponse(client.get()
.uri("http://localhost:" + port + "/total-shipped/Deluxe Chair")))
.assertNext(r -> assertEquals(235, r))
.verifyComplete();
}
@Test
@DirtiesContext
void givenOrdersAreUpdated_whenCallingOrderUpdates_thenUpdatesReturned() {
WebClient updaterClient = WebClient.builder()
.clientConnector(httpConnector())
.build();
WebClient receiverClient = WebClient.builder()
.clientConnector(httpConnector())
.build();
String orderId = UUID.randomUUID()
.toString();
String productId = UUID.randomUUID()
.toString();
StepVerifier.create(retrieveResponse(updaterClient.post()
.uri("http://localhost:" + port + "/order/" + orderId)))
.assertNext(Assertions::assertNotNull)
.verifyComplete();
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.schedule(() -> addIncrementDecrementConfirmAndShipProduct(orderId, productId), 1L, TimeUnit.SECONDS);
try {
StepVerifier.create(retrieveStreamingResponse(receiverClient.get()
.uri("http://localhost:" + port + "/order-updates/" + orderId)))
.assertNext(p -> assertTrue(p.getProducts()
.isEmpty()))
.assertNext(p -> assertEquals(1, p.getProducts()
.get(productId)))
.assertNext(p -> assertEquals(2, p.getProducts()
.get(productId)))
.assertNext(p -> assertEquals(1, p.getProducts()
.get(productId)))
.assertNext(p -> assertEquals(OrderStatusResponse.CONFIRMED, p.getOrderStatus()))
.assertNext(p -> assertEquals(OrderStatusResponse.SHIPPED, p.getOrderStatus()))
.thenCancel()
.verify();
} finally {
executor.shutdown();
}
}
private void addIncrementDecrementConfirmAndShipProduct(String orderId, String productId) {
WebClient client = WebClient.builder()
.clientConnector(httpConnector())
.build();
String base = "http://localhost:" + port + "/order/" + orderId;
verifyVoidPost(client, base + "/product/" + productId);
verifyVoidPost(client, base + "/product/" + productId + "/increment");
verifyVoidPost(client, base + "/product/" + productId + "/decrement");
verifyVoidPost(client, base + "/confirm");
verifyVoidPost(client, base + "/ship");
}
private void createRandomNewOrder(WebClient client){
StepVerifier.create(retrieveResponse(client.post()
.uri("http://localhost:" + port + "/order")))
.assertNext(Assertions::assertNotNull)
.verifyComplete();
}
private void verifyVoidPost(WebClient client, String uri) {
StepVerifier.create(retrieveResponse(client.post()
.uri(uri)))
.verifyComplete();
}
private static ReactorClientHttpConnector httpConnector() {
HttpClient httpClient = HttpClient.create()
.wiretap(true);
return new ReactorClientHttpConnector(httpClient);
}
private Mono<String> retrieveResponse(WebClient.RequestBodySpec spec) {
return spec.retrieve()
.bodyToMono(String.class);
}
private Mono<ResponseList> retrieveListResponse(WebClient.RequestHeadersSpec<?> spec) {
return spec.accept(MediaType.APPLICATION_JSON)
.retrieve()
.bodyToMono(ResponseList.class);
}
private Mono<Integer> retrieveIntegerResponse(WebClient.RequestHeadersSpec<?> spec) {
return spec.retrieve()
.bodyToMono(Integer.class);
}
private Flux<OrderResponse> retrieveStreamingResponse(WebClient.RequestHeadersSpec<?> spec) {
return spec.retrieve()
.bodyToFlux(OrderResponse.class);
}
private static class ResponseList extends ArrayList<OrderResponse> {
private ResponseList() {
super();
}
}
}
@@ -0,0 +1,214 @@
package com.baeldung.axon.querymodel;
import com.baeldung.axon.coreapi.events.OrderConfirmedEvent;
import com.baeldung.axon.coreapi.events.OrderCreatedEvent;
import com.baeldung.axon.coreapi.events.OrderShippedEvent;
import com.baeldung.axon.coreapi.events.ProductAddedEvent;
import com.baeldung.axon.coreapi.events.ProductCountDecrementedEvent;
import com.baeldung.axon.coreapi.events.ProductCountIncrementedEvent;
import com.baeldung.axon.coreapi.events.ProductRemovedEvent;
import com.baeldung.axon.coreapi.queries.FindAllOrderedProductsQuery;
import com.baeldung.axon.coreapi.queries.Order;
import com.baeldung.axon.coreapi.queries.OrderStatus;
import com.baeldung.axon.coreapi.queries.OrderUpdatesQuery;
import com.baeldung.axon.coreapi.queries.TotalProductsShippedQuery;
import org.axonframework.queryhandling.QueryUpdateEmitter;
import org.junit.jupiter.api.*;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import java.util.Arrays;
import java.util.List;
import java.util.UUID;
import java.util.function.Consumer;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
public abstract class AbstractOrdersEventHandlerUnitTest {
private static final String ORDER_ID_1 = UUID.randomUUID()
.toString();
private static final String ORDER_ID_2 = UUID.randomUUID()
.toString();
private static final String PRODUCT_ID_1 = UUID.randomUUID()
.toString();
private static final String PRODUCT_ID_2 = UUID.randomUUID()
.toString();
private OrdersEventHandler handler;
private static Order orderOne;
private static Order orderTwo;
QueryUpdateEmitter emitter = mock(QueryUpdateEmitter.class);
@BeforeAll
static void createOrders() {
orderOne = new Order(ORDER_ID_1);
orderOne.getProducts()
.put(PRODUCT_ID_1, 3);
orderOne.setOrderShipped();
orderTwo = new Order(ORDER_ID_2);
orderTwo.getProducts()
.put(PRODUCT_ID_1, 1);
orderTwo.getProducts()
.put(PRODUCT_ID_2, 1);
orderTwo.setOrderConfirmed();
}
@BeforeEach
void setUp() {
handler = getHandler();
}
protected abstract OrdersEventHandler getHandler();
@Test
void givenTwoOrdersPlacedOfWhichOneNotShipped_whenFindAllOrderedProductsQuery_thenCorrectOrdersAreReturned() {
resetWithTwoOrders();
List<Order> result = handler.handle(new FindAllOrderedProductsQuery());
assertNotNull(result);
assertEquals(2, result.size());
Order order_1 = result.stream()
.filter(o -> o.getOrderId()
.equals(ORDER_ID_1))
.findFirst()
.orElse(null);
assertEquals(orderOne, order_1);
Order order_2 = result.stream()
.filter(o -> o.getOrderId()
.equals(ORDER_ID_2))
.findFirst()
.orElse(null);
assertEquals(orderTwo, order_2);
}
@Test
void givenTwoOrdersPlacedOfWhichOneNotShipped_whenFindAllOrderedProductsQueryStreaming_thenCorrectOrdersAreReturned() {
resetWithTwoOrders();
final Consumer<Order> orderVerifier = order -> {
if (order.getOrderId()
.equals(orderOne.getOrderId())) {
assertEquals(orderOne, order);
} else if (order.getOrderId()
.equals(orderTwo.getOrderId())) {
assertEquals(orderTwo, order);
} else {
throw new RuntimeException("Would expect either order one or order two");
}
};
StepVerifier.create(Flux.from(handler.handleStreaming(new FindAllOrderedProductsQuery())))
.assertNext(orderVerifier)
.assertNext(orderVerifier)
.expectComplete()
.verify();
}
@Test
void givenNoOrdersPlaced_whenTotalProductsShippedQuery_thenZeroReturned() {
assertEquals(0, handler.handle(new TotalProductsShippedQuery(PRODUCT_ID_1)));
}
@Test
void givenTwoOrdersPlacedOfWhichOneNotShipped_whenTotalProductsShippedQuery_thenOnlyCountProductsFirstOrder() {
resetWithTwoOrders();
assertEquals(3, handler.handle(new TotalProductsShippedQuery(PRODUCT_ID_1)));
assertEquals(0, handler.handle(new TotalProductsShippedQuery(PRODUCT_ID_2)));
}
@Test
void givenTwoOrdersPlacedAndShipped_whenTotalProductsShippedQuery_thenCountBothOrders() {
resetWithTwoOrders();
handler.on(new OrderShippedEvent(ORDER_ID_2));
assertEquals(4, handler.handle(new TotalProductsShippedQuery(PRODUCT_ID_1)));
assertEquals(1, handler.handle(new TotalProductsShippedQuery(PRODUCT_ID_2)));
}
@Test
void givenOrderExist_whenOrderUpdatesQuery_thenOrderReturned() {
resetWithTwoOrders();
Order result = handler.handle(new OrderUpdatesQuery(ORDER_ID_1));
assertNotNull(result);
assertEquals(ORDER_ID_1, result.getOrderId());
assertEquals(3, result.getProducts()
.get(PRODUCT_ID_1));
assertEquals(OrderStatus.SHIPPED, result.getOrderStatus());
}
@Test
void givenOrderExist_whenProductAddedEvent_thenUpdateEmittedOnce() {
handler.on(new OrderCreatedEvent(ORDER_ID_1));
handler.on(new ProductAddedEvent(ORDER_ID_1, PRODUCT_ID_1));
verify(emitter, times(1)).emit(eq(OrderUpdatesQuery.class), any(), any(Order.class));
}
@Test
void givenOrderWithProductExist_whenProductCountDecrementedEvent_thenUpdateEmittedOnce() {
handler.on(new OrderCreatedEvent(ORDER_ID_1));
handler.on(new ProductAddedEvent(ORDER_ID_1, PRODUCT_ID_1));
reset(emitter);
handler.on(new ProductCountDecrementedEvent(ORDER_ID_1, PRODUCT_ID_1));
verify(emitter, times(1)).emit(eq(OrderUpdatesQuery.class), any(), any(Order.class));
}
@Test
void givenOrderWithProductExist_whenProductRemovedEvent_thenUpdateEmittedOnce() {
handler.on(new OrderCreatedEvent(ORDER_ID_1));
handler.on(new ProductAddedEvent(ORDER_ID_1, PRODUCT_ID_1));
reset(emitter);
handler.on(new ProductRemovedEvent(ORDER_ID_1, PRODUCT_ID_1));
verify(emitter, times(1)).emit(eq(OrderUpdatesQuery.class), any(), any(Order.class));
}
@Test
void givenOrderWithProductExist_whenProductCountIncrementedEvent_thenUpdateEmittedOnce() {
handler.on(new OrderCreatedEvent(ORDER_ID_1));
handler.on(new ProductAddedEvent(ORDER_ID_1, PRODUCT_ID_1));
reset(emitter);
handler.on(new ProductCountIncrementedEvent(ORDER_ID_1, PRODUCT_ID_1));
verify(emitter, times(1)).emit(eq(OrderUpdatesQuery.class), any(), any(Order.class));
}
@Test
void givenOrderWithProductExist_whenOrderConfirmedEvent_thenUpdateEmittedOnce() {
handler.on(new OrderCreatedEvent(ORDER_ID_1));
handler.on(new ProductAddedEvent(ORDER_ID_1, PRODUCT_ID_1));
reset(emitter);
handler.on(new OrderConfirmedEvent(ORDER_ID_1));
verify(emitter, times(1)).emit(eq(OrderUpdatesQuery.class), any(), any(Order.class));
}
@Test
void givenOrderWithProductAndConfirmationExist_whenOrderShippedEvent_thenUpdateEmittedOnce() {
handler.on(new OrderCreatedEvent(ORDER_ID_1));
handler.on(new ProductAddedEvent(ORDER_ID_1, PRODUCT_ID_1));
reset(emitter);
handler.on(new OrderShippedEvent(ORDER_ID_1));
verify(emitter, times(1)).emit(eq(OrderUpdatesQuery.class), any(), any(Order.class));
}
private void resetWithTwoOrders() {
handler.reset(Arrays.asList(orderOne, orderTwo));
}
}
@@ -0,0 +1,9 @@
package com.baeldung.axon.querymodel;
public class InMemoryOrdersEventHandlerUnitTest extends AbstractOrdersEventHandlerUnitTest {
@Override
protected OrdersEventHandler getHandler() {
return new InMemoryOrdersEventHandler(emitter);
}
}
@@ -0,0 +1,20 @@
package com.baeldung.axon.querymodel;
import com.mongodb.client.MongoClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.data.mongo.DataMongoTest;
@DataMongoTest
public class MongoOrdersEventHandlerUnitTest extends AbstractOrdersEventHandlerUnitTest {
@Autowired
MongoClient mongoClient;
@Override
protected OrdersEventHandler getHandler() {
mongoClient.getDatabase("axonframework")
.drop();
return new MongoOrdersEventHandler(mongoClient, emitter);
}
}
@@ -0,0 +1,139 @@
package com.baeldung.axon.querymodel;
import com.baeldung.axon.OrderApplication;
import com.baeldung.axon.coreapi.events.OrderConfirmedEvent;
import com.baeldung.axon.coreapi.events.OrderShippedEvent;
import com.baeldung.axon.coreapi.events.ProductAddedEvent;
import com.baeldung.axon.coreapi.events.ProductCountDecrementedEvent;
import com.baeldung.axon.coreapi.events.ProductCountIncrementedEvent;
import com.baeldung.axon.coreapi.queries.Order;
import org.axonframework.eventhandling.gateway.EventGateway;
import org.junit.jupiter.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import reactor.core.publisher.Flux;
import reactor.test.StepVerifier;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest(classes = OrderApplication.class)
class OrderQueryServiceIntegrationTest {
@Autowired
OrderQueryService queryService;
@Autowired
EventGateway eventGateway;
@Autowired
OrdersEventHandler handler;
private String orderId;
private final String productId = "Deluxe Chair";
@BeforeEach
void setUp() {
orderId = UUID.randomUUID()
.toString();
Order order = new Order(orderId);
handler.reset(Collections.singletonList(order));
}
@Test
void givenOrderCreatedEventSend_whenCallingAllOrders_thenOneCreatedOrderIsReturned() throws ExecutionException, InterruptedException {
List<OrderResponse> result = queryService.findAllOrders()
.get();
assertEquals(1, result.size());
OrderResponse response = result.get(0);
assertEquals(orderId, response.getOrderId());
assertEquals(OrderStatusResponse.CREATED, response.getOrderStatus());
assertTrue(response.getProducts()
.isEmpty());
}
@Test
void givenOrderCreatedEventSend_whenCallingAllOrdersStreaming_thenOneOrderIsReturned() {
Flux<OrderResponse> result = queryService.allOrdersStreaming();
StepVerifier.create(result)
.assertNext(order -> assertEquals(orderId, order.getOrderId()))
.expectComplete()
.verify();
}
@Test
void givenThreeDeluxeChairsShipped_whenCallingAllShippedChairs_then234PlusTreeIsReturned() {
Order order = new Order(orderId);
order.getProducts()
.put(productId, 3);
order.setOrderShipped();
handler.reset(Collections.singletonList(order));
assertEquals(237, queryService.totalShipped(productId));
}
@Test
void givenOrdersAreUpdated_whenCallingOrderUpdates_thenUpdatesReturned() {
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
executor.schedule(this::addIncrementDecrementConfirmAndShip, 100L, TimeUnit.MILLISECONDS);
try {
StepVerifier.create(queryService.orderUpdates(orderId))
.assertNext(order -> assertTrue(order.getProducts()
.isEmpty()))
.assertNext(order -> assertEquals(1, order.getProducts()
.get(productId)))
.assertNext(order -> assertEquals(2, order.getProducts()
.get(productId)))
.assertNext(order -> assertEquals(1, order.getProducts()
.get(productId)))
.assertNext(order -> assertEquals(OrderStatusResponse.CONFIRMED, order.getOrderStatus()))
.assertNext(order -> assertEquals(OrderStatusResponse.SHIPPED, order.getOrderStatus()))
.thenCancel()
.verify();
} finally {
executor.shutdown();
}
}
private void addIncrementDecrementConfirmAndShip() {
sendProductAddedEvent();
sendProductCountIncrementEvent();
sendProductCountDecrementEvent();
sendOrderConfirmedEvent();
sendOrderShippedEvent();
}
private void sendProductAddedEvent() {
ProductAddedEvent event = new ProductAddedEvent(orderId, productId);
eventGateway.publish(event);
}
private void sendProductCountIncrementEvent() {
ProductCountIncrementedEvent event = new ProductCountIncrementedEvent(orderId, productId);
eventGateway.publish(event);
}
private void sendProductCountDecrementEvent() {
ProductCountDecrementedEvent event = new ProductCountDecrementedEvent(orderId, productId);
eventGateway.publish(event);
}
private void sendOrderConfirmedEvent() {
OrderConfirmedEvent event = new OrderConfirmedEvent(orderId);
eventGateway.publish(event);
}
private void sendOrderShippedEvent() {
OrderShippedEvent event = new OrderShippedEvent(orderId);
eventGateway.publish(event);
}
}
@@ -0,0 +1,2 @@
spring.mongodb.embedded.version=5.0.6
axon.axonserver.enabled=false