amend test data according to new validations

This commit is contained in:
Michael Hoennig 2024-06-13 16:29:41 +02:00
parent 5cae64af4c
commit 5d15968e3c
17 changed files with 273 additions and 173 deletions

View File

@ -111,12 +111,10 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject {
@OneToMany(cascade = CascadeType.REFRESH, orphanRemoval = true)
@JoinColumn(name="parentitemuuid", referencedColumnName="uuid")
// @Transient
private List<HsBookingItemEntity> subBookingItems;
@OneToMany(cascade = CascadeType.REFRESH, orphanRemoval = true)
@JoinColumn(name="bookingitemuuid", referencedColumnName="uuid")
// @Transient
private List<HsHostingAssetEntity> subHostingAssets;
@Transient

View File

@ -67,7 +67,7 @@ public class HsBookingItemEntityValidator extends HsEntityValidator<HsBookingIte
return sequentiallyValidate(
() -> enrich(prefix(bookingItem.toShortString(), "resources"), validateProperties(bookingItem.getResources())),
() -> enrich(prefix(bookingItem.toShortString(), "parentItem"), optionallyValidate(bookingItem.getParentItem())),
() -> validateSubEntities(bookingItem)
() -> validateAgainstSubEntities(bookingItem)
);
}
@ -75,7 +75,7 @@ public class HsBookingItemEntityValidator extends HsEntityValidator<HsBookingIte
return bookingItem != null ? HsBookingItemEntityValidator.doValidate(bookingItem) : emptyList();
}
protected List<String> validateSubEntities(final HsBookingItemEntity bookingItem) {
protected List<String> validateAgainstSubEntities(final HsBookingItemEntity bookingItem) {
return Stream.concat(
stream(propertyValidators)
.map(propDef -> propDef.validateTotals(bookingItem))

View File

@ -1,8 +1,6 @@
package net.hostsharing.hsadminng.hs.booking.item.validators;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import java.util.List;
import static net.hostsharing.hsadminng.hs.validation.BooleanProperty.booleanProperty;
import static net.hostsharing.hsadminng.hs.validation.EnumerationProperty.enumerationProperty;
@ -25,11 +23,4 @@ class HsManagedServerBookingItemValidator extends HsBookingItemEntityValidator {
booleanProperty("SLA-Web").falseIf("SLA-Platform", "BASIC").optional()
);
}
@Override
public List<String> validate(final HsBookingItemEntity managedServerBookingItem) {
final var selfValidation = super.validate(managedServerBookingItem);
return !selfValidation.isEmpty() ? selfValidation : validateParentEntities(managedServerBookingItem);
}
}

View File

@ -25,7 +25,7 @@ class HsManagedWebspaceBookingItemValidator extends HsBookingItemEntityValidator
integerProperty("SSD").unit("GB").min(1).max(100).step(1).required(),
integerProperty("HDD").unit("GB").min(0).max(250).step(10).optional(),
integerProperty("Traffic").unit("GB").min(10).max(1000).step(10).required(),
integerProperty("MultiOptions").min(1).max(100).step(1).withDefault(1)
integerProperty("Multi").min(1).max(100).step(1).withDefault(1)
.eachComprising( 25, unixUsers())
.eachComprising( 5, databaseUsers())
.eachComprising( 5, databases())

View File

@ -14,13 +14,10 @@ import java.util.Map;
import java.util.Objects;
import java.util.Set;
import static java.lang.String.join;
import static java.util.Arrays.stream;
import static java.util.Collections.emptyList;
import static java.util.Optional.ofNullable;
import static net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetType.CLOUD_SERVER;
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.*;
public class HsHostingAssetEntityValidator extends HsEntityValidator<HsHostingAssetEntity> {
@ -29,6 +26,7 @@ public class HsHostingAssetEntityValidator extends HsEntityValidator<HsHostingAs
register(CLOUD_SERVER, new HsHostingAssetEntityValidator());
register(MANAGED_SERVER, new HsManagedServerHostingAssetValidator());
register(MANAGED_WEBSPACE, new HsManagedWebspaceHostingAssetValidator());
register(UNIX_USER, new HsHostingAssetEntityValidator());
}
private static void register(final Enum<HsHostingAssetType> type, final HsEntityValidator<HsHostingAssetEntity> validator) {

View File

@ -2,8 +2,11 @@ package net.hostsharing.hsadminng.hs.hosting.asset.validators;
import net.hostsharing.hsadminng.hs.hosting.asset.HsHostingAssetEntity;
import java.util.Collection;
import java.util.stream.Stream;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;
class HsManagedWebspaceHostingAssetValidator extends HsHostingAssetEntityValidator {
public HsManagedWebspaceHostingAssetValidator() {
@ -11,16 +14,16 @@ class HsManagedWebspaceHostingAssetValidator extends HsHostingAssetEntityValidat
@Override
public List<String> validate(final HsHostingAssetEntity assetEntity) {
final var result = super.validate(assetEntity);
validateIdentifierPattern(result, assetEntity);
return result;
return Stream.of(validateIdentifierPattern(assetEntity), super.validate(assetEntity))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
private static void validateIdentifierPattern(final List<String> result, final HsHostingAssetEntity assetEntity) {
private static List<String> validateIdentifierPattern(final HsHostingAssetEntity assetEntity) {
final var expectedIdentifierPattern = "^" + assetEntity.getParentAsset().getBookingItem().getProject().getDebitor().getDefaultPrefix() + "[0-9][0-9]$";
if ( !assetEntity.getIdentifier().matches(expectedIdentifierPattern)) {
result.add("'identifier' expected to match '"+expectedIdentifierPattern+"', but is '" + assetEntity.getIdentifier() + "'");
return List.of("'identifier' expected to match '"+expectedIdentifierPattern+"', but is '" + assetEntity.getIdentifier() + "'");
}
return Collections.emptyList();
}
}

View File

@ -167,11 +167,6 @@ public abstract class ValidatableProperty<T> {
.map(v -> v.apply(bookingItem))
.filter(Objects::nonNull)
.flatMap(Collection::stream)
.map(v -> wrap(v))
.toList();
}
private String wrap(final String v) {
return v;
}
}

View File

@ -37,9 +37,9 @@ begin
(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);
(managedServerUuid, relatedProject.uuid, 'MANAGED_SERVER', null, 'separate ManagedServer', daterange('20221001', null, '[]'), '{ "CPUs": 2, "RAM": 8, "SSD": 500, "Traffic": 500 }'::jsonb),
(uuid_generate_v4(), null, 'MANAGED_WEBSPACE', managedServerUuid, 'some ManagedWebspace', daterange('20221001', null, '[]'), '{ "SSD": 50, "Traffic": 20, "Daemons": 2, "Multi": 4 }'::jsonb),
(uuid_generate_v4(), relatedProject.uuid, 'MANAGED_WEBSPACE', null, 'separate ManagedWebspace', daterange('20221001', null, '[]'), '{ "SSD": 100, "Traffic": 50, "Daemons": 0, "Multi": 1 }'::jsonb);
end; $$;
--//

View File

@ -75,10 +75,10 @@ begin
end);
if expectedParentType is not null and actualParentType is null then
raise exception '[400] % must have % as parent, but got <NULL>',
raise exception '[400] HostingAsset % must have % as parent, but got <NULL>',
NEW.type, expectedParentType;
elsif expectedParentType is not null and actualParentType <> expectedParentType then
raise exception '[400] % must have % as parent, but got %s',
raise exception '[400] HostingAsset % must have % as parent, but got %s',
NEW.type, expectedParentType, actualParentType;
end if;
return NEW;
@ -100,27 +100,23 @@ create or replace function hs_hosting_asset_booking_item_hierarchy_check_tf()
language plpgsql as $$
declare
actualBookingItemType HsBookingItemType;
expectedBookingItemTypes HsBookingItemType[];
expectedBookingItemType HsBookingItemType;
begin
actualBookingItemType := (select type
from hs_booking_item
where NEW.bookingItemUuid = uuid);
if NEW.type = 'CLOUD_SERVER' then
expectedBookingItemTypes := ARRAY['PRIVATE_CLOUD', 'CLOUD_SERVER'];
expectedBookingItemType := 'CLOUD_SERVER';
elsif NEW.type = 'MANAGED_SERVER' then
expectedBookingItemTypes := ARRAY['PRIVATE_CLOUD', 'MANAGED_SERVER'];
expectedBookingItemType := 'MANAGED_SERVER';
elsif NEW.type = 'MANAGED_WEBSPACE' then
if NEW.parentAssetUuid is null then
expectedBookingItemTypes := ARRAY['MANAGED_WEBSPACE'];
else
expectedBookingItemTypes := ARRAY['PRIVATE_CLOUD', 'MANAGED_SERVER'];
end if;
expectedBookingItemType := 'MANAGED_WEBSPACE';
end if;
if not actualBookingItemType = any(expectedBookingItemTypes) then
raise exception '[400] % % must have any of % as booking-item, but got %',
NEW.type, NEW.identifier, expectedBookingItemTypes, actualBookingItemType;
if not actualBookingItemType = expectedBookingItemType then
raise exception '[400] HostingAsset % % must have % as booking-item, but got %',
NEW.type, NEW.identifier, expectedBookingItemType, actualBookingItemType;
end if;
return NEW;
end; $$;

View File

@ -11,16 +11,18 @@
create or replace procedure createHsHostingAssetTestData(givenProjectCaption varchar)
language plpgsql as $$
declare
currentTask varchar;
relatedProject hs_booking_project;
relatedDebitor hs_office_debitor;
relatedPrivateCloudBookingItem hs_booking_item;
relatedManagedServerBookingItem hs_booking_item;
debitorNumberSuffix varchar;
defaultPrefix varchar;
managedServerUuid uuid;
managedWebspaceUuid uuid;
webUnixUserUuid uuid;
currentTask varchar;
relatedProject hs_booking_project;
relatedDebitor hs_office_debitor;
relatedPrivateCloudBookingItem hs_booking_item;
relatedManagedServerBookingItem hs_booking_item;
relatedCloudServerBookingItem hs_booking_item;
relatedManagedWebspaceBookingItem hs_booking_item;
debitorNumberSuffix varchar;
defaultPrefix varchar;
managedServerUuid uuid;
managedWebspaceUuid uuid;
webUnixUserUuid uuid;
begin
currentTask := 'creating hosting-asset test-data ' || givenProjectCaption;
call defineContext(currentTask, null, 'superuser-alex@hostsharing.net', 'global#global:ADMIN');
@ -38,7 +40,7 @@ begin
select item.* into relatedPrivateCloudBookingItem
from hs_booking_item item
where item.projectUuid = relatedProject.uuid
where item.projectUuid = relatedProject.uuid
and item.type = 'PRIVATE_CLOUD';
assert relatedPrivateCloudBookingItem.uuid is not null, 'relatedPrivateCloudBookingItem for "' || givenProjectCaption|| '" must not be null';
@ -48,6 +50,18 @@ begin
and item.type = 'MANAGED_SERVER';
assert relatedManagedServerBookingItem.uuid is not null, 'relatedManagedServerBookingItem for "' || givenProjectCaption|| '" must not be null';
select item.* into relatedCloudServerBookingItem
from hs_booking_item item
where item.parentItemuuid = relatedPrivateCloudBookingItem.uuid
and item.type = 'CLOUD_SERVER';
assert relatedCloudServerBookingItem.uuid is not null, 'relatedCloudServerBookingItem for "' || givenProjectCaption|| '" must not be null';
select item.* into relatedManagedWebspaceBookingItem
from hs_booking_item item
where item.projectUuid = relatedProject.uuid
and item.type = 'MANAGED_WEBSPACE';
assert relatedManagedWebspaceBookingItem.uuid is not null, 'relatedManagedWebspaceBookingItem for "' || givenProjectCaption|| '" must not be null';
select uuid_generate_v4() into managedServerUuid;
select uuid_generate_v4() into managedWebspaceUuid;
select uuid_generate_v4() into webUnixUserUuid;
@ -55,12 +69,12 @@ begin
defaultPrefix := relatedDebitor.defaultPrefix;
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', '{ "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);
(uuid, bookingitemuuid, type, parentAssetUuid, assignedToAssetUuid, identifier, caption, config)
values (managedServerUuid, relatedManagedServerBookingItem.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(), relatedCloudServerBookingItem.uuid, 'CLOUD_SERVER', null, null, 'vm20' || debitorNumberSuffix, 'another CloudServer', '{}'::jsonb),
(managedWebspaceUuid, relatedManagedWebspaceBookingItem.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"}'::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": "*"}'::jsonb);
end; $$;
--//

View File

@ -77,14 +77,14 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
[
{
"type": "MANAGED_WEBSPACE",
"caption": "some ManagedWebspace",
"caption": "separate ManagedWebspace",
"validFrom": "2022-10-01",
"validTo": null,
"resources": {
"SSD": 512,
"Multi": 4,
"Daemons": 2,
"Traffic": 12
"SSD": 100,
"Multi": 1,
"Daemons": 0,
"Traffic": 50
}
},
{
@ -94,7 +94,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
"validTo": null,
"resources": {
"RAM": 8,
"SSD": 512,
"SSD": 500,
"CPUs": 2,
"Traffic": 500
}
@ -105,8 +105,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
"validFrom": "2024-04-01",
"validTo": null,
"resources": {
"SSD": 4000,
"HDD": 10000,
"RAM": 32,
"SSD": 4000,
"CPUs": 10,
"Traffic": 2000
}
@ -174,7 +175,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
@Test
void globalAdmin_canGetArbitraryBookingItem() {
context.define("superuser-alex@hostsharing.net");
final var givenBookingItemUuid = bookingItemRepo.findByCaption("some ManagedWebspace").stream()
final var givenBookingItemUuid = bookingItemRepo.findByCaption("separate ManagedWebspace").stream()
.filter(bi -> belongsToDebitorWithDefaultPrefix(bi, "fir"))
.map(HsBookingItemEntity::getUuid)
.findAny().orElseThrow();
@ -191,14 +192,14 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
.body("", lenientlyEquals("""
{
"type": "MANAGED_WEBSPACE",
"caption": "some ManagedWebspace",
"caption": "separate ManagedWebspace",
"validFrom": "2022-10-01",
"validTo": null,
"resources": {
"SSD": 512,
"Multi": 4,
"Daemons": 2,
"Traffic": 12
"SSD": 100,
"Multi": 1,
"Daemons": 0,
"Traffic": 50
}
}
""")); // @formatter:on
@ -251,7 +252,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
"validTo": null,
"resources": {
"RAM": 8,
"SSD": 512,
"SSD": 500,
"CPUs": 2,
"Traffic": 500
}

View File

@ -174,8 +174,8 @@ 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, 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, 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 })");
}
@ -194,8 +194,8 @@ 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: 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, 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 })");
}
}

View File

@ -137,7 +137,7 @@ class HsManagedServerBookingItemValidatorUnitTest {
.resources(ofEntries(
entry("SSD", 100),
entry("Traffic", 1000),
entry("MultiOptions", 1)
entry("Multi", 1)
))
.subHostingAssets(of(
HsHostingAssetEntity.builder()
@ -167,10 +167,10 @@ class HsManagedServerBookingItemValidatorUnitTest {
// then
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 9 found",
"MultiOptions=1 allows at maximum 250 databases, but 260 found"
"Multi=1 allows at maximum 25 unix users, but 26 found",
"Multi=1 allows at maximum 5 database users, but 6 found",
"Multi=1 allows at maximum 5 databases, but 9 found",
"Multi=1 allows at maximum 250 databases, but 260 found"
);
}

View File

@ -58,7 +58,7 @@ 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=false, defaultValue=1, isTotalsValidator=false}",
"{type=integer, propertyName=Multi, 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, defaultValue=BASIC, isTotalsValidator=false}");

View File

@ -5,6 +5,7 @@ import io.restassured.http.ContentType;
import net.hostsharing.hsadminng.HsadminNgApplication;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRepository;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRepository;
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
@ -21,6 +22,8 @@ import java.util.UUID;
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 org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.Matchers.matchesRegex;
@ -103,47 +106,47 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
RestAssured // @formatter:off
.given()
.header("current-user", "superuser-alex@hostsharing.net")
.port(port)
.header("current-user", "superuser-alex@hostsharing.net")
.port(port)
.when()
.get("http://localhost/api/hs/hosting/assets?type=" + MANAGED_SERVER)
. get("http://localhost/api/hs/hosting/assets?type=" + MANAGED_SERVER)
.then().log().all().assertThat()
.statusCode(200)
.contentType("application/json")
.body("", lenientlyEquals("""
[
{
"type": "MANAGED_SERVER",
"identifier": "vm1011",
"caption": "some ManagedServer",
"config": {
"monit_max_cpu_usage": 90,
"monit_max_ram_usage": 80,
"monit_max_ssd_usage": 70
.statusCode(200)
.contentType("application/json")
.body("", lenientlyEquals("""
[
{
"type": "MANAGED_SERVER",
"identifier": "vm1011",
"caption": "some ManagedServer",
"config": {
"monit_max_cpu_usage": 90,
"monit_max_ram_usage": 80,
"monit_max_ssd_usage": 70
}
},
{
"type": "MANAGED_SERVER",
"identifier": "vm1012",
"caption": "some ManagedServer",
"config": {
"monit_max_cpu_usage": 90,
"monit_max_ram_usage": 80,
"monit_max_ssd_usage": 70
}
},
{
"type": "MANAGED_SERVER",
"identifier": "vm1013",
"caption": "some ManagedServer",
"config": {
"monit_max_cpu_usage": 90,
"monit_max_ram_usage": 80,
"monit_max_ssd_usage": 70
}
}
},
{
"type": "MANAGED_SERVER",
"identifier": "vm1012",
"caption": "some ManagedServer",
"config": {
"monit_max_cpu_usage": 90,
"monit_max_ram_usage": 80,
"monit_max_ssd_usage": 70
}
},
{
"type": "MANAGED_SERVER",
"identifier": "vm1013",
"caption": "some ManagedServer",
"config": {
"monit_max_cpu_usage": 90,
"monit_max_ram_usage": 80,
"monit_max_ssd_usage": 70
}
}
]
"""));
]
"""));
// @formatter:on
}
}
@ -155,7 +158,14 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
void globalAdmin_canAddBookedAsset() {
context.define("superuser-alex@hostsharing.net");
final var givenBookingItem = givenBookingItem("D-1000111 default project", "some PrivateCloud");
final var givenBookingItem = newBookingItem("D-1000111 default project",
HsBookingItemType.MANAGED_WEBSPACE, "separate ManagedWebspace BI",
Map.ofEntries(
entry("SSD", 50),
entry("Traffic", 50)
)
);
final var givenParentAsset = givenParentAsset(MANAGED_SERVER, "vm1011");
final var location = RestAssured // @formatter:off
.given()
@ -164,12 +174,13 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
.body("""
{
"bookingItemUuid": "%s",
"type": "MANAGED_SERVER",
"identifier": "vm1400",
"caption": "some new ManagedServer",
"config": { "monit_max_ssd_usage": 80, "monit_max_cpu_usage": 90, "monit_max_ram_usage": 70 }
"type": "MANAGED_WEBSPACE",
"identifier": "fir10",
"parentAssetUuid": "%s",
"caption": "some separate ManagedWebspace HA",
"config": {}
}
""".formatted(givenBookingItem.getUuid()))
""".formatted(givenBookingItem.getUuid(), givenParentAsset.getUuid()))
.port(port)
.when()
.post("http://localhost/api/hs/hosting/assets")
@ -178,10 +189,10 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
.contentType(ContentType.JSON)
.body("", lenientlyEquals("""
{
"type": "MANAGED_SERVER",
"identifier": "vm1400",
"caption": "some new ManagedServer",
"config": { "monit_max_ssd_usage": 80, "monit_max_cpu_usage": 90, "monit_max_ram_usage": 70 }
"type": "MANAGED_WEBSPACE",
"identifier": "fir10",
"caption": "some separate ManagedWebspace HA",
"config": {}
}
"""))
.header("Location", matchesRegex("http://localhost:[1-9][0-9]*/api/hs/hosting/assets/[^/]*"))
@ -191,6 +202,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
final var newUserUuid = UUID.fromString(
location.substring(location.lastIndexOf('/') + 1));
assertThat(newUserUuid).isNotNull();
toCleanup(HsHostingAssetEntity.class, newUserUuid);
}
@Test
@ -239,7 +251,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
}
@Test
void additionalValidationsArePerformend_whenAddingAsset() {
void propertyValidationsArePerformend_whenAddingAsset() {
context.define("superuser-alex@hostsharing.net");
final var givenBookingItem = givenBookingItem("D-1000111 default project", "some PrivateCloud");
@ -275,6 +287,58 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
}
""".replaceAll(" +<<<", ""))); // @formatter:on
}
@Test
void totalsLimitValidationsArePerformend_whenAddingAsset() {
context.define("superuser-alex@hostsharing.net");
final var givenHostingAsset = givenHostingAsset(MANAGED_WEBSPACE, "fir01");
assertThat(givenHostingAsset.getBookingItem().getResources().get("Multi"))
.as("precondition failed")
.isEqualTo(1);
jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net");
for (int n = 0; n < 25; ++n ) {
toCleanup(assetRepo.save(
HsHostingAssetEntity.builder()
.type(UNIX_USER)
.parentAsset(givenHostingAsset)
.identifier("fir01-%2d".formatted(n))
.caption("Test UnixUser fir01-%2d".formatted(n))
.build()));
}
}).assertSuccessful();
RestAssured // @formatter:off
.given()
.header("current-user", "superuser-alex@hostsharing.net")
.contentType(ContentType.JSON)
.body("""
{
"parentAssetUuid": "%s",
"type": "UNIX_USER",
"identifier": "fir01-extra",
"caption": "some extra UnixUser",
"config": { }
}
""".formatted(givenHostingAsset.getUuid()))
.port(port)
.when()
.post("http://localhost/api/hs/hosting/assets")
.then().log().all().assertThat()
.statusCode(400)
.contentType(ContentType.JSON)
.body("", lenientlyEquals("""
{
"statusPhrase": "Bad Request",
"message": "[
<<<UNIX_USER:fir01-extra.parentAsset.MANAGED_WEBSPACE:fir01.bookingItem.Multi=1 allows at maximum 25 unix users, but 26 found
<<<]"
}
""".replaceAll(" +<<<", ""))); // @formatter:on
}
}
@Nested
@ -443,6 +507,29 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
}
}
HsHostingAssetEntity givenHostingAsset(final HsHostingAssetType type, final String identifier) {
return assetRepo.findByIdentifier(identifier).stream()
.filter(ha -> ha.getType()==type)
.findAny().orElseThrow();
}
HsBookingItemEntity newBookingItem(
final String projectCaption,
final HsBookingItemType type, final String bookingItemCaption, final Map<String, Object> resources) {
return jpaAttempt.transacted(() -> {
context.define("superuser-alex@hostsharing.net");
final var project = projectRepo.findByCaption(projectCaption).stream()
.findAny().orElseThrow();
final var bookingItem = HsBookingItemEntity.builder()
.project(project)
.type(type)
.caption(bookingItemCaption)
.resources(resources)
.build();
return toCleanup(bookingItemRepo.save(bookingItem));
}).assertSuccessful().returnedValue();
}
HsBookingItemEntity givenBookingItem(final String projectCaption, final String bookingItemCaption) {
return bookingItemRepo.findByCaption(bookingItemCaption).stream()
.filter(bi -> bi.getRelatedProject().getCaption().contains(projectCaption))

View File

@ -33,7 +33,8 @@ class HsHostingAssetPropsControllerAcceptanceTest {
[
"MANAGED_SERVER",
"MANAGED_WEBSPACE",
"CLOUD_SERVER"
"CLOUD_SERVER",
"UNIX_USER"
]
"""));
// @formatter:on

View File

@ -3,6 +3,7 @@ package net.hostsharing.hsadminng.hs.hosting.asset;
import net.hostsharing.hsadminng.context.Context;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRepository;
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRepository;
import net.hostsharing.hsadminng.rbac.rbacgrant.RawRbacGrantRepository;
import net.hostsharing.hsadminng.rbac.rbacrole.RawRbacRoleRepository;
@ -70,12 +71,13 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
// given
context("superuser-alex@hostsharing.net");
final var count = assetRepo.count();
final var givenManagedServer = givenManagedServer("D-1000111 default project", MANAGED_SERVER);
final var givenManagedServer = givenHostingAsset("D-1000111 default project", MANAGED_SERVER);
final var newWebspaceBookingItem = newBookingItem(givenManagedServer.getBookingItem(), HsBookingItemType.MANAGED_WEBSPACE, "fir01");
// when
final var result = attempt(em, () -> {
final var newAsset = HsHostingAssetEntity.builder()
.bookingItem(givenManagedServer.getBookingItem())
.bookingItem(newWebspaceBookingItem)
.parentAsset(givenManagedServer)
.caption("some new managed webspace")
.type(MANAGED_WEBSPACE)
@ -95,18 +97,19 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
public void createsAndGrantsRoles() {
// given
context("superuser-alex@hostsharing.net");
final var givenManagedServer = givenHostingAsset("D-1000111 default project", MANAGED_SERVER);
final var newWebspaceBookingItem = newBookingItem(givenManagedServer.getBookingItem(), HsBookingItemType.MANAGED_WEBSPACE, "fir01");
em.flush();
final var initialRoleNames = distinctRoleNamesOf(rawRoleRepo.findAll());
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll()).stream()
.map(s -> s.replace("hs_office_", ""))
.toList();
final var givenBookingItem = givenBookingItem("D-1000111 default project", "some PrivateCloud");
final var initialGrantNames = distinctGrantDisplaysOf(rawGrantRepo.findAll());
// when
final var result = attempt(em, () -> {
final var newAsset = HsHostingAssetEntity.builder()
.bookingItem(givenBookingItem)
.type(HsHostingAssetType.MANAGED_SERVER)
.identifier("vm9000")
.bookingItem(newWebspaceBookingItem)
.parentAsset(givenManagedServer)
.type(HsHostingAssetType.MANAGED_WEBSPACE)
.identifier("fir00")
.caption("some new managed webspace")
.build();
return toCleanup(assetRepo.save(newAsset));
@ -117,29 +120,33 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
final var all = rawRoleRepo.findAll();
assertThat(distinctRoleNamesOf(all)).containsExactlyInAnyOrder(Array.from(
initialRoleNames,
"hs_hosting_asset#vm9000:OWNER",
"hs_hosting_asset#vm9000:ADMIN",
"hs_hosting_asset#vm9000:AGENT",
"hs_hosting_asset#vm9000:TENANT"));
"hs_hosting_asset#fir00:ADMIN",
"hs_hosting_asset#fir00:AGENT",
"hs_hosting_asset#fir00:OWNER",
"hs_hosting_asset#fir00:TENANT"));
assertThat(distinctGrantDisplaysOf(rawGrantRepo.findAll()))
.map(s -> s.replace("hs_office_", ""))
.containsExactlyInAnyOrder(fromFormatted(
initialGrantNames,
// owner
"{ grant role:hs_hosting_asset#vm9000:OWNER to role:hs_booking_item#somePrivateCloud:ADMIN by system and assume }",
"{ grant perm:hs_hosting_asset#vm9000:DELETE to role:hs_hosting_asset#vm9000:OWNER by system and assume }",
"{ grant role:hs_hosting_asset#vm9000:ADMIN to role:hs_hosting_asset#vm9000:OWNER by system and assume }",
"{ 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 }",
"{ grant perm:hs_hosting_asset#fir00:DELETE to role:hs_hosting_asset#fir00:OWNER by system and assume }",
// admin
"{ grant perm:hs_hosting_asset#vm9000:INSERT>hs_hosting_asset to role:hs_hosting_asset#vm9000:ADMIN by system and assume }",
"{ grant perm:hs_hosting_asset#vm9000:UPDATE to role:hs_hosting_asset#vm9000:ADMIN by system and assume }",
"{ grant role:hs_hosting_asset#vm9000:ADMIN to role:hs_booking_item#somePrivateCloud:AGENT by system and assume }",
"{ grant role:hs_hosting_asset#vm9000:TENANT to role:hs_hosting_asset#vm9000:AGENT by system and assume }",
"{ grant role:hs_hosting_asset#vm9000:AGENT to role:hs_hosting_asset#vm9000:ADMIN by system and assume }",
"{ 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
"{ grant role:hs_hosting_asset#fir00:ADMIN to role:hs_hosting_asset#vm1011:AGENT by system and assume }",
"{ grant role:hs_hosting_asset#fir00:AGENT to role:hs_hosting_asset#fir00:ADMIN by system and assume }",
// tenant
"{ grant role:hs_booking_item#somePrivateCloud:TENANT to role:hs_hosting_asset#vm9000:TENANT by system and assume }",
"{ 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 }",
null));
}
@ -164,9 +171,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)",
"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)");
"HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedWebspace)",
"HsHostingAssetEntity(MANAGED_WEBSPACE, fir01, some Webspace, MANAGED_SERVER:vm1011, D-1000111:D-1000111 default project:separate ManagedWebspace)",
"HsHostingAssetEntity(MANAGED_WEBSPACE, thi01, some Webspace, MANAGED_SERVER:vm1013, D-1000313:D-1000313 default project:separate ManagedWebspace)");
}
@Test
@ -182,9 +189,8 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
// then:
exactlyTheseAssetsAreReturned(
result,
"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)");
"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 })");
}
@Test
@ -200,7 +206,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)");
"HsHostingAssetEntity(MANAGED_WEBSPACE, sec01, some Webspace, MANAGED_SERVER:vm1012, D-1000212:D-1000212 default project:separate ManagedWebspace)");
}
}
@ -351,7 +357,7 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
private HsHostingAssetEntity givenSomeTemporaryAsset(final String projectCaption, final String identifier) {
return jpaAttempt.transacted(() -> {
context("superuser-alex@hostsharing.net");
final var givenBookingItem = givenBookingItem("D-1000111 default project", "some PrivateCloud");
final var givenBookingItem = givenBookingItem("D-1000111 default project", "test CloudServer");
final var newAsset = HsHostingAssetEntity.builder()
.bookingItem(givenBookingItem)
.type(CLOUD_SERVER)
@ -367,20 +373,30 @@ class HsHostingAssetRepositoryIntegrationTest extends ContextBasedTestWithCleanu
}
HsBookingItemEntity givenBookingItem(final String projectCaption, final String bookingItemCaption) {
final var givenProject = projectRepo.findByCaption(projectCaption).stream()
.findAny().orElseThrow();
return bookingItemRepo.findAllByProjectUuid(givenProject.getUuid()).stream()
.filter(i -> i.getCaption().equals(bookingItemCaption))
return bookingItemRepo.findByCaption(bookingItemCaption).stream()
.filter(i -> i.getRelatedProject().getCaption().equals(projectCaption))
.findAny().orElseThrow();
}
HsHostingAssetEntity givenManagedServer(final String projectCaption, final HsHostingAssetType type) {
HsHostingAssetEntity givenHostingAsset(final String projectCaption, final HsHostingAssetType type) {
final var givenProject = projectRepo.findByCaption(projectCaption).stream()
.findAny().orElseThrow();
return assetRepo.findAllByCriteria(givenProject.getUuid(), null, type).stream()
.findAny().orElseThrow();
}
HsBookingItemEntity newBookingItem(
final HsBookingItemEntity parentBookingItem,
final HsBookingItemType type,
final String caption) {
final var newBookingItem = HsBookingItemEntity.builder()
.parentItem(parentBookingItem)
.type(type)
.caption(caption)
.build();
return toCleanup(bookingItemRepo.save(newBookingItem));
}
void exactlyTheseAssetsAreReturned(
final List<HsHostingAssetEntity> actualResult,
final String... serverNames) {