add alertContact to REST Schema, patcher and acceptance-test
This commit is contained in:
parent
9c43610e7c
commit
cb29730810
@ -16,7 +16,9 @@ import org.springframework.transaction.annotation.Transactional;
|
|||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import jakarta.persistence.EntityNotFoundException;
|
import jakarta.persistence.EntityNotFoundException;
|
||||||
|
import jakarta.persistence.PersistenceContext;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
@ -26,6 +28,9 @@ import static net.hostsharing.hsadminng.hs.hosting.asset.validators.HsHostingAss
|
|||||||
@RestController
|
@RestController
|
||||||
public class HsHostingAssetController implements HsHostingAssetsApi {
|
public class HsHostingAssetController implements HsHostingAssetsApi {
|
||||||
|
|
||||||
|
@PersistenceContext
|
||||||
|
private EntityManager em;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private Context context;
|
private Context context;
|
||||||
|
|
||||||
@ -119,7 +124,7 @@ public class HsHostingAssetController implements HsHostingAssetsApi {
|
|||||||
|
|
||||||
final var current = assetRepo.findByUuid(assetUuid).orElseThrow();
|
final var current = assetRepo.findByUuid(assetUuid).orElseThrow();
|
||||||
|
|
||||||
new HsHostingAssetEntityPatcher(current).apply(body);
|
new HsHostingAssetEntityPatcher(em, current).apply(body);
|
||||||
|
|
||||||
final var saved = validated(assetRepo.save(current));
|
final var saved = validated(assetRepo.save(current));
|
||||||
final var mapped = mapper.map(saved, HsHostingAssetResource.class);
|
final var mapped = mapper.map(saved, HsHostingAssetResource.class);
|
||||||
|
@ -100,7 +100,7 @@ public class HsHostingAssetEntity implements Stringifyable, RbacObject {
|
|||||||
|
|
||||||
@ManyToOne(fetch = FetchType.LAZY)
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name = "alarmcontactuuid")
|
@JoinColumn(name = "alarmcontactuuid")
|
||||||
private HsHostingContactEntity alarmContactUuid;
|
private HsHostingContactEntity alarmContact;
|
||||||
|
|
||||||
@OneToMany(cascade = CascadeType.REFRESH, orphanRemoval = true, fetch = FetchType.LAZY)
|
@OneToMany(cascade = CascadeType.REFRESH, orphanRemoval = true, fetch = FetchType.LAZY)
|
||||||
@JoinColumn(name="parentassetuuid", referencedColumnName="uuid")
|
@JoinColumn(name="parentassetuuid", referencedColumnName="uuid")
|
||||||
|
@ -1,17 +1,22 @@
|
|||||||
package net.hostsharing.hsadminng.hs.hosting.asset;
|
package net.hostsharing.hsadminng.hs.hosting.asset;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.hosting.contact.HsHostingContactEntity;
|
||||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetPatchResource;
|
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetPatchResource;
|
||||||
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
||||||
import net.hostsharing.hsadminng.mapper.KeyValueMap;
|
import net.hostsharing.hsadminng.mapper.KeyValueMap;
|
||||||
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
public class HsHostingAssetEntityPatcher implements EntityPatcher<HsHostingAssetPatchResource> {
|
public class HsHostingAssetEntityPatcher implements EntityPatcher<HsHostingAssetPatchResource> {
|
||||||
|
|
||||||
|
private final EntityManager em;
|
||||||
private final HsHostingAssetEntity entity;
|
private final HsHostingAssetEntity entity;
|
||||||
|
|
||||||
public HsHostingAssetEntityPatcher(final HsHostingAssetEntity entity) {
|
HsHostingAssetEntityPatcher(final EntityManager em, final HsHostingAssetEntity entity) {
|
||||||
|
this.em = em;
|
||||||
this.entity = entity;
|
this.entity = entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -21,5 +26,15 @@ public class HsHostingAssetEntityPatcher implements EntityPatcher<HsHostingAsset
|
|||||||
.ifPresent(entity::setCaption);
|
.ifPresent(entity::setCaption);
|
||||||
Optional.ofNullable(resource.getConfig())
|
Optional.ofNullable(resource.getConfig())
|
||||||
.ifPresent(r -> entity.getConfig().patch(KeyValueMap.from(resource.getConfig())));
|
.ifPresent(r -> entity.getConfig().patch(KeyValueMap.from(resource.getConfig())));
|
||||||
|
OptionalFromJson.of(resource.getAlarmContactUuid()).ifPresent(newValue -> {
|
||||||
|
verifyNotNull(newValue, "alarmContact");
|
||||||
|
entity.setAlarmContact(em.getReference(HsHostingContactEntity.class, newValue));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyNotNull(final UUID newValue, final String propertyName) {
|
||||||
|
if (newValue == null) {
|
||||||
|
throw new IllegalArgumentException("property '" + propertyName + "' must not be null");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,6 +32,8 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
caption:
|
caption:
|
||||||
type: string
|
type: string
|
||||||
|
alarmContact:
|
||||||
|
$ref: '../hs-office/hs-office-contact-schemas.yaml#/components/schemas/HsOfficeContact'
|
||||||
config:
|
config:
|
||||||
$ref: '#/components/schemas/HsHostingAssetConfiguration'
|
$ref: '#/components/schemas/HsHostingAssetConfiguration'
|
||||||
required:
|
required:
|
||||||
@ -46,6 +48,10 @@ components:
|
|||||||
caption:
|
caption:
|
||||||
type: string
|
type: string
|
||||||
nullable: true
|
nullable: true
|
||||||
|
alarmContactUuid:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
config:
|
config:
|
||||||
$ref: '#/components/schemas/HsHostingAssetConfiguration'
|
$ref: '#/components/schemas/HsHostingAssetConfiguration'
|
||||||
|
|
||||||
@ -72,6 +78,10 @@ components:
|
|||||||
minLength: 3
|
minLength: 3
|
||||||
maxLength: 80
|
maxLength: 80
|
||||||
nullable: false
|
nullable: false
|
||||||
|
alarmContactUuid:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
config:
|
config:
|
||||||
$ref: '#/components/schemas/HsHostingAssetConfiguration'
|
$ref: '#/components/schemas/HsHostingAssetConfiguration'
|
||||||
required:
|
required:
|
||||||
|
@ -7,6 +7,8 @@ import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntity;
|
|||||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRepository;
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemRepository;
|
||||||
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
|
import net.hostsharing.hsadminng.hs.booking.item.HsBookingItemType;
|
||||||
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRepository;
|
import net.hostsharing.hsadminng.hs.booking.project.HsBookingProjectRepository;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactEntity;
|
||||||
|
import net.hostsharing.hsadminng.hs.office.contact.HsOfficeContactRepository;
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorRepository;
|
||||||
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
|
import net.hostsharing.hsadminng.rbac.test.ContextBasedTestWithCleanup;
|
||||||
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
import net.hostsharing.hsadminng.rbac.test.JpaAttempt;
|
||||||
@ -54,6 +56,9 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
@Autowired
|
@Autowired
|
||||||
HsOfficeDebitorRepository debitorRepo;
|
HsOfficeDebitorRepository debitorRepo;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
HsOfficeContactRepository contactRepo;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
JpaAttempt jpaAttempt;
|
JpaAttempt jpaAttempt;
|
||||||
|
|
||||||
@ -425,6 +430,7 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
|
|
||||||
final var givenAsset = givenSomeTemporaryHostingAsset("2001", MANAGED_SERVER,
|
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));
|
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 alarmContactUuid = givenContact().getUuid();
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -432,13 +438,14 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
.body("""
|
.body("""
|
||||||
{
|
{
|
||||||
|
"alarmContactUuid": "%s",
|
||||||
"config": {
|
"config": {
|
||||||
"monit_max_ssd_usage": 85,
|
"monit_max_ssd_usage": 85,
|
||||||
"monit_max_hdd_usage": null,
|
"monit_max_hdd_usage": null,
|
||||||
"monit_min_free_ssd": 5
|
"monit_min_free_ssd": 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""")
|
""".formatted(alarmContactUuid))
|
||||||
.port(port)
|
.port(port)
|
||||||
.when()
|
.when()
|
||||||
.patch("http://localhost/api/hs/hosting/assets/" + givenAsset.getUuid())
|
.patch("http://localhost/api/hs/hosting/assets/" + givenAsset.getUuid())
|
||||||
@ -450,6 +457,11 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
"type": "MANAGED_SERVER",
|
"type": "MANAGED_SERVER",
|
||||||
"identifier": "vm2001",
|
"identifier": "vm2001",
|
||||||
"caption": "some test-asset",
|
"caption": "some test-asset",
|
||||||
|
"alarmContact": {
|
||||||
|
"uuid": "%s",
|
||||||
|
"caption": "second contact",
|
||||||
|
"emailAddresses": { "main": "contact-admin@secondcontact.example.com" }
|
||||||
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"monit_max_cpu_usage": 90,
|
"monit_max_cpu_usage": 90,
|
||||||
"monit_max_ram_usage": 70,
|
"monit_max_ram_usage": 70,
|
||||||
@ -457,12 +469,15 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
"monit_min_free_ssd": 5
|
"monit_min_free_ssd": 5
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""")); // @formatter:on
|
""".formatted(alarmContactUuid)));
|
||||||
|
// @formatter:on
|
||||||
|
|
||||||
// finally, the asset is actually updated
|
// finally, the asset is actually updated
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
assertThat(assetRepo.findByUuid(givenAsset.getUuid())).isPresent().get()
|
assertThat(assetRepo.findByUuid(givenAsset.getUuid())).isPresent().get()
|
||||||
.matches(asset -> {
|
.matches(asset -> {
|
||||||
|
assertThat(asset.getAlarmContact().toString()).isEqualTo(
|
||||||
|
"contact(caption='second contact', emailAddresses='{main=contact-admin@secondcontact.example.com}')");
|
||||||
assertThat(asset.getConfig().toString()).isEqualTo(
|
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 }");
|
"{ monit_max_cpu_usage: 90, monit_max_ram_usage: 70, monit_max_ssd_usage: 85, monit_min_free_ssd: 5 }");
|
||||||
return true;
|
return true;
|
||||||
@ -470,6 +485,13 @@ class HsHostingAssetControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private HsOfficeContactEntity givenContact() {
|
||||||
|
return jpaAttempt.transacted(() -> {
|
||||||
|
context.define("superuser-alex@hostsharing.net");
|
||||||
|
return contactRepo.findContactByOptionalCaptionLike("second").stream().findFirst().orElseThrow();
|
||||||
|
}).returnedValue();
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
@Order(5)
|
@Order(5)
|
||||||
class DeleteAsset {
|
class DeleteAsset {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package net.hostsharing.hsadminng.hs.hosting.asset;
|
package net.hostsharing.hsadminng.hs.hosting.asset;
|
||||||
|
|
||||||
|
import net.hostsharing.hsadminng.hs.hosting.contact.HsHostingContactEntity;
|
||||||
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetPatchResource;
|
import net.hostsharing.hsadminng.hs.hosting.generated.api.v1.model.HsHostingAssetPatchResource;
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
|
||||||
import net.hostsharing.hsadminng.mapper.KeyValueMap;
|
import net.hostsharing.hsadminng.mapper.KeyValueMap;
|
||||||
import net.hostsharing.hsadminng.rbac.test.PatchUnitTestBase;
|
import net.hostsharing.hsadminng.rbac.test.PatchUnitTestBase;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
@ -31,6 +31,7 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
> {
|
> {
|
||||||
|
|
||||||
private static final UUID INITIAL_BOOKING_ITEM_UUID = UUID.randomUUID();
|
private static final UUID INITIAL_BOOKING_ITEM_UUID = UUID.randomUUID();
|
||||||
|
private static final UUID PATCHED_CONTACT_UUID = UUID.randomUUID();
|
||||||
|
|
||||||
private static final Map<String, Object> INITIAL_CONFIG = patchMap(
|
private static final Map<String, Object> INITIAL_CONFIG = patchMap(
|
||||||
entry("CPU", 1),
|
entry("CPU", 1),
|
||||||
@ -47,6 +48,9 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
entry("SSD", 256),
|
entry("SSD", 256),
|
||||||
entry("MEM", 64)
|
entry("MEM", 64)
|
||||||
);
|
);
|
||||||
|
final HsHostingContactEntity givenInitialContact = HsHostingContactEntity.builder()
|
||||||
|
.uuid(UUID.randomUUID())
|
||||||
|
.build();
|
||||||
|
|
||||||
private static final String INITIAL_CAPTION = "initial caption";
|
private static final String INITIAL_CAPTION = "initial caption";
|
||||||
private static final String PATCHED_CAPTION = "patched caption";
|
private static final String PATCHED_CAPTION = "patched caption";
|
||||||
@ -56,10 +60,12 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
void initMocks() {
|
void initMocks() {
|
||||||
lenient().when(em.getReference(eq(HsOfficeDebitorEntity.class), any())).thenAnswer(invocation ->
|
// lenient().when(em.getReference(eq(HsOfficeDebitorEntity.class), any())).thenAnswer(invocation ->
|
||||||
HsOfficeDebitorEntity.builder().uuid(invocation.getArgument(1)).build());
|
// HsOfficeDebitorEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||||
lenient().when(em.getReference(eq(HsHostingAssetEntity.class), any())).thenAnswer(invocation ->
|
lenient().when(em.getReference(eq(HsHostingAssetEntity.class), any())).thenAnswer(invocation ->
|
||||||
HsHostingAssetEntity.builder().uuid(invocation.getArgument(1)).build());
|
HsHostingAssetEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||||
|
lenient().when(em.getReference(eq(HsHostingContactEntity.class), any())).thenAnswer(invocation ->
|
||||||
|
HsHostingContactEntity.builder().uuid(invocation.getArgument(1)).build());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -69,6 +75,7 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
entity.setBookingItem(TEST_BOOKING_ITEM);
|
entity.setBookingItem(TEST_BOOKING_ITEM);
|
||||||
entity.getConfig().putAll(KeyValueMap.from(INITIAL_CONFIG));
|
entity.getConfig().putAll(KeyValueMap.from(INITIAL_CONFIG));
|
||||||
entity.setCaption(INITIAL_CAPTION);
|
entity.setCaption(INITIAL_CAPTION);
|
||||||
|
entity.setAlarmContact(givenInitialContact);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -79,7 +86,7 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected HsHostingAssetEntityPatcher createPatcher(final HsHostingAssetEntity server) {
|
protected HsHostingAssetEntityPatcher createPatcher(final HsHostingAssetEntity server) {
|
||||||
return new HsHostingAssetEntityPatcher(server);
|
return new HsHostingAssetEntityPatcher(em, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -96,7 +103,18 @@ class HsHostingAssetEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
PATCH_CONFIG,
|
PATCH_CONFIG,
|
||||||
HsHostingAssetEntity::putConfig,
|
HsHostingAssetEntity::putConfig,
|
||||||
PATCHED_CONFIG)
|
PATCHED_CONFIG)
|
||||||
|
.notNullable(),
|
||||||
|
new JsonNullableProperty<>(
|
||||||
|
"alarmContact",
|
||||||
|
HsHostingAssetPatchResource::setAlarmContactUuid,
|
||||||
|
PATCHED_CONTACT_UUID,
|
||||||
|
HsHostingAssetEntity::setAlarmContact,
|
||||||
|
newContact(PATCHED_CONTACT_UUID))
|
||||||
.notNullable()
|
.notNullable()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static HsHostingContactEntity newContact(final UUID uuid) {
|
||||||
|
return HsHostingContactEntity.builder().uuid(uuid).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user