extract HsManagedWebspaceAssetValidator to separate class and validate identifier against debitor defaultPrefix

This commit is contained in:
Michael Hoennig 2024-05-07 12:20:08 +02:00
parent 7e6a02717f
commit 409f6c973c
7 changed files with 151 additions and 55 deletions

View File

@ -38,7 +38,7 @@ public abstract class HsHostingAssetPropertyValidator<T> {
final var propValue = props.get(propertyName); final var propValue = props.get(propertyName);
if (propValue == null) { if (propValue == null) {
if (required) { if (required) {
result.add("'" + propertyName + "' is required but missing"); result.add("'config." + propertyName + "' is required but missing");
} }
} }
if (propValue != null){ if (propValue != null){
@ -46,7 +46,7 @@ public abstract class HsHostingAssetPropertyValidator<T> {
//noinspection unchecked //noinspection unchecked
validate(result, (T) propValue, props); validate(result, (T) propValue, props);
} else { } else {
result.add("'" + propertyName + "' is expected to be of type " + type + ", " + result.add("'config." + propertyName + "' is expected to be of type " + type + ", " +
"but is of type '" + propValue.getClass().getSimpleName() + "'"); "but is of type '" + propValue.getClass().getSimpleName() + "'");
} }
} }
@ -90,13 +90,13 @@ class IntegerPropertyValidator extends HsHostingAssetPropertyValidator<Integer>{
@Override @Override
protected void validate(final ArrayList<String> result, final Integer propValue, final Map<String, Object> props) { protected void validate(final ArrayList<String> result, final Integer propValue, final Map<String, Object> props) {
if (min != null && propValue < min) { if (min != null && propValue < min) {
result.add("'" + propertyName + "' is expected to be >= " + min + " but is " + propValue); result.add("'config." + propertyName + "' is expected to be >= " + min + " but is " + propValue);
} }
if (max != null && propValue > max) { if (max != null && propValue > max) {
result.add("'" + propertyName + "' is expected to be <= " + max + " but is " + propValue); result.add("'config." + propertyName + "' is expected to be <= " + max + " but is " + propValue);
} }
if (step != null && propValue % step != 0) { if (step != null && propValue % step != 0) {
result.add("'" + propertyName + "' is expected to be multiple of " + step + " but is " + propValue); result.add("'config." + propertyName + "' is expected to be multiple of " + step + " but is " + propValue);
} }
} }
@ -127,7 +127,7 @@ class EnumPropertyValidator extends HsHostingAssetPropertyValidator<String> {
@Override @Override
protected void validate(final ArrayList<String> result, final String propValue, final Map<String, Object> props) { protected void validate(final ArrayList<String> result, final String propValue, final Map<String, Object> props) {
if (Arrays.stream(values).noneMatch(v -> v.equals(propValue))) { if (Arrays.stream(values).noneMatch(v -> v.equals(propValue))) {
result.add("'" + propertyName + "' is expected to be one of " + Arrays.toString(values) + " but is '" + propValue + "'"); result.add("'config." + propertyName + "' is expected to be one of " + Arrays.toString(values) + " but is '" + propValue + "'");
} }
} }
@ -159,8 +159,8 @@ class BooleanPropertyValidator extends HsHostingAssetPropertyValidator<Boolean>
protected void validate(final ArrayList<String> result, final Boolean propValue, final Map<String, Object> props) { protected void validate(final ArrayList<String> result, final Boolean propValue, final Map<String, Object> props) {
if (falseIf != null && !Objects.equals(props.get(falseIf.getKey()), falseIf.getValue())) { if (falseIf != null && !Objects.equals(props.get(falseIf.getKey()), falseIf.getValue())) {
if (propValue) { if (propValue) {
result.add("'" + propertyName + "' is expected to be false because " + result.add("'config." + propertyName + "' is expected to be false because " +
falseIf.getKey()+ "=" + falseIf.getValue() + " but is " + propValue); "config." + falseIf.getKey()+ "=" + falseIf.getValue() + " but is " + propValue);
} }
} }
} }

View File

@ -8,6 +8,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
@ -20,7 +21,7 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.validator.IntegerProper
public class HsHostingAssetValidator { public class HsHostingAssetValidator {
private static final Map<HsHostingAssetType, HsHostingAssetValidator> validators = Map.ofEntries( private static final Map<HsHostingAssetType, HsHostingAssetValidator> validators = new HashMap<>(Map.ofEntries(
defType(HsHostingAssetType.CLOUD_SERVER, new HsHostingAssetValidator( defType(HsHostingAssetType.CLOUD_SERVER, new HsHostingAssetValidator(
integerProperty("CPUs").min(1).max(32).required(), integerProperty("CPUs").min(1).max(32).required(),
integerProperty("RAM").unit("GB").min(1).max(128).required(), integerProperty("RAM").unit("GB").min(1).max(128).required(),
@ -39,15 +40,7 @@ public class HsHostingAssetValidator {
booleanProperty("SLA-Maria").falseIf("SLA-Platform", "BASIC").optional(), booleanProperty("SLA-Maria").falseIf("SLA-Platform", "BASIC").optional(),
booleanProperty("SLA-PgSQL").falseIf("SLA-Platform", "BASIC").optional(), booleanProperty("SLA-PgSQL").falseIf("SLA-Platform", "BASIC").optional(),
booleanProperty("SLA-Office").falseIf("SLA-Platform", "BASIC").optional(), booleanProperty("SLA-Office").falseIf("SLA-Platform", "BASIC").optional(),
booleanProperty("SLA-Web").falseIf("SLA-Platform", "BASIC").optional())), booleanProperty("SLA-Web").falseIf("SLA-Platform", "BASIC").optional()))));
defType(HsHostingAssetType.MANAGED_WEBSPACE, new HsHostingAssetValidator(
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(),
enumerationProperty("SLA-Platform").values("BASIC", "EXT24H").optional(),
integerProperty("Daemons").min(0).max(10).optional(),
booleanProperty("Online Office Server").optional())
));
static { static {
validators.entrySet().forEach(typeDef -> { validators.entrySet().forEach(typeDef -> {
stream(typeDef.getValue().propertyValidators).forEach( entry -> { stream(typeDef.getValue().propertyValidators).forEach( entry -> {
@ -57,6 +50,10 @@ public class HsHostingAssetValidator {
} }
private final HsHostingAssetPropertyValidator<?>[] propertyValidators; private final HsHostingAssetPropertyValidator<?>[] propertyValidators;
public static void register(final HsHostingAssetType type, final HsHostingAssetValidator validator) {
validators.put(type, validator);
}
public static HsHostingAssetValidator forType(final HsHostingAssetType type) { public static HsHostingAssetValidator forType(final HsHostingAssetType type) {
return validators.get(type); return validators.get(type);
} }
@ -73,7 +70,7 @@ public class HsHostingAssetValidator {
final var result = new ArrayList<String>(); final var result = new ArrayList<String>();
assetEntity.getConfig().keySet().forEach( givenPropName -> { assetEntity.getConfig().keySet().forEach( givenPropName -> {
if (stream(propertyValidators).map(pv -> pv.propertyName).noneMatch(propName -> propName.equals(givenPropName))) { if (stream(propertyValidators).map(pv -> pv.propertyName).noneMatch(propName -> propName.equals(givenPropName))) {
result.add("'" + givenPropName + "' is not expected but is '" +assetEntity.getConfig().get(givenPropName) + "'"); result.add("'config." + givenPropName + "' is not expected but is '" +assetEntity.getConfig().get(givenPropName) + "'");
} }
}); });
stream(propertyValidators).forEach(pv -> { stream(propertyValidators).forEach(pv -> {

View File

@ -0,0 +1,40 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validator;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import org.springframework.stereotype.Component;
import java.util.List;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
import static net.hostsharing.hsadminng.hs.hosting.asset.validator.BooleanPropertyValidator.booleanProperty;
import static net.hostsharing.hsadminng.hs.hosting.asset.validator.EnumPropertyValidator.enumerationProperty;
import static net.hostsharing.hsadminng.hs.hosting.asset.validator.IntegerPropertyValidator.integerProperty;
@Component
class HsManagedWebspaceAssetValidator extends HsHostingAssetValidator {
static {
HsHostingAssetValidator.register(MANAGED_WEBSPACE, new HsManagedWebspaceAssetValidator());
}
public HsManagedWebspaceAssetValidator() {
super(
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(),
enumerationProperty("SLA-Platform").values("BASIC", "EXT24H").optional(),
integerProperty("Daemons").min(0).max(10).optional(),
booleanProperty("Online Office Server").optional()
);
}
@Override
public List<String> validate(final HsHostingAssetEntity assetEntity) {
final var result = super.validate(assetEntity);
final var expectedIdentifierPattern = "^" + assetEntity.getParentAsset().getBookingItem().getDebitor().getDefaultPrefix() + "[0-9][0-9]$";
if ( !assetEntity.getIdentifier().matches(expectedIdentifierPattern)) {
result.add("'identifier' expected to match '"+expectedIdentifierPattern+"', but is '" + assetEntity.getIdentifier() + "'");
}
return result;
}
}

View File

@ -33,8 +33,6 @@ create table if not exists hs_hosting_asset
constraint chk_hs_hosting_asset_has_booking_item_or_parent_asset check (bookingItemUuid is not null or parentAssetUuid is not null) constraint chk_hs_hosting_asset_has_booking_item_or_parent_asset check (bookingItemUuid is not null or parentAssetUuid is not null)
); );
--// --//

View File

@ -215,7 +215,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
{ {
"parentAssetUuid": "%s", "parentAssetUuid": "%s",
"type": "MANAGED_WEBSPACE", "type": "MANAGED_WEBSPACE",
"identifier": "xyz00", "identifier": "fir90",
"caption": "some new ManagedWebspace in client's ManagedServer", "caption": "some new ManagedWebspace in client's ManagedServer",
"config": { "SSD": 100, "Traffic": 250 } "config": { "SSD": 100, "Traffic": 250 }
} }
@ -229,7 +229,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"type": "MANAGED_WEBSPACE", "type": "MANAGED_WEBSPACE",
"identifier": "xyz00", "identifier": "fir90",
"caption": "some new ManagedWebspace in client's ManagedServer", "caption": "some new ManagedWebspace in client's ManagedServer",
"config": { "SSD": 100, "Traffic": 250 } "config": { "SSD": 100, "Traffic": 250 }
} }
@ -271,7 +271,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
.body("", lenientlyEquals(""" .body("", lenientlyEquals("""
{ {
"statusPhrase": "Bad Request", "statusPhrase": "Bad Request",
"message": "['extra' is not expected but is '42', 'CPUs' is expected to be >= 1 but is 0, 'RAM' is required but missing, 'SSD' is required but missing, 'Traffic' is required but missing]" "message": "['config.extra' is not expected but is '42', 'config.CPUs' is expected to be >= 1 but is 0, 'config.RAM' is required but missing, 'config.SSD' is required but missing, 'config.Traffic' is required but missing]"
} }
""")); // @formatter:on """)); // @formatter:on
} }

View File

@ -0,0 +1,35 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validator;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import org.junit.jupiter.api.Test;
import java.util.Map;
import static java.util.Map.entry;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
import static org.assertj.core.api.Assertions.assertThat;
class HsHostingAssetValidatorUnitTest {
@Test
void validatesDependentProperties() {
// given
final var validator = HsHostingAssetValidator.forType(MANAGED_SERVER);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_SERVER)
.config(Map.ofEntries(
entry("CPUs", 2),
entry("RAM", 25),
entry("SSD", 25),
entry("Traffic", 250),
entry("SLA-EMail", true)
))
.build();
// when
final var result = validator.validate(mangedWebspaceHostingAssetEntity);
// then
assertThat(result).containsExactly("'config.SLA-EMail' is expected to be false because config.SLA-Platform=BASIC but is true");
}
}

View File

@ -1,6 +1,8 @@
package net.hostsharing.hsadminng.hs.hosting.asset; package net.hostsharing.hsadminng.hs.hosting.asset.validator;
import net.hostsharing.hsadminng.hs.hosting.asset.validator.HsHostingAssetValidator; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import java.util.Map; import java.util.Map;
@ -11,24 +13,66 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANA
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThat;
class HsHostingAssetValidatorUnitTest { class HsManagedWebspaceAssetValidatorUnitTest {
@SuppressWarnings("unused") // just to make sure the class is loaded
HsHostingAssetValidator validator = new HsManagedWebspaceAssetValidator();
final HsBookingItemEntity managedServerBookingItem = HsBookingItemEntity.builder()
.debitor(HsOfficeDebitorEntity.builder().defaultPrefix("abc").build()
)
.build();
final HsHostingAssetEntity mangedServerAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_SERVER)
.bookingItem(managedServerBookingItem)
.config(Map.ofEntries(
entry("HDD", 0),
entry("SSD", 1),
entry("Traffic", 10)
))
.build();
@Test
void validatesIdentifier() {
// given
final var validator = HsHostingAssetValidator.forType(MANAGED_WEBSPACE);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_WEBSPACE)
.parentAsset(mangedServerAssetEntity)
.identifier("xyz00")
.config(Map.ofEntries(
entry("HDD", 0),
entry("SSD", 1),
entry("Traffic", 10)
))
.build();
// when
final var result = validator.validate(mangedWebspaceHostingAssetEntity);
// then
assertThat(result).containsExactly("'identifier' expected to match '^abc[0-9][0-9]$', but is 'xyz00'");
}
@Test @Test
void validatesMissingProperties() { void validatesMissingProperties() {
// given // given
final var validator = HsHostingAssetValidator.forType(MANAGED_WEBSPACE); final var validator = HsHostingAssetValidator.forType(MANAGED_WEBSPACE);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_WEBSPACE) .type(MANAGED_WEBSPACE)
.config(emptyMap()) .parentAsset(mangedServerAssetEntity)
.build(); .identifier("abc00")
.config(emptyMap())
.build();
// when // when
final var result = validator.validate(mangedWebspaceHostingAssetEntity); final var result = validator.validate(mangedWebspaceHostingAssetEntity);
// then // then
assertThat(result).containsExactlyInAnyOrder( assertThat(result).containsExactlyInAnyOrder(
"'SSD' is required but missing", "'config.SSD' is required but missing",
"'Traffic' is required but missing" "'config.Traffic' is required but missing"
); );
} }
@ -38,6 +82,8 @@ class HsHostingAssetValidatorUnitTest {
final var validator = HsHostingAssetValidator.forType(MANAGED_WEBSPACE); final var validator = HsHostingAssetValidator.forType(MANAGED_WEBSPACE);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_WEBSPACE) .type(MANAGED_WEBSPACE)
.parentAsset(mangedServerAssetEntity)
.identifier("abc00")
.config(Map.ofEntries( .config(Map.ofEntries(
entry("HDD", 0), entry("HDD", 0),
entry("SSD", 1), entry("SSD", 1),
@ -50,29 +96,7 @@ class HsHostingAssetValidatorUnitTest {
final var result = validator.validate(mangedWebspaceHostingAssetEntity); final var result = validator.validate(mangedWebspaceHostingAssetEntity);
// then // then
assertThat(result).containsExactly("'unknown' is not expected but is 'some value'"); assertThat(result).containsExactly("'config.unknown' is not expected but is 'some value'");
}
@Test
void validatesDependentProperties() {
// given
final var validator = HsHostingAssetValidator.forType(MANAGED_SERVER);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_SERVER)
.config(Map.ofEntries(
entry("CPUs", 2),
entry("RAM", 25),
entry("SSD", 25),
entry("Traffic", 250),
entry("SLA-EMail", true)
))
.build();
// when
final var result = validator.validate(mangedWebspaceHostingAssetEntity);
// then
assertThat(result).containsExactly("'SLA-EMail' is expected to be false because SLA-Platform=BASIC but is true");
} }
@Test @Test
@ -81,6 +105,8 @@ class HsHostingAssetValidatorUnitTest {
final var validator = HsHostingAssetValidator.forType(MANAGED_WEBSPACE); final var validator = HsHostingAssetValidator.forType(MANAGED_WEBSPACE);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_WEBSPACE) .type(MANAGED_WEBSPACE)
.parentAsset(mangedServerAssetEntity)
.identifier("abc00")
.config(Map.ofEntries( .config(Map.ofEntries(
entry("HDD", 200), entry("HDD", 200),
entry("SSD", 25), entry("SSD", 25),