From 7ecbd74ff22688dc5cde54f4e758bdc936e656d2 Mon Sep 17 00:00:00 2001 From: abidknashtech Date: Tue, 16 Jan 2024 13:20:54 +0530 Subject: [PATCH 1/2] added unit test cases --- README.md | 7 +- order-service/pom.xml | 17 +++ .../nashtech/order/OrderAggregateTest.java | 104 ++++++++++++++++++ .../order/OrderEventsHandlerTest.java | 81 ++++++++++++++ .../order/OrderQueriesHandlerTest.java | 55 +++++++++ .../com/nashtech/order/OrderSagaTest.java | 63 +++++++++++ .../order/OrderServiceApplicationTests.java | 10 -- .../src/test/resources/application-test.yml | 3 + 8 files changed, 327 insertions(+), 13 deletions(-) create mode 100644 order-service/src/test/java/com/nashtech/order/OrderAggregateTest.java create mode 100644 order-service/src/test/java/com/nashtech/order/OrderEventsHandlerTest.java create mode 100644 order-service/src/test/java/com/nashtech/order/OrderQueriesHandlerTest.java create mode 100644 order-service/src/test/java/com/nashtech/order/OrderSagaTest.java delete mode 100644 order-service/src/test/java/com/nashtech/order/OrderServiceApplicationTests.java create mode 100644 order-service/src/test/resources/application-test.yml diff --git a/README.md b/README.md index 208f4970..3ddf6430 100644 --- a/README.md +++ b/README.md @@ -197,12 +197,13 @@ To verify the deployment of Kubernetes on Google Cloud Platform (GCP), follow th Examine logs for applications and services to identify any issues or error messages. ``` -#### Data platform +Data Analytics and Visualization +-- For the analytical purpose, the insightful data generated by microservices brings to the databricks Lakehouse platform. find the details here [README.md](databricks%2FREADME.md) Documentation -- -- Demo session [available](documentation/automobile ecommerce-platform.pptx) -- Demo Presentation [available](https://harveynashvn-my.sharepoint.com/personal/sushant_gupta_nashtechglobal_com/_layouts/15/stream.aspx?id=%2Fpersonal%2Fsushant%5Fgupta%5Fnashtechglobal%5Fcom%2FDocuments%2FJava%2Dcompetency%2Dartifacts%2Dinternal%2Dproject%2FRecordings%2Fdemo%5F%20automobile%20eCommerce%20platform%2D20231206%5F142041%2DMeeting%20Recording%2Emp4&referrer=StreamWebApp%2EWeb&referrerScenario=AddressBarCopied%2Eview&isSPOFile=1&OR=Teams%2DHL&CT=1705060735545&clickparams=eyJBcHBOYW1lIjoiVGVhbXMtRGVza3RvcCIsIkFwcFZlcnNpb24iOiI0OS8yMzExMzAyODcyMCIsIkhhc0ZlZGVyYXRlZFVzZXIiOmZhbHNlfQ%3D%3D) +- Demo session [available](https://harveynashvn-my.sharepoint.com/personal/sushant_gupta_nashtechglobal_com/_layouts/15/stream.aspx?id=%2Fpersonal%2Fsushant%5Fgupta%5Fnashtechglobal%5Fcom%2FDocuments%2FJava%2Dcompetency%2Dartifacts%2Dinternal%2Dproject%2FRecordings%2Fdemo%5F%20automobile%20eCommerce%20platform%2D20231206%5F142041%2DMeeting%20Recording%2Emp4&referrer=StreamWebApp%2EWeb&referrerScenario=AddressBarCopied%2Eview&isSPOFile=1&OR=Teams%2DHL&CT=1705060735545&clickparams=eyJBcHBOYW1lIjoiVGVhbXMtRGVza3RvcCIsIkFwcFZlcnNpb24iOiI0OS8yMzExMzAyODcyMCIsIkhhc0ZlZGVyYXRlZFVzZXIiOmZhbHNlfQ%3D%3D) +- Demo Presentation [available](documentation/automobile ecommerce-platform.pptx) diff --git a/order-service/pom.xml b/order-service/pom.xml index 6e1e8daf..72e47271 100644 --- a/order-service/pom.xml +++ b/order-service/pom.xml @@ -79,6 +79,23 @@ validation-api ${validation-api.version} + + + org.springframework.boot + spring-boot-starter-test + + + junit + junit + test + + + + org.axonframework + axon-test + 4.9.1 + + diff --git a/order-service/src/test/java/com/nashtech/order/OrderAggregateTest.java b/order-service/src/test/java/com/nashtech/order/OrderAggregateTest.java new file mode 100644 index 00000000..244dcb00 --- /dev/null +++ b/order-service/src/test/java/com/nashtech/order/OrderAggregateTest.java @@ -0,0 +1,104 @@ +package com.nashtech.order; + +import com.nashtech.common.utils.OrderStatus; +import com.nashtech.order.aggregate.OrderAggregate; +import com.nashtech.order.commands.ApproveOrderCommand; +import com.nashtech.order.commands.CreateOrderCommand; +import com.nashtech.order.commands.RejectOrderCommand; +import com.nashtech.order.events.OrderApprovedEvent; +import com.nashtech.order.events.OrderCancelledEvent; +import com.nashtech.order.events.OrderCreatedEvent; +import org.axonframework.test.aggregate.AggregateTestFixture; +import org.axonframework.test.aggregate.FixtureConfiguration; +import org.junit.Before; +import org.junit.Test; + +import java.util.UUID; + +public class OrderAggregateTest { + + private static final String ORDER_ID = UUID.randomUUID().toString(); + private static final String PRODUCT_ID = UUID.randomUUID().toString(); + private static final String PAYMENT_ID = UUID.randomUUID().toString(); + private static final String SHIPMENT_ID = UUID.randomUUID().toString(); + private static final String USER_ID = "1652"; + + private FixtureConfiguration fixture; + + @Before + public void setUp() { + fixture = new AggregateTestFixture<>(OrderAggregate.class); + } + + private static final OrderCreatedEvent orderCreatedEvent = OrderCreatedEvent.builder() + .orderId(ORDER_ID) + .productId(PRODUCT_ID) + .quantity(2) + .userId(USER_ID) + .orderStatus(OrderStatus.ORDER_PARTIALLY_APPROVED) + .build(); + + @Test + public void testCreateOrderCommand() { + CreateOrderCommand createOrderCommand = CreateOrderCommand.builder() + .productId(PRODUCT_ID) + .userId(USER_ID) + .quantity(2) + .orderId(ORDER_ID) + .build(); + + fixture.givenNoPriorActivity() + .when(createOrderCommand) + .expectSuccessfulHandlerExecution() + .expectEvents(orderCreatedEvent); + } + + @Test + public void testApproveOrderCommand() { + ApproveOrderCommand approveOrderCommand = ApproveOrderCommand.builder() + .orderId(ORDER_ID) + .paymentId(PAYMENT_ID) + .shipmentId(SHIPMENT_ID) + .orderStatus(OrderStatus.ORDER_PLACED) + .build(); + + OrderApprovedEvent orderApprovedEvent = OrderApprovedEvent.builder() + .orderId(approveOrderCommand.getOrderId()) + .paymentId(approveOrderCommand.getPaymentId()) + .shipmentId(approveOrderCommand.getShipmentId()) + .orderStatus(approveOrderCommand.getOrderStatus()) + .build(); + + fixture.given(orderCreatedEvent) + .when(approveOrderCommand) + .expectSuccessfulHandlerExecution() + .expectEvents(orderApprovedEvent); + } + + @Test + public void testRejectOrderCommand() { + RejectOrderCommand rejectOrderCommand = RejectOrderCommand.builder() + .userId(USER_ID) + .orderId(ORDER_ID) + .productId(PRODUCT_ID) + .paymentId(PAYMENT_ID) + .reasonToFailed("The user has insufficient amounts.") + .orderStatus(OrderStatus.ORDER_NOT_APPROVED) + .build(); + + OrderCancelledEvent orderCancelledEvent = OrderCancelledEvent.builder() + .orderId(rejectOrderCommand.getOrderId()) + .productId(rejectOrderCommand.getProductId()) + .paymentId(rejectOrderCommand.getPaymentId()) + .shipmentId(rejectOrderCommand.getShipmentId()) + .userId(rejectOrderCommand.getUserId()) + .reasonToFailed(rejectOrderCommand.getReasonToFailed()) + .orderStatus(rejectOrderCommand.getOrderStatus()) + .build(); + + fixture.given(orderCreatedEvent) + .when(rejectOrderCommand) + .expectSuccessfulHandlerExecution() + .expectEvents(orderCancelledEvent); + } +} diff --git a/order-service/src/test/java/com/nashtech/order/OrderEventsHandlerTest.java b/order-service/src/test/java/com/nashtech/order/OrderEventsHandlerTest.java new file mode 100644 index 00000000..07bc2305 --- /dev/null +++ b/order-service/src/test/java/com/nashtech/order/OrderEventsHandlerTest.java @@ -0,0 +1,81 @@ +package com.nashtech.order; + +import com.nashtech.common.utils.OrderStatus; +import com.nashtech.order.events.OrderApprovedEvent; +import com.nashtech.order.events.OrderCancelledEvent; +import com.nashtech.order.events.OrderCreatedEvent; +import com.nashtech.order.handler.OrderEventsHandler; +import com.nashtech.order.repository.FailedOrderRepository; +import com.nashtech.order.repository.OrderRepository; +import com.nashtech.order.repository.entity.OrderEntity; +import org.junit.Before; +import org.junit.Test; + +import java.util.Date; +import java.util.UUID; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class OrderEventsHandlerTest { + private static final String ORDER_ID = UUID.randomUUID().toString(); + private static final String PRODUCT_ID = UUID.randomUUID().toString(); + private static final String PAYMENT_ID = UUID.randomUUID().toString(); + private static final String SHIPMENT_ID = UUID.randomUUID().toString(); + private static final String USER_ID = "1652"; + + + private OrderRepository orderRepository = mock(OrderRepository.class); + + private FailedOrderRepository failedOrderRepository = mock(FailedOrderRepository.class); + + // @Autowired + private OrderEventsHandler handler; + + @Before + public void setUp() { + handler = new OrderEventsHandler(orderRepository, failedOrderRepository); + } + + + @Test + public void testOrderCreatedEventHandler() { + OrderCreatedEvent orderCreatedEvent = OrderCreatedEvent.builder() + .orderId(ORDER_ID) + .productId(PRODUCT_ID) + .quantity(2) + .userId(USER_ID) + .orderStatus(OrderStatus.ORDER_PLACED) + .build(); + handler.on(orderCreatedEvent); + } + + @Test + public void testOrderApprovedEventHandler() { + OrderApprovedEvent orderApprovedEvent = OrderApprovedEvent.builder() + .orderId(ORDER_ID) + .paymentId(PAYMENT_ID) + .shipmentId(SHIPMENT_ID) + .orderStatus(OrderStatus.ORDER_PLACED) + .build(); + + OrderEntity order = new OrderEntity(orderApprovedEvent.getOrderId(), USER_ID, PRODUCT_ID, + null, null, new Date(), orderApprovedEvent.getOrderStatus().toString()); + + when(orderRepository.findByOrderId(ORDER_ID)).thenReturn(order); + + handler.on(orderApprovedEvent); + } + + @Test + public void testOrderCancelledEventHandler() { + OrderCancelledEvent orderCancelledEvent = OrderCancelledEvent.builder() + .orderId(ORDER_ID) + .userId(USER_ID) + .productId(PRODUCT_ID) + .reasonToFailed("Car quantity not sufficient in inventory") + .orderStatus(OrderStatus.ORDER_NOT_APPROVED) + .build(); + handler.on(orderCancelledEvent); + } +} diff --git a/order-service/src/test/java/com/nashtech/order/OrderQueriesHandlerTest.java b/order-service/src/test/java/com/nashtech/order/OrderQueriesHandlerTest.java new file mode 100644 index 00000000..c5832dc6 --- /dev/null +++ b/order-service/src/test/java/com/nashtech/order/OrderQueriesHandlerTest.java @@ -0,0 +1,55 @@ +package com.nashtech.order; + +import com.nashtech.common.utils.OrderStatus; +import com.nashtech.order.query.FindOrdersByUserQuery; +import com.nashtech.order.query.OrderQueriesHandler; +import com.nashtech.order.repository.OrderRepository; +import com.nashtech.order.repository.entity.OrderEntity; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.UUID; + +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class OrderQueriesHandlerTest { + + private static final String ORDER_ID1 = UUID.randomUUID().toString(); + private static final String ORDER_ID2 = UUID.randomUUID().toString(); + private static final String PRODUCT_ID = UUID.randomUUID().toString(); + private static final String USER_ID = "1652"; + + private final OrderRepository orderRepository = mock(OrderRepository.class); + + private OrderQueriesHandler queriesHandler; + + @Before + public void setUp() { + queriesHandler = new OrderQueriesHandler(orderRepository); + } + + @Test + public void testOrderCreatedEventHandler() { + FindOrdersByUserQuery findOrdersByUserQuery = new FindOrdersByUserQuery(USER_ID); + + List orderEntityList = new ArrayList<>(); + OrderEntity order1 = new OrderEntity(ORDER_ID1, USER_ID, PRODUCT_ID, + null, null, new Date(), OrderStatus.ORDER_APPROVED.toString()); + orderEntityList.add(order1); + OrderEntity order2= new OrderEntity(ORDER_ID2, USER_ID, PRODUCT_ID, + null, null, new Date(), OrderStatus.ORDER_APPROVED.toString()); + orderEntityList.add(order2); + when(orderRepository.findByUserId(USER_ID)).thenReturn(orderEntityList); + + List orders = queriesHandler.findOrders(findOrdersByUserQuery); + + Assert.assertEquals(2,orders.size()); + Assert.assertEquals(ORDER_ID1,orders.get(0).getOrderId()); + Assert.assertEquals(ORDER_ID2,orders.get(1).getOrderId()); + } +} diff --git a/order-service/src/test/java/com/nashtech/order/OrderSagaTest.java b/order-service/src/test/java/com/nashtech/order/OrderSagaTest.java new file mode 100644 index 00000000..4d489169 --- /dev/null +++ b/order-service/src/test/java/com/nashtech/order/OrderSagaTest.java @@ -0,0 +1,63 @@ +package com.nashtech.order; + +import com.nashtech.common.event.ProductReservedEvent; +import com.nashtech.common.utils.OrderStatus; +import com.nashtech.order.events.OrderCreatedEvent; +import com.nashtech.order.saga.OrderSaga; +import org.axonframework.test.matchers.Matchers; +import org.axonframework.test.saga.FixtureConfiguration; +import org.axonframework.test.saga.SagaTestFixture; +import org.junit.Test; + +import java.time.Duration; +import java.util.UUID; + +public class OrderSagaTest { + private static final String ORDER_ID = UUID.randomUUID().toString(); + private static final String PRODUCT_ID = UUID.randomUUID().toString(); + private static final String PAYMENT_ID = UUID.randomUUID().toString(); + private static final String SHIPMENT_ID = UUID.randomUUID().toString(); + private static final String USER_ID = "1652"; + private static final FixtureConfiguration fixture = new SagaTestFixture<>(OrderSaga.class); + + @Test + public void testOrderCreatedEvent() { + OrderCreatedEvent orderCreatedEvent = OrderCreatedEvent.builder() + .orderId(ORDER_ID) + .productId(PRODUCT_ID) + .quantity(2) + .userId(USER_ID) + .orderStatus(OrderStatus.ORDER_PARTIALLY_APPROVED) + .build(); + + fixture.givenAggregate(ORDER_ID) + .published(orderCreatedEvent) + .whenTimeElapses(Duration.ofDays(31)) + .expectDispatchedCommandsMatching(Matchers.listWithAllOf()); + } + + @Test + public void testProductReservedEvent() { + ProductReservedEvent productReservedEvent = ProductReservedEvent.builder() + .orderId(ORDER_ID) + .productId(PRODUCT_ID) + .userId(USER_ID) + .quantity(2) + .brand("Tata") + .basePrice(30000.0) + .tax(0.03f) + .totalTax(0.06f) + .subTotal(60000.0) + .total(60000.06) + .model("model") + .mileage(12d) + .color("Red") + .year(2024) + .build(); + + fixture.givenAggregate(ORDER_ID) + .published(productReservedEvent) + .whenTimeElapses(Duration.ofDays(31)) + .expectDispatchedCommandsMatching(Matchers.listWithAllOf()); + } +} diff --git a/order-service/src/test/java/com/nashtech/order/OrderServiceApplicationTests.java b/order-service/src/test/java/com/nashtech/order/OrderServiceApplicationTests.java deleted file mode 100644 index 40cfc8cb..00000000 --- a/order-service/src/test/java/com/nashtech/order/OrderServiceApplicationTests.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.nashtech.order; - -/* -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class OrderServiceApplicationTests { - -} -*/ diff --git a/order-service/src/test/resources/application-test.yml b/order-service/src/test/resources/application-test.yml new file mode 100644 index 00000000..c31108da --- /dev/null +++ b/order-service/src/test/resources/application-test.yml @@ -0,0 +1,3 @@ +axon: + axonserver: + enabled: false \ No newline at end of file From 712ca9c78ece270ca56f158d33e1004f925d41ea Mon Sep 17 00:00:00 2001 From: abidknashtech Date: Tue, 16 Jan 2024 18:40:24 +0530 Subject: [PATCH 2/2] added readMe file and order rest API unit-test cases --- README.md | 2 +- common/pom.xml | 2 +- documentation/order-config.png | Bin 0 -> 48716 bytes order-service/README.md | 38 +++++++++ order-service/pom.xml | 6 +- .../java/com/nashtech/order/RestTest.java | 75 ++++++++++++++++++ 6 files changed, 119 insertions(+), 4 deletions(-) create mode 100644 documentation/order-config.png create mode 100644 order-service/README.md create mode 100644 order-service/src/test/java/com/nashtech/order/RestTest.java diff --git a/README.md b/README.md index 3ddf6430..74d7dd82 100644 --- a/README.md +++ b/README.md @@ -62,7 +62,7 @@ The listed services are operate sequentially. ***Phase-1*** - admin-service - inventory-service -- order-service +- order-service [README.md](order-service%2FREADME.md) - payment-service - shipment-service - elasticsearch diff --git a/common/pom.xml b/common/pom.xml index b7836eeb..0ec2307e 100644 --- a/common/pom.xml +++ b/common/pom.xml @@ -41,7 +41,7 @@ 19 - 4.8.1 + 4.9.1 4.0.0 8.0.33 0.8.8 diff --git a/documentation/order-config.png b/documentation/order-config.png new file mode 100644 index 0000000000000000000000000000000000000000..c7ecf03c0b457ea75382e6b4c4201a377713e933 GIT binary patch literal 48716 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

Zlg#oB*i8SPyIlVF1cP5u04}ZUm=86 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≷o5%UC>8>&`_beF{S*Z)D(TG&vHq6_>joalFory z5fqI(ATT@gIo8Wp@sMD9I8lpiUOOsi`JiTm?b-qM@^BHRAAou>42A-~?n-rDXRRz@ zt<46^^qlJM-pcZb)3FI2F*%E3URf4?MFW-ybV@kc5%V+>?%W6S%&07V^R)uiEO z&{0o1h*6#T#Uq6jU?B~A28g+Gq1*|d<4L*eCt%0&PjSldkggJWMuavo-80*#SDVq@sNQ|Zuf z|FbyhpGx@iJ+aZ)M;hFCVlI?P2EVQ_$MJdXoIQ}1VD5M%kL1OfK(IikJxvNx!83=Y zJ#Mn*r_CuGRUMslhaItM*R8!xaf^q~_BZ9wQMCRAb6T%#(t?Q$Q!QZ>e9w-(zfwfz z$#6FH&k7ST6v|w;R+a;>UZ{ZHqpmFz4umx>&S7W{WSA>c9)QMR0*9s;nNkFw7FzOF zM3&WVHV1cOD^dUlk6#Opx3+q8Y(ZXLi zs`dpL6zLJ8q`hT=^5iRug3a%37TMZ%ery*V?%-CcV*obEMNS6@#Pw});c5R>W9`8K z|0AX2pEF-FpKZw(upLY65vs3u@OQOsS*S_=PeW4T)9CT9(Jvc&{s8WpDQrPAytKsk zuBp^katr`tRqn*}eZ0!SW%Tj$+l-(Uq-x@YP~?k1IjX{+erhe~!)zEu`@KvS^wk4q?h( z=&7|3JCX55`syd>TGlCWhF{kH`gdY9tKz=_t!z!2bkt-s{o&5*%nI7n&=RWLPl;O^ z+WPoy6aXwV{JDL@5_9f2+67!iT@MPgzf!g4?=jy*L>EqcRBU=aIl2R&z1>X^JZv%t z%d8P@Q|?i;R<#e_%GFHKTc1n^tYf4e;e7m(3O7cJImTN##Zclh0nZ#JRRoLy@SVE2 z2^8-mHqC-q39mHrPX}77w+bjEs@H0}5~PD5LDD{%qU2;Z+j0I%tXgc9eu0PivelF& zC`WS!aa0(kiJ}Y>Gadp$va|> zEeTc5Fchd3EigFdStGQSv_tumd;wp4WW%N%hMeM#)&Y>wzcsH<&%=sCKdKOS_D2V7 zZX}$u*f`o!;s0m+iVU6l1Pvc{3VJjUoqbDHR1IaL?o>%*E2SH~rlb$)rZ z3$>PJ#(4CT2WFEe8!4bhEWC!dnV|vAaanNNc49K+C|2ftC!8K%n84F$M zZrekYMpA$9{>Q3E;7kMZ285(AvT(mJ+JYn_2;LzIMuh(dr}m>O6Jh5Y$Qr&UH2ht? z_Y!alArem#+;)r0p{;Gca5SdAuEMmn*7fExLRwT5{x+L8C`qK1G*y42q(c`*L&r1e z9dPB2ZjY5odf`e4ugj`Xm&=CovRphsMZ%K(76v}sAK28T6qAI9Cq7-?a6_v~MaKM70NBfxNep9iqn_Ai;6y!H z;rS}pfs=MJKUUVjDcOI*;kj=M-TDLe>vR8t!_E&iE4{y`S{A^_*XENN=po>&zeQkS zgpsi=JwHlHQxNqBuIEC`tj`6+%Q6hWS<6~`>c4T4g8NT}RNo8u=e(2PdWgYPoCPr! zRMK2g#2=IS#^nJu4df3|a0GaMaq&y6{xb000Zz(GHvq*^Z%=X{rtN>tnl{D72n!bK zJ)4=dr;A?wuEPzH7$0A#kf{1oQVvN%yW-9+IZ;p{EQKC42QZeKU6y0}NFU{Yv3fYWX74o-MWbtX9 zsluWXWiAou*t8p4{qZD0H)lU0U&|aDFqIb8q>uA0*E573kl&v4e|{2H1&m0T00uNI z;-)9tkzAL&BfCAw=-VO+tB%F);cO?z2D*@ z7JnFh?Tt)ZY6g(2ZEpUcdj)=0t*csPh)4#{7dQLG^m4r>BMfHJo;HgB26!h}en(H}k2qI62=1$LGv0#Ev? zzS3_Inh%GCp6?-1##Cf9&XAIwtI~>a*s&|Y$ojm1)Wzi~E*$KssonKOf9r9LCB^x# zFRZiP>YtheD_q?V;xsC9_YO$h>I*12D)+HUHiw3Nro4~6ct6&a(rMlLE}p^|8jN*3 zKUDf_>~7SwTg^y)U*=;C$ImNEUkdnpH2L4!E-7t z0BMKmuViW!nfw2ztm;_0A=cq+J}QTct#vU=_1}LDHhK(dqw=uOXpj`mi%{e3U z$->QKi(5e$h2+ohbP_WZ*y^8jJnJ*}K!zM~7?V3&vOb8geS(?!HQVDg0f8FUxT9q! z_HNELOgR6FhVAz00i=VosgM_^gJqYz`}mYQn)LrlcKCf(zZBa4!#Z3R&e85LDJu(t ze;xdNg!vR8qF@gs{J(MyvQVdN??w3PmoTB$>#@k!6V~t6a+Ig)5sVMbl3}~|L(jLp zm^%b8{JFvJsE=9gw>k1jo`)?_QfE8p(4Ct|1Sc1=9*~nDx&ENn#UJ9ye=he$Gv`As zE@ub@B^$JcHbat|RMe*+(p>O9NNk@%IhSb4>k(={%tiOlTyG)n`P>?4GG}l@BJEP< zaJn%UwWF%J8T|ku#rCJop=4&(wZGB(*?Hvm_1_j`!mD`wKUbREX7%{^SvF*f88I>` zMkSYQyFmHe5C@Rv2e!i_o4>;NhtlGLDFb8G;l~ zqh3!lCiIb{e_k5~cdi-GhKlVITdy1!Ey{A>S~u32v6*(mpO1O5SIgy*#%}w^UXW6y zfd5?_?t>K0uou6ami$2V&XgyfVt4;K6Y?Kx-CCYI?R=#AGmAZ0@mS1%z4|AfD4bl9 zxy{ovt%UNgaVtLkrucs)6!^E3Ok>g7TB3IceDUpK-xsQ1kwfoa3{YP#)Td5stF-xm zvMv$E1*~2Y4SV`z(=&yL?sheAFX)>NK52Uca+z4oWJWtEqA86ZNER3K>M$uG^0}_% z!O+lO$F|=l5UR>cuE^LHz2jJVMeg^vkX+QUNpH7>v|q2mC>WCIRf|ObWan*=+McK| zgq5|Q9pWJQ2BeMkyXX}jDD0-EhweTG;k-<4rpk|KUEf5fQ}2@H4(%^Ac+VfnCO%$% ztUYZhoVln$xbxl;`C#uGzr80TUM3vvIb(yHJVIt zDKo#(CNGvOHRQR1+pDUwe5h5&M&{#ib7Nc?S#Z1auWb1EwTGn)3#eDDplHg!sBymU z&G0sS|9;h);>O@)J`PoxP8JL1fY{@;AitRN7Y%f1bTK?GB$Wz~vqHZZTaxZLagy@9 zmM0ho77);J9sY~(8NPTNyzv;agV}3PV@Ywdz^Qzr_*9>>O~z5t`C(@*=e?WT%rj(v z+`T3{zByH0-1a2NJ+Bz>hZ3qbjRs%n>R$brMU|rQ42>p+Jtm)SOMKYKk_wk%hAaQ< zYH118+lCHQR4vIPB%dVybDq4Lb@K5rvM?}96E^Pvz>8;1hHu6>vO#nKYsE` zA*z?U_%7*St*PQ?J7stq!meUz(M&9KseoX=ywcr#V4~v2ENb3xHZC61WoZt=){) zZkPNbK~FoD021#B^NwfwVfVtoza%DRoxPU8Abx!u^Wj+W)#d2GQl{n}4{HTs$5-^c zKqnhCKQ#7~AuQYHNMYa0Y4tplJvfTvYM0L7@EpEb)W>+K2A)*q@Tc#I@oPKZ7Sltw?y^<}ZlbvaLXmOAXdU)b?jNQYnLU!CtU#O1uK&HT??jvl`) z(EebZq&+4x0T#e|1L|oEF0y)(FP)o?`tt~$5^Orw#XPZ{>tzK=1-a~)WCHHYMYSmy zw)Ig$v9xPPEm$WeI(?fuJBMY9slRNkx?sSbQ*CE4c#WBjWw2Y}i7mAy)lHjIu1%Eq zC{Kw4^UGA9z?>*|CMja`eig}~j1>$SirgLrwEp_~P4G%w8|-nUuY6fTp&C3ay6R1i z0Cc%gn5g}oOT1Ao6$elNy5mM(M*N3a))Az~|K4ttm9<%vBE!0b{MC-dYdINgT}$-yHuI=PVNP}t7 zPn^>=7`&BQ2ne<^VnkYmro}#w9++SC zkOY$r#=PpuX?f-XiYwHx`xg>mv>@R1-(x`T%ft&ny5z>^;VG8*?71Vn3}mgo8~m-C@cWE&H~G~*=b@biyP#tGjjI*F?6ebAXnb>dD1=clQ5GuOvrB{8 zxG6pVE9KB}VT9LbLKmUEHPDk6i}8rR#mEz2VRM$>Rgd|=%LjKPW#Gp+IbZk-aosac z7T=xushOhL$B@2ya=M>nC>$H9y=4)_h}a53ttzMXt{M& zJ(E^^tThFWKK0aeY}YqF$RADxdt?z9&Ah|cZ|v>ZxW2&mUkFu-*J7Wv`TBHJ{Zwkl z=it4DW4Vwy$Y(IXu_kOCLL&$lX|Z7@*+nf|-uvE}O6LAf(170>-x}n+)w$89pSap& zEhii1%yy>x2f-_E|B?#2nCqHO$=I)%mK~F%lk$t!`9wqQIK0D_tF|Ln*gOVw6G<8HR zeU7p|cf4bZS5fM2*toB`(|pr}zMJ8?*1+JR&c?W2NwFV*bl2rp5FyKcbl&L|@2)F- zQaRbLrF~u4YJsK25eIPXnuF}&O%xf1C9yz+omd~zA001G*x#cuc%w#70XLR1z<=Co z-NBRpH1<8#xLl`^-PX~AJ2U}DX}^Z7Bfa{aAeoXU2}#N5!0tE7S2CvdkYQbuHnKAD zAmM!Vg~>5$Wn=WQ-wI?SSVl!>m2-c~Q*g`9z;_$KAiF~=NyMq@K?Xy4lgBPMqp$#d z?gE918IFF6M%;43$Hk;2&(E7wf*t3f(Hx|f8?w#`5Xys`NE+X>M7-i@^YFrm>oo-# zqV+DWzCS-deKFt@KP~|e4|5XG)PLK3YZaqcoC-boDn*~W{G1aLMh-biCbrY38Vslf zNpy9_AJSK9{1TB?b6Q0BQ{wo_V7K&V>OkmB|Eev0hdlzlTbO@+j?$nVXG6fJ4(<89 zmazUZKi~?Z&y>crlKFHNcELjEqFE3 z0p?`CI~$$GrT7CrUGGMfFn&kT6rW;J?qyL}WLRKS{#^GEKqxjBM6!SoH7m(gV@2p9 zz@AQEq0hCw80@Px6Y|PlUSLgK+}Sqr61aoK=SiJQcwazm4LXukzU3;fs7Y4JRlB8e zFTfS9%I}VpLe1>#(=7@KL%&pO+hO7Jx9Ne#OifuuF-Xr$O^{*#FC`iGiPjs>B^6mO z3Wupt5rzlPb3*44!=2xi28p#i5tXoM_+4 z*Y3FL%dZ+)3@O{6kabE_zDL z9B((05*jV5&VMw%N!`fFp~0WE@vwlipCSrv0(() zo59D{@3SIg(7HhQ0RiRC9Ya*Q$Eq7T?&Hoyr$7ouilHfxGaQVdm2^sS{Rcd@tcL2b zkVJOE?({V--vQIfW1a)kxJKWLoCd@Y6;uR%>k7)I!E$&YBB(^A+G$56F;D9$!=HGe zpJJtNLFum39;bwQ%haJ?&JbE_28V$4zEw_M85=S!;=8<|LWM zFwQ=FoKgr~O&mScb736c?X9kdq^h7Bn2pV8bS80`5s|?-IZQY@jSAa2=ULvNBP2yf zS5}m>>?DK$XPv7MZH`l=)QZK4vW+MjL{W%g+n2KV26Wdoy!pVuQ)dB&=^)(W*m%@CK(Oez{=;h*2#z? z0z!7Yf57%)nD1G}&@fFczoMn7*MCv-u(dOR{G*%)x0=O}+X>;zko4KqtthHEJmD2EOcnnrRNU_L9HZC2<}^KAs$TdCAJWLJ?-7} zu{v_`Wwmiq94OpXOaVyjrDlARg3h5bd8@Sj5qc^tL+t+SFC==`$Kpbmjj#;Y$_YxX zPtyZy0aK=Z*|VNKkKlI?7`G&@muUmvM zBIn!58IKw|>YSK#ZDIBMs^n;k0rP{E=G@R!^tS|T$@dlH>7MRP#$**3CB*w^+aHJ>`Nz%rv6DjglV{x2;5|3>~IVfaU-A>ZvU~Dx9XfW!MVILR>4$v zn=d!?GG^#stj7dvUB^Gxo0N-x9{nfLlKDaQMCv098u=<)SV#Hp^VM9CymR6OLfzKU ziikt7`1k3sr{^>=@1fS=dkaQ(7I~hiNpC}!ec6jpV8Yze5{^)Kg{Npv=08~#rjsKh zyw`IbFsb$=t`FCtXJ_$QRoazwGZ)XqQOXW=q`*7qXx|vf=gAL02Px@`$n_x}d9vhC zSncfrhZIFHA1&Tbb(ZX}UIZHyAV0(=oVVvO`SXIKzk83$(yl1ojA}9LOg3h1e{`Yk zdp%-}r#d;lHhP@8YFk0JI}(08(fz7AXyI;TX$km?nNW=O3Mq%ly3sVbhW`WzEC-O1ese)gbWT;c)g;Ua*aeJ-U zS5N|$zSM2D0&hX}+VTjSUbs5e=EECRt1V@I3&H<(Uv(!Rs@+w=fU$G4Nt)?(p|=_l z<8!#-dFk-BplZ~a=4N*_=Jb(0-!LKmezUc(>U2T6-+mBYt1fgrHRgFeMt^dlD+VG$ zY)q?nl#5XUGsD?%m*rVqYCJl?R{Ig4uJD5JttBa%!HsK4Ras8)7t!Jt;+uiq0?gm# zFF`76%_m1oj;n7lu}r?3AWe3EyQX{ zOJ$LcEqsB+E|Wb}YsqbwA6RSZ-&ru@oev>99><~<7{Iq&h-REO<(3CO22fhPJr5L0 z#5EsmykWCOX0JqlJR0c7^IxOA;|ah+|@cKvp^@;%+|-HpvzogD|KC=cs< zWT9P8{O*U%+f!k3WJ(wT@^~|)sP(BTkI-blgw*~vXuGu7|9{q~gi(D3Qm_FS1$%t- zpS~7kh_Y?GSEW$th@kE)MGm?*&x4g#`^=D^KRv1zSP%DjhTieGmy~JO2fifY8%9fF z8fzV>)OP$gO8x=c|5Z$(q}q{H95A7JW;mbpvUIjQN6t_3797A*cg^aMRAzFmI@R~= zY@*Us|N0yCrTJk;r`g2|0=>D=?LJ?s=K5)?4cV9sL&My587h8Pb|#>p{-lI56JF%#)F95x8mC|nR5>_6Pnncj zZL|Dg%4^w;V$7!GM{btVR3f8;Yn_@a3{==gOYT1CFe1&BUwrP*dH74O-#;Et(mf30 zz-ox#dL?>L@Zgqmo6JwX%gd{47NM^wlsD8zsaVY+)JqgUIw`NH*FEPdW7i~w6U79? zf_+|!2{?V}nBeLZK>6}B?n^V<_REv&qpR&f`bi7_!79^%m(D@@%VuL*fxfz0mSSUM zV`fv9=s|gbQY{uS@iapH$_!cJne8E5$QkF)Zh$6<8JFlXPlLZ(Q+?>lp3&`-0rs>b zU9efp^w%IB(D^P2!3z`{&Gj0$PCWzc*UIx#4`)%77&dXPYdTOe#p5&(&#DVb+W0v@NMc>5zt@f55{`Kw zV((n#;%IZ8f|&SP`ANi^)45ryjUKfUT6fcqql4d`qEviBTZ@yVuL~Wg_tIJq?V^$h zL{~Ll&61guFJ+tnl!Y`55FcdskUi9}gdG&R!fM+rCDpY;l&J?;-+6X^{e;ugbA)o< zbHaR;99$r#u9}6M*qvWXxVw&hfcz2Zi770!>-aF124Li2etX{1L~%O26(#m*DM#e2 zZ+jbH)~5ViwWPRZJe+`vjb|m--~lOXQ}+968eHH+#qx`hCPefqYY0@KZ(F+NzLD|_ zMiM)xQ(#*SaUx+Pe(y=V6$09Yfm`!MQwOMrgIl{Tl*{X-XOHyd#d232IQVR11HUZf zb{u#7>6w@*?kpYf|Cx`lUQ^6id<45sN=#P}wVDbJ2?3OLls#o`jLEIi>{Bf+#c= zfATp=2tVybR56H`Ifx)^}HfuRIMQxPe9jkv!s~h@ajt6yK(I^ z+_XsKR>!2(=ntjuuAL4k983g=AOKz`6GD*BFAer5ue=iYj6FNa%={U!Ey5^zbFmri z878V2a=Q4%-61%`kq;BPUA``^uhrnYjm`$66`I#4I#YL@E|*D&UO&S#Rr!W9Vk@s^ z+;E|j#WgR(gAcQA=pkF-b38oJRK`8pI4}5|=eQzYIPAa{);-aC6}}g()~DYkKs=_x zBeTR@tl6>|OvgjjQv*J3@wMHYs624sxFg=FWZ!i+w{%8>_qFDm-j*uuFD@`@Ha_JF za${=y!0*g(Z$aacx{Tqr@qQ@Y`z&!t2?_aav%+C(i$op|W{1(O-Wd}?_QW?`#hoXE zmuq>K@WSD9g~;D&G<#Sh=da7G+8%L@;?-q&@K=~I0e6dk2`N^C$kaBu?pd09-PYj& zGFMr5AdmQ&wqQKn6>wl!@i(p8z%;ij-2Fl z!EktxoqIp$9xuLj4IHp;bcj8Z_w4Vz43#(LbVQJ~nx~}WMJA>8`t}sB3~0!%ZahbF zQ(-)5@bCNtmlL^<0@YmRg2sGW6yeQ?*B!(ql%Ll92B0XLDATVxkXupbPw}A0!gD_w zF&0!o??usPqUv*|{p<}(i;EZjb0fO*Nrt6$l4s6%WdwH-XtJ$8-t3rAp9{9tl%xb> z8h!`~$*dn?GJ~K(7B2ZNHQ?i^o+LH)Q3Lj)3Tr!ci@zyUvRY%ON;M)?eUcS}+P{xq z@y3EI5#fqsq@VA9NaY~X4TiiP1CAW#utWDe$#J z8IcV{P94344*k{E85Vrwxrk*LfjzPo{7~nA_H%`o`S%DbuD?vFNL4kh|D>^~Qj*!` zBKtfh2RAfE13djg?9jG-bM;xShfA|27HbgL3~RMjYqj^_fU^|b&7;$&h!BSqW-rE< z1OBco;AYYT!dVvH6Qe2{{RVpA)IV-sCmuaiRxGPSLcj)(9=0Yb$U5<+-N|Bi*)K)N zn3?-MNQLU^+Cq0=~Z^Y?4MzS_usG~Vya_{Rjn6b2h>&7y{ati*?-an#Y+BN!nMbuU*h{Z_`R`YA>d$JK&@WuHTT)4LSm zdK#4ph5p&FiG>zyFQoaR)`Bm9^sB)+}T*Z-P~*EnKD?_l7?%{Wu{jX&_yajI`#lYc2f`$ zZL8EgNO%)sF(Y#dEjS1(mc3_d67O}EDl`vWm=@M;@slD>WyV^PT#wo{&GEZJ@*WPW z19s2y28~=U{YS=gcQRdEk0NEckU%cwlT~G|7mGCo?mW^La#L61I9t?k)#|FjR#f}e zOV9?Snth9tGAAxsj)B6O(DVC(fxX~{&bEkW7IKF(_yyaehmJvTDq-4ZTLuj8Fy~!l z=XrFg)-84V3`YzmG8)&HHEFy{pDmHlkfDXH!+E~B&`4QbA2R@zlVgcjoiO}0x@k*b z{lYeno4eJ@MkCNG7b1=^hKGcR$)zV^dP^WJ3Aepmj_J6d14A45>=Za;WMpWVz<)o4 zvBP2)x|@WY(*i%^YBwbp1UhWL??nH(}6&=7k5;Afu`!yE}HbGDnUSH8O{wm)C zUxl|Dsv0!*C?48WlYMra55ssjN47u`SyRZ_O7w|=WOD6qCf%RGTe%a4zcU8?8E6fc zEi{%ARFmYA|WXoEHbS;8New)1q_V}nl8Cuy;_(g9;553w3Hf?n8? z&U4IMTsRDD(!Sl~HnLPk?7FJe#a)Ae_`Qt9`;!5Ie+TpeMYs$=lk2|WBI^B8tcueJ zCtaWcwfK{Q6wJZn#tHA|YR1T-Q4Hi?l>eY;IwLh5&78c)3S0&789sSBMusMDkdwrjaDas;2nQ6eu&d zILSKc@1QQ~s9!rR0N)}mM9v8LV@BC>L;q(Erj2mhtxgAVb*99f=L&y*S-=dtp{qOm z7U9BeL95;9XP}K&q>g%-4f6eD7lUIKiQeglzG`B^=G8;_NO3~8nP>@Vyx>f$CeoRu z4d@n}PWIMTRnXFr|ML^94okVGVL;e%ljygGjW&;yhe;ImJ6x3uGXpPZjq~*sO}vc2 z!+_CKN_GGo32oxYppmVf1SP@BVALq>ei>as9|Q||f@r0<@!N@oYwhZ%FSK`3`w{S$ zyOJ7~mPDwh#{)GydP?<>DIS3saXtlaa49`S>$#T1AkIIbvEZC>#>chz2*VA3@HO z=~tP#BB$)=sbOx^rJpj8qz%{PQRODA~C&2-ThXR`?! zoij-{+nRW^%Ol6jLLv(``}>H)PrKquC;FxRRmWistYp2XSzw zDOTq}O{x)7Qyx1$nVKu*r zVZuj>ZJextW>CIxPt+Sh$_LOhFlNff;Jicktg20%{bkw)B7=X@pgLV{LL3UQ8EWLp z5q<}ZJ`s!P>LI)SUTiii^%Z@i1ETaIad$W$>2N#$j*d;19<2)1V%fP`VTLShp_Gzp z>}7jn?;q7(-t~>?sq-i|b>|3l-?Ry@rnbhM=b;BUdXJWonO)H24_!=)X!YGXqW5zf z`>L&86C*ERO)zCxy(z`z5msE-qb^FRjmFk@23?LDuI5o6ZVub#ewkwcT_BLbDU<{* zTMW4qgd;Hp7SK{Nfi@dCLOXITr7>r{t&FVPNe|p)cE*Cp(dbL%mK#IPQF!e5cwLNW zHY_m)hNRgjTS)ei5={zMPYrFFK#SXnYOTJsH1pJl2S97iV!u4xL?HNJ1L6ZN3VW|M zmUvW1`#3bLfOW&zb?U1fy`ro+aFmVt?eXmsy5SQ;<7i$}PH<*dMg=cV3hj~72?rjU zD{WvrPmvk1yyyLCdg9)409|-?SrHm)kjUCV8c>R|a>~Ts1DGz3W%}}A92@@1{_~h2 ztm2K%y|vua?V+xR^j5VRM(L`E1mRmWe8VMY9PpA$vfH3K-8%kXr|Vbx*?-f&YZq3G zH2S_;9h*cOEM1^w8!E!K@zWWrI}~nn5oOwfl*`7K16O73IW# zRkH7(}v&G5`50KC*&B2 zv^yAkco-E$lI+qi-EzRsv+I9-Q>}JgEEcpiNw^XF<;6GV7|Hnw>@=+fA7e`HDkE9O z*LrPEb`K9}&{#2gSb$ekpH{Y>>AW?IZKlPsIji}_qcVPc^(-Qx&TPB=8C%v!X7K`$ z7=nudmgXDJdLj92y6Aq_eBvG zeXb#sKh}24wb<6+x|hSq?n~(|nQa$QFBG#mRqdO$UjBfkU#gs*PB~iV`12QRz)ktV&})U$7zoN7sJzo zbZ@%%=s*4N{g{=5&BtCI@3~I;c73a_8YY_h9%J&bID&sFfX7l=zhU*OSx?ISZJniX zYCd0w!X@izt=Z5uuJOsA=hb5n5(p_sM&@Bc;ydJcs~>7_?eUvTt?mKx2C=??tPI5` zdxBQhAGPH3Q@uK`{7Tox2-asgYwif)`#cz&YsYA<*Ag}7LA?#ttSC zH{%w~>_D_o3C)q8oz=DFbJkfc2{j`Y7T5Vt{x(^$SB6j`%_82F3fR^od~Mh3z(dW{ z7PEF9v-WqsJKDA9Se}wjS8k2n`P2d3U=f&>GlSrOSLPpoNAe9W%Z0Yi!dq`HD+@2w33dKCeL>gAQFa878$?ytAp*?Srszgk-K)wk z)KyZ)!Baetg1?T7?$hjnJJzGw%A9+AXq|z*<3cBkRi^F=XVtlRw}fBG z{t1;~$}rF`J6AoLjF&3D1^_gA-7)J;`n0#uK1y9|KHrZfX{BMEJ9~jgm%;0cI>Aax zxWuZrzRSd;OXyYm)%Kbmo@`l2qlT?5fl4VLFRSpTft30sWnw#%AUCgyPBb^f`IlD>JqI^*6)p`yT97UpzvfWE zOFl}}hWO$AzijqcO}cv6yyjVc{W7(s;2-u?nftFV`Y%6m0sAP#BgxsiYC8`Me*J^3 zf6h2%DB*^z8_m0(0;lJ-FBwZjDk@QYdEm}{PBj0jH^vtrMc#uM-ZT>O=gy00C*(G! z&*fKg*5-M2>p+fFIV(D<57#TR$qof~B!4G!ZFP~T+c0kre1&a6-5me~WP2c#a?05e zbUMKXVQT$A;?%-6+tl94eP3DWzP4?2sarru)$$s@!SVT<2eo$~hJ-JiL}H zBWxo0bQb%~i~6HmN<5)Mf+)!vUoXTMOz_unkQVgIf<{Tig}BlYwvj*K$ z4;8XBeqn@H!}%Vn%gwbGGk33)dOA=DqYe7y%?*WWOuw!Zxx+^6eWT?UDb;5@&Zh>f zcU>Jvnq+j4+oq0hv4B~$(P`cWyfvp`7+eJO-=LRqcmmqCNVrY_FkQseXZXU zt6Qz89ND8Vw1i>wqTi=x97A(;zc{x=L&yQ^6Xkz$SK2K}l-yjw?*63ZtJaP!YE}Q3 zh3cS3{q(?>Ba0i-QbdlrBylFP)wlPy!Ow-vASm|XTDiBv=*8{ZiQO~ax$ZYDb+;2X z$dKvZjn1?No2Ij_8@8MC;NZU6UKADO`2%#0!V~rkl30hLMr-zHZovj{)BIMiI$>6V zNT<_=;iVo{+r-2l8&RO(@l%pt+VRJzl>U^YLA;4m@91E(@Sv!&d8&aZ}(U~o?AP@3NT@)bx!)$e=4~N`ep4IpMpr* zZl9}smmG~R^5%*_63@DRu2M^~4#nZk>Az-Zf*V!V4d^1|D5QG z*s@A1j1hGbViYX>A{ZP3KW)6Q2uCQM1*plXPmpEIsJ_^-^*#LNxTgM-t>9$rE5?_{ zbDg0;{mL4jiLX=72I}zW>Mb4+DPy<`*AGIAY(Ypa+)w0(bJTamuzmY|9YVrw&!$5Y zYG6jADG^QlE%dEvF|yL16TWH-9_`j#nLh6^RjChy0y5jCd09b?;KS3NqMX{1QNOy} zVP;QJ;u%(Ll-w$y&e4XevI$7|-Q=i|f|vG#*C^L2p%ddVF18*vj@dGEeE z<66z+vxvoxH)z|URwIcK3!yj%Djws@CHxolb^d;|=8x<&$RL-y9QRQ1D5K5ahg^e+ z3hHq9HyXEGg+ux62uB}`gL>)DL5n{kwp{Nw|64o|?K&W1-Q(86*Mv><)kjE2yM`Pk zH}j&2od2G=+4cAv4Kf2R#&vw2UR(Lp6cH&QaZ6E|qw(gt<@w3P1YBkhl~Zz@L|g4)tsb(^tmC5z5p#=YlsM8 z_rop#WjEdojh1PhD?_hl+TIqk`8TjWSeqS2u8WT>H+i%TB?}@0>G26W(Mp;iPRP!K z*KUL75C?CrD#5tAMRG#kM|KSSy4XKhB<@>nG&UV}AXX>%Cl0p6QY-}Z+J)H}R5wbO za|YV+zGn1_bKA+d%Sh**IXA4H)LFg1y7ka|yxm7RJ}q_)6Hmfu2aJA?!4&Dkcdhn`l=O|J zj`B_an5{JLX$8m2nPW3km=8xS?2-prya^5FTTxjaa*d1KU73f?chgGVkYu_xeX@Yb zTUeu}mLXo#wkzw$vW&-V zhViH^-@VoeI>eX6Z`VmqGp6!dzj&rGm=L;g2D=GG_}pSk>^oCVMyOcMw3r9!y5M`` z>TgU+ru2I|Np_}>q3cdCFghMTjXQF`LnhJNbEN(Bf@{}T#@}L@7o9D(C8XT_Qo?b^ z<_ouRf2kHLo7_rXkOyB{DJ_GO8d0DR_LDHpjLhNskEOUgO!6v@Qy0%saKb?Cuzgqy z@G7LI@!PunXZycNRY=IP&9zVJcjft)dwL3n^6XanSF~2jw%Fx}oblb#Z}wB&z1jmw z-~Wi;xX$cYqdjCF&mt?6(n%!@*uwOEf_`3vnqpgG>n{k@ObR{2xSTyP7ZS~gWTh!@ z`*sJD^H6&@@k<&19@lZLPY*h7`FVv+@ADp(ZsWJXHqOiv1da(1X?cHq{LCW)LrKv#5^Fso0rK08P-YIJFA_$JrsCPGlMx>!>d%u%Um_p8e$=&c^*Ui z@bS=c+)v|ys;J%1ZDuDIN6l=t$@-f59Ku7}m9*3^;yh3zN||9LcUm*yxp}2=EcB_p zHTBLR6>5oM%J{WJ`Tk>xf`>_1WTrgp?`^uAjB+Pw3peT`q+7h|rz}aS4MF=`7N-r+ z0SMOE(2k?}9z1B+JW3?9HH7qIDs!z7dlYqpOrm|XnLVE`?$=mzWM@Ux97&(06K|k( z=h^Q^SH7IOBEs%K@aC#8%PMO-0~n9@vZL(SpubDZi0OTG6?}wq&t5V1+bl-BGBF8- zzw9e7?&lPsOv_L-i}Ir+?p~Getn+-m`o=EkUkES+co3UBc(?Te7py-P@fw3?-ffOG za{M9VF3|DB@+B>A5FL@N6!D1R*k}9m-5F?1(o#O+J<}%DQb)MrT8YoMPh=1I0e0Vz z#Ey0Wk0?k6^Zf>r3fwAFi~g4XA=3a?m;p@#}=mlSp9F<(? z_T#cU>Bw%5IIEt5(550UIS*7C6J{Y`Qd*&xxB1}9o$Id=3?(e3dW!C=4QWNf3PetB!v>L(GA zafz1wb4EFeBwKPoXBTZ;`&y-KL2ruwQ6DnY{4BkTkuf_NFJ`6g%JIxt(#(hrV-^zK zoOv5YF8Nr!?E#UnJjxUFR#dpzoIC3w8g?EKT?UN?X8vg~dIX1X(9meJ<)xpi{;TJ( zApi$fB8pyNn2xH$o zUyt{b6ByDbZpCp(nHApX#yojh!-KeC96)Chi)3FJt^cgeOr%abJw5C03PQh2W*}`p z{V4{Iy+20;;J5!n?>bOetod;wZA;HlC$Xn}Z-5?Nq^qG283Mj%y1z_oU23Ic8_?}| zS%(Ku#OXFhOvNO3r&V`r<`<4>X1>fgB0(mT#= z$H>9ppX|>_g^jCve9$d?fpxl3fl2<&8{yz>jpL;L6btW=$Llm%vFgO_FfdTj(}trl z7Qwgk8j)WS*Q6#U31Q*WzY6A$K?S=8CZop>WKrQzVpCM|(HuhYW|nGw(%DGI(rwfc z#kvVi-x{#N2erG-%4}KLK#wZ1WNE7Tq<-Ugb_W>M6J>$B_7GdF^T-^Af@sB^G1SvV z{}HX#o@q0qI2-9bslLO?^PBEL9o3g_+S-f6+pd}=mUB7@3D>!2yGQBo3PG;lU%N?T zPk2Z7_qu$168ej=EYzSFOW0KrFk!bS&(rbgLZ>kb(XgWs&9$2Klf#(ryd{MYYzUf^ zsPqpuh7X!x@n0Avvv$Hr@GLW9wVbyy=`C*B)i3IzVEO9gHY>|Sa&{Y?(-E%rmY#Bf z;!c{#giTql_J}kwej5q&(3WhcHgUx+>^4=%W!7yc1mW(yVEKwa3}vEW&rs=uQS=x` zgmw_?C>N%68wv4;`sPa!0z}Q8=}x^rrC#z-nwRA85(wp9{Kt3OET;*AES4=N{P%>0 zJe<({dyK21)HnoxfHcARO8YX7s`pgMjs`qa-O2`Sw_$%HG?r99oR?<7&dU{hOgGrB zcBWTQIavm1(-tBPzR-q!*+_(Qo6wqFM0;Q}Q2c(WFIT@yMDgd1cWT?v;0< zuOE`DC=K`S3ekirH$zYaXY~1OCV*FQF5eFdGP<)saD=CDPRIY+*;1tTtYmo&lq}X- z<=aJsQUAqwwEj+GN(nJV(n8>V7Ar%{x9|hX;r)(RUSFvsW1;zq%e7{5M5bs#xKYIp z>una>lE0ztY~T2{FYP^r*_%E1c)NRN_TuI4yiPqOl-0ya9QKL!G)t3f+D9iw4f@Xl znZHdQ=|4(rQWN#h2?_W$jTgUHUt3hQF;hNwzxI0jBy$KRld)#D7aHMAo!Q>WhxGte zK8vpoED#v~UZg;h_FHcAbfIy{Y(5k}HypYclZr*O^fWp#4%$?*J#hxh{a4y0rFw2$2)*EC-0lH!2HO?-BNuTU`LQnd-YA|MQ@qyTE=88z5CA+FYmM) zPM=*epQ{4GE&C&U#aC}mNn*~6hcY{;bbd7x7bkC;DbUn;A=k6LoK_cUY7q~x2<44E zb|sEoRV(TvqM|eOUbwBzJ=u5n#%@ecm_#0*QJRF)LFY5L=IU~*w&W`c9_QkA0@6EH zv%KXU_gCcDaotuV>EEtOdg!RQ3GIi{?n*4?T(VOAxVhM`vZ9!jOy<$YndX2k#tTYj z4c@tD)>Tqaf226_<^@)T{@MbJ%cM1?>u#&tCysZzi$YT^ug-1W547rer+y_BD9z9~ zIV_=AxR|C9c-mZM8pYve?rKIhck*<{QYX#*ME~N)Ay1@NFk$&kb>roHHjt(*cykC` z+8B9|HXTnu!;Bn79&Z#HcQvySJl8Gc3CXg zSE>CjQ%0#>f?$d@9~cx|Weh8iHmr2mA}-azDvc}@1G21#X}D~^zZf=BrxI}4J7T(+ zRL@LZNE}|?F15OtOtBBTOn3|2#2!2)KUsvh3VPBsztC0VcQwIg#1lGxim=Dhcj3s{ zy%ZDn#K&eFF&T)mUH*uDes~f4GoQ!k+fD?+-Rn*NlKt`&89FvqoL^=Hq|x7OVtgfX zx5s^QWO-r>QI8zqcnqry+-)P2KUgw-;fltyImVW*+^7+!yMu-&?VOKMI9Rk#B2)$?p)+#ZMZP8k>Q9IewkLE-R2=wxN8R2$B=6@EeFOmsWm z$OYT1z?CGJ)UNC{H(@QBelqGb@}RuT-2-PecI9B?bHH6yXL_lEYg*MV0lRreZ&}4V zNBcJ>`?V-wQZ@tXUq(MnNvlP-{P8wkk3B;P6qfAwS(Tt0&|(8w(Bq(>H8Y&6V{Jgd6U3}>BxahuUm5%&dr`FFn5+pnJ+O`RTg+b8Nxe~?osI|J6Du+q@ zt#O}zb2ulM8*AKlwYALsONiYy=#XD~yzpxlfHU?U3BiFiUuaj?gL6*3kp)Y7RY=!$ ztAKrw!=Q8QUhe_?M5eLRfzx`n1I&{c50zZ;l-!j!o4h}8BWyiOG|;`3&RYpLpk6wa z-;r9HP<)aq;#7i$4vhkd3MJ6DO4_f2+k>;LYF|1gaDfnhA_i;<3)g}Rr2=&ROxW9G z+oHVm)2YW>qFxV(QYCKF)&LD~h0d8Z>VhKy7ES?G!H(0J9B;_{~ zyMEANl5vB1mV}1&opeiuX?^%w%`@rM;_n1y{q|1hU)sI6bA4g0P0^?{zHPf)Z;*~i z?q%`JtXGvek%q(xV3PZZ#Q7AS8-<7mPuv~Rdb0(_QiuzmFgr#vKTr1bFpvDP`qA}u z{Gits(}eW-Qi5Mh(zCUisHCgGMn&(k=!Oc~>(yy+{c$q5{%UCc>phCEg(LsTaU&r) z|M30Z#penn1+m_qR`RsMAywvr2Jf1kgmEYKC7u`Ulcd6AS#;)^mxw2~uJp7Jm z?b;GUjgb=ynls_BA%IEl$GEs^zY3u}@dVGTY3L+VVj6t?v9z3ux14My^tt1^>5p)WnhZ%u)N_8x2v(+xg?@A=7I z4}ZwZd`qJS+m_7#Xe#QJ304LE-s9(Q`P#(Q7JLFymlsc|F0OP$8YZb4ixT)i(Q)l* z?x0h{c(J)Pr1WpS)VLc2STO!x;4S7q3mmOxGAVtM{rvzHG(k^Bh2cp~2g>sT3m(h2 z>iaS4UM4O4iGj5XgZSj&T)+Vq;E3B`i4E}u>|0JWce$Z0Ji7P&^%c9FSY`HfAu(Fm zHBzFTooV1gC(J4e#0o#ZtUohIqD#X$`ZQ90J*LC?a$Lc zJ+l-`7^y@SE<88)U|9REM98ih8 z#am8gXKFa+D7^=YqfP5r5^KHhCW3hQ#MxXx423GHmhSo}j|(jLcnR!qH+@X@ej#La z#l1Pd^!&E2ilWgLUuC`t3y=HAcz-dG4`70L(M!{mX6dNW+zwN3_9L1J{K4nb6QQxU z-cq0W8r!$K6tVziI*9jb-<9<(xgnzV}xlNt*MjO$fFlH0@8-P z@4;^M9cNZUCtsjGBGNREiV54*6zE5y*6PbU{sa~`^6W#Va(OS>GL>wnz+02!GN!hp z+-ZgeLNZP8*;IEzd${Pijy&|N-b1gW`h|kqO$PRRwQa=lECVC4^d66ikY=Rc^lnc2 zKcd9-Rb_lH05#OoV5=i^cNk+ zcOTN;Cy9(YuDHK@c&{UsaDT7;%fWe`^$#f^p@`5KLbFmJm7@g~A#@U_u1`(;r8u{u zDF9Bszns+%TMFk#iV-vKHd{l_`NYNjTS7usy{c|D-wCrVPffWR+gqDFn6RQDcOKf9 z2idp}U|x%=pU6+)4Zk{cTD@I(-~r!}dFiOX?`;Y+SiFBkoSxyEtUYCFh(cDHvb5M7 z4|$|>Z!95`CR5eBj|skW=ZJcD>IMY#+Ar0$4{nn9jM2aACI6hjhbW_%II9b{YgrQ`G4K?(Ioi=cX?EE7bkn>ic z9fHg;&MsU3N9uKRle?iU){yzRI3))CV*P;tG6Ro3*-oMtS(@21D93Ggoe_?2#|Pir z8)`9L#XL(NtMXN9Z>avH<3%d3B+1)&#xxYyul@e)<0SiBRY=9bX@T9v+lksDSi&|R z&d!wI1ICchr=KrOEXjy2w<+cu3Pe!R$}TsTa9-q0HsNJaUGQewurRqYNc9G}QjPQ; zD8=Z_jOOX^09sr*11QGsB9D9P;M#{@GflTi=a6wBy(0vdg2x>r>xc5iBeR$xM9?lz zpOH_WFm^R>RBjJ4>FLG&nHhgZJ~lxa8RxXaccrD?K^qepSMk5Dt?IS>SfH?4y!5(d z6(ZDKE=B$jzpe?KJ))1)%p5349igYuH%o`FupDKI>Z%-IxZr3>|-8woQGW{vt37_H}^jJiwN+5Cd=2XM{Qn9 zV#(2%is;GpA^0R$U{1fZvE;cp@V!E@YWutV0}{m@^S%VFfw&y z*PS|59On%8&+Dd6+N0bpUGND2KTAD7qz-P>Z>)XAG&l5W3*PSq7wC4@-S!7uzUtGv z#42mL!~v1jVbAr^`-r9V8Jj)6qwRia)@t@X5JPk9;qHpBjnNb1UnS0z{)--mQN+*p zI`jOAGFHb^->$`9{e-j)hBeTin2L<4sTs?;Ud*vW{#DP*soS5IEk}T%!aG0von8Ei z+{s|AkAhr~*Yxh_zC6QejvU7CJK`$s3@7{{X8JRPNfH3R&SoK(u^>ECw;p-%fR=bI zD#^5VjroDcoM_hq`3>LO|1_Dm)Dm%)Dw|G z*H(aaJS-2R_Kf9B$($z0-Wg#~0)_Po9~0h^w%~lY{oeGM+{vd?`oNzY(gWszop{(w8sta9ccm;$T(K<0#VMwuoabCV>G2!$ z-5{okV^}V9GyMjO5X3KDI38Xg2PPC<(3AJ6rZ18-9?E~^<0yL{@G8ahiI<7pK*7P` zb7||Vx@tSmovNoTlrly}_dLnU%wC0nnpsKr}zb{L4y`d%{HZBMC zYwdejut%-R+Ryg^x+o1a$i6i^jWzs;aQa8%w_pJRJrg|Ac%!Z=ZRjA(cJ|rje^lzm z+&w&v(J^$&$`e=>uBy>9WrPdsP;b%qhX)bP^{2MBR4tizk+(@joxNJ*`8YM+tBY2% z0{PQkJ33=_?>kE~Hh6`$O$18$wJ2Z!5H#qH2Ly~oo<5tn+J}S(REEv)tGd#zMeqQER#zZ{#V>D&ZWrzj<#cgYV0?4B;45X!Q?||MC$aZnK?$p9Y(+1oquevEZ zio5#M+r$}nzlK$-gdrg6_<1!7&)1sW+c!xPN?RmiG~;h|T98T-J{ z@z@^U1<*F$we-`KtUJ7IV|9Gt?yTNyTe315IVgU}x##W!%V*7v{!PoK3Efeq&h2-L ztQiJrR+gvyWNE>RaaE^(zsj zHVB!@tt&r#N^#fa?(Vc}z?Di#sqD);B%K5OqA=yW=7)SX#NTSXLOpO<6-zTjr2L%7 zoSvM&weKEnbjOw5V0TpJ1}#-R7!c3MiRfAzspQXV)GyY5G@OIsT^0t#t|_nHVpt#1 zZNEMUGLnP?%9<;pMu#vmKQ=Bu@Qm_K=1iGMSG(NRYu<__S)^B~y)LGwMS5lM9`G3ZV3oaCuldlXJb%+Ea5%tWp;qm&}-3ve1yNo(wqF0Sb=VAPdu4yPxf zD9X%V$ncr1VYMWBgkDx_-C@Lnoyir*|a@+3XQ5iceW9&_`@4JLKR|PwO)^!PaF|AD3*)SLw zoShj;O9>@ZJel()dK$qJC2MbFh9%ci$|mlDKHWN}l2_cQUrWuIuoI!hiDe6hp{+d@ ze$|3}l^-N}czRuu(;S$vzCX&M(Ktv=tS5Pc@CuoZ>UxLNW0m1zH8o=quHVqSir@{< zI>y#P7&WBTg%fC{poF-z?d133ex5t-oFMcOCEOku8XiYy$-F2wt8ZgOHWe-Kg#Vz0#Rv$1~1ZvEbvEPRQp znxJ+%L{u8KN(+v2gKvt${U`L1%7QtplCs;&7Si~&hPa`ig*42xMDC@2+1SR04^Ol) zV{(EPP>r#^jqdNW{XDa7k{gU98$$*fvG~PX*;)Cqw8>|a$^fB0(PJWB{q#QW7RkV+ z{PZyLfs2*t8VNQ`+r0Xc(CqrS?RabCF+ONGA}!<(8c@dd1sKZg?g(>zNG$Qhs8ShASP=MHJ|{78RjVNY7EbsQ`f=^2#DacObuD9X{XekhU6+&m9W`Q)O~71zc{m zGP11SXORP+6wI@U&7h-1=*~l+L@l1I#3Ab8#w`(h^>nl!NQsCp74e#TS%A-2BRjsHFnwj(};F;S8G}M>8jIwm8l);Dp1;7`3IsgCw literal 0 HcmV?d00001 diff --git a/order-service/README.md b/order-service/README.md new file mode 100644 index 00000000..4db0ebe4 --- /dev/null +++ b/order-service/README.md @@ -0,0 +1,38 @@ +# Order Service +This service monitors incoming order requests from the car UI (Car Dashboard), executes the order placement, and provides the relevant response. + +## Prerequisites +We must set up Axon Server to handle command and query operations, and configure MySQL as the persistent store destination. + +![order-config.png](..%2Fdocumentation%2Forder-config.png) + +## Local setup + +- Setup axon-server and MySQL docker images +``` +local-dev > docker compose up -d +``` +- Run the application +``` +order-service > mvn clean springboot:run +``` +- Endpoint for resting + - Generate a request for an order. +```arm +curl --location 'http://localhost:9090/orders/create' \ +--header 'Content-Type: application/json' \ +--data '{ + "productId": "199", + "quantity": 1, + "userId": "1652" +}' +``` + - Get user's order. +``` +curl --location 'http://localhost:9090/orders/1652' +``` +## Contributing + +Pull requests are welcome. For major changes, please open an issue first to discuss what you would like to change. + +Please make sure to update tests as appropriate. diff --git a/order-service/pom.xml b/order-service/pom.xml index 72e47271..a90b324e 100644 --- a/order-service/pom.xml +++ b/order-service/pom.xml @@ -83,10 +83,12 @@ org.springframework.boot spring-boot-starter-test + test + - junit - junit + org.junit.vintage + junit-vintage-engine test diff --git a/order-service/src/test/java/com/nashtech/order/RestTest.java b/order-service/src/test/java/com/nashtech/order/RestTest.java new file mode 100644 index 00000000..6a8f0586 --- /dev/null +++ b/order-service/src/test/java/com/nashtech/order/RestTest.java @@ -0,0 +1,75 @@ +package com.nashtech.order; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.nashtech.order.restapi.request.OrderCreateRequest; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockHttpServletResponse; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; + +import java.util.Collection; +import java.util.Objects; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@RunWith(SpringRunner.class) +@SpringBootTest +@AutoConfigureMockMvc +@ActiveProfiles("test") +public class RestTest { + @Autowired + private MockMvc mvc; + + @Test + public void testCreateOrder() throws Exception { + OrderCreateRequest orderRequest = OrderCreateRequest.builder().build(); + MvcResult result = mvc.perform(post("/orders/create") + .contentType(MediaType.APPLICATION_JSON) + .content(new ObjectMapper().writeValueAsString(orderRequest)) + .characterEncoding("utf-8")) + .andExpect(status().isOk()) + .andDo(print()) + .andReturn(); + + MockHttpServletResponse mockResponse = result.getResponse(); + Assert.assertEquals(200, mockResponse.getStatus()); + assertThat(mockResponse.getContentType(), + Objects.requireNonNull(mockResponse.getContentType()).contains("application/json")); + + Assert.assertFalse(mockResponse.getContentAsString().isEmpty()); + Collection responseHeaders = mockResponse.getHeaderNames(); + Assert.assertNotNull(responseHeaders); + Assert.assertFalse(responseHeaders.isEmpty()); + } + + @Test + public void testGetOrdersByUser() throws Exception { + + MvcResult result = mvc + .perform(get("/orders/1652")) + .andExpect(status().isOk()) + .andDo(print()) + .andReturn(); + + MockHttpServletResponse mockResponse = result.getResponse(); + Assert.assertEquals(200, mockResponse.getStatus()); + assertThat(mockResponse.getContentType(), + Objects.requireNonNull(mockResponse.getContentType()).contains("application/json")); + + Collection responseHeaders = mockResponse.getHeaderNames(); + Assert.assertNotNull(responseHeaders); + Assert.assertFalse(responseHeaders.isEmpty()); + } +}