avoid select before insert and map sub-entities in mapper

This commit is contained in:
Michael Hoennig 2022-10-26 16:44:51 +02:00
parent d7eed08420
commit 09c19649e4
57 changed files with 621 additions and 437 deletions

View File

@ -21,13 +21,13 @@ class CustomErrorResponse {
static String firstMessageLine(final Throwable exception) {
if (exception.getMessage() != null) {
return firstLine(exception.getMessage());
return line(exception.getMessage(), 0);
}
return "ERROR: [500] " + exception.getClass().getName();
}
static String firstLine(final String message) {
return message.split("\\r|\\n|\\r\\n", 0)[0];
static String line(final String message, final int lineNo) {
return message.split("\\r|\\n|\\r\\n", 0)[lineNo];
}
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")

View File

@ -31,21 +31,25 @@ public class RestResponseEntityExceptionHandler
protected ResponseEntity<CustomErrorResponse> handleConflict(
final RuntimeException exc, final WebRequest request) {
final var message = firstLine(NestedExceptionUtils.getMostSpecificCause(exc).getMessage());
final var rawMessage = NestedExceptionUtils.getMostSpecificCause(exc).getMessage();
var message = line(rawMessage, 0);
if (message.contains("violates foreign key constraint")) {
return errorResponse(request, HttpStatus.BAD_REQUEST, line(rawMessage, 1).replaceAll(" *Detail: *", ""));
}
return errorResponse(request, HttpStatus.CONFLICT, message);
}
@ExceptionHandler(JpaSystemException.class)
protected ResponseEntity<CustomErrorResponse> handleJpaExceptions(
final RuntimeException exc, final WebRequest request) {
final var message = firstLine(NestedExceptionUtils.getMostSpecificCause(exc).getMessage());
final var message = line(NestedExceptionUtils.getMostSpecificCause(exc).getMessage(), 0);
return errorResponse(request, httpStatus(message).orElse(HttpStatus.INTERNAL_SERVER_ERROR), message);
}
@ExceptionHandler(NoSuchElementException.class)
protected ResponseEntity<CustomErrorResponse> handleNoSuchElementException(
final RuntimeException exc, final WebRequest request) {
final var message = firstLine(NestedExceptionUtils.getMostSpecificCause(exc).getMessage());
final var message = line(NestedExceptionUtils.getMostSpecificCause(exc).getMessage(), 0);
return errorResponse(request, HttpStatus.NOT_FOUND, message);
}
@ -54,14 +58,14 @@ public class RestResponseEntityExceptionHandler
final RuntimeException exc, final WebRequest request) {
final var message =
userReadableEntityClassName(
firstLine(NestedExceptionUtils.getMostSpecificCause(exc).getMessage()));
line(NestedExceptionUtils.getMostSpecificCause(exc).getMessage(), 0));
return errorResponse(request, HttpStatus.BAD_REQUEST, message);
}
@ExceptionHandler({ Iban4jException.class, ValidationException.class })
protected ResponseEntity<CustomErrorResponse> handleIbanAndBicExceptions(
final Throwable exc, final WebRequest request) {
final var message = firstLine(NestedExceptionUtils.getMostSpecificCause(exc).getMessage());
final var message = line(NestedExceptionUtils.getMostSpecificCause(exc).getMessage(), 0);
return errorResponse(request, HttpStatus.BAD_REQUEST, message);
}

View File

@ -56,14 +56,13 @@ public class HsOfficeBankAccountController implements HsOfficeBankAccountsApi {
BicUtil.validate(body.getBic());
final var entityToSave = mapper.map(body, HsOfficeBankAccountEntity.class);
entityToSave.setUuid(UUID.randomUUID());
final var saved = bankAccountRepo.save(entityToSave);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/BankAccounts/{id}")
.buildAndExpand(entityToSave.getUuid())
.path("/api/hs/office/bankaccounts/{id}")
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficeBankAccountResource.class);
return ResponseEntity.created(uri).body(mapped);

View File

@ -2,11 +2,13 @@ package net.hostsharing.hsadminng.hs.office.bankaccount;
import lombok.*;
import lombok.experimental.FieldNameConstants;
import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import net.hostsharing.hsadminng.errors.DisplayName;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.util.UUID;
@ -29,7 +31,10 @@ public class HsOfficeBankAccountEntity implements Stringifyable {
.withProp(Fields.iban, HsOfficeBankAccountEntity::getIban)
.withProp(Fields.bic, HsOfficeBankAccountEntity::getBic);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
private String holder;
private String iban;

View File

@ -52,14 +52,13 @@ public class HsOfficeContactController implements HsOfficeContactsApi {
context.define(currentUser, assumedRoles);
final var entityToSave = mapper.map(body, HsOfficeContactEntity.class);
entityToSave.setUuid(UUID.randomUUID());
final var saved = contactRepo.save(entityToSave);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/contacts/{id}")
.buildAndExpand(entityToSave.getUuid())
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficeContactResource.class);
return ResponseEntity.created(uri).body(mapped);

View File

@ -5,11 +5,9 @@ import lombok.experimental.FieldNameConstants;
import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.*;
import java.util.UUID;
import static net.hostsharing.hsadminng.stringify.Stringify.stringify;
@ -29,7 +27,11 @@ public class HsOfficeContactEntity implements Stringifyable {
.withProp(Fields.label, HsOfficeContactEntity::getLabel)
.withProp(Fields.emailAddresses, HsOfficeContactEntity::getEmailAddresses);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
private String label;
@Column(name = "postaladdress")

View File

@ -66,14 +66,13 @@ public class HsOfficeCoopAssetsTransactionController implements HsOfficeCoopAsse
validate(requestBody);
final var entityToSave = mapper.map(requestBody, HsOfficeCoopAssetsTransactionEntity.class);
entityToSave.setUuid(UUID.randomUUID());
final var saved = coopAssetsTransactionRepo.save(entityToSave);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/coopassetstransactions/{id}")
.buildAndExpand(entityToSave.getUuid())
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficeCoopAssetsTransactionResource.class);
return ResponseEntity.created(uri).body(mapped);

View File

@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
@ -40,7 +41,10 @@ public class HsOfficeCoopAssetsTransactionEntity implements Stringifyable {
.withSeparator(", ")
.quotedValues(false);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@ManyToOne
@JoinColumn(name = "membershipuuid")

View File

@ -67,14 +67,13 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar
validate(requestBody);
final var entityToSave = mapper.map(requestBody, HsOfficeCoopSharesTransactionEntity.class);
entityToSave.setUuid(UUID.randomUUID());
final var saved = coopSharesTransactionRepo.save(entityToSave);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/coopsharestransactions/{id}")
.buildAndExpand(entityToSave.getUuid())
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficeCoopSharesTransactionResource.class);
return ResponseEntity.created(uri).body(mapped);

View File

@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.hs.office.membership.HsOfficeMembershipEntity;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
@ -38,7 +39,10 @@ public class HsOfficeCoopSharesTransactionEntity implements Stringifyable {
.withSeparator(", ")
.quotedValues(false);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@ManyToOne
@JoinColumn(name = "membershipuuid")

View File

@ -59,14 +59,13 @@ public class HsOfficeDebitorController implements HsOfficeDebitorsApi {
context.define(currentUser, assumedRoles);
final var entityToSave = mapper.map(body, HsOfficeDebitorEntity.class);
entityToSave.setUuid(UUID.randomUUID());
final var saved = debitorRepo.save(entityToSave);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/debitors/{id}")
.buildAndExpand(entityToSave.getUuid())
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficeDebitorResource.class);
return ResponseEntity.created(uri).body(mapped);

View File

@ -7,6 +7,7 @@ import net.hostsharing.hsadminng.stringify.Stringifyable;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.UUID;
@ -30,28 +31,35 @@ public class HsOfficeDebitorEntity implements Stringifyable {
.withSeparator(": ")
.quotedValues(false);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@ManyToOne
@JoinColumn(name = "partneruuid")
private HsOfficePartnerEntity partner;
private @Column(name = "debitornumber") Integer debitorNumber;
@Column(name = "debitornumber")
private Integer debitorNumber;
@ManyToOne
@JoinColumn(name = "billingcontactuuid")
private HsOfficeContactEntity billingContact;
private @Column(name = "vatid") String vatId;
private @Column(name = "vatcountrycode") String vatCountryCode;
private @Column(name = "vatbusiness") boolean vatBusiness;
@Column(name = "vatid")
private String vatId;
@Column(name = "vatcountrycode")
private String vatCountryCode;
@Column(name = "vatbusiness")
private boolean vatBusiness;
@ManyToOne
@JoinColumn(name = "refundbankaccountuuid")
private HsOfficeBankAccountEntity refundBankAccount;
@Override
public String toString() {
return stringify.apply(this);

View File

@ -61,14 +61,13 @@ public class HsOfficeMembershipController implements HsOfficeMembershipsApi {
context.define(currentUser, assumedRoles);
final var entityToSave = mapper.map(body, HsOfficeMembershipEntity.class);
entityToSave.setUuid(UUID.randomUUID());
final var saved = membershipRepo.save(entityToSave);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/Memberships/{id}")
.buildAndExpand(entityToSave.getUuid())
.path("/api/hs/office/memberships/{id}")
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficeMembershipResource.class,
SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER);

View File

@ -9,12 +9,11 @@ import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.hibernate.annotations.Fetch;
import org.hibernate.annotations.FetchMode;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
import org.hibernate.annotations.*;
import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Table;
import java.time.LocalDate;
import java.util.UUID;
@ -48,7 +47,10 @@ public class HsOfficeMembershipEntity implements Stringifyable {
.withSeparator(", ")
.quotedValues(false);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@ManyToOne
@JoinColumn(name = "partneruuid")
@ -63,7 +65,7 @@ public class HsOfficeMembershipEntity implements Stringifyable {
private int memberNumber;
@Column(name = "validity", columnDefinition = "daterange")
private Range<LocalDate> validity = Range.infinite(LocalDate.class);
private Range<LocalDate> validity;
@Column(name = "reasonfortermination")
@Enumerated(EnumType.STRING)
@ -78,6 +80,13 @@ public class HsOfficeMembershipEntity implements Stringifyable {
validity = toPostgresDateRange(getValidity().lower(), validTo);
}
public Range<LocalDate> getValidity() {
if ( validity == null ) {
validity = Range.infinite(LocalDate.class);
};
return validity;
}
@Override
public String toString() {
return stringify.apply(this);

View File

@ -1,6 +1,7 @@
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.generated.api.v1.api.HsOfficePartnersApi;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerInsertResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficePartnerPatchResource;
@ -56,16 +57,13 @@ public class HsOfficePartnerController implements HsOfficePartnersApi {
context.define(currentUser, assumedRoles);
final var entityToSave = mapper.map(body, HsOfficePartnerEntity.class);
entityToSave.setUuid(UUID.randomUUID());
entityToSave.setDetails(mapper.map(body.getDetails(), HsOfficePartnerDetailsEntity.class));
entityToSave.getDetails().setUuid(UUID.randomUUID());
final var saved = partnerRepo.save(entityToSave);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/partners/{id}")
.buildAndExpand(entityToSave.getUuid())
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficePartnerResource.class);
return ResponseEntity.created(uri).body(mapped);

View File

@ -4,11 +4,9 @@ import lombok.*;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import net.hostsharing.hsadminng.errors.DisplayName;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.*;
import java.time.LocalDate;
import java.util.UUID;
@ -35,7 +33,10 @@ public class HsOfficePartnerDetailsEntity implements Stringifyable {
.withSeparator(", ")
.quotedValues(false);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
private @Column(name = "registrationoffice") String registrationOffice;
private @Column(name = "registrationnumber") String registrationNumber;

View File

@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.NotFound;
import org.hibernate.annotations.NotFoundAction;
@ -30,7 +31,10 @@ public class HsOfficePartnerEntity implements Stringifyable {
.withSeparator(": ")
.quotedValues(false);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@ManyToOne
@JoinColumn(name = "personuuid", nullable = false)

View File

@ -52,14 +52,13 @@ public class HsOfficePersonController implements HsOfficePersonsApi {
context.define(currentUser, assumedRoles);
final var entityToSave = mapper.map(body, HsOfficePersonEntity.class);
entityToSave.setUuid(UUID.randomUUID());
final var saved = personRepo.save(entityToSave);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/persons/{id}")
.buildAndExpand(entityToSave.getUuid())
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficePersonResource.class);
return ResponseEntity.created(uri).body(mapped);

View File

@ -7,6 +7,7 @@ import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
@ -36,7 +37,10 @@ public class HsOfficePersonEntity implements Stringifyable {
.withProp(Fields.familyName, HsOfficePersonEntity::getFamilyName)
.withProp(Fields.givenName, HsOfficePersonEntity::getGivenName);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@Column(name = "persontype")
@Enumerated(EnumType.STRING)

View File

@ -69,7 +69,6 @@ public class HsOfficeRelationshipController implements HsOfficeRelationshipsApi
final var entityToSave = new HsOfficeRelationshipEntity();
entityToSave.setRelType(HsOfficeRelationshipType.valueOf(body.getRelType()));
entityToSave.setUuid(UUID.randomUUID());
entityToSave.setRelAnchor(relHolderRepo.findByUuid(body.getRelAnchorUuid()).orElseThrow(
() -> new NoSuchElementException("cannot find relAnchorUuid " + body.getRelAnchorUuid())
));
@ -85,7 +84,7 @@ public class HsOfficeRelationshipController implements HsOfficeRelationshipsApi
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/relationships/{id}")
.buildAndExpand(entityToSave.getUuid())
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficeRelationshipResource.class,
RELATIONSHIP_ENTITY_TO_RESOURCE_POSTMAPPER);

View File

@ -6,6 +6,7 @@ import lombok.experimental.FieldNameConstants;
import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
import net.hostsharing.hsadminng.hs.office.person.HsOfficePersonEntity;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Type;
import org.hibernate.annotations.TypeDef;
@ -34,7 +35,10 @@ public class HsOfficeRelationshipEntity {
.withProp(Fields.relHolder, HsOfficeRelationshipEntity::getRelHolder)
.withProp(Fields.contact, HsOfficeRelationshipEntity::getContact);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@ManyToOne
@JoinColumn(name = "relanchoruuid")

View File

@ -1,12 +1,11 @@
package net.hostsharing.hsadminng.hs.office.sepamandate;
import com.vladmihalcea.hibernate.type.range.Range;
import net.hostsharing.hsadminng.mapper.Mapper;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.api.HsOfficeSepaMandatesApi;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeSepaMandateInsertResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeSepaMandatePatchResource;
import net.hostsharing.hsadminng.hs.office.generated.api.v1.model.HsOfficeSepaMandateResource;
import net.hostsharing.hsadminng.mapper.Mapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
@ -62,14 +61,13 @@ public class HsOfficeSepaMandateController implements HsOfficeSepaMandatesApi {
context.define(currentUser, assumedRoles);
final var entityToSave = mapper.map(body, HsOfficeSepaMandateEntity.class, SEPA_MANDATE_RESOURCE_TO_ENTITY_POSTMAPPER);
entityToSave.setUuid(UUID.randomUUID());
final var saved = SepaMandateRepo.save(entityToSave);
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/hs/office/SepaMandates/{id}")
.buildAndExpand(entityToSave.getUuid())
.path("/api/hs/office/sepamandates/{id}")
.buildAndExpand(saved.getUuid())
.toUri();
final var mapped = mapper.map(saved, HsOfficeSepaMandateResource.class,
SEPA_MANDATE_ENTITY_TO_RESOURCE_POSTMAPPER);

View File

@ -8,6 +8,7 @@ import net.hostsharing.hsadminng.stringify.Stringify;
import net.hostsharing.hsadminng.stringify.Stringifyable;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountEntity;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.TypeDef;
import javax.persistence.*;
@ -37,7 +38,10 @@ public class HsOfficeSepaMandateEntity implements Stringifyable {
.withSeparator(", ")
.quotedValues(false);
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@ManyToOne
@JoinColumn(name = "debitoruuid")

View File

@ -1,7 +1,14 @@
package net.hostsharing.hsadminng.mapper;
import net.hostsharing.hsadminng.errors.DisplayName;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.ReflectionUtils;
import javax.persistence.EntityManager;
import javax.persistence.ManyToOne;
import javax.validation.ValidationException;
import java.lang.reflect.Field;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
@ -11,6 +18,9 @@ import java.util.stream.Collectors;
*/
public class Mapper extends ModelMapper {
@Autowired
EntityManager em;
public Mapper() {
getConfiguration().setAmbiguityIgnored(true);
}
@ -32,6 +42,45 @@ public class Mapper extends ModelMapper {
.collect(Collectors.toList());
}
@Override
public <D> D map(final Object source, final Class<D> destinationType) {
final var target = super.map(source, destinationType);
for (Field f : destinationType.getDeclaredFields()) {
if (f.getAnnotation(ManyToOne.class) == null) {
continue;
}
ReflectionUtils.makeAccessible(f);
final var subEntity = ReflectionUtils.getField(f, target);
if (subEntity == null) {
continue;
}
final var subEntityUuidField = ReflectionUtils.findField(f.getType(), "uuid");
if (subEntityUuidField == null) {
continue;
}
ReflectionUtils.makeAccessible(subEntityUuidField);
final var subEntityUuid = ReflectionUtils.getField(subEntityUuidField, subEntity);
if (subEntityUuid == null) {
continue;
}
ReflectionUtils.setField(f, target, findEntityById(f.getType(), subEntityUuid));
}
return target;
}
private Object findEntityById(final Class<?> entityClass, final Object subEntityUuid) {
// using getReference would be more efficent, but results in very technical error messages
final var entity = em.find(entityClass, subEntityUuid);
if (entity != null) {
return entity;
}
final var displayNameAnnot = entityClass.getAnnotation(DisplayName.class);
final var displayName = displayNameAnnot != null ? displayNameAnnot.value() : entityClass.getSimpleName();
throw new ValidationException("Unable to find %s with uuid %s".formatted(
displayName, subEntityUuid
));
}
public <S, T> T map(final S source, final Class<T> targetClass, final BiConsumer<S, T> postMapper) {
if (source == null) {
return null;

View File

@ -2,6 +2,7 @@ package net.hostsharing.hsadminng.rbac.rbacrole;
import lombok.*;
import org.hibernate.annotations.Formula;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.annotation.Immutable;
import javax.persistence.*;
@ -18,6 +19,8 @@ import java.util.UUID;
public class RbacRoleEntity {
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@Column(name = "objectuuid")

View File

@ -1,9 +1,11 @@
package net.hostsharing.hsadminng.rbac.rbacuser;
import lombok.*;
import org.hibernate.annotations.GenericGenerator;
import org.springframework.data.annotation.Immutable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Table;
import java.time.LocalDateTime;
@ -25,6 +27,8 @@ public class RbacUserEntity {
private static DateTimeFormatter DATE_FORMAT_WITH_FULLHOUR = DateTimeFormatter.ofPattern("MM-dd-yyyy HH");
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
private String name;

View File

@ -48,16 +48,12 @@ public class TestCustomerController implements TestCustomersApi {
context.define(currentUser, assumedRoles);
if (customer.getUuid() == null) {
customer.setUuid(UUID.randomUUID());
}
final var saved = testCustomerRepository.save(mapper.map(customer, TestCustomerEntity.class));
final var uri =
MvcUriComponentsBuilder.fromController(getClass())
.path("/api/test/customers/{id}")
.buildAndExpand(customer.getUuid())
.buildAndExpand(saved.getUuid())
.toUri();
return ResponseEntity.created(uri).body(mapper.map(saved, TestCustomerResource.class));
}

View File

@ -4,6 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.UUID;
@ -15,8 +16,14 @@ import java.util.UUID;
@NoArgsConstructor
@AllArgsConstructor
public class TestCustomerEntity {
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
private String prefix;
private int reference;
private @Column(name="adminusername")String adminUserName;
@Column(name="adminusername")
private String adminUserName;
}

View File

@ -5,6 +5,7 @@ import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import net.hostsharing.hsadminng.test.cust.TestCustomerEntity;
import org.hibernate.annotations.GenericGenerator;
import javax.persistence.*;
import java.util.UUID;
@ -17,7 +18,10 @@ import java.util.UUID;
@AllArgsConstructor
public class TestPackageEntity {
private @Id UUID uuid;
@Id
@GeneratedValue(generator = "UUID")
@GenericGenerator(name = "UUID", strategy = "org.hibernate.id.UUIDGenerator")
private UUID uuid;
@Version
private int version;

View File

@ -9,6 +9,7 @@ import org.springframework.core.MethodParameter;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.validation.BindingResult;
@ -43,6 +44,25 @@ class RestResponseEntityExceptionHandlerUnitTest {
assertThat(errorResponse.getBody().getMessage()).isEqualTo("First Line");
}
@Test
void handleForeignKeyViolation() {
// given
final var givenException = new DataIntegrityViolationException("""
... violates foreign key constraint ...
Detail: Second Line
Third Line
""");
final var givenWebRequest = mock(WebRequest.class);
// when
final var errorResponse = exceptionHandler.handleConflict(givenException, givenWebRequest);
// then
assertThat(errorResponse.getStatusCodeValue()).isEqualTo(400);
assertThat(errorResponse.getBody()).isNotNull()
.extracting(CustomErrorResponse::getMessage).isEqualTo("Second Line");
}
@Test
void jpaExceptionWithKnownErrorCode() {
// given

View File

@ -9,7 +9,6 @@ public class TestHsOfficeBankAccount {
static public HsOfficeBankAccountEntity hsOfficeBankAccount(final String holder, final String iban, final String bic) {
return HsOfficeBankAccountEntity.builder()
.uuid(UUID.randomUUID())
.holder(holder)
.iban(iban)
.bic(bic)

View File

@ -17,8 +17,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
@ -49,7 +48,8 @@ class HsOfficeContactControllerAcceptanceTest {
@Autowired
JpaAttempt jpaAttempt;
Set<UUID> tempContactUuids = new HashSet<>();
@Autowired
EntityManager em;
@Nested
@Accepts({ "Contact:F(Find)" })
@ -103,7 +103,7 @@ class HsOfficeContactControllerAcceptanceTest {
.contentType(ContentType.JSON)
.body("""
{
"label": "Test Contact",
"label": "Temp Contact",
"emailAddresses": "test@example.org"
}
""")
@ -114,14 +114,14 @@ class HsOfficeContactControllerAcceptanceTest {
.statusCode(201)
.contentType(ContentType.JSON)
.body("uuid", isUuidValid())
.body("label", is("Test Contact"))
.body("label", is("Temp Contact"))
.body("emailAddresses", is("test@example.org"))
.header("Location", startsWith("http://localhost"))
.extract().header("Location"); // @formatter:on
// finally, the new contact can be accessed under the generated UUID
final var newUserUuid = toCleanup(UUID.fromString(
location.substring(location.lastIndexOf('/') + 1)));
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
assertThat(newUserUuid).isNotNull();
}
}
@ -208,7 +208,7 @@ class HsOfficeContactControllerAcceptanceTest {
.contentType(ContentType.JSON)
.body("""
{
"label": "patched contact",
"label": "Temp patched contact",
"emailAddresses": "patched@example.org",
"postalAddress": "Patched Address",
"phoneNumbers": "+01 100 123456"
@ -221,7 +221,7 @@ class HsOfficeContactControllerAcceptanceTest {
.statusCode(200)
.contentType(ContentType.JSON)
.body("uuid", isUuidValid())
.body("label", is("patched contact"))
.body("label", is("Temp patched contact"))
.body("emailAddresses", is("patched@example.org"))
.body("postalAddress", is("Patched Address"))
.body("phoneNumbers", is("+01 100 123456"));
@ -231,7 +231,7 @@ class HsOfficeContactControllerAcceptanceTest {
context.define("superuser-alex@hostsharing.net");
assertThat(contactRepo.findByUuid(givenContact.getUuid())).isPresent().get()
.matches(person -> {
assertThat(person.getLabel()).isEqualTo("patched contact");
assertThat(person.getLabel()).isEqualTo("Temp patched contact");
assertThat(person.getEmailAddresses()).isEqualTo("patched@example.org");
assertThat(person.getPostalAddress()).isEqualTo("Patched Address");
assertThat(person.getPhoneNumbers()).isEqualTo("+01 100 123456");
@ -353,28 +353,16 @@ class HsOfficeContactControllerAcceptanceTest {
.phoneNumbers("+01 200 " + RandomStringUtils.randomNumeric(8))
.build();
toCleanup(newContact.getUuid());
return contactRepo.save(newContact);
}).assertSuccessful().returnedValue();
}
private UUID toCleanup(final UUID tempContactUuid) {
tempContactUuids.add(tempContactUuid);
return tempContactUuid;
}
@BeforeEach
@AfterEach
void cleanup() {
tempContactUuids.forEach(uuid -> {
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
System.out.println("DELETING temporary contact: " + uuid);
final var count = contactRepo.deleteByUuid(uuid);
System.out.println("DELETED temporary contact: " + uuid + (count > 0 ? " successful" : " failed"));
}).assertSuccessful();
});
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
em.createQuery("DELETE FROM HsOfficeContactEntity c WHERE c.label LIKE 'Temp %'").executeUpdate();
}).assertSuccessful();
}
}

View File

@ -54,9 +54,6 @@ class HsOfficeContactRepositoryIntegrationTest extends ContextBasedTest {
@MockBean
HttpServletRequest request;
@Container
Container postgres;
@Nested
class CreateContact {

View File

@ -8,7 +8,6 @@ public class TestHsOfficeContact {
static public HsOfficeContactEntity hsOfficeContact(final String label, final String emailAddr) {
return HsOfficeContactEntity.builder()
.uuid(UUID.randomUUID())
.label(label)
.postalAddress("address of " + label)
.emailAddresses(emailAddr)

View File

@ -71,7 +71,6 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
// when
final var result = attempt(em, () -> {
final var newCoopAssetsTransaction = HsOfficeCoopAssetsTransactionEntity.builder()
.uuid(UUID.randomUUID())
.membership(givenMembership)
.transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT)
.assetValue(new BigDecimal("128.00"))
@ -104,7 +103,6 @@ class HsOfficeCoopAssetsTransactionRepositoryIntegrationTest extends ContextBase
null,
10001).get(0);
final var newCoopAssetsTransaction = HsOfficeCoopAssetsTransactionEntity.builder()
.uuid(UUID.randomUUID())
.membership(givenMembership)
.transactionType(HsOfficeCoopAssetsTransactionType.DEPOSIT)
.assetValue(new BigDecimal("128.00"))

View File

@ -69,7 +69,6 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
// when
final var result = attempt(em, () -> {
final var newCoopSharesTransaction = HsOfficeCoopSharesTransactionEntity.builder()
.uuid(UUID.randomUUID())
.membership(givenMembership)
.transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION)
.shareCount(4)
@ -102,7 +101,6 @@ class HsOfficeCoopSharesTransactionRepositoryIntegrationTest extends ContextBase
null,
10001).get(0);
final var newCoopSharesTransaction = HsOfficeCoopSharesTransactionEntity.builder()
.uuid(UUID.randomUUID())
.membership(givenMembership)
.transactionType(HsOfficeCoopSharesTransactionType.SUBSCRIPTION)
.shareCount(4)

View File

@ -2,15 +2,16 @@ package net.hostsharing.hsadminng.hs.office.debitor;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import net.hostsharing.test.Accepts;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerRepository;
import net.hostsharing.test.Accepts;
import net.hostsharing.test.JpaAttempt;
import org.json.JSONException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -18,8 +19,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
@ -35,7 +35,8 @@ import static org.hamcrest.Matchers.*;
@Transactional
class HsOfficeDebitorControllerAcceptanceTest {
private static int nextDebitorNumber = 20001;
private static final int LOWEST_TEMP_DEBITOR_NUMBER = 20000;
private static int nextDebitorNumber = LOWEST_TEMP_DEBITOR_NUMBER;
@LocalServerPort
private Integer port;
@ -58,7 +59,8 @@ class HsOfficeDebitorControllerAcceptanceTest {
@Autowired
JpaAttempt jpaAttempt;
Set<UUID> tempDebitorUuids = new HashSet<>();
@Autowired
EntityManager em;
@Nested
@Accepts({ "Debitor:F(Find)" })
@ -164,7 +166,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
"vatBusiness": true,
"refundBankAccountUuid": "%s"
}
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), nextDebitorNumber++, givenBankAccount.getUuid()))
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), ++nextDebitorNumber, givenBankAccount.getUuid()))
.port(port)
.when()
.post("http://localhost/api/hs/office/debitors")
@ -180,8 +182,8 @@ class HsOfficeDebitorControllerAcceptanceTest {
.extract().header("Location"); // @formatter:on
// finally, the new debitor can be accessed under the generated UUID
final var newUserUuid = toCleanup(UUID.fromString(
location.substring(location.lastIndexOf('/') + 1)));
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
assertThat(newUserUuid).isNotNull();
}
@ -202,7 +204,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
"billingContactUuid": "%s",
"debitorNumber": "%s"
}
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), nextDebitorNumber++))
""".formatted( givenPartner.getUuid(), givenContact.getUuid(), ++nextDebitorNumber))
.port(port)
.when()
.post("http://localhost/api/hs/office/debitors")
@ -220,8 +222,8 @@ class HsOfficeDebitorControllerAcceptanceTest {
.extract().header("Location"); // @formatter:on
// finally, the new debitor can be accessed under the generated UUID
final var newUserUuid = toCleanup(UUID.fromString(
location.substring(location.lastIndexOf('/') + 1)));
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
assertThat(newUserUuid).isNotNull();
}
@ -245,7 +247,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
"vatCountryCode": "DE",
"vatBusiness": true
}
""".formatted( givenPartner.getUuid(), givenContactUuid, nextDebitorNumber++))
""".formatted( givenPartner.getUuid(), givenContactUuid, ++nextDebitorNumber))
.port(port)
.when()
.post("http://localhost/api/hs/office/debitors")
@ -275,7 +277,7 @@ class HsOfficeDebitorControllerAcceptanceTest {
"vatCountryCode": "DE",
"vatBusiness": true
}
""".formatted( givenPartnerUuid, givenContact.getUuid(), nextDebitorNumber++))
""".formatted( givenPartnerUuid, givenContact.getUuid(), ++nextDebitorNumber))
.port(port)
.when()
.post("http://localhost/api/hs/office/debitors")
@ -520,33 +522,24 @@ class HsOfficeDebitorControllerAcceptanceTest {
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
final var newDebitor = HsOfficeDebitorEntity.builder()
.uuid(UUID.randomUUID())
.debitorNumber(nextDebitorNumber++)
.debitorNumber(++nextDebitorNumber)
.partner(givenPartner)
.billingContact(givenContact)
.build();
toCleanup(newDebitor.getUuid());
return debitorRepo.save(newDebitor);
}).assertSuccessful().returnedValue();
}
private UUID toCleanup(final UUID tempDebitorUuid) {
tempDebitorUuids.add(tempDebitorUuid);
return tempDebitorUuid;
}
@BeforeEach
@AfterEach
void cleanup() {
tempDebitorUuids.forEach(uuid -> {
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
System.out.println("DELETING temporary debitor: " + uuid);
final var count = debitorRepo.deleteByUuid(uuid);
System.out.println("DELETED temporary debitor: " + uuid + (count > 0 ? " successful" : " failed"));
});
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net");
final var count = em.createQuery(
"DELETE FROM HsOfficeDebitorEntity d WHERE d.debitorNumber > " + LOWEST_TEMP_DEBITOR_NUMBER)
.executeUpdate();
System.out.printf("deleted %d entities%n", count);
});
}
}

View File

@ -79,7 +79,6 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () -> {
final var newDebitor = HsOfficeDebitorEntity.builder()
.uuid(UUID.randomUUID())
.debitorNumber(20001)
.partner(givenPartner)
.billingContact(givenContact)
@ -112,7 +111,6 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("Fourth").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
final var newDebitor = HsOfficeDebitorEntity.builder()
.uuid(UUID.randomUUID())
.debitorNumber(20002)
.partner(givenPartner)
.billingContact(givenContact)
@ -544,7 +542,6 @@ class HsOfficeDebitorRepositoryIntegrationTest extends ContextBasedTest {
final var givenBankAccount =
bankAccount != null ? bankAccountRepo.findByOptionalHolderLike(bankAccount).get(0) : null;
final var newDebitor = HsOfficeDebitorEntity.builder()
.uuid(UUID.randomUUID())
.debitorNumber(20000)
.partner(givenPartner)
.billingContact(givenContact)

View File

@ -11,7 +11,6 @@ import static net.hostsharing.hsadminng.hs.office.partner.TestHsOfficePartner.TE
public class TestHsOfficeDebitor {
public static final HsOfficeDebitorEntity TEST_DEBITOR = HsOfficeDebitorEntity.builder()
.uuid(UUID.randomUUID())
.debitorNumber(10001)
.partner(TEST_PARTNER)
.billingContact(TEST_CONTACT)

View File

@ -2,26 +2,25 @@ package net.hostsharing.hsadminng.hs.office.membership;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.coopassets.HsOfficeCoopAssetsTransactionRepository;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
import net.hostsharing.hsadminng.hs.office.partner.HsOfficePartnerEntity;
import net.hostsharing.hsadminng.mapper.Mapper;
import org.junit.jupiter.api.Test;
import org.junit.runner.RunWith;
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.boot.test.mock.mockito.SpyBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.orm.jpa.JpaObjectRetrievalFailureException;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import javax.persistence.EntityManager;
import javax.persistence.EntityNotFoundException;
import java.util.UUID;
import static org.hamcrest.Matchers.is;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
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;
@ -97,14 +96,13 @@ public class HsOfficeMembershipControllerRestTest {
}
@Test
void respondBadRequest_ifAnyGivenUuidCannotBeResolved() throws Exception {
void respondBadRequest_ifAnyGivenPartnerUuidCannotBeFound() throws Exception {
// given
when(membershipRepo.save(any())).thenThrow(
new JpaObjectRetrievalFailureException(
new EntityNotFoundException(
// same would happen with HsOfficePartnerEntity which could not be resolved
"Unable to find net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity with id ...")));
final var givenPartnerUuid = UUID.randomUUID();
final var givenMainDebitorUuid = UUID.randomUUID();
when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(null);
when(em.find(HsOfficeDebitorEntity.class, givenMainDebitorUuid)).thenReturn(mock(HsOfficeDebitorEntity.class));
// when
mockMvc.perform(MockMvcRequestBuilders
@ -118,13 +116,44 @@ public class HsOfficeMembershipControllerRestTest {
"memberNumber": 20001,
"validFrom": "2022-10-13"
}
""".formatted(UUID.randomUUID(), UUID.randomUUID()))
""".formatted(givenPartnerUuid, givenMainDebitorUuid))
.accept(MediaType.APPLICATION_JSON))
// then
.andExpect(status().is4xxClientError())
.andExpect(jsonPath("status", is(400)))
.andExpect(jsonPath("error", is("Bad Request")))
.andExpect(jsonPath("message", is("Unable to find Debitor with uuid ...")));
.andExpect(jsonPath("message", is("Unable to find Partner with uuid " + givenPartnerUuid)));
}
@Test
void respondBadRequest_ifAnyGivenDebitorUuidCannotBeFound() throws Exception {
// given
final var givenPartnerUuid = UUID.randomUUID();
final var givenMainDebitorUuid = UUID.randomUUID();
when(em.find(HsOfficePartnerEntity.class, givenPartnerUuid)).thenReturn(mock(HsOfficePartnerEntity.class));
when(em.find(HsOfficeDebitorEntity.class, givenMainDebitorUuid)).thenReturn(null);
// when
mockMvc.perform(MockMvcRequestBuilders
.post("/api/hs/office/memberships")
.header("current-user", "superuser-alex@hostsharing.net")
.contentType(MediaType.APPLICATION_JSON)
.content("""
{
"partnerUuid": "%s",
"mainDebitorUuid": "%s",
"memberNumber": 20001,
"validFrom": "2022-10-13"
}
""".formatted(givenPartnerUuid, givenMainDebitorUuid))
.accept(MediaType.APPLICATION_JSON))
// then
.andExpect(status().is4xxClientError())
.andExpect(jsonPath("status", is(400)))
.andExpect(jsonPath("error", is("Bad Request")))
.andExpect(jsonPath("message", is("Unable to find Debitor with uuid " + givenMainDebitorUuid)));
}
}

View File

@ -76,7 +76,6 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () -> {
final var newMembership = toCleanup(HsOfficeMembershipEntity.builder()
.uuid(UUID.randomUUID())
.memberNumber(20001)
.partner(givenPartner)
.mainDebitor(givenDebitor)
@ -107,7 +106,6 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike("First").get(0);
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0);
final var newMembership = toCleanup(HsOfficeMembershipEntity.builder()
.uuid(UUID.randomUUID())
.memberNumber(20002)
.partner(givenPartner)
.mainDebitor(givenDebitor)
@ -409,7 +407,6 @@ class HsOfficeMembershipRepositoryIntegrationTest extends ContextBasedTest {
final var givenPartner = partnerRepo.findPartnerByOptionalNameLike(partnerTradeName).get(0);
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike(debitorName).get(0);
final var newMembership = HsOfficeMembershipEntity.builder()
.uuid(UUID.randomUUID())
.memberNumber(20002)
.partner(givenPartner)
.mainDebitor(givenDebitor)

View File

@ -11,7 +11,6 @@ public class TestHsMembership {
public static final HsOfficeMembershipEntity TEST_MEMBERSHIP =
HsOfficeMembershipEntity.builder()
.uuid(UUID.randomUUID())
.partner(TEST_PARTNER)
.memberNumber(300001)
.validity(Range.closedInfinite(LocalDate.parse("2020-01-01")))

View File

@ -17,8 +17,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
@ -32,7 +31,6 @@ import static org.hamcrest.Matchers.startsWith;
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, JpaAttempt.class }
)
@Transactional
class HsOfficePartnerControllerAcceptanceTest {
@LocalServerPort
@ -56,10 +54,12 @@ class HsOfficePartnerControllerAcceptanceTest {
@Autowired
JpaAttempt jpaAttempt;
Set<UUID> tempPartnerUuids = new HashSet<>();
@Autowired
EntityManager em;
@Nested
@Accepts({ "Partner:F(Find)" })
@Transactional
class ListPartners {
@Test
@ -109,6 +109,7 @@ class HsOfficePartnerControllerAcceptanceTest {
@Nested
@Accepts({ "Partner:C(Create)" })
@Transactional
class AddPartner {
@Test
@ -127,8 +128,8 @@ class HsOfficePartnerControllerAcceptanceTest {
"contactUuid": "%s",
"personUuid": "%s",
"details": {
"registrationOffice": "Registergericht Aurich",
"registrationNumber": "123456"
"registrationOffice": "Temp Registergericht Aurich",
"registrationNumber": "111111"
}
}
""".formatted(givenContact.getUuid(), givenPerson.getUuid()))
@ -139,16 +140,16 @@ class HsOfficePartnerControllerAcceptanceTest {
.statusCode(201)
.contentType(ContentType.JSON)
.body("uuid", isUuidValid())
.body("details.registrationOffice", is("Registergericht Aurich"))
.body("details.registrationNumber", is("123456"))
.body("details.registrationOffice", is("Temp Registergericht Aurich"))
.body("details.registrationNumber", is("111111"))
.body("contact.label", is(givenContact.getLabel()))
.body("person.tradeName", is(givenPerson.getTradeName()))
.header("Location", startsWith("http://localhost"))
.extract().header("Location"); // @formatter:on
// finally, the new partner can be accessed under the generated UUID
final var newUserUuid = toCleanup(UUID.fromString(
location.substring(location.lastIndexOf('/') + 1)));
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
assertThat(newUserUuid).isNotNull();
}
@ -209,6 +210,7 @@ class HsOfficePartnerControllerAcceptanceTest {
@Nested
@Accepts({ "Partner:R(Read)" })
@Transactional
class GetPartner {
@Test
@ -275,6 +277,7 @@ class HsOfficePartnerControllerAcceptanceTest {
@Nested
@Accepts({ "Partner:U(Update)" })
@Transactional
class PatchPartner {
@Test
@ -294,7 +297,7 @@ class HsOfficePartnerControllerAcceptanceTest {
"contactUuid": "%s",
"personUuid": "%s",
"details": {
"registrationOffice": "Registergericht Hamburg",
"registrationOffice": "Temp Registergericht Aurich",
"registrationNumber": "222222",
"birthName": "Maja Schmidt",
"birthday": "1938-04-08",
@ -320,7 +323,7 @@ class HsOfficePartnerControllerAcceptanceTest {
.matches(person -> {
assertThat(person.getPerson().getTradeName()).isEqualTo("Third OHG");
assertThat(person.getContact().getLabel()).isEqualTo("forth contact");
assertThat(person.getDetails().getRegistrationOffice()).isEqualTo("Registergericht Hamburg");
assertThat(person.getDetails().getRegistrationOffice()).isEqualTo("Temp Registergericht Aurich");
assertThat(person.getDetails().getRegistrationNumber()).isEqualTo("222222");
assertThat(person.getDetails().getBirthName()).isEqualTo("Maja Schmidt");
assertThat(person.getDetails().getBirthday()).isEqualTo("1938-04-08");
@ -365,8 +368,8 @@ class HsOfficePartnerControllerAcceptanceTest {
.matches(person -> {
assertThat(person.getPerson().getTradeName()).isEqualTo(givenPartner.getPerson().getTradeName());
assertThat(person.getContact().getLabel()).isEqualTo(givenPartner.getContact().getLabel());
assertThat(person.getDetails().getRegistrationOffice()).isEqualTo(null);
assertThat(person.getDetails().getRegistrationNumber()).isEqualTo(null);
assertThat(person.getDetails().getRegistrationOffice()).isEqualTo("Temp Registergericht Leer");
assertThat(person.getDetails().getRegistrationNumber()).isEqualTo("333333");
assertThat(person.getDetails().getBirthName()).isEqualTo("Maja Schmidt");
assertThat(person.getDetails().getBirthday()).isEqualTo("1938-04-08");
assertThat(person.getDetails().getDateOfDeath()).isEqualTo("2022-01-12");
@ -378,6 +381,7 @@ class HsOfficePartnerControllerAcceptanceTest {
@Nested
@Accepts({ "Partner:D(Delete)" })
@Transactional
class DeletePartner {
@Test
@ -445,35 +449,41 @@ class HsOfficePartnerControllerAcceptanceTest {
final var givenPerson = personRepo.findPersonByOptionalNameLike("Erben Bessler").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
final var newPartner = HsOfficePartnerEntity.builder()
.uuid(UUID.randomUUID())
.person(givenPerson)
.contact(givenContact)
.details(HsOfficePartnerDetailsEntity.builder()
.uuid((UUID.randomUUID()))
.registrationOffice("Temp Registergericht Leer")
.registrationNumber("333333")
.build())
.build();
toCleanup(newPartner.getUuid());
return partnerRepo.save(newPartner);
}).assertSuccessful().returnedValue();
}
private UUID toCleanup(final UUID tempPartnerUuid) {
tempPartnerUuids.add(tempPartnerUuid);
return tempPartnerUuid;
}
@AfterEach
void cleanup() {
tempPartnerUuids.forEach(uuid -> {
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
System.out.println("DELETING temporary partner: " + uuid);
final var count = partnerRepo.deleteByUuid(uuid);
System.out.println("DELETED temporary partner: " + uuid + (count > 0 ? " successful" : " failed"));
});
});
final var deleted = jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
em.createNativeQuery("""
delete from hs_office_partner p
where p.detailsuuid in (
select d.uuid from hs_office_partner_details d
where d.registrationoffice like 'Temp %')
""")
.executeUpdate();
}).assertSuccessful().returnedValue();
final var remaining = jpaAttempt.transacted(() -> {
em.createNativeQuery("""
select count(p) from hs_office_partner p
where p.detailsuuid in (
select d.uuid from hs_office_partner_details d
where d.registrationoffice like 'Temp %')
""")
.getSingleResult();
}).assertSuccessful().returnedValue();
System.err.println("@AfterEach" + ": " + deleted + " records deleted, " + remaining + " remaining");
}
}

View File

@ -73,11 +73,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () -> {
final var newPartner = toCleanup(HsOfficePartnerEntity.builder()
.uuid(UUID.randomUUID())
.person(givenPerson)
.contact(givenContact)
.details(HsOfficePartnerDetailsEntity.builder()
.uuid(UUID.randomUUID())
.build())
.build());
return partnerRepo.save(newPartner);
@ -106,10 +104,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
final var givenPerson = personRepo.findPersonByOptionalNameLike("Erben Bessler").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
final var newPartner = toCleanup(HsOfficePartnerEntity.builder()
.uuid(UUID.randomUUID())
.person(givenPerson)
.contact(givenContact)
.details(HsOfficePartnerDetailsEntity.builder().uuid(UUID.randomUUID()).build())
.details(HsOfficePartnerDetailsEntity.builder().build())
.build());
return partnerRepo.save(newPartner);
});
@ -406,12 +403,9 @@ class HsOfficePartnerRepositoryIntegrationTest extends ContextBasedTest {
final var givenPerson = personRepo.findPersonByOptionalNameLike("Erben Bessler").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0);
final var newPartner = HsOfficePartnerEntity.builder()
.uuid(UUID.randomUUID())
.person(givenPerson)
.contact(givenContact)
.details(HsOfficePartnerDetailsEntity.builder()
.uuid(UUID.randomUUID())
.build())
.details(HsOfficePartnerDetailsEntity.builder().build())
.build();
toCleanup(newPartner);

View File

@ -13,7 +13,6 @@ public class TestHsOfficePartner {
static public HsOfficePartnerEntity HsOfficePartnerWithLegalPerson(final String tradeName) {
return HsOfficePartnerEntity.builder()
.uuid(UUID.randomUUID())
.person(HsOfficePersonEntity.builder()
.personType(LEGAL)
.tradeName(tradeName)

View File

@ -2,14 +2,13 @@ package net.hostsharing.hsadminng.hs.office.person;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import net.hostsharing.test.Accepts;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.test.Accepts;
import net.hostsharing.test.JpaAttempt;
import org.apache.commons.lang3.RandomStringUtils;
import org.json.JSONException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -17,8 +16,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
@ -31,7 +29,6 @@ import static org.hamcrest.Matchers.startsWith;
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
classes = { HsadminNgApplication.class, JpaAttempt.class }
)
@Transactional
class HsOfficePersonControllerAcceptanceTest {
@LocalServerPort
@ -49,7 +46,8 @@ class HsOfficePersonControllerAcceptanceTest {
@Autowired
JpaAttempt jpaAttempt;
Set<UUID> tempPersonUuids = new HashSet<>();
@Autowired
EntityManager em;
@Nested
@Accepts({ "Person:F(Find)" })
@ -129,9 +127,7 @@ class HsOfficePersonControllerAcceptanceTest {
class AddPerson {
@Test
void globalAdmin_withoutAssumedRole_canAddPerson() {
context.define("superuser-alex@hostsharing.net");
void globalAdmin_canAddPerson() {
final var location = RestAssured // @formatter:off
.given()
@ -141,7 +137,7 @@ class HsOfficePersonControllerAcceptanceTest {
{
"personType": "NATURAL",
"familyName": "Tester",
"givenName": "Testi"
"givenName": "Temp Testi"
}
""")
.port(port)
@ -153,23 +149,24 @@ class HsOfficePersonControllerAcceptanceTest {
.body("uuid", isUuidValid())
.body("personType", is("NATURAL"))
.body("familyName", is("Tester"))
.body("givenName", is("Testi"))
.body("givenName", is("Temp Testi"))
.header("Location", startsWith("http://localhost"))
.extract().header("Location"); // @formatter:on
// finally, the new person can be accessed under the generated UUID
final var newUserUuid = toCleanup(UUID.fromString(
location.substring(location.lastIndexOf('/') + 1)));
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
assertThat(newUserUuid).isNotNull();
}
}
@Nested
@Accepts({ "Person:R(Read)" })
@Transactional
class GetPerson {
@Test
void globalAdmin_withoutAssumedRole_canGetArbitraryPerson() {
void globalAdmin_canGetArbitraryPerson() {
context.define("superuser-alex@hostsharing.net");
final var givenPersonUuid = personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
@ -192,8 +189,10 @@ class HsOfficePersonControllerAcceptanceTest {
@Test
@Accepts({ "Person:X(Access Control)" })
void normalUser_canNotGetUnrelatedPerson() {
context.define("superuser-alex@hostsharing.net");
final var givenPersonUuid = personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
final var givenPersonUuid = jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net");
return personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
}).returnedValue();
RestAssured // @formatter:off
.given()
@ -208,8 +207,10 @@ class HsOfficePersonControllerAcceptanceTest {
@Test
@Accepts({ "Person:X(Access Control)" })
void personOwnerUser_canGetRelatedPerson() {
context.define("superuser-alex@hostsharing.net");
final var givenPersonUuid = personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
final var givenPersonUuid = jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net");
return personRepo.findPersonByOptionalNameLike("Erben").get(0).getUuid();
}).returnedValue();
RestAssured // @formatter:off
.given()
@ -233,12 +234,12 @@ class HsOfficePersonControllerAcceptanceTest {
@Nested
@Accepts({ "Person:U(Update)" })
@Transactional
class PatchPerson {
@Test
void globalAdmin_withoutAssumedRole_canPatchAllPropertiesOfArbitraryPerson() {
void globalAdmin_canPatchAllPropertiesOfArbitraryPerson() {
context.define("superuser-alex@hostsharing.net");
final var givenPerson = givenSomeTemporaryPersonCreatedBy("selfregistered-test-user@hostsharing.org");
final var location = RestAssured // @formatter:off
@ -248,9 +249,9 @@ class HsOfficePersonControllerAcceptanceTest {
.body("""
{
"personType": "JOINT_REPRESENTATION",
"tradeName": "Patched Trade Name",
"familyName": "Patched Family Name",
"givenName": "Patched Given Name"
"tradeName": "Temp Trade Name - patched",
"familyName": "Temp Family Name - patched",
"givenName": "Temp Given Name - patched"
}
""")
.port(port)
@ -261,9 +262,9 @@ class HsOfficePersonControllerAcceptanceTest {
.contentType(ContentType.JSON)
.body("uuid", isUuidValid())
.body("personType", is("JOINT_REPRESENTATION"))
.body("tradeName", is("Patched Trade Name"))
.body("familyName", is("Patched Family Name"))
.body("givenName", is("Patched Given Name"));
.body("tradeName", is("Temp Trade Name - patched"))
.body("familyName", is("Temp Family Name - patched"))
.body("givenName", is("Temp Given Name - patched"));
// @formatter:on
// finally, the person is actually updated
@ -271,17 +272,16 @@ class HsOfficePersonControllerAcceptanceTest {
assertThat(personRepo.findByUuid(givenPerson.getUuid())).isPresent().get()
.matches(person -> {
assertThat(person.getPersonType()).isEqualTo(HsOfficePersonType.JOINT_REPRESENTATION);
assertThat(person.getTradeName()).isEqualTo("Patched Trade Name");
assertThat(person.getFamilyName()).isEqualTo("Patched Family Name");
assertThat(person.getGivenName()).isEqualTo("Patched Given Name");
assertThat(person.getTradeName()).isEqualTo("Temp Trade Name - patched");
assertThat(person.getFamilyName()).isEqualTo("Temp Family Name - patched");
assertThat(person.getGivenName()).isEqualTo("Temp Given Name - patched");
return true;
});
}
@Test
void globalAdmin_withoutAssumedRole_canPatchPartialPropertiesOfArbitraryPerson() {
void globalAdmin_canPatchPartialPropertiesOfArbitraryPerson() {
context.define("superuser-alex@hostsharing.net");
final var givenPerson = givenSomeTemporaryPersonCreatedBy("selfregistered-test-user@hostsharing.org");
final var location = RestAssured // @formatter:off
@ -290,8 +290,8 @@ class HsOfficePersonControllerAcceptanceTest {
.contentType(ContentType.JSON)
.body("""
{
"familyName": "Patched Family Name",
"givenName": "Patched Given Name"
"familyName": "Temp Family Name - patched",
"givenName": "Temp Given Name - patched"
}
""")
.port(port)
@ -303,17 +303,18 @@ class HsOfficePersonControllerAcceptanceTest {
.body("uuid", isUuidValid())
.body("personType", is(givenPerson.getPersonType().toString()))
.body("tradeName", is(givenPerson.getTradeName()))
.body("familyName", is("Patched Family Name"))
.body("givenName", is("Patched Given Name"));
.body("familyName", is("Temp Family Name - patched"))
.body("givenName", is("Temp Given Name - patched"));
// @formatter:on
// finally, the person is actually updated
context.define("superuser-alex@hostsharing.net");
assertThat(personRepo.findByUuid(givenPerson.getUuid())).isPresent().get()
.matches(person -> {
assertThat(person.getPersonType()).isEqualTo(givenPerson.getPersonType());
assertThat(person.getTradeName()).isEqualTo(givenPerson.getTradeName());
assertThat(person.getFamilyName()).isEqualTo("Patched Family Name");
assertThat(person.getGivenName()).isEqualTo("Patched Given Name");
assertThat(person.getFamilyName()).isEqualTo("Temp Family Name - patched");
assertThat(person.getGivenName()).isEqualTo("Temp Given Name - patched");
return true;
});
}
@ -321,11 +322,11 @@ class HsOfficePersonControllerAcceptanceTest {
@Nested
@Accepts({ "Person:D(Delete)" })
@Transactional
class DeletePerson {
@Test
void globalAdmin_withoutAssumedRole_canDeleteArbitraryPerson() {
context.define("superuser-alex@hostsharing.net");
void globalAdmin_canDeleteArbitraryPerson() {
final var givenPerson = givenSomeTemporaryPersonCreatedBy("selfregistered-test-user@hostsharing.org");
RestAssured // @formatter:off
@ -338,6 +339,8 @@ class HsOfficePersonControllerAcceptanceTest {
.statusCode(204); // @formatter:on
// then the given person is gone
context.define("superuser-alex@hostsharing.net");
assertThat(personRepo.findByUuid(givenPerson.getUuid())).isEmpty();
}
@ -362,7 +365,6 @@ class HsOfficePersonControllerAcceptanceTest {
@Test
@Accepts({ "Person:X(Access Control)" })
void normalUser_canNotDeleteUnrelatedPerson() {
context.define("superuser-alex@hostsharing.net");
final var givenPerson = givenSomeTemporaryPersonCreatedBy("selfregistered-test-user@hostsharing.org");
RestAssured // @formatter:off
@ -376,6 +378,7 @@ class HsOfficePersonControllerAcceptanceTest {
// @formatter:on
// then the given person is still there
context.define("superuser-alex@hostsharing.net");
assertThat(personRepo.findByUuid(givenPerson.getUuid())).isNotEmpty();
}
}
@ -388,32 +391,21 @@ class HsOfficePersonControllerAcceptanceTest {
.personType(HsOfficePersonType.LEGAL)
.tradeName("Temp " + Context.getCallerMethodNameFromStackFrame(2))
.familyName(RandomStringUtils.randomAlphabetic(10) + "@example.org")
.givenName("Given Name " + RandomStringUtils.randomAlphabetic(10))
.givenName("Temp Given Name " + RandomStringUtils.randomAlphabetic(10))
.build();
toCleanup(newPerson.getUuid());
return personRepo.save(newPerson);
}).assertSuccessful().returnedValue();
}
private UUID toCleanup(final UUID tempPersonUuid) {
tempPersonUuids.add(tempPersonUuid);
return tempPersonUuid;
}
@BeforeEach
@AfterEach
void cleanup() {
tempPersonUuids.forEach(uuid -> {
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
System.out.println("DELETING temporary person: " + uuid);
final var entity = personRepo.findByUuid(uuid);
final var count = personRepo.deleteByUuid(uuid);
System.out.println("DELETED temporary person: " + uuid + (count > 0 ? " successful" : " failed") +
(" (" + entity.map(hsOfficePersonEntity -> hsOfficePersonEntity.toShortString()).orElse("null") + ")"));
}).assertSuccessful();
});
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
em.createQuery("""
DELETE FROM HsOfficePersonEntity p
WHERE p.tradeName LIKE 'Temp %' OR p.givenName LIKE 'Temp %'
""").executeUpdate();
}).assertSuccessful();
}
}

View File

@ -8,7 +8,6 @@ public class TestHsOfficePerson {
static public HsOfficePersonEntity hsOfficePerson(final String tradeName) {
return HsOfficePersonEntity.builder()
.uuid(UUID.randomUUID())
.personType(HsOfficePersonType.NATURAL)
.tradeName(tradeName)
.build();

View File

@ -1,6 +1,5 @@
package net.hostsharing.hsadminng.hs.office.relationship;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.context.ContextBasedTest;
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
@ -15,10 +14,8 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.test.annotation.DirtiesContext;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
@ -74,7 +71,6 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () -> {
final var newRelationship = toCleanup(HsOfficeRelationshipEntity.builder()
.uuid(UUID.randomUUID())
.relAnchor(givenAnchorPerson)
.relHolder(givenHolderPerson)
.relType(HsOfficeRelationshipType.JOINT_AGENT)
@ -103,7 +99,6 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTest {
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike("Anita").get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike("forth contact").get(0);
final var newRelationship = toCleanup(HsOfficeRelationshipEntity.builder()
.uuid(UUID.randomUUID())
.relAnchor(givenAnchorPerson)
.relHolder(givenHolderPerson)
.relType(HsOfficeRelationshipType.JOINT_AGENT)
@ -393,7 +388,6 @@ class HsOfficeRelationshipRepositoryIntegrationTest extends ContextBasedTest {
final var givenHolderPerson = personRepo.findPersonByOptionalNameLike(holderPerson).get(0);
final var givenContact = contactRepo.findContactByOptionalLabelLike(contact).get(0);
final var newRelationship = HsOfficeRelationshipEntity.builder()
.uuid(UUID.randomUUID())
.relType(HsOfficeRelationshipType.JOINT_AGENT)
.relAnchor(givenAnchorPerson)
.relHolder(givenHolderPerson)

View File

@ -3,14 +3,15 @@ package net.hostsharing.hsadminng.hs.office.sepamandate;
import com.vladmihalcea.hibernate.type.range.Range;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import net.hostsharing.test.Accepts;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.office.bankaccount.HsOfficeBankAccountRepository;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
import net.hostsharing.test.Accepts;
import net.hostsharing.test.JpaAttempt;
import org.json.JSONException;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -18,9 +19,8 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import java.time.LocalDate;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
@ -56,7 +56,8 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
@Autowired
JpaAttempt jpaAttempt;
Set<UUID> tempSepaMandateUuids = new HashSet<>();
@Autowired
EntityManager em;
@Nested
@Accepts({ "SepaMandate:F(Find)" })
@ -131,7 +132,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
{
"debitorUuid": "%s",
"bankAccountUuid": "%s",
"reference": "temp ref A",
"reference": "temp ref CAT A",
"validFrom": "2022-10-13"
}
""".formatted(givenDebitor.getUuid(), givenBankAccount.getUuid()))
@ -144,15 +145,15 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
.body("uuid", isUuidValid())
.body("debitor.partner.person.tradeName", is("Third OHG"))
.body("bankAccount.iban", is("DE02200505501015871393"))
.body("reference", is("temp ref A"))
.body("reference", is("temp ref CAT A"))
.body("validFrom", is("2022-10-13"))
.body("validTo", equalTo(null))
.header("Location", startsWith("http://localhost"))
.extract().header("Location"); // @formatter:on
// finally, the new sepaMandate can be accessed under the generated UUID
final var newUserUuid = toCleanup(UUID.fromString(
location.substring(location.lastIndexOf('/') + 1)));
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
assertThat(newUserUuid).isNotNull();
}
@ -171,7 +172,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
.body("""
{
"bankAccountUuid": "%s",
"reference": "temp ref A",
"reference": "temp ref CAT B",
"validFrom": "2022-10-13"
}
""".formatted(givenBankAccount.getUuid()))
@ -197,7 +198,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
{
"debitorUuid": "%s",
"bankAccountUuid": "%s",
"reference": "temp ref A",
"reference": "temp ref CAT C",
"validFrom": "2022-10-13",
"validTo": "2024-12-31"
}
@ -226,7 +227,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
{
"debitorUuid": "%s",
"bankAccountUuid": "%s",
"reference": "temp ref A",
"reference": "temp refCAT D",
"validFrom": "2022-10-13",
"validTo": "2024-12-31"
}
@ -267,7 +268,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
"debitorNumber": 10001,
"billingContact": { "label": "first contact" }
},
"bankAccount": {
"bankAccount": {
"holder": "First GmbH",
"iban": "DE02120300000000202051"
},
@ -319,7 +320,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
"debitorNumber": 10001,
"billingContact": { "label": "first contact" }
},
"bankAccount": {
"bankAccount": {
"holder": "First GmbH",
"iban": "DE02120300000000202051"
},
@ -359,7 +360,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
.body("uuid", isUuidValid())
.body("debitor.partner.person.tradeName", is("First GmbH"))
.body("bankAccount.iban", is("DE02120300000000202051"))
.body("reference", is("temp ref X"))
.body("reference", is("temp ref CAT Z"))
.body("validFrom", is("2022-11-01"))
.body("validTo", is("2022-12-31"));
// @formatter:on
@ -369,7 +370,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
.matches(mandate -> {
assertThat(mandate.getDebitor().toString()).isEqualTo("debitor(10001: First GmbH)");
assertThat(mandate.getBankAccount().toShortString()).isEqualTo("First GmbH");
assertThat(mandate.getReference()).isEqualTo("temp ref X");
assertThat(mandate.getReference()).isEqualTo("temp ref CAT Z");
assertThat(mandate.getValidity().asString()).isEqualTo("[2022-11-01,2023-01-01)");
return true;
});
@ -387,7 +388,7 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
.contentType(ContentType.JSON)
.body("""
{
"reference": "new ref"
"reference": "temp ref CAT new"
}
""")
.port(port)
@ -405,7 +406,6 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
return true;
});
}
}
@Nested
@ -435,7 +435,6 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
void bankAccountAdminUser_canNotDeleteRelatedSepaMandate() {
context.define("superuser-alex@hostsharing.net");
final var givenSepaMandate = givenSomeTemporarySepaMandate();
assertThat(givenSepaMandate.getReference()).isEqualTo("temp ref X");
RestAssured // @formatter:off
.given()
@ -455,7 +454,6 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
void normalUser_canNotDeleteUnrelatedSepaMandate() {
context.define("superuser-alex@hostsharing.net");
final var givenSepaMandate = givenSomeTemporarySepaMandate();
assertThat(givenSepaMandate.getReference()).isEqualTo("temp ref X");
RestAssured // @formatter:off
.given()
@ -480,32 +478,25 @@ class HsOfficeSepaMandateControllerAcceptanceTest {
.uuid(UUID.randomUUID())
.debitor(givenDebitor)
.bankAccount(givenBankAccount)
.reference("temp ref X")
.reference("temp ref CAT Z")
.validity(Range.closedOpen(
LocalDate.parse("2022-11-01"), LocalDate.parse("2023-03-31")))
.build();
toCleanup(newSepaMandate.getUuid());
return sepaMandateRepo.save(newSepaMandate);
}).assertSuccessful().returnedValue();
}
private UUID toCleanup(final UUID tempSepaMandateUuid) {
tempSepaMandateUuids.add(tempSepaMandateUuid);
return tempSepaMandateUuid;
}
@BeforeEach
@AfterEach
void cleanup() {
tempSepaMandateUuids.forEach(uuid -> {
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
System.out.println("DELETING temporary sepaMandate: " + uuid);
final var count = sepaMandateRepo.deleteByUuid(uuid);
System.out.println("DELETED temporary sepaMandate: " + uuid + (count > 0 ? " successful" : " failed"));
});
});
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
final var count = em.createQuery("DELETE FROM HsOfficeSepaMandateEntity s WHERE s.reference like 'temp %'")
.executeUpdate();
if (count == 0) {
System.out.println("nothing deleted");
}
}).assertSuccessful();
}
}

View File

@ -16,15 +16,15 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.transaction.annotation.Transactional;
import javax.persistence.EntityManager;
import javax.servlet.http.HttpServletRequest;
import java.time.LocalDate;
import java.util.*;
import java.util.Arrays;
import java.util.List;
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.grantDisplaysOf;
import static net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleEntity.roleNamesOf;
@ -33,7 +33,7 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assumptions.assumeThat;
@DataJpaTest
@Import( { Context.class, JpaAttempt.class })
@Import({ Context.class, JpaAttempt.class })
class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
@Autowired
@ -52,16 +52,14 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
RawRbacGrantRepository rawGrantRepo;
@Autowired
EntityManager em;
JpaAttempt jpaAttempt;
@Autowired
JpaAttempt jpaAttempt;
EntityManager em;
@MockBean
HttpServletRequest request;
Set<HsOfficeSepaMandateEntity> tempEntities = new HashSet<>();
@Nested
class CreateSepaMandate {
@ -75,14 +73,13 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
// when
final var result = attempt(em, () -> {
final var newSepaMandate = toCleanup(HsOfficeSepaMandateEntity.builder()
.uuid(UUID.randomUUID())
final var newSepaMandate = HsOfficeSepaMandateEntity.builder()
.debitor(givenDebitor)
.bankAccount(givenBankAccount)
.reference("temp ref A")
.validity(Range.closedOpen(
LocalDate.parse("2020-01-01"), LocalDate.parse("2023-01-01")))
.build());
.build();
return sepaMandateRepo.save(newSepaMandate);
});
@ -108,14 +105,13 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
attempt(em, () -> {
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0);
final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike("Paul Winkler").get(0);
final var newSepaMandate = toCleanup(HsOfficeSepaMandateEntity.builder()
.uuid(UUID.randomUUID())
final var newSepaMandate = HsOfficeSepaMandateEntity.builder()
.debitor(givenDebitor)
.bankAccount(givenBankAccount)
.reference("temp ref B")
.validity(Range.closedOpen(
LocalDate.parse("2020-01-01"), LocalDate.parse("2023-01-01")))
.build());
.build();
return sepaMandateRepo.save(newSepaMandate);
});
@ -255,7 +251,7 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
context("superuser-alex@hostsharing.net");
givenSepaMandate.setValidity(Range.closedOpen(
givenSepaMandate.getValidity().lower(), newValidityEnd));
return toCleanup(sepaMandateRepo.save(givenSepaMandate));
return sepaMandateRepo.save(givenSepaMandate);
});
// then
@ -408,18 +404,10 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
@BeforeEach
@AfterEach
@Transactional
void cleanup() {
tempEntities.forEach(tempSepaMandate -> {
jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net", null);
System.out.println("DELETING temporary sepaMandate: " + tempSepaMandate.toString());
sepaMandateRepo.deleteByUuid(tempSepaMandate.getUuid());
});
});
jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net", null);
em.createQuery("DELETE FROM HsOfficeSepaMandateEntity WHERE reference like 'temp ref%'");
});
context("superuser-alex@hostsharing.net", null);
em.createQuery("DELETE FROM HsOfficeSepaMandateEntity WHERE reference like 'temp ref%'").executeUpdate();
}
private HsOfficeSepaMandateEntity givenSomeTemporarySepaMandateBessler(final String bankAccountHolder) {
@ -428,7 +416,6 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
final var givenDebitor = debitorRepo.findDebitorByOptionalNameLike("First").get(0);
final var givenBankAccount = bankAccountRepo.findByOptionalHolderLike(bankAccountHolder).get(0);
final var newSepaMandate = HsOfficeSepaMandateEntity.builder()
.uuid(UUID.randomUUID())
.debitor(givenDebitor)
.bankAccount(givenBankAccount)
.reference("temp ref X")
@ -436,17 +423,10 @@ class HsOfficeSepaMandateRepositoryIntegrationTest extends ContextBasedTest {
LocalDate.parse("2020-01-01"), LocalDate.parse("2023-01-01")))
.build();
toCleanup(newSepaMandate);
return sepaMandateRepo.save(newSepaMandate);
}).assertSuccessful().returnedValue();
}
private HsOfficeSepaMandateEntity toCleanup(final HsOfficeSepaMandateEntity tempEntity) {
tempEntities.add(tempEntity);
return tempEntity;
}
void exactlyTheseSepaMandatesAreReturned(
final List<HsOfficeSepaMandateEntity> actualResult,
final String... sepaMandateNames) {

View File

@ -13,6 +13,8 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import javax.persistence.EntityManager;
import static java.util.Arrays.asList;
import static net.hostsharing.hsadminng.rbac.rbacrole.TestRbacRole.*;
import static org.hamcrest.Matchers.hasSize;
@ -35,6 +37,9 @@ class RbacRoleControllerRestTest {
@MockBean
RbacRoleRepository rbacRoleRepository;
@MockBean
EntityManager em;
@Test
void apiCustomersWillReturnCustomersFromRepository() throws Exception {

View File

@ -13,6 +13,7 @@ import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import javax.persistence.EntityManager;
import java.util.UUID;
import static net.hostsharing.test.IsValidUuidMatcher.isUuidValid;
@ -36,6 +37,9 @@ class RbacUserControllerRestTest {
@MockBean
RbacUserRepository rbacUserRepository;
@MockBean
EntityManager em;
@Test
void createUserUsesGivenUuid() throws Exception {
// given

View File

@ -8,6 +8,6 @@ public class TestCustomer {
static final TestCustomerEntity yyy = hsCustomer("yyy", 10002, "yyy@example.com");
static public TestCustomerEntity hsCustomer(final String prefix, final int reference, final String adminName) {
return new TestCustomerEntity(randomUUID(), prefix, reference, adminName);
return new TestCustomerEntity(null, prefix, reference, adminName);
}
}

View File

@ -6,6 +6,7 @@ import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.test.JpaAttempt;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
@ -13,8 +14,7 @@ import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.EntityManager;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
@ -43,7 +43,8 @@ class TestCustomerControllerAcceptanceTest {
@Autowired
JpaAttempt jpaAttempt;
Set<UUID> tempPartnerUuids = new HashSet<>();
@Autowired
EntityManager em;
@Nested
class ListCustomers {
@ -144,51 +145,13 @@ class TestCustomerControllerAcceptanceTest {
.extract().header("Location"); // @formatter:on
// finally, the new customer can be viewed by its own admin
final var newUserUuid = toCleanup(UUID.fromString(
location.substring(location.lastIndexOf('/') + 1)));
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
context.define("customer-admin@uuu.example.com");
assertThat(testCustomerRepository.findByUuid(newUserUuid))
.hasValueSatisfying(c -> assertThat(c.getPrefix()).isEqualTo("uuu"));
}
@Test
void globalAdmin_withoutAssumedRole_canAddCustomerWithGivenUuid() {
final var givenUuid = toCleanup(UUID.randomUUID());
final var location = RestAssured // @formatter:off
.given()
.header("current-user", "superuser-alex@hostsharing.net")
.contentType(ContentType.JSON)
.body("""
{
"uuid": "%s",
"reference": 90010,
"prefix": "vvv",
"adminUserName": "customer-admin@vvv.example.com"
}
""".formatted(givenUuid))
.port(port)
.when()
.post("http://localhost/api/test/customers")
.then().assertThat()
.statusCode(201)
.contentType(ContentType.JSON)
.body("prefix", is("vvv"))
.header("Location", startsWith("http://localhost"))
.extract().header("Location"); // @formatter:on
// finally, the new customer can be viewed by its own admin
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
context.define("customer-admin@vvv.example.com");
assertThat(testCustomerRepository.findByUuid(newUserUuid))
.hasValueSatisfying(c -> {
assertThat(c.getPrefix()).isEqualTo("vvv");
assertThat(c.getUuid()).isEqualTo(givenUuid);
});
}
@Test
void globalAdmin_withAssumedCustomerAdminRole_canNotAddCustomer() {
@ -266,26 +229,14 @@ class TestCustomerControllerAcceptanceTest {
.body("message", containsString("line: 1, column: 1"));
// @formatter:on
}
}
private UUID toCleanup(final UUID tempPartnerUuid) {
tempPartnerUuids.add(tempPartnerUuid);
return tempPartnerUuid;
}
@BeforeEach
@AfterEach
void cleanup() {
tempPartnerUuids.forEach(uuid -> {
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
System.out.println("DELETING temporary partner: " + uuid);
final var entity = testCustomerRepository.findByUuid(uuid);
final var count = testCustomerRepository.deleteByUuid(uuid);
System.out.println(
"DELETED temporary partner: " + uuid + (count > 0 ? " successful" : " failed") + " (" + entity.map(
TestCustomerEntity::getPrefix).orElse("???") + ")");
}).assertSuccessful();
});
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net", null);
em.createQuery("DELETE FROM TestCustomerEntity c WHERE c.reference < 99900").executeUpdate();
}).assertSuccessful();
}
}

View File

@ -8,9 +8,7 @@ import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Import;
import org.springframework.test.annotation.DirtiesContext;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceException;

View File

@ -1,5 +1,6 @@
package net.hostsharing.test;
import org.assertj.core.api.ObjectAssert;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.NestedExceptionUtils;
import org.springframework.stereotype.Service;
@ -105,6 +106,11 @@ public class JpaAttempt {
return result;
}
public ObjectAssert<T> assertThatResult() {
assertSuccessful();
return assertThat(returnedValue());
}
public RuntimeException caughtException() {
return exception;
}

View File

@ -1,41 +1,35 @@
package net.hostsharing.test;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.*;
import net.hostsharing.hsadminng.errors.DisplayName;
import net.hostsharing.hsadminng.mapper.Mapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import javax.persistence.EntityManager;
import javax.persistence.ManyToOne;
import javax.validation.ValidationException;
import java.util.List;
import java.util.UUID;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.catchThrowable;
import static org.junit.jupiter.api.Assertions.fail;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class MapperUnitTest {
private Mapper mapper = new Mapper();
@Mock
EntityManager em;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class SourceBean {
@InjectMocks
Mapper mapper;
private String a;
private String b;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class TargetBean {
private String a;
private String b;
private String c;
}
final UUID GIVEN_UUID = UUID.randomUUID();
@Test
void mapsNullBeanToNull() {
@ -46,48 +40,198 @@ class MapperUnitTest {
@Test
void mapsBean() {
final SourceBean givenSource = new SourceBean("1234", "Text");
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").build();
final var result = mapper.map(givenSource, TargetBean.class);
assertThat(result).usingRecursiveComparison().isEqualTo(
new TargetBean("1234", "Text", null)
TargetBean.builder().a("1234").b("Text").build()
);
}
@Test
void mapsBeanWithExistingSubEntity() {
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s1(new SubSourceBean1(GIVEN_UUID)).build();
when(em.find(SubTargetBean1.class, GIVEN_UUID)).thenReturn(new SubTargetBean1(GIVEN_UUID, "xxx"));
final var result = mapper.map(givenSource, TargetBean.class);
assertThat(result).usingRecursiveComparison().isEqualTo(
TargetBean.builder().a("1234").b("Text").s1(new SubTargetBean1(GIVEN_UUID, "xxx")).build()
);
}
@Test
void mapsBeanWithSubEntityWithNullUuid() {
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s1(new SubSourceBean1(null)).build();
final var result = mapper.map(givenSource, TargetBean.class);
assertThat(result).usingRecursiveComparison().isEqualTo(
TargetBean.builder().a("1234").b("Text").s1(new SubTargetBean1(null, null)).build()
);
}
@Test
void mapsBeanWithSubEntityWithoutUuidField() {
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s3(new SubSourceBean3("xxx")).build();
final var result = mapper.map(givenSource, TargetBean.class);
assertThat(result).usingRecursiveComparison().isEqualTo(
TargetBean.builder().a("1234").b("Text").s3(new SubTargetBean3("xxx")).build()
);
}
@Test
void mapsBeanWithSubEntityNotFound() {
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s1(new SubSourceBean1(GIVEN_UUID)).build();
when(em.find(SubTargetBean1.class, GIVEN_UUID)).thenReturn(null);
final var exception = catchThrowable(() ->
mapper.map(givenSource, TargetBean.class)
);
assertThat(exception).isInstanceOf(ValidationException.class)
.hasMessage("Unable to find SubTargetBean1 with uuid " + GIVEN_UUID);
}
@Test
void mapsBeanWithSubEntityNotFoundAndDisplayName() {
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").s2(new SubSourceBean2(GIVEN_UUID)).build();
when(em.find(SubTargetBean2.class, GIVEN_UUID)).thenReturn(null);
final var exception = catchThrowable(() ->
mapper.map(givenSource, TargetBean.class)
);
assertThat(exception).isInstanceOf(ValidationException.class)
.hasMessage("Unable to find SomeDisplayName with uuid " + GIVEN_UUID);
}
@Test
void mapsBeanWithPostmapper() {
final SourceBean givenSource = new SourceBean("1234", "Text");
final SourceBean givenSource = SourceBean.builder().a("1234").b("Text").build();
final var result = mapper.map(givenSource, TargetBean.class, (s, t) -> {t.setC("Extra");});
assertThat(result).usingRecursiveComparison().isEqualTo(
new TargetBean("1234", "Text", "Extra")
TargetBean.builder().a("1234").b("Text").c("Extra").build()
);
}
@Test
void mapsList() {
final var givenSource = List.of(
new SourceBean("111", "Text A"),
new SourceBean("222", "Text B"),
new SourceBean("333", "Text C"));
SourceBean.builder().a("111").b("Text A").build(),
SourceBean.builder().a("222").b("Text B").build(),
SourceBean.builder().a("333").b("Text C").build());
final var result = mapper.mapList(givenSource, TargetBean.class);
assertThat(result).usingRecursiveComparison().isEqualTo(
List.of(
new TargetBean("111", "Text A", null),
new TargetBean("222", "Text B", null),
new TargetBean("333", "Text C", null)));
TargetBean.builder().a("111").b("Text A").build(),
TargetBean.builder().a("222").b("Text B").build(),
TargetBean.builder().a("333").b("Text C").build()));
}
@Test
void mapsListWithPostMapper() {
final var givenSource = List.of(
new SourceBean("111", "Text A"),
new SourceBean("222", "Text B"),
new SourceBean("333", "Text C"));
SourceBean.builder().a("111").b("Text A").build(),
SourceBean.builder().a("222").b("Text B").build(),
SourceBean.builder().a("333").b("Text C").build());
final var result = mapper.mapList(givenSource, TargetBean.class, (s, t) -> {t.setC("Extra");});
assertThat(result).usingRecursiveComparison().isEqualTo(
List.of(
new TargetBean("111", "Text A", "Extra"),
new TargetBean("222", "Text B", "Extra"),
new TargetBean("333", "Text C", "Extra")));
TargetBean.builder().a("111").b("Text A").c("Extra").build(),
TargetBean.builder().a("222").b("Text B").c("Extra").build(),
TargetBean.builder().a("333").b("Text C").c("Extra").build()));
}
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class SourceBean {
private String a;
private String b;
private SubSourceBean1 s1;
private SubSourceBean2 s2;
private SubSourceBean3 s3;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class SubSourceBean1 {
private UUID uuid;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class SubSourceBean2 {
private UUID uuid;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class SubSourceBean3 {
private String x;
}
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class TargetBean {
private String a;
private String b;
private String c;
@ManyToOne
private SubTargetBean1 s1;
@ManyToOne
private SubTargetBean2 s2;
@ManyToOne
private SubTargetBean3 s3;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class SubTargetBean1 {
private UUID uuid;
private String x;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@DisplayName("SomeDisplayName")
public static class SubTargetBean2 {
private UUID uuid;
private String x;
}
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public static class SubTargetBean3 {
private String x;
}
}