diff --git a/pom.xml b/pom.xml index 3427391..45deb9c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,10 +9,10 @@ 3.3.3 - it.gov.pagopa.onboarding.citizen - emd-onboarding-citizen - emd-onboarding-citizen - Onboarding Citizen Microservice + it.gov.pagopa.citizen + emd-citizen + emd-citizen + Citizen Microservice 0.0.1-SNAPSHOT @@ -24,18 +24,10 @@ org.springframework.boot spring-boot-starter - - org.springframework.boot - spring-boot-starter-web - org.springframework.boot spring-boot-starter-webflux - - org.springframework.boot - spring-boot-starter-data-mongodb - org.springframework.boot spring-boot-starter-data-mongodb-reactive @@ -48,27 +40,12 @@ org.springframework.boot spring-boot-starter-validation - - org.springframework.cloud - spring-cloud-starter-openfeign - - - org.springframework.boot - spring-boot-starter-data-redis - - - com.azure.spring - spring-cloud-azure-stream-binder-servicebus - + com.azure.spring spring-cloud-azure-starter-data-cosmos - - org.springframework.boot - spring-boot-starter-cache - org.springframework.cloud spring-cloud-stream-test-support @@ -83,17 +60,6 @@ lombok 1.18.30 - - - io.github.openfeign - feign-okhttp - 13.1 - - - org.codehaus.janino - janino - 3.1.11 - @@ -108,14 +74,8 @@ - org.springframework.cloud - spring-cloud-contract-wiremock - test - - - de.flapdoodle.embed - de.flapdoodle.embed.mongo.spring30x - 4.11.0 + io.projectreactor + reactor-test test @@ -136,6 +96,12 @@ pom import + + org.xmlunit + xmlunit-core + 2.10.0 + test + diff --git a/src/main/java/it/gov/pagopa/common/configuration/CustomReactiveMongoHealthIndicator.java b/src/main/java/it/gov/pagopa/common/configuration/CustomReactiveMongoHealthIndicator.java new file mode 100644 index 0000000..d713e4e --- /dev/null +++ b/src/main/java/it/gov/pagopa/common/configuration/CustomReactiveMongoHealthIndicator.java @@ -0,0 +1,28 @@ +package it.gov.pagopa.common.configuration; + +import org.bson.Document; +import org.springframework.boot.actuate.health.AbstractReactiveHealthIndicator; +import org.springframework.boot.actuate.health.Health; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import org.springframework.util.Assert; +import reactor.core.publisher.Mono; + +public class CustomReactiveMongoHealthIndicator extends AbstractReactiveHealthIndicator { + + private final ReactiveMongoTemplate reactiveMongoTemplate; + + public CustomReactiveMongoHealthIndicator(ReactiveMongoTemplate reactiveMongoTemplate) { + super("Mongo health check failed"); + Assert.notNull(reactiveMongoTemplate, "ReactiveMongoTemplate must not be null"); + this.reactiveMongoTemplate = reactiveMongoTemplate; + } + + @Override + protected Mono doHealthCheck(Health.Builder builder) { + Mono buildInfo = this.reactiveMongoTemplate.executeCommand("{ isMaster: 1 }"); + return buildInfo.map(document -> builderUp(builder, document)); + } + private Health builderUp(Health.Builder builder, Document document) { + return builder.up().withDetail("maxWireVersion", document.getInteger("maxWireVersion")).build(); + } +} diff --git a/src/main/java/it/gov/pagopa/common/configuration/MongoConfig.java b/src/main/java/it/gov/pagopa/common/configuration/MongoConfig.java new file mode 100644 index 0000000..aa906e0 --- /dev/null +++ b/src/main/java/it/gov/pagopa/common/configuration/MongoConfig.java @@ -0,0 +1,104 @@ +package it.gov.pagopa.common.configuration; + +import com.mongodb.lang.NonNull; +import it.gov.pagopa.common.utils.CommonConstants; +import lombok.Setter; +import org.bson.types.Decimal128; +import org.springframework.boot.autoconfigure.mongo.MongoClientSettingsBuilderCustomizer; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.convert.converter.Converter; +import org.springframework.data.convert.ReadingConverter; +import org.springframework.data.convert.WritingConverter; +import org.springframework.data.mongodb.core.convert.MongoCustomConversions; + +import java.math.BigDecimal; +import java.time.OffsetDateTime; +import java.util.Arrays; +import java.util.Date; +import java.util.concurrent.TimeUnit; + +@Configuration +public class MongoConfig { + + @Configuration + @ConfigurationProperties(prefix = "spring.data.mongodb.config") + public static class MongoDbCustomProperties { + @Setter + ConnectionPoolSettings connectionPool; + + @Setter + static class ConnectionPoolSettings { + int maxSize; + int minSize; + long maxWaitTimeMS; + long maxConnectionLifeTimeMS; + long maxConnectionIdleTimeMS; + int maxConnecting; + } + + } + + @Bean + public MongoClientSettingsBuilderCustomizer customizer(MongoDbCustomProperties mongoDbCustomProperties) { + return builder -> builder.applyToConnectionPoolSettings( + connectionPool -> { + connectionPool.maxSize(mongoDbCustomProperties.connectionPool.maxSize); + connectionPool.minSize(mongoDbCustomProperties.connectionPool.minSize); + connectionPool.maxWaitTime(mongoDbCustomProperties.connectionPool.maxWaitTimeMS, TimeUnit.MILLISECONDS); + connectionPool.maxConnectionLifeTime(mongoDbCustomProperties.connectionPool.maxConnectionLifeTimeMS, TimeUnit.MILLISECONDS); + connectionPool.maxConnectionIdleTime(mongoDbCustomProperties.connectionPool.maxConnectionIdleTimeMS, TimeUnit.MILLISECONDS); + connectionPool.maxConnecting(mongoDbCustomProperties.connectionPool.maxConnecting); + }); + } + + @Bean + public MongoCustomConversions mongoCustomConversions() { + return new MongoCustomConversions(Arrays.asList( + // BigDecimal support + new BigDecimalDecimal128Converter(), + new Decimal128BigDecimalConverter(), + + // OffsetDateTime support + new OffsetDateTimeWriteConverter(), + new OffsetDateTimeReadConverter() + )); + } + + @WritingConverter + private static class BigDecimalDecimal128Converter implements Converter { + + @Override + public Decimal128 convert(@NonNull BigDecimal source) { + return new Decimal128(source); + } + } + + @ReadingConverter + private static class Decimal128BigDecimalConverter implements Converter { + + @Override + public BigDecimal convert(@NonNull Decimal128 source) { + return source.bigDecimalValue(); + } + + } + + @WritingConverter + public static class OffsetDateTimeWriteConverter implements Converter { + @Override + public Date convert(OffsetDateTime offsetDateTime) { + return Date.from(offsetDateTime.toInstant()); + } + } + + @ReadingConverter + public static class OffsetDateTimeReadConverter implements Converter { + @Override + public OffsetDateTime convert(Date date) { + return date.toInstant().atZone(CommonConstants.ZONEID).toOffsetDateTime(); + } + } +} + diff --git a/src/main/java/it/gov/pagopa/common/configuration/MongoHealthConfig.java b/src/main/java/it/gov/pagopa/common/configuration/MongoHealthConfig.java new file mode 100644 index 0000000..d046ec2 --- /dev/null +++ b/src/main/java/it/gov/pagopa/common/configuration/MongoHealthConfig.java @@ -0,0 +1,14 @@ +package it.gov.pagopa.common.configuration; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; + +@Configuration +public class MongoHealthConfig { + @Bean + public CustomReactiveMongoHealthIndicator customMongoHealthIndicator(ReactiveMongoTemplate reactiveMongoTemplate) { + return new CustomReactiveMongoHealthIndicator(reactiveMongoTemplate); + } +} + diff --git a/src/main/java/it/gov/pagopa/common/utils/CommonConstants.java b/src/main/java/it/gov/pagopa/common/utils/CommonConstants.java new file mode 100644 index 0000000..79440b2 --- /dev/null +++ b/src/main/java/it/gov/pagopa/common/utils/CommonConstants.java @@ -0,0 +1,16 @@ +package it.gov.pagopa.common.utils; + +import java.time.ZoneId; + +public class CommonConstants { + + + public static final class ExceptionCode { + public static final String GENERIC_ERROR = "GENERIC_ERROR"; + private ExceptionCode() {} + } + + public static final ZoneId ZONEID = ZoneId.of("Europe/Rome"); + + private CommonConstants(){} +} diff --git a/src/main/java/it/gov/pagopa/common/utils/Utils.java b/src/main/java/it/gov/pagopa/common/utils/Utils.java index 704b8e7..28bfd53 100644 --- a/src/main/java/it/gov/pagopa/common/utils/Utils.java +++ b/src/main/java/it/gov/pagopa/common/utils/Utils.java @@ -1,5 +1,5 @@ package it.gov.pagopa.common.utils; -import it.gov.pagopa.onboarding.citizen.exception.custom.EmdEncryptionException; +import it.gov.pagopa.common.web.exception.EmdEncryptionException; import lombok.extern.slf4j.Slf4j; import java.nio.charset.StandardCharsets; @@ -30,10 +30,7 @@ public static String createSHA256(String fiscalCode) { } } - public static void logInfo(String message){ - log.info(inputSanify(message)); - } - private static String inputSanify(String message){ + public static String inputSanify(String message){ if (message != null) return message.replaceAll("[\\r\\n]", ""); return "[EMD][WARNING] Null log"; diff --git a/src/main/java/it/gov/pagopa/common/web/exception/ClientExceptionNoBody.java b/src/main/java/it/gov/pagopa/common/web/exception/ClientExceptionNoBody.java index e7d8182..f330ec2 100644 --- a/src/main/java/it/gov/pagopa/common/web/exception/ClientExceptionNoBody.java +++ b/src/main/java/it/gov/pagopa/common/web/exception/ClientExceptionNoBody.java @@ -2,7 +2,7 @@ import org.springframework.http.HttpStatus; -public class ClientExceptionNoBody extends ClientException{ +public class ClientExceptionNoBody extends ClientException { public ClientExceptionNoBody(HttpStatus httpStatus, String message) { super(httpStatus, message); diff --git a/src/main/java/it/gov/pagopa/common/web/exception/ClientExceptionWithBody.java b/src/main/java/it/gov/pagopa/common/web/exception/ClientExceptionWithBody.java index 06bfb81..7faac1c 100644 --- a/src/main/java/it/gov/pagopa/common/web/exception/ClientExceptionWithBody.java +++ b/src/main/java/it/gov/pagopa/common/web/exception/ClientExceptionWithBody.java @@ -4,7 +4,7 @@ import org.springframework.http.HttpStatus; @Getter -public class ClientExceptionWithBody extends ClientException{ +public class ClientExceptionWithBody extends ClientException { private final String code; public ClientExceptionWithBody(HttpStatus httpStatus, String code, String message){ diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/exception/custom/EmdEncryptionException.java b/src/main/java/it/gov/pagopa/common/web/exception/EmdEncryptionException.java similarity index 64% rename from src/main/java/it/gov/pagopa/onboarding/citizen/exception/custom/EmdEncryptionException.java rename to src/main/java/it/gov/pagopa/common/web/exception/EmdEncryptionException.java index 9994924..c846862 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/exception/custom/EmdEncryptionException.java +++ b/src/main/java/it/gov/pagopa/common/web/exception/EmdEncryptionException.java @@ -1,8 +1,7 @@ -package it.gov.pagopa.onboarding.citizen.exception.custom; +package it.gov.pagopa.common.web.exception; -import it.gov.pagopa.common.web.exception.ServiceException; -import it.gov.pagopa.onboarding.citizen.constants.OnboardingCitizenConstants.ExceptionCode; +import it.gov.pagopa.common.utils.CommonConstants.ExceptionCode; public class EmdEncryptionException extends ServiceException { diff --git a/src/main/java/it/gov/pagopa/common/web/exception/ErrorManager.java b/src/main/java/it/gov/pagopa/common/web/exception/ErrorManager.java index cead9f8..7b37f7a 100644 --- a/src/main/java/it/gov/pagopa/common/web/exception/ErrorManager.java +++ b/src/main/java/it/gov/pagopa/common/web/exception/ErrorManager.java @@ -1,11 +1,11 @@ package it.gov.pagopa.common.web.exception; import it.gov.pagopa.common.web.dto.ErrorDTO; -import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.lang.Nullable; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -23,7 +23,7 @@ public ErrorManager(@Nullable ErrorDTO defaultErrorDTO) { } @ExceptionHandler(RuntimeException.class) - protected ResponseEntity handleException(RuntimeException error, HttpServletRequest request) { + protected ResponseEntity handleException(RuntimeException error, ServerHttpRequest request) { logClientException(error, request); @@ -46,7 +46,7 @@ protected ResponseEntity handleException(RuntimeException error, HttpS .body(errorDTO); } } - public static void logClientException(RuntimeException error, HttpServletRequest request) { + public static void logClientException(RuntimeException error, ServerHttpRequest request) { Throwable unwrappedException = error.getCause() instanceof ServiceException ? error.getCause() : error; @@ -71,7 +71,7 @@ public static void logClientException(RuntimeException error, HttpServletRequest } } - public static String getRequestDetails(HttpServletRequest request) { - return "%s %s".formatted(request.getMethod(), request.getRequestURI()); + public static String getRequestDetails(ServerHttpRequest request) { + return "%s %s".formatted(request.getMethod(), request.getURI()); } } diff --git a/src/main/java/it/gov/pagopa/common/web/exception/ServiceExceptionHandler.java b/src/main/java/it/gov/pagopa/common/web/exception/ServiceExceptionHandler.java index ccd1014..4763292 100644 --- a/src/main/java/it/gov/pagopa/common/web/exception/ServiceExceptionHandler.java +++ b/src/main/java/it/gov/pagopa/common/web/exception/ServiceExceptionHandler.java @@ -1,13 +1,13 @@ package it.gov.pagopa.common.web.exception; -import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -27,7 +27,7 @@ public ServiceExceptionHandler(ErrorManager errorManager, Map handleException(ServiceException error, HttpServletRequest request) { + protected ResponseEntity handleException(ServiceException error, ServerHttpRequest request) { if (null != error.getPayload()) { return handleBodyProvidedException(error, request); } @@ -45,7 +45,7 @@ private ClientException transcodeException(ServiceException error) { return new ClientExceptionWithBody(httpStatus, error.getCode(), error.getMessage(), error.isPrintStackTrace(), error); } - private ResponseEntity handleBodyProvidedException(ServiceException error, HttpServletRequest request) { + private ResponseEntity handleBodyProvidedException(ServiceException error, ServerHttpRequest request) { ClientException clientException = transcodeException(error); ErrorManager.logClientException(clientException, request); diff --git a/src/main/java/it/gov/pagopa/common/web/exception/ValidationExceptionHandler.java b/src/main/java/it/gov/pagopa/common/web/exception/ValidationExceptionHandler.java index 96688c3..b7873ff 100644 --- a/src/main/java/it/gov/pagopa/common/web/exception/ValidationExceptionHandler.java +++ b/src/main/java/it/gov/pagopa/common/web/exception/ValidationExceptionHandler.java @@ -1,18 +1,19 @@ package it.gov.pagopa.common.web.exception; import it.gov.pagopa.common.web.dto.ErrorDTO; -import jakarta.servlet.http.HttpServletRequest; import lombok.extern.slf4j.Slf4j; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.http.HttpStatus; +import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.lang.Nullable; import org.springframework.validation.FieldError; -import org.springframework.web.bind.MethodArgumentNotValidException; -import org.springframework.web.bind.MissingRequestHeaderException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestControllerAdvice; +import org.springframework.web.bind.support.WebExchangeBindException; +import org.springframework.web.reactive.resource.NoResourceFoundException; +import org.springframework.web.server.MissingRequestValueException; import java.util.Optional; import java.util.stream.Collectors; @@ -29,10 +30,10 @@ public ValidationExceptionHandler(@Nullable ErrorDTO templateValidationErrorDTO) .orElse(new ErrorDTO("INVALID_REQUEST", "Invalid request")); } - @ExceptionHandler(MethodArgumentNotValidException.class) + @ExceptionHandler(WebExchangeBindException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) - public ErrorDTO handleValidationExceptions( - MethodArgumentNotValidException ex, HttpServletRequest request) { + public ErrorDTO handleWebExchangeBindException( + WebExchangeBindException ex, ServerHttpRequest request) { String message = ex.getBindingResult().getAllErrors().stream() .map(error -> { @@ -41,24 +42,34 @@ public ErrorDTO handleValidationExceptions( return String.format("[%s]: %s", fieldName, errorMessage); }).collect(Collectors.joining("; ")); - log.info("A MethodArgumentNotValidException occurred handling request {}: HttpStatus 400 - {}", + log.info("A WebExchangeBindException occurred handling request {}: HttpStatus 400 - {}", ErrorManager.getRequestDetails(request), message); log.debug("Something went wrong while validating http request", ex); return new ErrorDTO(templateValidationErrorDTO.getCode(), message); } - @ExceptionHandler(MissingRequestHeaderException.class) + @ExceptionHandler(MissingRequestValueException.class) @ResponseStatus(HttpStatus.BAD_REQUEST) - public ErrorDTO handleMissingRequestHeaderExceptions( - MissingRequestHeaderException ex, HttpServletRequest request) { + public ErrorDTO handleMissingRequestValueException(MissingRequestValueException e, ServerHttpRequest request) { - String message = ex.getMessage(); + log.info("A MissingRequestValueException occurred handling request {}: HttpStatus 400 - {}", + ErrorManager.getRequestDetails(request), e.getMessage()); + log.debug("Something went wrong due to a missing request value", e); - log.info("A MissingRequestHeaderException occurred handling request {}: HttpStatus 400 - {}", - ErrorManager.getRequestDetails(request), message); - log.debug("Something went wrong handling request", ex); + return new ErrorDTO(templateValidationErrorDTO.getCode(), templateValidationErrorDTO.getMessage()); + } - return new ErrorDTO(templateValidationErrorDTO.getCode(), message); + @ExceptionHandler(NoResourceFoundException.class) + @ResponseStatus(HttpStatus.NOT_FOUND) + public ErrorDTO handleNoResourceFoundException(NoResourceFoundException e, ServerHttpRequest request) { + + log.info("A NoResourceFoundException occurred handling request {}: HttpStatus 400 - {}", + ErrorManager.getRequestDetails(request), e.getMessage()); + log.debug("Something went wrong due to a missing request value", e); + + return new ErrorDTO(templateValidationErrorDTO.getCode(), templateValidationErrorDTO.getMessage()); } + + } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/EmdOnboardingCitizen.java b/src/main/java/it/gov/pagopa/onboarding/citizen/EmdCitizen.java similarity index 74% rename from src/main/java/it/gov/pagopa/onboarding/citizen/EmdOnboardingCitizen.java rename to src/main/java/it/gov/pagopa/onboarding/citizen/EmdCitizen.java index 92908d5..94b6308 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/EmdOnboardingCitizen.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/EmdCitizen.java @@ -4,10 +4,10 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication(scanBasePackages = "it.gov.pagopa") -public class EmdOnboardingCitizen { +public class EmdCitizen { public static void main(String[] args) { - SpringApplication.run(EmdOnboardingCitizen.class, args); + SpringApplication.run(EmdCitizen.class, args); } } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/exception/custom/ExceptionMap.java b/src/main/java/it/gov/pagopa/onboarding/citizen/configuration/ExceptionMap.java similarity index 95% rename from src/main/java/it/gov/pagopa/onboarding/citizen/exception/custom/ExceptionMap.java rename to src/main/java/it/gov/pagopa/onboarding/citizen/configuration/ExceptionMap.java index 33b3c81..141f65f 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/exception/custom/ExceptionMap.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/configuration/ExceptionMap.java @@ -1,4 +1,4 @@ -package it.gov.pagopa.onboarding.citizen.exception.custom; +package it.gov.pagopa.onboarding.citizen.configuration; import it.gov.pagopa.common.web.exception.ClientExceptionWithBody; diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerImpl.java b/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerImpl.java index a3b86c3..668325d 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerImpl.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerImpl.java @@ -3,7 +3,6 @@ import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; import it.gov.pagopa.onboarding.citizen.service.CitizenServiceImpl; import jakarta.validation.Valid; -import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.RestController; import reactor.core.publisher.Mono; @@ -22,35 +21,33 @@ public CitizenControllerImpl(CitizenServiceImpl citizenService) { @Override public Mono> saveCitizenConsent(@Valid CitizenConsentDTO citizenConsentDTO) { return citizenService.createCitizenConsent(citizenConsentDTO) - .map(consent -> new ResponseEntity<>(consent, HttpStatus.CREATED)); + .map(ResponseEntity::ok); } @Override public Mono> stateUpdate(@Valid CitizenConsentDTO citizenConsentDTO) { return citizenService.updateChannelState( - citizenConsentDTO.getHashedFiscalCode(), + citizenConsentDTO.getHashedFiscalCode(), //at this stage the fiscalCode has not yet been hashed citizenConsentDTO.getTppId(), citizenConsentDTO.getTppState()) - .map(consent -> new ResponseEntity<>(consent, HttpStatus.OK)); + .map(ResponseEntity::ok); } @Override public Mono> getConsentStatus(String fiscalCode, String tppId) { return citizenService.getConsentStatus(fiscalCode, tppId) - .map(consent -> new ResponseEntity<>(consent, HttpStatus.OK)); + .map(ResponseEntity::ok); } @Override public Mono>> getCitizenConsentsEnabled(String fiscalCode) { return citizenService.getListEnabledConsents(fiscalCode) - .collectList() - .map(consents -> new ResponseEntity<>(consents, HttpStatus.OK)); + .map(ResponseEntity::ok); } @Override public Mono>> getCitizenConsents(String fiscalCode) { return citizenService.getListAllConsents(fiscalCode) - .collectList() - .map(consents -> new ResponseEntity<>(consents, HttpStatus.OK)); + .map(ResponseEntity::ok); } } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentDTO.java b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentDTO.java index 8957ef4..9151702 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentDTO.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/CitizenConsentDTO.java @@ -1,5 +1,6 @@ package it.gov.pagopa.onboarding.citizen.dto; +import com.fasterxml.jackson.annotation.JsonAlias; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; @@ -12,6 +13,7 @@ @AllArgsConstructor @NoArgsConstructor public class CitizenConsentDTO { + @JsonAlias("fiscalCode") private String hashedFiscalCode; private String tppId; private Boolean tppState; diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentMapperToDTO.java b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentObjectToDTOMapper.java similarity index 81% rename from src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentMapperToDTO.java rename to src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentObjectToDTOMapper.java index cb4a462..885bf6f 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentMapperToDTO.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/dto/mapper/CitizenConsentObjectToDTOMapper.java @@ -6,9 +6,9 @@ import org.springframework.stereotype.Service; @Service -public class CitizenConsentMapperToDTO { +public class CitizenConsentObjectToDTOMapper { - public CitizenConsentDTO citizenConsentMapper(CitizenConsent citizenConsent){ + public CitizenConsentDTO map(CitizenConsent citizenConsent){ return CitizenConsentDTO.builder() .tppState(citizenConsent.getTppState()) .tppId(citizenConsent.getTppId()) diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/model/CitizenConsent.java b/src/main/java/it/gov/pagopa/onboarding/citizen/model/CitizenConsent.java index d717c4a..4c8657e 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/model/CitizenConsent.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/model/CitizenConsent.java @@ -1,7 +1,5 @@ package it.gov.pagopa.onboarding.citizen.model; -import com.fasterxml.jackson.annotation.JsonAlias; -import com.fasterxml.jackson.annotation.JsonProperty; import lombok.Data; import lombok.NoArgsConstructor; import lombok.experimental.SuperBuilder; @@ -15,19 +13,12 @@ @NoArgsConstructor public class CitizenConsent { - @JsonAlias("_id") private String id; - @JsonProperty("hashed_fiscal_code") private String hashedFiscalCode; - @JsonProperty("tpp_id") private String tppId; - @JsonProperty("tpp_state") private Boolean tppState; - @JsonProperty("user_id") private String userId; - @JsonProperty("creation_date") private LocalDateTime creationDate; - @JsonProperty("last_update_date") private LocalDateTime lastUpdateDate; } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentMapperToObject.java b/src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentDTOToObjectMapper.java similarity index 80% rename from src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentMapperToObject.java rename to src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentDTOToObjectMapper.java index bbd2f55..195aebe 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentMapperToObject.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/model/mapper/CitizenConsentDTOToObjectMapper.java @@ -6,9 +6,9 @@ import org.springframework.stereotype.Service; @Service -public class CitizenConsentMapperToObject{ +public class CitizenConsentDTOToObjectMapper { - public CitizenConsent citizenConsentDTOMapper(CitizenConsentDTO citizenConsentDTO){ + public CitizenConsent map(CitizenConsentDTO citizenConsentDTO){ return CitizenConsent.builder() .tppState(true) .tppId(citizenConsentDTO.getTppId()) diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenService.java b/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenService.java index a1846b5..ae98fcd 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenService.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenService.java @@ -1,14 +1,15 @@ package it.gov.pagopa.onboarding.citizen.service; import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; +import java.util.List; + public interface CitizenService { Mono createCitizenConsent(CitizenConsentDTO citizenConsent); - Mono updateChannelState(String hashedFiscalCode, String tppId, boolean tppState); + Mono updateChannelState(String fiscalCode, String tppId, boolean tppState); Mono getConsentStatus(String fiscalCode, String tppId); - Flux getListEnabledConsents(String fiscalCode); - Flux getListAllConsents(String fiscalCode); + Mono> getListEnabledConsents(String fiscalCode); + Mono> getListAllConsents(String fiscalCode); } diff --git a/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceImpl.java b/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceImpl.java index 5c06e25..14e9875 100644 --- a/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceImpl.java +++ b/src/main/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceImpl.java @@ -3,28 +3,30 @@ import it.gov.pagopa.common.utils.Utils; import it.gov.pagopa.onboarding.citizen.constants.OnboardingCitizenConstants.ExceptionName; import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; -import it.gov.pagopa.onboarding.citizen.dto.mapper.CitizenConsentMapperToDTO; -import it.gov.pagopa.onboarding.citizen.exception.custom.ExceptionMap; +import it.gov.pagopa.onboarding.citizen.dto.mapper.CitizenConsentObjectToDTOMapper; +import it.gov.pagopa.onboarding.citizen.configuration.ExceptionMap; import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; -import it.gov.pagopa.onboarding.citizen.model.mapper.CitizenConsentMapperToObject; +import it.gov.pagopa.onboarding.citizen.model.mapper.CitizenConsentDTOToObjectMapper; import it.gov.pagopa.onboarding.citizen.repository.CitizenRepository; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import java.time.LocalDateTime; +import java.util.List; -import static it.gov.pagopa.common.utils.Utils.logInfo; +import static it.gov.pagopa.common.utils.Utils.inputSanify; @Service +@Slf4j public class CitizenServiceImpl implements CitizenService { private final CitizenRepository citizenRepository; - private final CitizenConsentMapperToDTO mapperToDTO; - private final CitizenConsentMapperToObject mapperToObject; + private final CitizenConsentObjectToDTOMapper mapperToDTO; + private final CitizenConsentDTOToObjectMapper mapperToObject; private final ExceptionMap exceptionMap; - public CitizenServiceImpl(CitizenRepository citizenRepository, CitizenConsentMapperToDTO mapperToDTO, CitizenConsentMapperToObject mapperToObject, ExceptionMap exceptionMap) { + public CitizenServiceImpl(CitizenRepository citizenRepository, CitizenConsentObjectToDTOMapper mapperToDTO, CitizenConsentDTOToObjectMapper mapperToObject, ExceptionMap exceptionMap) { this.citizenRepository = citizenRepository; this.mapperToDTO = mapperToDTO; this.mapperToObject = mapperToObject; @@ -33,22 +35,23 @@ public CitizenServiceImpl(CitizenRepository citizenRepository, CitizenConsentMap @Override public Mono createCitizenConsent(CitizenConsentDTO citizenConsentDTO) { - logInfo("[EMD][CREATE-CITIZEN-CONSENT] Received message: %s".formatted(citizenConsentDTO.toString())); - CitizenConsent citizenConsent = mapperToObject.citizenConsentDTOMapper(citizenConsentDTO); + log.info("[EMD][CITIZEN][CREATE] Received message: {}",inputSanify(citizenConsentDTO.toString())); + CitizenConsent citizenConsent = mapperToObject.map(citizenConsentDTO); String hashedFiscalCode = Utils.createSHA256(citizenConsent.getHashedFiscalCode()); citizenConsent.setHashedFiscalCode(hashedFiscalCode); citizenConsent.setCreationDate(LocalDateTime.now()); citizenConsent.setLastUpdateDate(LocalDateTime.now()); - return citizenRepository.save(citizenConsent) - .doOnSuccess(savedConsent -> logInfo("[EMD][CREATE-CITIZEN-CONSENT] Created")) - .map(mapperToDTO::citizenConsentMapper); + .map(mapperToDTO::map) + .doOnSuccess(savedConsent -> log.info("[EMD][CREATE-CITIZEN-CONSENT] Created")); + } @Override - public Mono updateChannelState(String hashedFiscalCode, String tppId, boolean tppState) { - logInfo("[EMD][UPDATE-CHANNEL-STATE] Received hashedFiscalCode: %s and tppId: %s with state: %s".formatted(hashedFiscalCode, tppId, tppState)); - + public Mono updateChannelState(String fiscalCode, String tppId, boolean tppState) { + String hashedFiscalCode = Utils.createSHA256(fiscalCode); + log.info("[EMD][[CITIZEN][UPDATE-CHANNEL-STATE] Received hashedFiscalCode: {} and tppId: {} with state: {}" + ,hashedFiscalCode, inputSanify(tppId), tppState); return citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId) .switchIfEmpty(Mono.error(exceptionMap.getException(ExceptionName.CITIZEN_NOT_ONBOARDED))) .flatMap(citizenConsent -> { @@ -56,37 +59,45 @@ public Mono updateChannelState(String hashedFiscalCode, Strin citizenConsent.setLastUpdateDate(LocalDateTime.now()); return citizenRepository.save(citizenConsent); }) - .doOnSuccess(savedConsent -> logInfo("[EMD][UPDATE-CHANNEL-STATE] Updated state")) - .map(mapperToDTO::citizenConsentMapper); + .map(mapperToDTO::map) + .doOnSuccess(savedConsent -> log.info("[EMD][[CITIZEN][UPDATE-CHANNEL-STATE] Updated state")); } @Override public Mono getConsentStatus(String fiscalCode, String tppId) { - logInfo("[EMD][GET-CONSENT-STATUS] Received fiscalCode: %s and tppId: %s".formatted(fiscalCode, tppId)); String hashedFiscalCode = Utils.createSHA256(fiscalCode); - + log.info("[EMD][CITIZEN][GET-CONSENT-STATUS] Received hashedFiscalCode: {} and tppId: {}",hashedFiscalCode,inputSanify(tppId)); return citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId) .switchIfEmpty(Mono.error(exceptionMap.getException(ExceptionName.CITIZEN_NOT_ONBOARDED))) - .map(mapperToDTO::citizenConsentMapper); + .map(mapperToDTO::map) + .doOnSuccess(consent -> log.info("[EMD][CITIZEN][GET-CONSENT-STATUS] Consent found:: {}",consent)); + } @Override - public Flux getListEnabledConsents(String fiscalCode) { - logInfo("[EMD][FIND-CITIZEN-CONSENTS-ENABLED] Received fiscalCode: %s".formatted(fiscalCode)); + public Mono> getListEnabledConsents(String fiscalCode) { String hashedFiscalCode = Utils.createSHA256(fiscalCode); - + log.info("[EMD][CITIZEN][FIND-CITIZEN-CONSENTS-ENABLED] Received hashedFiscalCode: {}",hashedFiscalCode); return citizenRepository.findByHashedFiscalCodeAndTppStateTrue(hashedFiscalCode) - .map(mapperToDTO::citizenConsentMapper) - .doOnNext(citizenConsentDTO -> logInfo("[EMD][FIND-CITIZEN-CONSENT-ENABLED] Consents enabled found: %s".formatted(citizenConsentDTO))); + .collectList() + .map(consentList -> consentList.stream() + .map(mapperToDTO::map) + .toList() + ) + .doOnSuccess(consentList -> log.info("EMD][CITIZEN][FIND-CITIZEN-CONSENTS-ENABLED] Consents founded: {}",(consentList.size()))); + } @Override - public Flux getListAllConsents(String fiscalCode) { - logInfo("[EMD][FIND-ALL-CITIZEN-CONSENTS] Received fiscalCode: %s".formatted(fiscalCode)); + public Mono> getListAllConsents(String fiscalCode) { String hashedFiscalCode = Utils.createSHA256(fiscalCode); - + log.info("[EMD][CITIZEN][FIND-ALL-CITIZEN-CONSENTS] Received hashedFiscalCode: {}",(hashedFiscalCode)); return citizenRepository.findByHashedFiscalCode(hashedFiscalCode) - .map(mapperToDTO::citizenConsentMapper) - .doOnNext(citizenConsentDTO -> logInfo("[EMD][FIND-ALL-CITIZEN-CONSENTS] Consents found: %s".formatted(citizenConsentDTO))); + .collectList() + .map(consentList -> consentList.stream() + .map(mapperToDTO::map) + .toList() + ) + .doOnSuccess(consentList -> log.info("[EMD][CITIZEN][FIND-ALL-CITIZEN-CONSENTS] Consents found:: {}",consentList)); } } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 9c501d8..9dc143c 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -6,13 +6,6 @@ spring: name: "@project.artifactId@" version: "@project.version@" jmx.enabled: true - resources: - static-locations: classpath:/static/ - cache: - cachecontrol: - max-age: 3600 - no-transform: true - must-revalidate: true config: activate: on-profile: default @@ -20,19 +13,30 @@ spring: mongodb: database: ${MONGODB_DBNAME:mil} uri: ${MONGODB_URI:mongodb://localhost:27017} + config: + connectionPool: + maxSize: ${MONGODB_CONNECTIONPOOL_MAX_SIZE:100} + minSize: ${MONGODB_CONNECTIONPOOL_MIN_SIZE:5} + maxWaitTimeMS: ${MONGODB_CONNECTIONPOOL_MAX_WAIT_MS:120000} + maxConnectionLifeTimeMS: ${MONGODB_CONNECTIONPOOL_MAX_CONNECTION_LIFE_MS:0} + maxConnectionIdleTimeMS: ${MONGODB_CONNECTIONPOOL_MAX_CONNECTION_IDLE_MS:120000} + maxConnecting: ${MONGODB_CONNECTIONPOOL_MAX_CONNECTING:2} + +server: + port: ${CITIZEN_PORT:8084} management: health: - redis.enabled: ${REDIS_CACHE_ENABLED:false} - mongo.enabled: ${HEALTH_MONGO_ENABLED:true} + mongo.enabled: ${HEALTH_MONGO_ENABLED:false} endpoint: health: + show-details: always probes.enabled: true group: readiness.include: "*" - liveness.include: livenessState,diskSpace,ping,binders + liveness.include: livenessState,diskSpace,ping endpoints: jmx: exposure.include: "*" web: - exposure.include: info, health \ No newline at end of file + exposure.include: info, health diff --git a/src/test/java/it/gov/pagopa/common/configuration/CustomMongoHealthIndicatorTest.java b/src/test/java/it/gov/pagopa/common/configuration/CustomMongoHealthIndicatorTest.java new file mode 100644 index 0000000..8b0b8c5 --- /dev/null +++ b/src/test/java/it/gov/pagopa/common/configuration/CustomMongoHealthIndicatorTest.java @@ -0,0 +1,50 @@ +package it.gov.pagopa.common.configuration; + +import com.mongodb.MongoException; +import org.bson.Document; +import org.junit.jupiter.api.Test; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; +import org.springframework.data.mongodb.core.ReactiveMongoTemplate; +import reactor.core.publisher.Mono; +import reactor.test.StepVerifier; + +import java.time.Duration; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.mock; + + +class CustomMongoHealthIndicatorTest { + @Test + void testMongoIsUp() { + Document buildInfo = mock(Document.class); + given(buildInfo.getInteger("maxWireVersion")).willReturn(10); + ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class); + given(reactiveMongoTemplate.executeCommand("{ isMaster: 1 }")).willReturn(Mono.just(buildInfo)); + CustomReactiveMongoHealthIndicator customReactiveMongoHealthIndicator = new CustomReactiveMongoHealthIndicator( + reactiveMongoTemplate); + Mono health = customReactiveMongoHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith(h -> { + assertThat(h.getStatus()).isEqualTo(Status.UP); + assertThat(h.getDetails()).containsOnlyKeys("maxWireVersion"); + assertThat(h.getDetails()).containsEntry("maxWireVersion", 10); + }).expectComplete().verify(Duration.ofSeconds(30)); + } + + @Test + void testMongoIsDown() { + ReactiveMongoTemplate reactiveMongoTemplate = mock(ReactiveMongoTemplate.class); + given(reactiveMongoTemplate.executeCommand("{ isMaster: 1 }")).willThrow(new MongoException("Connection failed")); + CustomReactiveMongoHealthIndicator customReactiveMongoHealthIndicator = new CustomReactiveMongoHealthIndicator( + reactiveMongoTemplate); + Mono health = customReactiveMongoHealthIndicator.health(); + StepVerifier.create(health).consumeNextWith(h -> { + assertThat(h.getStatus()).isEqualTo(Status.DOWN); + assertThat(h.getDetails()).containsOnlyKeys("error"); + assertThat(h.getDetails()).containsEntry("error", MongoException.class.getName() + ": Connection failed"); + }).expectComplete().verify(Duration.ofSeconds(30)); + } + +} diff --git a/src/test/java/it/gov/pagopa/common/utils/UtilsTest.java b/src/test/java/it/gov/pagopa/common/utils/UtilsTest.java index 52ebf02..3fa89a3 100644 --- a/src/test/java/it/gov/pagopa/common/utils/UtilsTest.java +++ b/src/test/java/it/gov/pagopa/common/utils/UtilsTest.java @@ -1,7 +1,7 @@ package it.gov.pagopa.common.utils; -import it.gov.pagopa.onboarding.citizen.exception.custom.EmdEncryptionException; +import it.gov.pagopa.common.web.exception.EmdEncryptionException; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.MockedStatic; @@ -20,15 +20,16 @@ class UtilsTest { @Test - void createSHA256_Ko_NoSuchAlgorithm() throws NoSuchAlgorithmException { + void createSHA256_Ko_NoSuchAlgorithm() { try (MockedStatic mockedStatic = Mockito.mockStatic(MessageDigest.class)) { mockedStatic.when(() -> MessageDigest.getInstance(any())) - .thenThrow(NoSuchAlgorithmException.class); + .thenThrow(new NoSuchAlgorithmException("SHA-256 not available")); EmdEncryptionException exception = assertThrows(EmdEncryptionException.class, () -> Utils.createSHA256("")); + + assertEquals("SHA-256 not available", exception.getCause().getMessage()); } } - @Test void createSHA256_Ok(){ String toHash = "RSSMRA98B18L049O"; diff --git a/src/test/java/it/gov/pagopa/common/web/exception/ErrorManagerTest.java b/src/test/java/it/gov/pagopa/common/web/exception/ErrorManagerTest.java index 832e8c7..078708d 100644 --- a/src/test/java/it/gov/pagopa/common/web/exception/ErrorManagerTest.java +++ b/src/test/java/it/gov/pagopa/common/web/exception/ErrorManagerTest.java @@ -10,43 +10,37 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; import org.springframework.boot.test.mock.mockito.SpyBean; import org.springframework.http.HttpStatus; import org.springframework.http.MediaType; 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.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import java.util.regex.Pattern; -@ExtendWith(SpringExtension.class) -@WebMvcTest(value = { - ErrorManagerTest.TestController.class}, excludeAutoConfiguration = SecurityAutoConfiguration.class) +@WebFluxTest(value = { + ErrorManagerTest.TestController.class}, excludeAutoConfiguration = SecurityAutoConfiguration.class) @ContextConfiguration(classes = {ErrorManagerTest.TestController.class, ErrorManager.class}) +@Slf4j class ErrorManagerTest { private static final String EXPECTED_GENERIC_ERROR = "{\"code\":\"Error\",\"message\":\"Something gone wrong\"}"; @Autowired - private MockMvc mockMvc; - + private WebTestClient webTestClient; @SpyBean private TestController testControllerSpy; + private static MemoryAppender memoryAppender; @RestController - @Slf4j static class TestController { - @GetMapping("/test") String testEndpoint() { return "OK"; @@ -54,98 +48,106 @@ String testEndpoint() { } @BeforeAll - static void configureMemoryAppender(){ + static void configureMemoryAppender() { memoryAppender = new MemoryAppender(); memoryAppender.setContext((LoggerContext) LoggerFactory.getILoggerFactory()); memoryAppender.start(); } @BeforeEach - void clearMemoryAppender(){ + void clearMemoryAppender() { memoryAppender.reset(); - ch.qos.logback.classic.Logger logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ErrorManager.class.getName()); logger.setLevel(ch.qos.logback.classic.Level.INFO); logger.addAppender(memoryAppender); } @Test - void handleExceptionClientExceptionNoBody() throws Exception { + void handleExceptionClientExceptionNoBody() { Mockito.doThrow( - new ClientExceptionNoBody(HttpStatus.BAD_REQUEST, "NOTFOUND ClientExceptionNoBody")) - .when(testControllerSpy).testEndpoint(); + new ClientExceptionNoBody(HttpStatus.BAD_REQUEST, "NOTFOUND ClientExceptionNoBody")) + .when(testControllerSpy).testEndpoint(); - mockMvc.perform(MockMvcRequestBuilders.get("/test") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()); + webTestClient.get() + .uri("/test") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().isBadRequest(); checkStackTraceSuppressedLog(memoryAppender, "A ClientExceptionNoBody occurred handling request GET /test: HttpStatus 400 BAD_REQUEST - NOTFOUND ClientExceptionNoBody at it.gov.pagopa.common.web.exception.ErrorManagerTest\\$TestController.testEndpoint\\(ErrorManagerTest.java:[0-9]+\\)"); - } @Test - void handleExceptionClientExceptionWithBody() throws Exception { + void handleExceptionClientExceptionWithBody() { Mockito.doThrow( - new ClientExceptionWithBody(HttpStatus.BAD_REQUEST, "Error", "Error ClientExceptionWithBody")) - .when(testControllerSpy).testEndpoint(); + new ClientExceptionWithBody(HttpStatus.BAD_REQUEST, "Error", "Error ClientExceptionWithBody")) + .when(testControllerSpy).testEndpoint(); - mockMvc.perform(MockMvcRequestBuilders.get("/test") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"code\":\"Error\",\"message\":\"Error ClientExceptionWithBody\"}")); + webTestClient.get() + .uri("/test") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().isBadRequest() + .expectBody() + .json("{\"code\":\"Error\",\"message\":\"Error ClientExceptionWithBody\"}"); Mockito.doThrow( - new ClientExceptionWithBody(HttpStatus.BAD_REQUEST, "Error", "Error ClientExceptionWithBody", - new Exception())) - .when(testControllerSpy).testEndpoint(); - - mockMvc.perform(MockMvcRequestBuilders.get("/test") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.content() - .json("{\"code\":\"Error\",\"message\":\"Error ClientExceptionWithBody\"}")); + new ClientExceptionWithBody(HttpStatus.BAD_REQUEST, "Error", "Error ClientExceptionWithBody", + new Exception())) + .when(testControllerSpy).testEndpoint(); + + webTestClient.get() + .uri("/test") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().isBadRequest() + .expectBody() + .json("{\"code\":\"Error\",\"message\":\"Error ClientExceptionWithBody\"}"); } @Test - void handleExceptionClientExceptionTest() throws Exception { - + void handleExceptionClientExceptionTest() { Mockito.doThrow(ClientException.class) - .when(testControllerSpy).testEndpoint(); + .when(testControllerSpy).testEndpoint(); - mockMvc.perform(MockMvcRequestBuilders.get("/test") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()) - .andExpect(MockMvcResultMatchers.content() - .json(EXPECTED_GENERIC_ERROR)); + webTestClient.get() + .uri("/test") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().is5xxServerError() + .expectBody() + .json(EXPECTED_GENERIC_ERROR); checkStackTraceSuppressedLog(memoryAppender, "A ClientException occurred handling request GET /test: HttpStatus null - null at UNKNOWN"); memoryAppender.reset(); Mockito.doThrow( - new ClientException(HttpStatus.BAD_REQUEST, "ClientException with httpStatus and message")) - .when(testControllerSpy).testEndpoint(); + new ClientException(HttpStatus.BAD_REQUEST, "ClientException with httpStatus and message")) + .when(testControllerSpy).testEndpoint(); - mockMvc.perform(MockMvcRequestBuilders.get("/test") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()) - .andExpect(MockMvcResultMatchers.content() - .json(EXPECTED_GENERIC_ERROR)); + webTestClient.get() + .uri("/test") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().is5xxServerError() + .expectBody() + .json(EXPECTED_GENERIC_ERROR); checkStackTraceSuppressedLog(memoryAppender, "A ClientException occurred handling request GET /test: HttpStatus 400 BAD_REQUEST - ClientException with httpStatus and message at it.gov.pagopa.common.web.exception.ErrorManagerTest\\$TestController.testEndpoint\\(ErrorManagerTest.java:[0-9]+\\)"); memoryAppender.reset(); - Mockito.doThrow(new ClientException(HttpStatus.BAD_REQUEST, - "ClientException with httpStatus, message and throwable", new Throwable())) - .when(testControllerSpy).testEndpoint(); + "ClientException with httpStatus, message and throwable", new Throwable())) + .when(testControllerSpy).testEndpoint(); - mockMvc.perform(MockMvcRequestBuilders.get("/test") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()) - .andExpect(MockMvcResultMatchers.content() - .json(EXPECTED_GENERIC_ERROR)); + webTestClient.get() + .uri("/test") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().is5xxServerError() + .expectBody() + .json(EXPECTED_GENERIC_ERROR); checkLog(memoryAppender, "Something went wrong handling request GET /test: HttpStatus 400 BAD_REQUEST - ClientException with httpStatus, message and throwable", @@ -155,15 +157,17 @@ void handleExceptionClientExceptionTest() throws Exception { } @Test - void handleExceptionRuntimeException() throws Exception { + void handleExceptionRuntimeException() { Mockito.doThrow(RuntimeException.class) - .when(testControllerSpy).testEndpoint(); - - mockMvc.perform(MockMvcRequestBuilders.get("/test") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()) - .andExpect(MockMvcResultMatchers.content() - .json(EXPECTED_GENERIC_ERROR)); + .when(testControllerSpy).testEndpoint(); + + webTestClient.get() + .uri("/test") + .accept(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().is5xxServerError() + .expectBody() + .json(EXPECTED_GENERIC_ERROR); } public static void checkStackTraceSuppressedLog(MemoryAppender memoryAppender, String expectedLoggedMessage) { diff --git a/src/test/java/it/gov/pagopa/common/web/exception/ServiceExceptionHandlerTest.java b/src/test/java/it/gov/pagopa/common/web/exception/ServiceExceptionHandlerTest.java index 43397a1..0896c70 100644 --- a/src/test/java/it/gov/pagopa/common/web/exception/ServiceExceptionHandlerTest.java +++ b/src/test/java/it/gov/pagopa/common/web/exception/ServiceExceptionHandlerTest.java @@ -9,28 +9,24 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; +import org.springframework.http.HttpMethod; import org.springframework.http.MediaType; 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.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; -@ExtendWith(SpringExtension.class) -@WebMvcTest(value = { +@WebFluxTest(value = { ServiceExceptionHandlerTest.TestController.class}, excludeAutoConfiguration = SecurityAutoConfiguration.class) @ContextConfiguration(classes = {ServiceExceptionHandler.class, ServiceExceptionHandlerTest.TestController.class, ErrorManager.class}) class ServiceExceptionHandlerTest { @Autowired - private MockMvc mockMvc; + private WebTestClient webTestClient; private static MemoryAppender memoryAppender; @@ -74,22 +70,29 @@ static class ErrorPayloadTest implements ServiceExceptionPayload { } @Test - void testSimpleException() throws Exception{ - mockMvc.perform(MockMvcRequestBuilders.get("/test") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()) - .andExpect(MockMvcResultMatchers.content().json("{\"code\":\"DUMMY_CODE\",\"message\":\"DUMMY_MESSAGE\"}", false)); + void testSimpleException(){ + webTestClient.method(HttpMethod.GET) + .uri("/test") + .contentType(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().is5xxServerError() + .expectBody() + .json("{\"code\":\"DUMMY_CODE\",\"message\":\"DUMMY_MESSAGE\"}", false); ErrorManagerTest.checkStackTraceSuppressedLog(memoryAppender, "A ServiceException occurred handling request GET /test: HttpStatus 500 INTERNAL_SERVER_ERROR - DUMMY_CODE: DUMMY_MESSAGE at it.gov.pagopa.common.web.exception.ServiceExceptionHandlerTest\\$TestController.test\\(ServiceExceptionHandlerTest.java:[0-9]+\\)"); } @Test - void testCustomBodyException() throws Exception{ - mockMvc.perform(MockMvcRequestBuilders.get("/test/customBody") - .contentType(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isInternalServerError()) - .andExpect(MockMvcResultMatchers.content().json("{\"stringCode\":\"RESPONSE\",\"longCode\":0}", false)); + void testCustomBodyException(){ + + webTestClient.method(HttpMethod.GET) + .uri("/test/customBody") + .contentType(MediaType.APPLICATION_JSON) + .exchange() + .expectStatus().is5xxServerError() + .expectBody() + .json("{\"stringCode\":\"RESPONSE\",\"longCode\":0}", false); ErrorManagerTest.checkLog(memoryAppender, "Something went wrong handling request GET /test/customBody: HttpStatus 500 INTERNAL_SERVER_ERROR - DUMMY_CODE: DUMMY_MESSAGE", diff --git a/src/test/java/it/gov/pagopa/common/web/exception/ValidationExceptionHandlerTest.java b/src/test/java/it/gov/pagopa/common/web/exception/ValidationExceptionHandlerTest.java index d87f430..3236568 100644 --- a/src/test/java/it/gov/pagopa/common/web/exception/ValidationExceptionHandlerTest.java +++ b/src/test/java/it/gov/pagopa/common/web/exception/ValidationExceptionHandlerTest.java @@ -1,48 +1,37 @@ package it.gov.pagopa.common.web.exception; -import com.fasterxml.jackson.databind.ObjectMapper; + +import it.gov.pagopa.common.web.dto.ErrorDTO; import jakarta.validation.Valid; import jakarta.validation.constraints.NotBlank; import lombok.AllArgsConstructor; import lombok.Data; import lombok.NoArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; -import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; -import org.springframework.boot.test.mock.mockito.SpyBean; +import org.springframework.boot.test.autoconfigure.web.reactive.WebFluxTest; import org.springframework.http.MediaType; 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.request.MockMvcRequestBuilders; -import org.springframework.test.web.servlet.result.MockMvcResultMatchers; +import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RestController; -@ExtendWith({SpringExtension.class, MockitoExtension.class}) -@WebMvcTest(value = {ValidationExceptionHandlerTest.TestController.class}, excludeAutoConfiguration = SecurityAutoConfiguration.class) +import static org.assertj.core.api.Assertions.assertThat; + +@WebFluxTest(value = {ValidationExceptionHandlerTest.TestController.class}, excludeAutoConfiguration = SecurityAutoConfiguration.class) @ContextConfiguration(classes = { ValidationExceptionHandlerTest.TestController.class, ValidationExceptionHandler.class}) class ValidationExceptionHandlerTest { @Autowired - private MockMvc mockMvc; - - @Autowired - ObjectMapper objectMapper; + private WebTestClient webTestClient; - @SpyBean - private TestController testControllerSpy; @RestController - @Slf4j static class TestController { @PutMapping("/test") @@ -59,31 +48,43 @@ static class ValidationDTO { private String data; } - private final ValidationDTO VALIDATION_DTO = new ValidationDTO("data"); - @Test - void handleMethodArgumentNotValidException() throws Exception { + void testHandleValueNotValidException() { + String invalidJson = "{}"; - mockMvc.perform(MockMvcRequestBuilders.put("/test") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(new ValidationDTO(""))) - .header("data", "data") - .accept(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("INVALID_REQUEST")) - .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("[data]: The field is mandatory!")); + webTestClient.put() + .uri("/test") + .contentType(MediaType.APPLICATION_JSON) + .header("data", "someValue") + .bodyValue(invalidJson) + .exchange() + .expectStatus().isBadRequest() + .expectBody(ErrorDTO.class) + .consumeWith(response -> { + ErrorDTO errorDTO = response.getResponseBody(); + assertThat(errorDTO).isNotNull(); + assertThat(errorDTO.getCode()).isEqualTo("INVALID_REQUEST"); + assertThat(errorDTO.getMessage()).isEqualTo("[data]: The field is mandatory!"); + }); } - @Test - void handleMissingRequestHeaderException() throws Exception { + void testHandleHeaderNotValidException() { + String invalidJson = "{}"; + + webTestClient.put() + .uri("/test") + .contentType(MediaType.APPLICATION_JSON) + .bodyValue(new ValidationDTO("data")) + .exchange() + .expectStatus().isBadRequest() + .expectBody(ErrorDTO.class) - mockMvc.perform(MockMvcRequestBuilders.put("/test") - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(VALIDATION_DTO)) - .accept(MediaType.APPLICATION_JSON)) - .andExpect(MockMvcResultMatchers.status().isBadRequest()) - .andExpect(MockMvcResultMatchers.jsonPath("$.code").value("INVALID_REQUEST")) - .andExpect(MockMvcResultMatchers.jsonPath("$.message").value("Required request header 'data' for method parameter type String is not present")); + .consumeWith(response -> { + ErrorDTO errorDTO = response.getResponseBody(); + assertThat(errorDTO).isNotNull(); + assertThat(errorDTO.getCode()).isEqualTo("INVALID_REQUEST"); + assertThat(errorDTO.getMessage()).isEqualTo("Invalid request"); + }); } } diff --git a/src/test/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerTest.java b/src/test/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerTest.java index 1dfe4ee..d19116e 100644 --- a/src/test/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerTest.java +++ b/src/test/java/it/gov/pagopa/onboarding/citizen/controller/CitizenControllerTest.java @@ -2,7 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; -import it.gov.pagopa.onboarding.citizen.model.mapper.CitizenConsentMapperToObject; +import it.gov.pagopa.onboarding.citizen.faker.CitizenConsentDTOFaker; import it.gov.pagopa.onboarding.citizen.service.CitizenServiceImpl; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -12,10 +12,8 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.reactive.server.WebTestClient; -import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import java.util.Collections; import java.util.List; @WebFluxTest(CitizenControllerImpl.class) @@ -30,12 +28,13 @@ class CitizenControllerTest { @Autowired private ObjectMapper objectMapper; - @MockBean - CitizenConsentMapperToObject mapperToObject; + private static final String FISCAL_CODE = "fiscalCode"; + private static final String TPP_ID = "tppId"; + @Test void saveCitizenConsent_Ok() { - CitizenConsentDTO citizenConsentDTO = new CitizenConsentDTO(); + CitizenConsentDTO citizenConsentDTO = CitizenConsentDTOFaker.mockInstance(true); Mockito.when(citizenService.createCitizenConsent(citizenConsentDTO)).thenReturn(Mono.just(citizenConsentDTO)); @@ -44,7 +43,7 @@ void saveCitizenConsent_Ok() { .contentType(MediaType.APPLICATION_JSON) .bodyValue(citizenConsentDTO) .exchange() - .expectStatus().isCreated() + .expectStatus().isOk() .expectBody(CitizenConsentDTO.class) .consumeWith(response -> { CitizenConsentDTO resultResponse = response.getResponseBody(); @@ -55,10 +54,7 @@ void saveCitizenConsent_Ok() { @Test void stateUpdate_Ok() { - CitizenConsentDTO citizenConsentDTO = new CitizenConsentDTO(); - citizenConsentDTO.setHashedFiscalCode("hashedFiscalCode"); - citizenConsentDTO.setTppId("tppId"); - citizenConsentDTO.setTppState(true); + CitizenConsentDTO citizenConsentDTO = CitizenConsentDTOFaker.mockInstance(true); Mockito.when(citizenService.updateChannelState( citizenConsentDTO.getHashedFiscalCode(), @@ -82,15 +78,14 @@ void stateUpdate_Ok() { @Test void getConsentStatus_Ok() { - String fiscalCode = "fiscalCode"; - String tppId = "tppId"; - CitizenConsentDTO citizenConsentDTO = new CitizenConsentDTO(); - Mockito.when(citizenService.getConsentStatus(fiscalCode, tppId)) + CitizenConsentDTO citizenConsentDTO = CitizenConsentDTOFaker.mockInstance(true); + + Mockito.when(citizenService.getConsentStatus(FISCAL_CODE, TPP_ID)) .thenReturn(Mono.just(citizenConsentDTO)); webClient.get() - .uri("/emd/citizen/{fiscalCode}/{tppId}", fiscalCode, tppId) + .uri("/emd/citizen/{fiscalCode}/{tppId}", FISCAL_CODE, TPP_ID) .exchange() .expectStatus().isOk() .expectBody(CitizenConsentDTO.class) @@ -103,14 +98,13 @@ void getConsentStatus_Ok() { @Test void getCitizenConsentsEnabled_Ok() { - String fiscalCode = "fiscalCode"; - List citizenConsentDTOList = Collections.singletonList(new CitizenConsentDTO()); + List citizenConsentDTOList = List.of(CitizenConsentDTOFaker.mockInstance(true)); - Mockito.when(citizenService.getListEnabledConsents(fiscalCode)) - .thenReturn(Flux.fromIterable(citizenConsentDTOList)); + Mockito.when(citizenService.getListEnabledConsents(FISCAL_CODE)) + .thenReturn(Mono.just(citizenConsentDTOList)); webClient.get() - .uri("/emd/citizen/list/{fiscalCode}/enabled", fiscalCode) + .uri("/emd/citizen/list/{fiscalCode}/enabled", FISCAL_CODE) .exchange() .expectStatus().isOk() .expectBodyList(CitizenConsentDTO.class) @@ -123,14 +117,13 @@ void getCitizenConsentsEnabled_Ok() { @Test void getCitizenConsents_Ok() { - String fiscalCode = "fiscalCode"; - List citizenConsentDTOList = Collections.singletonList(new CitizenConsentDTO()); + List citizenConsentDTOList = List.of(CitizenConsentDTOFaker.mockInstance(true)); - Mockito.when(citizenService.getListAllConsents(fiscalCode)) - .thenReturn(Flux.fromIterable(citizenConsentDTOList)); + Mockito.when(citizenService.getListAllConsents(FISCAL_CODE)) + .thenReturn(Mono.just(citizenConsentDTOList)); webClient.get() - .uri("/emd/citizen/list/{fiscalCode}", fiscalCode) + .uri("/emd/citizen/list/{fiscalCode}", FISCAL_CODE) .exchange() .expectStatus().isOk() .expectBodyList(CitizenConsentDTO.class) diff --git a/src/test/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceTest.java b/src/test/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceTest.java index 4c56166..f6ee817 100644 --- a/src/test/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceTest.java +++ b/src/test/java/it/gov/pagopa/onboarding/citizen/service/CitizenServiceTest.java @@ -3,12 +3,13 @@ import it.gov.pagopa.common.utils.Utils; import it.gov.pagopa.common.web.exception.ClientExceptionWithBody; import it.gov.pagopa.onboarding.citizen.dto.CitizenConsentDTO; -import it.gov.pagopa.onboarding.citizen.dto.mapper.CitizenConsentMapperToDTO; -import it.gov.pagopa.onboarding.citizen.exception.custom.EmdEncryptionException; -import it.gov.pagopa.onboarding.citizen.exception.custom.ExceptionMap; +import it.gov.pagopa.onboarding.citizen.dto.mapper.CitizenConsentObjectToDTOMapper; +import it.gov.pagopa.common.web.exception.EmdEncryptionException; +import it.gov.pagopa.onboarding.citizen.configuration.ExceptionMap; import it.gov.pagopa.onboarding.citizen.faker.CitizenConsentDTOFaker; +import it.gov.pagopa.onboarding.citizen.faker.CitizenConsentFaker; import it.gov.pagopa.onboarding.citizen.model.CitizenConsent; -import it.gov.pagopa.onboarding.citizen.model.mapper.CitizenConsentMapperToObject; +import it.gov.pagopa.onboarding.citizen.model.mapper.CitizenConsentDTOToObjectMapper; import it.gov.pagopa.onboarding.citizen.repository.CitizenRepository; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -23,15 +24,16 @@ import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertThrows; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.any; @ExtendWith({SpringExtension.class, MockitoExtension.class}) @ContextConfiguration(classes = { CitizenServiceImpl.class, - CitizenConsentMapperToDTO.class, - CitizenConsentMapperToObject.class, + CitizenConsentObjectToDTOMapper.class, + CitizenConsentDTOToObjectMapper.class, ExceptionMap.class }) class CitizenServiceTest { @@ -43,21 +45,25 @@ class CitizenServiceTest { CitizenRepository citizenRepository; @Autowired - CitizenConsentMapperToObject mapperToObject; - @Autowired - ExceptionMap exceptionMap; + CitizenConsentDTOToObjectMapper mapperToObject; + + private static final String FISCAL_CODE = "fiscalCode"; + private static final String HASHED_FISCAL_CODE = Utils.createSHA256(FISCAL_CODE); + private static final String TPP_ID = "tppId"; + private static final boolean TPP_STATE = true; + private static final CitizenConsent CITIZEN_CONSENT = CitizenConsentFaker.mockInstance(true); @Test void createCitizenConsent_Ok() { CitizenConsentDTO citizenConsentDTO = CitizenConsentDTOFaker.mockInstance(true); - CitizenConsent citizenConsent = mapperToObject.citizenConsentDTOMapper(citizenConsentDTO); + CitizenConsent citizenConsent = mapperToObject.map(citizenConsentDTO); Mockito.when(citizenRepository.save(Mockito.any())) .thenReturn(Mono.just(citizenConsent)); CitizenConsentDTO response = citizenService.createCitizenConsent(citizenConsentDTO).block(); - assert response != null; + assertNotNull(response); citizenConsentDTO.setLastUpdateDate(response.getLastUpdateDate()); citizenConsentDTO.setCreationDate(response.getCreationDate()); @@ -78,30 +84,27 @@ void createCitizenConsent_Ko_EmdEncryptError() { @Test void updateChannelState_Ok() { - String hashedFiscalCode = "hashedFiscalCode"; - String tppId = "tppId"; - boolean tppState = true; - CitizenConsent citizenConsent = new CitizenConsent(); - Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId)) - .thenReturn(Mono.just(citizenConsent)); + + + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(HASHED_FISCAL_CODE, TPP_ID)) + .thenReturn(Mono.just(CITIZEN_CONSENT)); Mockito.when(citizenRepository.save(Mockito.any())) - .thenReturn(Mono.just(citizenConsent)); + .thenReturn(Mono.just(CITIZEN_CONSENT)); - CitizenConsentDTO response = citizenService.updateChannelState(hashedFiscalCode, tppId, tppState).block(); - assert response != null; - assertEquals(tppState, response.getTppState()); + CitizenConsentDTO response = citizenService.updateChannelState(FISCAL_CODE, TPP_ID, TPP_STATE).block(); + assertNotNull(response); + assertEquals(TPP_STATE, response.getTppState()); } @Test void updateChannelState_Ko_CitizenNotOnboarded() { - String hashedFiscalCode = "hashedFiscalCode"; - String tppId = "tppId"; - Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId)) + + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(HASHED_FISCAL_CODE, TPP_ID)) .thenReturn(Mono.empty()); - Executable executable = () -> citizenService.updateChannelState(hashedFiscalCode, tppId, true).block(); + Executable executable = () -> citizenService.updateChannelState(FISCAL_CODE, TPP_ID, true).block(); ClientExceptionWithBody exception = assertThrows(ClientExceptionWithBody.class, executable); assertEquals("CITIZEN_NOT_ONBOARDED", exception.getMessage()); @@ -109,28 +112,22 @@ void updateChannelState_Ko_CitizenNotOnboarded() { @Test void getConsentStatus_Ok() { - String fiscalCode = "fiscalCode"; - String tppId = "tppId"; - String hashedFiscalCode = Utils.createSHA256(fiscalCode); - CitizenConsent citizenConsent = new CitizenConsent(); + - Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId)) - .thenReturn(Mono.just(citizenConsent)); + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(HASHED_FISCAL_CODE, TPP_ID)) + .thenReturn(Mono.just(CITIZEN_CONSENT)); - CitizenConsentDTO response = citizenService.getConsentStatus(fiscalCode, tppId).block(); - assert response != null; + CitizenConsentDTO response = citizenService.getConsentStatus(FISCAL_CODE, TPP_ID).block(); + assertNotNull(response); } @Test void getConsentStatus_Ko_CitizenNotOnboarded() { - String fiscalCode = "fiscalCode"; - String tppId = "tppId"; - String hashedFiscalCode = Utils.createSHA256(fiscalCode); - Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(hashedFiscalCode, tppId)) + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppId(HASHED_FISCAL_CODE, TPP_ID)) .thenReturn(Mono.empty()); - Executable executable = () -> citizenService.getConsentStatus(fiscalCode, tppId).block(); + Executable executable = () -> citizenService.getConsentStatus(FISCAL_CODE, TPP_ID).block(); ClientExceptionWithBody exception = assertThrows(ClientExceptionWithBody.class, executable); assertEquals("CITIZEN_NOT_ONBOARDED", exception.getMessage()); @@ -138,27 +135,25 @@ void getConsentStatus_Ko_CitizenNotOnboarded() { @Test void getListEnabledConsents_Ok() { - String fiscalCode = "fiscalCode"; - String hashedFiscalCode = Utils.createSHA256(fiscalCode); - CitizenConsent citizenConsent = new CitizenConsent(); + - Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppStateTrue(hashedFiscalCode)) - .thenReturn(Flux.just(citizenConsent)); + Mockito.when(citizenRepository.findByHashedFiscalCodeAndTppStateTrue(HASHED_FISCAL_CODE)) + .thenReturn(Flux.just(CITIZEN_CONSENT)); - Flux response = citizenService.getListEnabledConsents(fiscalCode); - assertEquals(1, response.count().block()); + List response = citizenService.getListEnabledConsents(FISCAL_CODE).block(); + assertNotNull(response); + assertEquals(1, response.size()); } @Test void getListAllConsents_Ok() { - String fiscalCode = "fiscalCode"; - String hashedFiscalCode = Utils.createSHA256(fiscalCode); - CitizenConsent citizenConsent = new CitizenConsent(); + - Mockito.when(citizenRepository.findByHashedFiscalCode(hashedFiscalCode)) - .thenReturn(Flux.just(citizenConsent)); + Mockito.when(citizenRepository.findByHashedFiscalCode(HASHED_FISCAL_CODE)) + .thenReturn(Flux.just(CITIZEN_CONSENT)); - Flux response = citizenService.getListAllConsents(fiscalCode); - assertEquals(1, response.count().block()); + List response = citizenService.getListAllConsents(FISCAL_CODE).block(); + assertNotNull(response); + assertEquals(1, response.size()); } }