add-domain-setup-validation (#71)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/71 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
@@ -185,6 +185,67 @@ public class HsHostingAssetControllerRestTest {
|
||||
}
|
||||
}
|
||||
]
|
||||
"""),
|
||||
DOMAIN_SETUP(
|
||||
List.of(
|
||||
HsHostingAssetEntity.builder()
|
||||
.type(HsHostingAssetType.DOMAIN_SETUP)
|
||||
.identifier("example.org")
|
||||
.caption("some fake Domain-Setup")
|
||||
.build()),
|
||||
"""
|
||||
[
|
||||
{
|
||||
"type": "DOMAIN_SETUP",
|
||||
"identifier": "example.org",
|
||||
"caption": "some fake Domain-Setup",
|
||||
"alarmContact": null,
|
||||
"config": {}
|
||||
}
|
||||
]
|
||||
"""),
|
||||
DOMAIN_DNS_SETUP(
|
||||
List.of(
|
||||
HsHostingAssetEntity.builder()
|
||||
.type(HsHostingAssetType.DOMAIN_DNS_SETUP)
|
||||
.identifier("example.org")
|
||||
.caption("some fake Domain-DNS-Setup")
|
||||
.config(Map.ofEntries(
|
||||
entry("auto-WILDCARD-MX-RR", false),
|
||||
entry("auto-WILDCARD-A-RR", false),
|
||||
entry("auto-WILDCARD-AAAA-RR", false),
|
||||
entry("auto-WILDCARD-DKIM-RR", false),
|
||||
entry("auto-WILDCARD-SPF-RR", false),
|
||||
entry("user-RR", Array.of(
|
||||
"www IN CNAME example.com. ; www.example.com is an alias for example.com",
|
||||
"test1 IN 1h30m CNAME example.com.",
|
||||
"test2 1h30m IN CNAME example.com.",
|
||||
"ns IN A 192.0.2.2; IPv4 address for ns.example.com")
|
||||
)
|
||||
))
|
||||
.build()),
|
||||
"""
|
||||
[
|
||||
{
|
||||
"type": "DOMAIN_DNS_SETUP",
|
||||
"identifier": "example.org",
|
||||
"caption": "some fake Domain-DNS-Setup",
|
||||
"alarmContact": null,
|
||||
"config": {
|
||||
"auto-WILDCARD-AAAA-RR": false,
|
||||
"auto-WILDCARD-MX-RR": false,
|
||||
"auto-WILDCARD-SPF-RR": false,
|
||||
"auto-WILDCARD-DKIM-RR": false,
|
||||
"auto-WILDCARD-A-RR": false,
|
||||
"user-RR": [
|
||||
"www IN CNAME example.com. ; www.example.com is an alias for example.com",
|
||||
"test1 IN 1h30m CNAME example.com.",
|
||||
"test2 1h30m IN CNAME example.com.",
|
||||
"ns IN A 192.0.2.2; IPv4 address for ns.example.com"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
""");
|
||||
|
||||
final HsHostingAssetType assetType;
|
||||
|
@@ -35,7 +35,9 @@ class HsHostingAssetPropsControllerAcceptanceTest {
|
||||
"MANAGED_WEBSPACE",
|
||||
"CLOUD_SERVER",
|
||||
"UNIX_USER",
|
||||
"EMAIL_ALIAS"
|
||||
"EMAIL_ALIAS",
|
||||
"DOMAIN_SETUP",
|
||||
"DOMAIN_DNS_SETUP"
|
||||
]
|
||||
"""));
|
||||
// @formatter:on
|
||||
|
@@ -27,6 +27,7 @@ import java.util.Map;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
|
||||
import static net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantEntity.distinctGrantDisplaysOf;
|
||||
@@ -129,6 +130,9 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
||||
.containsExactlyInAnyOrder(fromFormatted(
|
||||
initialGrantNames,
|
||||
|
||||
// global-admin
|
||||
"{ grant perm:hs_hosting_asset#fir00:SELECT to role:global#global:ADMIN by system and assume }", // workaround
|
||||
|
||||
// owner
|
||||
"{ grant role:hs_hosting_asset#fir00:OWNER to role:hs_booking_item#fir01:ADMIN by system and assume }",
|
||||
"{ grant role:hs_hosting_asset#fir00:OWNER to role:hs_hosting_asset#vm1011:ADMIN by system and assume }",
|
||||
@@ -137,7 +141,6 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
||||
// admin
|
||||
"{ grant role:hs_hosting_asset#fir00:ADMIN to role:hs_hosting_asset#fir00:OWNER by system and assume }",
|
||||
"{ grant role:hs_hosting_asset#fir00:ADMIN to role:hs_booking_item#fir01:AGENT by system and assume }",
|
||||
"{ grant perm:hs_hosting_asset#fir00:INSERT>hs_hosting_asset to role:hs_hosting_asset#fir00:ADMIN by system and assume }",
|
||||
"{ grant perm:hs_hosting_asset#fir00:UPDATE to role:hs_hosting_asset#fir00:ADMIN by system and assume }",
|
||||
|
||||
// agent
|
||||
@@ -148,17 +151,44 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
||||
"{ grant role:hs_booking_item#fir01:TENANT to role:hs_hosting_asset#fir00:TENANT by system and assume }",
|
||||
"{ grant role:hs_hosting_asset#fir00:TENANT to role:hs_hosting_asset#fir00:AGENT by system and assume }",
|
||||
"{ grant role:hs_hosting_asset#vm1011:TENANT to role:hs_hosting_asset#fir00:TENANT by system and assume }",
|
||||
"{ grant perm:hs_hosting_asset#fir00:SELECT to role:hs_hosting_asset#fir00:TENANT by system and assume }",
|
||||
"{ grant perm:hs_hosting_asset#fir00:SELECT to role:hs_hosting_asset#fir00:TENANT by system and assume }", // workaround
|
||||
|
||||
null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void anyUser_canCreateNewDomainSetupAsset() {
|
||||
// given
|
||||
context("superuser-alex@hostsharing.net");
|
||||
final var assetCount = assetRepo.count();
|
||||
|
||||
// when
|
||||
context("person-SmithPeter@example.com");
|
||||
final var result = attempt(em, () -> {
|
||||
final var newAsset = HsHostingAssetEntity.builder()
|
||||
.caption("some new domain setup")
|
||||
.type(DOMAIN_SETUP)
|
||||
.identifier("example.org")
|
||||
.build();
|
||||
return toCleanup(assetRepo.save(newAsset));
|
||||
});
|
||||
|
||||
// then
|
||||
result.assertSuccessful();
|
||||
assertThat(result.returnedValue()).isNotNull().extracting(HsHostingAssetEntity::getUuid).isNotNull();
|
||||
assertThat(result.returnedValue().isLoaded()).isFalse();
|
||||
context("superuser-alex@hostsharing.net");
|
||||
assertThatAssetIsPersisted(result.returnedValue());
|
||||
assertThat(assetRepo.count()).isEqualTo(assetCount + 1);
|
||||
}
|
||||
|
||||
private void assertThatAssetIsPersisted(final HsHostingAssetEntity saved) {
|
||||
final var context =
|
||||
attempt(em, () -> {
|
||||
context("superuser-alex@hostsharing.net");
|
||||
final var found = assetRepo.findByUuid(saved.getUuid());
|
||||
assertThat(found).isNotEmpty().map(HsHostingAssetEntity::toString).get().isEqualTo(saved.toString());
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,245 @@
|
||||
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_DNS_SETUP;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsDomainDnsSetupHostingAssetValidator.RR_COMMENT;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsDomainDnsSetupHostingAssetValidator.RR_RECORD_DATA;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsDomainDnsSetupHostingAssetValidator.RR_RECORD_TYPE;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsDomainDnsSetupHostingAssetValidator.RR_REGEX_IN;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsDomainDnsSetupHostingAssetValidator.RR_REGEX_NAME;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsDomainDnsSetupHostingAssetValidator.RR_REGEX_TTL;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class HsDomainDnsSetupHostingAssetValidatorUnitTest {
|
||||
|
||||
static final HsHostingAssetEntity validDomainSetupEntity = HsHostingAssetEntity.builder()
|
||||
.type(DOMAIN_SETUP)
|
||||
.identifier("example.org")
|
||||
.build();
|
||||
|
||||
static HsHostingAssetEntityBuilder validEntityBuilder() {
|
||||
return HsHostingAssetEntity.builder()
|
||||
.type(DOMAIN_DNS_SETUP)
|
||||
.parentAsset(validDomainSetupEntity)
|
||||
.identifier("example.org")
|
||||
.config(Map.ofEntries(
|
||||
entry("user-RR", Array.of(
|
||||
"@ 1814400 IN XXX example.org. root.example.org ( 1234 10800 900 604800 86400 )",
|
||||
"www IN CNAME example.com. ; www.example.com is an alias for example.com",
|
||||
"test1 IN 1h30m CNAME example.com.",
|
||||
"test2 1h30m IN CNAME example.com.",
|
||||
"ns IN A 192.0.2.2; IPv4 address for ns.example.com")
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsExpectedProperties() {
|
||||
// when
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(DOMAIN_DNS_SETUP);
|
||||
|
||||
// then
|
||||
assertThat(validator.properties()).map(Map::toString).containsExactlyInAnyOrder(
|
||||
"{type=integer, propertyName=TTL, min=0, defaultValue=21600}",
|
||||
"{type=boolean, propertyName=auto-SOA-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-NS-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-MX-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-A-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-AAAA-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-MAILSERVICES-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-AUTOCONFIG-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-AUTODISCOVER-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-DKIM-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-SPF-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-WILDCARD-MX-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-WILDCARD-A-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-WILDCARD-AAAA-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-WILDCARD-DKIM-RR, defaultValue=true}",
|
||||
"{type=boolean, propertyName=auto-WILDCARD-SPF-RR, defaultValue=true}",
|
||||
"{type=string[], propertyName=user-RR, elementsOf={type=string, propertyName=user-RR, matchesRegEx=[([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+[^;].*(;.*)*], required=true}}"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void preprocessesTakesIdentifierFromParent() {
|
||||
// given
|
||||
final var givenEntity = validEntityBuilder().build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||
|
||||
// when
|
||||
validator.preprocessEntity(givenEntity);
|
||||
|
||||
// then
|
||||
assertThat(givenEntity.getIdentifier()).isEqualTo(givenEntity.getParentAsset().getIdentifier());
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInvalidIdentifier() {
|
||||
// given
|
||||
final var givenEntity = validEntityBuilder().identifier("wrong.org").build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validateEntity(givenEntity);
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactly(
|
||||
"'identifier' expected to match '^example.org$', but is 'wrong.org'"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsValidIdentifier() {
|
||||
// given
|
||||
final var givenEntity = validEntityBuilder().identifier(validDomainSetupEntity.getIdentifier()).build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validateEntity(givenEntity);
|
||||
|
||||
// then
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatesReferencedEntities() {
|
||||
// given
|
||||
final var mangedServerHostingAssetEntity = validEntityBuilder()
|
||||
.parentAsset(HsHostingAssetEntity.builder().build())
|
||||
.assignedToAsset(HsHostingAssetEntity.builder().build())
|
||||
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
|
||||
.build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validateEntity(mangedServerHostingAssetEntity);
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'DOMAIN_DNS_SETUP:example.org.bookingItem' must be null but is set to D-???????-?:null",
|
||||
"'DOMAIN_DNS_SETUP:example.org.parentAsset' must be of type DOMAIN_SETUP but is of type null",
|
||||
"'DOMAIN_DNS_SETUP:example.org.assignedToAsset' must be null but is set to D-???????-?:null");
|
||||
}
|
||||
|
||||
@Test
|
||||
void acceptsValidEntity() {
|
||||
// given
|
||||
final var givenEntity = validEntityBuilder().build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||
|
||||
// when
|
||||
final var errors = validator.validateEntity(givenEntity);
|
||||
|
||||
// then
|
||||
assertThat(errors).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void recectsInvalidProperties() {
|
||||
// given
|
||||
final var mangedServerHostingAssetEntity = validEntityBuilder()
|
||||
.config(Map.ofEntries(
|
||||
entry("TTL", "1d30m"), // currently only an integer for seconds is implemented here
|
||||
entry("user-RR", Array.of(
|
||||
"@ 1814400 IN 1814400 BAD1 TTL only allowed once",
|
||||
"www BAD1 Record-Class missing / not enough columns"))
|
||||
))
|
||||
.build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validateEntity(mangedServerHostingAssetEntity);
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'DOMAIN_DNS_SETUP:example.org.config.TTL' is expected to be of type class java.lang.Integer, but is of type 'String'",
|
||||
"'DOMAIN_DNS_SETUP:example.org.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.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");
|
||||
}
|
||||
|
||||
@Test
|
||||
void validStringMatchesRegEx() {
|
||||
assertThat("@ ").matches(RR_REGEX_NAME);
|
||||
assertThat("ns ").matches(RR_REGEX_NAME);
|
||||
assertThat("example.com. ").matches(RR_REGEX_NAME);
|
||||
|
||||
assertThat("12400 ").matches(RR_REGEX_TTL);
|
||||
assertThat("12400\t\t ").matches(RR_REGEX_TTL);
|
||||
assertThat("12400 \t\t").matches(RR_REGEX_TTL);
|
||||
assertThat("1h30m ").matches(RR_REGEX_TTL);
|
||||
assertThat("30m ").matches(RR_REGEX_TTL);
|
||||
|
||||
assertThat("IN ").matches(RR_REGEX_IN);
|
||||
assertThat("IN\t\t ").matches(RR_REGEX_IN);
|
||||
assertThat("IN \t\t").matches(RR_REGEX_IN);
|
||||
|
||||
assertThat("CNAME ").matches(RR_RECORD_TYPE);
|
||||
assertThat("CNAME\t\t ").matches(RR_RECORD_TYPE);
|
||||
assertThat("CNAME \t\t").matches(RR_RECORD_TYPE);
|
||||
|
||||
assertThat("example.com.").matches(RR_RECORD_DATA);
|
||||
assertThat("123.123.123.123").matches(RR_RECORD_DATA);
|
||||
assertThat("(some more complex argument in parenthesis)").matches(RR_RECORD_DATA);
|
||||
assertThat("\"some more complex argument; including a semicolon\"").matches(RR_RECORD_DATA);
|
||||
|
||||
assertThat("; whatever ; \" really anything").matches(RR_COMMENT);
|
||||
}
|
||||
|
||||
@Test
|
||||
void generatesZonefile() {
|
||||
// given
|
||||
final var givenEntity = validEntityBuilder().build();
|
||||
final var validator = (HsDomainDnsSetupHostingAssetValidator) HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||
|
||||
// when
|
||||
final var zonefile = validator.toZonefileString(givenEntity);
|
||||
|
||||
// then
|
||||
assertThat(zonefile).isEqualTo("""
|
||||
$ORIGIN example.org.
|
||||
$TTL 21600
|
||||
|
||||
; these records are just placeholders to create a valid zonefile for the validation
|
||||
@ 1814400 IN SOA example.org. root.example.org ( 1999010100 10800 900 604800 86400 )
|
||||
@ IN NS ns
|
||||
|
||||
@ 1814400 IN XXX example.org. root.example.org ( 1234 10800 900 604800 86400 )
|
||||
www IN CNAME example.com. ; www.example.com is an alias for example.com
|
||||
test1 IN 1h30m CNAME example.com.
|
||||
test2 1h30m IN CNAME example.com.
|
||||
ns IN A 192.0.2.2; IPv4 address for ns.example.com
|
||||
""");
|
||||
}
|
||||
|
||||
@Test
|
||||
void rejectsInvalidZonefile() {
|
||||
// given
|
||||
final var givenEntity = validEntityBuilder().config(Map.ofEntries(
|
||||
entry("user-RR", Array.of(
|
||||
"example.org. 1814400 IN SOA example.org. root.example.org (1234 10800 900 604800 86400)"
|
||||
))
|
||||
))
|
||||
.build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||
|
||||
// when
|
||||
final var errors = validator.validateContext(givenEntity);
|
||||
|
||||
// then
|
||||
assertThat(errors).containsExactlyInAnyOrder(
|
||||
"dns_master_load: example.org: multiple RRs of singleton type",
|
||||
"zone example.org/IN: loading from master file (null) failed: multiple RRs of singleton type",
|
||||
"zone example.org/IN: not loaded due to errors."
|
||||
);
|
||||
}
|
||||
}
|
@@ -0,0 +1,111 @@
|
||||
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 org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.EnumSource;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.DOMAIN_SETUP;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class HsDomainSetupHostingAssetValidatorUnitTest {
|
||||
|
||||
static HsHostingAssetEntityBuilder validEntityBuilder() {
|
||||
return HsHostingAssetEntity.builder()
|
||||
.type(DOMAIN_SETUP)
|
||||
.identifier("example.org");
|
||||
}
|
||||
|
||||
enum InvalidDomainNameIdentifier {
|
||||
EMPTY(""),
|
||||
TOO_LONG("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz0123456890123456789.de"),
|
||||
DASH_AT_BEGINNING("-example.com"),
|
||||
DOT_AT_BEGINNING(".example.com"),
|
||||
DOT_AT_END("example.com.");
|
||||
|
||||
final String domainName;
|
||||
|
||||
InvalidDomainNameIdentifier(final String domainName) {
|
||||
this.domainName = domainName;
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(InvalidDomainNameIdentifier.class)
|
||||
void rejectsInvalidIdentifier(final InvalidDomainNameIdentifier testCase) {
|
||||
// given
|
||||
final var givenEntity = validEntityBuilder().identifier(testCase.domainName).build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validateEntity(givenEntity);
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactly(
|
||||
"'identifier' expected to match '^((?!-)[A-Za-z0-9-]{1,63}(?<!-)\\.)+[A-Za-z]{2,6}', but is '"+testCase.domainName+"'"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
enum ValidDomainNameIdentifier {
|
||||
SIMPLE("exampe.org"),
|
||||
MAX_LENGTH("abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz01234568901.de"),
|
||||
WITH_DASH("example-test.com"),
|
||||
SUBDOMAIN("test.example.com");
|
||||
|
||||
final String domainName;
|
||||
|
||||
ValidDomainNameIdentifier(final String domainName) {
|
||||
this.domainName = domainName;
|
||||
}
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@EnumSource(ValidDomainNameIdentifier.class)
|
||||
void acceptsValidIdentifier(final ValidDomainNameIdentifier testCase) {
|
||||
// given
|
||||
final var givenEntity = validEntityBuilder().identifier(testCase.domainName).build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(givenEntity.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validateEntity(givenEntity);
|
||||
|
||||
// then
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void containsNoProperties() {
|
||||
// when
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(CLOUD_SERVER);
|
||||
|
||||
// then
|
||||
assertThat(validator.properties()).map(Map::toString).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatesReferencedEntities() {
|
||||
// given
|
||||
final var mangedServerHostingAssetEntity = validEntityBuilder()
|
||||
.parentAsset(HsHostingAssetEntity.builder().build())
|
||||
.assignedToAsset(HsHostingAssetEntity.builder().build())
|
||||
.bookingItem(HsBookingItemEntity.builder().type(HsBookingItemType.CLOUD_SERVER).build())
|
||||
.build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(mangedServerHostingAssetEntity.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validateEntity(mangedServerHostingAssetEntity);
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'DOMAIN_SETUP:example.org.bookingItem' must be null but is set to D-???????-?:null",
|
||||
"'DOMAIN_SETUP:example.org.parentAsset' must be null but is set to D-???????-?:null",
|
||||
"'DOMAIN_SETUP:example.org.assignedToAsset' must be null but is set to D-???????-?:null");
|
||||
}
|
||||
}
|
@@ -33,7 +33,9 @@ class HsHostingAssetEntityValidatorRegistryUnitTest {
|
||||
HsHostingAssetType.MANAGED_SERVER,
|
||||
HsHostingAssetType.MANAGED_WEBSPACE,
|
||||
HsHostingAssetType.UNIX_USER,
|
||||
HsHostingAssetType.EMAIL_ALIAS
|
||||
HsHostingAssetType.EMAIL_ALIAS,
|
||||
HsHostingAssetType.DOMAIN_SETUP,
|
||||
HsHostingAssetType.DOMAIN_DNS_SETUP
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,81 @@
|
||||
package net.hostsharing.hsadminng.system;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.condition.EnabledOnOs;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.catchThrowable;
|
||||
import static org.junit.jupiter.api.condition.OS.LINUX;
|
||||
|
||||
class SystemProcessTest {
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(LINUX)
|
||||
void shouldExecuteAndFetchOutput() throws IOException, InterruptedException {
|
||||
// given
|
||||
final var process = new SystemProcess("bash", "-c", "echo 'Hello, World!'; echo 'Error!' >&2");
|
||||
|
||||
// when
|
||||
final var returnCode = process.execute();
|
||||
|
||||
// then
|
||||
assertThat(returnCode).isEqualTo(0);
|
||||
assertThat(process.getStdOut()).isEqualTo("Hello, World!\n");
|
||||
assertThat(process.getStdErr()).isEqualTo("Error!\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(LINUX)
|
||||
void shouldReturnErrorCode() throws IOException, InterruptedException {
|
||||
// given
|
||||
final var process = new SystemProcess("false");
|
||||
|
||||
// when
|
||||
final int returnCode = process.execute();
|
||||
|
||||
// then
|
||||
assertThat(returnCode).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
@EnabledOnOs(LINUX)
|
||||
void shouldExecuteAndFeedInput() throws IOException, InterruptedException {
|
||||
// given
|
||||
final var process = new SystemProcess("tr", "[:lower:]", "[:upper:]");
|
||||
|
||||
// when
|
||||
final int returnCode = process.execute("Hallo");
|
||||
|
||||
// then
|
||||
assertThat(returnCode).isEqualTo(0);
|
||||
assertThat(process.getStdOut()).isEqualTo("HALLO\n");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldThrowExceptionIfProgramNotFound() {
|
||||
// given
|
||||
final var process = new SystemProcess("non-existing program");
|
||||
|
||||
// when
|
||||
final var exception = catchThrowable(process::execute);
|
||||
|
||||
// then
|
||||
assertThat(exception).isInstanceOf(IOException.class)
|
||||
.hasMessage("Cannot run program \"non-existing program\": error=2, No such file or directory");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldBeAbleToRunMultipleTimes() throws IOException, InterruptedException {
|
||||
// given
|
||||
final var process = new SystemProcess("true");
|
||||
|
||||
// when
|
||||
process.execute();
|
||||
final int returnCode = process.execute();
|
||||
|
||||
// then
|
||||
assertThat(returnCode).isEqualTo(0);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user