diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java index 78947570..04dcbb6a 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerController.java @@ -15,6 +15,7 @@ import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipRepo import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipType; import net.hostsharing.hsadminng.mapper.Mapper; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RestController; @@ -112,7 +113,7 @@ public class HsOfficePartnerController implements HsOfficePartnersApi { if (partnerRepo.deleteByUuid(partnerUuid) != 1 || // TODO: move to after delete trigger in partner relationshipRepo.deleteByUuid(partnerToDelete.get().getPartnerRole().getUuid()) != 1 ) { - ResponseEntity.internalServerError().build(); + return ResponseEntity.status(HttpStatus.FORBIDDEN).build(); } return ResponseEntity.noContent().build(); @@ -159,9 +160,7 @@ public class HsOfficePartnerController implements HsOfficePartnersApi { private E ref(final Class entityClass, final UUID uuid) { try { - final var e = em.getReference(entityClass, uuid); - em.contains(e); // TODO: check if this is really needed to force an exception if not existing - return e; + return em.getReference(entityClass, uuid); } catch (final Throwable exc) { throw new ReferenceNotFoundException(entityClass, uuid, exc); } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java index 76afd85e..33a312c4 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerAcceptanceTest.java @@ -288,7 +288,6 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu @Nested @Accepts({ "Partner:U(Update)" }) @Transactional - @Disabled // TODO: enable one partner.person + partner.contract are removed class PatchPartner { @Test @@ -396,7 +395,6 @@ class HsOfficePartnerControllerAcceptanceTest extends ContextBasedTestWithCleanu @Nested @Accepts({ "Partner:D(Delete)" }) @Transactional - @Disabled // TODO: enable one partner.person + partner.contract are removed class DeletePartner { @Test diff --git a/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerRestTest.java b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerRestTest.java new file mode 100644 index 00000000..ed04d899 --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/hs/office/partner/HsOfficePartnerControllerRestTest.java @@ -0,0 +1,221 @@ +package net.hostsharing.hsadminng.hs.office.partner; + +import net.hostsharing.hsadminng.context.Context; +import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity; +import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; +import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipEntity; +import net.hostsharing.hsadminng.hs.office.relationship.HsOfficeRelationshipRepository; +import net.hostsharing.hsadminng.mapper.Mapper; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; +import org.mockito.Mock; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; + +import jakarta.persistence.EntityManager; +import jakarta.persistence.EntityManagerFactory; +import jakarta.persistence.EntityNotFoundException; +import jakarta.persistence.SynchronizationType; +import java.util.Map; +import java.util.Optional; +import java.util.UUID; + +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.startsWith; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@WebMvcTest(HsOfficePartnerController.class) +@Import(Mapper.class) +class HsOfficePartnerControllerRestTest { + + static final UUID GIVEN_MANDANTE_UUID = UUID.randomUUID(); + static final UUID GIVEN_PERSON_UUID = UUID.randomUUID(); + static final UUID GIVEN_CONTACT_UUID = UUID.randomUUID(); + static final UUID GIVEN_INVALID_UUID = UUID.fromString("00000000-0000-0000-0000-000000000000"); + + @Autowired + MockMvc mockMvc; + + @MockBean + Context contextMock; + + @MockBean + HsOfficePartnerRepository partnerRepo; + + @MockBean + HsOfficeRelationshipRepository relationshipRepo; + + @MockBean + EntityManager em; + + @MockBean + EntityManagerFactory emf; + + @Mock + HsOfficePersonEntity mandateMock; + + @Mock + HsOfficePersonEntity personMock; + + @Mock + HsOfficeContactEntity contactMock; + + @Mock + HsOfficePartnerEntity partnerMock; + + @BeforeEach + void init() { + when(emf.createEntityManager()).thenReturn(em); + when(emf.createEntityManager(any(Map.class))).thenReturn(em); + when(emf.createEntityManager(any(SynchronizationType.class))).thenReturn(em); + when(emf.createEntityManager(any(SynchronizationType.class), any(Map.class))).thenReturn(em); + + lenient().when(em.getReference(HsOfficePersonEntity.class, GIVEN_MANDANTE_UUID)).thenReturn(mandateMock); + lenient().when(em.getReference(HsOfficePersonEntity.class, GIVEN_PERSON_UUID)).thenReturn(personMock); + lenient().when(em.getReference(HsOfficeContactEntity.class, GIVEN_CONTACT_UUID)).thenReturn(contactMock); + lenient().when(em.getReference(any(), eq(GIVEN_INVALID_UUID))).thenThrow(EntityNotFoundException.class); + } + + @Nested + class AddPartner { + + @Test + void respondBadRequest_ifPersonUuidIsInvalid() throws Exception { + // when + mockMvc.perform(MockMvcRequestBuilders + .post("/api/hs/office/partners") + .header("current-user", "superuser-alex@hostsharing.net") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "partnerNumber": "20002", + "partnerRole": { + "relAnchorUuid": "%s", + "relHolderUuid": "%s", + "contactUuid": "%s" + }, + "personUuid": "%s", + "contactUuid": "%s", + "details": { + "registrationOffice": "Temp Registergericht Aurich", + "registrationNumber": "111111" + } + } + """.formatted( + GIVEN_MANDANTE_UUID, + GIVEN_INVALID_UUID, + GIVEN_CONTACT_UUID, + GIVEN_INVALID_UUID, + GIVEN_CONTACT_UUID)) + .accept(MediaType.APPLICATION_JSON)) + + // then + .andExpect(status().is4xxClientError()) + .andExpect(jsonPath("statusCode", is(400))) + .andExpect(jsonPath("statusPhrase", is("Bad Request"))) + .andExpect(jsonPath("message", startsWith("Cannot resolve HsOfficePersonEntity with uuid "))); + } + + @Test + void respondBadRequest_ifContactUuidIsInvalid() throws Exception { + // when + mockMvc.perform(MockMvcRequestBuilders + .post("/api/hs/office/partners") + .header("current-user", "superuser-alex@hostsharing.net") + .contentType(MediaType.APPLICATION_JSON) + .content(""" + { + "partnerNumber": "20002", + "partnerRole": { + "relAnchorUuid": "%s", + "relHolderUuid": "%s", + "contactUuid": "%s" + }, + "personUuid": "%s", + "contactUuid": "%s", + "details": { + "registrationOffice": "Temp Registergericht Aurich", + "registrationNumber": "111111" + } + } + """.formatted( + GIVEN_MANDANTE_UUID, + GIVEN_PERSON_UUID, + GIVEN_INVALID_UUID, + GIVEN_PERSON_UUID, + GIVEN_INVALID_UUID)) + .accept(MediaType.APPLICATION_JSON)) + + // then + .andExpect(status().is4xxClientError()) + .andExpect(jsonPath("statusCode", is(400))) + .andExpect(jsonPath("statusPhrase", is("Bad Request"))) + .andExpect(jsonPath("message", startsWith("Cannot resolve HsOfficeContactEntity with uuid "))); + } + } + + @Nested + class DeletePartner { + + @Test + void respondBadRequest_ifPartnerCannotBeDeleted() throws Exception { + // given + final UUID givenPartnerUuid = UUID.randomUUID(); + when(partnerRepo.findByUuid(givenPartnerUuid)).thenReturn(Optional.of(partnerMock)); + when(partnerRepo.deleteByUuid(givenPartnerUuid)).thenReturn(0); + + final UUID givenRelationshipUuid = UUID.randomUUID(); + when(partnerMock.getPartnerRole()).thenReturn(HsOfficeRelationshipEntity.builder() + .uuid(givenRelationshipUuid) + .build()); + when(relationshipRepo.deleteByUuid(givenRelationshipUuid)).thenReturn(0); + + // when + mockMvc.perform(MockMvcRequestBuilders + .delete("/api/hs/office/partners/" + givenPartnerUuid) + .header("current-user", "superuser-alex@hostsharing.net") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + + // then + .andExpect(status().isForbidden()); + } + + @Test + void respondBadRequest_ifRelationshipCannotBeDeleted() throws Exception { + // given + final UUID givenPartnerUuid = UUID.randomUUID(); + when(partnerRepo.findByUuid(givenPartnerUuid)).thenReturn(Optional.of(partnerMock)); + when(partnerRepo.deleteByUuid(givenPartnerUuid)).thenReturn(1); + when(relationshipRepo.deleteByUuid(any())).thenReturn(0); + + final UUID givenRelationshipUuid = UUID.randomUUID(); + when(partnerMock.getPartnerRole()).thenReturn(HsOfficeRelationshipEntity.builder() + .uuid(givenRelationshipUuid) + .build()); + when(relationshipRepo.deleteByUuid(givenRelationshipUuid)).thenReturn(0); + + // when + mockMvc.perform(MockMvcRequestBuilders + .delete("/api/hs/office/partners/" + givenPartnerUuid) + .header("current-user", "superuser-alex@hostsharing.net") + .contentType(MediaType.APPLICATION_JSON) + .accept(MediaType.APPLICATION_JSON)) + + // then + .andExpect(status().isForbidden()); + } + + } +}