diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetPropertyValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetPropertyValidator.java index 7e61845f..15936ea3 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetPropertyValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetPropertyValidator.java @@ -38,7 +38,7 @@ public abstract class HsHostingAssetPropertyValidator { final var propValue = props.get(propertyName); if (propValue == null) { if (required) { - result.add("'" + propertyName + "' is required but missing"); + result.add("'config." + propertyName + "' is required but missing"); } } if (propValue != null){ @@ -46,7 +46,7 @@ public abstract class HsHostingAssetPropertyValidator { //noinspection unchecked validate(result, (T) propValue, props); } 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() + "'"); } } @@ -90,13 +90,13 @@ class IntegerPropertyValidator extends HsHostingAssetPropertyValidator{ @Override protected void validate(final ArrayList result, final Integer propValue, final Map props) { 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) { - 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) { - 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 { @Override protected void validate(final ArrayList result, final String propValue, final Map props) { 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 protected void validate(final ArrayList result, final Boolean propValue, final Map props) { if (falseIf != null && !Objects.equals(props.get(falseIf.getKey()), falseIf.getValue())) { if (propValue) { - result.add("'" + propertyName + "' is expected to be false because " + - falseIf.getKey()+ "=" + falseIf.getValue() + " but is " + propValue); + result.add("'config." + propertyName + "' is expected to be false because " + + "config." + falseIf.getKey()+ "=" + falseIf.getValue() + " but is " + propValue); } } } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetValidator.java index 1389de21..d713330b 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetValidator.java @@ -8,6 +8,7 @@ import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -20,7 +21,7 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.validator.IntegerProper public class HsHostingAssetValidator { - private static final Map validators = Map.ofEntries( + private static final Map validators = new HashMap<>(Map.ofEntries( defType(HsHostingAssetType.CLOUD_SERVER, new HsHostingAssetValidator( integerProperty("CPUs").min(1).max(32).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-PgSQL").falseIf("SLA-Platform", "BASIC").optional(), booleanProperty("SLA-Office").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()) - )); + booleanProperty("SLA-Web").falseIf("SLA-Platform", "BASIC").optional())))); static { validators.entrySet().forEach(typeDef -> { stream(typeDef.getValue().propertyValidators).forEach( entry -> { @@ -57,6 +50,10 @@ public class HsHostingAssetValidator { } 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) { return validators.get(type); } @@ -73,7 +70,7 @@ public class HsHostingAssetValidator { final var result = new ArrayList(); assetEntity.getConfig().keySet().forEach( 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 -> { diff --git a/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsManagedWebspaceAssetValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsManagedWebspaceAssetValidator.java new file mode 100644 index 00000000..709a3ec5 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsManagedWebspaceAssetValidator.java @@ -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 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; + } +} diff --git a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql index 950d01b0..4aa9e099 100644 --- a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql +++ b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7010-hs-hosting-asset.sql @@ -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) ); - - --// diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java index 0d7c8dc5..94c4ceae 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java @@ -215,7 +215,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup { "parentAssetUuid": "%s", "type": "MANAGED_WEBSPACE", - "identifier": "xyz00", + "identifier": "fir90", "caption": "some new ManagedWebspace in client's ManagedServer", "config": { "SSD": 100, "Traffic": 250 } } @@ -229,7 +229,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup .body("", lenientlyEquals(""" { "type": "MANAGED_WEBSPACE", - "identifier": "xyz00", + "identifier": "fir90", "caption": "some new ManagedWebspace in client's ManagedServer", "config": { "SSD": 100, "Traffic": 250 } } @@ -271,7 +271,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup .body("", lenientlyEquals(""" { "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 } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetValidatorUnitTest.java new file mode 100644 index 00000000..90ff4e42 --- /dev/null +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsHostingAssetValidatorUnitTest.java @@ -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"); + } +} diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsManagedWebspaceAssetValidatorUnitTest.java similarity index 54% rename from src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetValidatorUnitTest.java rename to src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsManagedWebspaceAssetValidatorUnitTest.java index d7f21222..952498e0 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validator/HsManagedWebspaceAssetValidatorUnitTest.java @@ -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 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 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 void validatesMissingProperties() { // given final var validator = HsHostingAssetValidator.forType(MANAGED_WEBSPACE); final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() - .type(MANAGED_WEBSPACE) - .config(emptyMap()) - .build(); + .type(MANAGED_WEBSPACE) + .parentAsset(mangedServerAssetEntity) + .identifier("abc00") + .config(emptyMap()) + .build(); // when final var result = validator.validate(mangedWebspaceHostingAssetEntity); // then assertThat(result).containsExactlyInAnyOrder( - "'SSD' is required but missing", - "'Traffic' is required but missing" + "'config.SSD' 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 mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() .type(MANAGED_WEBSPACE) + .parentAsset(mangedServerAssetEntity) + .identifier("abc00") .config(Map.ofEntries( entry("HDD", 0), entry("SSD", 1), @@ -50,29 +96,7 @@ class HsHostingAssetValidatorUnitTest { final var result = validator.validate(mangedWebspaceHostingAssetEntity); // then - assertThat(result).containsExactly("'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"); + assertThat(result).containsExactly("'config.unknown' is not expected but is 'some value'"); } @Test @@ -81,6 +105,8 @@ class HsHostingAssetValidatorUnitTest { final var validator = HsHostingAssetValidator.forType(MANAGED_WEBSPACE); final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() .type(MANAGED_WEBSPACE) + .parentAsset(mangedServerAssetEntity) + .identifier("abc00") .config(Map.ofEntries( entry("HDD", 200), entry("SSD", 25),