From 0045c62a277e86d331fc20b8c1a687b37bd0e121 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Wed, 12 Jun 2024 15:59:43 +0200 Subject: [PATCH] improved exception handling and fixing test data for validations --- .../hsadminng/errors/CustomErrorResponse.java | 2 +- .../RestResponseEntityExceptionHandler.java | 4 +- .../booking/item/HsBookingItemController.java | 12 ++++-- .../hs/booking/item/HsBookingItemEntity.java | 3 ++ .../HsBookingItemEntityValidator.java | 9 ++-- .../asset/HsHostingAssetController.java | 6 +-- .../HsHostingAssetEntityValidator.java | 10 ++--- ...OfficeCoopAssetsTransactionController.java | 2 +- ...OfficeCoopSharesTransactionController.java | 2 +- .../validation/MultiValidationException.java | 19 +++++++++ .../6208-hs-booking-item-test-data.sql | 14 +++---- .../7018-hs-hosting-asset-test-data.sql | 6 +-- ...HsBookingItemControllerAcceptanceTest.java | 26 ++++++------ .../HsBookingItemEntityPatcherUnitTest.java | 4 +- ...sBookingItemRepositoryIntegrationTest.java | 12 +++--- .../HsBookingItemEntityValidatorUnitTest.java | 4 +- ...gedServerBookingItemValidatorUnitTest.java | 35 +++++++++++++--- ...dWebspaceBookingItemValidatorUnitTest.java | 12 +++--- ...sHostingAssetControllerAcceptanceTest.java | 41 ++++++++++--------- .../HsHostingAssetEntityPatcherUnitTest.java | 4 +- ...ingAssetPropsControllerAcceptanceTest.java | 26 ++++++------ ...HostingAssetRepositoryIntegrationTest.java | 14 +++---- ...HsHostingAssetEntityValidatorUnitTest.java | 4 +- 23 files changed, 160 insertions(+), 111 deletions(-) create mode 100644 src/main/java/net/hostsharing/hsadminng/hs/validation/MultiValidationException.java diff --git a/src/main/java/net/hostsharing/hsadminng/errors/CustomErrorResponse.java b/src/main/java/net/hostsharing/hsadminng/errors/CustomErrorResponse.java index 2714b817..9b182137 100644 --- a/src/main/java/net/hostsharing/hsadminng/errors/CustomErrorResponse.java +++ b/src/main/java/net/hostsharing/hsadminng/errors/CustomErrorResponse.java @@ -9,7 +9,7 @@ import org.springframework.web.context.request.WebRequest; import java.time.LocalDateTime; @Getter -class CustomErrorResponse { +public class CustomErrorResponse { static ResponseEntity errorResponse( final WebRequest request, diff --git a/src/main/java/net/hostsharing/hsadminng/errors/RestResponseEntityExceptionHandler.java b/src/main/java/net/hostsharing/hsadminng/errors/RestResponseEntityExceptionHandler.java index 5d675484..12f5aafe 100644 --- a/src/main/java/net/hostsharing/hsadminng/errors/RestResponseEntityExceptionHandler.java +++ b/src/main/java/net/hostsharing/hsadminng/errors/RestResponseEntityExceptionHandler.java @@ -1,5 +1,6 @@ package net.hostsharing.hsadminng.errors; +import net.hostsharing.hsadminng.hs.validation.MultiValidationException; import org.iban4j.Iban4jException; import org.springframework.core.NestedExceptionUtils; import org.springframework.dao.DataIntegrityViolationException; @@ -75,7 +76,8 @@ public class RestResponseEntityExceptionHandler @ExceptionHandler({ Iban4jException.class, ValidationException.class }) protected ResponseEntity handleIbanAndBicExceptions( final Throwable exc, final WebRequest request) { - final var message = line(NestedExceptionUtils.getMostSpecificCause(exc).getMessage(), 0); + final String fullMessage = NestedExceptionUtils.getMostSpecificCause(exc).getMessage(); + final var message = exc instanceof MultiValidationException ? fullMessage : line(fullMessage, 0); return errorResponse(request, HttpStatus.BAD_REQUEST, message); } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemController.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemController.java index 174ba076..6af3d73d 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemController.java @@ -13,11 +13,13 @@ import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; +import jakarta.persistence.EntityManager; +import jakarta.persistence.PersistenceContext; import java.util.List; import java.util.UUID; import java.util.function.BiConsumer; -import static net.hostsharing.hsadminng.hs.booking.item.validators.HsBookingItemEntityValidator.valid; +import static net.hostsharing.hsadminng.hs.booking.item.validators.HsBookingItemEntityValidator.validated; import static net.hostsharing.hsadminng.mapper.PostgresDateRange.toPostgresDateRange; @RestController @@ -32,6 +34,9 @@ public class HsBookingItemController implements HsBookingItemsApi { @Autowired private HsBookingItemRepository bookingItemRepo; + @PersistenceContext + private EntityManager em; + @Override @Transactional(readOnly = true) public ResponseEntity> listBookingItemsByProjectUuid( @@ -57,7 +62,7 @@ public class HsBookingItemController implements HsBookingItemsApi { final var entityToSave = mapper.map(body, HsBookingItemEntity.class, RESOURCE_TO_ENTITY_POSTMAPPER); - final var saved = bookingItemRepo.save(valid(entityToSave)); + final var saved = validated(bookingItemRepo.save(entityToSave)); final var uri = MvcUriComponentsBuilder.fromController(getClass()) @@ -78,6 +83,7 @@ public class HsBookingItemController implements HsBookingItemsApi { context.define(currentUser, assumedRoles); final var result = bookingItemRepo.findByUuid(bookingItemUuid); + result.ifPresent(entity -> em.detach(entity)); return result .map(bookingItemEntity -> ResponseEntity.ok( mapper.map(bookingItemEntity, HsBookingItemResource.class, ENTITY_TO_RESOURCE_POSTMAPPER))) @@ -112,7 +118,7 @@ public class HsBookingItemController implements HsBookingItemsApi { new HsBookingItemEntityPatcher(current).apply(body); - final var saved = bookingItemRepo.save(valid(current)); + final var saved = bookingItemRepo.save(validated(current)); final var mapped = mapper.map(saved, HsBookingItemResource.class, ENTITY_TO_RESOURCE_POSTMAPPER); return ResponseEntity.ok(mapped); } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntity.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntity.java index b820c243..cd812243 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntity.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntity.java @@ -88,6 +88,7 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject { @ManyToOne @JoinColumn(name = "parentitemuuid") +// @Transient private HsBookingItemEntity parentItem; @Column(name = "type") @@ -110,10 +111,12 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject { @OneToMany(cascade = CascadeType.REFRESH, orphanRemoval = true) @JoinColumn(name="parentitemuuid", referencedColumnName="uuid") +// @Transient private List subBookingItems; @OneToMany(cascade = CascadeType.REFRESH, orphanRemoval = true) @JoinColumn(name="bookingitemuuid", referencedColumnName="uuid") +// @Transient private List subHostingAssets; @Transient diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidator.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidator.java index a2067e9b..848be955 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidator.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidator.java @@ -3,9 +3,9 @@ package net.hostsharing.hsadminng.hs.booking.item.validators; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity; import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType; import net.hostsharing.hsadminng.hs.validation.HsEntityValidator; +import net.hostsharing.hsadminng.hs.validation.MultiValidationException; import net.hostsharing.hsadminng.hs.validation.ValidatableProperty; -import jakarta.validation.ValidationException; import java.util.Collection; import java.util.HashMap; import java.util.List; @@ -54,11 +54,8 @@ public class HsBookingItemEntityValidator extends HsEntityValidator 0) { - throw new ValidationException("[" + join(", ", violations) + "]"); + throw new ValidationException("[" + join(",\n", violations) + "]"); // FIXME: move the join into an exception subclass } } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java index 9a3295a2..382de113 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/office/coopshares/HsOfficeCoopSharesTransactionController.java @@ -100,7 +100,7 @@ public class HsOfficeCoopSharesTransactionController implements HsOfficeCoopShar validateCancellationTransaction(requestBody, violations); validateshareCount(requestBody, violations); if (violations.size() > 0) { - throw new ValidationException("[" + join(", ", violations) + "]"); + throw new ValidationException("[" + join(",\n", violations) + "]"); // FIXME: move the join into an exception subclass } } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/validation/MultiValidationException.java b/src/main/java/net/hostsharing/hsadminng/hs/validation/MultiValidationException.java new file mode 100644 index 00000000..5d52feb9 --- /dev/null +++ b/src/main/java/net/hostsharing/hsadminng/hs/validation/MultiValidationException.java @@ -0,0 +1,19 @@ +package net.hostsharing.hsadminng.hs.validation; + +import jakarta.validation.ValidationException; +import java.util.List; + +import static java.lang.String.join; + +public class MultiValidationException extends ValidationException { + + private MultiValidationException(final List violations) { + super("[\n" + join(",\n", violations) + "\n]"); + } + + public static void throwInvalid(final List violations) { + if (!violations.isEmpty()) { + throw new MultiValidationException(violations); + } + } +} diff --git a/src/main/resources/db/changelog/6-hs-booking/630-booking-item/6208-hs-booking-item-test-data.sql b/src/main/resources/db/changelog/6-hs-booking/630-booking-item/6208-hs-booking-item-test-data.sql index bc3a9e51..3a15936b 100644 --- a/src/main/resources/db/changelog/6-hs-booking/630-booking-item/6208-hs-booking-item-test-data.sql +++ b/src/main/resources/db/changelog/6-hs-booking/630-booking-item/6208-hs-booking-item-test-data.sql @@ -33,13 +33,13 @@ begin managedServerUuid := uuid_generate_v4(); insert into hs_booking_item (uuid, projectuuid, type, parentitemuuid, caption, validity, resources) - values (privateCloudUuid, relatedProject.uuid, 'PRIVATE_CLOUD', null, 'some PrivateCloud', daterange('20240401', null, '[]'), '{ "CPUs": 10, "SDD": 10240, "HDD": 10240, "Traffic": 42 }'::jsonb), - (uuid_generate_v4(), null, 'MANAGED_SERVER', privateCloudUuid, 'some ManagedServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "RAM": 4, "HDD": 1024, "Traffic": 42 }'::jsonb), - (uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'test CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "RAM": 4, "HDD": 1024, "Traffic": 42 }'::jsonb), - (uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'prod CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 4, "RAM": 16, "HDD": 2924, "Traffic": 420 }'::jsonb), - (managedServerUuid, relatedProject.uuid, 'MANAGED_SERVER', null, 'separate ManagedServer', daterange('20221001', null, '[]'), '{ "CPUs": 2, "RAM": 8, "SDD": 512, "Traffic": 42 }'::jsonb), - (uuid_generate_v4(), null, 'MANAGED_WEBSPACE', managedServerUuid, 'some ManagedWebspace', daterange('20221001', null, '[]'), '{ "SDD": 512, "Traffic": 12, "Daemons": 2, "Multi": 4 }'::jsonb), - (uuid_generate_v4(), relatedProject.uuid, 'MANAGED_WEBSPACE', null, 'some ManagedWebspace', daterange('20221001', null, '[]'), '{ "SDD": 512, "Traffic": 12, "Daemons": 2, "Multi": 4 }'::jsonb); + values (privateCloudUuid, relatedProject.uuid, 'PRIVATE_CLOUD', null, 'some PrivateCloud', daterange('20240401', null, '[]'), '{ "CPUs": 10, "RAM": 32, "SSD": 4000, "HDD": 10000, "Traffic": 2000 }'::jsonb), + (uuid_generate_v4(), null, 'MANAGED_SERVER', privateCloudUuid, 'some ManagedServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "RAM": 4, "SSD": 500, "Traffic": 500 }'::jsonb), + (uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'test CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "RAM": 4, "SSD": 750, "Traffic": 500 }'::jsonb), + (uuid_generate_v4(), null, 'CLOUD_SERVER', privateCloudUuid, 'prod CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 4, "RAM": 16, "SSD": 1000, "Traffic": 500 }'::jsonb), + (managedServerUuid, relatedProject.uuid, 'MANAGED_SERVER', null, 'separate ManagedServer', daterange('20221001', null, '[]'), '{ "CPUs": 2, "RAM": 8, "SSD": 512, "Traffic": 500 }'::jsonb), + (uuid_generate_v4(), null, 'MANAGED_WEBSPACE', managedServerUuid, 'some ManagedWebspace', daterange('20221001', null, '[]'), '{ "SSD": 512, "Traffic": 12, "Daemons": 2, "Multi": 4 }'::jsonb), + (uuid_generate_v4(), relatedProject.uuid, 'MANAGED_WEBSPACE', null, 'some ManagedWebspace', daterange('20221001', null, '[]'), '{ "SSD": 512, "Traffic": 12, "Daemons": 2, "Multi": 4 }'::jsonb); end; $$; --// diff --git a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7018-hs-hosting-asset-test-data.sql b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7018-hs-hosting-asset-test-data.sql index 964acdec..2a12011d 100644 --- a/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7018-hs-hosting-asset-test-data.sql +++ b/src/main/resources/db/changelog/7-hs-hosting/701-hosting-asset/7018-hs-hosting-asset-test-data.sql @@ -56,9 +56,9 @@ begin insert into hs_hosting_asset (uuid, bookingitemuuid, type, parentAssetUuid, assignedToAssetUuid, identifier, caption, config) - values (managedServerUuid, relatedPrivateCloudBookingItem.uuid, 'MANAGED_SERVER', null, null, 'vm10' || debitorNumberSuffix, 'some ManagedServer', '{ "extra": 42 }'::jsonb), - (uuid_generate_v4(), relatedPrivateCloudBookingItem.uuid, 'CLOUD_SERVER', null, null, 'vm20' || debitorNumberSuffix, 'another CloudServer', '{ "extra": 42 }'::jsonb), - (managedWebspaceUuid, relatedManagedServerBookingItem.uuid, 'MANAGED_WEBSPACE', managedServerUuid, null, defaultPrefix || '01', 'some Webspace', '{ "extra": 42 }'::jsonb), + values (managedServerUuid, relatedPrivateCloudBookingItem.uuid, 'MANAGED_SERVER', null, null, 'vm10' || debitorNumberSuffix, 'some ManagedServer', '{ "monit_max_cpu_usage": 90, "monit_max_ram_usage": 80, "monit_max_ssd_usage": 70 }'::jsonb), + (uuid_generate_v4(), relatedPrivateCloudBookingItem.uuid, 'CLOUD_SERVER', null, null, 'vm20' || debitorNumberSuffix, 'another CloudServer', '{}'::jsonb), + (managedWebspaceUuid, relatedManagedServerBookingItem.uuid, 'MANAGED_WEBSPACE', managedServerUuid, null, defaultPrefix || '01', 'some Webspace', '{}'::jsonb), (webUnixUserUuid, null, 'UNIX_USER', managedWebspaceUuid, null, defaultPrefix || '01-web', 'some UnixUser for Website', '{ "SSD-soft-quota": "128", "SSD-hard-quota": "256", "HDD-soft-quota": "512", "HDD-hard-quota": "1024", "extra": 42 }'::jsonb), (uuid_generate_v4(), null, 'DOMAIN_HTTP_SETUP', managedWebspaceUuid, webUnixUserUuid, defaultPrefix || '.example.org', 'some Domain-HTTP-Setup', '{ "option-htdocsfallback": true, "use-fcgiphpbin": "/usr/lib/cgi-bin/php", "validsubdomainnames": "*", "extra": 42 }'::jsonb); end; $$; diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemControllerAcceptanceTest.java index a0054b4f..694175ba 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemControllerAcceptanceTest.java @@ -81,7 +81,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "validFrom": "2022-10-01", "validTo": null, "resources": { - "SDD": 512, + "SSD": 512, "Multi": 4, "Daemons": 2, "Traffic": 12 @@ -94,9 +94,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "validTo": null, "resources": { "RAM": 8, - "SDD": 512, + "SSD": 512, "CPUs": 2, - "Traffic": 42 + "Traffic": 500 } }, { @@ -105,10 +105,10 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "validFrom": "2024-04-01", "validTo": null, "resources": { - "HDD": 10240, - "SDD": 10240, + "SSD": 4000, + "HDD": 10000, "CPUs": 10, - "Traffic": 42 + "Traffic": 2000 } } ] @@ -195,7 +195,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "validFrom": "2022-10-01", "validTo": null, "resources": { - "SDD": 512, + "SSD": 512, "Multi": 4, "Daemons": 2, "Traffic": 12 @@ -227,14 +227,16 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup void projectAdmin_canGetRelatedBookingItem() { context.define("superuser-alex@hostsharing.net"); final var givenBookingItemUuid = bookingItemRepo.findByCaption("separate ManagedServer").stream() - .filter(bi -> belongsToDebitorWithDefaultPrefix(bi, "thi")) + .filter(bi -> belongsToDebitorWithDefaultPrefix(bi, "sec")) .map(HsBookingItemEntity::getUuid) .findAny().orElseThrow(); + generateRbacDiagramForObjectPermission(givenBookingItemUuid, "SELECT", "select"); + RestAssured // @formatter:off .given() .header("current-user", "superuser-alex@hostsharing.net") - .header("assumed-roles", "hs_booking_project#D-1000313-D-1000313defaultproject:ADMIN") + .header("assumed-roles", "hs_booking_project#D-1000212-D-1000212defaultproject:ADMIN") .port(port) .when() .get("http://localhost/api/hs/booking/items/" + givenBookingItemUuid) @@ -249,9 +251,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "validTo": null, "resources": { "RAM": 8, - "SDD": 512, + "SSD": 512, "CPUs": 2, - "Traffic": 42 + "Traffic": 500 } } """)); // @formatter:on @@ -261,7 +263,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup return ofNullable(bi) .map(HsBookingItemEntity::getProject) .map(HsBookingProjectEntity::getDebitor) - .map(bd -> bd.getDefaultPrefix().equals(defaultPrefix)) + .filter(bd -> bd.getDefaultPrefix().equals(defaultPrefix)) .isPresent(); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntityPatcherUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntityPatcherUnitTest.java index 7e312fbc..ca179fc3 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntityPatcherUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntityPatcherUnitTest.java @@ -44,11 +44,11 @@ class HsBookingItemEntityPatcherUnitTest extends PatchUnitTestBase< private static final Map PATCH_RESOURCES = patchMap( entry("CPU", 2), entry("HDD", null), - entry("SDD", 256) + entry("SSD", 256) ); private static final Map PATCHED_RESOURCES = patchMap( entry("CPU", 2), - entry("SDD", 256), + entry("SSD", 256), entry("MEM", 64) ); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemRepositoryIntegrationTest.java index f4114c9c..7c160969 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemRepositoryIntegrationTest.java @@ -174,9 +174,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup // then allTheseBookingItemsAreReturned( result, - "HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SDD: 512, Traffic: 12 })", - "HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SDD: 512, Traffic: 42 })", - "HsBookingItemEntity(D-1000212:D-1000212 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10240, SDD: 10240, Traffic: 42 })"); + "HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SSD: 512, Traffic: 12 })", + "HsBookingItemEntity(D-1000212:D-1000212 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 512, 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 })"); } @Test @@ -194,9 +194,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, SDD: 512, Traffic: 42 })", - "HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SDD: 512, Traffic: 12 })", - "HsBookingItemEntity(D-1000111:D-1000111 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10240, SDD: 10240, Traffic: 42 })"); + "HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_SERVER, [2022-10-01,), separate ManagedServer, { CPUs: 2, RAM: 8, SSD: 512, Traffic: 500 })", + "HsBookingItemEntity(D-1000111:D-1000111 default project, MANAGED_WEBSPACE, [2022-10-01,), some ManagedWebspace, { Daemons: 2, Multi: 4, SSD: 512, Traffic: 12 })", + "HsBookingItemEntity(D-1000111:D-1000111 default project, PRIVATE_CLOUD, [2024-04-01,), some PrivateCloud, { CPUs: 10, HDD: 10000, RAM: 32, SSD: 4000, Traffic: 2000 })"); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorUnitTest.java index d6d355ac..a25d6860 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsBookingItemEntityValidatorUnitTest.java @@ -11,7 +11,7 @@ import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.PRIVAT import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.CLOUD_SERVER; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_SERVER; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType.MANAGED_WEBSPACE; -import static net.hostsharing.hsadminng.hs.booking.item.validators.HsBookingItemEntityValidator.valid; +import static net.hostsharing.hsadminng.hs.booking.item.validators.HsBookingItemEntityValidator.validated; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; @@ -34,7 +34,7 @@ class HsBookingItemEntityValidatorUnitTest { .build(); // when - final var result = catchThrowable( ()-> valid(cloudServerBookingItemEntity) ); + final var result = catchThrowable( ()-> validated(cloudServerBookingItemEntity) ); // then assertThat(result).isInstanceOf(ValidationException.class) diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsManagedServerBookingItemValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsManagedServerBookingItemValidatorUnitTest.java index 415ef895..d5c694e8 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsManagedServerBookingItemValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsManagedServerBookingItemValidatorUnitTest.java @@ -147,13 +147,17 @@ class HsManagedServerBookingItemValidatorUnitTest { generate(26, HsHostingAssetType.UNIX_USER, "xyz00-%c%c"), generateDbUsersWithDatabases(3, HsHostingAssetType.PGSQL_USER, "xyz00_%c%c", - 1, HsHostingAssetType.PGSQL_DATABASE + 1, HsHostingAssetType.PGSQL_DATABASE ), generateDbUsersWithDatabases(3, HsHostingAssetType.MARIADB_USER, "xyz00_%c%c", - 1, HsHostingAssetType.MARIADB_DATABASE + 2, HsHostingAssetType.MARIADB_DATABASE + ), + generateDomainEmailSetupsWithEMailAddresses(26, HsHostingAssetType.DOMAIN_EMAIL_SETUP, + "%c%c.example.com", + 10, HsHostingAssetType.EMAIL_ADDRESS ) - )) + )) .build() )) .build(); @@ -165,7 +169,8 @@ class HsManagedServerBookingItemValidatorUnitTest { assertThat(result).containsExactlyInAnyOrder( "MultiOptions=1 allows at maximum 25 unix users, but 26 found", "MultiOptions=1 allows at maximum 5 database users, but 6 found", - "MultiOptions=1 allows at maximum 5 databases, but 6 found" + "MultiOptions=1 allows at maximum 5 databases, but 9 found", + "MultiOptions=1 allows at maximum 250 databases, but 260 found" ); } @@ -189,14 +194,32 @@ class HsManagedServerBookingItemValidatorUnitTest { private List generateDbUsersWithDatabases( final int userCount, final HsHostingAssetType directAssetType, - final String directAssetIdentifierFormat, final int dbCount, + final String directAssetIdentifierFormat, + final int dbCount, final HsHostingAssetType subAssetType) { return IntStream.range(0, userCount) .mapToObj(n -> HsHostingAssetEntity.builder() .type(directAssetType) .identifier(directAssetIdentifierFormat.formatted((n/'a')+'a', (n%'a')+'a')) .subHostingAssets( - generate(dbCount, subAssetType, "xyz00_%c%c%%c%%c".formatted((n/'a')+'a', (n%'a')+'a')) + generate(dbCount, subAssetType, "%c%c.example.com".formatted((n/'a')+'a', (n%'a')+'a')) + ) + .build()) + .toList(); + } + + private List generateDomainEmailSetupsWithEMailAddresses( + final int domainCount, + final HsHostingAssetType directAssetType, + final String directAssetIdentifierFormat, + final int emailAddressCount, + final HsHostingAssetType subAssetType) { + return IntStream.range(0, domainCount) + .mapToObj(n -> HsHostingAssetEntity.builder() + .type(directAssetType) + .identifier(directAssetIdentifierFormat.formatted((n/'a')+'a', (n%'a')+'a')) + .subHostingAssets( + generate(emailAddressCount, subAssetType, "xyz00_%c%c%%c%%c".formatted((n/'a')+'a', (n%'a')+'a')) ) .build()) .toList(); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsManagedWebspaceBookingItemValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsManagedWebspaceBookingItemValidatorUnitTest.java index d4c05d03..928b6ce6 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsManagedWebspaceBookingItemValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/booking/item/validators/HsManagedWebspaceBookingItemValidatorUnitTest.java @@ -31,7 +31,6 @@ class HsManagedWebspaceBookingItemValidatorUnitTest { .resources(Map.ofEntries( entry("CPUs", 2), entry("RAM", 25), - entry("SSD", 25), entry("Traffic", 250), entry("SLA-EMail", true) )) @@ -42,10 +41,11 @@ class HsManagedWebspaceBookingItemValidatorUnitTest { // then assertThat(result).containsExactlyInAnyOrder( - "D-12345:Test-Project:Test Managed-Webspace.resources.SLA-EMail is not expected but is set to 'true'", "D-12345:Test-Project:Test Managed-Webspace.resources.CPUs is not expected but is set to '2'", "D-12345:Test-Project:Test Managed-Webspace.resources.RAM is not expected but is set to '25'", - "D-12345:Test-Project:Test Managed-Webspace.resources.MultiOptions is required but missing"); + "D-12345:Test-Project:Test Managed-Webspace.resources.SSD is required but missing", + "D-12345:Test-Project:Test Managed-Webspace.resources.SLA-EMail is not expected but is set to 'true'" + ); } @Test @@ -58,9 +58,9 @@ class HsManagedWebspaceBookingItemValidatorUnitTest { "{type=integer, propertyName=SSD, unit=GB, min=1, max=100, step=1, required=true, isTotalsValidator=false}", "{type=integer, propertyName=HDD, unit=GB, min=0, max=250, step=10, required=false, isTotalsValidator=false}", "{type=integer, propertyName=Traffic, unit=GB, min=10, max=1000, step=10, required=true, isTotalsValidator=false}", - "{type=integer, propertyName=MultiOptions, min=1, max=100, step=1, required=true, isTotalsValidator=false}", - "{type=integer, propertyName=Daemons, min=0, max=10, required=false, isTotalsValidator=false}", + "{type=integer, propertyName=MultiOptions, min=1, max=100, step=1, required=false, defaultValue=1, isTotalsValidator=false}", + "{type=integer, propertyName=Daemons, min=0, max=10, required=false, defaultValue=0, isTotalsValidator=false}", "{type=boolean, propertyName=Online Office Server, required=false, isTotalsValidator=false}", - "{type=enumeration, propertyName=SLA-Platform, values=[BASIC, EXT24H], required=false, isTotalsValidator=false}"); + "{type=enumeration, propertyName=SLA-Platform, values=[BASIC, EXT24H], required=false, defaultValue=BASIC, isTotalsValidator=false}"); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java index f4945cb1..2d1e477b 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetControllerAcceptanceTest.java @@ -76,25 +76,19 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup "type": "MANAGED_WEBSPACE", "identifier": "sec01", "caption": "some Webspace", - "config": { - "extra": 42 - } + "config": {} }, { "type": "MANAGED_WEBSPACE", "identifier": "fir01", "caption": "some Webspace", - "config": { - "extra": 42 - } + "config": {} }, { "type": "MANAGED_WEBSPACE", "identifier": "thi01", "caption": "some Webspace", - "config": { - "extra": 42 - } + "config": {} } ] """)); @@ -123,7 +117,9 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup "identifier": "vm1011", "caption": "some ManagedServer", "config": { - "extra": 42 + "monit_max_cpu_usage": 90, + "monit_max_ram_usage": 80, + "monit_max_ssd_usage": 70 } }, { @@ -131,7 +127,9 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup "identifier": "vm1012", "caption": "some ManagedServer", "config": { - "extra": 42 + "monit_max_cpu_usage": 90, + "monit_max_ram_usage": 80, + "monit_max_ssd_usage": 70 } }, { @@ -139,7 +137,9 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup "identifier": "vm1013", "caption": "some ManagedServer", "config": { - "extra": 42 + "monit_max_cpu_usage": 90, + "monit_max_ram_usage": 80, + "monit_max_ssd_usage": 70 } } ] @@ -266,9 +266,14 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup .body("", lenientlyEquals(""" { "statusPhrase": "Bad Request", - "message": "['config.extra' is not expected but is set to '42', 'config.monit_max_ssd_usage' is expected to be >= 10 but is 0, 'config.monit_max_cpu_usage' is expected to be <= 100 but is 101, 'config.monit_max_ram_usage' is required but missing]" + "message": "[ + <<= 10 but is 0, + << PATCH_CONFIG = patchMap( entry("CPU", 2), entry("HDD", null), - entry("SDD", 256) + entry("SSD", 256) ); private static final Map PATCHED_CONFIG = patchMap( entry("CPU", 2), - entry("SDD", 256), + entry("SSD", 256), entry("MEM", 64) ); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsControllerAcceptanceTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsControllerAcceptanceTest.java index 55c2e29e..f1b1acb9 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsControllerAcceptanceTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetPropsControllerAcceptanceTest.java @@ -55,56 +55,54 @@ class HsHostingAssetPropsControllerAcceptanceTest { { "type": "integer", "propertyName": "monit_min_free_ssd", - "required": false, - "unit": null, "min": 1, "max": 1000, - "step": null + "required": false, + "isTotalsValidator": false }, { "type": "integer", "propertyName": "monit_min_free_hdd", - "required": false, - "unit": null, "min": 1, "max": 4000, - "step": null + "required": false, + "isTotalsValidator": false }, { "type": "integer", "propertyName": "monit_max_ssd_usage", - "required": true, "unit": "%", "min": 10, "max": 100, - "step": null + "required": true, + "isTotalsValidator": false }, { "type": "integer", "propertyName": "monit_max_hdd_usage", - "required": false, "unit": "%", "min": 10, "max": 100, - "step": null + "required": false, + "isTotalsValidator": false }, { "type": "integer", "propertyName": "monit_max_cpu_usage", - "required": true, "unit": "%", "min": 10, "max": 100, - "step": null + "required": true, + "isTotalsValidator": false }, { "type": "integer", "propertyName": "monit_max_ram_usage", - "required": true, "unit": "%", "min": 10, "max": 100, - "step": null + "required": true, + "isTotalsValidator": false } ] """)); diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java index 29a8af07..c166801b 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/HsHostingAssetRepositoryIntegrationTest.java @@ -164,9 +164,9 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu // then allTheseServersAreReturned( result, - "HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedServer, { extra: 42 })", - "HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:separate ManagedServer, { extra: 42 })", - "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedServer, { extra: 42 })"); + "HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedServer)", + "HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:separate ManagedServer)", + "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedServer)"); } @Test @@ -182,9 +182,9 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu // then: exactlyTheseAssetsAreReturned( result, - "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedServer, { extra: 42 })", - "HsHostingAssetEntity(MANAGED_SERVER, vm1011, some ManagedServer, D-1000111:D-1000111 default project:some PrivateCloud, { extra: 42 })", - "HsHostingAssetEntity(CLOUD_SERVER, vm2011, another CloudServer, D-1000111:D-1000111 default project:some PrivateCloud, { extra: 42 })"); + "HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedServer)", + "HsHostingAssetEntity(MANAGED_SERVER, vm1011, some ManagedServer, D-1000111:D-1000111 default project:some PrivateCloud, { monit_max_cpu_usage: 90, monit_max_ram_usage: 80, monit_max_ssd_usage: 70 })", + "HsHostingAssetEntity(CLOUD_SERVER, vm2011, another CloudServer, D-1000111:D-1000111 default project:some PrivateCloud)"); } @Test @@ -200,7 +200,7 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu // then allTheseServersAreReturned( result, - "HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:separate ManagedServer, { extra: 42 })"); + "HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:separate ManagedServer)"); } } diff --git a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorUnitTest.java b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorUnitTest.java index a648463f..28fb5c6e 100644 --- a/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorUnitTest.java +++ b/src/test/java/net/hostsharing/hsadminng/hs/hosting/asset/validators/HsHostingAssetEntityValidatorUnitTest.java @@ -6,7 +6,7 @@ import org.junit.jupiter.api.Test; import jakarta.validation.ValidationException; import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.MANAGED_SERVER; -import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidator.valid; +import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAssetEntityValidator.validated; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; @@ -21,7 +21,7 @@ class HsHostingAssetEntityValidatorUnitTest { .build(); // when - final var result = catchThrowable( ()-> valid(managedServerHostingAssetEntity) ); + final var result = catchThrowable( ()-> validated(managedServerHostingAssetEntity) ); // then assertThat(result).isInstanceOf(ValidationException.class)