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:
+136
@@ -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)));
|
||||
}
|
||||
}
|
||||
+188
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
+214
@@ -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));
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package com.baeldung.axon.querymodel;
|
||||
|
||||
public class InMemoryOrdersEventHandlerUnitTest extends AbstractOrdersEventHandlerUnitTest {
|
||||
|
||||
@Override
|
||||
protected OrdersEventHandler getHandler() {
|
||||
return new InMemoryOrdersEventHandler(emitter);
|
||||
}
|
||||
}
|
||||
+20
@@ -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);
|
||||
}
|
||||
}
|
||||
+139
@@ -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
|
||||
Reference in New Issue
Block a user