add-domain-http-setup-validation (#73)

Co-authored-by: Michael Hoennig <michael@hoennig.de>
Reviewed-on: #73
Reviewed-by: Timotheus Pokorra <timotheus.pokorra@hostsharing.net>
This commit is contained in:
Michael Hoennig 2024-07-10 15:54:02 +02:00
parent afb6771ed7
commit 0af389d7c6
26 changed files with 363 additions and 81 deletions

View File

@ -1,8 +1,8 @@
package net.hostsharing.hsadminng.hs.hosting.asset; package net.hostsharing.hsadminng.hs.hosting.asset;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRepository; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRepository;
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityProcessor; import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntitySaveProcessor;
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidatorRegistry; import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityValidatorRegistry;
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetsApi; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetsApi;
import net.hostsharing.hsadminng.context.Context; import net.hostsharing.hsadminng.context.Context;
@ -72,7 +72,7 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
final var entity = mapper.map(body, HsHostingAssetEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER); final var entity = mapper.map(body, HsHostingAssetEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER);
final var mapped = new HsHostingAssetEntityProcessor(entity) final var mapped = new HostingAssetEntitySaveProcessor(entity)
.preprocessEntity() .preprocessEntity()
.validateEntity() .validateEntity()
.prepareForSave() .prepareForSave()
@ -133,7 +133,7 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
new HsHostingAssetEntityPatcher(em, entity).apply(body); new HsHostingAssetEntityPatcher(em, entity).apply(body);
final var mapped = new HsHostingAssetEntityProcessor(entity) final var mapped = new HostingAssetEntitySaveProcessor(entity)
.preprocessEntity() .preprocessEntity()
.validateEntity() .validateEntity()
.prepareForSave() .prepareForSave()
@ -161,6 +161,6 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
final BiConsumer<HsHostingAssetEntity, HsHostingAssetResource> ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource) final BiConsumer<HsHostingAssetEntity, HsHostingAssetResource> ENTITY_TO_RESOURCE_POSTMAPPER = (entity, resource)
-> resource.setConfig(HsHostingAssetEntityValidatorRegistry.forType(entity.getType()) -> resource.setConfig(HostingAssetEntityValidatorRegistry.forType(entity.getType())
.revampProperties(entity, (Map<String, Object>) resource.getConfig())); .revampProperties(entity, (Map<String, Object>) resource.getConfig()));
} }

View File

@ -1,6 +1,6 @@
package net.hostsharing.hsadminng.hs.hosting.asset; package net.hostsharing.hsadminng.hs.hosting.asset;
import net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidatorRegistry; import net.hostsharing.hsadminng.hs.hosting.asset.validators.HostingAssetEntityValidatorRegistry;
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetPropsApi; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.api.HsHostingAssetPropsApi;
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetTypeResource; import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetTypeResource;
import org.springframework.http.ResponseEntity; import org.springframework.http.ResponseEntity;
@ -15,7 +15,7 @@ public class HsHostingAssetPropsController implements HsHostingAssetPropsApi {
@Override @Override
public ResponseEntity<List<String>> listAssetTypes() { public ResponseEntity<List<String>> listAssetTypes() {
final var resource = HsHostingAssetEntityValidatorRegistry.types().stream() final var resource = HostingAssetEntityValidatorRegistry.types().stream()
.map(Enum::name) .map(Enum::name)
.toList(); .toList();
return ResponseEntity.ok(resource); return ResponseEntity.ok(resource);
@ -26,7 +26,7 @@ public class HsHostingAssetPropsController implements HsHostingAssetPropsApi {
final HsHostingAssetTypeResource assetType) { final HsHostingAssetTypeResource assetType) {
final Enum<HsHostingAssetType> type = HsHostingAssetType.of(assetType); final Enum<HsHostingAssetType> type = HsHostingAssetType.of(assetType);
final var propValidators = HsHostingAssetEntityValidatorRegistry.forType(type); final var propValidators = HostingAssetEntityValidatorRegistry.forType(type);
final List<Map<String, Object>> resource = propValidators.properties(); final List<Map<String, Object>> resource = propValidators.properties();
return ResponseEntity.ok(toListOfObjects(resource)); return ResponseEntity.ok(toListOfObjects(resource));
} }

View File

@ -11,27 +11,27 @@ import java.util.function.Function;
/** /**
* Wraps the steps of the pararation, validation, mapping and revamp around saving of a HsHostingAssetEntity into a readable API. * Wraps the steps of the pararation, validation, mapping and revamp around saving of a HsHostingAssetEntity into a readable API.
*/ */
public class HsHostingAssetEntityProcessor { public class HostingAssetEntitySaveProcessor {
private final HsEntityValidator<HsHostingAssetEntity> validator; private final HsEntityValidator<HsHostingAssetEntity> validator;
private String expectedStep = "preprocessEntity"; private String expectedStep = "preprocessEntity";
private HsHostingAssetEntity entity; private HsHostingAssetEntity entity;
private HsHostingAssetResource resource; private HsHostingAssetResource resource;
public HsHostingAssetEntityProcessor(final HsHostingAssetEntity entity) { public HostingAssetEntitySaveProcessor(final HsHostingAssetEntity entity) {
this.entity = entity; this.entity = entity;
this.validator = HsHostingAssetEntityValidatorRegistry.forType(entity.getType()); this.validator = HostingAssetEntityValidatorRegistry.forType(entity.getType());
} }
/// initial step allowing to set default values before any validations /// initial step allowing to set default values before any validations
public HsHostingAssetEntityProcessor preprocessEntity() { public HostingAssetEntitySaveProcessor preprocessEntity() {
step("preprocessEntity", "validateEntity"); step("preprocessEntity", "validateEntity");
validator.preprocessEntity(entity); validator.preprocessEntity(entity);
return this; return this;
} }
/// validates the entity itself including its properties /// validates the entity itself including its properties
public HsHostingAssetEntityProcessor validateEntity() { public HostingAssetEntitySaveProcessor validateEntity() {
step("validateEntity", "prepareForSave"); step("validateEntity", "prepareForSave");
MultiValidationException.throwIfNotEmpty(validator.validateEntity(entity)); MultiValidationException.throwIfNotEmpty(validator.validateEntity(entity));
return this; return this;
@ -39,27 +39,27 @@ public class HsHostingAssetEntityProcessor {
/// hashing passwords etc. /// hashing passwords etc.
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public HsHostingAssetEntityProcessor prepareForSave() { public HostingAssetEntitySaveProcessor prepareForSave() {
step("prepareForSave", "saveUsing"); step("prepareForSave", "saveUsing");
validator.prepareProperties(entity); validator.prepareProperties(entity);
return this; return this;
} }
public HsHostingAssetEntityProcessor saveUsing(final Function<HsHostingAssetEntity, HsHostingAssetEntity> saveFunction) { public HostingAssetEntitySaveProcessor saveUsing(final Function<HsHostingAssetEntity, HsHostingAssetEntity> saveFunction) {
step("saveUsing", "validateContext"); step("saveUsing", "validateContext");
entity = saveFunction.apply(entity); entity = saveFunction.apply(entity);
return this; return this;
} }
/// validates the entity within it's parent and child hierarchy (e.g. totals validators and other limits) /// validates the entity within it's parent and child hierarchy (e.g. totals validators and other limits)
public HsHostingAssetEntityProcessor validateContext() { public HostingAssetEntitySaveProcessor validateContext() {
step("validateContext", "mapUsing"); step("validateContext", "mapUsing");
MultiValidationException.throwIfNotEmpty(validator.validateContext(entity)); MultiValidationException.throwIfNotEmpty(validator.validateContext(entity));
return this; return this;
} }
/// maps entity to JSON resource representation /// maps entity to JSON resource representation
public HsHostingAssetEntityProcessor mapUsing( public HostingAssetEntitySaveProcessor mapUsing(
final Function<HsHostingAssetEntity, HsHostingAssetResource> mapFunction) { final Function<HsHostingAssetEntity, HsHostingAssetResource> mapFunction) {
step("mapUsing", "revampProperties"); step("mapUsing", "revampProperties");
resource = mapFunction.apply(entity); resource = mapFunction.apply(entity);

View File

@ -21,16 +21,16 @@ import static java.util.Arrays.stream;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Optional.ofNullable; import static java.util.Optional.ofNullable;
public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<HsHostingAssetEntity> { public abstract class HostingAssetEntityValidator extends HsEntityValidator<HsHostingAssetEntity> {
static final ValidatableProperty<?, ?>[] NO_EXTRA_PROPERTIES = new ValidatableProperty<?, ?>[0]; static final ValidatableProperty<?, ?>[] NO_EXTRA_PROPERTIES = new ValidatableProperty<?, ?>[0];
private final ReferenceValidator<HsBookingItemEntity, HsBookingItemType> bookingItemReferenceValidation; private final ReferenceValidator<HsBookingItemEntity, HsBookingItemType> bookingItemReferenceValidation;
private final ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> parentAssetReferenceValidation; private final ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> parentAssetReferenceValidation;
private final ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> assignedToAssetReferenceValidation; private final ReferenceValidator<HsHostingAssetEntity, HsHostingAssetType> assignedToAssetReferenceValidation;
private final HsHostingAssetEntityValidator.AlarmContact alarmContactValidation; private final HostingAssetEntityValidator.AlarmContact alarmContactValidation;
HsHostingAssetEntityValidator( HostingAssetEntityValidator(
final HsHostingAssetType assetType, final HsHostingAssetType assetType,
final AlarmContact alarmContactValidation, final AlarmContact alarmContactValidation,
final ValidatableProperty<?, ?>... properties) { final ValidatableProperty<?, ?>... properties) {
@ -98,7 +98,7 @@ public abstract class HsHostingAssetEntityValidator extends HsEntityValidator<Hs
return assetEntity != null return assetEntity != null
? enrich( ? enrich(
prefix(assetEntity.toShortString(), "parentAsset"), prefix(assetEntity.toShortString(), "parentAsset"),
HsHostingAssetEntityValidatorRegistry.forType(assetEntity.getType()).validateContext(assetEntity)) HostingAssetEntityValidatorRegistry.forType(assetEntity.getType()).validateContext(assetEntity))
: emptyList(); : emptyList();
} }

View File

@ -10,7 +10,7 @@ import java.util.*;
import static java.util.Arrays.stream; import static java.util.Arrays.stream;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.*; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.*;
public class HsHostingAssetEntityValidatorRegistry { public class HostingAssetEntityValidatorRegistry {
private static final Map<Enum<HsHostingAssetType>, HsEntityValidator<HsHostingAssetEntity>> validators = new HashMap<>(); private static final Map<Enum<HsHostingAssetType>, HsEntityValidator<HsHostingAssetEntity>> validators = new HashMap<>();
static { static {
@ -22,6 +22,7 @@ public class HsHostingAssetEntityValidatorRegistry {
register(EMAIL_ALIAS, new HsEMailAliasHostingAssetValidator()); register(EMAIL_ALIAS, new HsEMailAliasHostingAssetValidator());
register(DOMAIN_SETUP, new HsDomainSetupHostingAssetValidator()); register(DOMAIN_SETUP, new HsDomainSetupHostingAssetValidator());
register(DOMAIN_DNS_SETUP, new HsDomainDnsSetupHostingAssetValidator()); register(DOMAIN_DNS_SETUP, new HsDomainDnsSetupHostingAssetValidator());
register(DOMAIN_HTTP_SETUP, new HsDomainHttpSetupHostingAssetValidator());
} }
private static void register(final Enum<HsHostingAssetType> type, final HsEntityValidator<HsHostingAssetEntity> validator) { private static void register(final Enum<HsHostingAssetType> type, final HsEntityValidator<HsHostingAssetEntity> validator) {

View File

@ -6,7 +6,7 @@ import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
class HsCloudServerHostingAssetValidator extends HsHostingAssetEntityValidator { class HsCloudServerHostingAssetValidator extends HostingAssetEntityValidator {
HsCloudServerHostingAssetValidator() { HsCloudServerHostingAssetValidator() {
super( super(

View File

@ -15,7 +15,7 @@ import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanPro
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty; import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty; import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty;
class HsDomainDnsSetupHostingAssetValidator extends HsHostingAssetEntityValidator { class HsDomainDnsSetupHostingAssetValidator extends HostingAssetEntityValidator {
// according to RFC 1035 (section 5) and RFC 1034 // according to RFC 1035 (section 5) and RFC 1034
static final String RR_REGEX_NAME = "([a-z0-9\\.-]+|@)\\s+"; static final String RR_REGEX_NAME = "([a-z0-9\\.-]+|@)\\s+";

View File

@ -0,0 +1,56 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import java.util.regex.Pattern;
import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_HTTP_SETUP;
import static net.hostsharing.hsadminng.hs.validation.ArrayProperty.arrayOf;
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty;
class HsDomainHttpSetupHostingAssetValidator extends HostingAssetEntityValidator {
public static final String IDENTIFIER_SUFFIX = "|HTTP";
public static final String FILESYSTEM_PATH = "^/";
public static final String PARTIAL_DOMAIN_NAME_REGEX = "(?!-)[A-Za-z0-9-]{1,63}(?<!-)";
HsDomainHttpSetupHostingAssetValidator() {
super(
DOMAIN_HTTP_SETUP,
AlarmContact.isOptional(),
booleanProperty("htdocsfallback").withDefault(true),
booleanProperty("indexes").withDefault(true),
booleanProperty("cgi").withDefault(true),
booleanProperty("passenger").withDefault(true),
booleanProperty("passenger-errorpage").withDefault(false),
booleanProperty("fastcgi").withDefault(true),
booleanProperty("autoconfig").withDefault(true),
booleanProperty("greylisting").withDefault(true),
booleanProperty("includes").withDefault(true),
booleanProperty("letsencrypt").withDefault(true),
booleanProperty("multiviews").withDefault(true),
stringProperty("fcgi-php-bin").matchesRegEx(FILESYSTEM_PATH).provided("/usr/lib/cgi-bin/php").withDefault("/usr/lib/cgi-bin/php"),
stringProperty("passenger-nodejs").matchesRegEx(FILESYSTEM_PATH).provided("/usr/bin/node").withDefault("/usr/bin/node"),
stringProperty("passenger-python").matchesRegEx(FILESYSTEM_PATH).provided("/usr/bin/python3").withDefault("/usr/bin/python3"),
stringProperty("passenger-ruby").matchesRegEx(FILESYSTEM_PATH).provided("/usr/bin/ruby").withDefault("/usr/bin/ruby"),
arrayOf(
stringProperty("subdomains").matchesRegEx(PARTIAL_DOMAIN_NAME_REGEX).required()
).optional());
}
@Override
protected Pattern identifierPattern(final HsHostingAssetEntity assetEntity) {
return Pattern.compile("^" + assetEntity.getParentAsset().getIdentifier() + Pattern.quote(IDENTIFIER_SUFFIX) + "$");
}
@Override
public void preprocessEntity(final HsHostingAssetEntity entity) {
super.preprocessEntity(entity);
if (entity.getIdentifier() == null) {
ofNullable(entity.getParentAsset()).ifPresent(pa -> entity.setIdentifier(pa.getIdentifier() + IDENTIFIER_SUFFIX));
}
}
}

View File

@ -7,9 +7,9 @@ import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
class HsDomainSetupHostingAssetValidator extends HsHostingAssetEntityValidator { class HsDomainSetupHostingAssetValidator extends HostingAssetEntityValidator {
public static final String DOMAIN_NAME_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}"; public static final String FQDN_REGEX = "^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}";
private final Pattern identifierPattern; private final Pattern identifierPattern;
@ -18,7 +18,7 @@ class HsDomainSetupHostingAssetValidator extends HsHostingAssetEntityValidator {
AlarmContact.isOptional(), AlarmContact.isOptional(),
NO_EXTRA_PROPERTIES); NO_EXTRA_PROPERTIES);
this.identifierPattern = Pattern.compile(DOMAIN_NAME_REGEX); this.identifierPattern = Pattern.compile(FQDN_REGEX);
} }
@Override @Override

View File

@ -8,7 +8,7 @@ import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.validation.ArrayProperty.arrayOf; import static net.hostsharing.hsadminng.hs.validation.ArrayProperty.arrayOf;
import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty; import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty;
class HsEMailAliasHostingAssetValidator extends HsHostingAssetEntityValidator { class HsEMailAliasHostingAssetValidator extends HostingAssetEntityValidator {
private static final String UNIX_USER_REGEX = "^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9]+)?$"; // also accepts legacy pac-names private static final String UNIX_USER_REGEX = "^[a-z][a-z0-9]{2}[0-9]{2}(-[a-z0-9]+)?$"; // also accepts legacy pac-names
private static final String EMAIL_ADDRESS_REGEX = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"; // RFC 5322 private static final String EMAIL_ADDRESS_REGEX = "^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^.-]+@[a-zA-Z0-9.-]+$"; // RFC 5322

View File

@ -9,7 +9,7 @@ import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanPro
import static net.hostsharing.hsadminng.hs.validation.EnumerationProperty.enumerationProperty; import static net.hostsharing.hsadminng.hs.validation.EnumerationProperty.enumerationProperty;
import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty; import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerProperty;
class HsManagedServerHostingAssetValidator extends HsHostingAssetEntityValidator { class HsManagedServerHostingAssetValidator extends HostingAssetEntityValidator {
public HsManagedServerHostingAssetValidator() { public HsManagedServerHostingAssetValidator() {
super( super(

View File

@ -6,7 +6,7 @@ import java.util.regex.Pattern;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
class HsManagedWebspaceHostingAssetValidator extends HsHostingAssetEntityValidator { class HsManagedWebspaceHostingAssetValidator extends HostingAssetEntityValidator {
public HsManagedWebspaceHostingAssetValidator() { public HsManagedWebspaceHostingAssetValidator() {
super( super(
MANAGED_WEBSPACE, MANAGED_WEBSPACE,

View File

@ -12,7 +12,7 @@ import static net.hostsharing.hsadminng.hs.validation.IntegerProperty.integerPro
import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordProperty; import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordProperty;
import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty; import static net.hostsharing.hsadminng.hs.validation.StringProperty.stringProperty;
class HsUnixUserHostingAssetValidator extends HsHostingAssetEntityValidator { class HsUnixUserHostingAssetValidator extends HostingAssetEntityValidator {
private static final int DASH_LENGTH = "-".length(); private static final int DASH_LENGTH = "-".length();

View File

@ -15,9 +15,10 @@ public class StringProperty<P extends StringProperty<P>> extends ValidatableProp
protected static final String[] KEY_ORDER = Array.join( protected static final String[] KEY_ORDER = Array.join(
ValidatableProperty.KEY_ORDER_HEAD, ValidatableProperty.KEY_ORDER_HEAD,
Array.of("matchesRegEx", "minLength", "maxLength"), Array.of("matchesRegEx", "minLength", "maxLength", "provided"),
ValidatableProperty.KEY_ORDER_TAIL, ValidatableProperty.KEY_ORDER_TAIL,
Array.of("undisclosed")); Array.of("undisclosed"));
private String[] provided;
private Pattern[] matchesRegEx; private Pattern[] matchesRegEx;
private Integer minLength; private Integer minLength;
private Integer maxLength; private Integer maxLength;
@ -50,6 +51,12 @@ public class StringProperty<P extends StringProperty<P>> extends ValidatableProp
return self(); return self();
} }
/// predifined values, similar to fixed values in a combobox
public P provided(final String... provided) {
this.provided = provided;
return self();
}
/** /**
* The property value is not disclosed in error messages. * The property value is not disclosed in error messages.
* *
@ -70,7 +77,7 @@ public class StringProperty<P extends StringProperty<P>> extends ValidatableProp
} }
if (matchesRegEx != null && if (matchesRegEx != null &&
stream(matchesRegEx).map(p -> p.matcher(propValue)).noneMatch(Matcher::matches)) { stream(matchesRegEx).map(p -> p.matcher(propValue)).noneMatch(Matcher::matches)) {
result.add(propertyName + "' is expected to match any of " + Arrays.toString(matchesRegEx) + " but " + display(propValue) + " does not match any"); result.add(propertyName + "' is expected to match any of " + Arrays.toString(matchesRegEx) + " but " + display(propValue) + " does not match" + (matchesRegEx.length>1?" any":""));
} }
if (isReadOnly() && propValue != null) { if (isReadOnly() && propValue != null) {
result.add(propertyName + "' is readonly but given as " + display(propValue)); result.add(propertyName + "' is readonly but given as " + display(propValue));

View File

@ -182,8 +182,8 @@ protected void setDeferredInit(final Function<ValidatableProperty<?, ?>[], T[]>
//noinspection unchecked //noinspection unchecked
validate(result, (T) propValue, propsProvider); validate(result, (T) propValue, propsProvider);
} else { } else {
result.add(propertyName + "' is expected to be of type " + type + ", " + result.add(propertyName + "' is expected to be of type " + type.getSimpleName() + ", " +
"but is of type '" + propValue.getClass().getSimpleName() + "'"); "but is of type " + propValue.getClass().getSimpleName() + "");
} }
} }
return result; return result;

View File

@ -246,6 +246,59 @@ public class HsHostingAssetControllerRestTest {
} }
} }
] ]
"""),
DOMAIN_HTTP_SETUP(
List.of(
HsHostingAssetEntity.builder()
.type(HsHostingAssetType.DOMAIN_HTTP_SETUP)
.identifier("example.org")
.caption("some fake Domain-HTTP-Setup")
.config(Map.ofEntries(
entry("htdocsfallback", false),
entry("indexes", false),
entry("cgi", false),
entry("passenger", false),
entry("passenger-errorpage", true),
entry("fastcgi", false),
entry("autoconfig", false),
entry("greylisting", false),
entry("includes", false),
entry("letsencrypt", false),
entry("multiviews", false),
entry("fcgi-php-bin", "/usr/lib/cgi-bin/php8"),
entry("passenger-nodejs", "/usr/bin/node-js7"),
entry("passenger-python", "/usr/bin/python6"),
entry("passenger-ruby", "/usr/bin/ruby5"),
entry("subdomains", Array.of("www", "test1", "test2"))
))
.build()),
"""
[
{
"type": "DOMAIN_HTTP_SETUP",
"identifier": "example.org",
"caption": "some fake Domain-HTTP-Setup",
"alarmContact": null,
"config": {
"autoconfig": false,
"cgi": false,
"fastcgi": false,
"greylisting": false,
"htdocsfallback": false,
"includes": false,
"indexes": false,
"letsencrypt": false,
"multiviews": false,
"passenger": false,
"passenger-errorpage": true,
"passenger-nodejs": "/usr/bin/node-js7",
"passenger-python": "/usr/bin/python6",
"passenger-ruby": "/usr/bin/ruby5",
"fcgi-php-bin": "/usr/lib/cgi-bin/php8",
"subdomains": ["www","test1","test2"]
}
}
]
"""); """);
final HsHostingAssetType assetType; final HsHostingAssetType assetType;

View File

@ -37,7 +37,8 @@ class HsHostingAssetPropsControllerAcceptanceTest {
"UNIX_USER", "UNIX_USER",
"EMAIL_ALIAS", "EMAIL_ALIAS",
"DOMAIN_SETUP", "DOMAIN_SETUP",
"DOMAIN_DNS_SETUP" "DOMAIN_DNS_SETUP",
"DOMAIN_HTTP_SETUP"
] ]
""")); """));
// @formatter:on // @formatter:on

View File

@ -6,13 +6,13 @@ import org.junit.jupiter.api.Test;
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.assertj.core.api.Assertions.catchThrowable;
class HsHostingAssetEntityValidatorRegistryUnitTest { class HostingAssetEntityValidatorRegistryUnitTest {
@Test @Test
void forTypeWithUnknownTypeThrowsException() { void forTypeWithUnknownTypeThrowsException() {
// when // when
final var thrown = catchThrowable(() -> { final var thrown = catchThrowable(() -> {
HsHostingAssetEntityValidatorRegistry.forType(null); HostingAssetEntityValidatorRegistry.forType(null);
}); });
// then // then
@ -22,7 +22,7 @@ class HsHostingAssetEntityValidatorRegistryUnitTest {
@Test @Test
void typesReturnsAllImplementedTypes() { void typesReturnsAllImplementedTypes() {
// when // when
final var types = HsHostingAssetEntityValidatorRegistry.types(); final var types = HostingAssetEntityValidatorRegistry.types();
// then // then
// TODO.test: when all types are implemented, replace with set of all types: // TODO.test: when all types are implemented, replace with set of all types:
@ -35,7 +35,8 @@ class HsHostingAssetEntityValidatorRegistryUnitTest {
HsHostingAssetType.UNIX_USER, HsHostingAssetType.UNIX_USER,
HsHostingAssetType.EMAIL_ALIAS, HsHostingAssetType.EMAIL_ALIAS,
HsHostingAssetType.DOMAIN_SETUP, HsHostingAssetType.DOMAIN_SETUP,
HsHostingAssetType.DOMAIN_DNS_SETUP HsHostingAssetType.DOMAIN_DNS_SETUP,
HsHostingAssetType.DOMAIN_HTTP_SETUP
); );
} }
} }

View File

@ -25,7 +25,7 @@ class HsCloudServerHostingAssetValidatorUnitTest {
entry("RAM", 2000) entry("RAM", 2000)
)) ))
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(cloudServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(cloudServerHostingAssetEntity.getType());
// when // when
@ -45,7 +45,7 @@ class HsCloudServerHostingAssetValidatorUnitTest {
.identifier("xyz99") .identifier("xyz99")
.bookingItem(TEST_CLOUD_SERVER_BOOKING_ITEM) .bookingItem(TEST_CLOUD_SERVER_BOOKING_ITEM)
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(cloudServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(cloudServerHostingAssetEntity.getType());
// when // when
@ -59,7 +59,7 @@ class HsCloudServerHostingAssetValidatorUnitTest {
@Test @Test
void containsAllValidations() { void containsAllValidations() {
// when // when
final var validator = HsHostingAssetEntityValidatorRegistry.forType(CLOUD_SERVER); final var validator = HostingAssetEntityValidatorRegistry.forType(CLOUD_SERVER);
// then // then
assertThat(validator.properties()).map(Map::toString).isEmpty(); assertThat(validator.properties()).map(Map::toString).isEmpty();
@ -73,7 +73,7 @@ class HsCloudServerHostingAssetValidatorUnitTest {
.identifier("xyz00") .identifier("xyz00")
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build()) .bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(mangedServerHostingAssetEntity); final var result = validator.validateEntity(mangedServerHostingAssetEntity);
@ -93,7 +93,7 @@ class HsCloudServerHostingAssetValidatorUnitTest {
.parentAsset(HsHostingAssetEntity.builder().type(MANAGED_SERVER).build()) .parentAsset(HsHostingAssetEntity.builder().type(MANAGED_SERVER).build())
.assignedToAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build()) .assignedToAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build())
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(mangedServerHostingAssetEntity); final var result = validator.validateEntity(mangedServerHostingAssetEntity);

View File

@ -46,7 +46,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
@Test @Test
void containsExpectedProperties() { void containsExpectedProperties() {
// when // when
final var validator = HsHostingAssetEntityValidatorRegistry.forType(DOMAIN_DNS_SETUP); final var validator = HostingAssetEntityValidatorRegistry.forType(DOMAIN_DNS_SETUP);
// then // then
assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder( assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder(
@ -75,7 +75,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
// given // given
final var givenEntity = validEntityBuilder().build(); final var givenEntity = validEntityBuilder().build();
assertThat(givenEntity.getParentAsset().getIdentifier()).as("preconditon failed").isEqualTo("example.org"); assertThat(givenEntity.getParentAsset().getIdentifier()).as("preconditon failed").isEqualTo("example.org");
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when // when
validator.preprocessEntity(givenEntity); validator.preprocessEntity(givenEntity);
@ -88,7 +88,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
void rejectsInvalidIdentifier() { void rejectsInvalidIdentifier() {
// given // given
final var givenEntity = validEntityBuilder().identifier("example.org").build(); final var givenEntity = validEntityBuilder().identifier("example.org").build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when // when
final var result = validator.validateEntity(givenEntity); final var result = validator.validateEntity(givenEntity);
@ -103,7 +103,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
void acceptsValidIdentifier() { void acceptsValidIdentifier() {
// given // given
final var givenEntity = validEntityBuilder().identifier(validDomainSetupEntity.getIdentifier()+"|DNS").build(); final var givenEntity = validEntityBuilder().identifier(validDomainSetupEntity.getIdentifier()+"|DNS").build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when // when
final var result = validator.validateEntity(givenEntity); final var result = validator.validateEntity(givenEntity);
@ -120,7 +120,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
.parentAsset(null) .parentAsset(null)
.assignedToAsset(HsHostingAssetEntity.builder().type(DOMAIN_SETUP).build()) .assignedToAsset(HsHostingAssetEntity.builder().type(DOMAIN_SETUP).build())
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(mangedServerHostingAssetEntity); final var result = validator.validateEntity(mangedServerHostingAssetEntity);
@ -136,7 +136,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
void acceptsValidEntity() { void acceptsValidEntity() {
// given // given
final var givenEntity = validEntityBuilder().build(); final var givenEntity = validEntityBuilder().build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when // when
final var errors = validator.validateEntity(givenEntity); final var errors = validator.validateEntity(givenEntity);
@ -146,7 +146,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
} }
@Test @Test
void recectsInvalidProperties() { void rejectsInvalidProperties() {
// given // given
final var mangedServerHostingAssetEntity = validEntityBuilder() final var mangedServerHostingAssetEntity = validEntityBuilder()
.config(Map.ofEntries( .config(Map.ofEntries(
@ -156,14 +156,14 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
"www BAD1 Record-Class missing / not enough columns")) "www BAD1 Record-Class missing / not enough columns"))
)) ))
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(mangedServerHostingAssetEntity); final var result = validator.validateEntity(mangedServerHostingAssetEntity);
// then // then
assertThat(result).containsExactlyInAnyOrder( assertThat(result).containsExactlyInAnyOrder(
"'DOMAIN_DNS_SETUP:example.org|DNS.config.TTL' is expected to be of type class java.lang.Integer, but is of type 'String'", "'DOMAIN_DNS_SETUP:example.org|DNS.config.TTL' is expected to be of type Integer, but is of type String",
"'DOMAIN_DNS_SETUP:example.org|DNS.config.user-RR' is expected to match any of [([a-z0-9\\.-]+|@)\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*IN\\s+[A-Z]+\\s+[^;].*(;.*)*, ([a-z0-9\\.-]+|@)\\s+IN\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*[A-Z]+\\s+[^;].*(;.*)*] but '@ 1814400 IN 1814400 BAD1 TTL only allowed once' does not match any", "'DOMAIN_DNS_SETUP:example.org|DNS.config.user-RR' is expected to match any of [([a-z0-9\\.-]+|@)\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*IN\\s+[A-Z]+\\s+[^;].*(;.*)*, ([a-z0-9\\.-]+|@)\\s+IN\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*[A-Z]+\\s+[^;].*(;.*)*] but '@ 1814400 IN 1814400 BAD1 TTL only allowed once' does not match any",
"'DOMAIN_DNS_SETUP:example.org|DNS.config.user-RR' is expected to match any of [([a-z0-9\\.-]+|@)\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*IN\\s+[A-Z]+\\s+[^;].*(;.*)*, ([a-z0-9\\.-]+|@)\\s+IN\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*[A-Z]+\\s+[^;].*(;.*)*] but 'www BAD1 Record-Class missing / not enough columns' does not match any"); "'DOMAIN_DNS_SETUP:example.org|DNS.config.user-RR' is expected to match any of [([a-z0-9\\.-]+|@)\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*IN\\s+[A-Z]+\\s+[^;].*(;.*)*, ([a-z0-9\\.-]+|@)\\s+IN\\s+(([1-9][0-9]*[mMhHdDwW]{0,1})+\\s+)*[A-Z]+\\s+[^;].*(;.*)*] but 'www BAD1 Record-Class missing / not enough columns' does not match any");
} }
@ -200,7 +200,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
void generatesZonefile() { void generatesZonefile() {
// given // given
final var givenEntity = validEntityBuilder().build(); final var givenEntity = validEntityBuilder().build();
final var validator = (HsDomainDnsSetupHostingAssetValidator) HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); final var validator = (HsDomainDnsSetupHostingAssetValidator) HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when // when
final var zonefile = validator.toZonefileString(givenEntity); final var zonefile = validator.toZonefileString(givenEntity);
@ -231,7 +231,7 @@ class HsDomainDnsSetupHostingAssetValidatorUnitTest {
)) ))
)) ))
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when // when
final var errors = validator.validateContext(givenEntity); final var errors = validator.validateContext(givenEntity);

View File

@ -0,0 +1,163 @@
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity.HsHostingAssetEntityBuilder;
import net.hostsharing.hsadminng.mapper.Array;
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.DOMAIN_HTTP_SETUP;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.UNIX_USER;
import static org.assertj.core.api.Assertions.assertThat;
class HsDomainHttpSetupHostingAssetValidatorUnitTest {
static final HsHostingAssetEntity validDomainSetupEntity = HsHostingAssetEntity.builder()
.type(DOMAIN_SETUP)
.identifier("example.org")
.build();
static HsHostingAssetEntityBuilder validEntityBuilder() {
return HsHostingAssetEntity.builder()
.type(DOMAIN_HTTP_SETUP)
.parentAsset(validDomainSetupEntity)
.assignedToAsset(HsHostingAssetEntity.builder().type(UNIX_USER).build())
.identifier("example.org|HTTP")
.config(Map.ofEntries(
entry("passenger-errorpage", true),
entry("subdomains", Array.of("www", "test")
)
));
}
@Test
void containsExpectedProperties() {
// when
final var validator = HostingAssetEntityValidatorRegistry.forType(DOMAIN_HTTP_SETUP);
// then
assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder(
"{type=boolean, propertyName=htdocsfallback, defaultValue=true}",
"{type=boolean, propertyName=indexes, defaultValue=true}",
"{type=boolean, propertyName=cgi, defaultValue=true}",
"{type=boolean, propertyName=passenger, defaultValue=true}",
"{type=boolean, propertyName=passenger-errorpage}",
"{type=boolean, propertyName=fastcgi, defaultValue=true}",
"{type=boolean, propertyName=autoconfig, defaultValue=true}",
"{type=boolean, propertyName=greylisting, defaultValue=true}",
"{type=boolean, propertyName=includes, defaultValue=true}",
"{type=boolean, propertyName=letsencrypt, defaultValue=true}",
"{type=boolean, propertyName=multiviews, defaultValue=true}",
"{type=string, propertyName=fcgi-php-bin, matchesRegEx=[^/], provided=[/usr/lib/cgi-bin/php], defaultValue=/usr/lib/cgi-bin/php}",
"{type=string, propertyName=passenger-nodejs, matchesRegEx=[^/], provided=[/usr/bin/node], defaultValue=/usr/bin/node}",
"{type=string, propertyName=passenger-python, matchesRegEx=[^/], provided=[/usr/bin/python3], defaultValue=/usr/bin/python3}",
"{type=string, propertyName=passenger-ruby, matchesRegEx=[^/], provided=[/usr/bin/ruby], defaultValue=/usr/bin/ruby}",
"{type=string[], propertyName=subdomains, elementsOf={type=string, propertyName=subdomains, matchesRegEx=[(?!-)[A-Za-z0-9-]{1,63}(?<!-)], required=true}}"
);
}
@Test
void preprocessesTakesIdentifierFromParent() {
// given
final var givenEntity = validEntityBuilder().build();
assertThat(givenEntity.getParentAsset().getIdentifier()).as("preconditon failed").isEqualTo("example.org");
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when
validator.preprocessEntity(givenEntity);
// then
assertThat(givenEntity.getIdentifier()).isEqualTo("example.org|HTTP");
}
@Test
void rejectsInvalidIdentifier() {
// given
final var givenEntity = validEntityBuilder().identifier("example.org").build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when
final var result = validator.validateEntity(givenEntity);
// then
assertThat(result).containsExactly(
"'identifier' expected to match '^example.org\\Q|HTTP\\E$', but is 'example.org'"
);
}
@Test
void acceptsValidIdentifier() {
// given
final var givenEntity = validEntityBuilder().identifier(validDomainSetupEntity.getIdentifier()+"|HTTP").build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when
final var result = validator.validateEntity(givenEntity);
// then
assertThat(result).isEmpty();
}
@Test
void rejectsInvalidReferencedEntities() {
// given
final var mangedServerHostingAssetEntity = validEntityBuilder()
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
.parentAsset(HsHostingAssetEntity.builder().type(MANAGED_WEBSPACE).build())
.assignedToAsset(null)
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when
final var result = validator.validateEntity(mangedServerHostingAssetEntity);
// then
assertThat(result).containsExactlyInAnyOrder(
"'DOMAIN_HTTP_SETUP:example.org|HTTP.bookingItem' must be null but is of type CLOUD_SERVER",
"'DOMAIN_HTTP_SETUP:example.org|HTTP.parentAsset' must be of type DOMAIN_SETUP but is of type MANAGED_WEBSPACE",
"'DOMAIN_HTTP_SETUP:example.org|HTTP.assignedToAsset' must be of type UNIX_USER but is null");
}
@Test
void acceptsValidEntity() {
// given
final var givenEntity = validEntityBuilder().build();
final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when
final var errors = validator.validateEntity(givenEntity);
// then
assertThat(errors).isEmpty();
}
@Test
void rejectsInvalidProperties() {
// given
final var mangedServerHostingAssetEntity = validEntityBuilder()
.config(Map.ofEntries(
entry("htdocsfallback", "false"),
entry("fcgi-php-bin", "false"),
entry("subdomains", Array.of("", "@", "example.com"))
))
.build();
final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when
final var result = validator.validateEntity(mangedServerHostingAssetEntity);
// then
assertThat(result).containsExactlyInAnyOrder(
"'DOMAIN_HTTP_SETUP:example.org|HTTP.config.htdocsfallback' is expected to be of type Boolean, but is of type String",
"'DOMAIN_HTTP_SETUP:example.org|HTTP.config.fcgi-php-bin' is expected to match any of [^/] but 'false' does not match",
"'DOMAIN_HTTP_SETUP:example.org|HTTP.config.subdomains' is expected to match any of [(?!-)[A-Za-z0-9-]{1,63}(?<!-)] but '' does not match",
"'DOMAIN_HTTP_SETUP:example.org|HTTP.config.subdomains' is expected to match any of [(?!-)[A-Za-z0-9-]{1,63}(?<!-)] but '@' does not match",
"'DOMAIN_HTTP_SETUP:example.org|HTTP.config.subdomains' is expected to match any of [(?!-)[A-Za-z0-9-]{1,63}(?<!-)] but 'example.com' does not match");
}
}

View File

@ -42,7 +42,7 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
void rejectsInvalidIdentifier(final InvalidDomainNameIdentifier testCase) { void rejectsInvalidIdentifier(final InvalidDomainNameIdentifier testCase) {
// given // given
final var givenEntity = validEntityBuilder().identifier(testCase.domainName).build(); final var givenEntity = validEntityBuilder().identifier(testCase.domainName).build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when // when
final var result = validator.validateEntity(givenEntity); final var result = validator.validateEntity(givenEntity);
@ -72,7 +72,7 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
void acceptsValidIdentifier(final ValidDomainNameIdentifier testCase) { void acceptsValidIdentifier(final ValidDomainNameIdentifier testCase) {
// given // given
final var givenEntity = validEntityBuilder().identifier(testCase.domainName).build(); final var givenEntity = validEntityBuilder().identifier(testCase.domainName).build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
// when // when
final var result = validator.validateEntity(givenEntity); final var result = validator.validateEntity(givenEntity);
@ -84,7 +84,7 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
@Test @Test
void containsNoProperties() { void containsNoProperties() {
// when // when
final var validator = HsHostingAssetEntityValidatorRegistry.forType(CLOUD_SERVER); final var validator = HostingAssetEntityValidatorRegistry.forType(CLOUD_SERVER);
// then // then
assertThat(validator.properties()).map(Map::toString).isEmpty(); assertThat(validator.properties()).map(Map::toString).isEmpty();
@ -98,7 +98,7 @@ class HsDomainSetupHostingAssetValidatorUnitTest {
.assignedToAsset(HsHostingAssetEntity.builder().type(MANAGED_SERVER).build()) .assignedToAsset(HsHostingAssetEntity.builder().type(MANAGED_SERVER).build())
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build()) .bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(mangedServerHostingAssetEntity); final var result = validator.validateEntity(mangedServerHostingAssetEntity);

View File

@ -18,7 +18,7 @@ class HsEMailAliasHostingAssetValidatorUnitTest {
@Test @Test
void containsAllValidations() { void containsAllValidations() {
// when // when
final var validator = HsHostingAssetEntityValidatorRegistry.forType(EMAIL_ALIAS); final var validator = HostingAssetEntityValidatorRegistry.forType(EMAIL_ALIAS);
// then // then
assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder( assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder(
@ -36,7 +36,7 @@ class HsEMailAliasHostingAssetValidatorUnitTest {
entry("target", Array.of("xyz00", "xyz00-abc", "office@example.com")) entry("target", Array.of("xyz00", "xyz00-abc", "office@example.com"))
)) ))
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(emailAliasHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(emailAliasHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(emailAliasHostingAssetEntity); final var result = validator.validateEntity(emailAliasHostingAssetEntity);
@ -56,7 +56,7 @@ class HsEMailAliasHostingAssetValidatorUnitTest {
entry("target", Array.of("xyz00", "xyz00-abc", "garbage", "office@example.com")) entry("target", Array.of("xyz00", "xyz00-abc", "garbage", "office@example.com"))
)) ))
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(emailAliasHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(emailAliasHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(emailAliasHostingAssetEntity); final var result = validator.validateEntity(emailAliasHostingAssetEntity);
@ -77,7 +77,7 @@ class HsEMailAliasHostingAssetValidatorUnitTest {
entry("target", Array.of("office@example.com")) entry("target", Array.of("office@example.com"))
)) ))
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(emailAliasHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(emailAliasHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(emailAliasHostingAssetEntity); final var result = validator.validateEntity(emailAliasHostingAssetEntity);
@ -100,7 +100,7 @@ class HsEMailAliasHostingAssetValidatorUnitTest {
entry("target", Array.of("office@example.com")) entry("target", Array.of("office@example.com"))
)) ))
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(emailAliasHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(emailAliasHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(emailAliasHostingAssetEntity); final var result = validator.validateEntity(emailAliasHostingAssetEntity);

View File

@ -31,7 +31,7 @@ class HsManagedServerHostingAssetValidatorUnitTest {
entry("monit_max_ram_usage", 101) entry("monit_max_ram_usage", 101)
)) ))
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedWebspaceHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(mangedWebspaceHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(mangedWebspaceHostingAssetEntity); final var result = validator.validateEntity(mangedWebspaceHostingAssetEntity);
@ -42,7 +42,7 @@ class HsManagedServerHostingAssetValidatorUnitTest {
"'MANAGED_SERVER:vm1234.assignedToAsset' must be null but is of type CLOUD_SERVER", "'MANAGED_SERVER:vm1234.assignedToAsset' must be null but is of type CLOUD_SERVER",
"'MANAGED_SERVER:vm1234.config.monit_max_cpu_usage' is expected to be at least 10 but is 2", "'MANAGED_SERVER:vm1234.config.monit_max_cpu_usage' is expected to be at least 10 but is 2",
"'MANAGED_SERVER:vm1234.config.monit_max_ram_usage' is expected to be at most 100 but is 101", "'MANAGED_SERVER:vm1234.config.monit_max_ram_usage' is expected to be at most 100 but is 101",
"'MANAGED_SERVER:vm1234.config.monit_max_hdd_usage' is expected to be of type class java.lang.Integer, but is of type 'String'"); "'MANAGED_SERVER:vm1234.config.monit_max_hdd_usage' is expected to be of type Integer, but is of type String");
} }
@Test @Test
@ -53,7 +53,7 @@ class HsManagedServerHostingAssetValidatorUnitTest {
.identifier("xyz00") .identifier("xyz00")
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.MANAGED_SERVER).build()) .bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.MANAGED_SERVER).build())
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(mangedServerHostingAssetEntity); final var result = validator.validateEntity(mangedServerHostingAssetEntity);
@ -73,7 +73,7 @@ class HsManagedServerHostingAssetValidatorUnitTest {
.parentAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build()) .parentAsset(HsHostingAssetEntity.builder().type(CLOUD_SERVER).build())
.assignedToAsset(HsHostingAssetEntity.builder().type(MANAGED_SERVER).build()) .assignedToAsset(HsHostingAssetEntity.builder().type(MANAGED_SERVER).build())
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
// when // when
final var result = validator.validateEntity(mangedServerHostingAssetEntity); final var result = validator.validateEntity(mangedServerHostingAssetEntity);

View File

@ -59,7 +59,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
@Test @Test
void acceptsAlienIdentifierPrefixForPreExistingEntity() { void acceptsAlienIdentifierPrefixForPreExistingEntity() {
// given // given
final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE); final var validator = HostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_WEBSPACE) .type(MANAGED_WEBSPACE)
.bookingItem(HsBookingItemEntity.builder() .bookingItem(HsBookingItemEntity.builder()
@ -81,7 +81,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
@Test @Test
void validatesIdentifierAndReferencedEntities() { void validatesIdentifierAndReferencedEntities() {
// given // given
final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE); final var validator = HostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_WEBSPACE) .type(MANAGED_WEBSPACE)
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.MANAGED_WEBSPACE).build()) .bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.MANAGED_WEBSPACE).build())
@ -99,7 +99,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
@Test @Test
void validatesUnknownProperties() { void validatesUnknownProperties() {
// given // given
final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE); final var validator = HostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_WEBSPACE) .type(MANAGED_WEBSPACE)
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.MANAGED_WEBSPACE).build()) .bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.MANAGED_WEBSPACE).build())
@ -120,7 +120,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
@Test @Test
void validatesValidEntity() { void validatesValidEntity() {
// given // given
final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE); final var validator = HostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_WEBSPACE) .type(MANAGED_WEBSPACE)
.bookingItem(HsBookingItemEntity.builder() .bookingItem(HsBookingItemEntity.builder()
@ -145,7 +145,7 @@ class HsManagedWebspaceHostingAssetValidatorUnitTest {
@Test @Test
void rejectsInvalidEntityReferences() { void rejectsInvalidEntityReferences() {
// given // given
final var validator = HsHostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE); final var validator = HostingAssetEntityValidatorRegistry.forType(MANAGED_WEBSPACE);
final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder() final var mangedWebspaceHostingAssetEntity = HsHostingAssetEntity.builder()
.type(MANAGED_WEBSPACE) .type(MANAGED_WEBSPACE)
.bookingItem(HsBookingItemEntity.builder() .bookingItem(HsBookingItemEntity.builder()

View File

@ -47,7 +47,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
void preparesUnixUser() { void preparesUnixUser() {
// given // given
final var unixUserHostingAsset = GIVEN_VALID_UNIX_USER_HOSTING_ASSET; final var unixUserHostingAsset = GIVEN_VALID_UNIX_USER_HOSTING_ASSET;
final var validator = HsHostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType());
// when // when
LinuxEtcShadowHashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); LinuxEtcShadowHashGenerator.nextSalt("Ly3LbsArtL5u4EVt");
@ -66,7 +66,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
void validatesValidUnixUser() { void validatesValidUnixUser() {
// given // given
final var unixUserHostingAsset = GIVEN_VALID_UNIX_USER_HOSTING_ASSET; final var unixUserHostingAsset = GIVEN_VALID_UNIX_USER_HOSTING_ASSET;
final var validator = HsHostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType());
// when // when
final var result = Stream.concat( final var result = Stream.concat(
@ -97,7 +97,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
entry("password", "short") entry("password", "short")
)) ))
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType());
// when // when
final var result = validator.validateEntity(unixUserHostingAsset); final var result = validator.validateEntity(unixUserHostingAsset);
@ -110,7 +110,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
"'UNIX_USER:abc00-temp.config.HDD soft quota' is expected to be at most 100 but is 200", "'UNIX_USER:abc00-temp.config.HDD soft quota' is expected to be at most 100 but is 200",
"'UNIX_USER:abc00-temp.config.shell' is expected to be one of [/bin/false, /bin/bash, /bin/csh, /bin/dash, /usr/bin/tcsh, /usr/bin/zsh, /usr/bin/passwd] but is '/is/invalid'", "'UNIX_USER:abc00-temp.config.shell' is expected to be one of [/bin/false, /bin/bash, /bin/csh, /bin/dash, /usr/bin/tcsh, /usr/bin/zsh, /usr/bin/passwd] but is '/is/invalid'",
"'UNIX_USER:abc00-temp.config.homedir' is readonly but given as '/is/read-only'", "'UNIX_USER:abc00-temp.config.homedir' is readonly but given as '/is/read-only'",
"'UNIX_USER:abc00-temp.config.totpKey' is expected to match any of [^0x([0-9A-Fa-f]{2})+$] but provided value does not match any", "'UNIX_USER:abc00-temp.config.totpKey' is expected to match any of [^0x([0-9A-Fa-f]{2})+$] but provided value does not match",
"'UNIX_USER:abc00-temp.config.password' length is expected to be at min 8 but length of provided value is 5", "'UNIX_USER:abc00-temp.config.password' length is expected to be at min 8 but length of provided value is 5",
"'UNIX_USER:abc00-temp.config.password' must contain at least one character of at least 3 of the following groups: upper case letters, lower case letters, digits, special characters" "'UNIX_USER:abc00-temp.config.password' must contain at least one character of at least 3 of the following groups: upper case letters, lower case letters, digits, special characters"
); );
@ -124,7 +124,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
.parentAsset(HsHostingAssetEntity.builder().type(MANAGED_WEBSPACE).identifier("abc00").build()) .parentAsset(HsHostingAssetEntity.builder().type(MANAGED_WEBSPACE).identifier("abc00").build())
.identifier("xyz99-temp") .identifier("xyz99-temp")
.build(); .build();
final var validator = HsHostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType());
// when // when
final var result = validator.validateEntity(unixUserHostingAsset); final var result = validator.validateEntity(unixUserHostingAsset);
@ -138,7 +138,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
void revampsUnixUser() { void revampsUnixUser() {
// given // given
final var unixUserHostingAsset = GIVEN_VALID_UNIX_USER_HOSTING_ASSET; final var unixUserHostingAsset = GIVEN_VALID_UNIX_USER_HOSTING_ASSET;
final var validator = HsHostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType()); final var validator = HostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType());
// when // when
LinuxEtcShadowHashGenerator.nextSalt("Ly3LbsArtL5u4EVt"); LinuxEtcShadowHashGenerator.nextSalt("Ly3LbsArtL5u4EVt");
@ -155,7 +155,7 @@ class HsUnixUserHostingAssetValidatorUnitTest {
@Test @Test
void describesItsProperties() { void describesItsProperties() {
// given // given
final var validator = HsHostingAssetEntityValidatorRegistry.forType(UNIX_USER); final var validator = HostingAssetEntityValidatorRegistry.forType(UNIX_USER);
// when // when
final var props = validator.properties(); final var props = validator.properties();