hierarchical-validation-baseline #59
@ -6,11 +6,13 @@ import net.hostsharing.hsadminng.hs.validation.HsEntityValidator;
|
||||
import net.hostsharing.hsadminng.hs.validation.ValidatableProperty;
|
||||
|
||||
import jakarta.validation.ValidationException;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.Collections.emptyList;
|
||||
@ -77,14 +79,18 @@ public class HsBookingItemEntityValidator extends HsEntityValidator<HsBookingIte
|
||||
}
|
||||
|
||||
protected List<String> validateSubEntities(final HsBookingItemEntity bookingItem) {
|
||||
return stream(propertyValidators)
|
||||
return Stream.concat(
|
||||
stream(propertyValidators)
|
||||
.map(propDef -> propDef.validateTotals(bookingItem))
|
||||
.flatMap(Collection::stream),
|
||||
stream(propertyValidators)
|
||||
.filter(ValidatableProperty::isTotalsValidator)
|
||||
.map(prop -> validateMaxTotalValue(bookingItem, prop))
|
||||
.filter(Objects::nonNull)
|
||||
.toList();
|
||||
).filter(Objects::nonNull).toList();
|
||||
}
|
||||
|
||||
private String validateMaxTotalValue(
|
||||
// FIXME: convert into generic shape like multi-options validator
|
||||
private static String validateMaxTotalValue(
|
||||
final HsBookingItemEntity bookingItem,
|
||||
final ValidatableProperty<?> propDef) {
|
||||
final var propName = propDef.propertyName();
|
||||
|
@ -25,21 +25,22 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
||||
integerProperty("SSD").unit("GB").min(1).max(100).step(1).required(),
|
||||
integerProperty("HDD").unit("GB").min(0).max(250).step(10).optional(),
|
||||
integerProperty("Traffic").unit("GB").min(10).max(1000).step(10).required(),
|
||||
integerProperty("MultiOptions").min(1).max(100).step(1).required()
|
||||
integerProperty("MultiOptions").min(1).max(100).step(1).withDefault(1)
|
||||
.eachComprising( 25, unixUsers())
|
||||
.eachComprising( 5, databaseUsers())
|
||||
.eachComprising( 5, databases())
|
||||
.eachComprising(250, eMailAddresses()),
|
||||
integerProperty("Daemons").min(0).max(10).optional(),
|
||||
integerProperty("Daemons").min(0).max(10).withDefault(0),
|
||||
booleanProperty("Online Office Server").optional(),
|
||||
enumerationProperty("SLA-Platform").values("BASIC", "EXT24H").optional()
|
||||
enumerationProperty("SLA-Platform").values("BASIC", "EXT24H").withDefault("BASIC")
|
||||
);
|
||||
}
|
||||
|
||||
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> unixUsers() {
|
||||
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
||||
final var unixUserCount = entity.getSubHostingAssets().stream()
|
||||
.filter(bi -> bi.getType() == UNIX_USER)
|
||||
.flatMap(ha -> ha.getSubHostingAssets().stream())
|
||||
.filter(ha -> ha.getType() == UNIX_USER)
|
||||
.count();
|
||||
final long limitingValue = prop.getValue(entity.getResources());
|
||||
if (unixUserCount > factor*limitingValue) {
|
||||
@ -52,6 +53,7 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
||||
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> databaseUsers() {
|
||||
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
||||
final var unixUserCount = entity.getSubHostingAssets().stream()
|
||||
.flatMap(ha -> ha.getSubHostingAssets().stream())
|
||||
.filter(bi -> bi.getType() == PGSQL_USER || bi.getType() == MARIADB_USER )
|
||||
.count();
|
||||
final long limitingValue = prop.getValue(entity.getResources());
|
||||
@ -65,6 +67,7 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
||||
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> databases() {
|
||||
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
||||
final var unixUserCount = entity.getSubHostingAssets().stream()
|
||||
.flatMap(ha -> ha.getSubHostingAssets().stream())
|
||||
.filter(bi -> bi.getType()==PGSQL_USER || bi.getType()==MARIADB_USER )
|
||||
.flatMap(domainEMailSetup -> domainEMailSetup.getSubHostingAssets().stream()
|
||||
.filter(ha -> ha.getType()==PGSQL_DATABASE || ha.getType()==MARIADB_DATABASE))
|
||||
@ -80,6 +83,7 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
|
||||
private static TriFunction<HsBookingItemEntity, IntegerProperty, Integer, List<String>> eMailAddresses() {
|
||||
return (final HsBookingItemEntity entity, final IntegerProperty prop, final Integer factor) -> {
|
||||
final var unixUserCount = entity.getSubHostingAssets().stream()
|
||||
.flatMap(ha -> ha.getSubHostingAssets().stream())
|
||||
.filter(bi -> bi.getType() == DOMAIN_EMAIL_SETUP)
|
||||
.flatMap(domainEMailSetup -> domainEMailSetup.getSubHostingAssets().stream()
|
||||
.filter(ha -> ha.getType()==EMAIL_ADDRESS))
|
||||
|
@ -8,14 +8,17 @@ import net.hostsharing.hsadminng.mapper.Array;
|
||||
import org.apache.commons.lang3.function.TriFunction;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
import static java.lang.Boolean.FALSE;
|
||||
import static java.lang.Boolean.TRUE;
|
||||
import static java.util.Collections.emptyList;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class ValidatableProperty<T> {
|
||||
@ -64,7 +67,7 @@ public abstract class ValidatableProperty<T> {
|
||||
}
|
||||
|
||||
public boolean isTotalsValidator() {
|
||||
return isTotalsValidator;
|
||||
return isTotalsValidator || asTotalLimitValidators != null;
|
||||
}
|
||||
|
||||
public Integer thresholdPercentage() {
|
||||
@ -155,4 +158,20 @@ public abstract class ValidatableProperty<T> {
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
public List<String> validateTotals(final HsBookingItemEntity bookingItem) {
|
||||
if (asTotalLimitValidators==null) {
|
||||
return emptyList();
|
||||
}
|
||||
return asTotalLimitValidators.stream()
|
||||
.map(v -> v.apply(bookingItem))
|
||||
.filter(Objects::nonNull)
|
||||
.flatMap(Collection::stream)
|
||||
.map(v -> wrap(v))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private String wrap(final String v) {
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
@ -3,15 +3,23 @@ package net.hostsharing.hsadminng.hs.booking.item.validators;
|
||||
import net.hostsharing.hsadminng.hs.booking.debitor.HsBookingDebitorEntity;
|
||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
|
||||
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectEntity;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
import static java.util.Arrays.stream;
|
||||
import static java.util.List.of;
|
||||
import static java.util.Map.entry;
|
||||
import static java.util.Map.ofEntries;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.CLOUD_SERVER;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_SERVER;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_WEBSPACE;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.PRIVATE_CLOUD;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.validators.HsBookingItemEntityValidator.forType;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@ -119,4 +127,79 @@ class HsManagedServerBookingItemValidatorUnitTest {
|
||||
"D-12345:Test-Project:null.parentItem.total Traffic is 5500 GB exceeds max total Traffic 5000 GB"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatesExceedingTotals() {
|
||||
// given
|
||||
final var managedWebspaceBookingItem = HsBookingItemEntity.builder()
|
||||
.type(MANAGED_WEBSPACE)
|
||||
.caption("test Managed-Webspace")
|
||||
.resources(ofEntries(
|
||||
entry("SSD", 100),
|
||||
entry("Traffic", 1000),
|
||||
entry("MultiOptions", 1)
|
||||
))
|
||||
.subHostingAssets(of(
|
||||
HsHostingAssetEntity.builder()
|
||||
.type(HsHostingAssetType.MANAGED_WEBSPACE)
|
||||
.identifier("abc00")
|
||||
.subHostingAssets(concat(
|
||||
generate(26, HsHostingAssetType.UNIX_USER, "xyz00-%c%c"),
|
||||
generateDbUsersWithDatabases(3, HsHostingAssetType.PGSQL_USER,
|
||||
"xyz00_%c%c",
|
||||
1, HsHostingAssetType.PGSQL_DATABASE
|
||||
),
|
||||
generateDbUsersWithDatabases(3, HsHostingAssetType.MARIADB_USER,
|
||||
"xyz00_%c%c",
|
||||
1, HsHostingAssetType.MARIADB_DATABASE
|
||||
)
|
||||
))
|
||||
.build()
|
||||
))
|
||||
.build();
|
||||
|
||||
// when
|
||||
final var result = HsBookingItemEntityValidator.doValidate(managedWebspaceBookingItem);
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"MultiOptions=1 allows at maximum 25 unix users, but 26 found",
|
||||
"MultiOptions=1 allows at maximum 5 database users, but 6 found",
|
||||
"MultiOptions=1 allows at maximum 5 databases, but 6 found"
|
||||
);
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private List<HsHostingAssetEntity> concat(final List<HsHostingAssetEntity>... hostingAssets) {
|
||||
return stream(hostingAssets)
|
||||
.flatMap(Collection::stream)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
private List<HsHostingAssetEntity> generate(final int count, final HsHostingAssetType hostingAssetType,
|
||||
final String identifierPattern) {
|
||||
return IntStream.range(0, count)
|
||||
.mapToObj(number -> HsHostingAssetEntity.builder()
|
||||
.type(hostingAssetType)
|
||||
.identifier(identifierPattern.formatted((number/'a')+'a', (number%'a')+'a'))
|
||||
.build())
|
||||
.toList();
|
||||
}
|
||||
|
||||
private List<HsHostingAssetEntity> generateDbUsersWithDatabases(
|
||||
final int userCount,
|
||||
final HsHostingAssetType directAssetType,
|
||||
final String directAssetIdentifierFormat, final int dbCount,
|
||||
final HsHostingAssetType subAssetType) {
|
||||
return IntStream.range(0, userCount)
|
||||
.mapToObj(n -> HsHostingAssetEntity.builder()
|
||||
.type(directAssetType)
|
||||
.identifier(directAssetIdentifierFormat.formatted((n/'a')+'a', (n%'a')+'a'))
|
||||
.subHostingAssets(
|
||||
generate(dbCount, subAssetType, "xyz00_%c%c%%c%%c".formatted((n/'a')+'a', (n%'a')+'a'))
|
||||
)
|
||||
.build())
|
||||
.toList();
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user