add-unix-user-hosting-asset-validation (#66)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/66 Reviewed-by: Marc Sandlus <marc.sandlus@hostsharing.net>
This commit is contained in:
@@ -53,7 +53,7 @@ class HsBookingItemEntityUnitTest {
|
||||
void toStringContainsAllPropertiesAndResourcesSortedByKey() {
|
||||
final var result = givenBookingItem.toString();
|
||||
|
||||
assertThat(result).isEqualTo("HsBookingItemEntity(D-1234500:test project, CLOUD_SERVER, [2020-01-01,2031-01-01), some caption, { CPUs: 2, HDD-storage: 2048, SSD-storage: 512 })");
|
||||
assertThat(result).isEqualToIgnoringWhitespace("HsBookingItemEntity(D-1234500:test project, CLOUD_SERVER, [2020-01-01,2031-01-01), some caption, { \"CPUs\": 2, \"HDD-storage\": 2048, \"SSD-storage\": 512 })");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -170,9 +170,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
|
||||
// then
|
||||
allTheseBookingItemsAreReturned(
|
||||
result,
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), separate ManagedWebspace, { Daemons: 0, Multi: 1, SSD: 100, Traffic: 50 })",
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 500, Traffic: 500 })",
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 })");
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), separate ManagedWebspace, { Daemons: 0, Multi: 1, SSD: 100, Traffic: 50 } )",
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 500, Traffic: 500 } )",
|
||||
"HsBookingItemEntity(D-1000212:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 } )");
|
||||
assertThat(result.stream().filter(bi -> bi.getRelatedHostingAsset()!=null).findAny())
|
||||
.as("at least one relatedProject expected, but none found => fetching relatedProject does not work")
|
||||
.isNotEmpty();
|
||||
@@ -193,9 +193,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
|
||||
// then:
|
||||
exactlyTheseBookingItemsAreReturned(
|
||||
result,
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 500, Traffic: 500 })",
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_WEBSPACE, [2022-10-01,), separate ManagedWebspace, { Daemons: 0, Multi: 1, SSD: 100, Traffic: 50 })",
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 })");
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_WEBSPACE, [2022-10-01,), separate ManagedWebspace, { Daemons: 0, Multi: 1, SSD: 100, Traffic: 50 } )",
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 500, Traffic: 500 } )",
|
||||
"HsBookingItemEntity(D-1000111:D-1000111 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 } )");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,13 +348,17 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
|
||||
final List<HsBookingItemEntity> actualResult,
|
||||
final String... bookingItemNames) {
|
||||
assertThat(actualResult)
|
||||
.extracting(bookingItemEntity -> bookingItemEntity.toString())
|
||||
.extracting(HsBookingItemEntity::toString)
|
||||
.extracting(string-> string.replaceAll("\\s+", " "))
|
||||
.extracting(string-> string.replaceAll("\"", ""))
|
||||
.containsExactlyInAnyOrder(bookingItemNames);
|
||||
}
|
||||
|
||||
void allTheseBookingItemsAreReturned(final List<HsBookingItemEntity> actualResult, final String... bookingItemNames) {
|
||||
assertThat(actualResult)
|
||||
.extracting(bookingItemEntity -> bookingItemEntity.toString())
|
||||
.extracting(HsBookingItemEntity::toString)
|
||||
.extracting(string -> string.replaceAll("\\s+", " "))
|
||||
.extracting(string -> string.replaceAll("\"", ""))
|
||||
.contains(bookingItemNames);
|
||||
}
|
||||
}
|
||||
|
@@ -12,21 +12,35 @@ import static net.hostsharing.hsadminng.hs.booking.project.TestHsBookingProject.
|
||||
@UtilityClass
|
||||
public class TestHsBookingItem {
|
||||
|
||||
public static final HsBookingItemEntity TEST_MANAGED_SERVER_BOOKING_ITEM = HsBookingItemEntity.builder()
|
||||
.project(TEST_PROJECT)
|
||||
.type(HsBookingItemType.MANAGED_SERVER)
|
||||
.caption("test project booking item")
|
||||
.resources(Map.ofEntries(
|
||||
entry("someThing", 1),
|
||||
entry("anotherThing", "blue")
|
||||
))
|
||||
.validity(Range.closedInfinite(LocalDate.of(2020, 1, 15)))
|
||||
.build();
|
||||
|
||||
public static final HsBookingItemEntity TEST_CLOUD_SERVER_BOOKING_ITEM = HsBookingItemEntity.builder()
|
||||
.project(TEST_PROJECT)
|
||||
.type(HsBookingItemType.CLOUD_SERVER)
|
||||
.caption("test cloud server booking item")
|
||||
.validity(Range.closedInfinite(LocalDate.of(2020, 1, 15)))
|
||||
.build();
|
||||
|
||||
public static final HsBookingItemEntity TEST_MANAGED_SERVER_BOOKING_ITEM = HsBookingItemEntity.builder()
|
||||
.project(TEST_PROJECT)
|
||||
.type(HsBookingItemType.MANAGED_SERVER)
|
||||
.caption("test project booking item")
|
||||
.resources(Map.ofEntries(
|
||||
entry("CPUs", 2),
|
||||
entry("RAM", 4),
|
||||
entry("SSD", 50),
|
||||
entry("Traffic", 250)
|
||||
))
|
||||
.validity(Range.closedInfinite(LocalDate.of(2020, 1, 15)))
|
||||
.build();
|
||||
|
||||
public static final HsBookingItemEntity TEST_MANAGED_WEBSPACE_BOOKING_ITEM = HsBookingItemEntity.builder()
|
||||
.parentItem(TEST_MANAGED_SERVER_BOOKING_ITEM)
|
||||
.type(HsBookingItemType.MANAGED_WEBSPACE)
|
||||
.caption("test managed webspace item")
|
||||
.resources(Map.ofEntries(
|
||||
entry("SSD", 50),
|
||||
entry("Traffic", 250)
|
||||
))
|
||||
.validity(Range.closedInfinite(LocalDate.of(2020, 1, 15)))
|
||||
.build();
|
||||
|
||||
}
|
||||
|
@@ -25,12 +25,14 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static java.util.Map.entry;
|
||||
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.hs.hosting.asset.HsHostingAssetType.UNIX_USER;
|
||||
import static net.hostsharing.hsadminng.rbac.test.JsonMatcher.lenientlyEquals;
|
||||
import static net.hostsharing.hsadminng.rbac.test.JsonMatcher.strictlyEquals;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.hamcrest.Matchers.matchesRegex;
|
||||
|
||||
@@ -73,7 +75,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
// given
|
||||
context("superuser-alex@hostsharing.net");
|
||||
final var givenProject = projectRepo.findByCaption("D-1000111 default project").stream()
|
||||
.findAny().orElseThrow();
|
||||
.findAny().orElseThrow();
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
@@ -264,7 +266,8 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
void propertyValidationsArePerformend_whenAddingAsset() {
|
||||
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenBookingItem = givenSomeNewBookingItem("D-1000111 default project",
|
||||
final var givenBookingItem = givenSomeNewBookingItem(
|
||||
"D-1000111 default project",
|
||||
HsBookingItemType.MANAGED_SERVER,
|
||||
"some PrivateCloud");
|
||||
|
||||
@@ -292,14 +295,13 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"statusPhrase": "Bad Request",
|
||||
"message": "[
|
||||
<<<'MANAGED_SERVER:vm1400.config.extra' is not expected but is set to '42',
|
||||
<<<'MANAGED_SERVER:vm1400.config.monit_max_cpu_usage' is expected to be <= 100 but is 101,
|
||||
<<<'MANAGED_SERVER:vm1400.config.monit_max_ssd_usage' is expected to be >= 10 but is 0
|
||||
<<<'MANAGED_SERVER:vm1400.config.monit_max_cpu_usage' is expected to be at most 100 but is 101,
|
||||
<<<'MANAGED_SERVER:vm1400.config.monit_max_ssd_usage' is expected to be at least 10 but is 0
|
||||
<<<]"
|
||||
}
|
||||
""".replaceAll(" +<<<", ""))); // @formatter:on
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
void totalsLimitValidationsArePerformend_whenAddingAsset() {
|
||||
|
||||
@@ -311,7 +313,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
|
||||
jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
for (int n = 0; n < 25; ++n ) {
|
||||
for (int n = 0; n < 25; ++n) {
|
||||
toCleanup(assetRepo.save(
|
||||
HsHostingAssetEntity.builder()
|
||||
.type(UNIX_USER)
|
||||
@@ -358,8 +360,8 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
void globalAdmin_canGetArbitraryAsset() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenAssetUuid = assetRepo.findByIdentifier("vm1011").stream()
|
||||
.filter(bi -> bi.getBookingItem().getProject().getCaption().equals("D-1000111 default project"))
|
||||
.findAny().orElseThrow().getUuid();
|
||||
.filter(bi -> bi.getBookingItem().getProject().getCaption().equals("D-1000111 default project"))
|
||||
.findAny().orElseThrow().getUuid();
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
@@ -429,8 +431,23 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
@Test
|
||||
void globalAdmin_canPatchAllUpdatablePropertiesOfAsset() {
|
||||
|
||||
final var givenAsset = givenSomeTemporaryHostingAsset("2001", MANAGED_SERVER,
|
||||
config("monit_max_ssd_usage", 80), config("monit_max_hdd_usage", 90), config("monit_max_cpu_usage", 90), config("monit_max_ram_usage", 70));
|
||||
final var givenAsset = givenSomeTemporaryHostingAsset(() ->
|
||||
HsHostingAssetEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.bookingItem(givenSomeNewBookingItem(
|
||||
"D-1000111 default project",
|
||||
HsBookingItemType.MANAGED_SERVER,
|
||||
"temp ManagedServer"))
|
||||
.type(MANAGED_SERVER)
|
||||
.identifier("vm2001")
|
||||
.caption("some test-asset")
|
||||
.config(Map.ofEntries(
|
||||
Map.<String, Object>entry("monit_max_ssd_usage", 80),
|
||||
Map.<String, Object>entry("monit_max_hdd_usage", 90),
|
||||
Map.<String, Object>entry("monit_max_cpu_usage", 90),
|
||||
Map.<String, Object>entry("monit_max_ram_usage", 70)
|
||||
))
|
||||
.build());
|
||||
final var alarmContactUuid = givenContact().getUuid();
|
||||
|
||||
RestAssured // @formatter:off
|
||||
@@ -459,9 +476,10 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"identifier": "vm2001",
|
||||
"caption": "some test-asset",
|
||||
"alarmContact": {
|
||||
"uuid": "%s",
|
||||
"caption": "second contact",
|
||||
"emailAddresses": { "main": "contact-admin@secondcontact.example.com" }
|
||||
"emailAddresses": {
|
||||
"main": "contact-admin@secondcontact.example.com"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"monit_max_cpu_usage": 90,
|
||||
@@ -470,27 +488,101 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
"monit_min_free_ssd": 5
|
||||
}
|
||||
}
|
||||
""".formatted(alarmContactUuid)));
|
||||
"""));
|
||||
// @formatter:on
|
||||
|
||||
// finally, the asset is actually updated
|
||||
em.clear();
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
assertThat(assetRepo.findByUuid(givenAsset.getUuid())).isPresent().get()
|
||||
.matches(asset -> {
|
||||
assertThat(asset.getAlarmContact().toString()).isEqualTo(
|
||||
"contact(caption='second contact', emailAddresses='{ main: contact-admin@secondcontact.example.com }')");
|
||||
assertThat(asset.getConfig().toString()).isEqualTo(
|
||||
"{ monit_max_cpu_usage: 90, monit_max_ram_usage: 70, monit_max_ssd_usage: 85, monit_min_free_ssd: 5 }");
|
||||
assertThat(asset.getAlarmContact()).isNotNull()
|
||||
.extracting(c -> c.getEmailAddresses().get("main"))
|
||||
.isEqualTo("contact-admin@secondcontact.example.com");
|
||||
assertThat(asset.getConfig().toString())
|
||||
.isEqualToIgnoringWhitespace("""
|
||||
{
|
||||
"monit_max_cpu_usage": 90,
|
||||
"monit_max_ram_usage": 70,
|
||||
"monit_max_ssd_usage": 85,
|
||||
"monit_min_free_ssd": 5
|
||||
}
|
||||
""");
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private HsOfficeContactEntity givenContact() {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
return contactRepo.findContactByOptionalCaptionLike("second").stream().findFirst().orElseThrow();
|
||||
}).returnedValue();
|
||||
@Test
|
||||
void assetAdmin_canPatchAllUpdatablePropertiesOfAsset() {
|
||||
|
||||
final var givenAsset = givenSomeTemporaryHostingAsset(() ->
|
||||
HsHostingAssetEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.type(UNIX_USER)
|
||||
.parentAsset(givenHostingAsset(MANAGED_WEBSPACE, "fir01"))
|
||||
.identifier("fir01-temp")
|
||||
.caption("some test-unix-user")
|
||||
.build());
|
||||
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
.header("current-user", "superuser-alex@hostsharing.net")
|
||||
//.header("assumed-roles", "hs_hosting_asset#vm2001:ADMIN")
|
||||
.contentType(ContentType.JSON)
|
||||
.body("""
|
||||
{
|
||||
"caption": "some patched test-unix-user",
|
||||
"config": {
|
||||
"shell": "/bin/bash",
|
||||
"totpKey": "0x1234567890abcdef0123456789abcdef",
|
||||
"password": "Ein Passwort mit 4 Zeichengruppen!"
|
||||
}
|
||||
}
|
||||
""")
|
||||
.port(port)
|
||||
.when()
|
||||
.patch("http://localhost/api/hs/hosting/assets/" + givenAsset.getUuid())
|
||||
.then().log().all().assertThat()
|
||||
.statusCode(200)
|
||||
.contentType(ContentType.JSON)
|
||||
.body("", lenientlyEquals("""
|
||||
{
|
||||
"type": "UNIX_USER",
|
||||
"identifier": "fir01-temp",
|
||||
"caption": "some patched test-unix-user",
|
||||
"config": {
|
||||
"homedir": "/home/pacs/fir01/users/temp",
|
||||
"shell": "/bin/bash"
|
||||
}
|
||||
}
|
||||
"""))
|
||||
// the config separately but not-leniently to make sure that no write-only-properties are listed
|
||||
.body("config", strictlyEquals("""
|
||||
{
|
||||
"homedir": "/home/pacs/fir01/users/temp",
|
||||
"shell": "/bin/bash"
|
||||
}
|
||||
"""))
|
||||
;
|
||||
// @formatter:on
|
||||
|
||||
// finally, the asset is actually updated
|
||||
assertThat(jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
return assetRepo.findByUuid(givenAsset.getUuid());
|
||||
}).returnedValue()).isPresent().get()
|
||||
.matches(asset -> {
|
||||
assertThat(asset.getCaption()).isEqualTo("some patched test-unix-user");
|
||||
assertThat(asset.getConfig().toString()).isEqualTo("""
|
||||
{
|
||||
"password": "Ein Passwort mit 4 Zeichengruppen!",
|
||||
"shell": "/bin/bash",
|
||||
"totpKey": "0x1234567890abcdef0123456789abcdef"
|
||||
}
|
||||
""");
|
||||
return true;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@@ -500,9 +592,23 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
@Test
|
||||
void globalAdmin_canDeleteArbitraryAsset() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenAsset = givenSomeTemporaryHostingAsset("1002", MANAGED_SERVER,
|
||||
config("monit_max_ssd_usage", 80), config("monit_max_hdd_usage", 90), config("monit_max_cpu_usage", 90), config("monit_max_ram_usage", 70));
|
||||
|
||||
final var givenAsset = givenSomeTemporaryHostingAsset(() ->
|
||||
HsHostingAssetEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.bookingItem(givenSomeNewBookingItem(
|
||||
"D-1000111 default project",
|
||||
HsBookingItemType.MANAGED_SERVER,
|
||||
"temp ManagedServer"))
|
||||
.type(MANAGED_SERVER)
|
||||
.identifier("vm1002")
|
||||
.caption("some test-asset")
|
||||
.config(Map.ofEntries(
|
||||
Map.<String, Object>entry("monit_max_ssd_usage", 80),
|
||||
Map.<String, Object>entry("monit_max_hdd_usage", 90),
|
||||
Map.<String, Object>entry("monit_max_cpu_usage", 90),
|
||||
Map.<String, Object>entry("monit_max_ram_usage", 70)
|
||||
))
|
||||
.build());
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
.header("current-user", "superuser-alex@hostsharing.net")
|
||||
@@ -519,9 +625,23 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
@Test
|
||||
void normalUser_canNotDeleteUnrelatedAsset() {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var givenAsset = givenSomeTemporaryHostingAsset("1003", MANAGED_SERVER,
|
||||
config("monit_max_ssd_usage", 80), config("monit_max_hdd_usage", 90), config("monit_max_cpu_usage", 90), config("monit_max_ram_usage", 70));
|
||||
|
||||
final var givenAsset = givenSomeTemporaryHostingAsset(() ->
|
||||
HsHostingAssetEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.bookingItem(givenSomeNewBookingItem(
|
||||
"D-1000111 default project",
|
||||
HsBookingItemType.MANAGED_SERVER,
|
||||
"temp ManagedServer"))
|
||||
.type(MANAGED_SERVER)
|
||||
.identifier("vm1003")
|
||||
.caption("some test-asset")
|
||||
.config(Map.ofEntries(
|
||||
Map.<String, Object>entry("monit_max_ssd_usage", 80),
|
||||
Map.<String, Object>entry("monit_max_hdd_usage", 90),
|
||||
Map.<String, Object>entry("monit_max_cpu_usage", 90),
|
||||
Map.<String, Object>entry("monit_max_ram_usage", 70)
|
||||
))
|
||||
.build());
|
||||
RestAssured // @formatter:off
|
||||
.given()
|
||||
.header("current-user", "selfregistered-user-drew@hostsharing.org")
|
||||
@@ -538,7 +658,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
|
||||
HsHostingAssetEntity givenHostingAsset(final HsHostingAssetType type, final String identifier) {
|
||||
return assetRepo.findByIdentifier(identifier).stream()
|
||||
.filter(ha -> ha.getType()==type)
|
||||
.filter(ha -> ha.getType() == type)
|
||||
.findAny().orElseThrow();
|
||||
}
|
||||
|
||||
@@ -559,12 +679,18 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
}).assertSuccessful().returnedValue();
|
||||
}
|
||||
|
||||
HsBookingItemEntity givenSomeNewBookingItem(final String projectCaption, final HsBookingItemType bookingItemType, final String bookingItemCaption) {
|
||||
HsBookingItemEntity givenSomeNewBookingItem(
|
||||
final String projectCaption,
|
||||
final HsBookingItemType bookingItemType,
|
||||
final String bookingItemCaption) {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var project = projectRepo.findByCaption(projectCaption).getFirst();
|
||||
final var resources = switch (bookingItemType) {
|
||||
case MANAGED_SERVER -> Map.<String, Object>ofEntries(entry("CPUs", 1), entry("RAM", 20), entry("SSD", 25), entry("Traffic", 250));
|
||||
case MANAGED_SERVER -> Map.<String, Object>ofEntries(entry("CPUs", 1),
|
||||
entry("RAM", 20),
|
||||
entry("SSD", 25),
|
||||
entry("Traffic", 250));
|
||||
default -> new HashMap<String, Object>();
|
||||
};
|
||||
final var newBookingItem = HsBookingItemEntity.builder()
|
||||
@@ -584,33 +710,18 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
||||
return givenAsset;
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private HsHostingAssetEntity givenSomeTemporaryHostingAsset(final String identifierSuffix,
|
||||
final HsHostingAssetType hostingAssetType,
|
||||
final Map.Entry<String, Object>... config) {
|
||||
private HsHostingAssetEntity givenSomeTemporaryHostingAsset(final Supplier<HsHostingAssetEntity> newAsset) {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
final var bookingItemType = switch (hostingAssetType) {
|
||||
case CLOUD_SERVER -> HsBookingItemType.CLOUD_SERVER;
|
||||
case MANAGED_SERVER -> HsBookingItemType.MANAGED_SERVER;
|
||||
case MANAGED_WEBSPACE -> HsBookingItemType.MANAGED_WEBSPACE;
|
||||
default -> null;
|
||||
};
|
||||
final var newBookingItem = givenSomeNewBookingItem("D-1000111 default project", bookingItemType, "temp ManagedServer");
|
||||
final var newAsset = HsHostingAssetEntity.builder()
|
||||
.uuid(UUID.randomUUID())
|
||||
.bookingItem(newBookingItem)
|
||||
.type(hostingAssetType)
|
||||
.identifier("vm" + identifierSuffix)
|
||||
.caption("some test-asset")
|
||||
.config(Map.ofEntries(config))
|
||||
.build();
|
||||
|
||||
return assetRepo.save(newAsset);
|
||||
return toCleanup(assetRepo.save(newAsset.get()));
|
||||
}).assertSuccessful().returnedValue();
|
||||
}
|
||||
|
||||
private Map.Entry<String, Object> config(final String key, final Object value) {
|
||||
return entry(key, value);
|
||||
private HsOfficeContactEntity givenContact() {
|
||||
return jpaAttempt.transacted(() -> {
|
||||
context.define("superuser-alex@hostsharing.net");
|
||||
return contactRepo.findContactByOptionalCaptionLike("second").stream().findFirst().orElseThrow();
|
||||
}).returnedValue();
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -57,14 +57,14 @@ class HsHostingAssetEntityUnitTest {
|
||||
@Test
|
||||
void toStringContainsAllPropertiesAndResourcesSortedByKey() {
|
||||
|
||||
assertThat(givenWebspace.toString()).isEqualTo(
|
||||
"HsHostingAssetEntity(MANAGED_WEBSPACE, xyz00, some managed webspace, MANAGED_SERVER:vm1234, D-1234500:test project:test cloud server booking item, { CPUs: 2, HDD-storage: 2048, SSD-storage: 512 })");
|
||||
assertThat(givenWebspace.toString()).isEqualToIgnoringWhitespace(
|
||||
"HsHostingAssetEntity(MANAGED_WEBSPACE, xyz00, some managed webspace, MANAGED_SERVER:vm1234, D-1234500:test project:test cloud server booking item, { \"CPUs\": 2, \"HDD-storage\": 2048, \"SSD-storage\": 512 })");
|
||||
|
||||
assertThat(givenUnixUser.toString()).isEqualTo(
|
||||
"HsHostingAssetEntity(UNIX_USER, xyz00-web, some unix-user, MANAGED_WEBSPACE:xyz00, { HDD-hard-quota: 512, HDD-soft-quota: 256, SSD-hard-quota: 256, SSD-soft-quota: 128 })");
|
||||
assertThat(givenUnixUser.toString()).isEqualToIgnoringWhitespace(
|
||||
"HsHostingAssetEntity(UNIX_USER, xyz00-web, some unix-user, MANAGED_WEBSPACE:xyz00, { \"HDD-hard-quota\": 512, \"HDD-soft-quota\": 256, \"SSD-hard-quota\": 256, \"SSD-soft-quota\": 128 })");
|
||||
|
||||
assertThat(givenDomainHttpSetup.toString()).isEqualTo(
|
||||
"HsHostingAssetEntity(DOMAIN_HTTP_SETUP, example.org, some domain setup, MANAGED_WEBSPACE:xyz00, UNIX_USER:xyz00-web, { option-htdocsfallback: true, use-fcgiphpbin: /usr/lib/cgi-bin/php, validsubdomainnames: * })");
|
||||
assertThat(givenDomainHttpSetup.toString()).isEqualToIgnoringWhitespace(
|
||||
"HsHostingAssetEntity(DOMAIN_HTTP_SETUP, example.org, some domain setup, MANAGED_WEBSPACE:xyz00, UNIX_USER:xyz00-web, { \"option-htdocsfallback\": true, \"use-fcgiphpbin\": \"/usr/lib/cgi-bin/php\", \"validsubdomainnames\": \"*\" })");
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@@ -59,9 +59,7 @@ class HsHostingAssetPropsControllerAcceptanceTest {
|
||||
"unit": "%",
|
||||
"min": 10,
|
||||
"max": 100,
|
||||
"required": false,
|
||||
"defaultValue": 92,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": 92
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
@@ -69,9 +67,7 @@ class HsHostingAssetPropsControllerAcceptanceTest {
|
||||
"unit": "%",
|
||||
"min": 10,
|
||||
"max": 100,
|
||||
"required": false,
|
||||
"defaultValue": 92,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": 92
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
@@ -79,18 +75,14 @@ class HsHostingAssetPropsControllerAcceptanceTest {
|
||||
"unit": "%",
|
||||
"min": 10,
|
||||
"max": 100,
|
||||
"required": false,
|
||||
"defaultValue": 98,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": 98
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"propertyName": "monit_min_free_ssd",
|
||||
"min": 1,
|
||||
"max": 1000,
|
||||
"required": false,
|
||||
"defaultValue": 5,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": 5
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
@@ -98,32 +90,24 @@ class HsHostingAssetPropsControllerAcceptanceTest {
|
||||
"unit": "%",
|
||||
"min": 10,
|
||||
"max": 100,
|
||||
"required": false,
|
||||
"defaultValue": 95,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": 95
|
||||
},
|
||||
{
|
||||
"type": "integer",
|
||||
"propertyName": "monit_min_free_hdd",
|
||||
"min": 1,
|
||||
"max": 4000,
|
||||
"required": false,
|
||||
"defaultValue": 10,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": 10
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-pgsql",
|
||||
"required": false,
|
||||
"defaultValue": true,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-mariadb",
|
||||
"required": false,
|
||||
"defaultValue": true,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"type": "enumeration",
|
||||
@@ -139,114 +123,70 @@ class HsHostingAssetPropsControllerAcceptanceTest {
|
||||
"8.1",
|
||||
"8.2"
|
||||
],
|
||||
"required": false,
|
||||
"defaultValue": "8.2",
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": "8.2"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-php-5.6",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-php-5.6"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-php-7.0",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-php-7.0"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-php-7.1",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-php-7.1"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-php-7.2",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-php-7.2"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-php-7.3",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-php-7.3"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-php-7.4",
|
||||
"required": false,
|
||||
"defaultValue": true,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-php-8.0",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-php-8.0"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-php-8.1",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-php-8.1"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-php-8.2",
|
||||
"required": false,
|
||||
"defaultValue": true,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-postfix-tls-1.0",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-postfix-tls-1.0"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-dovecot-tls-1.0",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-dovecot-tls-1.0"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-clamav",
|
||||
"required": false,
|
||||
"defaultValue": true,
|
||||
"isTotalsValidator": false
|
||||
"defaultValue": true
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-collabora",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-collabora"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-libreoffice",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-libreoffice"
|
||||
},
|
||||
{
|
||||
"type": "boolean",
|
||||
"propertyName": "software-imagemagick-ghostscript",
|
||||
"required": false,
|
||||
"defaultValue": false,
|
||||
"isTotalsValidator": false
|
||||
"propertyName": "software-imagemagick-ghostscript"
|
||||
}
|
||||
]
|
||||
"""));
|
||||
|
@@ -195,7 +195,7 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
||||
exactlyTheseAssetsAreReturned(
|
||||
result,
|
||||
"HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedWebspace)",
|
||||
"HsHostingAssetEntity(MANAGED_SERVER, vm1011, some ManagedServer, D-1000111:D-1000111 default project:separate ManagedServer, { monit_max_cpu_usage: 90, monit_max_ram_usage: 80, monit_max_ssd_usage: 70 })");
|
||||
"HsHostingAssetEntity(MANAGED_SERVER, vm1011, some ManagedServer, D-1000111:D-1000111 default project:separate ManagedServer, { monit_max_cpu_usage: 90, monit_max_ram_usage: 80, monit_max_ssd_usage: 70 } )");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -407,6 +407,8 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
|
||||
final String... serverNames) {
|
||||
assertThat(actualResult)
|
||||
.extracting(HsHostingAssetEntity::toString)
|
||||
.extracting(input -> input.replaceAll("\\s+", " "))
|
||||
.extracting(input -> input.replaceAll("\"", ""))
|
||||
.containsExactlyInAnyOrder(serverNames);
|
||||
}
|
||||
|
||||
|
@@ -37,8 +37,8 @@ class HsManagedServerHostingAssetValidatorUnitTest {
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'MANAGED_SERVER:vm1234.parentAsset' must be null but is set to D-???????-?:null",
|
||||
"'MANAGED_SERVER:vm1234.assignedToAsset' must be null but is set to D-???????-?:null",
|
||||
"'MANAGED_SERVER:vm1234.config.monit_max_cpu_usage' is expected to be >= 10 but is 2",
|
||||
"'MANAGED_SERVER:vm1234.config.monit_max_ram_usage' is expected to be <= 100 but is 101",
|
||||
"'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_hdd_usage' is expected to be of type class java.lang.Integer, but is of type 'String'");
|
||||
}
|
||||
|
||||
|
@@ -1,14 +1,95 @@
|
||||
package net.hostsharing.hsadminng.hs.hosting.asset.validators;
|
||||
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
|
||||
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.TEST_MANAGED_SERVER_BOOKING_ITEM;
|
||||
import static net.hostsharing.hsadminng.hs.booking.item.TestHsBookingItem.TEST_MANAGED_WEBSPACE_BOOKING_ITEM;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_WEBSPACE;
|
||||
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.UNIX_USER;
|
||||
import static net.hostsharing.hsadminng.mapper.PatchMap.entry;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class HsUnixUserHostingAssetValidatorUnitTest {
|
||||
|
||||
private final HsHostingAssetEntity TEST_MANAGED_SERVER_HOSTING_ASSET = HsHostingAssetEntity.builder()
|
||||
.type(HsHostingAssetType.MANAGED_SERVER)
|
||||
.identifier("vm1234")
|
||||
.caption("some managed server")
|
||||
.bookingItem(TEST_MANAGED_SERVER_BOOKING_ITEM)
|
||||
.build();
|
||||
private HsHostingAssetEntity TEST_MANAGED_WEBSPACE_HOSTING_ASSET = HsHostingAssetEntity.builder()
|
||||
.type(MANAGED_WEBSPACE)
|
||||
.bookingItem(TEST_MANAGED_WEBSPACE_BOOKING_ITEM)
|
||||
.parentAsset(TEST_MANAGED_SERVER_HOSTING_ASSET)
|
||||
.identifier("abc00")
|
||||
.build();;
|
||||
|
||||
@Test
|
||||
void validatesValidUnixUser() {
|
||||
// given
|
||||
final var unixUserHostingAsset = HsHostingAssetEntity.builder()
|
||||
.type(UNIX_USER)
|
||||
.parentAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
|
||||
.identifier("abc00-temp")
|
||||
.caption("some valid test UnixUser")
|
||||
.config(Map.ofEntries(
|
||||
entry("SSD hard quota", 50),
|
||||
entry("SSD soft quota", 40),
|
||||
entry("totpKey", "0x123456789abcdef01234"),
|
||||
entry("password", "Hallo Computer, lass mich rein!")
|
||||
))
|
||||
.build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validate(unixUserHostingAsset);
|
||||
|
||||
// then
|
||||
assertThat(result).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatesUnixUserProperties() {
|
||||
// given
|
||||
final var unixUserHostingAsset = HsHostingAssetEntity.builder()
|
||||
.type(UNIX_USER)
|
||||
.parentAsset(TEST_MANAGED_WEBSPACE_HOSTING_ASSET)
|
||||
.identifier("abc00-temp")
|
||||
.caption("some test UnixUser with invalid properties")
|
||||
.config(Map.ofEntries(
|
||||
entry("SSD hard quota", 100),
|
||||
entry("SSD soft quota", 200),
|
||||
entry("HDD hard quota", 100),
|
||||
entry("HDD soft quota", 200),
|
||||
entry("shell", "/is/invalid"),
|
||||
entry("homedir", "/is/read-only"),
|
||||
entry("totpKey", "should be a hex number"),
|
||||
entry("password", "short")
|
||||
))
|
||||
.build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType());
|
||||
|
||||
// when
|
||||
final var result = validator.validate(unixUserHostingAsset);
|
||||
|
||||
// then
|
||||
assertThat(result).containsExactlyInAnyOrder(
|
||||
"'UNIX_USER:abc00-temp.config.SSD hard quota' is expected to be at most 50 but is 100",
|
||||
"'UNIX_USER:abc00-temp.config.SSD soft quota' is expected to be at most 100 but is 200",
|
||||
"'UNIX_USER:abc00-temp.config.HDD hard quota' is expected to be at most 0 but is 100",
|
||||
"'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.homedir' is readonly but given as '/is/read-only'",
|
||||
"'UNIX_USER:abc00-temp.config.totpKey' is expected to be match ^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' must contain at least one character of at least 3 of the following groups: upper case letters, lower case letters, digits, special characters"
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
void validatesInvalidIdentifier() {
|
||||
// given
|
||||
@@ -19,7 +100,6 @@ class HsUnixUserHostingAssetValidatorUnitTest {
|
||||
.build();
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(unixUserHostingAsset.getType());
|
||||
|
||||
|
||||
// when
|
||||
final var result = validator.validate(unixUserHostingAsset);
|
||||
|
||||
@@ -27,4 +107,25 @@ class HsUnixUserHostingAssetValidatorUnitTest {
|
||||
assertThat(result).containsExactly(
|
||||
"'identifier' expected to match '^abc00$|^abc00-[a-z0-9]+$', but is 'xyz99-temp'");
|
||||
}
|
||||
|
||||
@Test
|
||||
void describesItsProperties() {
|
||||
// given
|
||||
final var validator = HsHostingAssetEntityValidatorRegistry.forType(UNIX_USER);
|
||||
|
||||
// when
|
||||
final var props = validator.properties();
|
||||
|
||||
// then
|
||||
assertThat(props).extracting(Object::toString).containsExactlyInAnyOrder(
|
||||
"{type=integer, propertyName=SSD hard quota, unit=GB, maxFrom=SSD}",
|
||||
"{type=integer, propertyName=SSD soft quota, unit=GB, maxFrom=SSD hard quota}",
|
||||
"{type=integer, propertyName=HDD hard quota, unit=GB, maxFrom=HDD}",
|
||||
"{type=integer, propertyName=HDD soft quota, unit=GB, maxFrom=HDD hard quota}",
|
||||
"{type=enumeration, propertyName=shell, values=[/bin/false, /bin/bash, /bin/csh, /bin/dash, /usr/bin/tcsh, /usr/bin/zsh, /usr/bin/passwd], defaultValue=/bin/false}",
|
||||
"{type=string, propertyName=homedir, readOnly=true, computed=true}",
|
||||
"{type=string, propertyName=totpKey, matchesRegEx=^0x([0-9A-Fa-f]{2})+$, minLength=20, maxLength=256, writeOnly=true, undisclosed=true}",
|
||||
"{type=password, propertyName=password, minLength=8, maxLength=40, writeOnly=true, undisclosed=true}"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,92 @@
|
||||
package net.hostsharing.hsadminng.hs.validation;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.hostsharing.hsadminng.hs.validation.PasswordProperty.passwordProperty;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
class PasswordPropertyUnitTest {
|
||||
|
||||
private final ValidatableProperty<String> passwordProp = passwordProperty("password").minLength(8).maxLength(40).writeOnly();
|
||||
private final List<String> violations = new ArrayList<>();
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"lowerUpperAndDigit1",
|
||||
"lowerUpperAndSpecial!",
|
||||
"digit1LowerAndSpecial!",
|
||||
"digit1special!lower",
|
||||
"DIGIT1SPECIAL!UPPER" })
|
||||
void shouldValidateValidPassword(final String password) {
|
||||
// when
|
||||
passwordProp.validate(violations, password, null);
|
||||
|
||||
// then
|
||||
assertThat(violations).isEmpty();
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {
|
||||
"noDigitNoSpecial",
|
||||
"!!!!!!12345",
|
||||
"nolower-nodigit",
|
||||
"nolower1nospecial",
|
||||
"NOLOWER-NODIGIT",
|
||||
"NOLOWER1NOSPECIAL"
|
||||
})
|
||||
void shouldRecognizeMissingCharacterGroup(final String givenPassword) {
|
||||
// when
|
||||
passwordProp.validate(violations, givenPassword, null);
|
||||
|
||||
// then
|
||||
assertThat(violations)
|
||||
.contains("password' must contain at least one character of at least 3 of the following groups: upper case letters, lower case letters, digits, special characters")
|
||||
.doesNotContain(givenPassword);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRecognizeTooShortPassword() {
|
||||
// given
|
||||
final String givenPassword = "0123456";
|
||||
|
||||
// when
|
||||
passwordProp.validate(violations, givenPassword, null);
|
||||
|
||||
// then
|
||||
assertThat(violations)
|
||||
.contains("password' length is expected to be at min 8 but length of provided value is 7")
|
||||
.doesNotContain(givenPassword);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRecognizeTooLongPassowrd() {
|
||||
// given
|
||||
final String givenPassword = "password' length is expected to be at max 40 but is 41";
|
||||
|
||||
// when
|
||||
passwordProp.validate(violations, givenPassword, null);
|
||||
|
||||
// then
|
||||
assertThat(violations).contains("password' length is expected to be at max 40 but length of provided value is 54")
|
||||
.doesNotContain(givenPassword);
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldRecognizeColonInPassword() {
|
||||
// given
|
||||
final String givenPassword = "lowerUpper:1234";
|
||||
|
||||
// when
|
||||
passwordProp.validate(violations, givenPassword, null);
|
||||
|
||||
// then
|
||||
assertThat(violations)
|
||||
.contains("password' must not contain colon (':')")
|
||||
.doesNotContain(givenPassword);
|
||||
}
|
||||
}
|
@@ -9,13 +9,15 @@ import org.json.JSONException;
|
||||
import org.skyscreamer.jsonassert.JSONAssert;
|
||||
import org.skyscreamer.jsonassert.JSONCompareMode;
|
||||
|
||||
import static com.fasterxml.jackson.databind.SerializationFeature.INDENT_OUTPUT;
|
||||
|
||||
public class JsonMatcher extends BaseMatcher<CharSequence> {
|
||||
|
||||
private final String expected;
|
||||
private final String expectedJson;
|
||||
private JSONCompareMode compareMode;
|
||||
|
||||
public JsonMatcher(final String expected, final JSONCompareMode compareMode) {
|
||||
this.expected = expected;
|
||||
public JsonMatcher(final String expectedJson, final JSONCompareMode compareMode) {
|
||||
this.expectedJson = expectedJson;
|
||||
this.compareMode = compareMode;
|
||||
}
|
||||
|
||||
@@ -47,8 +49,8 @@ public class JsonMatcher extends BaseMatcher<CharSequence> {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
final var actualJson = new ObjectMapper().writeValueAsString(actual);
|
||||
JSONAssert.assertEquals(expected, actualJson, compareMode);
|
||||
final var actualJson = new ObjectMapper().enable(INDENT_OUTPUT).writeValueAsString(actual);
|
||||
JSONAssert.assertEquals(expectedJson, actualJson, compareMode);
|
||||
return true;
|
||||
} catch (final JSONException | JsonProcessingException e) {
|
||||
throw new AssertionError(e);
|
||||
@@ -59,5 +61,4 @@ public class JsonMatcher extends BaseMatcher<CharSequence> {
|
||||
public void describeTo(final Description description) {
|
||||
description.appendText("leniently matches JSON");
|
||||
}
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user