From 3a894ed72e5b907645a220980ff24a0fbf731c67 Mon Sep 17 00:00:00 2001 From: Michael Hoennig Date: Mon, 15 Apr 2024 15:15:27 +0200 Subject: [PATCH] patchable BookingResources --- .../booking/item/HsBookingItemController.java | 3 + .../hs/booking/item/HsBookingItemEntity.java | 4 +- .../item/HsBookingItemEntityPatcher.java | 11 ++- .../hsadminng/mapper/PatchMap.java | 18 ++-- .../hsadminng/mapper/PatchableMapWrapper.java | 13 ++- .../hs-booking/hs-booking-item-schemas.yaml | 58 +++++++++++-- .../hs-booking-items-with-uuid.yaml | 32 +++---- .../hs-booking/hs-booking-items.yaml | 24 +++--- .../api-definition/hs-booking/hs-booking.yaml | 4 +- .../6018-hs-booking-item-test-data.sql | 6 +- ...HsBookingItemControllerAcceptanceTest.java | 85 +++++++++++-------- .../HsBookingItemEntityPatcherUnitTest.java | 33 ++++--- ...sBookingItemRepositoryIntegrationTest.java | 12 +-- 13 files changed, 196 insertions(+), 107 deletions(-) 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 b74e7e0c..06926266 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,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import java.util.List; +import java.util.Map; import java.util.UUID; import java.util.function.BiConsumer; @@ -122,7 +123,9 @@ public class HsBookingItemController implements HsBookingItemsApi { } }; + @SuppressWarnings("unchecked") final BiConsumer RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> { entity.setValidity(toPostgresDateRange(resource.getValidFrom(), resource.getValidTo())); + entity.putResources((Map) resource.getResources()); }; } 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 828ffe0f..7a846f46 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 @@ -32,7 +32,6 @@ import java.io.IOException; import java.time.LocalDate; import java.util.HashMap; import java.util.Map; -import java.util.TreeMap; import java.util.UUID; import static java.util.Optional.ofNullable; @@ -122,6 +121,9 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject { } public void putResources(Map entries) { + if ( resourcesWrapper == null ) { + resourcesWrapper = new PatchableMapWrapper(resources); + } resourcesWrapper.assign(entries); } diff --git a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntityPatcher.java b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntityPatcher.java index 39fb863d..1905967b 100644 --- a/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntityPatcher.java +++ b/src/main/java/net/hostsharing/hsadminng/hs/booking/item/HsBookingItemEntityPatcher.java @@ -1,6 +1,5 @@ package net.hostsharing.hsadminng.hs.booking.item; -import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.ArbitraryBookingResourcesJsonResource; import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemPatchResource; import net.hostsharing.hsadminng.mapper.EntityPatcher; import net.hostsharing.hsadminng.mapper.OptionalFromJson; @@ -25,7 +24,7 @@ public class HsBookingItemEntityPatcher implements EntityPatcher entity.putResources(objectToMap(resource.getResources()))); + .ifPresent(r -> entity.getResources().patch(objectToMap(resource.getResources()))); OptionalFromJson.of(resource.getValidFrom()) .ifPresent(entity::setValidFrom); OptionalFromJson.of(resource.getValidTo()) @@ -33,6 +32,9 @@ public class HsBookingItemEntityPatcher implements EntityPatcher objectToMap(final Object obj) { + if (obj instanceof Map) { + return toKeyValueMap(obj); + } return stream(obj.getClass().getDeclaredFields()) .map(field -> { try { @@ -53,4 +55,9 @@ public class HsBookingItemEntityPatcher implements EntityPatcher toKeyValueMap(final Object obj) { + return (Map) obj; + } } diff --git a/src/main/java/net/hostsharing/hsadminng/mapper/PatchMap.java b/src/main/java/net/hostsharing/hsadminng/mapper/PatchMap.java index abcc9c4f..74a36bfa 100644 --- a/src/main/java/net/hostsharing/hsadminng/mapper/PatchMap.java +++ b/src/main/java/net/hostsharing/hsadminng/mapper/PatchMap.java @@ -18,13 +18,13 @@ public class PatchMap extends TreeMap { stream(entries).forEach(r -> put(r.getKey(), r.getValue())); } -// @SafeVarargs -// public static Map patchMap(final ImmutablePair... entries) { -// return new PatchMap(entries); -// } -// -// @NotNull -// public static ImmutablePair entry(final String key, final Object value) { -// return new ImmutablePair<>(key, value); -// } + @SafeVarargs + public static Map patchMap(final ImmutablePair... entries) { + return new PatchMap(entries); + } + + @NotNull + public static ImmutablePair entry(final String key, final Object value) { + return new ImmutablePair<>(key, value); + } } diff --git a/src/main/java/net/hostsharing/hsadminng/mapper/PatchableMapWrapper.java b/src/main/java/net/hostsharing/hsadminng/mapper/PatchableMapWrapper.java index beb6cc5b..678a68cd 100644 --- a/src/main/java/net/hostsharing/hsadminng/mapper/PatchableMapWrapper.java +++ b/src/main/java/net/hostsharing/hsadminng/mapper/PatchableMapWrapper.java @@ -4,12 +4,9 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import jakarta.validation.constraints.NotNull; import java.util.Collection; -import java.util.HashMap; import java.util.Map; import java.util.Set; -import java.util.TreeMap; -import static java.util.Arrays.stream; import static java.util.stream.Collectors.joining; /** This class wraps another (usually persistent) map and @@ -33,6 +30,16 @@ public class PatchableMapWrapper implements Map { delegate.putAll(entries); } + public void patch(final Map patch) { + patch.forEach((key, value) -> { + if (value == null) { + remove(key); + } else { + put(key, value); + } + }); + } + public String toString() { return "{ " + ( diff --git a/src/main/resources/api-definition/hs-booking/hs-booking-item-schemas.yaml b/src/main/resources/api-definition/hs-booking/hs-booking-item-schemas.yaml index e06a5ffd..7424a46e 100644 --- a/src/main/resources/api-definition/hs-booking/hs-booking-item-schemas.yaml +++ b/src/main/resources/api-definition/hs-booking/hs-booking-item-schemas.yaml @@ -18,7 +18,7 @@ components: type: string format: date resources: - $ref: '#/components/schemas/ArbitraryBookingResourcesJson' + $ref: '#/components/schemas/BookingResources' required: - uuid - debitor @@ -41,7 +41,7 @@ components: format: date nullable: true resources: - $ref: '#/components/schemas/ArbitraryBookingResourcesJson' + $ref: '#/components/schemas/BookingResources' HsBookingItemInsert: type: object @@ -64,7 +64,7 @@ components: format: date nullable: true resources: - $ref: '#/components/schemas/ArbitraryBookingResourcesJson' + $ref: '#/components/schemas/BookingResources' required: - caption - debitorUuid @@ -72,7 +72,53 @@ components: - resources additionalProperties: false - ArbitraryBookingResourcesJson: + BookingResourcesDoesNotWork: type: object - description: An object containing arbitrary JSON - additionalProperties: true + x-javaType: 'java.util.Map' + additionalProperties: + type: object + + BookingResources: + anyOf: + - $ref: '#/components/schemas/ManagedServerBookingResources' + - $ref: '#/components/schemas/ManagedWebspaceBookingResources' + + ManagedServerBookingResources: + type: object + properties: + caption: + type: string + minLength: 3 + maxLength: + nullable: false + CPU: + type: integer + minimum: 1 + maximum: 16 + SSD: + type: integer + minimum: 16 + maximum: 4096 + HDD: + type: integer + minimum: 16 + maximum: 4096 + additionalProperties: false + + ManagedWebspaceBookingResources: + type: object + properties: + disk: + type: integer + minimum: 1 + maximum: 16 + SSD: + type: integer + minimum: 16 + maximum: 4096 + HDD: + type: integer + minimum: 16 + maximum: 4096 + additionalProperties: false + diff --git a/src/main/resources/api-definition/hs-booking/hs-booking-items-with-uuid.yaml b/src/main/resources/api-definition/hs-booking/hs-booking-items-with-uuid.yaml index 99a8803a..3d7567c8 100644 --- a/src/main/resources/api-definition/hs-booking/hs-booking-items-with-uuid.yaml +++ b/src/main/resources/api-definition/hs-booking/hs-booking-items-with-uuid.yaml @@ -4,8 +4,8 @@ get: description: 'Fetch a single booking item its uuid, if visible for the current subject.' operationId: getBookingItemByUuid parameters: - - $ref: './auth.yaml#/components/parameters/currentUser' - - $ref: './auth.yaml#/components/parameters/assumedRoles' + - $ref: 'auth.yaml#/components/parameters/currentUser' + - $ref: 'auth.yaml#/components/parameters/assumedRoles' - name: bookingItemUuid in: path required: true @@ -19,12 +19,12 @@ get: content: 'application/json': schema: - $ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem' + $ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem' "401": - $ref: './error-responses.yaml#/components/responses/Unauthorized' + $ref: 'error-responses.yaml#/components/responses/Unauthorized' "403": - $ref: './error-responses.yaml#/components/responses/Forbidden' + $ref: 'error-responses.yaml#/components/responses/Forbidden' patch: tags: @@ -32,8 +32,8 @@ patch: description: 'Updates a single booking item identified by its uuid, if permitted for the current subject.' operationId: patchBookingItem parameters: - - $ref: './auth.yaml#/components/parameters/currentUser' - - $ref: './auth.yaml#/components/parameters/assumedRoles' + - $ref: 'auth.yaml#/components/parameters/currentUser' + - $ref: 'auth.yaml#/components/parameters/assumedRoles' - name: bookingItemUuid in: path required: true @@ -44,18 +44,18 @@ patch: content: 'application/json': schema: - $ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItemPatch' + $ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItemPatch' responses: "200": description: OK content: 'application/json': schema: - $ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem' + $ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem' "401": - $ref: './error-responses.yaml#/components/responses/Unauthorized' + $ref: 'error-responses.yaml#/components/responses/Unauthorized' "403": - $ref: './error-responses.yaml#/components/responses/Forbidden' + $ref: 'error-responses.yaml#/components/responses/Forbidden' delete: tags: @@ -63,8 +63,8 @@ delete: description: 'Delete a single booking item identified by its uuid, if permitted for the current subject.' operationId: deleteBookingIemByUuid parameters: - - $ref: './auth.yaml#/components/parameters/currentUser' - - $ref: './auth.yaml#/components/parameters/assumedRoles' + - $ref: 'auth.yaml#/components/parameters/currentUser' + - $ref: 'auth.yaml#/components/parameters/assumedRoles' - name: bookingItemUuid in: path required: true @@ -76,8 +76,8 @@ delete: "204": description: No Content "401": - $ref: './error-responses.yaml#/components/responses/Unauthorized' + $ref: 'error-responses.yaml#/components/responses/Unauthorized' "403": - $ref: './error-responses.yaml#/components/responses/Forbidden' + $ref: 'error-responses.yaml#/components/responses/Forbidden' "404": - $ref: './error-responses.yaml#/components/responses/NotFound' + $ref: 'error-responses.yaml#/components/responses/NotFound' diff --git a/src/main/resources/api-definition/hs-booking/hs-booking-items.yaml b/src/main/resources/api-definition/hs-booking/hs-booking-items.yaml index 1e6679b4..e869af21 100644 --- a/src/main/resources/api-definition/hs-booking/hs-booking-items.yaml +++ b/src/main/resources/api-definition/hs-booking/hs-booking-items.yaml @@ -5,8 +5,8 @@ get: - hs-booking-items operationId: listBookingItemsByDebitorUuid parameters: - - $ref: './auth.yaml#/components/parameters/currentUser' - - $ref: './auth.yaml#/components/parameters/assumedRoles' + - $ref: 'auth.yaml#/components/parameters/currentUser' + - $ref: 'auth.yaml#/components/parameters/assumedRoles' - name: debitorUuid in: query required: true @@ -22,11 +22,11 @@ get: schema: type: array items: - $ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem' + $ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem' "401": - $ref: './error-responses.yaml#/components/responses/Unauthorized' + $ref: 'error-responses.yaml#/components/responses/Unauthorized' "403": - $ref: './error-responses.yaml#/components/responses/Forbidden' + $ref: 'error-responses.yaml#/components/responses/Forbidden' post: summary: Adds a new booking item. @@ -34,25 +34,25 @@ post: - hs-booking-items operationId: addBookingItem parameters: - - $ref: './auth.yaml#/components/parameters/currentUser' - - $ref: './auth.yaml#/components/parameters/assumedRoles' + - $ref: 'auth.yaml#/components/parameters/currentUser' + - $ref: 'auth.yaml#/components/parameters/assumedRoles' requestBody: description: A JSON object describing the new booking item. required: true content: application/json: schema: - $ref: '/hs-booking-item-schemas.yaml#/components/schemas/HsBookingItemInsert' + $ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItemInsert' responses: "201": description: Created content: 'application/json': schema: - $ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem' + $ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem' "401": - $ref: './error-responses.yaml#/components/responses/Unauthorized' + $ref: 'error-responses.yaml#/components/responses/Unauthorized' "403": - $ref: './error-responses.yaml#/components/responses/Forbidden' + $ref: 'error-responses.yaml#/components/responses/Forbidden' "409": - $ref: './error-responses.yaml#/components/responses/Conflict' + $ref: 'error-responses.yaml#/components/responses/Conflict' diff --git a/src/main/resources/api-definition/hs-booking/hs-booking.yaml b/src/main/resources/api-definition/hs-booking/hs-booking.yaml index 8da21d09..d6a67058 100644 --- a/src/main/resources/api-definition/hs-booking/hs-booking.yaml +++ b/src/main/resources/api-definition/hs-booking/hs-booking.yaml @@ -11,7 +11,7 @@ paths: # Items /api/hs/booking/items: - $ref: "./hs-booking-items.yaml" + $ref: "hs-booking-items.yaml" /api/hs/booking/items/{bookingItemUuid}: - $ref: "./hs-booking-items-with-uuid.yaml" + $ref: "hs-booking-items-with-uuid.yaml" diff --git a/src/main/resources/db/changelog/6-hs-booking/601-booking-item/6018-hs-booking-item-test-data.sql b/src/main/resources/db/changelog/6-hs-booking/601-booking-item/6018-hs-booking-item-test-data.sql index 7a688e42..6326ce7f 100644 --- a/src/main/resources/db/changelog/6-hs-booking/601-booking-item/6018-hs-booking-item-test-data.sql +++ b/src/main/resources/db/changelog/6-hs-booking/601-booking-item/6018-hs-booking-item-test-data.sql @@ -32,9 +32,9 @@ begin raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor; insert into hs_booking_item (uuid, debitoruuid, caption, validity, resources) - values (uuid_generate_v4(), relatedDebitor.uuid, 'some ManagedServer', daterange('20221001', null, '[]'), '{ "CPUs": 2, "SDD-storage": 512 }'::jsonb), - (uuid_generate_v4(), relatedDebitor.uuid, 'some CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPUs": 2, "HDD-storage": 1024 }'::jsonb), - (uuid_generate_v4(), relatedDebitor.uuid, 'some Whatever', daterange('20240401', null, '[]'), '{ "CPUs": 1, "SDD-storage": 512, "HDD-storage": 2048 }'::jsonb); + values (uuid_generate_v4(), relatedDebitor.uuid, 'some ManagedServer', daterange('20221001', null, '[]'), '{ "CPU": 2, "SDD": 512, "extra": 42 }'::jsonb), + (uuid_generate_v4(), relatedDebitor.uuid, 'some CloudServer', daterange('20230115', '20240415', '[)'), '{ "CPU": 2, "HDD": 1024, "extra": 42 }'::jsonb), + (uuid_generate_v4(), relatedDebitor.uuid, 'some Whatever', daterange('20240401', null, '[]'), '{ "CPU": 1, "SDD": 512, "HDD": 2048, "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 7579e23c..23f61106 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 @@ -69,23 +69,36 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup .body("", lenientlyEquals(""" [ { - "caption": "some ManagedServer", - "validFrom": "2022-10-01", - "validTo": null, - "resources": { CPUs: 2, SDD-storage: 512 } - }, - { - "caption": "some CloudServer", - "validFrom": "2023-01-15", - "validTo": "2024-04-14", - "resources": { CPUs: 2, HDD-storage: 1024 } - }, - { - "caption": "some Whatever", - "validFrom": "2024-04-01", - "validTo": null, - "resources": { CPUs: 1, HDD-storage: 2048, SDD-storage: 512 } - } + "caption": "some ManagedServer", + "validFrom": "2022-10-01", + "validTo": null, + "resources": { + "CPU": 2, + "SDD": 512, + "extra": 42 + } + }, + { + "caption": "some CloudServer", + "validFrom": "2023-01-15", + "validTo": "2024-04-14", + "resources": { + "CPU": 2, + "HDD": 1024, + "extra": 42 + } + }, + { + "caption": "some Whatever", + "validFrom": "2024-04-01", + "validTo": null, + "resources": { + "CPU": 1, + "HDD": 2048, + "SDD": 512, + "extra": 42 + } + } ] """)); // @formatter:on @@ -109,7 +122,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup { "debitorUuid": "%s", "caption": "some new booking", - "resources": { "something": 12 }, + "resources": { "CPU": 12, "extra": 42 }, "validFrom": "2022-10-13" } """.formatted(givenDebitor.getUuid())) @@ -124,7 +137,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "caption": "some new booking", "validFrom": "2022-10-13", "validTo": null, - "resources": { "something": 12 } + "resources": { "CPU": 12 } } """)) .header("Location", startsWith("http://localhost")) @@ -162,7 +175,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "caption": "some CloudServer", "validFrom": "2023-01-15", "validTo": "2024-04-14", - "resources": { CPUs: 2, HDD-storage: 1024 } + "resources": { CPU: 2, HDD: 1024 } } """)); // @formatter:on } @@ -207,7 +220,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "caption": "some CloudServer", "validFrom": "2023-01-15", "validTo": "2024-04-14", - "resources": { CPUs: 2, HDD-storage: 1024 } + "resources": { CPU: 2, HDD: 1024 } } """)); // @formatter:on } @@ -219,7 +232,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup @Test void globalAdmin_canPatchAllUpdatablePropertiesOfBookingItem() { - final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111); + final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111, entry("something", 1)); RestAssured // @formatter:off .given() @@ -230,9 +243,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "validFrom": "2020-06-05", "validTo": "2022-12-31", "resources": { - "CPUs": "4", - "HDD_storage": null, - "SSD-storage": "4096" + "CPU": "4", + "HDD": null, + "SSD": "4096" } } """) @@ -248,8 +261,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "validFrom": "2020-06-05", "validTo": "2022-12-31", "resources": { - "CPUs": "2", - "SSD-storage": "2048" + "CPU": "4", + "SSD": "4096", + "something": 1 } } """)); // @formatter:on @@ -269,9 +283,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup void globalAdmin_canPatchJustValidToOfArbitraryBookingItem() { context.define("superuser-alex@hostsharing.net"); - final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111); + final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111, entry("something", 1)); - final var location = RestAssured // @formatter:off + RestAssured // @formatter:off .given() .header("current-user", "superuser-alex@hostsharing.net") .contentType(ContentType.JSON) @@ -292,7 +306,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup "validFrom": "2022-11-01", "validTo": "2022-12-31", "resources": { - "CPUs": 5 + "something": 1 } } """)); // @formatter:on @@ -310,7 +324,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup void globalAdmin_canNotPatchReferenceOfArbitraryBookingItem() { context.define("superuser-alex@hostsharing.net"); - final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111); + final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111, entry("something", 1)); final var location = RestAssured // @formatter:off .given() @@ -344,7 +358,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup @Test void globalAdmin_canDeleteArbitraryBookingItem() { context.define("superuser-alex@hostsharing.net"); - final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111); + final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111, entry("something", 1)); RestAssured // @formatter:off .given() @@ -362,7 +376,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup @Test void normalUser_canNotDeleteUnrelatedBookingItem() { context.define("superuser-alex@hostsharing.net"); - final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111); + final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111, entry("something", 1)); RestAssured // @formatter:off .given() @@ -378,7 +392,8 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup } } - private HsBookingItemEntity givenSomeTemporaryBookingItemForDebitorNumber(final int debitorNumber) { + private HsBookingItemEntity givenSomeTemporaryBookingItemForDebitorNumber(final int debitorNumber, + final Map.Entry resources) { return jpaAttempt.transacted(() -> { context.define("superuser-alex@hostsharing.net"); final var givenDebitor = debitorRepo.findDebitorByDebitorNumber(debitorNumber).get(0); @@ -386,7 +401,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup .uuid(UUID.randomUUID()) .debitor(givenDebitor) .caption("some test-booking") - .resources(Map.ofEntries(entry("something", 1))) + .resources(Map.ofEntries(resources)) .validity(Range.closedOpen( LocalDate.parse("2022-11-01"), LocalDate.parse("2023-03-31"))) .build(); 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 5163305f..dd3a59ee 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 @@ -1,7 +1,6 @@ package net.hostsharing.hsadminng.hs.booking.item; import io.hypersistence.utils.hibernate.type.range.Range; -import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.ArbitraryBookingResourcesJsonResource; import net.hostsharing.hsadminng.hs.booking.generated.api.v1.model.HsBookingItemPatchResource; import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity; import net.hostsharing.hsadminng.rbac.test.PatchUnitTestBase; @@ -13,11 +12,14 @@ import org.mockito.junit.jupiter.MockitoExtension; import jakarta.persistence.EntityManager; import java.time.LocalDate; +import java.util.Map; import java.util.UUID; import java.util.stream.Stream; import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntityPatcher.objectToMap; import static net.hostsharing.hsadminng.hs.office.debitor.TestHsOfficeDebitor.TEST_DEBITOR; +import static net.hostsharing.hsadminng.mapper.PatchMap.entry; +import static net.hostsharing.hsadminng.mapper.PatchMap.patchMap; import static org.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; @@ -35,15 +37,22 @@ class HsBookingItemEntityPatcherUnitTest extends PatchUnitTestBase< private static final LocalDate PATCHED_VALID_FROM = LocalDate.parse("2022-10-30"); private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31"); - private static final ArbitraryBookingResourcesJsonResource INITIAL_RESOURCES = new ArbitraryBookingResourcesJsonResource() { - Integer cpus = 1; - Integer hddStorage = 1024; - }; - private static final ArbitraryBookingResourcesJsonResource PATCHED_RESOURCES = new ArbitraryBookingResourcesJsonResource() { - Integer cpus = 2; - Integer sddStorage = 256; - Integer hddStorage = null; - }; + private static final Map INITIAL_RESOURCES = patchMap( + entry("CPU", 1), + entry("HDD", 1024), + entry("MEM", 64) + ); + private static final Map PATCH_RESOURCES = patchMap( + entry("CPU", 2), + entry("HDD", null), + entry("SDD", 256) + ); + private static final Map PATCHED_RESOURCES = patchMap( + entry("CPU", 2), + entry("SDD", 256), + entry("MEM", 64) + ); + private static final String INITIAL_CAPTION = "initial caption"; private static final String PATCHED_CAPTION = "patched caption"; @@ -90,9 +99,9 @@ class HsBookingItemEntityPatcherUnitTest extends PatchUnitTestBase< new SimpleProperty<>( "resources", HsBookingItemPatchResource::setResources, - PATCHED_RESOURCES, + PATCH_RESOURCES, HsBookingItemEntity::putResources, - objectToMap(PATCHED_RESOURCES)) + PATCHED_RESOURCES) .notNullable(), new JsonNullableProperty<>( "validfrom", 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 e1558f95..ad112896 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 @@ -157,9 +157,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup // then allTheseBookingItemsAreReturned( result, - "HsBookingItemEntity(D-1000212, [2022-10-01,), some ManagedServer, { CPUs: 2, SDD-storage: 512 })", - "HsBookingItemEntity(D-1000212, [2023-01-15,2024-04-15), some CloudServer, { CPUs: 2, HDD-storage: 1024 })", - "HsBookingItemEntity(D-1000212, [2024-04-01,), some Whatever, { CPUs: 1, HDD-storage: 2048, SDD-storage: 512 })"); + "HsBookingItemEntity(D-1000212, [2022-10-01,), some ManagedServer, { CPU: 2, SDD: 512, extra: 42 })", + "HsBookingItemEntity(D-1000212, [2023-01-15,2024-04-15), some CloudServer, { CPU: 2, HDD: 1024, extra: 42 })", + "HsBookingItemEntity(D-1000212, [2024-04-01,), some Whatever, { CPU: 1, HDD: 2048, SDD: 512, extra: 42 })"); } @Test @@ -174,9 +174,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup // then: exactlyTheseBookingItemsAreReturned( result, - "HsBookingItemEntity(D-1000111, [2022-10-01,), some ManagedServer, { CPUs: 2, SDD-storage: 512 })", - "HsBookingItemEntity(D-1000111, [2023-01-15,2024-04-15), some CloudServer, { CPUs: 2, HDD-storage: 1024 })", - "HsBookingItemEntity(D-1000111, [2024-04-01,), some Whatever, { CPUs: 1, HDD-storage: 2048, SDD-storage: 512 })"); + "HsBookingItemEntity(D-1000111, [2022-10-01,), some ManagedServer, { CPU: 2, SDD: 512, extra: 42 })", + "HsBookingItemEntity(D-1000111, [2023-01-15,2024-04-15), some CloudServer, { CPU: 2, HDD: 1024, extra: 42 })", + "HsBookingItemEntity(D-1000111, [2024-04-01,), some Whatever, { CPU: 1, HDD: 2048, SDD: 512, extra: 42 })"); } }