split up AssetDTOUnitTest and AssetDTOIntTest, AccessMappingsUnitTestBase
This commit is contained in:
parent
2fdb914f6d
commit
3abc201a8d
@ -130,9 +130,10 @@ public class JSonDeserializationWithAccessFilter<T> extends JSonAccessFilter<T>
|
|||||||
|
|
||||||
private void checkAccessToWrittenFields(final T currentDto) {
|
private void checkAccessToWrittenFields(final T currentDto) {
|
||||||
writtenFields.forEach(field -> {
|
writtenFields.forEach(field -> {
|
||||||
|
// TODO this ugly code needs cleanup
|
||||||
if (!field.equals(selfIdField)) {
|
if (!field.equals(selfIdField)) {
|
||||||
final Role role = getLoginUserRole();
|
final Role role = getLoginUserRole();
|
||||||
if (getId() == null) {
|
if (isInitAccess()) {
|
||||||
if (!role.isAllowedToInit(field)) {
|
if (!role.isAllowedToInit(field)) {
|
||||||
if (!field.equals(parentIdField)) {
|
if (!field.equals(parentIdField)) {
|
||||||
throw new BadRequestAlertException("Initialization of field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "initializationProhibited");
|
throw new BadRequestAlertException("Initialization of field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "initializationProhibited");
|
||||||
@ -140,14 +141,18 @@ public class JSonDeserializationWithAccessFilter<T> extends JSonAccessFilter<T>
|
|||||||
throw new BadRequestAlertException("Referencing field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "referencingProhibited");
|
throw new BadRequestAlertException("Referencing field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "referencingProhibited");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (isUpdate(field, dto, currentDto) && !getLoginUserRole().isAllowedToUpdate(field)) {
|
} else if ( !Role.toBeIgnoredForUpdates(field) && isActuallyUpdated(field, dto, currentDto) && !getLoginUserRole().isAllowedToUpdate(field)) {
|
||||||
throw new BadRequestAlertException("Update of field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "updateProhibited");
|
throw new BadRequestAlertException("Update of field " + toDisplay(field) + " prohibited for current user role " + role, toDisplay(field), "updateProhibited");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isUpdate(final Field field, final T dto, T currentDto) {
|
private boolean isInitAccess() {
|
||||||
|
return getId() == null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isActuallyUpdated(final Field field, final T dto, T currentDto) {
|
||||||
return ObjectUtils.notEqual(ReflectionUtil.getValue(dto, field), ReflectionUtil.getValue(currentDto, field));
|
return ObjectUtils.notEqual(ReflectionUtil.getValue(dto, field), ReflectionUtil.getValue(currentDto, field));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,10 +2,12 @@ package org.hostsharing.hsadminng.service.accessfilter;
|
|||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
|
import static com.google.common.base.Verify.verify;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* These enum values are on the one hand used to define the minimum role required to grant access to resources,
|
* These enum values are on the one hand used to define the minimum role required to grant access to resources,
|
||||||
* but on the other hand also for the roles users can be assigned to.
|
* but on the other hand also for the roles users can be assigned to.
|
||||||
*
|
* <p>
|
||||||
* TODO: Maybe splitting it up into UserRole and RequiredRole would make it more clear?
|
* TODO: Maybe splitting it up into UserRole and RequiredRole would make it more clear?
|
||||||
* And maybe instead of a level, we could then add the comprised roles in the constructor?
|
* And maybe instead of a level, we could then add the comprised roles in the constructor?
|
||||||
* This could also be a better way to express that the financial contact has no rights to
|
* This could also be a better way to express that the financial contact has no rights to
|
||||||
@ -79,14 +81,45 @@ public enum Role {
|
|||||||
* This role is meant to specify that a resources can be accessed by anybody, even without login.
|
* This role is meant to specify that a resources can be accessed by anybody, even without login.
|
||||||
* It's currently only used for technical purposes.
|
* It's currently only used for technical purposes.
|
||||||
*/
|
*/
|
||||||
ANYBODY(99);
|
ANYBODY(99),
|
||||||
|
|
||||||
private final int level;
|
/**
|
||||||
|
* Pseudo-role to mark init/update access as ignored because the field is display-only.
|
||||||
|
* This allows REST clients to send the whole response back as a new update request.
|
||||||
|
* This role is not covered by any and covers itself no role.
|
||||||
|
*/
|
||||||
|
IGNORED;
|
||||||
|
|
||||||
|
private final Integer level;
|
||||||
|
|
||||||
|
Role() {
|
||||||
|
this.level = null;
|
||||||
|
}
|
||||||
|
|
||||||
Role(final int level) {
|
Role(final int level) {
|
||||||
this.level = level;
|
this.level = level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param field a field of a DTO with AccessMappings
|
||||||
|
* @return true if update access can be ignored because the field is just for display anyway
|
||||||
|
*/
|
||||||
|
public static boolean toBeIgnoredForUpdates(final Field field) {
|
||||||
|
final AccessFor accessForAnnot = field.getAnnotation(AccessFor.class);
|
||||||
|
if (accessForAnnot == null) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
final Role[] updateAccessFor = field.getAnnotation(AccessFor.class).update();
|
||||||
|
return updateAccessFor.length == 1 && updateAccessFor[0].isIgnored();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return true if the role is the IGNORED role
|
||||||
|
*/
|
||||||
|
public boolean isIgnored() {
|
||||||
|
return this == Role.IGNORED;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return true if this role is independent of a target object, false otherwise.
|
* @return true if this role is independent of a target object, false otherwise.
|
||||||
*/
|
*/
|
||||||
@ -95,12 +128,12 @@ public enum Role {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@return the role with the broadest access rights
|
* @return the role with the broadest access rights
|
||||||
*/
|
*/
|
||||||
public static Role broadest(final Role role, final Role... roles) {
|
public static Role broadest(final Role role, final Role... roles) {
|
||||||
Role broadests = role;
|
Role broadests = role;
|
||||||
for ( Role r: roles ) {
|
for (Role r : roles) {
|
||||||
if ( r.covers(broadests)) {
|
if (r.covers(broadests)) {
|
||||||
broadests = r;
|
broadests = r;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -108,27 +141,51 @@ public enum Role {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if the given role is covered by this role.
|
* Determines if 'this' actual role covered the given required role.
|
||||||
*
|
* <p>
|
||||||
* Where 'this' means the Java instance itself as a role of a system user.
|
* Where 'this' means the Java instance itself as a role of a system user.
|
||||||
*
|
* <p>
|
||||||
* {@code
|
* {@code
|
||||||
* Role.HOSTMASTER.covers(Role.ANY_CUSTOMER_USER) == true
|
* Role.HOSTMASTER.covers(Role.ANY_CUSTOMER_USER) == true
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
* @param role The required role for a resource.
|
* @param role The required role for a resource.
|
||||||
*
|
|
||||||
* @return whether this role comprises the given role
|
* @return whether this role comprises the given role
|
||||||
*/
|
*/
|
||||||
public boolean covers(final Role role) {
|
public boolean covers(final Role role) {
|
||||||
|
if (this.isIgnored() || role.isIgnored()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return this == role || this.level < role.level;
|
return this == role || this.level < role.level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if 'this' actual role covers any of the given required roles.
|
||||||
|
* <p>
|
||||||
|
* Where 'this' means the Java instance itself as a role of a system user.
|
||||||
|
* <p>
|
||||||
|
* {@code
|
||||||
|
* Role.HOSTMASTER.coversAny(Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT) == true
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* @param roles The alternatively required roles for a resource. Must be at least one.
|
||||||
|
* @return whether this role comprises any of the given roles
|
||||||
|
*/
|
||||||
|
public boolean coversAny(final Role... roles) {
|
||||||
|
verify(roles != null && roles.length > 0, "roles expected");
|
||||||
|
|
||||||
|
for (Role role : roles) {
|
||||||
|
if (this.covers(role)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if this role of a user allows to initialize the given field when creating the resource.
|
* Checks if this role of a user allows to initialize the given field when creating the resource.
|
||||||
*
|
*
|
||||||
* @param field a field of the DTO of a resource
|
* @param field a field of the DTO of a resource
|
||||||
*
|
|
||||||
* @return true if allowed
|
* @return true if allowed
|
||||||
*/
|
*/
|
||||||
public boolean isAllowedToInit(final Field field) {
|
public boolean isAllowedToInit(final Field field) {
|
||||||
@ -145,7 +202,6 @@ public enum Role {
|
|||||||
* Checks if this role of a user allows to update the given field.
|
* Checks if this role of a user allows to update the given field.
|
||||||
*
|
*
|
||||||
* @param field a field of the DTO of a resource
|
* @param field a field of the DTO of a resource
|
||||||
*
|
|
||||||
* @return true if allowed
|
* @return true if allowed
|
||||||
*/
|
*/
|
||||||
public boolean isAllowedToUpdate(final Field field) {
|
public boolean isAllowedToUpdate(final Field field) {
|
||||||
@ -162,7 +218,6 @@ public enum Role {
|
|||||||
* Checks if this role of a user allows to read the given field.
|
* Checks if this role of a user allows to read the given field.
|
||||||
*
|
*
|
||||||
* @param field a field of the DTO of a resource
|
* @param field a field of the DTO of a resource
|
||||||
*
|
|
||||||
* @return true if allowed
|
* @return true if allowed
|
||||||
*/
|
*/
|
||||||
public boolean isAllowedToRead(final Field field) {
|
public boolean isAllowedToRead(final Field field) {
|
||||||
|
@ -20,23 +20,23 @@ import java.util.Objects;
|
|||||||
public class AssetDTO implements Serializable, AccessMappings {
|
public class AssetDTO implements Serializable, AccessMappings {
|
||||||
|
|
||||||
@SelfId(resolver = AssetService.class)
|
@SelfId(resolver = AssetService.class)
|
||||||
@AccessFor(read = Role.ANY_CUSTOMER_USER)
|
@AccessFor(read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private LocalDate documentDate;
|
private LocalDate documentDate;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private LocalDate valueDate;
|
private LocalDate valueDate;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private AssetAction action;
|
private AssetAction action;
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private BigDecimal amount;
|
private BigDecimal amount;
|
||||||
|
|
||||||
@Size(max = 160)
|
@Size(max = 160)
|
||||||
@ -44,12 +44,10 @@ public class AssetDTO implements Serializable, AccessMappings {
|
|||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
@ParentId(resolver = MembershipService.class)
|
@ParentId(resolver = MembershipService.class)
|
||||||
@AccessFor(init = Role.ADMIN, update = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
@AccessFor(init = Role.ADMIN, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
private Long membershipId;
|
private Long membershipId;
|
||||||
|
|
||||||
// TODO: these init/update rights actually mean "ignore", we might want to express this in a better way
|
@AccessFor(update = Role.IGNORED, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
||||||
// background: there is no converter for any display label in DTOs to entity field values anyway
|
|
||||||
@AccessFor(init=Role.ANYBODY, update = Role.ANYBODY, read = {Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT})
|
|
||||||
private String membershipDisplayLabel;
|
private String membershipDisplayLabel;
|
||||||
|
|
||||||
public Long getId() {
|
public Long getId() {
|
||||||
@ -147,7 +145,7 @@ public class AssetDTO implements Serializable, AccessMappings {
|
|||||||
", amount=" + getAmount() +
|
", amount=" + getAmount() +
|
||||||
", remark='" + getRemark() + "'" +
|
", remark='" + getRemark() + "'" +
|
||||||
", membership=" + getMembershipId() +
|
", membership=" + getMembershipId() +
|
||||||
", membership='" + getMembershipDisplayLabel() + "'" +
|
", membershipDisplayLabel='" + getMembershipDisplayLabel() + "'" +
|
||||||
"}";
|
"}";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,6 +35,10 @@ public class JSonAccessFilterTestFixture {
|
|||||||
@SelfId(resolver = GivenService.class)
|
@SelfId(resolver = GivenService.class)
|
||||||
@AccessFor(read = ANYBODY)
|
@AccessFor(read = ANYBODY)
|
||||||
Long id;
|
Long id;
|
||||||
|
|
||||||
|
@AccessFor(update = IGNORED, read = ANYBODY)
|
||||||
|
String displayLabel;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static abstract class GivenCustomerService implements IdToDtoResolver<GivenCustomerDto> {
|
static abstract class GivenCustomerService implements IdToDtoResolver<GivenCustomerDto> {
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
package org.hostsharing.hsadminng.service.accessfilter;
|
package org.hostsharing.hsadminng.service.accessfilter;
|
||||||
|
|
||||||
|
import com.google.common.base.VerifyException;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
import java.lang.reflect.Field;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.ThrowableAssert.catchThrowable;
|
||||||
|
|
||||||
public class RoleUnitTest {
|
public class RoleUnitTest {
|
||||||
|
|
||||||
@ -71,6 +73,46 @@ public class RoleUnitTest {
|
|||||||
assertThat(Role.FINANCIAL_CONTACT.covers(Role.ACTUAL_CUSTOMER_USER)).isFalse();
|
assertThat(Role.FINANCIAL_CONTACT.covers(Role.ACTUAL_CUSTOMER_USER)).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void ignoredCoversNothingAndIsNotCovered() {
|
||||||
|
assertThat(Role.IGNORED.covers(Role.HOSTMASTER)).isFalse();
|
||||||
|
assertThat(Role.IGNORED.covers(Role.ANYBODY)).isFalse();
|
||||||
|
assertThat(Role.IGNORED.covers(Role.IGNORED)).isFalse();
|
||||||
|
assertThat(Role.HOSTMASTER.covers(Role.IGNORED)).isFalse();
|
||||||
|
assertThat(Role.ANYBODY.covers(Role.IGNORED)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void coversAny() {
|
||||||
|
assertThat(Role.HOSTMASTER.coversAny(Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT)).isTrue();
|
||||||
|
assertThat(Role.CONTRACTUAL_CONTACT.coversAny(Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT)).isTrue();
|
||||||
|
assertThat(Role.FINANCIAL_CONTACT.coversAny(Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT)).isTrue();
|
||||||
|
|
||||||
|
assertThat(Role.ANY_CUSTOMER_USER.coversAny(Role.CONTRACTUAL_CONTACT, Role.FINANCIAL_CONTACT)).isFalse();
|
||||||
|
|
||||||
|
assertThat(catchThrowable(() -> Role.HOSTMASTER.coversAny())).isInstanceOf(VerifyException.class);
|
||||||
|
assertThat(catchThrowable(() -> Role.HOSTMASTER.coversAny(null))).isInstanceOf(VerifyException.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void isIgnored() {
|
||||||
|
for (Role role : Role.values()) {
|
||||||
|
if (role == Role.IGNORED) {
|
||||||
|
assertThat(role.isIgnored()).isTrue();
|
||||||
|
} else {
|
||||||
|
assertThat(role.isIgnored()).isFalse();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toBeIgnoredForUpdates() {
|
||||||
|
assertThat(Role.toBeIgnoredForUpdates(someFieldWithoutAccessForAnnotation)).isTrue();
|
||||||
|
assertThat(Role.toBeIgnoredForUpdates(someFieldWithAccessForAnnotationToBeIgnoredForUpdates)).isTrue();
|
||||||
|
assertThat(Role.toBeIgnoredForUpdates(someFieldWithAccessForAnnotationToBeIgnoredForUpdatesAmongOthers)).isFalse();
|
||||||
|
assertThat(Role.toBeIgnoredForUpdates(someFieldWithAccessForAnnotation)).isFalse();
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isIndependent() {
|
public void isIndependent() {
|
||||||
assertThat(Role.HOSTMASTER.isIndependent()).isTrue();
|
assertThat(Role.HOSTMASTER.isIndependent()).isTrue();
|
||||||
@ -114,14 +156,25 @@ public class RoleUnitTest {
|
|||||||
@AccessFor(init = Role.ADMIN, update = Role.SUPPORTER, read = Role.ANY_CUSTOMER_CONTACT)
|
@AccessFor(init = Role.ADMIN, update = Role.SUPPORTER, read = Role.ANY_CUSTOMER_CONTACT)
|
||||||
private Integer someFieldWithAccessForAnnotation;
|
private Integer someFieldWithAccessForAnnotation;
|
||||||
|
|
||||||
|
@AccessFor(update = Role.IGNORED, read = Role.ANY_CUSTOMER_CONTACT)
|
||||||
|
private Integer someFieldWithAccessForAnnotationToBeIgnoredForUpdates;
|
||||||
|
|
||||||
|
@AccessFor(update = {Role.IGNORED, Role.SUPPORTER}, read = Role.ANY_CUSTOMER_CONTACT)
|
||||||
|
private Integer someFieldWithAccessForAnnotationToBeIgnoredForUpdatesAmongOthers;
|
||||||
|
|
||||||
private Integer someFieldWithoutAccessForAnnotation;
|
private Integer someFieldWithoutAccessForAnnotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Field someFieldWithoutAccessForAnnotation;
|
private static Field someFieldWithoutAccessForAnnotation;
|
||||||
|
private static Field someFieldWithAccessForAnnotationToBeIgnoredForUpdates;
|
||||||
|
private static Field someFieldWithAccessForAnnotationToBeIgnoredForUpdatesAmongOthers;
|
||||||
private static Field someFieldWithAccessForAnnotation;
|
private static Field someFieldWithAccessForAnnotation;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
try {
|
try {
|
||||||
someFieldWithoutAccessForAnnotation = TestDto.class.getDeclaredField("someFieldWithoutAccessForAnnotation");
|
someFieldWithoutAccessForAnnotation = TestDto.class.getDeclaredField("someFieldWithoutAccessForAnnotation");
|
||||||
|
someFieldWithAccessForAnnotationToBeIgnoredForUpdates = TestDto.class.getDeclaredField("someFieldWithAccessForAnnotationToBeIgnoredForUpdates");
|
||||||
|
someFieldWithAccessForAnnotationToBeIgnoredForUpdatesAmongOthers = TestDto.class.getDeclaredField("someFieldWithAccessForAnnotationToBeIgnoredForUpdatesAmongOthers");
|
||||||
someFieldWithAccessForAnnotation = TestDto.class.getDeclaredField("someFieldWithAccessForAnnotation");
|
someFieldWithAccessForAnnotation = TestDto.class.getDeclaredField("someFieldWithAccessForAnnotation");
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (NoSuchFieldException e) {
|
||||||
throw new AssertionError("precondition failed", e);
|
throw new AssertionError("precondition failed", e);
|
||||||
|
@ -0,0 +1,86 @@
|
|||||||
|
package org.hostsharing.hsadminng.service.dto;
|
||||||
|
|
||||||
|
import org.hostsharing.hsadminng.service.accessfilter.AccessFor;
|
||||||
|
import org.hostsharing.hsadminng.service.accessfilter.Role;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Usually base classes for unit tests are not a good idea, but because
|
||||||
|
* DTOs which implement AccessMapping are more like a DSL,
|
||||||
|
* this base class should be used to enforce its required structure.
|
||||||
|
*/
|
||||||
|
public abstract class AccessMappingsUnitTestBase {
|
||||||
|
|
||||||
|
protected AccessRightsMatcher initAccesFor(final Class<AssetDTO> dtoClass, final Role role) {
|
||||||
|
return new AccessRightsMatcher(dtoClass, role, AccessFor::init);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AccessRightsMatcher updateAccesFor(final Class<AssetDTO> dtoClass, final Role role) {
|
||||||
|
return new AccessRightsMatcher(dtoClass, role, AccessFor::update);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected AccessRightsMatcher readAccesFor(final Class<AssetDTO> dtoClass, final Role role) {
|
||||||
|
return new AccessRightsMatcher(dtoClass, role, AccessFor::read);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected static class AccessRightsMatcher {
|
||||||
|
private final Class<AssetDTO> dtoClass;
|
||||||
|
private final Role role;
|
||||||
|
|
||||||
|
private final String[] namesOfFieldsWithAccessForAnnotation;
|
||||||
|
private final String[] namesOfAccessibleFields;
|
||||||
|
|
||||||
|
AccessRightsMatcher(final Class<AssetDTO> dtoClass, final Role role, final Function<AccessFor, Role[]> access) {
|
||||||
|
this.dtoClass = dtoClass;
|
||||||
|
this.role = role;
|
||||||
|
|
||||||
|
final Set<Field> fieldsWithAccessForAnnotation = determineFieldsWithAccessForAnnotation(dtoClass);
|
||||||
|
this.namesOfFieldsWithAccessForAnnotation = fieldsWithAccessForAnnotation.stream()
|
||||||
|
.map(Field::getName).collect(Collectors.toList()).toArray(new String[]{});
|
||||||
|
this.namesOfAccessibleFields = fieldsWithAccessForAnnotation.stream()
|
||||||
|
.filter(f -> allows(f, access, role)).map(Field::getName).collect(Collectors.toList()).toArray(new String[]{});
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shouldBeExactlyFor(final String... expectedFields) {
|
||||||
|
assertThat(namesOfAccessibleFields).containsExactlyInAnyOrder(expectedFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shouldBeForNothing() {
|
||||||
|
assertThat(namesOfAccessibleFields).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void shouldBeForAllFields() {
|
||||||
|
assertThat(namesOfAccessibleFields).containsExactlyInAnyOrder(namesOfFieldsWithAccessForAnnotation);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private static Set<Field> determineFieldsWithAccessForAnnotation(final Class<AssetDTO> dtoClass) {
|
||||||
|
|
||||||
|
final Set<Field> fieldsWithAccessForAnnotation = new HashSet<>();
|
||||||
|
|
||||||
|
for (Field field : dtoClass.getDeclaredFields()) {
|
||||||
|
if (field.isAnnotationPresent(AccessFor.class)) {
|
||||||
|
final AccessFor accessFor = field.getAnnotation(AccessFor.class);
|
||||||
|
fieldsWithAccessForAnnotation.add(field);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fieldsWithAccessForAnnotation;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static boolean allows(final Field field, final Function<AccessFor, Role[]> access, final Role role) {
|
||||||
|
if (field.isAnnotationPresent(AccessFor.class)) {
|
||||||
|
final AccessFor accessFor = field.getAnnotation(AccessFor.class);
|
||||||
|
return role.coversAny(access.apply(accessFor));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,212 @@
|
|||||||
|
package org.hostsharing.hsadminng.service.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
|
import org.hostsharing.hsadminng.domain.Asset;
|
||||||
|
import org.hostsharing.hsadminng.domain.Customer;
|
||||||
|
import org.hostsharing.hsadminng.domain.Membership;
|
||||||
|
import org.hostsharing.hsadminng.domain.enumeration.AssetAction;
|
||||||
|
import org.hostsharing.hsadminng.repository.AssetRepository;
|
||||||
|
import org.hostsharing.hsadminng.repository.CustomerRepository;
|
||||||
|
import org.hostsharing.hsadminng.repository.MembershipRepository;
|
||||||
|
import org.hostsharing.hsadminng.service.AssetService;
|
||||||
|
import org.hostsharing.hsadminng.service.AssetValidator;
|
||||||
|
import org.hostsharing.hsadminng.service.MembershipValidator;
|
||||||
|
import org.hostsharing.hsadminng.service.accessfilter.JSonBuilder;
|
||||||
|
import org.hostsharing.hsadminng.service.accessfilter.Role;
|
||||||
|
import org.hostsharing.hsadminng.service.mapper.AssetMapper;
|
||||||
|
import org.hostsharing.hsadminng.service.mapper.AssetMapperImpl;
|
||||||
|
import org.hostsharing.hsadminng.service.mapper.CustomerMapperImpl;
|
||||||
|
import org.hostsharing.hsadminng.service.mapper.MembershipMapperImpl;
|
||||||
|
import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.junit.MockitoJUnit;
|
||||||
|
import org.mockito.junit.MockitoRule;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.json.JsonTest;
|
||||||
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||||
|
import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenAuthenticatedUser;
|
||||||
|
import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenUserHavingRole;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.mockito.BDDMockito.given;
|
||||||
|
|
||||||
|
@JsonTest
|
||||||
|
@SpringBootTest(classes = {
|
||||||
|
CustomerMapperImpl.class,
|
||||||
|
MembershipMapperImpl.class,
|
||||||
|
AssetMapperImpl.class,
|
||||||
|
AssetDTO.AssetJsonSerializer.class,
|
||||||
|
AssetDTO.AssetJsonDeserializer.class
|
||||||
|
})
|
||||||
|
@RunWith(SpringRunner.class)
|
||||||
|
public class AssetDTOIntTest {
|
||||||
|
|
||||||
|
private static final Long SOME_CUSTOMER_ID = RandomUtils.nextLong(100, 199);
|
||||||
|
private static final Integer SOME_CUSTOMER_REFERENCE = 10001;
|
||||||
|
private static final String SOME_CUSTOMER_PREFIX = "abc";
|
||||||
|
private static final String SOME_CUSTOMER_NAME = "Some Customer Name";
|
||||||
|
private static final Customer SOME_CUSTOMER = new Customer().id(SOME_CUSTOMER_ID)
|
||||||
|
.reference(SOME_CUSTOMER_REFERENCE).prefix(SOME_CUSTOMER_PREFIX).name(SOME_CUSTOMER_NAME);
|
||||||
|
|
||||||
|
private static final Long SOME_MEMBERSHIP_ID = RandomUtils.nextLong(200, 299);
|
||||||
|
private static final LocalDate SOME_MEMBER_FROM_DATE = LocalDate.parse("2000-12-06");
|
||||||
|
private static final Membership SOME_MEMBERSHIP = new Membership().id(SOME_MEMBERSHIP_ID)
|
||||||
|
.customer(SOME_CUSTOMER).memberFromDate(SOME_MEMBER_FROM_DATE);
|
||||||
|
private static final String SOME_MEMBERSHIP_DISPLAY_LABEL = "Some Customer Name [10001:abc] 2000-12-06 - ...";
|
||||||
|
|
||||||
|
private static final Long SOME_ASSET_ID = RandomUtils.nextLong(300, 399);
|
||||||
|
private static final Asset SOME_ASSET = new Asset().id(SOME_ASSET_ID).membership(SOME_MEMBERSHIP);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public MockitoRule mockito = MockitoJUnit.rule();
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private AssetMapper assetMapper;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private AssetRepository assetRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private AssetValidator assetValidator;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private CustomerRepository customerRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private MembershipRepository membershipRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private MembershipValidator membershipValidator;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private AssetService assetService;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private EntityManager em;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void init() {
|
||||||
|
given(customerRepository.findById(SOME_CUSTOMER_ID)).willReturn(Optional.of(SOME_CUSTOMER));
|
||||||
|
given(membershipRepository.findById(SOME_MEMBERSHIP_ID)).willReturn(Optional.of(SOME_MEMBERSHIP));
|
||||||
|
given(assetRepository.findById(SOME_ASSET_ID)).willReturn((Optional.of(SOME_ASSET)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSerializePartiallyForFinancialCustomerContact() throws JsonProcessingException {
|
||||||
|
|
||||||
|
// given
|
||||||
|
givenAuthenticatedUser();
|
||||||
|
givenUserHavingRole(CustomerDTO.class, SOME_CUSTOMER_ID, Role.FINANCIAL_CONTACT);
|
||||||
|
final AssetDTO given = createSomeAssetDTO(SOME_ASSET_ID);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final String actual = objectMapper.writeValueAsString(given);
|
||||||
|
|
||||||
|
// then
|
||||||
|
given.setRemark(null);
|
||||||
|
assertEquals(createExpectedJSon(given), actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldSerializeCompletelyForSupporter() throws JsonProcessingException {
|
||||||
|
|
||||||
|
// given
|
||||||
|
givenAuthenticatedUser();
|
||||||
|
givenUserHavingRole(Role.SUPPORTER);
|
||||||
|
final AssetDTO given = createSomeAssetDTO(SOME_ASSET_ID);
|
||||||
|
|
||||||
|
// when
|
||||||
|
final String actual = objectMapper.writeValueAsString(given);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(createExpectedJSon(given), actual);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldNotDeserializeForContractualCustomerContact() {
|
||||||
|
// given
|
||||||
|
givenAuthenticatedUser();
|
||||||
|
givenUserHavingRole(CustomerDTO.class, SOME_CUSTOMER_ID, Role.CONTRACTUAL_CONTACT);
|
||||||
|
final String json = new JSonBuilder()
|
||||||
|
.withFieldValue("id", SOME_ASSET_ID)
|
||||||
|
.withFieldValue("remark", "Updated Remark")
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
// when
|
||||||
|
final Throwable actual = catchThrowable(() -> objectMapper.readValue(json, AssetDTO.class));
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertThat(actual).isInstanceOfSatisfying(BadRequestAlertException.class, bre ->
|
||||||
|
assertThat(bre.getMessage()).isEqualTo("Update of field AssetDTO.remark prohibited for current user role CONTRACTUAL_CONTACT")
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void shouldDeserializeForAdminIfRemarkIsChanged() throws IOException {
|
||||||
|
// given
|
||||||
|
givenAuthenticatedUser();
|
||||||
|
givenUserHavingRole(Role.ADMIN);
|
||||||
|
final String json = new JSonBuilder()
|
||||||
|
.withFieldValue("id", SOME_ASSET_ID)
|
||||||
|
.withFieldValue("remark", "Updated Remark")
|
||||||
|
.toString();
|
||||||
|
|
||||||
|
// when
|
||||||
|
final AssetDTO actual = objectMapper.readValue(json, AssetDTO.class);
|
||||||
|
|
||||||
|
// then
|
||||||
|
final AssetDTO expected = new AssetDTO();
|
||||||
|
expected.setId(SOME_ASSET_ID);
|
||||||
|
expected.setMembershipId(SOME_MEMBERSHIP_ID);
|
||||||
|
expected.setRemark("Updated Remark");
|
||||||
|
expected.setMembershipDisplayLabel(SOME_MEMBERSHIP_DISPLAY_LABEL);
|
||||||
|
assertThat(actual).isEqualToIgnoringGivenFields(expected, "displayLabel");
|
||||||
|
}
|
||||||
|
|
||||||
|
// --- only test fixture below ---
|
||||||
|
|
||||||
|
private String createExpectedJSon(AssetDTO dto) {
|
||||||
|
return new JSonBuilder()
|
||||||
|
.withFieldValueIfPresent("id", dto.getId())
|
||||||
|
.withFieldValueIfPresent("documentDate", dto.getDocumentDate().toString())
|
||||||
|
.withFieldValueIfPresent("valueDate", dto.getValueDate().toString())
|
||||||
|
.withFieldValueIfPresent("action", dto.getAction().name())
|
||||||
|
.withFieldValueIfPresent("amount", dto.getAmount().doubleValue())
|
||||||
|
.withFieldValueIfPresent("remark", dto.getRemark())
|
||||||
|
.withFieldValueIfPresent("membershipId", dto.getMembershipId())
|
||||||
|
.withFieldValue("membershipDisplayLabel", dto.getMembershipDisplayLabel())
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private AssetDTO createSomeAssetDTO(final long id) {
|
||||||
|
final AssetDTO given = new AssetDTO();
|
||||||
|
given.setId(id);
|
||||||
|
given.setAction(AssetAction.PAYMENT);
|
||||||
|
given.setAmount(new BigDecimal("512.01"));
|
||||||
|
given.setDocumentDate(LocalDate.parse("2019-04-27"));
|
||||||
|
given.setValueDate(LocalDate.parse("2019-04-28"));
|
||||||
|
given.setMembershipId(SOME_MEMBERSHIP_ID);
|
||||||
|
given.setRemark("Some Remark");
|
||||||
|
given.setMembershipDisplayLabel("Display Label for Membership #" + SOME_MEMBERSHIP_ID);
|
||||||
|
return given;
|
||||||
|
}
|
||||||
|
}
|
@ -1,214 +1,101 @@
|
|||||||
package org.hostsharing.hsadminng.service.dto;
|
package org.hostsharing.hsadminng.service.dto;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
import org.apache.commons.lang3.RandomStringUtils;
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import org.apache.commons.lang3.RandomUtils;
|
import org.apache.commons.lang3.RandomUtils;
|
||||||
import org.hostsharing.hsadminng.domain.Asset;
|
|
||||||
import org.hostsharing.hsadminng.domain.Customer;
|
|
||||||
import org.hostsharing.hsadminng.domain.Membership;
|
|
||||||
import org.hostsharing.hsadminng.domain.enumeration.AssetAction;
|
import org.hostsharing.hsadminng.domain.enumeration.AssetAction;
|
||||||
import org.hostsharing.hsadminng.repository.AssetRepository;
|
|
||||||
import org.hostsharing.hsadminng.repository.CustomerRepository;
|
|
||||||
import org.hostsharing.hsadminng.repository.MembershipRepository;
|
|
||||||
import org.hostsharing.hsadminng.service.AssetService;
|
|
||||||
import org.hostsharing.hsadminng.service.AssetValidator;
|
|
||||||
import org.hostsharing.hsadminng.service.MembershipValidator;
|
|
||||||
import org.hostsharing.hsadminng.service.accessfilter.JSonBuilder;
|
|
||||||
import org.hostsharing.hsadminng.service.accessfilter.Role;
|
import org.hostsharing.hsadminng.service.accessfilter.Role;
|
||||||
import org.hostsharing.hsadminng.service.mapper.AssetMapper;
|
|
||||||
import org.hostsharing.hsadminng.service.mapper.AssetMapperImpl;
|
|
||||||
import org.hostsharing.hsadminng.service.mapper.CustomerMapperImpl;
|
|
||||||
import org.hostsharing.hsadminng.service.mapper.MembershipMapperImpl;
|
|
||||||
import org.hostsharing.hsadminng.web.rest.errors.BadRequestAlertException;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.mockito.junit.MockitoJUnit;
|
|
||||||
import org.mockito.junit.MockitoRule;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.boot.test.autoconfigure.json.JsonTest;
|
|
||||||
import org.springframework.boot.test.context.SpringBootTest;
|
|
||||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.Assertions.catchThrowable;
|
|
||||||
import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenAuthenticatedUser;
|
|
||||||
import static org.hostsharing.hsadminng.service.accessfilter.MockSecurityContext.givenUserHavingRole;
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.mockito.BDDMockito.given;
|
|
||||||
|
|
||||||
|
public class AssetDTOUnitTest extends AccessMappingsUnitTestBase {
|
||||||
|
|
||||||
@JsonTest
|
@Test
|
||||||
@SpringBootTest(classes = {
|
public void shouldHaveProperAccessForAdmin() {
|
||||||
AssetMapperImpl.class,
|
initAccesFor(AssetDTO.class, Role.ADMIN).shouldBeExactlyFor(
|
||||||
AssetDTO.AssetJsonSerializer.class,
|
"membershipId", "documentDate", "amount", "action", "valueDate", "remark");
|
||||||
AssetDTO.AssetJsonDeserializer.class,
|
updateAccesFor(AssetDTO.class, Role.ADMIN).shouldBeExactlyFor("remark");
|
||||||
|
readAccesFor(AssetDTO.class, Role.ADMIN).shouldBeForAllFields();
|
||||||
MembershipMapperImpl.class,
|
|
||||||
|
|
||||||
CustomerMapperImpl.class
|
|
||||||
})
|
|
||||||
@RunWith(SpringRunner.class)
|
|
||||||
public class AssetDTOUnitTest {
|
|
||||||
|
|
||||||
|
|
||||||
private static final Long SOME_CUSTOMER_ID = RandomUtils.nextLong(100, 199);
|
|
||||||
private static final Integer SOME_CUSTOMER_REFERENCE = 10001;
|
|
||||||
private static final String SOME_CUSTOMER_PREFIX = "abc";
|
|
||||||
private static final String SOME_CUSTOMER_NAME = "Some Customer Name";
|
|
||||||
private static final Customer SOME_CUSTOMER = new Customer().id(SOME_CUSTOMER_ID).reference(SOME_CUSTOMER_REFERENCE).prefix(SOME_CUSTOMER_PREFIX).name(SOME_CUSTOMER_NAME);
|
|
||||||
|
|
||||||
private static final Long SOME_MEMBERSHIP_ID = RandomUtils.nextLong(200, 299);
|
|
||||||
private static final LocalDate SOME_MEMBER_FROM_DATE = LocalDate.parse("2000-12-06") ;
|
|
||||||
private static final Membership SOME_MEMBERSHIP = new Membership().id(SOME_MEMBERSHIP_ID).customer(SOME_CUSTOMER).memberFromDate(SOME_MEMBER_FROM_DATE);
|
|
||||||
public static final String SOME_MEMBERSHIP_DISPLAY_LABEL = "Some Customer Name [10001:abc] 2000-12-06 - ...";
|
|
||||||
|
|
||||||
private static final Long SOME_ASSET_ID = RandomUtils.nextLong(300, 399);
|
|
||||||
private static final Asset SOME_ASSET = new Asset().id(SOME_ASSET_ID).membership(SOME_MEMBERSHIP);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public MockitoRule mockito = MockitoJUnit.rule();
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private AssetMapper assetMapper;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private AssetRepository assetRepository;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private AssetValidator assetValidator;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private CustomerRepository customerRepository;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private MembershipRepository membershipRepository;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private MembershipValidator membershipValidator;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private AssetService assetService;
|
|
||||||
|
|
||||||
@MockBean
|
|
||||||
private EntityManager em;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void init() {
|
|
||||||
given(customerRepository.findById(SOME_CUSTOMER_ID)).willReturn(Optional.of(SOME_CUSTOMER));
|
|
||||||
given(membershipRepository.findById(SOME_MEMBERSHIP_ID)).willReturn(Optional.of(SOME_MEMBERSHIP));
|
|
||||||
given(assetRepository.findById(SOME_ASSET_ID)).willReturn((Optional.of(SOME_ASSET)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldSerializePartiallyForFinancialCustomerContact() throws JsonProcessingException {
|
public void shouldHaveProperAccessForContractualContact() {
|
||||||
|
initAccesFor(AssetDTO.class, Role.CONTRACTUAL_CONTACT).shouldBeForNothing();
|
||||||
// given
|
updateAccesFor(AssetDTO.class, Role.CONTRACTUAL_CONTACT).shouldBeForNothing();
|
||||||
givenAuthenticatedUser();
|
readAccesFor(AssetDTO.class, Role.CONTRACTUAL_CONTACT).shouldBeExactlyFor(
|
||||||
givenUserHavingRole(CustomerDTO.class, SOME_CUSTOMER_ID, Role.FINANCIAL_CONTACT);
|
"id", "membershipId", "documentDate", "amount", "action", "valueDate", "membershipDisplayLabel");
|
||||||
final AssetDTO given = createSomeAssetDTO(SOME_ASSET_ID);
|
|
||||||
|
|
||||||
// when
|
|
||||||
final String actual = objectMapper.writeValueAsString(given);
|
|
||||||
|
|
||||||
// then
|
|
||||||
given.setRemark(null);
|
|
||||||
assertEquals(createExpectedJSon(given), actual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldSerializeCompletelyForSupporter() throws JsonProcessingException {
|
public void shouldHaveNoAccessForTechnicalContact() {
|
||||||
|
initAccesFor(AssetDTO.class, Role.TECHNICAL_CONTACT).shouldBeForNothing();
|
||||||
// given
|
updateAccesFor(AssetDTO.class, Role.TECHNICAL_CONTACT).shouldBeForNothing();
|
||||||
givenAuthenticatedUser();
|
readAccesFor(AssetDTO.class, Role.TECHNICAL_CONTACT).shouldBeForNothing();
|
||||||
givenUserHavingRole(Role.SUPPORTER);
|
|
||||||
final AssetDTO given = createSomeAssetDTO(SOME_ASSET_ID);
|
|
||||||
|
|
||||||
// when
|
|
||||||
final String actual = objectMapper.writeValueAsString(given);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertEquals(createExpectedJSon(given), actual);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldNotDeserializeForContractualCustomerContact() {
|
public void shouldHaveNoAccessForNormalUsersWithinCustomerRealm() {
|
||||||
// given
|
initAccesFor(AssetDTO.class, Role.ANY_CUSTOMER_USER).shouldBeForNothing();
|
||||||
givenAuthenticatedUser();
|
updateAccesFor(AssetDTO.class, Role.ANY_CUSTOMER_USER).shouldBeForNothing();
|
||||||
givenUserHavingRole(CustomerDTO.class, SOME_CUSTOMER_ID, Role.CONTRACTUAL_CONTACT);
|
readAccesFor(AssetDTO.class, Role.ANY_CUSTOMER_USER).shouldBeForNothing();
|
||||||
final String json = new JSonBuilder()
|
|
||||||
.withFieldValue("id", SOME_ASSET_ID)
|
|
||||||
.withFieldValue("remark", "Updated Remark")
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
// when
|
|
||||||
final Throwable actual = catchThrowable(() -> objectMapper.readValue(json, AssetDTO.class));
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertThat(actual).isInstanceOfSatisfying(BadRequestAlertException.class, bre ->
|
|
||||||
assertThat(bre.getMessage()).isEqualTo("Update of field AssetDTO.remark prohibited for current user role CONTRACTUAL_CONTACT")
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void shouldDeserializeForAdminIfRemarkIsChanged() throws IOException {
|
public void shouldConvertToString() {
|
||||||
// given
|
final AssetDTO dto = createDto(1234L);
|
||||||
givenAuthenticatedUser();
|
assertThat(dto.toString()).isEqualTo("AssetDTO{id=1234, documentDate='2000-12-07', valueDate='2000-12-18', action='PAYMENT', amount=512.01, remark='Some Remark', membership=888, membershipDisplayLabel='Some Membership'}");
|
||||||
givenUserHavingRole(Role.ADMIN);
|
}
|
||||||
final String json = new JSonBuilder()
|
|
||||||
.withFieldValue("id", SOME_ASSET_ID)
|
|
||||||
.withFieldValue("remark", "Updated Remark")
|
|
||||||
.toString();
|
|
||||||
|
|
||||||
// when
|
@Test
|
||||||
final AssetDTO actual = objectMapper.readValue(json, AssetDTO.class);
|
public void shouldImplementEqualsJustUsingClassAndId() {
|
||||||
|
final AssetDTO dto = createDto(1234L);
|
||||||
|
assertThat(dto.equals(dto)).isTrue();
|
||||||
|
|
||||||
// then
|
final AssetDTO dtoWithSameId = createRandomDto(1234L);
|
||||||
final AssetDTO expected = new AssetDTO();
|
assertThat(dto.equals(dtoWithSameId)).isTrue();
|
||||||
expected.setId(SOME_ASSET_ID);
|
|
||||||
expected.setMembershipId(SOME_MEMBERSHIP_ID);
|
final AssetDTO dtoWithAnotherId = createRandomDto(RandomUtils.nextLong(2000, 9999));
|
||||||
expected.setRemark("Updated Remark");
|
assertThat(dtoWithAnotherId.equals(dtoWithSameId)).isFalse();
|
||||||
expected.setMembershipDisplayLabel(SOME_MEMBERSHIP_DISPLAY_LABEL);
|
|
||||||
assertThat(actual).isEqualToIgnoringGivenFields(expected, "displayLabel");
|
final AssetDTO dtoWithoutId = createRandomDto(null);
|
||||||
|
assertThat(dto.equals(dtoWithoutId)).isFalse();
|
||||||
|
assertThat(dtoWithoutId.equals(dto)).isFalse();
|
||||||
|
|
||||||
|
assertThat(dto.equals(null)).isFalse();
|
||||||
|
assertThat(dto.equals("")).isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- only test fixture below ---
|
// --- only test fixture below ---
|
||||||
|
|
||||||
private String createExpectedJSon(AssetDTO dto) {
|
private AssetDTO createDto(final Long id) {
|
||||||
return new JSonBuilder()
|
final AssetDTO dto = new AssetDTO();
|
||||||
.withFieldValueIfPresent("id", dto.getId())
|
dto.setId(id);
|
||||||
.withFieldValueIfPresent("documentDate", dto.getDocumentDate().toString())
|
dto.setDocumentDate(LocalDate.parse("2000-12-07"));
|
||||||
.withFieldValueIfPresent("valueDate", dto.getValueDate().toString())
|
dto.setAmount(new BigDecimal("512.01"));
|
||||||
.withFieldValueIfPresent("action", dto.getAction().name())
|
dto.setAction(AssetAction.PAYMENT);
|
||||||
.withFieldValueIfPresent("amount", dto.getAmount().doubleValue())
|
dto.setRemark("Some Remark");
|
||||||
.withFieldValueIfPresent("remark", dto.getRemark())
|
dto.setValueDate(LocalDate.parse("2000-12-18"));
|
||||||
.withFieldValueIfPresent("membershipId", dto.getMembershipId())
|
dto.setMembershipId(888L);
|
||||||
.withFieldValue("membershipDisplayLabel", dto.getMembershipDisplayLabel())
|
dto.setMembershipDisplayLabel("Some Membership");
|
||||||
.toString();
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private AssetDTO createSomeAssetDTO(final long id) {
|
private AssetDTO createRandomDto(final Long id) {
|
||||||
final AssetDTO given = new AssetDTO();
|
final AssetDTO dto = new AssetDTO();
|
||||||
given.setId(id);
|
dto.setId(id);
|
||||||
given.setAction(AssetAction.PAYMENT);
|
final LocalDate randomDate = LocalDate.parse("2000-12-07").plusDays(RandomUtils.nextInt(1, 999));
|
||||||
given.setAmount(new BigDecimal("512.01"));
|
dto.setDocumentDate(randomDate);
|
||||||
given.setDocumentDate(LocalDate.parse("2019-04-27"));
|
dto.setAmount(new BigDecimal("512.01"));
|
||||||
given.setValueDate(LocalDate.parse("2019-04-28"));
|
dto.setAction(AssetAction.PAYMENT);
|
||||||
given.setMembershipId(SOME_MEMBERSHIP_ID);
|
dto.setRemark("Some Remark");
|
||||||
given.setRemark("Some Remark");
|
dto.setValueDate(randomDate.plusDays(RandomUtils.nextInt(1, 99)));
|
||||||
given.setMembershipDisplayLabel("Display Label for Membership #" + SOME_MEMBERSHIP_ID);
|
dto.setMembershipId(RandomUtils.nextLong());
|
||||||
return given;
|
dto.setMembershipDisplayLabel(RandomStringUtils.randomAlphabetic(20));
|
||||||
|
return dto;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -73,7 +73,6 @@ public class ShareDTOUnitTest {
|
|||||||
public void init() {
|
public void init() {
|
||||||
given(jsonParser.getCodec()).willReturn(codec);
|
given(jsonParser.getCodec()).willReturn(codec);
|
||||||
|
|
||||||
given(ctx.getAutowireCapableBeanFactory()).willReturn(autowireCapableBeanFactory);
|
|
||||||
given(ctx.getAutowireCapableBeanFactory()).willReturn(autowireCapableBeanFactory);
|
given(ctx.getAutowireCapableBeanFactory()).willReturn(autowireCapableBeanFactory);
|
||||||
given(autowireCapableBeanFactory.createBean(CustomerService.class)).willReturn(customerService);
|
given(autowireCapableBeanFactory.createBean(CustomerService.class)).willReturn(customerService);
|
||||||
given(autowireCapableBeanFactory.createBean(MembershipService.class)).willReturn(membershipService);
|
given(autowireCapableBeanFactory.createBean(MembershipService.class)).willReturn(membershipService);
|
||||||
|
@ -162,6 +162,7 @@ public class AssetResourceIntTest {
|
|||||||
|
|
||||||
// Create the Asset
|
// Create the Asset
|
||||||
AssetDTO assetDTO = assetMapper.toDto(asset);
|
AssetDTO assetDTO = assetMapper.toDto(asset);
|
||||||
|
assetDTO.setMembershipDisplayLabel(null);
|
||||||
restAssetMockMvc.perform(post("/api/assets")
|
restAssetMockMvc.perform(post("/api/assets")
|
||||||
.contentType(TestUtil.APPLICATION_JSON_UTF8)
|
.contentType(TestUtil.APPLICATION_JSON_UTF8)
|
||||||
.content(TestUtil.convertObjectToJsonBytes(assetDTO)))
|
.content(TestUtil.convertObjectToJsonBytes(assetDTO)))
|
||||||
|
Loading…
Reference in New Issue
Block a user