From 400157800c0254175c89cd53dda4e3fa25882f61 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:20:13 +0100 Subject: [PATCH 01/25] equals on Object --- src/main/java/fr/arolla/modec/entity/CartId.java | 3 +-- src/main/java/fr/arolla/modec/entity/OrderId.java | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/CartId.java b/src/main/java/fr/arolla/modec/entity/CartId.java index c93454c..4610f31 100644 --- a/src/main/java/fr/arolla/modec/entity/CartId.java +++ b/src/main/java/fr/arolla/modec/entity/CartId.java @@ -25,12 +25,11 @@ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof CartId)) return false; CartId cartId = (CartId) o; - return id == cartId.id; + return Objects.equals(id, cartId.id); } @Override public int hashCode() { - return Objects.hash(id); } } diff --git a/src/main/java/fr/arolla/modec/entity/OrderId.java b/src/main/java/fr/arolla/modec/entity/OrderId.java index ab28264..7de400c 100644 --- a/src/main/java/fr/arolla/modec/entity/OrderId.java +++ b/src/main/java/fr/arolla/modec/entity/OrderId.java @@ -25,12 +25,11 @@ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof OrderId)) return false; OrderId orderId = (OrderId) o; - return id == orderId.id; + return Objects.equals(id, orderId.id); } @Override public int hashCode() { - return Objects.hash(id); } From debce8243aae7dcdf15839d74651e72a923ccd8e Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:20:59 +0100 Subject: [PATCH 02/25] private fields --- src/main/java/fr/arolla/modec/entity/CartLine.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/CartLine.java b/src/main/java/fr/arolla/modec/entity/CartLine.java index 33b4cb5..567af52 100644 --- a/src/main/java/fr/arolla/modec/entity/CartLine.java +++ b/src/main/java/fr/arolla/modec/entity/CartLine.java @@ -10,12 +10,12 @@ public class CartLine { @Embedded @Column(name = "productSku") - Sku productSku; + private Sku productSku; - String productName; + private String productName; @Embedded - Quantity quantity; + private Quantity quantity; public CartLine() { //for JPA } From 496136f79e34fb7394ab820f3c81c338b384318d Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:21:25 +0100 Subject: [PATCH 03/25] remove empty line --- src/main/java/fr/arolla/modec/entity/DeliveryId.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/DeliveryId.java b/src/main/java/fr/arolla/modec/entity/DeliveryId.java index f602129..550a86c 100644 --- a/src/main/java/fr/arolla/modec/entity/DeliveryId.java +++ b/src/main/java/fr/arolla/modec/entity/DeliveryId.java @@ -11,12 +11,10 @@ public DeliveryId() { //for JPA } public DeliveryId(Long id) { - this.id = id; } public Long getId() { - return id; } @@ -30,7 +28,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(id); } } From a60774b2ee01939932375a309fb1d2c562edf63c Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:22:41 +0100 Subject: [PATCH 04/25] Use Date instead of Calendar - not better but less mutable tentation --- src/main/java/fr/arolla/modec/entity/Order.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/Order.java b/src/main/java/fr/arolla/modec/entity/Order.java index e18cb5c..7495652 100644 --- a/src/main/java/fr/arolla/modec/entity/Order.java +++ b/src/main/java/fr/arolla/modec/entity/Order.java @@ -2,6 +2,7 @@ import javax.persistence.*; import java.util.Calendar; +import java.util.Date; import java.util.List; @Entity @@ -18,7 +19,7 @@ public class Order { private Status status; - private Calendar creationDate; + private Date creationDate; @Embedded private ShippingAddress shippingAddress; @@ -29,7 +30,7 @@ public class Order { public Order() { // for JPA } - public Order(List lines, Calendar creationDate, Recipient recipient, ShippingAddress shippingAddress) { + public Order(List lines, Date creationDate, Recipient recipient, ShippingAddress shippingAddress) { this.lines = lines; this.creationDate = creationDate; this.recipient = recipient; @@ -56,7 +57,7 @@ public void setStatus(Status status) { this.status = status; } - public Calendar getCreationDate() { + public Date getCreationDate() { return creationDate; } @@ -64,7 +65,7 @@ public enum Status { CREATED, IN_PREPARATION; public String toString() { - return super.toString().toLowerCase().replaceAll("_", " "); + return name().toLowerCase().replaceAll("_", " "); } } } From 26f723218f03dd8c1259bd188ed79facdebe589d Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:23:02 +0100 Subject: [PATCH 05/25] private fields --- src/main/java/fr/arolla/modec/entity/OrderLine.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/OrderLine.java b/src/main/java/fr/arolla/modec/entity/OrderLine.java index 20ce279..0786847 100644 --- a/src/main/java/fr/arolla/modec/entity/OrderLine.java +++ b/src/main/java/fr/arolla/modec/entity/OrderLine.java @@ -9,11 +9,11 @@ public class OrderLine { private Long id; @Embedded - Sku productSku; - String productName; + private Sku productSku; + private String productName; @Embedded - Quantity quantity; + private Quantity quantity; public OrderLine() { //for JPA } From e19c6c7bdb88b13d493caa2244ee7de295fbcab7 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:23:31 +0100 Subject: [PATCH 06/25] move ctor at head of class --- .../java/fr/arolla/modec/entity/Product.java | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/Product.java b/src/main/java/fr/arolla/modec/entity/Product.java index 873a2cb..0a67dd7 100644 --- a/src/main/java/fr/arolla/modec/entity/Product.java +++ b/src/main/java/fr/arolla/modec/entity/Product.java @@ -19,6 +19,16 @@ public class Product { @Embedded private Weight weight; + public Product() { //for JPA + } + + public Product(Sku sku, String name, String description, Weight weight) { + this.sku = sku; + this.name = name; + this.description = description; + this.weight = weight; + } + public Sku getSku() { return sku; } @@ -35,13 +45,4 @@ public Weight getWeight() { return weight; } - public Product() { //for JPA - } - - public Product(Sku sku, String name, String description, Weight weight) { - this.sku = sku; - this.name = name; - this.description = description; - this.weight = weight; - } } From 5ef7568f0ca3ddc025e4c6c56fdc4bb973319d25 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:24:06 +0100 Subject: [PATCH 07/25] reorder field then ctor then methods --- src/main/java/fr/arolla/modec/entity/Quantity.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/Quantity.java b/src/main/java/fr/arolla/modec/entity/Quantity.java index 49cb70d..a1d722d 100644 --- a/src/main/java/fr/arolla/modec/entity/Quantity.java +++ b/src/main/java/fr/arolla/modec/entity/Quantity.java @@ -4,11 +4,7 @@ @Embeddable public class Quantity { - long quantity; - - public long getQuantity() { - return quantity; - } + private long quantity; public Quantity() { //for JPA } @@ -18,6 +14,10 @@ public Quantity(long quantity) { this.quantity = quantity; } + public long getQuantity() { + return quantity; + } + @Override public String toString() { return Long.toString(quantity); From b4aff731ef354fe6bcea9b7e03e030e10e7d21fc Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:24:27 +0100 Subject: [PATCH 08/25] no getter ? --- src/main/java/fr/arolla/modec/entity/Recipient.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/main/java/fr/arolla/modec/entity/Recipient.java b/src/main/java/fr/arolla/modec/entity/Recipient.java index 05cdafb..c34d626 100644 --- a/src/main/java/fr/arolla/modec/entity/Recipient.java +++ b/src/main/java/fr/arolla/modec/entity/Recipient.java @@ -14,4 +14,12 @@ public Recipient(String recipientFullName, String email) { this.recipientFullName = recipientFullName; this.email = email; } + + public String getRecipientFullName() { + return recipientFullName; + } + + public String getEmail() { + return email; + } } From 99da19fbd9825cff5ea7ec6bd9771e12dac70615 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:24:55 +0100 Subject: [PATCH 09/25] reorder ctor --- src/main/java/fr/arolla/modec/entity/ShippingAddress.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/ShippingAddress.java b/src/main/java/fr/arolla/modec/entity/ShippingAddress.java index 41991b4..8eb59f2 100644 --- a/src/main/java/fr/arolla/modec/entity/ShippingAddress.java +++ b/src/main/java/fr/arolla/modec/entity/ShippingAddress.java @@ -13,6 +13,9 @@ public class ShippingAddress implements Serializable { private String zipCode; private String isoCountryCode; + public ShippingAddress() {//for JPA + } + public ShippingAddress(String fullName, String line1, String city, String zipCode, String isoCountryCode) { this.fullName = fullName; this.line1 = line1; @@ -21,9 +24,6 @@ public ShippingAddress(String fullName, String line1, String city, String zipCod this.isoCountryCode = isoCountryCode; } - public ShippingAddress() {//for JPA - } - public String getFullName() { return fullName; } @@ -58,7 +58,6 @@ public boolean equals(Object o) { @Override public int hashCode() { - return Objects.hash(fullName, line1, city, zipCode, isoCountryCode); } } From a00da2c6f5935494720514fe166730308b01b559 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:25:25 +0100 Subject: [PATCH 10/25] lightweight toString --- src/main/java/fr/arolla/modec/entity/Sku.java | 8 +++----- src/main/java/fr/arolla/modec/entity/Weight.java | 4 +--- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/Sku.java b/src/main/java/fr/arolla/modec/entity/Sku.java index 07c1228..5169e9c 100644 --- a/src/main/java/fr/arolla/modec/entity/Sku.java +++ b/src/main/java/fr/arolla/modec/entity/Sku.java @@ -20,17 +20,15 @@ public String getSku() { @Override public String toString() { - return "Sku{" + - "sku='" + sku + '\'' + - '}'; + return "Sku{'" + sku + '\'' + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Sku)) return false; - Sku sku1 = (Sku) o; - return Objects.equals(sku, sku1.sku); + Sku oSku = (Sku) o; + return Objects.equals(this.sku, oSku.sku); } @Override diff --git a/src/main/java/fr/arolla/modec/entity/Weight.java b/src/main/java/fr/arolla/modec/entity/Weight.java index fffcbc4..06f87be 100644 --- a/src/main/java/fr/arolla/modec/entity/Weight.java +++ b/src/main/java/fr/arolla/modec/entity/Weight.java @@ -19,8 +19,6 @@ public double getWeight() { @Override public String toString() { - return "Weight{" + - "weight=" + weight + - '}'; + return "Weight{" + weight + '}'; } } From 1ecd9c2442d17efd0b7fd56f9b7676f413a76400 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:25:54 +0100 Subject: [PATCH 11/25] should rely on java's Clock directly --- .../arolla/modec/service/system/Timestamp.java | 7 ------- .../service/system/impl/TimestampSystem.java | 16 ---------------- 2 files changed, 23 deletions(-) delete mode 100644 src/main/java/fr/arolla/modec/service/system/Timestamp.java delete mode 100644 src/main/java/fr/arolla/modec/service/system/impl/TimestampSystem.java diff --git a/src/main/java/fr/arolla/modec/service/system/Timestamp.java b/src/main/java/fr/arolla/modec/service/system/Timestamp.java deleted file mode 100644 index 17cf7ad..0000000 --- a/src/main/java/fr/arolla/modec/service/system/Timestamp.java +++ /dev/null @@ -1,7 +0,0 @@ -package fr.arolla.modec.service.system; - -import java.util.Calendar; - -public interface Timestamp { - Calendar getCurrentDate(); -} diff --git a/src/main/java/fr/arolla/modec/service/system/impl/TimestampSystem.java b/src/main/java/fr/arolla/modec/service/system/impl/TimestampSystem.java deleted file mode 100644 index be379a5..0000000 --- a/src/main/java/fr/arolla/modec/service/system/impl/TimestampSystem.java +++ /dev/null @@ -1,16 +0,0 @@ -package fr.arolla.modec.service.system.impl; - -import fr.arolla.modec.service.system.Timestamp; -import org.springframework.stereotype.Service; - -import java.util.Calendar; -import java.util.GregorianCalendar; - -@Service -public class TimestampSystem implements Timestamp { - - @Override - public Calendar getCurrentDate() { - return new GregorianCalendar(); - } -} From e9060af1e61e240acbed8f2126cf7abcac084074 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:36:50 +0100 Subject: [PATCH 12/25] should rely on java's Clock directly and Instant --- src/main/java/fr/arolla/modec/entity/Order.java | 9 ++++----- src/main/java/fr/arolla/modec/service/OrderService.java | 9 +++++---- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/java/fr/arolla/modec/entity/Order.java b/src/main/java/fr/arolla/modec/entity/Order.java index 7495652..a3f7515 100644 --- a/src/main/java/fr/arolla/modec/entity/Order.java +++ b/src/main/java/fr/arolla/modec/entity/Order.java @@ -1,8 +1,7 @@ package fr.arolla.modec.entity; import javax.persistence.*; -import java.util.Calendar; -import java.util.Date; +import java.time.Instant; import java.util.List; @Entity @@ -19,7 +18,7 @@ public class Order { private Status status; - private Date creationDate; + private Instant creationDate; @Embedded private ShippingAddress shippingAddress; @@ -30,7 +29,7 @@ public class Order { public Order() { // for JPA } - public Order(List lines, Date creationDate, Recipient recipient, ShippingAddress shippingAddress) { + public Order(List lines, Instant creationDate, Recipient recipient, ShippingAddress shippingAddress) { this.lines = lines; this.creationDate = creationDate; this.recipient = recipient; @@ -57,7 +56,7 @@ public void setStatus(Status status) { this.status = status; } - public Date getCreationDate() { + public Instant getCreationDate() { return creationDate; } diff --git a/src/main/java/fr/arolla/modec/service/OrderService.java b/src/main/java/fr/arolla/modec/service/OrderService.java index 8c60ac1..1ff1c9b 100644 --- a/src/main/java/fr/arolla/modec/service/OrderService.java +++ b/src/main/java/fr/arolla/modec/service/OrderService.java @@ -7,19 +7,20 @@ import fr.arolla.modec.repository.OrderRepository; import fr.arolla.modec.service.system.Timestamp; +import java.time.Clock; import java.util.List; import java.util.stream.Collectors; public class OrderService { private final CartRepository cartRepository; - private final Timestamp timestamp; + private final Clock clock; private final OrderRepository orderRepository; private final OrderLineRepository orderLineRepository; - public OrderService(CartRepository cartRepository, Timestamp timestamp, OrderRepository orderRepository, OrderLineRepository orderLineRepository) { + public OrderService(CartRepository cartRepository, Clock clock, OrderRepository orderRepository, OrderLineRepository orderLineRepository) { this.cartRepository = cartRepository; - this.timestamp = timestamp; + this.clock = clock; this.orderRepository = orderRepository; this.orderLineRepository = orderLineRepository; } @@ -31,7 +32,7 @@ public OrderId createOrderFromCart(CartId cartId) throws BusinessException { .stream() .map(cartLine -> orderLineRepository.save(new OrderLine(cartLine.getProductSku(), cartLine.getProductName(), cartLine.getQuantity()))) .collect(Collectors.toList()), - timestamp.getCurrentDate(), + clock.instant(), cart.getRecipient(), cart.getShippingAddress()); order.setStatus(Order.Status.CREATED); From f48c5ce744460879d6e3c03dfd89a6d6ddd4dbc8 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 20:37:34 +0100 Subject: [PATCH 13/25] should rely on java's Clock directly and Instant - remove unused import --- src/main/java/fr/arolla/modec/service/OrderService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/fr/arolla/modec/service/OrderService.java b/src/main/java/fr/arolla/modec/service/OrderService.java index 1ff1c9b..bf174e8 100644 --- a/src/main/java/fr/arolla/modec/service/OrderService.java +++ b/src/main/java/fr/arolla/modec/service/OrderService.java @@ -5,7 +5,6 @@ import fr.arolla.modec.repository.CartRepository; import fr.arolla.modec.repository.OrderLineRepository; import fr.arolla.modec.repository.OrderRepository; -import fr.arolla.modec.service.system.Timestamp; import java.time.Clock; import java.util.List; From 9d7eb3e134ce43c25d5d6c751ef2f63c3726be66 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:26:24 +0100 Subject: [PATCH 14/25] should rely on java's Clock directly and Instant --- .../modec/util/FixedButMutableClock.java | 65 +++++++++++++++++++ .../fr/arolla/modec/acceptance/StepDefs.java | 37 ++++++----- 2 files changed, 87 insertions(+), 15 deletions(-) create mode 100644 src/main/java/fr/arolla/modec/util/FixedButMutableClock.java diff --git a/src/main/java/fr/arolla/modec/util/FixedButMutableClock.java b/src/main/java/fr/arolla/modec/util/FixedButMutableClock.java new file mode 100644 index 0000000..2aad58e --- /dev/null +++ b/src/main/java/fr/arolla/modec/util/FixedButMutableClock.java @@ -0,0 +1,65 @@ +package fr.arolla.modec.util; + +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + +/** + * Implementation of a clock that always returns the same instant. + * This is typically used for testing. + */ +public class FixedButMutableClock extends Clock { + private Instant instant; + private ZoneId zone; + + public FixedButMutableClock(Instant fixedInstant, ZoneId zone) { + this.instant = fixedInstant; + this.zone = zone; + } + + public void setInstant(Instant instant) { + this.instant = instant; + } + + @Override + public ZoneId getZone() { + return zone; + } + + @Override + public Clock withZone(ZoneId zone) { + if (zone.equals(this.zone)) { // intentional NPE + return this; + } + return new FixedButMutableClock(instant, zone); + } + + @Override + public long millis() { + return instant.toEpochMilli(); + } + + @Override + public Instant instant() { + return instant; + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof FixedButMutableClock) { + FixedButMutableClock other = (FixedButMutableClock) obj; + return instant.equals(other.instant) && zone.equals(other.zone); + } + return false; + } + + @Override + public int hashCode() { + return instant.hashCode() ^ zone.hashCode(); + } + + @Override + public String toString() { + return "FixedMutableClock[" + instant + "," + zone + "]"; + } +} diff --git a/src/test/java/fr/arolla/modec/acceptance/StepDefs.java b/src/test/java/fr/arolla/modec/acceptance/StepDefs.java index ca636dd..26b50ab 100644 --- a/src/test/java/fr/arolla/modec/acceptance/StepDefs.java +++ b/src/test/java/fr/arolla/modec/acceptance/StepDefs.java @@ -5,23 +5,31 @@ import cucumber.api.java.en.Then; import fr.arolla.modec.BusinessException; import fr.arolla.modec.entity.*; -import fr.arolla.modec.repository.*; +import fr.arolla.modec.repository.CartLineRepository; +import fr.arolla.modec.repository.CartRepository; +import fr.arolla.modec.repository.OrderLineRepository; +import fr.arolla.modec.repository.OrderRepository; +import fr.arolla.modec.repository.ProductRepository; +import fr.arolla.modec.repository.ShippingServiceRepository; import fr.arolla.modec.service.CartService; import fr.arolla.modec.service.DeliveryService; import fr.arolla.modec.service.OrderService; import fr.arolla.modec.service.ProductService; -import fr.arolla.modec.service.system.Timestamp; +import fr.arolla.modec.util.FixedButMutableClock; import io.cucumber.datatable.DataTable; -import org.mockito.Mockito; import org.springframework.boot.test.context.TestConfiguration; import org.springframework.context.annotation.Bean; import org.springframework.transaction.annotation.Transactional; -import java.text.SimpleDateFormat; +import java.time.Clock; import java.time.Instant; +import java.time.ZoneId; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; @@ -32,7 +40,7 @@ public class StepDefs extends SpringBootBaseStepDefs { private ProductRepository productRepository; private ProductService productService; private CartService cartService; - private Timestamp timestamp; + private FixedButMutableClock clock; private ShippingServiceRepository shippingServiceRepository; private OrderService orderService; private DeliveryService deliveryService; @@ -40,13 +48,13 @@ public class StepDefs extends SpringBootBaseStepDefs { private OrderId currentOrderId; private DeliveryId currentDeliveryId; - public StepDefs(ProductRepository productRepository, Timestamp timestamp, ShippingServiceRepository shippingServiceRepository, CartRepository cartRepository, CartLineRepository cartLineRepository, OrderRepository orderRepository, OrderLineRepository orderLineRepository) { + public StepDefs(ProductRepository productRepository, FixedButMutableClock clock, ShippingServiceRepository shippingServiceRepository, CartRepository cartRepository, CartLineRepository cartLineRepository, OrderRepository orderRepository, OrderLineRepository orderLineRepository) { this.productRepository = productRepository; this.productService = new ProductService(productRepository); this.cartService = new CartService(cartRepository, productRepository, cartLineRepository, shippingServiceRepository); - this.timestamp = timestamp; + this.clock = clock; this.shippingServiceRepository = shippingServiceRepository; - this.orderService = new OrderService(cartRepository, timestamp, orderRepository, orderLineRepository); + this.orderService = new OrderService(cartRepository, clock, orderRepository, orderLineRepository); this.deliveryService = new DeliveryService(orderRepository); } @@ -54,16 +62,15 @@ public StepDefs(ProductRepository productRepository, Timestamp timestamp, Shippi static class TestContextConfiguration { @Bean - public Timestamp timestamp() { - return Mockito.mock(Timestamp.class); + public Clock clock() { + return new FixedButMutableClock(Instant.now(), ZoneId.systemDefault()); } } @Given("^now is \"([^\"]*)\"$") public void nowIs(String stringDate) throws Throwable { - Calendar now = new GregorianCalendar(); - now.setTime(Date.from(Instant.from(ZonedDateTime.parse(stringDate, DateTimeFormatter.ISO_OFFSET_DATE_TIME)))); - Mockito.when(timestamp.getCurrentDate()).thenReturn(now); + Instant instant = Instant.from(ZonedDateTime.parse(stringDate, DateTimeFormatter.ISO_OFFSET_DATE_TIME)); + clock.setInstant(instant); } @Given("^\"([^\"]*)\" as default locale$") @@ -174,7 +181,7 @@ public void theHistoricalOrdersForRecipientShouldBe(String eMail, DataTable orde for (Order order : orderService.getOrdersForEMail(eMail)) { Map orderMap = new HashMap<>(); - orderMap.put("creation date", new SimpleDateFormat("YYYY-MM-dd").format(order.getCreationDate().getTime())); + orderMap.put("creation date", DateTimeFormatter.ofPattern("YYYY-MM-dd").withZone(ZoneId.systemDefault()).format(order.getCreationDate())); orderMap.put("status", order.getStatus().toString()); actualList.add(orderMap); } From 9aa5d0d075342cb8b86a066eea5907c6019756a8 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:28:01 +0100 Subject: [PATCH 15/25] move feature to src/test/resources --- .../java/fr/arolla/modec/acceptance/AcceptanceTest.java | 6 +----- .../fr/arolla/modec/service/CartServiceFeaturedTest.java | 5 +---- .../fr/arolla/modec/acceptance/bordercase.feature | 0 .../fr/arolla/modec/acceptance/nominal.feature | 0 .../fr/arolla/modec/service/CartService.feature | 0 5 files changed, 2 insertions(+), 9 deletions(-) rename src/test/{java => resources}/fr/arolla/modec/acceptance/bordercase.feature (100%) rename src/test/{java => resources}/fr/arolla/modec/acceptance/nominal.feature (100%) rename src/test/{java => resources}/fr/arolla/modec/service/CartService.feature (100%) diff --git a/src/test/java/fr/arolla/modec/acceptance/AcceptanceTest.java b/src/test/java/fr/arolla/modec/acceptance/AcceptanceTest.java index 7c93ae7..9c1edb4 100644 --- a/src/test/java/fr/arolla/modec/acceptance/AcceptanceTest.java +++ b/src/test/java/fr/arolla/modec/acceptance/AcceptanceTest.java @@ -5,10 +5,6 @@ import org.junit.runner.RunWith; @RunWith(Cucumber.class) -@CucumberOptions( - features = "src/test/java/fr/arolla/modec/acceptance" -) - +@CucumberOptions() public class AcceptanceTest { - } diff --git a/src/test/java/fr/arolla/modec/service/CartServiceFeaturedTest.java b/src/test/java/fr/arolla/modec/service/CartServiceFeaturedTest.java index 500e323..96c5d6f 100644 --- a/src/test/java/fr/arolla/modec/service/CartServiceFeaturedTest.java +++ b/src/test/java/fr/arolla/modec/service/CartServiceFeaturedTest.java @@ -5,10 +5,7 @@ import org.junit.runner.RunWith; @RunWith(Cucumber.class) -@CucumberOptions( - features = "src/test/java/fr/arolla/modec/service" -) - +@CucumberOptions() public class CartServiceFeaturedTest { } diff --git a/src/test/java/fr/arolla/modec/acceptance/bordercase.feature b/src/test/resources/fr/arolla/modec/acceptance/bordercase.feature similarity index 100% rename from src/test/java/fr/arolla/modec/acceptance/bordercase.feature rename to src/test/resources/fr/arolla/modec/acceptance/bordercase.feature diff --git a/src/test/java/fr/arolla/modec/acceptance/nominal.feature b/src/test/resources/fr/arolla/modec/acceptance/nominal.feature similarity index 100% rename from src/test/java/fr/arolla/modec/acceptance/nominal.feature rename to src/test/resources/fr/arolla/modec/acceptance/nominal.feature diff --git a/src/test/java/fr/arolla/modec/service/CartService.feature b/src/test/resources/fr/arolla/modec/service/CartService.feature similarity index 100% rename from src/test/java/fr/arolla/modec/service/CartService.feature rename to src/test/resources/fr/arolla/modec/service/CartService.feature From f2acec7f570c3ca7a49802906af210e0f899e36d Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:28:26 +0100 Subject: [PATCH 16/25] assert something --- src/test/java/fr/arolla/modec/entity/QuantityTest.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/test/java/fr/arolla/modec/entity/QuantityTest.java b/src/test/java/fr/arolla/modec/entity/QuantityTest.java index 776ca73..4540cdc 100644 --- a/src/test/java/fr/arolla/modec/entity/QuantityTest.java +++ b/src/test/java/fr/arolla/modec/entity/QuantityTest.java @@ -1,21 +1,24 @@ package fr.arolla.modec.entity; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; public class QuantityTest { @Test public void quantity_can_be_null() { Quantity quantity = new Quantity(0); + assertThat(quantity.getQuantity()).isEqualTo(0); } @Test public void quantity_can_be_positive() { Quantity quantity = new Quantity(1); + assertThat(quantity.getQuantity()).isEqualTo(1); } @Test(expected = IllegalArgumentException.class) public void quantity_cannot_be_negative() { - Quantity quantity = new Quantity(-1); + new Quantity(-1); } } From 32bca3ea2e3a17a1da886b0e6a18169dbbb8a7a9 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:36:09 +0100 Subject: [PATCH 17/25] move controller in dedicated package --- src/main/java/fr/arolla/modec/{ => web}/HttpController.java | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/fr/arolla/modec/{ => web}/HttpController.java (100%) diff --git a/src/main/java/fr/arolla/modec/HttpController.java b/src/main/java/fr/arolla/modec/web/HttpController.java similarity index 100% rename from src/main/java/fr/arolla/modec/HttpController.java rename to src/main/java/fr/arolla/modec/web/HttpController.java From cb474dd93d21aa6a83d0660e9da948bffddc8469 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:36:41 +0100 Subject: [PATCH 18/25] move controller in dedicated package --- src/main/java/fr/arolla/modec/web/HttpController.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/fr/arolla/modec/web/HttpController.java b/src/main/java/fr/arolla/modec/web/HttpController.java index fe7c0e2..e0a5b5e 100644 --- a/src/main/java/fr/arolla/modec/web/HttpController.java +++ b/src/main/java/fr/arolla/modec/web/HttpController.java @@ -1,4 +1,4 @@ -package fr.arolla.modec; +package fr.arolla.modec.web; import fr.arolla.modec.entity.Product; import fr.arolla.modec.repository.ProductRepository; From fca6b8f11839fcacccda1545a2a7c2105fb000df Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:37:09 +0100 Subject: [PATCH 19/25] get without check --- .../arolla/modec/service/CartNotFoundException.java | 11 +++++++++++ .../java/fr/arolla/modec/service/CartService.java | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/main/java/fr/arolla/modec/service/CartNotFoundException.java diff --git a/src/main/java/fr/arolla/modec/service/CartNotFoundException.java b/src/main/java/fr/arolla/modec/service/CartNotFoundException.java new file mode 100644 index 0000000..565b241 --- /dev/null +++ b/src/main/java/fr/arolla/modec/service/CartNotFoundException.java @@ -0,0 +1,11 @@ +package fr.arolla.modec.service; + +import fr.arolla.modec.entity.CartId; + +/** + */ +public class CartNotFoundException extends RuntimeException { + public CartNotFoundException(CartId cartId) { + super("cartId: " + cartId.getId()); + } +} diff --git a/src/main/java/fr/arolla/modec/service/CartService.java b/src/main/java/fr/arolla/modec/service/CartService.java index bff2158..4126bb0 100644 --- a/src/main/java/fr/arolla/modec/service/CartService.java +++ b/src/main/java/fr/arolla/modec/service/CartService.java @@ -31,7 +31,7 @@ public void addToCart(CartId cartId, Sku sku, Quantity quantity) { Product product = productRepository.findOneBySku(sku); CartLine line = new CartLine(sku, product.getName(), quantity); cartLineRepository.save(line); - cartRepository.findById(cartId).get().getLines().add(line); + cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)).getLines().add(line); } public List getLines(CartId cartId) { From 9752b96ac913e3bfb20974929caca70c000da73e Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:38:09 +0100 Subject: [PATCH 20/25] get without check --- src/main/java/fr/arolla/modec/service/CartService.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/fr/arolla/modec/service/CartService.java b/src/main/java/fr/arolla/modec/service/CartService.java index 4126bb0..d39bcbf 100644 --- a/src/main/java/fr/arolla/modec/service/CartService.java +++ b/src/main/java/fr/arolla/modec/service/CartService.java @@ -35,17 +35,17 @@ public void addToCart(CartId cartId, Sku sku, Quantity quantity) { } public List getLines(CartId cartId) { - return cartRepository.findById(cartId).get().getLines(); + return cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)).getLines(); } public void setShippingAddress(CartId cartId, String fullName, String line1, String city, String zipCode, String isoCountryCode) { ShippingAddress address = new ShippingAddress(fullName, line1, city, zipCode, isoCountryCode); - cartRepository.findById(cartId).get().setShippingAddress(address); + cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)).setShippingAddress(address); } public List getShippingServices(CartId cartId) { List servicesFound = new ArrayList<>(); - Cart cart = cartRepository.findById(cartId).get(); + Cart cart = cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)); if (cart.getShippingAddress() != null && !cart.getLines().isEmpty()) { Sku firstProductSku = cart.getLines().get(0).getProductSku(); Product firstProduct = productRepository.findOneBySku(firstProductSku); @@ -61,6 +61,6 @@ public List getShippingServices(CartId cartId) { public void setRecipient(CartId cartId, String fullName, String eMail) { Recipient recipient = new Recipient(fullName, eMail); - cartRepository.findById(cartId).get().setRecipient(recipient); + cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)).setRecipient(recipient); } } From 688722046ad5cbc6d87a8a1efada123640091681 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:41:33 +0100 Subject: [PATCH 21/25] findOrFail --- .../java/fr/arolla/modec/service/CartService.java | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/fr/arolla/modec/service/CartService.java b/src/main/java/fr/arolla/modec/service/CartService.java index d39bcbf..0758033 100644 --- a/src/main/java/fr/arolla/modec/service/CartService.java +++ b/src/main/java/fr/arolla/modec/service/CartService.java @@ -31,21 +31,21 @@ public void addToCart(CartId cartId, Sku sku, Quantity quantity) { Product product = productRepository.findOneBySku(sku); CartLine line = new CartLine(sku, product.getName(), quantity); cartLineRepository.save(line); - cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)).getLines().add(line); + findOrFail(cartId).getLines().add(line); } public List getLines(CartId cartId) { - return cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)).getLines(); + return findOrFail(cartId).getLines(); } public void setShippingAddress(CartId cartId, String fullName, String line1, String city, String zipCode, String isoCountryCode) { ShippingAddress address = new ShippingAddress(fullName, line1, city, zipCode, isoCountryCode); - cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)).setShippingAddress(address); + findOrFail(cartId).setShippingAddress(address); } public List getShippingServices(CartId cartId) { List servicesFound = new ArrayList<>(); - Cart cart = cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)); + Cart cart = findOrFail(cartId); if (cart.getShippingAddress() != null && !cart.getLines().isEmpty()) { Sku firstProductSku = cart.getLines().get(0).getProductSku(); Product firstProduct = productRepository.findOneBySku(firstProductSku); @@ -61,6 +61,10 @@ public List getShippingServices(CartId cartId) { public void setRecipient(CartId cartId, String fullName, String eMail) { Recipient recipient = new Recipient(fullName, eMail); - cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)).setRecipient(recipient); + findOrFail(cartId).setRecipient(recipient); + } + + private Cart findOrFail(CartId cartId) { + return cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)); } } From 44d7b8fe7cfbeb315c5a5cb0be0b523af40f56af Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:47:52 +0100 Subject: [PATCH 22/25] extract constants : fix incoherence --- .../fr/arolla/modec/service/CartServiceTest.java | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/test/java/fr/arolla/modec/service/CartServiceTest.java b/src/test/java/fr/arolla/modec/service/CartServiceTest.java index a218087..48b67a9 100644 --- a/src/test/java/fr/arolla/modec/service/CartServiceTest.java +++ b/src/test/java/fr/arolla/modec/service/CartServiceTest.java @@ -18,6 +18,9 @@ @RunWith(MockitoJUnitRunner.class) public class CartServiceTest { + private static final Sku SKU_1 = new Sku("sku1"); + private static final Sku SKU_2 = new Sku("sku2"); + @Mock private CartRepository cartRepository; @Mock @@ -34,8 +37,8 @@ public void setUp() throws Exception { Mockito.when(cartRepository.findById(cartId)).thenReturn(Optional.of(cart)); Mockito.when(shippingServiceRepository.findOneByCode("Chrono10")).thenReturn(new ShippingService("Chrono10", "Chronopost", "level")); Mockito.when(shippingServiceRepository.findOneByCode("laposte")).thenReturn(new ShippingService("laposte", "La Poste", "level")); - Mockito.when(productRepository.findOneBySku(new Sku("sku1"))).thenReturn(new Product(new Sku("sku"), "Heavy","A heavy product", new Weight(10))); - Mockito.when(productRepository.findOneBySku(new Sku("sku2"))).thenReturn(new Product(new Sku("sku"), "Light","A light product", new Weight(0.5))); + Mockito.when(productRepository.findOneBySku(SKU_1)).thenReturn(new Product(SKU_1, "Heavy","A heavy product", new Weight(10))); + Mockito.when(productRepository.findOneBySku(SKU_2)).thenReturn(new Product(SKU_2, "Light","A light product", new Weight(0.5))); cartService = new CartService(cartRepository, productRepository, null, shippingServiceRepository); } @@ -46,7 +49,7 @@ public void emptyCartShouldHaveNoShippingService() { @Test public void FilledCartWithNoAddressShouldHaveNoShippingService() { - CartLine line = new CartLine(new Sku("sku1"), "name", new Quantity(1)); + CartLine line = new CartLine(SKU_1, "name", new Quantity(1)); cart.getLines().add(line); assertThat(cartService.getShippingServices(cartId)).isEmpty(); } @@ -59,7 +62,7 @@ public void emptyCartWithShippingShouldHaveNoShippingService() { @Test public void FilledCartWithShippingShouldHaveAShippingService() { - CartLine line = new CartLine(new Sku("sku1"), "name", new Quantity(1)); + CartLine line = new CartLine(SKU_1, "name", new Quantity(1)); cart.getLines().add(line); cart.setShippingAddress(new ShippingAddress("fullName", "line1", "city", "zipCode", "isoCountryCode")); assertThat(cartService.getShippingServices(cartId).size()).isEqualTo(1); @@ -68,7 +71,7 @@ public void FilledCartWithShippingShouldHaveAShippingService() { @Test public void LightCartShouldHaveLaPosteShippingService() { - CartLine line = new CartLine(new Sku("sku2"), "name", new Quantity(1)); + CartLine line = new CartLine(SKU_2, "name", new Quantity(1)); cart.getLines().add(line); cart.setShippingAddress(new ShippingAddress("fullName", "line1", "city", "zipCode", "isoCountryCode")); assertThat(cartService.getShippingServices(cartId).size()).isEqualTo(1); From a64a9dae9966b5d91f6f38a46cc644916c500e5e Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 22:48:36 +0100 Subject: [PATCH 23/25] Parameter Object --- src/main/java/fr/arolla/modec/service/CartService.java | 8 +++----- src/test/java/fr/arolla/modec/acceptance/StepDefs.java | 6 ++++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/fr/arolla/modec/service/CartService.java b/src/main/java/fr/arolla/modec/service/CartService.java index 0758033..245050e 100644 --- a/src/main/java/fr/arolla/modec/service/CartService.java +++ b/src/main/java/fr/arolla/modec/service/CartService.java @@ -38,9 +38,8 @@ public List getLines(CartId cartId) { return findOrFail(cartId).getLines(); } - public void setShippingAddress(CartId cartId, String fullName, String line1, String city, String zipCode, String isoCountryCode) { - ShippingAddress address = new ShippingAddress(fullName, line1, city, zipCode, isoCountryCode); - findOrFail(cartId).setShippingAddress(address); + public void setShippingAddress(CartId cartId, ShippingAddress shippingAddress) { + findOrFail(cartId).setShippingAddress(shippingAddress); } public List getShippingServices(CartId cartId) { @@ -59,8 +58,7 @@ public List getShippingServices(CartId cartId) { return servicesFound; } - public void setRecipient(CartId cartId, String fullName, String eMail) { - Recipient recipient = new Recipient(fullName, eMail); + public void setRecipient(CartId cartId, Recipient recipient) { findOrFail(cartId).setRecipient(recipient); } diff --git a/src/test/java/fr/arolla/modec/acceptance/StepDefs.java b/src/test/java/fr/arolla/modec/acceptance/StepDefs.java index 26b50ab..90bc2d8 100644 --- a/src/test/java/fr/arolla/modec/acceptance/StepDefs.java +++ b/src/test/java/fr/arolla/modec/acceptance/StepDefs.java @@ -110,7 +110,8 @@ public void productIsAddedToThisCart(String sku) throws Throwable { @Transactional @Given("^\"([^\"]*)\", \"([^\"]*)\", \"([^\"]*)\", \"([^\"]*)\" in \"([^\"]*)\" is set as the shipping address of this cart$") public void inIsSetAsTheShippingAddressOfThisCart(String fullName, String line1, String city, String zipCode, String isoCountryCode) throws Throwable { - cartService.setShippingAddress(this.currentCartId, fullName, line1, city, zipCode, isoCountryCode); + ShippingAddress shippingAddress = new ShippingAddress(fullName, line1, city, zipCode, isoCountryCode); + cartService.setShippingAddress(this.currentCartId, shippingAddress); } @Transactional @@ -159,7 +160,8 @@ public void theShippingServicesAvailableForThisCartShouldBe(DataTable shippingSe @Transactional @And("^\"([^\"]*)\" with email address \"([^\"]*)\" is set as the recipient$") public void withEmailAdressIsSetAsTheRecipient(String fullName, String eMail) throws Throwable { - cartService.setRecipient(currentCartId, fullName, eMail); + Recipient recipient = new Recipient(fullName, eMail); + cartService.setRecipient(currentCartId, recipient); } @Transactional From 1b3d8bf823006e5c0f75a833dc8d2a54baa4c79d Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 23:14:20 +0100 Subject: [PATCH 24/25] exception in dedicated package, erf... --- .../modec/{ => exception}/BusinessException.java | 2 +- .../{service => exception}/CartNotFoundException.java | 2 +- .../modec/exception/OrderNotFoundException.java | 11 +++++++++++ 3 files changed, 13 insertions(+), 2 deletions(-) rename src/main/java/fr/arolla/modec/{ => exception}/BusinessException.java (93%) rename src/main/java/fr/arolla/modec/{service => exception}/CartNotFoundException.java (85%) create mode 100644 src/main/java/fr/arolla/modec/exception/OrderNotFoundException.java diff --git a/src/main/java/fr/arolla/modec/BusinessException.java b/src/main/java/fr/arolla/modec/exception/BusinessException.java similarity index 93% rename from src/main/java/fr/arolla/modec/BusinessException.java rename to src/main/java/fr/arolla/modec/exception/BusinessException.java index 7df3540..3526297 100644 --- a/src/main/java/fr/arolla/modec/BusinessException.java +++ b/src/main/java/fr/arolla/modec/exception/BusinessException.java @@ -1,4 +1,4 @@ -package fr.arolla.modec; +package fr.arolla.modec.exception; public class BusinessException extends Exception { public BusinessException() { diff --git a/src/main/java/fr/arolla/modec/service/CartNotFoundException.java b/src/main/java/fr/arolla/modec/exception/CartNotFoundException.java similarity index 85% rename from src/main/java/fr/arolla/modec/service/CartNotFoundException.java rename to src/main/java/fr/arolla/modec/exception/CartNotFoundException.java index 565b241..894b49c 100644 --- a/src/main/java/fr/arolla/modec/service/CartNotFoundException.java +++ b/src/main/java/fr/arolla/modec/exception/CartNotFoundException.java @@ -1,4 +1,4 @@ -package fr.arolla.modec.service; +package fr.arolla.modec.exception; import fr.arolla.modec.entity.CartId; diff --git a/src/main/java/fr/arolla/modec/exception/OrderNotFoundException.java b/src/main/java/fr/arolla/modec/exception/OrderNotFoundException.java new file mode 100644 index 0000000..3716cd7 --- /dev/null +++ b/src/main/java/fr/arolla/modec/exception/OrderNotFoundException.java @@ -0,0 +1,11 @@ +package fr.arolla.modec.exception; + +import fr.arolla.modec.entity.OrderId; + +/** + */ +public class OrderNotFoundException extends RuntimeException { + public OrderNotFoundException(OrderId orderId) { + super("orderId: " + orderId.getId()); + } +} From 27982f91cf4b6951b722573d58dca53ce544d6a9 Mon Sep 17 00:00:00 2001 From: Arnauld Date: Thu, 28 Mar 2019 23:15:51 +0100 Subject: [PATCH 25/25] move transactional to service, in absence of usecase/controller services have to handle the transaction management + hack for lazy issue while traversing list on cart --- .../fr/arolla/modec/service/CartService.java | 13 +++++++- .../arolla/modec/service/DeliveryService.java | 7 +++- .../fr/arolla/modec/service/OrderService.java | 10 ++++-- .../arolla/modec/service/ProductService.java | 4 +++ .../modec/service/TimeConfiguration.java | 14 ++++++++ .../fr/arolla/modec/web/HttpController.java | 5 ++- .../acceptance/SpringBootBaseStepDefs.java | 9 +++++- .../fr/arolla/modec/acceptance/StepDefs.java | 32 +++++++------------ 8 files changed, 66 insertions(+), 28 deletions(-) create mode 100644 src/main/java/fr/arolla/modec/service/TimeConfiguration.java diff --git a/src/main/java/fr/arolla/modec/service/CartService.java b/src/main/java/fr/arolla/modec/service/CartService.java index 245050e..4052035 100644 --- a/src/main/java/fr/arolla/modec/service/CartService.java +++ b/src/main/java/fr/arolla/modec/service/CartService.java @@ -1,14 +1,18 @@ package fr.arolla.modec.service; import fr.arolla.modec.entity.*; +import fr.arolla.modec.exception.CartNotFoundException; import fr.arolla.modec.repository.CartLineRepository; import fr.arolla.modec.repository.CartRepository; import fr.arolla.modec.repository.ProductRepository; import fr.arolla.modec.repository.ShippingServiceRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.ArrayList; import java.util.List; +@Service public class CartService { private final CartRepository cartRepository; @@ -23,10 +27,12 @@ public CartService(CartRepository cartRepository, ProductRepository productRepos this.shippingServiceRepository = shippingServiceRepository; } + @Transactional public CartId createCart() { return cartRepository.save(new Cart()).getId(); } + @Transactional public void addToCart(CartId cartId, Sku sku, Quantity quantity) { Product product = productRepository.findOneBySku(sku); CartLine line = new CartLine(sku, product.getName(), quantity); @@ -34,14 +40,18 @@ public void addToCart(CartId cartId, Sku sku, Quantity quantity) { findOrFail(cartId).getLines().add(line); } + @Transactional public List getLines(CartId cartId) { - return findOrFail(cartId).getLines(); + // return a copy to load content + return new ArrayList<>(findOrFail(cartId).getLines()); } + @Transactional public void setShippingAddress(CartId cartId, ShippingAddress shippingAddress) { findOrFail(cartId).setShippingAddress(shippingAddress); } + @Transactional public List getShippingServices(CartId cartId) { List servicesFound = new ArrayList<>(); Cart cart = findOrFail(cartId); @@ -58,6 +68,7 @@ public List getShippingServices(CartId cartId) { return servicesFound; } + @Transactional public void setRecipient(CartId cartId, Recipient recipient) { findOrFail(cartId).setRecipient(recipient); } diff --git a/src/main/java/fr/arolla/modec/service/DeliveryService.java b/src/main/java/fr/arolla/modec/service/DeliveryService.java index b71b4eb..d6d5502 100644 --- a/src/main/java/fr/arolla/modec/service/DeliveryService.java +++ b/src/main/java/fr/arolla/modec/service/DeliveryService.java @@ -3,8 +3,12 @@ import fr.arolla.modec.entity.DeliveryId; import fr.arolla.modec.entity.Order; import fr.arolla.modec.entity.OrderId; +import fr.arolla.modec.exception.OrderNotFoundException; import fr.arolla.modec.repository.OrderRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +@Service public class DeliveryService { private final OrderRepository orderRepository; @@ -13,8 +17,9 @@ public DeliveryService(OrderRepository orderRepository) { this.orderRepository = orderRepository; } + @Transactional public DeliveryId createDeliveryFromOrder(OrderId orderId) { - orderRepository.findById(orderId).get().setStatus(Order.Status.IN_PREPARATION); + orderRepository.findById(orderId).orElseThrow(() -> new OrderNotFoundException(orderId)).setStatus(Order.Status.IN_PREPARATION); return new DeliveryId(orderId.getId()); } } diff --git a/src/main/java/fr/arolla/modec/service/OrderService.java b/src/main/java/fr/arolla/modec/service/OrderService.java index bf174e8..6dd8c4c 100644 --- a/src/main/java/fr/arolla/modec/service/OrderService.java +++ b/src/main/java/fr/arolla/modec/service/OrderService.java @@ -1,15 +1,19 @@ package fr.arolla.modec.service; -import fr.arolla.modec.BusinessException; +import fr.arolla.modec.exception.BusinessException; import fr.arolla.modec.entity.*; +import fr.arolla.modec.exception.CartNotFoundException; import fr.arolla.modec.repository.CartRepository; import fr.arolla.modec.repository.OrderLineRepository; import fr.arolla.modec.repository.OrderRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.time.Clock; import java.util.List; import java.util.stream.Collectors; +@Service public class OrderService { private final CartRepository cartRepository; @@ -24,8 +28,9 @@ public OrderService(CartRepository cartRepository, Clock clock, OrderRepository this.orderLineRepository = orderLineRepository; } + @Transactional public OrderId createOrderFromCart(CartId cartId) throws BusinessException { - Cart cart = cartRepository.findById(cartId).get(); + Cart cart = cartRepository.findById(cartId).orElseThrow(() -> new CartNotFoundException(cartId)); checkCartForOrder(cart); Order order = new Order(cart.getLines() .stream() @@ -45,6 +50,7 @@ private void checkCartForOrder(Cart cart) throws BusinessException { } } + @Transactional public List getOrdersForEMail(String eMail) { return orderRepository.findByRecipientEmail(eMail); } diff --git a/src/main/java/fr/arolla/modec/service/ProductService.java b/src/main/java/fr/arolla/modec/service/ProductService.java index f9467b9..1268718 100644 --- a/src/main/java/fr/arolla/modec/service/ProductService.java +++ b/src/main/java/fr/arolla/modec/service/ProductService.java @@ -2,7 +2,10 @@ import fr.arolla.modec.entity.Product; import fr.arolla.modec.repository.ProductRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +@Service public class ProductService { private final ProductRepository productRepository; @@ -11,6 +14,7 @@ public ProductService(ProductRepository productRepository) { this.productRepository = productRepository; } + @Transactional public Iterable getList() { return productRepository.findAll(); } diff --git a/src/main/java/fr/arolla/modec/service/TimeConfiguration.java b/src/main/java/fr/arolla/modec/service/TimeConfiguration.java new file mode 100644 index 0000000..0acf25b --- /dev/null +++ b/src/main/java/fr/arolla/modec/service/TimeConfiguration.java @@ -0,0 +1,14 @@ +package fr.arolla.modec.service; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.Clock; + +@Configuration +public class TimeConfiguration { + @Bean + public Clock clock() { + return Clock.systemDefaultZone(); + } +} diff --git a/src/main/java/fr/arolla/modec/web/HttpController.java b/src/main/java/fr/arolla/modec/web/HttpController.java index e0a5b5e..d7d7926 100644 --- a/src/main/java/fr/arolla/modec/web/HttpController.java +++ b/src/main/java/fr/arolla/modec/web/HttpController.java @@ -1,7 +1,6 @@ package fr.arolla.modec.web; import fr.arolla.modec.entity.Product; -import fr.arolla.modec.repository.ProductRepository; import fr.arolla.modec.service.ProductService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; @@ -14,8 +13,8 @@ public class HttpController { private final ProductService product; @Autowired - public HttpController(ProductRepository productRepository) { - this.product = new ProductService(productRepository); + public HttpController(ProductService product) { + this.product = product; } @RequestMapping(value = "/product", method = RequestMethod.GET) diff --git a/src/test/java/fr/arolla/modec/acceptance/SpringBootBaseStepDefs.java b/src/test/java/fr/arolla/modec/acceptance/SpringBootBaseStepDefs.java index 0fdfd77..7806c33 100644 --- a/src/test/java/fr/arolla/modec/acceptance/SpringBootBaseStepDefs.java +++ b/src/test/java/fr/arolla/modec/acceptance/SpringBootBaseStepDefs.java @@ -1,11 +1,18 @@ package fr.arolla.modec.acceptance; +import fr.arolla.modec.util.FixedButMutableClock; import org.junit.runner.RunWith; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.TestConfiguration; +import org.springframework.context.annotation.Bean; import org.springframework.test.context.junit4.SpringRunner; +import java.time.Clock; +import java.time.Instant; +import java.time.ZoneId; + @RunWith(SpringRunner.class) -@SpringBootTest() +@SpringBootTest(properties = {"spring.main.allow-bean-definition-overriding=true"}) public class SpringBootBaseStepDefs { } diff --git a/src/test/java/fr/arolla/modec/acceptance/StepDefs.java b/src/test/java/fr/arolla/modec/acceptance/StepDefs.java index 90bc2d8..8c4430c 100644 --- a/src/test/java/fr/arolla/modec/acceptance/StepDefs.java +++ b/src/test/java/fr/arolla/modec/acceptance/StepDefs.java @@ -3,12 +3,8 @@ import cucumber.api.java.en.And; import cucumber.api.java.en.Given; import cucumber.api.java.en.Then; -import fr.arolla.modec.BusinessException; import fr.arolla.modec.entity.*; -import fr.arolla.modec.repository.CartLineRepository; -import fr.arolla.modec.repository.CartRepository; -import fr.arolla.modec.repository.OrderLineRepository; -import fr.arolla.modec.repository.OrderRepository; +import fr.arolla.modec.exception.BusinessException; import fr.arolla.modec.repository.ProductRepository; import fr.arolla.modec.repository.ShippingServiceRepository; import fr.arolla.modec.service.CartService; @@ -48,14 +44,20 @@ public class StepDefs extends SpringBootBaseStepDefs { private OrderId currentOrderId; private DeliveryId currentDeliveryId; - public StepDefs(ProductRepository productRepository, FixedButMutableClock clock, ShippingServiceRepository shippingServiceRepository, CartRepository cartRepository, CartLineRepository cartLineRepository, OrderRepository orderRepository, OrderLineRepository orderLineRepository) { + public StepDefs(ProductRepository productRepository, + ProductService productService, + FixedButMutableClock clock, + ShippingServiceRepository shippingServiceRepository, + CartService cartService, + OrderService orderService, + DeliveryService deliveryService) { this.productRepository = productRepository; - this.productService = new ProductService(productRepository); - this.cartService = new CartService(cartRepository, productRepository, cartLineRepository, shippingServiceRepository); + this.productService = productService; + this.cartService = cartService; this.clock = clock; this.shippingServiceRepository = shippingServiceRepository; - this.orderService = new OrderService(cartRepository, clock, orderRepository, orderLineRepository); - this.deliveryService = new DeliveryService(orderRepository); + this.orderService = orderService; + this.deliveryService = deliveryService; } @TestConfiguration @@ -101,20 +103,17 @@ public void aNewCartIsCreated() throws Throwable { this.currentCartId = cartService.createCart(); } - @Transactional @Given("^product \"([^\"]*)\" is added to this cart$") public void productIsAddedToThisCart(String sku) throws Throwable { cartService.addToCart(this.currentCartId, new Sku(sku), new Quantity(1)); } - @Transactional @Given("^\"([^\"]*)\", \"([^\"]*)\", \"([^\"]*)\", \"([^\"]*)\" in \"([^\"]*)\" is set as the shipping address of this cart$") public void inIsSetAsTheShippingAddressOfThisCart(String fullName, String line1, String city, String zipCode, String isoCountryCode) throws Throwable { ShippingAddress shippingAddress = new ShippingAddress(fullName, line1, city, zipCode, isoCountryCode); cartService.setShippingAddress(this.currentCartId, shippingAddress); } - @Transactional @Then("^product catalog should contain:$") public void productCatalogShouldContain(DataTable products) throws Throwable { List> actualList = new ArrayList<>(); @@ -128,7 +127,6 @@ public void productCatalogShouldContain(DataTable products) throws Throwable { assertThat(actualList).isEqualTo(products.asMaps()); } - @Transactional @Then("^cart content should contain:$") public void cartContentShouldContain(DataTable cartLines) throws Throwable { List> actualList = new ArrayList<>(); @@ -143,7 +141,6 @@ public void cartContentShouldContain(DataTable cartLines) throws Throwable { assertThat(actualList).isEqualTo(cartLines.asMaps()); } - @Transactional @Then("^the shipping services available for this cart should be:$") public void theShippingServicesAvailableForThisCartShouldBe(DataTable shippingServices) throws Throwable { List> actualList = new ArrayList<>(); @@ -157,26 +154,22 @@ public void theShippingServicesAvailableForThisCartShouldBe(DataTable shippingSe assertThat(actualList).isEqualTo(shippingServices.asMaps()); } - @Transactional @And("^\"([^\"]*)\" with email address \"([^\"]*)\" is set as the recipient$") public void withEmailAdressIsSetAsTheRecipient(String fullName, String eMail) throws Throwable { Recipient recipient = new Recipient(fullName, eMail); cartService.setRecipient(currentCartId, recipient); } - @Transactional @And("^order is validated$") public void orderIsValidated() throws Throwable { currentOrderId = orderService.createOrderFromCart(this.currentCartId); } - @Transactional @And("^order should not be validated$") public void orderCannotBeValidated() throws Throwable { assertThatThrownBy(() -> orderService.createOrderFromCart(currentCartId)).isInstanceOf(BusinessException.class); } - @Transactional @Then("^the historical orders for recipient \"([^\"]*)\" should be:$") public void theHistoricalOrdersForRecipientShouldBe(String eMail, DataTable orders) throws Throwable { List> actualList = new ArrayList<>(); @@ -190,7 +183,6 @@ public void theHistoricalOrdersForRecipientShouldBe(String eMail, DataTable orde assertThat(actualList).isEqualTo(orders.asMaps()); } - @Transactional @And("^delivery is validated$") public void deliveryIsValidated() throws Throwable { currentDeliveryId = deliveryService.createDeliveryFromOrder(currentOrderId);