From 58085044168cca927ba06639f326c8debd246a62 Mon Sep 17 00:00:00 2001 From: Raja Kolli Date: Mon, 13 Nov 2023 20:31:19 +0530 Subject: [PATCH] feat: format numbers to 2 decimals (#600) * feat: format numbers to 2 decimals * feat: update asserts * fix: issue with setting BigDecimal * feat: remove scaling as it is not necessary at parent level --- ReadMe.md | 4 ++ catalog-service/pom.xml | 2 +- .../model/response/ProductResponse.java | 3 +- .../web/controllers/ProductControllerIT.java | 65 ++++++++++--------- order-service/pom.xml | 2 +- .../model/response/OrderItemResponse.java | 8 ++- .../model/response/OrderResponse.java | 3 +- .../TestOrderServiceApplication.java | 2 +- .../web/controllers/OrderControllerIT.java | 13 ++-- 9 files changed, 60 insertions(+), 42 deletions(-) diff --git a/ReadMe.md b/ReadMe.md index d57f8b19..dd695d08 100644 --- a/ReadMe.md +++ b/ReadMe.md @@ -189,3 +189,7 @@ taskkill /PID /f - Fluent-bit only supports AMD architecture hence swithced to pormtail. If you want to use fluent-bit please ensure grafana is started first and then other services are started. - JOOQ expects `Transactional` annotation on repository though we have it on Service + + +### Tips +then using `jsonPath` in a mvc test for asserting `BigDecimal` use `jsonPath("$.totalPrice").value(closeTo(100.00, 0.01))` instead of `jsonPath("$.totalPrice").value(100.00))` \ No newline at end of file diff --git a/catalog-service/pom.xml b/catalog-service/pom.xml index 161391ef..29cef6a4 100644 --- a/catalog-service/pom.xml +++ b/catalog-service/pom.xml @@ -20,7 +20,7 @@ UTF-8 21 - 2023.0.0-M2 + 2023.0.0-RC1 2.2.0 1.5.5.Final diff --git a/catalog-service/src/main/java/com/example/catalogservice/model/response/ProductResponse.java b/catalog-service/src/main/java/com/example/catalogservice/model/response/ProductResponse.java index 11a3980b..cf208747 100644 --- a/catalog-service/src/main/java/com/example/catalogservice/model/response/ProductResponse.java +++ b/catalog-service/src/main/java/com/example/catalogservice/model/response/ProductResponse.java @@ -6,6 +6,7 @@ Licensed under MIT License Copyright (c) 2023 Raja Kolli. package com.example.catalogservice.model.response; +import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonIgnore; public record ProductResponse( @@ -13,7 +14,7 @@ public record ProductResponse( String code, String productName, String description, - double price, + @JsonFormat(shape = JsonFormat.Shape.NUMBER_FLOAT, pattern = "0.00") double price, boolean inStock) { @JsonIgnore diff --git a/catalog-service/src/test/java/com/example/catalogservice/web/controllers/ProductControllerIT.java b/catalog-service/src/test/java/com/example/catalogservice/web/controllers/ProductControllerIT.java index 17c952db..de66159d 100644 --- a/catalog-service/src/test/java/com/example/catalogservice/web/controllers/ProductControllerIT.java +++ b/catalog-service/src/test/java/com/example/catalogservice/web/controllers/ProductControllerIT.java @@ -9,10 +9,6 @@ Licensed under MIT License Copyright (c) 2021-2023 Raja Kolli. import static org.assertj.core.api.Assertions.assertThat; import static org.awaitility.Awaitility.await; import static org.hamcrest.CoreMatchers.is; -import static org.junit.jupiter.api.Assertions.assertAll; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertTrue; import com.example.catalogservice.common.AbstractCircuitBreakerTest; import com.example.catalogservice.config.TestKafkaListenerConfig; @@ -27,10 +23,8 @@ Licensed under MIT License Copyright (c) 2021-2023 Raja Kolli. import java.time.Duration; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.TimeUnit; import okhttp3.mockwebserver.MockResponse; import okhttp3.mockwebserver.MockWebServer; -import org.awaitility.Awaitility; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; @@ -140,15 +134,19 @@ void shouldFetchAllProductsAsEmpty() { .expectBody(PagedResult.class) .value( response -> - assertAll( - () -> assertThat(response.isFirst()).isTrue(), - () -> assertThat(response.isLast()).isTrue(), - () -> assertThat(response.hasNext()).isFalse(), - () -> assertThat(response.hasPrevious()).isFalse(), - () -> assertThat(response.totalElements()).isZero(), - () -> assertThat(response.pageNumber()).isEqualTo(1), - () -> assertThat(response.totalPages()).isZero(), - () -> assertThat(response.data()).isEmpty())); + assertThat(response) + .isNotNull() + .satisfies( + r -> { + assertThat(r.isFirst()).isTrue(); + assertThat(r.isLast()).isTrue(); + assertThat(r.hasNext()).isFalse(); + assertThat(r.hasPrevious()).isFalse(); + assertThat(r.totalElements()).isZero(); + assertThat(r.pageNumber()).isEqualTo(1); + assertThat(r.totalPages()).isZero(); + assertThat(r.data()).isEmpty(); + })); checkHealthStatus("getInventoryByProductCodes", CircuitBreaker.State.HALF_OPEN); } @@ -176,15 +174,20 @@ void shouldFetchAllProductsWithCircuitBreaker() { .expectBody(PagedResult.class) .value( response -> - assertAll( - () -> assertTrue(response.isFirst()), - () -> assertTrue(response.isLast()), - () -> assertFalse(response.hasNext()), - () -> assertFalse(response.hasPrevious()), - () -> assertEquals(3, response.totalElements()), - () -> assertEquals(1, response.pageNumber()), - () -> assertEquals(1, response.totalPages()), - () -> assertEquals(3, response.data().size()))); + assertThat(response) + .isNotNull() + .satisfies( + r -> { + assertThat(r.isFirst()).isTrue(); + assertThat(r.isLast()).isTrue(); + assertThat(r.hasNext()).isFalse(); + assertThat(r.hasPrevious()).isFalse(); + assertThat(r.totalElements()).isEqualTo(3); + assertThat(r.pageNumber()).isEqualTo(1); + assertThat(r.totalPages()).isEqualTo(1); + assertThat(r.data().size()) + .isEqualTo(savedProductList.size()); + })); // Then, As it is still failing state should not change checkHealthStatus("getInventoryByProductCodes", CircuitBreaker.State.HALF_OPEN); @@ -495,8 +498,7 @@ void shouldCreateNewProduct() { .jsonPath("$.price") .isEqualTo(productRequest.price()); - Awaitility.await() - .atMost(15, TimeUnit.SECONDS) + await().atMost(Duration.ofSeconds(15)) .pollInterval(Duration.ofSeconds(1)) .pollDelay(Duration.ofSeconds(1)) .untilAsserted( @@ -566,13 +568,16 @@ void shouldReturn400WhenCreateNewProductWithoutCode() { @Test void shouldUpdateProduct() { Product product = savedProductList.get(0); - product.setDescription("Updated Catalog"); + + ProductRequest productRequest = + new ProductRequest( + product.getCode(), product.getProductName(), "Updated Catalog", 100D); webTestClient .put() .uri("/api/catalog/{id}", product.getId()) .contentType(MediaType.APPLICATION_JSON) - .body(Mono.just(product), Product.class) + .body(Mono.just(productRequest), ProductRequest.class) .exchange() .expectStatus() .isOk() @@ -586,9 +591,9 @@ void shouldUpdateProduct() { .jsonPath("$.productName") .value(is(product.getProductName())) .jsonPath("$.description") - .value(is(product.getDescription())) + .value(is("Updated Catalog")) .jsonPath("$.price") - .value(is(product.getPrice())); + .value(is(100.00)); } @Test diff --git a/order-service/pom.xml b/order-service/pom.xml index 90bd70e0..2704b6f3 100644 --- a/order-service/pom.xml +++ b/order-service/pom.xml @@ -19,7 +19,7 @@ UTF-8 21 - 2023.0.0-M2 + 2023.0.0-RC1 1.5.5.Final 2.2.0 diff --git a/order-service/src/main/java/com/example/orderservice/model/response/OrderItemResponse.java b/order-service/src/main/java/com/example/orderservice/model/response/OrderItemResponse.java index e90f5553..be22b7bd 100644 --- a/order-service/src/main/java/com/example/orderservice/model/response/OrderItemResponse.java +++ b/order-service/src/main/java/com/example/orderservice/model/response/OrderItemResponse.java @@ -6,7 +6,13 @@ Licensed under MIT License Copyright (c) 2023 Raja Kolli. package com.example.orderservice.model.response; +import com.fasterxml.jackson.annotation.JsonFormat; import java.math.BigDecimal; public record OrderItemResponse( - Long itemId, String productId, int quantity, BigDecimal productPrice, BigDecimal price) {} + Long itemId, + String productId, + int quantity, + @JsonFormat(shape = JsonFormat.Shape.NUMBER_FLOAT, pattern = "0.00") + BigDecimal productPrice, + @JsonFormat(shape = JsonFormat.Shape.NUMBER_FLOAT, pattern = "0.00") BigDecimal price) {} diff --git a/order-service/src/main/java/com/example/orderservice/model/response/OrderResponse.java b/order-service/src/main/java/com/example/orderservice/model/response/OrderResponse.java index b63710ff..83fc7638 100644 --- a/order-service/src/main/java/com/example/orderservice/model/response/OrderResponse.java +++ b/order-service/src/main/java/com/example/orderservice/model/response/OrderResponse.java @@ -6,6 +6,7 @@ Licensed under MIT License Copyright (c) 2023 Raja Kolli. package com.example.orderservice.model.response; +import com.fasterxml.jackson.annotation.JsonFormat; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; @@ -16,5 +17,5 @@ public record OrderResponse( String status, String source, LocalDateTime createdDate, - BigDecimal totalPrice, + @JsonFormat(shape = JsonFormat.Shape.NUMBER_FLOAT, pattern = "0.00") BigDecimal totalPrice, List items) {} diff --git a/order-service/src/test/java/com/example/orderservice/TestOrderServiceApplication.java b/order-service/src/test/java/com/example/orderservice/TestOrderServiceApplication.java index a4bcfb3e..f464fdc3 100644 --- a/order-service/src/test/java/com/example/orderservice/TestOrderServiceApplication.java +++ b/order-service/src/test/java/com/example/orderservice/TestOrderServiceApplication.java @@ -25,7 +25,7 @@ public class TestOrderServiceApplication { @ServiceConnection @RestartScope KafkaContainer kafkaContainer() { - return new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka").withTag("7.5.1")) + return new KafkaContainer(DockerImageName.parse("confluentinc/cp-kafka").withTag("7.5.2")) .withKraft() .withReuse(true); } diff --git a/order-service/src/test/java/com/example/orderservice/web/controllers/OrderControllerIT.java b/order-service/src/test/java/com/example/orderservice/web/controllers/OrderControllerIT.java index 8f30fd87..7826a36b 100644 --- a/order-service/src/test/java/com/example/orderservice/web/controllers/OrderControllerIT.java +++ b/order-service/src/test/java/com/example/orderservice/web/controllers/OrderControllerIT.java @@ -8,6 +8,7 @@ Licensed under MIT License Copyright (c) 2021-2023 Raja Kolli. import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; +import static org.hamcrest.Matchers.closeTo; import static org.hamcrest.Matchers.hasSize; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; @@ -94,7 +95,7 @@ void shouldFindOrderById() throws Exception { .andExpect(jsonPath("$.customerId", is(order.getCustomerId()), Long.class)) .andExpect(jsonPath("$.status", is(order.getStatus().name()))) .andExpect(jsonPath("$.source", is(order.getSource()))) - .andExpect(jsonPath("$.totalPrice").value("201.0")) + .andExpect(jsonPath("$.totalPrice").value(closeTo(201.00, 0.01))) .andExpect(jsonPath("$.items.size()", is(order.getItems().size()))); } @@ -114,10 +115,10 @@ void shouldCreateNewOrder() throws Exception { .andExpect(jsonPath("$.orderId", notNullValue())) .andExpect(jsonPath("$.customerId", is(orderRequest.customerId()), Long.class)) .andExpect(jsonPath("$.status", is("NEW"))) - .andExpect(jsonPath("$.totalPrice").value("100.0")) + .andExpect(jsonPath("$.totalPrice").value(closeTo(100.00, 0.01))) .andExpect(jsonPath("$.items.size()", is(1))) .andExpect(jsonPath("$.items[0].itemId", notNullValue())) - .andExpect(jsonPath("$.items[0].price", is(100.0))); + .andExpect(jsonPath("$.items[0].price", is(100.00))); } @Test @@ -183,12 +184,12 @@ void shouldUpdateOrder() throws Exception { .content(objectMapper.writeValueAsString(orderDto))) .andExpect(status().isOk()) .andExpect(jsonPath("$.status", is("NEW"))) - .andExpect(jsonPath("$.totalPrice").value("1211.0")) + .andExpect(jsonPath("$.totalPrice").value(closeTo(1211.00, 0.01))) .andExpect(jsonPath("$.items.size()", is(2))) .andExpect(jsonPath("$.items[0].quantity", is(110))) - .andExpect(jsonPath("$.items[0].price", is(1111.0))) + .andExpect(jsonPath("$.items[0].price", is(1111.00))) .andExpect(jsonPath("$.items[1].quantity", is(100))) - .andExpect(jsonPath("$.items[1].price", is(100.0))); + .andExpect(jsonPath("$.items[1].price", is(100.00))); } @Test