From 9c45013550aace0aec6ac2effef8e66e814b220b Mon Sep 17 00:00:00 2001 From: rdsmart97 <73801108+rdsmart97@users.noreply.github.com> Date: Thu, 8 Dec 2022 17:57:35 -0800 Subject: [PATCH 1/3] Robert Smart Candidate Assesment --- .../user/controller/PaymentController.java | 33 ++++++++ .../user/dao/model/mapper/ResourceMapper.java | 2 +- .../dao/repository/PaymentRepository.java | 13 +++ .../bravo/user/service/PaymentService.java | 36 ++++++++ src/main/resources/data.sql | 7 ++ .../controller/PaymentControllerTest.java | 82 +++++++++++++++++++ .../dao/model/mapper/ResourceMapperTest.java | 13 +++ .../user/service/PaymentServiceTest.java | 80 ++++++++++++++++++ .../ResourceMapperTest/convertPaymentTest.csv | 15 ++++ 9 files changed, 280 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/bravo/user/controller/PaymentController.java create mode 100644 src/main/java/com/bravo/user/dao/repository/PaymentRepository.java create mode 100644 src/main/java/com/bravo/user/service/PaymentService.java create mode 100644 src/test/java/com/bravo/user/controller/PaymentControllerTest.java create mode 100644 src/test/java/com/bravo/user/service/PaymentServiceTest.java create mode 100644 src/test/resources/ResourceMapperTest/convertPaymentTest.csv diff --git a/src/main/java/com/bravo/user/controller/PaymentController.java b/src/main/java/com/bravo/user/controller/PaymentController.java new file mode 100644 index 0000000..baff0d2 --- /dev/null +++ b/src/main/java/com/bravo/user/controller/PaymentController.java @@ -0,0 +1,33 @@ +package com.bravo.user.controller; + +import com.bravo.user.annotation.SwaggerController; +import com.bravo.user.model.dto.PaymentDto; +import com.bravo.user.service.PaymentService; +import com.bravo.user.validator.UserValidator; +import lombok.NonNull; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseBody; + +import java.util.List; + +@RequestMapping(value = "/payment") +@SwaggerController +public class PaymentController { + + private final PaymentService paymentService; + private final UserValidator userValidator; + + public PaymentController(PaymentService paymentService, UserValidator userValidator) { + this.paymentService = paymentService; + this.userValidator = userValidator; + } + + @GetMapping(value = "/retrieve/{userId}") + @ResponseBody + public List retrieve(@NonNull final @PathVariable String userId) { + userValidator.validateId(userId); + return paymentService.retrieveByUserId(userId); + } +} diff --git a/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java b/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java index 4a78188..81efe58 100644 --- a/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java +++ b/src/main/java/com/bravo/user/dao/model/mapper/ResourceMapper.java @@ -48,7 +48,7 @@ public > List convertPayments(final T public PaymentDto convertPayment(final Payment payment){ final String cardNumber = payment.getCardNumber(); final PaymentDto dto = mapperFacade.map(payment, PaymentDto.class); - dto.setCardNumberLast4(cardNumber.substring(cardNumber.length() - 5)); + dto.setCardNumberLast4(cardNumber.substring(cardNumber.length() - 4)); return dto; } diff --git a/src/main/java/com/bravo/user/dao/repository/PaymentRepository.java b/src/main/java/com/bravo/user/dao/repository/PaymentRepository.java new file mode 100644 index 0000000..2a01bc9 --- /dev/null +++ b/src/main/java/com/bravo/user/dao/repository/PaymentRepository.java @@ -0,0 +1,13 @@ +package com.bravo.user.dao.repository; + +import com.bravo.user.dao.model.Payment; +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public interface PaymentRepository extends JpaRepository { + + List findPaymentByUserId(final String userId); +} \ No newline at end of file diff --git a/src/main/java/com/bravo/user/service/PaymentService.java b/src/main/java/com/bravo/user/service/PaymentService.java new file mode 100644 index 0000000..1dad177 --- /dev/null +++ b/src/main/java/com/bravo/user/service/PaymentService.java @@ -0,0 +1,36 @@ +package com.bravo.user.service; + +import com.bravo.user.dao.model.Payment; +import com.bravo.user.dao.model.mapper.ResourceMapper; +import com.bravo.user.dao.repository.PaymentRepository; +import com.bravo.user.exception.DataNotFoundException; +import com.bravo.user.model.dto.PaymentDto; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class PaymentService { + + private static final Logger LOGGER = LoggerFactory.getLogger(PaymentService.class); + + private final PaymentRepository paymentRepository; + private final ResourceMapper resourceMapper; + + public PaymentService(PaymentRepository paymentRepository, ResourceMapper resourceMapper) { + this.paymentRepository = paymentRepository; + this.resourceMapper = resourceMapper; + } + + public List retrieveByUserId(final String userId) { + final List paymentList = paymentRepository.findPaymentByUserId(userId); + if (paymentList.isEmpty()) { + throw new DataNotFoundException(String.format("No payment methods were found for user %s", userId)); + } + LOGGER.info("found {} payment method(s)", paymentList.size()); + + return resourceMapper.convertPayments(paymentList); + } +} diff --git a/src/main/resources/data.sql b/src/main/resources/data.sql index da45720..e54cc08 100644 --- a/src/main/resources/data.sql +++ b/src/main/resources/data.sql @@ -648,3 +648,10 @@ insert into address (id, user_id, line1, line2, city, state, zip) values ('42f33d30-f3f8-4743-a94e-4db11fdb747d', '008a4215-0b1d-445e-b655-a964039cbb5a', '412 Maple St', null, 'Dowagiac', 'Michigan', '49047'), ('579872ec-46f8-46b5-b809-d0724d965f0e', '00963d9b-f884-485e-9455-fcf30c6ac379', '237 Mountain Ter', 'Apt 10', 'Odenville', 'Alabama', '35120'), ('95a983d0-ba0e-4f30-afb6-667d4724b253', '00963d9b-f884-485e-9455-fcf30c6ac379', '107 Annettes Ct', null, 'Aydlett', 'North Carolina', '27916'); + +insert into payment (id, user_id, card_number, expiry_month, expiry_year) values +('96bc3112-7753-11ed-a1eb-0242ac120002', '008a4215-0b1d-445e-b655-a964039cbb5a', '1234567890123456', '01', '2023'), +('9d0b2230-7753-11ed-a1eb-0242ac120002', '00963d9b-f884-485e-9455-fcf30c6ac379', '0987654321098765', '07', '2025'), +('a1c8c7fa-7753-11ed-a1eb-0242ac120002', 'fd6d21f6-f1c2-473d-8ed7-f3f9c7550cc9', '1234246835790987', '08', '2024'), +('39d95670-7756-11ed-a1eb-0242ac120002', 'fd6d21f6-f1c2-473d-8ed7-f3f9c7550cc9', '3691232465796801', '08', '2024'), +('410e0df0-7756-11ed-a1eb-0242ac120002', 'fd6d21f6-f1c2-473d-8ed7-f3f9c7550cc9', '1234509876123450', '08', '2024'); diff --git a/src/test/java/com/bravo/user/controller/PaymentControllerTest.java b/src/test/java/com/bravo/user/controller/PaymentControllerTest.java new file mode 100644 index 0000000..e846384 --- /dev/null +++ b/src/test/java/com/bravo/user/controller/PaymentControllerTest.java @@ -0,0 +1,82 @@ +package com.bravo.user.controller; + +import com.bravo.user.App; +import com.bravo.user.model.dto.PaymentDto; +import com.bravo.user.service.PaymentService; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +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.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@ContextConfiguration(classes = { App.class }) +@ExtendWith(SpringExtension.class) +@SpringBootTest() +@AutoConfigureMockMvc +class PaymentControllerTest { + + @Autowired + private MockMvc mockMvc; + + @MockBean + private PaymentService paymentService; + + private List payments; + + @BeforeEach + public void beforeEach() { + final List ids = IntStream.range(1, 10).boxed().collect(Collectors.toList()); + + this.payments = ids.stream().map(id -> createPaymentDto(Integer.toString(id))) + .collect(Collectors.toList()); + } + + @Test + void givenValidUserId_retrievePayment_shouldReturnPayment() throws Exception { + final String userId = "123a-456b"; + + when(paymentService.retrieveByUserId(anyString())).thenReturn(payments); + + final ResultActions result = this.mockMvc.perform(get("/payment/retrieve/".concat(userId))) + .andExpect(status().isOk()); + + for (int i = 0; i < payments.size(); i++) { + result.andExpect(jsonPath(String.format("$[%d].id", i)).value(payments.get(i).getId())); + } + + verify(paymentService).retrieveByUserId(userId); + } + + @Test + void givenWhitespaceUserId_retrievePayment_shouldBadRequestException() throws Exception { + this.mockMvc.perform(get("/payment/retrieve/ /")).andExpect(status().isBadRequest()); + } + + @Test + void givenMissingUserId_retrievePayment_shouldThrowNotFoundException() throws Exception { + this.mockMvc.perform(get("/payment/retrieve")).andExpect(status().isNotFound()); + } + + private PaymentDto createPaymentDto(final String id) { + final PaymentDto payment = new PaymentDto(); + payment.setId(id); + return payment; + } +} diff --git a/src/test/java/com/bravo/user/dao/model/mapper/ResourceMapperTest.java b/src/test/java/com/bravo/user/dao/model/mapper/ResourceMapperTest.java index 2b1e32c..ff1848d 100644 --- a/src/test/java/com/bravo/user/dao/model/mapper/ResourceMapperTest.java +++ b/src/test/java/com/bravo/user/dao/model/mapper/ResourceMapperTest.java @@ -1,5 +1,7 @@ package com.bravo.user.dao.model.mapper; +import com.bravo.user.dao.model.Payment; +import com.bravo.user.model.dto.PaymentDto; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.extension.ExtendWith; import org.junit.jupiter.params.ParameterizedTest; @@ -48,4 +50,15 @@ void convertAddressTest( @ConvertWith(MapperArgConverter.class) AddressDto addressDto) { Assertions.assertEquals(addressDto, resourceMapper.convertAddress(address)); } + + @ParameterizedTest + @CsvFileSource( + resources = ("/ResourceMapperTest/convertPaymentTest.csv"), + delimiter = '$', + lineSeparator = ">") + void convertPaymentTest( + @ConvertWith(MapperArgConverter.class) Payment payment, + @ConvertWith(MapperArgConverter.class) PaymentDto paymentDto) { + Assertions.assertEquals(paymentDto, resourceMapper.convertPayment(payment)); + } } \ No newline at end of file diff --git a/src/test/java/com/bravo/user/service/PaymentServiceTest.java b/src/test/java/com/bravo/user/service/PaymentServiceTest.java new file mode 100644 index 0000000..f48d3bb --- /dev/null +++ b/src/test/java/com/bravo/user/service/PaymentServiceTest.java @@ -0,0 +1,80 @@ +package com.bravo.user.service; + +import com.bravo.user.App; +import com.bravo.user.dao.model.Address; +import com.bravo.user.dao.model.Payment; +import com.bravo.user.dao.model.mapper.ResourceMapper; +import com.bravo.user.dao.repository.AddressRepository; +import com.bravo.user.dao.repository.PaymentRepository; +import com.bravo.user.model.dto.AddressDto; +import com.bravo.user.model.dto.PaymentDto; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ContextConfiguration(classes = { App.class }) +@ExtendWith(SpringExtension.class) +@SpringBootTest +class PaymentServiceTest { + + @Autowired + private PaymentService paymentService; + + @MockBean + private ResourceMapper resourceMapper; + + @MockBean + private PaymentRepository paymentRepository; + + private List paymentDtos; + + @BeforeEach + public void beforeEach() { + final List ids = IntStream.range(1, 10).boxed().collect(Collectors.toList()); + + final List daoPayments = ids.stream() + .map(id -> createPayment(Integer.toString(id))).collect(Collectors.toList()); + + when(paymentRepository.findPaymentByUserId(anyString())).thenReturn(daoPayments); + + this.paymentDtos = ids.stream().map(id -> createPaymentDto(Integer.toString(id))) + .collect(Collectors.toList()); + + when(resourceMapper.convertPayments(daoPayments)).thenReturn(paymentDtos); + } + + @Test + void givenValidUserId_findPaymentByUserId_retrievesPaymentMethods() { + final String userId = "123a-456b"; + final List results = paymentService.retrieveByUserId(userId); + assertEquals(paymentDtos, results); + + verify(paymentRepository).findPaymentByUserId(userId); + } + + private Payment createPayment(final String id) { + final Payment payment = new Payment(); + payment.setId(id); + return payment; + } + + private PaymentDto createPaymentDto(final String id) { + final PaymentDto paymentDto = new PaymentDto(); + paymentDto.setId(id); + return paymentDto; + } +} diff --git a/src/test/resources/ResourceMapperTest/convertPaymentTest.csv b/src/test/resources/ResourceMapperTest/convertPaymentTest.csv new file mode 100644 index 0000000..576a22d --- /dev/null +++ b/src/test/resources/ResourceMapperTest/convertPaymentTest.csv @@ -0,0 +1,15 @@ +>{ + "id":"testId", + "userId":"testUserId", + "cardNumber":"1234567890123456", + "expiryMonth":"01", + "expiryYear":"2023", + "updated":"2021-07-12 12:00:00" +} +${ + "id":"testId", + "cardNumberLast4":"3456", + "expiryMonth":"01", + "expiryYear":"2023", + "updated":"2021-07-12 12:00:00" +} From 192f28e7d297c6a5f0af844935e8d684e968f635 Mon Sep 17 00:00:00 2001 From: rdsmart97 <73801108+rdsmart97@users.noreply.github.com> Date: Thu, 8 Dec 2022 18:31:46 -0800 Subject: [PATCH 2/3] removing unused imports --- src/test/java/com/bravo/user/service/PaymentServiceTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/test/java/com/bravo/user/service/PaymentServiceTest.java b/src/test/java/com/bravo/user/service/PaymentServiceTest.java index f48d3bb..b47789e 100644 --- a/src/test/java/com/bravo/user/service/PaymentServiceTest.java +++ b/src/test/java/com/bravo/user/service/PaymentServiceTest.java @@ -1,12 +1,9 @@ package com.bravo.user.service; import com.bravo.user.App; -import com.bravo.user.dao.model.Address; import com.bravo.user.dao.model.Payment; import com.bravo.user.dao.model.mapper.ResourceMapper; -import com.bravo.user.dao.repository.AddressRepository; import com.bravo.user.dao.repository.PaymentRepository; -import com.bravo.user.model.dto.AddressDto; import com.bravo.user.model.dto.PaymentDto; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; From 2e9110d6e7b2d14b3450373d97ffc3a6edf2590f Mon Sep 17 00:00:00 2001 From: rdsmart97 <73801108+rdsmart97@users.noreply.github.com> Date: Fri, 9 Dec 2022 16:00:04 -0800 Subject: [PATCH 3/3] refactoring payment controller code to remove redendant variables --- .../java/com/bravo/user/controller/PaymentController.java | 3 +-- .../com/bravo/user/controller/PaymentControllerTest.java | 5 ++--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/bravo/user/controller/PaymentController.java b/src/main/java/com/bravo/user/controller/PaymentController.java index baff0d2..503cbcf 100644 --- a/src/main/java/com/bravo/user/controller/PaymentController.java +++ b/src/main/java/com/bravo/user/controller/PaymentController.java @@ -4,7 +4,6 @@ import com.bravo.user.model.dto.PaymentDto; import com.bravo.user.service.PaymentService; import com.bravo.user.validator.UserValidator; -import lombok.NonNull; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; @@ -26,7 +25,7 @@ public PaymentController(PaymentService paymentService, UserValidator userValida @GetMapping(value = "/retrieve/{userId}") @ResponseBody - public List retrieve(@NonNull final @PathVariable String userId) { + public List retrieve(final @PathVariable String userId) { userValidator.validateId(userId); return paymentService.retrieveByUserId(userId); } diff --git a/src/test/java/com/bravo/user/controller/PaymentControllerTest.java b/src/test/java/com/bravo/user/controller/PaymentControllerTest.java index e846384..d5b203e 100644 --- a/src/test/java/com/bravo/user/controller/PaymentControllerTest.java +++ b/src/test/java/com/bravo/user/controller/PaymentControllerTest.java @@ -42,9 +42,8 @@ class PaymentControllerTest { @BeforeEach public void beforeEach() { - final List ids = IntStream.range(1, 10).boxed().collect(Collectors.toList()); - - this.payments = ids.stream().map(id -> createPaymentDto(Integer.toString(id))) + this.payments = IntStream.range(1, 10).boxed() + .map(id -> createPaymentDto(Integer.toString(id))) .collect(Collectors.toList()); }