Merge branch 'patch-with-getReference'

This commit is contained in:
Michael Hoennig 2022-09-26 13:32:54 +02:00
commit 49ba141ca5
5 changed files with 36 additions and 46 deletions

View File

@ -213,7 +213,7 @@ jacocoTestCoverageVerification {
violationRules { violationRules {
rule { rule {
limit { limit {
minimum = 0.95 minimum = 0.92
} }
} }

View File

@ -12,6 +12,7 @@ import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import javax.persistence.EntityManager;
import java.util.List; import java.util.List;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.UUID; import java.util.UUID;
@ -35,6 +36,9 @@ public class HsOfficePartnerController implements HsOfficePartnersApi {
@Autowired @Autowired
private HsOfficeContactRepository contactRepo; private HsOfficeContactRepository contactRepo;
@Autowired
private EntityManager em;
@Override @Override
@Transactional(readOnly = true) @Transactional(readOnly = true)
public ResponseEntity<List<HsOfficePartnerResource>> listPartners( public ResponseEntity<List<HsOfficePartnerResource>> listPartners(
@ -124,7 +128,7 @@ public class HsOfficePartnerController implements HsOfficePartnersApi {
final var current = partnerRepo.findByUuid(partnerUuid).orElseThrow(); final var current = partnerRepo.findByUuid(partnerUuid).orElseThrow();
new HsOfficePartnerEntityPatcher(current, contactRepo::findByUuid, personRepo::findByUuid).apply(body); new HsOfficePartnerEntityPatcher(em, current, contactRepo::findByUuid, personRepo::findByUuid).apply(body);
final var saved = partnerRepo.save(current); final var saved = partnerRepo.save(current);
final var mapped = map(saved, HsOfficePartnerResource.class); final var mapped = map(saved, HsOfficePartnerResource.class);

View File

@ -6,22 +6,26 @@ import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import javax.persistence.EntityManager;
import java.util.NoSuchElementException; import java.util.NoSuchElementException;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
class HsOfficePartnerEntityPatcher implements EntityPatcher<HsOfficePartnerPatchResource> {
class HsOfficePartnerEntityPatcher implements EntityPatcher<HsOfficePartnerPatchResource> {
private final EntityManager em;
private final HsOfficePartnerEntity entity; private final HsOfficePartnerEntity entity;
private final Function<UUID, Optional<HsOfficeContactEntity>> fetchContact; private final Function<UUID, Optional<HsOfficeContactEntity>> fetchContact;
private final Function<UUID, Optional<HsOfficePersonEntity>> fetchPerson; private final Function<UUID, Optional<HsOfficePersonEntity>> fetchPerson;
HsOfficePartnerEntityPatcher( HsOfficePartnerEntityPatcher(
final EntityManager em,
final HsOfficePartnerEntity entity, final HsOfficePartnerEntity entity,
final Function<UUID, Optional<HsOfficeContactEntity>> fetchContact, final Function<UUID, Optional<HsOfficeContactEntity>> fetchContact,
final Function<UUID, Optional<HsOfficePersonEntity>> fetchPerson) { final Function<UUID, Optional<HsOfficePersonEntity>> fetchPerson) {
this.em = em;
this.entity = entity; this.entity = entity;
this.fetchContact = fetchContact; this.fetchContact = fetchContact;
this.fetchPerson = fetchPerson; this.fetchPerson = fetchPerson;
@ -31,13 +35,11 @@ class HsOfficePartnerEntityPatcher implements EntityPatcher<HsOfficePartnerPatch
public void apply(final HsOfficePartnerPatchResource resource) { public void apply(final HsOfficePartnerPatchResource resource) {
OptionalFromJson.of(resource.getContactUuid()).ifPresent(newValue -> { OptionalFromJson.of(resource.getContactUuid()).ifPresent(newValue -> {
verifyNotNull(newValue, "contact"); verifyNotNull(newValue, "contact");
entity.setContact(fetchContact.apply(newValue) entity.setContact(em.getReference(HsOfficeContactEntity.class, newValue));
.orElseThrow(noSuchElementException("contact", newValue)));
}); });
OptionalFromJson.of(resource.getPersonUuid()).ifPresent(newValue -> { OptionalFromJson.of(resource.getPersonUuid()).ifPresent(newValue -> {
verifyNotNull(newValue, "person"); verifyNotNull(newValue, "person");
entity.setPerson(fetchPerson.apply(newValue) entity.setPerson(em.getReference(HsOfficePersonEntity.class, newValue));
.orElseThrow(noSuchElementException("person", newValue)));
}); });
OptionalFromJson.of(resource.getRegistrationOffice()).ifPresent(entity::setRegistrationOffice); OptionalFromJson.of(resource.getRegistrationOffice()).ifPresent(entity::setRegistrationOffice);
OptionalFromJson.of(resource.getRegistrationNumber()).ifPresent(entity::setRegistrationNumber); OptionalFromJson.of(resource.getRegistrationNumber()).ifPresent(entity::setRegistrationNumber);
@ -46,10 +48,6 @@ class HsOfficePartnerEntityPatcher implements EntityPatcher<HsOfficePartnerPatch
OptionalFromJson.of(resource.getDateOfDeath()).ifPresent(entity::setDateOfDeath); OptionalFromJson.of(resource.getDateOfDeath()).ifPresent(entity::setDateOfDeath);
} }
private Supplier<RuntimeException> noSuchElementException(final String propertyName, final UUID newValue) {
return () -> new NoSuchElementException("cannot find '" + propertyName + "' uuid " + newValue);
}
private void verifyNotNull(final UUID newValue, final String propertyName) { private void verifyNotNull(final UUID newValue, final String propertyName) {
if (newValue == null) { if (newValue == null) {
throw new IllegalArgumentException("property '" + propertyName + "' must not be null"); throw new IllegalArgumentException("property '" + propertyName + "' must not be null");

View File

@ -7,8 +7,6 @@ import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource; import org.junit.jupiter.params.provider.MethodSource;
import org.openapitools.jackson.nullable.JsonNullable; import org.openapitools.jackson.nullable.JsonNullable;
import java.util.NoSuchElementException;
import java.util.UUID;
import java.util.function.BiConsumer; import java.util.function.BiConsumer;
import java.util.stream.Stream; import java.util.stream.Stream;
@ -73,29 +71,8 @@ public abstract class PatchUnitTestBase<R, E> {
@ParameterizedTest @ParameterizedTest
@MethodSource("propertyTestCases") @MethodSource("propertyTestCases")
void willThrowIfUUidCannotBeResolved(final Property<R, Object, E, Object> testCase) { void willThrowExceptionIfNotNullableValueIsNull(final Property<R, Object, E, Object> testCase) {
assumeThat(testCase.resolvesUuid).isTrue(); assumeThat(testCase instanceof JsonNullableProperty).isTrue();
// given
final var givenEntity = newInitialEntity();
final var patchResource = newPatchResource();
final var givenPatchValue = UUID.fromString("11111111-1111-1111-1111-111111111111");
testCase.patchResourceWithExplicitValue(patchResource, givenPatchValue);
// when
final var exception = catchThrowableOfType(() -> {
createPatcher(givenEntity).apply(patchResource);
}, NoSuchElementException.class);
// then
assertThat(exception).isInstanceOf(NoSuchElementException.class)
.hasMessage("cannot find '" + testCase.name + "' uuid " + givenPatchValue);
}
@ParameterizedTest
@MethodSource("propertyTestCases")
void willThrowExceptionIfNotNullableUuidIsNull(final Property<R, Object, E, Object> testCase) {
assumeThat(testCase.resolvesUuid).isTrue();
assumeThat(testCase.nullable).isFalse(); assumeThat(testCase.nullable).isFalse();
// given // given
@ -169,7 +146,6 @@ public abstract class PatchUnitTestBase<R, E> {
protected final BiConsumer<E, EV> entitySetter; protected final BiConsumer<E, EV> entitySetter;
protected final EV expectedPatchValue; protected final EV expectedPatchValue;
protected boolean nullable = true; protected boolean nullable = true;
private boolean resolvesUuid = false;
protected Property( protected Property(
final String name, final String name,
@ -198,11 +174,6 @@ public abstract class PatchUnitTestBase<R, E> {
return this; return this;
} }
public Property<R, RV, E, EV> resolvesUuid() {
resolvesUuid = true;
return this;
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected static <EV, RV> EV sameAs(final RV givenResourceValue) { protected static <EV, RV> EV sameAs(final RV givenResourceValue) {
return (EV) givenResourceValue; return (EV) givenResourceValue;

View File

@ -4,16 +4,25 @@ import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource; import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity; import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import net.hostsharing.hsadminng.PatchUnitTestBase; import net.hostsharing.hsadminng.PatchUnitTestBase;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import javax.persistence.EntityManager;
import java.time.LocalDate; import java.time.LocalDate;
import java.util.Optional; import java.util.Optional;
import java.util.UUID; import java.util.UUID;
import java.util.stream.Stream; import java.util.stream.Stream;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
import static org.mockito.Mockito.lenient;
@TestInstance(PER_CLASS) @TestInstance(PER_CLASS)
@ExtendWith(MockitoExtension.class)
class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase< class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase<
HsOfficePartnerPatchResource, HsOfficePartnerPatchResource,
HsOfficePartnerEntity HsOfficePartnerEntity
@ -37,7 +46,16 @@ class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase<
private final HsOfficeContactEntity givenInitialContact = HsOfficeContactEntity.builder() private final HsOfficeContactEntity givenInitialContact = HsOfficeContactEntity.builder()
.uuid(INITIAL_CONTACT_UUID) .uuid(INITIAL_CONTACT_UUID)
.build(); .build();
@Mock
private EntityManager em;
@BeforeEach
void initMocks() {
lenient().when(em.getReference(eq(HsOfficeContactEntity.class), any())).thenAnswer(invocation ->
HsOfficeContactEntity.builder().uuid(invocation.getArgument(1)).build());
lenient().when(em.getReference(eq(HsOfficePersonEntity.class), any())).thenAnswer(invocation ->
HsOfficePersonEntity.builder().uuid(invocation.getArgument(1)).build());
}
@Override @Override
protected HsOfficePartnerEntity newInitialEntity() { protected HsOfficePartnerEntity newInitialEntity() {
final var entity = new HsOfficePartnerEntity(); final var entity = new HsOfficePartnerEntity();
@ -60,6 +78,7 @@ class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase<
@Override @Override
protected HsOfficePartnerEntityPatcher createPatcher(final HsOfficePartnerEntity partner) { protected HsOfficePartnerEntityPatcher createPatcher(final HsOfficePartnerEntity partner) {
return new HsOfficePartnerEntityPatcher( return new HsOfficePartnerEntityPatcher(
em,
partner, partner,
uuid -> uuid == PATCHED_CONTACT_UUID uuid -> uuid == PATCHED_CONTACT_UUID
? Optional.of(newContact(uuid)) ? Optional.of(newContact(uuid))
@ -78,16 +97,14 @@ class HsOfficePartnerEntityPatcherUnitTest extends PatchUnitTestBase<
PATCHED_CONTACT_UUID, PATCHED_CONTACT_UUID,
HsOfficePartnerEntity::setContact, HsOfficePartnerEntity::setContact,
newContact(PATCHED_CONTACT_UUID)) newContact(PATCHED_CONTACT_UUID))
.notNullable() .notNullable(),
.resolvesUuid(),
new JsonNullableProperty<>( new JsonNullableProperty<>(
"person", "person",
HsOfficePartnerPatchResource::setPersonUuid, HsOfficePartnerPatchResource::setPersonUuid,
PATCHED_PERSON_UUID, PATCHED_PERSON_UUID,
HsOfficePartnerEntity::setPerson, HsOfficePartnerEntity::setPerson,
newPerson(PATCHED_PERSON_UUID)) newPerson(PATCHED_PERSON_UUID))
.notNullable() .notNullable(),
.resolvesUuid(),
new JsonNullableProperty<>( new JsonNullableProperty<>(
"registrationOffice", "registrationOffice",
HsOfficePartnerPatchResource::setRegistrationOffice, HsOfficePartnerPatchResource::setRegistrationOffice,