From a5f0fbc093643e6d155f7805a73814381c494485 Mon Sep 17 00:00:00 2001 From: tkuzynow Date: Tue, 9 Jan 2024 17:02:18 +0100 Subject: [PATCH] feat: fix rollback policy for the case where consultant cannot be created in appointment service --- .../ApiResponseEntityExceptionHandler.java | 12 +++++- .../consultant/ConsultantAdminService.java | 30 +++++++++++++- .../service/consultant/TransactionalStep.java | 10 +++++ .../create/ConsultantCreatorService.java | 8 ++++ .../CustomValidationHttpStatusException.java | 6 +-- .../DistributedTransactionException.java | 40 +++++++++++++++++++ .../DistributedTransactionInfo.java | 19 +++++++++ .../api/facade/rollback/RollbackFacade.java | 20 ++++++++++ .../userservice/api/service/LogService.java | 8 +++- .../appointment/AppointmentService.java | 40 ++++++++++++------- .../delete/model/DeletionWorkflowError.java | 2 + .../service/DeleteUserAccountService.java | 2 +- .../keycloak/KeycloakServiceTest.java | 18 +++++---- .../admin/create/CreateAdminServiceIT.java | 4 +- .../admin/update/UpdateAdminServiceIT.java | 2 +- .../ConsultantAgencyAdminUserServiceTest.java | 2 +- ...ntAgencyDeletionValidationServiceTest.java | 4 +- .../create/ConsultantCreatorServiceIT.java | 4 +- .../ConsultantPreDeletionServiceTest.java | 2 +- .../update/ConsultantUpdateServiceBase.java | 4 +- .../UserAccountInputValidatorTest.java | 8 ++-- .../api/facade/CreateUserFacadeTest.java | 8 ++-- .../facade/rollback/RollbackFacadeTest.java | 15 +++++++ 23 files changed, 220 insertions(+), 48 deletions(-) create mode 100644 src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/TransactionalStep.java create mode 100644 src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/DistributedTransactionException.java create mode 100644 src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/DistributedTransactionInfo.java diff --git a/src/main/java/de/caritas/cob/userservice/api/adapters/web/controller/interceptor/ApiResponseEntityExceptionHandler.java b/src/main/java/de/caritas/cob/userservice/api/adapters/web/controller/interceptor/ApiResponseEntityExceptionHandler.java index 97e29010a..40ead6482 100644 --- a/src/main/java/de/caritas/cob/userservice/api/adapters/web/controller/interceptor/ApiResponseEntityExceptionHandler.java +++ b/src/main/java/de/caritas/cob/userservice/api/adapters/web/controller/interceptor/ApiResponseEntityExceptionHandler.java @@ -6,6 +6,7 @@ import de.caritas.cob.userservice.api.exception.httpresponses.ConflictException; import de.caritas.cob.userservice.api.exception.httpresponses.CreateEnquiryMessageException; import de.caritas.cob.userservice.api.exception.httpresponses.CustomValidationHttpStatusException; +import de.caritas.cob.userservice.api.exception.httpresponses.DistributedTransactionException; import de.caritas.cob.userservice.api.exception.httpresponses.ForbiddenException; import de.caritas.cob.userservice.api.exception.httpresponses.InternalServerErrorException; import de.caritas.cob.userservice.api.exception.httpresponses.NoContentException; @@ -55,6 +56,14 @@ public ResponseEntity handleJPAConstraintViolationException( return handleExceptionInternal(ex, null, new HttpHeaders(), HttpStatus.CONFLICT, request); } + @ExceptionHandler({DistributedTransactionException.class}) + public ResponseEntity handleDistributedTransactionException( + final DistributedTransactionException ex, final WebRequest request) { + log.error("Distributed transaction failed to complete", ex); + return handleExceptionInternal( + ex, null, ex.getCustomHttpHeaders(), HttpStatus.FAILED_DEPENDENCY, request); + } + @ExceptionHandler({CreateEnquiryMessageException.class}) public ResponseEntity handleCreateEnquiryMessageException( final CreateEnquiryMessageException ex, final WebRequest request) { @@ -88,7 +97,8 @@ public ResponseEntity handleCustomBadRequest( final CustomValidationHttpStatusException ex, final WebRequest request) { ex.executeLogging(); - return handleExceptionInternal(ex, null, ex.getCustomHttpHeader(), ex.getHttpStatus(), request); + return handleExceptionInternal( + ex, null, ex.getCustomHttpHeaders(), ex.getHttpStatus(), request); } /** diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminService.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminService.java index 027486d38..d555b073c 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminService.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/ConsultantAdminService.java @@ -15,6 +15,8 @@ import de.caritas.cob.userservice.api.admin.service.consultant.create.ConsultantCreatorService; import de.caritas.cob.userservice.api.admin.service.consultant.delete.ConsultantPreDeletionService; import de.caritas.cob.userservice.api.admin.service.consultant.update.ConsultantUpdateService; +import de.caritas.cob.userservice.api.exception.httpresponses.DistributedTransactionException; +import de.caritas.cob.userservice.api.exception.httpresponses.DistributedTransactionInfo; import de.caritas.cob.userservice.api.exception.httpresponses.NoContentException; import de.caritas.cob.userservice.api.exception.httpresponses.NotFoundException; import de.caritas.cob.userservice.api.helper.AuthenticatedUser; @@ -23,10 +25,12 @@ import de.caritas.cob.userservice.api.port.out.ConsultantRepository; import de.caritas.cob.userservice.api.port.out.SessionRepository; import de.caritas.cob.userservice.api.service.appointment.AppointmentService; +import java.util.List; import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; +import org.springframework.web.client.RestClientException; /** Service class for admin operations on {@link Consultant} objects. */ @Service @@ -69,14 +73,36 @@ public ConsultantAdminResponseDTO findConsultantById(String consultantId) { * @return the generated and persisted {@link Consultant} representation as {@link * ConsultantAdminResponseDTO} */ - public ConsultantAdminResponseDTO createNewConsultant(CreateConsultantDTO createConsultantDTO) { + public ConsultantAdminResponseDTO createNewConsultant(CreateConsultantDTO createConsultantDTO) + throws DistributedTransactionException { Consultant newConsultant = this.consultantCreatorService.createNewConsultant(createConsultantDTO); + List completedSteps = + Lists.newArrayList( + TransactionalStep.CREATE_ACCOUNT_IN_KEYCLOAK, + TransactionalStep.CREATE_ACCOUNT_IN_ROCKETCHAT, + TransactionalStep.CREATE_CONSULTANT_IN_MARIADB); ConsultantAdminResponseDTO consultantAdminResponseDTO = ConsultantResponseDTOBuilder.getInstance(newConsultant).buildResponseDTO(); - this.appointmentService.createConsultant(consultantAdminResponseDTO); + try { + this.appointmentService.createConsultant(consultantAdminResponseDTO); + } catch (RestClientException e) { + log.error( + "User with id {}, who has roles {}, has created a consultant with id {} but the appointment service returned an error: {}", + authenticatedUser.getUserId(), + authenticatedUser.getRoles(), + newConsultant.getId(), + e.getMessage()); + this.consultantCreatorService.rollbackCreateNewConsultant(newConsultant); + throw new DistributedTransactionException( + e, + new DistributedTransactionInfo( + "createNewConsultant", + completedSteps, + TransactionalStep.CREATE_ACCOUNT_IN_CALCOM_OR_APPOINTMENTSERVICE)); + } return consultantAdminResponseDTO; } diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/TransactionalStep.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/TransactionalStep.java new file mode 100644 index 000000000..93cbbaa43 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/TransactionalStep.java @@ -0,0 +1,10 @@ +package de.caritas.cob.userservice.api.admin.service.consultant; + +public enum TransactionalStep { + CREATE_ACCOUNT_IN_KEYCLOAK, + CREATE_CONSULTANT_IN_MARIADB, + + CREATE_ACCOUNT_IN_ROCKETCHAT, + + CREATE_ACCOUNT_IN_CALCOM_OR_APPOINTMENTSERVICE +} diff --git a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorService.java b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorService.java index 1c5a71c38..13dba1c52 100644 --- a/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorService.java +++ b/src/main/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorService.java @@ -20,6 +20,7 @@ import de.caritas.cob.userservice.api.exception.httpresponses.InternalServerErrorException; import de.caritas.cob.userservice.api.exception.httpresponses.customheader.HttpStatusExceptionReason; import de.caritas.cob.userservice.api.exception.rocketchat.RocketChatLoginException; +import de.caritas.cob.userservice.api.facade.rollback.RollbackFacade; import de.caritas.cob.userservice.api.helper.AuthenticatedUser; import de.caritas.cob.userservice.api.helper.UserHelper; import de.caritas.cob.userservice.api.helper.UsernameTranscoder; @@ -52,6 +53,8 @@ public class ConsultantCreatorService { private final @NonNull UserAccountInputValidator userAccountInputValidator; private final @NonNull TenantAdminService tenantAdminService; + private final @NonNull RollbackFacade rollbackFacade; + @Value("${multitenancy.enabled}") private boolean multiTenancyEnabled; @@ -235,4 +238,9 @@ private void addGroupChatConsultantRole( roles.add(GROUP_CHAT_CONSULTANT.getValue()); } } + + public void rollbackCreateNewConsultant(Consultant newConsultant) { + log.info("Rollback creation of consultant with id {}", newConsultant.getId()); + rollbackFacade.rollbackConsultantAccount(newConsultant); + } } diff --git a/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomValidationHttpStatusException.java b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomValidationHttpStatusException.java index 7f5a0a471..60c05acb0 100644 --- a/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomValidationHttpStatusException.java +++ b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/CustomValidationHttpStatusException.java @@ -10,7 +10,7 @@ @Getter public class CustomValidationHttpStatusException extends CustomHttpStatusException { - private final HttpHeaders customHttpHeader; + private final HttpHeaders customHttpHeaders; private final HttpStatus httpStatus; /** @@ -21,7 +21,7 @@ public class CustomValidationHttpStatusException extends CustomHttpStatusExcepti */ public CustomValidationHttpStatusException(HttpStatusExceptionReason httpStatusExceptionReason) { super(); - this.customHttpHeader = new CustomHttpHeader(httpStatusExceptionReason).buildHeader(); + this.customHttpHeaders = new CustomHttpHeader(httpStatusExceptionReason).buildHeader(); this.httpStatus = HttpStatus.BAD_REQUEST; } @@ -35,7 +35,7 @@ public CustomValidationHttpStatusException(HttpStatusExceptionReason httpStatusE public CustomValidationHttpStatusException( HttpStatusExceptionReason reason, HttpStatus httpStatus) { super(); - this.customHttpHeader = new CustomHttpHeader(reason).buildHeader(); + this.customHttpHeaders = new CustomHttpHeader(reason).buildHeader(); this.httpStatus = httpStatus; } } diff --git a/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/DistributedTransactionException.java b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/DistributedTransactionException.java new file mode 100644 index 000000000..54732fef1 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/DistributedTransactionException.java @@ -0,0 +1,40 @@ +package de.caritas.cob.userservice.api.exception.httpresponses; + +import de.caritas.cob.userservice.api.service.LogService; +import org.springframework.http.HttpHeaders; + +public class DistributedTransactionException extends CustomHttpStatusException { + + private final HttpHeaders customHttpHeaders; + + public DistributedTransactionException( + Exception e, DistributedTransactionInfo distributedTransactionInfo) { + super( + getFormattedMessageWithDistributedTransactionInfo(distributedTransactionInfo), + e, + LogService::logError); + this.customHttpHeaders = + buildCustomHeaders( + "DISTRIBUTED_TRANSACTION_FAILED_ON_STEP_" + + distributedTransactionInfo.getFailedStep().name()); + } + + private HttpHeaders buildCustomHeaders(String message) { + HttpHeaders headers = new HttpHeaders(); + headers.add("X-Reason", message); + return headers; + } + + private static String getFormattedMessageWithDistributedTransactionInfo( + DistributedTransactionInfo distributedTransactionInfo) { + return String.format( + "Distributed transaction %s failed. Completed transactional operations: %s. Failed step: %s", + distributedTransactionInfo.getName(), + distributedTransactionInfo.getCompletedTransactionalOperations(), + distributedTransactionInfo.getFailedStep()); + } + + public HttpHeaders getCustomHttpHeaders() { + return customHttpHeaders; + } +} diff --git a/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/DistributedTransactionInfo.java b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/DistributedTransactionInfo.java new file mode 100644 index 000000000..60fd1b1b9 --- /dev/null +++ b/src/main/java/de/caritas/cob/userservice/api/exception/httpresponses/DistributedTransactionInfo.java @@ -0,0 +1,19 @@ +package de.caritas.cob.userservice.api.exception.httpresponses; + +import de.caritas.cob.userservice.api.admin.service.consultant.TransactionalStep; +import java.util.List; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +@Data +@Builder +@AllArgsConstructor +public class DistributedTransactionInfo { + + String name; + List completedTransactionalOperations; + TransactionalStep failedStep; +} diff --git a/src/main/java/de/caritas/cob/userservice/api/facade/rollback/RollbackFacade.java b/src/main/java/de/caritas/cob/userservice/api/facade/rollback/RollbackFacade.java index a2031e09e..26eb0cb0d 100644 --- a/src/main/java/de/caritas/cob/userservice/api/facade/rollback/RollbackFacade.java +++ b/src/main/java/de/caritas/cob/userservice/api/facade/rollback/RollbackFacade.java @@ -2,12 +2,18 @@ import static java.util.Objects.nonNull; +import de.caritas.cob.userservice.api.model.Consultant; import de.caritas.cob.userservice.api.port.out.IdentityClient; import de.caritas.cob.userservice.api.service.UserAgencyService; import de.caritas.cob.userservice.api.service.session.SessionService; import de.caritas.cob.userservice.api.service.user.UserService; +import de.caritas.cob.userservice.api.workflow.delete.model.DeletionWorkflowError; +import de.caritas.cob.userservice.api.workflow.delete.service.DeleteUserAccountService; +import java.time.LocalDateTime; +import java.util.List; import lombok.NonNull; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; /* @@ -15,6 +21,7 @@ */ @Service @RequiredArgsConstructor +@Slf4j public class RollbackFacade { private final @NonNull IdentityClient identityClient; @@ -22,6 +29,19 @@ public class RollbackFacade { private final @NonNull SessionService sessionService; private final @NonNull UserService userService; + private final @NonNull DeleteUserAccountService deleteUserAccountService; + + public void rollbackConsultantAccount(Consultant consultant) { + log.info("Rollback consultant account: {}", consultant); + consultant.setDeleteDate(LocalDateTime.now()); + List deletionWorkflowErrors = + deleteUserAccountService.performConsultantDeletion(consultant); + if (nonNull(deletionWorkflowErrors) && !deletionWorkflowErrors.isEmpty()) { + + deletionWorkflowErrors.stream() + .forEach(e -> log.error("Consultant delete workflow error: ", e)); + } + } /** * Deletes the provided user in Keycloak, MariaDB and its related session or user-chat/agency * relations depending on the provided {@link RollbackUserAccountInformation}. diff --git a/src/main/java/de/caritas/cob/userservice/api/service/LogService.java b/src/main/java/de/caritas/cob/userservice/api/service/LogService.java index 7c665313a..7f6d3c6b6 100644 --- a/src/main/java/de/caritas/cob/userservice/api/service/LogService.java +++ b/src/main/java/de/caritas/cob/userservice/api/service/LogService.java @@ -106,12 +106,18 @@ public static void logInfo(Exception exception) { LOGGER.info(getStackTrace(exception)); } + public static void logError(Exception exception) { + LOGGER.error(getStackTrace(exception)); + } + /** * Logs an warning message. * * @param exception The exception */ public static void logWarn(Exception exception) { - LOGGER.warn(getStackTrace(exception)); + if (LOGGER.isWarnEnabled()) { + LOGGER.warn(getStackTrace(exception)); + } } } diff --git a/src/main/java/de/caritas/cob/userservice/api/service/appointment/AppointmentService.java b/src/main/java/de/caritas/cob/userservice/api/service/appointment/AppointmentService.java index 20be35694..6e7feabb5 100644 --- a/src/main/java/de/caritas/cob/userservice/api/service/appointment/AppointmentService.java +++ b/src/main/java/de/caritas/cob/userservice/api/service/appointment/AppointmentService.java @@ -1,5 +1,6 @@ package de.caritas.cob.userservice.api.service.appointment; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import de.caritas.cob.userservice.api.adapters.web.dto.ConsultantAdminResponseDTO; @@ -28,6 +29,7 @@ import org.springframework.http.HttpStatus; import org.springframework.stereotype.Component; import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestClientException; /** Service class to communicate with the AppointmentService. */ @Component @@ -52,7 +54,8 @@ public class AppointmentService { @Value("${feature.appointment.enabled}") private boolean appointmentFeatureEnabled; - public void createConsultant(ConsultantAdminResponseDTO consultantAdminResponseDTO) { + public void createConsultant(ConsultantAdminResponseDTO consultantAdminResponseDTO) + throws RestClientException { if (!appointmentFeatureEnabled) { return; } @@ -62,29 +65,38 @@ public void createConsultant(ConsultantAdminResponseDTO consultantAdminResponseD ConsultantApi appointmentConsultantApi = this.appointmentConsultantServiceApiControllerFactory.createControllerApi(); addTechnicalUserHeaders(appointmentConsultantApi.getApiClient()); - try { - de.caritas.cob.userservice.appointmentservice.generated.web.model.ConsultantDTO consultant = - mapper.readValue( - mapper.writeValueAsString(consultantAdminResponseDTO.getEmbedded()), - de.caritas.cob.userservice.appointmentservice.generated.web.model.ConsultantDTO - .class); - appointmentConsultantApi.createConsultant(consultant); - } catch (Exception e) { - log.error(e.getMessage()); - } + de.caritas.cob.userservice.appointmentservice.generated.web.model.ConsultantDTO consultant = + getConsultantDTO(consultantAdminResponseDTO, mapper); + appointmentConsultantApi.createConsultant(consultant); + } + } + + private de.caritas.cob.userservice.appointmentservice.generated.web.model.ConsultantDTO + getConsultantDTO(ConsultantAdminResponseDTO consultantAdminResponseDTO, ObjectMapper mapper) { + de.caritas.cob.userservice.appointmentservice.generated.web.model.ConsultantDTO consultant = + null; + try { + consultant = + mapper.readValue( + mapper.writeValueAsString(consultantAdminResponseDTO.getEmbedded()), + de.caritas.cob.userservice.appointmentservice.generated.web.model.ConsultantDTO + .class); + } catch (JsonProcessingException e) { + throw new IllegalStateException(e); } + return consultant; } public void syncConsultantData(Consultant consultant) { - ConsultantAdminResponseDTO ConsultantAdminResponseDTO = new ConsultantAdminResponseDTO(); + ConsultantAdminResponseDTO consultantAdminResponseDTO = new ConsultantAdminResponseDTO(); ConsultantDTO consultantEmbeded = new ConsultantDTO(); consultantEmbeded.setId(consultant.getId()); consultantEmbeded.setFirstname(consultant.getFirstName()); consultantEmbeded.setLastname(consultant.getLastName()); consultantEmbeded.setEmail(consultant.getEmail()); consultantEmbeded.setAbsent(consultant.isAbsent()); - ConsultantAdminResponseDTO.setEmbedded(consultantEmbeded); - updateConsultant(ConsultantAdminResponseDTO); + consultantAdminResponseDTO.setEmbedded(consultantEmbeded); + updateConsultant(consultantAdminResponseDTO); } public void updateConsultant(ConsultantAdminResponseDTO consultantAdminResponseDTO) { diff --git a/src/main/java/de/caritas/cob/userservice/api/workflow/delete/model/DeletionWorkflowError.java b/src/main/java/de/caritas/cob/userservice/api/workflow/delete/model/DeletionWorkflowError.java index 32682a453..6573d0a4c 100644 --- a/src/main/java/de/caritas/cob/userservice/api/workflow/delete/model/DeletionWorkflowError.java +++ b/src/main/java/de/caritas/cob/userservice/api/workflow/delete/model/DeletionWorkflowError.java @@ -3,9 +3,11 @@ import java.time.LocalDateTime; import lombok.Builder; import lombok.Data; +import lombok.ToString; @Data @Builder +@ToString public class DeletionWorkflowError { private DeletionSourceType deletionSourceType; diff --git a/src/main/java/de/caritas/cob/userservice/api/workflow/delete/service/DeleteUserAccountService.java b/src/main/java/de/caritas/cob/userservice/api/workflow/delete/service/DeleteUserAccountService.java index 580c485be..79d099e94 100644 --- a/src/main/java/de/caritas/cob/userservice/api/workflow/delete/service/DeleteUserAccountService.java +++ b/src/main/java/de/caritas/cob/userservice/api/workflow/delete/service/DeleteUserAccountService.java @@ -83,7 +83,7 @@ private List deleteConsultantsAndCollectPossibleErrors() .collect(Collectors.toList()); } - private List performConsultantDeletion(Consultant consultant) { + public List performConsultantDeletion(Consultant consultant) { var deletionWorkflowDTO = new ConsultantDeletionWorkflowDTO(consultant, new ArrayList<>()); diff --git a/src/test/java/de/caritas/cob/userservice/api/adapters/keycloak/KeycloakServiceTest.java b/src/test/java/de/caritas/cob/userservice/api/adapters/keycloak/KeycloakServiceTest.java index 2afdd7a35..748206202 100644 --- a/src/test/java/de/caritas/cob/userservice/api/adapters/keycloak/KeycloakServiceTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/adapters/keycloak/KeycloakServiceTest.java @@ -271,6 +271,8 @@ public void deleteEmailAddress_Should_useServicesCorrectly() { when(keycloakClient.getUsersResource()).thenReturn(usersResource); keycloakService.deleteEmailAddress(); + + Mockito.verify(userResource, times(1)).update(any()); } @Test @@ -403,8 +405,8 @@ public void createKeycloakUser_Should_createUserWithDefaultLocale() { try { this.keycloakService.createKeycloakUser(userDTO); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader(), notNullValue()); - assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), is(EMAIL_NOT_AVAILABLE.name())); + assertThat(e.getCustomHttpHeaders(), notNullValue()); + assertThat(e.getCustomHttpHeaders().get("X-Reason").get(0), is(EMAIL_NOT_AVAILABLE.name())); } } @@ -424,8 +426,9 @@ public void createKeycloakUser_Should_createUserWithDefaultLocale() { try { this.keycloakService.createKeycloakUser(userDTO); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader(), notNullValue()); - assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), is(USERNAME_NOT_AVAILABLE.name())); + assertThat(e.getCustomHttpHeaders(), notNullValue()); + assertThat( + e.getCustomHttpHeaders().get("X-Reason").get(0), is(USERNAME_NOT_AVAILABLE.name())); } } @@ -445,8 +448,9 @@ public void createKeycloakUser_Should_createUserWithDefaultLocale() { try { this.keycloakService.createKeycloakUser(userDTO); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader(), notNullValue()); - assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), is(USERNAME_NOT_AVAILABLE.name())); + assertThat(e.getCustomHttpHeaders(), notNullValue()); + assertThat( + e.getCustomHttpHeaders().get("X-Reason").get(0), is(USERNAME_NOT_AVAILABLE.name())); } } @@ -723,7 +727,7 @@ public void updateUserData_Should_throwCustomException_When_emailIsChangedButNot this.keycloakService.updateUserData("userId", userDTO, "firstName", "lastName"); fail("Exception was not thrown"); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), is(EMAIL_NOT_AVAILABLE.name())); + assertThat(e.getCustomHttpHeaders().get("X-Reason").get(0), is(EMAIL_NOT_AVAILABLE.name())); } } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/admin/create/CreateAdminServiceIT.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/admin/create/CreateAdminServiceIT.java index 098ebeb8c..a115750f2 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/admin/create/CreateAdminServiceIT.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/admin/create/CreateAdminServiceIT.java @@ -179,8 +179,8 @@ public void createNewAdminAgency_Should_throwExpectedException_When_emailIsInval // then } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader()).isNotNull(); - assertThat(e.getCustomHttpHeader().get("X-Reason").get(0)).isEqualTo(EMAIL_NOT_VALID.name()); + assertThat(e.getCustomHttpHeaders()).isNotNull(); + assertThat(e.getCustomHttpHeaders().get("X-Reason").get(0)).isEqualTo(EMAIL_NOT_VALID.name()); } } } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/admin/update/UpdateAdminServiceIT.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/admin/update/UpdateAdminServiceIT.java index 7846ae422..8af4d9cb4 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/admin/update/UpdateAdminServiceIT.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/admin/update/UpdateAdminServiceIT.java @@ -74,7 +74,7 @@ public void updateAgencyAdmin_Should_throwCustomResponseException_When_newEmailI // then } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), is(EMAIL_NOT_VALID.name())); + assertThat(e.getCustomHttpHeaders().get("X-Reason").get(0), is(EMAIL_NOT_VALID.name())); } } } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/agency/ConsultantAgencyAdminUserServiceTest.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/agency/ConsultantAgencyAdminUserServiceTest.java index 36ec737ce..4d1515753 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/agency/ConsultantAgencyAdminUserServiceTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/agency/ConsultantAgencyAdminUserServiceTest.java @@ -141,7 +141,7 @@ public void removeConsultantsFromTeamSessionsByAgencyId_Should_changeTeamSession fail("Exception was not thrown"); } catch (CustomValidationHttpStatusException e) { assertThat( - requireNonNull(e.getCustomHttpHeader().get("X-Reason")).iterator().next(), + requireNonNull(e.getCustomHttpHeaders().get("X-Reason")).iterator().next(), is(CONSULTANT_AGENCY_RELATION_DOES_NOT_EXIST.name())); } } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/agency/ConsultantAgencyDeletionValidationServiceTest.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/agency/ConsultantAgencyDeletionValidationServiceTest.java index 5a2adc9a5..2b601ae55 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/agency/ConsultantAgencyDeletionValidationServiceTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/agency/ConsultantAgencyDeletionValidationServiceTest.java @@ -53,7 +53,7 @@ public class ConsultantAgencyDeletionValidationServiceTest { fail("Exception was not thrown"); } catch (CustomValidationHttpStatusException e) { assertThat( - requireNonNull(e.getCustomHttpHeader().get("X-Reason")).iterator().next(), + requireNonNull(e.getCustomHttpHeaders().get("X-Reason")).iterator().next(), is(CONSULTANT_IS_THE_LAST_OF_AGENCY_AND_AGENCY_IS_STILL_ACTIVE.name())); } } @@ -75,7 +75,7 @@ public class ConsultantAgencyDeletionValidationServiceTest { fail("Exception was not thrown"); } catch (CustomValidationHttpStatusException e) { assertThat( - requireNonNull(e.getCustomHttpHeader().get("X-Reason")).iterator().next(), + requireNonNull(e.getCustomHttpHeaders().get("X-Reason")).iterator().next(), is(CONSULTANT_IS_THE_LAST_OF_AGENCY_AND_AGENCY_HAS_OPEN_ENQUIRIES.name())); } } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorServiceIT.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorServiceIT.java index 938b89388..1da133c48 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorServiceIT.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/create/ConsultantCreatorServiceIT.java @@ -193,8 +193,8 @@ public void createNewConsultant_Should_throwExpectedException_When_emailIsInvali this.consultantCreatorService.createNewConsultant(createConsultantDTO); fail("Exception should be thrown"); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader(), notNullValue()); - assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), is(EMAIL_NOT_VALID.name())); + assertThat(e.getCustomHttpHeaders(), notNullValue()); + assertThat(e.getCustomHttpHeaders().get("X-Reason").get(0), is(EMAIL_NOT_VALID.name())); } } } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/delete/ConsultantPreDeletionServiceTest.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/delete/ConsultantPreDeletionServiceTest.java index 3f492b612..cbe90a169 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/delete/ConsultantPreDeletionServiceTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/delete/ConsultantPreDeletionServiceTest.java @@ -55,7 +55,7 @@ public class ConsultantPreDeletionServiceTest { fail("Exception was not thrown"); } catch (CustomValidationHttpStatusException e) { assertThat( - requireNonNull(e.getCustomHttpHeader().get("X-Reason")).iterator().next(), + requireNonNull(e.getCustomHttpHeaders().get("X-Reason")).iterator().next(), is(CONSULTANT_HAS_ACTIVE_OR_ARCHIVE_SESSIONS.name())); } } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/update/ConsultantUpdateServiceBase.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/update/ConsultantUpdateServiceBase.java index 10307f8e6..3e691e767 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/update/ConsultantUpdateServiceBase.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/update/ConsultantUpdateServiceBase.java @@ -61,7 +61,7 @@ public void updateConsultant_Should_throwCustomResponseException_When_absenceIsI fail("Exception should be thrown"); } catch (CustomValidationHttpStatusException e) { assertThat( - e.getCustomHttpHeader().get("X-Reason").get(0), + e.getCustomHttpHeaders().get("X-Reason").get(0), is(MISSING_ABSENCE_MESSAGE_FOR_ABSENT_USER.name())); } } @@ -74,7 +74,7 @@ public void updateConsultant_Should_throwCustomResponseException_When_newEmailIs this.consultantUpdateService.updateConsultant(getValidConsultantId(), updateConsultantDTO); fail("Exception should be thrown"); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), is(EMAIL_NOT_VALID.name())); + assertThat(e.getCustomHttpHeaders().get("X-Reason").get(0), is(EMAIL_NOT_VALID.name())); } } diff --git a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/validation/UserAccountInputValidatorTest.java b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/validation/UserAccountInputValidatorTest.java index 9d197f56e..b37976cab 100644 --- a/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/validation/UserAccountInputValidatorTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/admin/service/consultant/validation/UserAccountInputValidatorTest.java @@ -68,9 +68,9 @@ public void validateCreateConsultantDTO_ShouldNot_throwException_When_consultant this.userAccountInputValidator.validateAbsence(createConsultantDTO); fail("Exception should be thrown"); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader(), notNullValue()); + assertThat(e.getCustomHttpHeaders(), notNullValue()); assertThat( - e.getCustomHttpHeader().get("X-Reason").get(0), + e.getCustomHttpHeaders().get("X-Reason").get(0), is(MISSING_ABSENCE_MESSAGE_FOR_ABSENT_USER.name())); } } @@ -106,8 +106,8 @@ public void validateEmailAddressShould_throwExpectedException_When_EmailIsInvali this.userAccountInputValidator.validateEmailAddress("invalid"); fail("Exception should be thrown"); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader(), notNullValue()); - assertThat(e.getCustomHttpHeader().get("X-Reason").get(0), is(EMAIL_NOT_VALID.name())); + assertThat(e.getCustomHttpHeaders(), notNullValue()); + assertThat(e.getCustomHttpHeaders().get("X-Reason").get(0), is(EMAIL_NOT_VALID.name())); } } } diff --git a/src/test/java/de/caritas/cob/userservice/api/facade/CreateUserFacadeTest.java b/src/test/java/de/caritas/cob/userservice/api/facade/CreateUserFacadeTest.java index 8fe8ed7ca..99e844996 100644 --- a/src/test/java/de/caritas/cob/userservice/api/facade/CreateUserFacadeTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/facade/CreateUserFacadeTest.java @@ -78,9 +78,9 @@ public class CreateUserFacadeTest { try { this.createUserFacade.createUserAccountWithInitializedConsultingType(USER_DTO_SUCHT); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader(), notNullValue()); + assertThat(e.getCustomHttpHeaders(), notNullValue()); assertThat( - e.getCustomHttpHeader().get("X-Reason").get(0), + e.getCustomHttpHeaders().get("X-Reason").get(0), Matchers.is(USERNAME_NOT_AVAILABLE.name())); } } @@ -106,9 +106,9 @@ public class CreateUserFacadeTest { try { this.createUserFacade.createUserAccountWithInitializedConsultingType(USER_DTO_SUCHT); } catch (CustomValidationHttpStatusException e) { - assertThat(e.getCustomHttpHeader(), notNullValue()); + assertThat(e.getCustomHttpHeaders(), notNullValue()); assertThat( - e.getCustomHttpHeader().get("X-Reason").get(0), + e.getCustomHttpHeaders().get("X-Reason").get(0), Matchers.is(USERNAME_NOT_AVAILABLE.name())); assertThat(e.getHttpStatus(), is(HttpStatus.CONFLICT)); } diff --git a/src/test/java/de/caritas/cob/userservice/api/facade/rollback/RollbackFacadeTest.java b/src/test/java/de/caritas/cob/userservice/api/facade/rollback/RollbackFacadeTest.java index a7a30cb7c..63117d8c9 100644 --- a/src/test/java/de/caritas/cob/userservice/api/facade/rollback/RollbackFacadeTest.java +++ b/src/test/java/de/caritas/cob/userservice/api/facade/rollback/RollbackFacadeTest.java @@ -5,12 +5,14 @@ import static org.mockito.Mockito.verify; import de.caritas.cob.userservice.api.adapters.keycloak.KeycloakService; +import de.caritas.cob.userservice.api.model.Consultant; import de.caritas.cob.userservice.api.model.Session; import de.caritas.cob.userservice.api.model.User; import de.caritas.cob.userservice.api.model.UserAgency; import de.caritas.cob.userservice.api.service.UserAgencyService; import de.caritas.cob.userservice.api.service.session.SessionService; import de.caritas.cob.userservice.api.service.user.UserService; +import de.caritas.cob.userservice.api.workflow.delete.service.DeleteUserAccountService; import org.jeasy.random.EasyRandom; import org.junit.Test; import org.junit.runner.RunWith; @@ -27,6 +29,19 @@ public class RollbackFacadeTest { @Mock private SessionService sessionService; @Mock private UserService userService; + @Mock DeleteUserAccountService deleteUserAccountService; + + @Test + public void rollbackConsultantAccount_Should_Call_DeleteUserAccountService() { + // given + EasyRandom easyRandom = new EasyRandom(); + Consultant consultant = easyRandom.nextObject(Consultant.class); + // when + rollbackFacade.rollbackConsultantAccount(consultant); + // then + verify(deleteUserAccountService, times(1)).performConsultantDeletion(consultant); + } + @Test public void rollBackUserAccount_Should_DeleteSessionAndMonitoring_When_SessionIsGiven() { EasyRandom easyRandom = new EasyRandom();