diff --git a/openapi/pagopa-arc-be.openapi.yaml b/openapi/pagopa-arc-be.openapi.yaml index 3dca8e07..83417769 100644 --- a/openapi/pagopa-arc-be.openapi.yaml +++ b/openapi/pagopa-arc-be.openapi.yaml @@ -110,10 +110,17 @@ paths: application/json: schema: $ref: '#/components/schemas/TransactionsListDTO' + '400': + description: "Invalid Request" + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorDTO' + example: + error: invalid_amount + error_description: "Invalid amount format" '401': description: "Wrong or missing function key" - '429': - description: "Too many Requests" '500': description: "Service unavailable" content: @@ -140,6 +147,15 @@ paths: application/json: schema: $ref: '#/components/schemas/TransactionDetailsDTO' + '400': + description: "Invalid Request" + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorDTO' + example: + error: invalid_amount + error_description: "Invalid amount format" '401': description: "Wrong or missing function key" '404': @@ -151,8 +167,6 @@ paths: example: error: "transaction_not_found_error" error_description: "string" - '429': - description: "Too many Requests" '500': description: "Service unavailable" content: @@ -191,8 +205,6 @@ paths: example: error: "receipt_not_found_error" error_description: "string" - '429': - description: "Too many Requests" '500': description: "Service unavailable" content: @@ -237,6 +249,15 @@ paths: application/json: schema: $ref: '#/components/schemas/PaymentNoticesListDTO' + '400': + description: "Invalid Request" + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorDTO' + example: + error: invalid_request + error_description: "One or more inputs provided during the request from pull payment are invalid" '401': description: "Wrong or missing function key" '500': diff --git a/src/main/java/it/gov/pagopa/arc/connector/bizevents/BizEventsConnectorImpl.java b/src/main/java/it/gov/pagopa/arc/connector/bizevents/BizEventsConnectorImpl.java index a6332fbe..01eeccc4 100644 --- a/src/main/java/it/gov/pagopa/arc/connector/bizevents/BizEventsConnectorImpl.java +++ b/src/main/java/it/gov/pagopa/arc/connector/bizevents/BizEventsConnectorImpl.java @@ -6,6 +6,7 @@ import it.gov.pagopa.arc.exception.custom.BizEventsInvocationException; import it.gov.pagopa.arc.exception.custom.BizEventsReceiptNotFoundException; import it.gov.pagopa.arc.exception.custom.BizEventsTransactionNotFoundException; +import it.gov.pagopa.arc.utils.Utilities; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; @@ -45,6 +46,7 @@ public BizEventsTransactionsListDTO getTransactionsList(String fiscalCode, int s e.status(), e.getMessage()); }else { + Utilities.logExceptionDetails(e); throw new BizEventsInvocationException(ERROR_MESSAGE_INVOCATION_EXCEPTION); } } @@ -60,6 +62,7 @@ public BizEventsTransactionDetailsDTO getTransactionDetails(String fiscalCode, S if(e.status() == HttpStatus.NOT_FOUND.value()){ throw new BizEventsTransactionNotFoundException("An error occurred handling request from biz-Events to retrieve transaction with transaction id [%s] for the current user".formatted(transactionId)); } + Utilities.logExceptionDetails(e); throw new BizEventsInvocationException(ERROR_MESSAGE_INVOCATION_EXCEPTION); } return bizEventsTransactionDetailsDTO; @@ -74,6 +77,7 @@ public Resource getTransactionReceipt(String fiscalCode, String transactionId) { if (e.status() == HttpStatus.NOT_FOUND.value()){ throw new BizEventsReceiptNotFoundException("An error occurred handling request from biz-Events to retrieve transaction receipt with transaction id [%s] for the current user".formatted(transactionId)); } + Utilities.logExceptionDetails(e); throw new BizEventsInvocationException(ERROR_MESSAGE_INVOCATION_EXCEPTION); } return transactionReceipt; diff --git a/src/main/java/it/gov/pagopa/arc/connector/pullpayment/PullPaymentConnectorImpl.java b/src/main/java/it/gov/pagopa/arc/connector/pullpayment/PullPaymentConnectorImpl.java index f77486be..aeedecad 100644 --- a/src/main/java/it/gov/pagopa/arc/connector/pullpayment/PullPaymentConnectorImpl.java +++ b/src/main/java/it/gov/pagopa/arc/connector/pullpayment/PullPaymentConnectorImpl.java @@ -2,6 +2,9 @@ import feign.FeignException; import it.gov.pagopa.arc.connector.pullpayment.dto.PullPaymentNoticeDTO; +import it.gov.pagopa.arc.exception.custom.PullPaymentInvalidRequestException; +import it.gov.pagopa.arc.exception.custom.PullPaymentInvocationException; +import it.gov.pagopa.arc.utils.Utilities; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; @@ -35,9 +38,11 @@ public List getPaymentNotices(String fiscalCode, LocalDate e.getClass(), e.status(), e.getMessage()); + } else if(e.status() == HttpStatus.BAD_REQUEST.value()) { + throw new PullPaymentInvalidRequestException("One or more inputs provided during the request from pull payment are invalid"); }else{ - //replace this exception with Custom exception - throw new RuntimeException("An error occurred handling request from pull payment service;"); + Utilities.logExceptionDetails(e); + throw new PullPaymentInvocationException("An error occurred handling request from pull payment service"); } } diff --git a/src/main/java/it/gov/pagopa/arc/exception/ArcExceptionHandler.java b/src/main/java/it/gov/pagopa/arc/exception/ArcExceptionHandler.java index f4fe0bbe..9050104d 100644 --- a/src/main/java/it/gov/pagopa/arc/exception/ArcExceptionHandler.java +++ b/src/main/java/it/gov/pagopa/arc/exception/ArcExceptionHandler.java @@ -43,6 +43,16 @@ public ResponseEntity handleBizEventsInvalidDateException(RuntimeExcep return handleArcErrorException(ex, request, HttpStatus.BAD_REQUEST, ErrorDTO.ErrorEnum.INVALID_DATE); } + @ExceptionHandler(PullPaymentInvalidRequestException.class) + public ResponseEntity handlePullPaymentInvalidRequestException(RuntimeException ex, HttpServletRequest request){ + return handleArcErrorException(ex, request, HttpStatus.BAD_REQUEST, ErrorDTO.ErrorEnum.INVALID_REQUEST); + } + + @ExceptionHandler(PullPaymentInvocationException.class) + public ResponseEntity handlePullPaymentInvocationException(RuntimeException ex, HttpServletRequest request){ + return handleArcErrorException(ex, request, HttpStatus.INTERNAL_SERVER_ERROR, ErrorDTO.ErrorEnum.GENERIC_ERROR); + } + private static ResponseEntity handleArcErrorException(RuntimeException ex, HttpServletRequest request, HttpStatus httpStatus, ErrorDTO.ErrorEnum errorEnum) { String message = ex.getMessage(); log.info("A {} occurred handling request {}: HttpStatus {} - {}", diff --git a/src/main/java/it/gov/pagopa/arc/exception/custom/PullPaymentInvalidRequestException.java b/src/main/java/it/gov/pagopa/arc/exception/custom/PullPaymentInvalidRequestException.java new file mode 100644 index 00000000..d45b677b --- /dev/null +++ b/src/main/java/it/gov/pagopa/arc/exception/custom/PullPaymentInvalidRequestException.java @@ -0,0 +1,8 @@ +package it.gov.pagopa.arc.exception.custom; + +import lombok.Getter; + +@Getter +public class PullPaymentInvalidRequestException extends RuntimeException{ + public PullPaymentInvalidRequestException(String message){super(message);} +} diff --git a/src/main/java/it/gov/pagopa/arc/exception/custom/PullPaymentInvocationException.java b/src/main/java/it/gov/pagopa/arc/exception/custom/PullPaymentInvocationException.java new file mode 100644 index 00000000..087575c7 --- /dev/null +++ b/src/main/java/it/gov/pagopa/arc/exception/custom/PullPaymentInvocationException.java @@ -0,0 +1,9 @@ +package it.gov.pagopa.arc.exception.custom; + +import lombok.Getter; + +@Getter +public class PullPaymentInvocationException extends RuntimeException{ + + public PullPaymentInvocationException(String message){super(message);} +} diff --git a/src/main/java/it/gov/pagopa/arc/utils/Utilities.java b/src/main/java/it/gov/pagopa/arc/utils/Utilities.java index be5b8d1b..5e737998 100644 --- a/src/main/java/it/gov/pagopa/arc/utils/Utilities.java +++ b/src/main/java/it/gov/pagopa/arc/utils/Utilities.java @@ -3,6 +3,7 @@ import it.gov.pagopa.arc.exception.custom.BizEventsInvalidAmountException; import it.gov.pagopa.arc.exception.custom.BizEventsInvalidDateException; +import lombok.extern.slf4j.Slf4j; import java.text.NumberFormat; import java.text.ParseException; @@ -11,6 +12,7 @@ import java.time.format.DateTimeParseException; import java.util.Locale; +@Slf4j public class Utilities { private Utilities(){} @@ -40,4 +42,13 @@ public static ZonedDateTime dateStringToZonedDateTime(String dateString){ throw new BizEventsInvalidDateException("Invalid date format"); } } + + /** + * To log the full error stack + * + * @param ex exception to log + */ + public static void logExceptionDetails(RuntimeException ex){ + log.error("Exception occurred: {} - {}", ex.getClass().getSimpleName(), ex.getMessage(), ex); + } } diff --git a/src/test/java/it/gov/pagopa/arc/config/WireMockConfig.java b/src/test/java/it/gov/pagopa/arc/config/WireMockConfig.java new file mode 100644 index 00000000..7ff1a5f8 --- /dev/null +++ b/src/test/java/it/gov/pagopa/arc/config/WireMockConfig.java @@ -0,0 +1,56 @@ +package it.gov.pagopa.arc.config; + +import com.github.tomakehurst.wiremock.WireMockServer; +import com.github.tomakehurst.wiremock.core.WireMockConfiguration; +import org.springframework.context.ApplicationContextInitializer; +import org.springframework.context.ConfigurableApplicationContext; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.event.ContextClosedEvent; +import org.springframework.core.env.EnumerablePropertySource; +import org.springframework.test.context.support.TestPropertySourceUtils; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; + +@Configuration +public class WireMockConfig { + public static final String WIREMOCK_TEST_PROP2BASEPATH_MAP_PREFIX = "wireMock-test.prop2basePath."; + private static final Map propertiesMap = new HashMap<>(); + + public static class WireMockInitializer + implements ApplicationContextInitializer { + @Override + public void initialize(ConfigurableApplicationContext applicationContext) { + WireMockServer wireMockServer = new WireMockServer(new WireMockConfiguration().usingFilesUnderClasspath("src/test/resources/stub").dynamicPort()); + wireMockServer.start(); + + applicationContext.getBeanFactory().registerSingleton("wireMockServer", wireMockServer); + applicationContext.addApplicationListener( + applicationEvent -> { + if (applicationEvent instanceof ContextClosedEvent) { + wireMockServer.stop(); + } + }); + + applicationContext.getEnvironment().getPropertySources().stream() + .filter(propertySource -> propertySource instanceof EnumerablePropertySource) + .map(propertySource -> (EnumerablePropertySource) propertySource) + .flatMap(propertySource -> Arrays.stream(propertySource.getPropertyNames())) + .forEach(key -> { + if (key.startsWith(WIREMOCK_TEST_PROP2BASEPATH_MAP_PREFIX)) { + propertiesMap.put(key.substring(WIREMOCK_TEST_PROP2BASEPATH_MAP_PREFIX.length()), applicationContext.getEnvironment().getProperty(key)); + } + }); + + for (Map.Entry entry : propertiesMap.entrySet()) { + setWireMockBaseMockedServicePath(applicationContext,wireMockServer.baseUrl(),entry); + } + + } + } + + private static void setWireMockBaseMockedServicePath(ConfigurableApplicationContext applicationContext, String serverWireMock,Map.Entry entry){ + TestPropertySourceUtils.addInlinedPropertiesToEnvironment(applicationContext,String.format("%s=%s/%s",entry.getKey(),serverWireMock,entry.getValue())); + } +} diff --git a/src/test/java/it/gov/pagopa/arc/connector/bizevents/BizEventsConnectorImplTest.java b/src/test/java/it/gov/pagopa/arc/connector/bizevents/BizEventsConnectorImplTest.java index afadf987..19adb67e 100644 --- a/src/test/java/it/gov/pagopa/arc/connector/bizevents/BizEventsConnectorImplTest.java +++ b/src/test/java/it/gov/pagopa/arc/connector/bizevents/BizEventsConnectorImplTest.java @@ -1,9 +1,8 @@ package it.gov.pagopa.arc.connector.bizevents; import ch.qos.logback.classic.LoggerContext; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import it.gov.pagopa.arc.config.FeignConfig; +import it.gov.pagopa.arc.config.WireMockConfig; import it.gov.pagopa.arc.connector.bizevents.dto.BizEventsTransactionDetailsDTO; import it.gov.pagopa.arc.connector.bizevents.dto.BizEventsTransactionsListDTO; import it.gov.pagopa.arc.connector.bizevents.enums.Origin; @@ -20,23 +19,20 @@ import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.openfeign.FeignAutoConfiguration; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.event.ContextClosedEvent; import org.springframework.core.io.Resource; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.support.TestPropertySourceUtils; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; +import static it.gov.pagopa.arc.config.WireMockConfig.WIREMOCK_TEST_PROP2BASEPATH_MAP_PREFIX; import static org.junit.jupiter.api.Assertions.*; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) @ContextConfiguration( - initializers = BizEventsConnectorImplTest.WireMockInitializer.class, + initializers = WireMockConfig.WireMockInitializer.class, classes = { BizEventsConnectorImpl.class, FeignConfig.class, @@ -46,12 +42,13 @@ }) @TestPropertySource( properties = { - "rest-client.biz-events.api-key=x_api_key0" -}) + "rest-client.biz-events.api-key=x_api_key0", + WIREMOCK_TEST_PROP2BASEPATH_MAP_PREFIX + "rest-client.biz-events.baseUrl=bizEventsMock" + }) class BizEventsConnectorImplTest { @Autowired - private BizEventsConnector bizEventsConnector; + private BizEventsConnector bizEventsConnector; private MemoryAppender memoryAppender; @BeforeEach @@ -88,7 +85,7 @@ void givenHeaderAndParameterWhenNotFoundThenReturnEmptyTransactionList() { //when BizEventsTransactionsListDTO bizEventsTransactionsListDTO = bizEventsConnector.getTransactionsList("DUMMY_FISCAL_CODE_NOT_FOUND", 2); //then - Assertions.assertEquals(0,bizEventsTransactionsListDTO.getTransactions().size()); + Assertions.assertEquals(0, bizEventsTransactionsListDTO.getTransactions().size()); Assertions.assertTrue(memoryAppender.getLoggedEvents().get(0).getFormattedMessage() .contains(("A class feign.FeignException$NotFound occurred handling request getTransactionsList from biz-Events: HttpStatus 404")) ); @@ -99,7 +96,7 @@ void givenHeaderAndParameterWhenErrorThenThrowBizEventsInvocationException() { //When //Then Assertions.assertThrows(BizEventsInvocationException.class, - ()-> bizEventsConnector.getTransactionsList("DUMMY_FISCAL_CODE_ERROR", 2)); + () -> bizEventsConnector.getTransactionsList("DUMMY_FISCAL_CODE_ERROR", 2)); } @@ -112,19 +109,19 @@ void givenTransactionIdWhenCallBizEventsConnectorThenReturnTransactionDetails() //then Assertions.assertNotNull(transactionDetails.getBizEventsInfoTransactionDTO()); Assertions.assertEquals(1, transactionDetails.getBizEventsCartsDTO().size()); - Assertions.assertEquals( "TRANSACTION_ID", transactionDetails.getBizEventsInfoTransactionDTO().getTransactionId()); - Assertions.assertEquals( "250863", transactionDetails.getBizEventsInfoTransactionDTO().getAuthCode()); - Assertions.assertEquals( "223560110624", transactionDetails.getBizEventsInfoTransactionDTO().getRrn()); - Assertions.assertEquals( "2024-06-13T15:22:04Z", transactionDetails.getBizEventsInfoTransactionDTO().getTransactionDate()); - Assertions.assertEquals( "Worldline Merchant Services Italia S.p.A.", transactionDetails.getBizEventsInfoTransactionDTO().getPspName()); + Assertions.assertEquals("TRANSACTION_ID", transactionDetails.getBizEventsInfoTransactionDTO().getTransactionId()); + Assertions.assertEquals("250863", transactionDetails.getBizEventsInfoTransactionDTO().getAuthCode()); + Assertions.assertEquals("223560110624", transactionDetails.getBizEventsInfoTransactionDTO().getRrn()); + Assertions.assertEquals("2024-06-13T15:22:04Z", transactionDetails.getBizEventsInfoTransactionDTO().getTransactionDate()); + Assertions.assertEquals("Worldline Merchant Services Italia S.p.A.", transactionDetails.getBizEventsInfoTransactionDTO().getPspName()); - Assertions.assertEquals( "ERNESTO HOLDER", transactionDetails.getBizEventsInfoTransactionDTO().getBizEventsWalletInfoDTO().getAccountHolder()); - Assertions.assertEquals( "MASTERCARD", transactionDetails.getBizEventsInfoTransactionDTO().getBizEventsWalletInfoDTO().getBrand()); - Assertions.assertEquals( "0403", transactionDetails.getBizEventsInfoTransactionDTO().getBizEventsWalletInfoDTO().getBlurredNumber()); + Assertions.assertEquals("ERNESTO HOLDER", transactionDetails.getBizEventsInfoTransactionDTO().getBizEventsWalletInfoDTO().getAccountHolder()); + Assertions.assertEquals("MASTERCARD", transactionDetails.getBizEventsInfoTransactionDTO().getBizEventsWalletInfoDTO().getBrand()); + Assertions.assertEquals("0403", transactionDetails.getBizEventsInfoTransactionDTO().getBizEventsWalletInfoDTO().getBlurredNumber()); - Assertions.assertEquals( PaymentMethod.PO, transactionDetails.getBizEventsInfoTransactionDTO().getPaymentMethod()); - Assertions.assertEquals( "ERNESTO PAYER", transactionDetails.getBizEventsInfoTransactionDTO().getPayer().getName()); - Assertions.assertEquals( "TAX_CODE", transactionDetails.getBizEventsInfoTransactionDTO().getPayer().getTaxCode()); + Assertions.assertEquals(PaymentMethod.PO, transactionDetails.getBizEventsInfoTransactionDTO().getPaymentMethod()); + Assertions.assertEquals("ERNESTO PAYER", transactionDetails.getBizEventsInfoTransactionDTO().getPayer().getName()); + Assertions.assertEquals("TAX_CODE", transactionDetails.getBizEventsInfoTransactionDTO().getPayer().getTaxCode()); Assertions.assertEquals("634,37", transactionDetails.getBizEventsInfoTransactionDTO().getAmount()); Assertions.assertEquals("0,53", transactionDetails.getBizEventsInfoTransactionDTO().getFee()); @@ -149,7 +146,7 @@ void givenTransactionIdWhenNotFoundThenReturnException() { //when BizEventsTransactionNotFoundException bizEventsTransactionNotFoundException = assertThrows(BizEventsTransactionNotFoundException.class, () -> bizEventsConnector.getTransactionDetails("DUMMY_FISCAL_CODE_NOT_FOUND", "TRANSACTION_ID_NOT_FOUND_1")); - Assertions.assertEquals( "An error occurred handling request from biz-Events to retrieve transaction with transaction id [TRANSACTION_ID_NOT_FOUND_1] for the current user", bizEventsTransactionNotFoundException.getMessage()); + Assertions.assertEquals("An error occurred handling request from biz-Events to retrieve transaction with transaction id [TRANSACTION_ID_NOT_FOUND_1] for the current user", bizEventsTransactionNotFoundException.getMessage()); } @Test @@ -158,7 +155,7 @@ void givenTransactionIdWhenErrorThenThrowBizEventsInvocationException() { //Then BizEventsInvocationException bizEventsInvocationException = assertThrows(BizEventsInvocationException.class, () -> bizEventsConnector.getTransactionDetails("DUMMY_FISCAL_CODE_ERROR", "TRANSACTION_ID_ERROR_1")); - Assertions.assertEquals( "An error occurred handling request from biz-Events", bizEventsInvocationException.getMessage()); + Assertions.assertEquals("An error occurred handling request from biz-Events", bizEventsInvocationException.getMessage()); } @Test @@ -181,7 +178,7 @@ void givenTransactionIdWhenReceiptNotFoundThenReturnException() { //when BizEventsReceiptNotFoundException bizEventsReceiptNotFoundException = assertThrows(BizEventsReceiptNotFoundException.class, () -> bizEventsConnector.getTransactionReceipt("DUMMY_FISCAL_CODE_RECEIPT_NOT_FOUND", "TRANSACTION_ID_RECEIPT_NOT_FOUND_1")); - Assertions.assertEquals( "An error occurred handling request from biz-Events to retrieve transaction receipt with transaction id [TRANSACTION_ID_RECEIPT_NOT_FOUND_1] for the current user", bizEventsReceiptNotFoundException.getMessage()); + Assertions.assertEquals("An error occurred handling request from biz-Events to retrieve transaction receipt with transaction id [TRANSACTION_ID_RECEIPT_NOT_FOUND_1] for the current user", bizEventsReceiptNotFoundException.getMessage()); } @Test @@ -190,30 +187,7 @@ void givenTransactionIdWhenReceiptErrorThenThrowBizEventsInvocationException() { //Then BizEventsInvocationException bizEventsInvocationException = assertThrows(BizEventsInvocationException.class, () -> bizEventsConnector.getTransactionReceipt("DUMMY_FISCAL_CODE_RECEIPT_ERROR", "TRANSACTION_ID_RECEIPT_ERROR_1")); - Assertions.assertEquals( "An error occurred handling request from biz-Events", bizEventsInvocationException.getMessage()); - } - - public static class WireMockInitializer - implements ApplicationContextInitializer { - @Override - public void initialize(ConfigurableApplicationContext applicationContext) { - WireMockServer wireMockServer = new WireMockServer(new WireMockConfiguration().usingFilesUnderClasspath("src/test/resources/stub").dynamicPort()); - wireMockServer.start(); - - applicationContext.getBeanFactory().registerSingleton("wireMockServer", wireMockServer); - applicationContext.addApplicationListener( - applicationEvent -> { - if (applicationEvent instanceof ContextClosedEvent) { - wireMockServer.stop(); - } - }); - - TestPropertySourceUtils.addInlinedPropertiesToEnvironment( - applicationContext, - String.format( - "rest-client.biz-events.baseUrl=http://%s:%d/bizEventsMock", - wireMockServer.getOptions().bindAddress(), wireMockServer.port())); - } + Assertions.assertEquals("An error occurred handling request from biz-Events", bizEventsInvocationException.getMessage()); } } diff --git a/src/test/java/it/gov/pagopa/arc/connector/pullpayment/PullPaymentConnectorImplTest.java b/src/test/java/it/gov/pagopa/arc/connector/pullpayment/PullPaymentConnectorImplTest.java index 1eaabd70..9b7ddeb8 100644 --- a/src/test/java/it/gov/pagopa/arc/connector/pullpayment/PullPaymentConnectorImplTest.java +++ b/src/test/java/it/gov/pagopa/arc/connector/pullpayment/PullPaymentConnectorImplTest.java @@ -1,10 +1,11 @@ package it.gov.pagopa.arc.connector.pullpayment; import ch.qos.logback.classic.LoggerContext; -import com.github.tomakehurst.wiremock.WireMockServer; -import com.github.tomakehurst.wiremock.core.WireMockConfiguration; import it.gov.pagopa.arc.config.FeignConfig; +import it.gov.pagopa.arc.config.WireMockConfig; import it.gov.pagopa.arc.connector.pullpayment.dto.PullPaymentNoticeDTO; +import it.gov.pagopa.arc.exception.custom.PullPaymentInvalidRequestException; +import it.gov.pagopa.arc.exception.custom.PullPaymentInvocationException; import it.gov.pagopa.arc.fakers.connector.pullPayment.PullPaymentNoticeDTOFaker; import it.gov.pagopa.arc.utils.MemoryAppender; import org.junit.jupiter.api.Assertions; @@ -15,20 +16,17 @@ import org.springframework.boot.autoconfigure.http.HttpMessageConvertersAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.cloud.openfeign.FeignAutoConfiguration; -import org.springframework.context.ApplicationContextInitializer; -import org.springframework.context.ConfigurableApplicationContext; -import org.springframework.context.event.ContextClosedEvent; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; -import org.springframework.test.context.support.TestPropertySourceUtils; import java.time.LocalDate; import java.util.List; +import static it.gov.pagopa.arc.config.WireMockConfig.WIREMOCK_TEST_PROP2BASEPATH_MAP_PREFIX; @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE) @ContextConfiguration( - initializers = PullPaymentConnectorImplTest.WireMockInitializer.class, + initializers = WireMockConfig.WireMockInitializer.class, classes = { PullPaymentConnectorImpl.class, FeignConfig.class, @@ -38,9 +36,11 @@ }) @TestPropertySource( properties = { - "rest-client.pull-payment.api-key=x_api_key0" + "rest-client.pull-payment.api-key=x_api_key0", + WIREMOCK_TEST_PROP2BASEPATH_MAP_PREFIX + "rest-client.pull-payment.baseUrl=pullPaymentMock" }) class PullPaymentConnectorImplTest { + private static final LocalDate LOCAL_DATE = LocalDate.parse("2024-04-11"); @Autowired private PullPaymentConnector pullPaymentConnector; @@ -82,34 +82,21 @@ void givenHeaderAndParameterWhenCallPullPaymentConnectorThenReturnEmptyPaymentNo } @Test - void givenHeaderAndParameterWhenErrorThenThrowPullPaymentInvocationException() { + void givenHeaderAndParameterWhenBadRequestErrorThenThrowPullPaymentInvalidRequestException() { //When //Then - Assertions.assertThrows(RuntimeException.class, - ()-> pullPaymentConnector.getPaymentNotices("DUMMY_FISCAL_CODE_ERROR", LocalDate.now(), 10, 0)); + PullPaymentInvalidRequestException pullPaymentInvalidRequestException = Assertions.assertThrows(PullPaymentInvalidRequestException.class, + () -> pullPaymentConnector.getPaymentNotices("DUMMY_FISCAL_CODE_BAD_REQUEST", LOCAL_DATE, 1000, 0)); + Assertions.assertEquals( "One or more inputs provided during the request from pull payment are invalid", pullPaymentInvalidRequestException.getMessage()); } - public static class WireMockInitializer - implements ApplicationContextInitializer { - @Override - public void initialize(ConfigurableApplicationContext applicationContext) { - WireMockServer wireMockServer = new WireMockServer(new WireMockConfiguration().usingFilesUnderClasspath("src/test/resources/stub").dynamicPort()); - wireMockServer.start(); - - applicationContext.getBeanFactory().registerSingleton("wireMockServer", wireMockServer); - applicationContext.addApplicationListener( - applicationEvent -> { - if (applicationEvent instanceof ContextClosedEvent) { - wireMockServer.stop(); - } - }); - - TestPropertySourceUtils.addInlinedPropertiesToEnvironment( - applicationContext, - String.format( - "rest-client.pull-payment.baseUrl=http://%s:%d/pullPaymentMock", - wireMockServer.getOptions().bindAddress(), wireMockServer.port())); - } + @Test + void givenHeaderAndParameterWhenErrorThenThrowPullPaymentInvocationException() { + //When + //Then + PullPaymentInvocationException pullPaymentInvocationException = Assertions.assertThrows(PullPaymentInvocationException.class, + () -> pullPaymentConnector.getPaymentNotices("DUMMY_FISCAL_CODE_ERROR", LOCAL_DATE, 10, 0)); + Assertions.assertEquals( "An error occurred handling request from pull payment service", pullPaymentInvocationException.getMessage()); } } \ No newline at end of file diff --git a/src/test/java/it/gov/pagopa/arc/exception/ArcExceptionHandlerTest.java b/src/test/java/it/gov/pagopa/arc/exception/ArcExceptionHandlerTest.java index eeee29cb..4e74961f 100644 --- a/src/test/java/it/gov/pagopa/arc/exception/ArcExceptionHandlerTest.java +++ b/src/test/java/it/gov/pagopa/arc/exception/ArcExceptionHandlerTest.java @@ -1,13 +1,8 @@ package it.gov.pagopa.arc.exception; -import static org.mockito.Mockito.doThrow; - import ch.qos.logback.classic.LoggerContext; -import it.gov.pagopa.arc.exception.custom.BizEventsInvocationException; -import it.gov.pagopa.arc.exception.custom.BizEventsReceiptNotFoundException; -import it.gov.pagopa.arc.exception.custom.BizEventsTransactionNotFoundException; -import it.gov.pagopa.arc.utils.MemoryAppender; import it.gov.pagopa.arc.exception.custom.*; +import it.gov.pagopa.arc.utils.MemoryAppender; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @@ -27,6 +22,8 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; +import static org.mockito.Mockito.doThrow; + @ExtendWith({SpringExtension.class, MockitoExtension.class}) @WebMvcTest(value = {ArcExceptionHandlerTest.TestController.class}) @ContextConfiguration(classes = { @@ -152,4 +149,36 @@ void givenRequestWhenBizEventsServiceReturnNotFoundErrorThenHandleBizEventsNotFo Assertions.assertTrue(memoryAppender.getLoggedEvents().get(0).getFormattedMessage().contains("A class it.gov.pagopa.arc.exception.custom.BizEventsReceiptNotFoundException occurred handling request GET /test/TRANSACTION_ID/pdf: HttpStatus 404 - Error")); } + @Test + void givenRequestWhenPullPaymentReturnBadRequestErrorThenHandlePullPaymentInvalidRequestException() throws Exception { + doThrow(new PullPaymentInvalidRequestException("Error")).when(testControllerSpy).testEndpoint(); + + mockMvc.perform(MockMvcRequestBuilders.get("/test") + .param(DATA, DATA) + .header(HEADER,HEADER) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isBadRequest()) + .andExpect(MockMvcResultMatchers.jsonPath("$.error").value("invalid_request")) + .andExpect(MockMvcResultMatchers.jsonPath("$.error_description").value("Error")); + + Assertions.assertTrue(memoryAppender.getLoggedEvents().get(0).getFormattedMessage().contains("A class it.gov.pagopa.arc.exception.custom.PullPaymentInvalidRequestException occurred handling request GET /test: HttpStatus 400 - Error")); + } + + @Test + void givenRequestWhenPullPaymentReturnErrorThenHandlePullPaymentInvocationException() throws Exception { + doThrow(new PullPaymentInvocationException("Error")).when(testControllerSpy).testEndpoint(); + + mockMvc.perform(MockMvcRequestBuilders.get("/test") + .param(DATA, DATA) + .header(HEADER,HEADER) + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + .andExpect(MockMvcResultMatchers.status().isInternalServerError()) + .andExpect(MockMvcResultMatchers.jsonPath("$.error").value("generic_error")) + .andExpect(MockMvcResultMatchers.jsonPath("$.error_description").value("Error")); + + Assertions.assertTrue(memoryAppender.getLoggedEvents().get(0).getFormattedMessage().contains("A class it.gov.pagopa.arc.exception.custom.PullPaymentInvocationException occurred handling request GET /test: HttpStatus 500 - Error")); + } + } \ No newline at end of file diff --git a/src/test/resources/stub/mappings/pullPaymentService/pullPayment_Get_PaymentNotices_BAD_REQUEST.json b/src/test/resources/stub/mappings/pullPaymentService/pullPayment_Get_PaymentNotices_BAD_REQUEST.json new file mode 100644 index 00000000..1ce46f5a --- /dev/null +++ b/src/test/resources/stub/mappings/pullPaymentService/pullPayment_Get_PaymentNotices_BAD_REQUEST.json @@ -0,0 +1,25 @@ +{ + "request": { + "method": "GET", + "urlPathPattern": "/pullPaymentMock/payment-notices/v1", + "headers": { + "Ocp-Apim-Subscription-Key": { + "matches": "x_api_key([0-9]?)+" + }, + "x-tax-code": { + "matches": "DUMMY_FISCAL_CODE_BAD_REQUEST" + } + }, + "queryParameters": { + "limit": { + "equalTo": "1000" + }, + "page": { + "equalTo": "0" + } + } + }, + "response": { + "status": 400 + } +} \ No newline at end of file