patchable BookingResources
This commit is contained in:
parent
3e2775a8a0
commit
3a894ed72e
@ -13,6 +13,7 @@ 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 java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.function.BiConsumer;
|
import java.util.function.BiConsumer;
|
||||||
|
|
||||||
@ -122,7 +123,9 @@ public class HsBookingItemController implements HsBookingItemsApi {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
final BiConsumer<HsBookingItemInsertResource, HsBookingItemEntity> RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
|
final BiConsumer<HsBookingItemInsertResource, HsBookingItemEntity> RESOURCE_TO_ENTITY_POSTMAPPER = (resource, entity) -> {
|
||||||
entity.setValidity(toPostgresDateRange(resource.getValidFrom(), resource.getValidTo()));
|
entity.setValidity(toPostgresDateRange(resource.getValidFrom(), resource.getValidTo()));
|
||||||
|
entity.putResources((Map<String, Object>) resource.getResources());
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ import java.io.IOException;
|
|||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
import static java.util.Optional.ofNullable;
|
import static java.util.Optional.ofNullable;
|
||||||
@ -122,6 +121,9 @@ public class HsBookingItemEntity implements Stringifyable, RbacObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void putResources(Map<String, Object> entries) {
|
public void putResources(Map<String, Object> entries) {
|
||||||
|
if ( resourcesWrapper == null ) {
|
||||||
|
resourcesWrapper = new PatchableMapWrapper(resources);
|
||||||
|
}
|
||||||
resourcesWrapper.assign(entries);
|
resourcesWrapper.assign(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
package net.hostsharing.hsadminng.hs.booking.item;
|
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.hs.booking.generated.api.v1.model.HsBookingItemPatchResource;
|
||||||
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
import net.hostsharing.hsadminng.mapper.EntityPatcher;
|
||||||
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
import net.hostsharing.hsadminng.mapper.OptionalFromJson;
|
||||||
@ -25,7 +24,7 @@ public class HsBookingItemEntityPatcher implements EntityPatcher<HsBookingItemPa
|
|||||||
OptionalFromJson.of(resource.getCaption())
|
OptionalFromJson.of(resource.getCaption())
|
||||||
.ifPresent(entity::setCaption);
|
.ifPresent(entity::setCaption);
|
||||||
Optional.ofNullable(resource.getResources())
|
Optional.ofNullable(resource.getResources())
|
||||||
.ifPresent(r -> entity.putResources(objectToMap(resource.getResources())));
|
.ifPresent(r -> entity.getResources().patch(objectToMap(resource.getResources())));
|
||||||
OptionalFromJson.of(resource.getValidFrom())
|
OptionalFromJson.of(resource.getValidFrom())
|
||||||
.ifPresent(entity::setValidFrom);
|
.ifPresent(entity::setValidFrom);
|
||||||
OptionalFromJson.of(resource.getValidTo())
|
OptionalFromJson.of(resource.getValidTo())
|
||||||
@ -33,6 +32,9 @@ public class HsBookingItemEntityPatcher implements EntityPatcher<HsBookingItemPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
static Map<String, Object> objectToMap(final Object obj) {
|
static Map<String, Object> objectToMap(final Object obj) {
|
||||||
|
if (obj instanceof Map<?, ?>) {
|
||||||
|
return toKeyValueMap(obj);
|
||||||
|
}
|
||||||
return stream(obj.getClass().getDeclaredFields())
|
return stream(obj.getClass().getDeclaredFields())
|
||||||
.map(field -> {
|
.map(field -> {
|
||||||
try {
|
try {
|
||||||
@ -53,4 +55,9 @@ public class HsBookingItemEntityPatcher implements EntityPatcher<HsBookingItemPa
|
|||||||
return map1;
|
return map1;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static Map<String, Object> toKeyValueMap(final Object obj) {
|
||||||
|
return (Map<String, Object>) obj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,13 +18,13 @@ public class PatchMap extends TreeMap<String, Object> {
|
|||||||
stream(entries).forEach(r -> put(r.getKey(), r.getValue()));
|
stream(entries).forEach(r -> put(r.getKey(), r.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// @SafeVarargs
|
@SafeVarargs
|
||||||
// public static Map<String, Object> patchMap(final ImmutablePair<String, Object>... entries) {
|
public static Map<String, Object> patchMap(final ImmutablePair<String, Object>... entries) {
|
||||||
// return new PatchMap(entries);
|
return new PatchMap(entries);
|
||||||
// }
|
}
|
||||||
//
|
|
||||||
// @NotNull
|
@NotNull
|
||||||
// public static ImmutablePair<String, Object> entry(final String key, final Object value) {
|
public static ImmutablePair<String, Object> entry(final String key, final Object value) {
|
||||||
// return new ImmutablePair<>(key, value);
|
return new ImmutablePair<>(key, value);
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,12 +4,9 @@ import org.apache.commons.lang3.tuple.ImmutablePair;
|
|||||||
|
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeMap;
|
|
||||||
|
|
||||||
import static java.util.Arrays.stream;
|
|
||||||
import static java.util.stream.Collectors.joining;
|
import static java.util.stream.Collectors.joining;
|
||||||
|
|
||||||
/** This class wraps another (usually persistent) map and
|
/** This class wraps another (usually persistent) map and
|
||||||
@ -33,6 +30,16 @@ public class PatchableMapWrapper implements Map<String, Object> {
|
|||||||
delegate.putAll(entries);
|
delegate.putAll(entries);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void patch(final Map<String, Object> patch) {
|
||||||
|
patch.forEach((key, value) -> {
|
||||||
|
if (value == null) {
|
||||||
|
remove(key);
|
||||||
|
} else {
|
||||||
|
put(key, value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "{ "
|
return "{ "
|
||||||
+ (
|
+ (
|
||||||
|
@ -18,7 +18,7 @@ components:
|
|||||||
type: string
|
type: string
|
||||||
format: date
|
format: date
|
||||||
resources:
|
resources:
|
||||||
$ref: '#/components/schemas/ArbitraryBookingResourcesJson'
|
$ref: '#/components/schemas/BookingResources'
|
||||||
required:
|
required:
|
||||||
- uuid
|
- uuid
|
||||||
- debitor
|
- debitor
|
||||||
@ -41,7 +41,7 @@ components:
|
|||||||
format: date
|
format: date
|
||||||
nullable: true
|
nullable: true
|
||||||
resources:
|
resources:
|
||||||
$ref: '#/components/schemas/ArbitraryBookingResourcesJson'
|
$ref: '#/components/schemas/BookingResources'
|
||||||
|
|
||||||
HsBookingItemInsert:
|
HsBookingItemInsert:
|
||||||
type: object
|
type: object
|
||||||
@ -64,7 +64,7 @@ components:
|
|||||||
format: date
|
format: date
|
||||||
nullable: true
|
nullable: true
|
||||||
resources:
|
resources:
|
||||||
$ref: '#/components/schemas/ArbitraryBookingResourcesJson'
|
$ref: '#/components/schemas/BookingResources'
|
||||||
required:
|
required:
|
||||||
- caption
|
- caption
|
||||||
- debitorUuid
|
- debitorUuid
|
||||||
@ -72,7 +72,53 @@ components:
|
|||||||
- resources
|
- resources
|
||||||
additionalProperties: false
|
additionalProperties: false
|
||||||
|
|
||||||
ArbitraryBookingResourcesJson:
|
BookingResourcesDoesNotWork:
|
||||||
type: object
|
type: object
|
||||||
description: An object containing arbitrary JSON
|
x-javaType: 'java.util.Map<String, Object>'
|
||||||
additionalProperties: true
|
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
|
||||||
|
|
||||||
|
@ -4,8 +4,8 @@ get:
|
|||||||
description: 'Fetch a single booking item its uuid, if visible for the current subject.'
|
description: 'Fetch a single booking item its uuid, if visible for the current subject.'
|
||||||
operationId: getBookingItemByUuid
|
operationId: getBookingItemByUuid
|
||||||
parameters:
|
parameters:
|
||||||
- $ref: './auth.yaml#/components/parameters/currentUser'
|
- $ref: 'auth.yaml#/components/parameters/currentUser'
|
||||||
- $ref: './auth.yaml#/components/parameters/assumedRoles'
|
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
||||||
- name: bookingItemUuid
|
- name: bookingItemUuid
|
||||||
in: path
|
in: path
|
||||||
required: true
|
required: true
|
||||||
@ -19,12 +19,12 @@ get:
|
|||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem'
|
$ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem'
|
||||||
|
|
||||||
"401":
|
"401":
|
||||||
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
$ref: 'error-responses.yaml#/components/responses/Unauthorized'
|
||||||
"403":
|
"403":
|
||||||
$ref: './error-responses.yaml#/components/responses/Forbidden'
|
$ref: 'error-responses.yaml#/components/responses/Forbidden'
|
||||||
|
|
||||||
patch:
|
patch:
|
||||||
tags:
|
tags:
|
||||||
@ -32,8 +32,8 @@ patch:
|
|||||||
description: 'Updates a single booking item identified by its uuid, if permitted for the current subject.'
|
description: 'Updates a single booking item identified by its uuid, if permitted for the current subject.'
|
||||||
operationId: patchBookingItem
|
operationId: patchBookingItem
|
||||||
parameters:
|
parameters:
|
||||||
- $ref: './auth.yaml#/components/parameters/currentUser'
|
- $ref: 'auth.yaml#/components/parameters/currentUser'
|
||||||
- $ref: './auth.yaml#/components/parameters/assumedRoles'
|
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
||||||
- name: bookingItemUuid
|
- name: bookingItemUuid
|
||||||
in: path
|
in: path
|
||||||
required: true
|
required: true
|
||||||
@ -44,18 +44,18 @@ patch:
|
|||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItemPatch'
|
$ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItemPatch'
|
||||||
responses:
|
responses:
|
||||||
"200":
|
"200":
|
||||||
description: OK
|
description: OK
|
||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem'
|
$ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem'
|
||||||
"401":
|
"401":
|
||||||
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
$ref: 'error-responses.yaml#/components/responses/Unauthorized'
|
||||||
"403":
|
"403":
|
||||||
$ref: './error-responses.yaml#/components/responses/Forbidden'
|
$ref: 'error-responses.yaml#/components/responses/Forbidden'
|
||||||
|
|
||||||
delete:
|
delete:
|
||||||
tags:
|
tags:
|
||||||
@ -63,8 +63,8 @@ delete:
|
|||||||
description: 'Delete a single booking item identified by its uuid, if permitted for the current subject.'
|
description: 'Delete a single booking item identified by its uuid, if permitted for the current subject.'
|
||||||
operationId: deleteBookingIemByUuid
|
operationId: deleteBookingIemByUuid
|
||||||
parameters:
|
parameters:
|
||||||
- $ref: './auth.yaml#/components/parameters/currentUser'
|
- $ref: 'auth.yaml#/components/parameters/currentUser'
|
||||||
- $ref: './auth.yaml#/components/parameters/assumedRoles'
|
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
||||||
- name: bookingItemUuid
|
- name: bookingItemUuid
|
||||||
in: path
|
in: path
|
||||||
required: true
|
required: true
|
||||||
@ -76,8 +76,8 @@ delete:
|
|||||||
"204":
|
"204":
|
||||||
description: No Content
|
description: No Content
|
||||||
"401":
|
"401":
|
||||||
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
$ref: 'error-responses.yaml#/components/responses/Unauthorized'
|
||||||
"403":
|
"403":
|
||||||
$ref: './error-responses.yaml#/components/responses/Forbidden'
|
$ref: 'error-responses.yaml#/components/responses/Forbidden'
|
||||||
"404":
|
"404":
|
||||||
$ref: './error-responses.yaml#/components/responses/NotFound'
|
$ref: 'error-responses.yaml#/components/responses/NotFound'
|
||||||
|
@ -5,8 +5,8 @@ get:
|
|||||||
- hs-booking-items
|
- hs-booking-items
|
||||||
operationId: listBookingItemsByDebitorUuid
|
operationId: listBookingItemsByDebitorUuid
|
||||||
parameters:
|
parameters:
|
||||||
- $ref: './auth.yaml#/components/parameters/currentUser'
|
- $ref: 'auth.yaml#/components/parameters/currentUser'
|
||||||
- $ref: './auth.yaml#/components/parameters/assumedRoles'
|
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
||||||
- name: debitorUuid
|
- name: debitorUuid
|
||||||
in: query
|
in: query
|
||||||
required: true
|
required: true
|
||||||
@ -22,11 +22,11 @@ get:
|
|||||||
schema:
|
schema:
|
||||||
type: array
|
type: array
|
||||||
items:
|
items:
|
||||||
$ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem'
|
$ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem'
|
||||||
"401":
|
"401":
|
||||||
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
$ref: 'error-responses.yaml#/components/responses/Unauthorized'
|
||||||
"403":
|
"403":
|
||||||
$ref: './error-responses.yaml#/components/responses/Forbidden'
|
$ref: 'error-responses.yaml#/components/responses/Forbidden'
|
||||||
|
|
||||||
post:
|
post:
|
||||||
summary: Adds a new booking item.
|
summary: Adds a new booking item.
|
||||||
@ -34,25 +34,25 @@ post:
|
|||||||
- hs-booking-items
|
- hs-booking-items
|
||||||
operationId: addBookingItem
|
operationId: addBookingItem
|
||||||
parameters:
|
parameters:
|
||||||
- $ref: './auth.yaml#/components/parameters/currentUser'
|
- $ref: 'auth.yaml#/components/parameters/currentUser'
|
||||||
- $ref: './auth.yaml#/components/parameters/assumedRoles'
|
- $ref: 'auth.yaml#/components/parameters/assumedRoles'
|
||||||
requestBody:
|
requestBody:
|
||||||
description: A JSON object describing the new booking item.
|
description: A JSON object describing the new booking item.
|
||||||
required: true
|
required: true
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '/hs-booking-item-schemas.yaml#/components/schemas/HsBookingItemInsert'
|
$ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItemInsert'
|
||||||
responses:
|
responses:
|
||||||
"201":
|
"201":
|
||||||
description: Created
|
description: Created
|
||||||
content:
|
content:
|
||||||
'application/json':
|
'application/json':
|
||||||
schema:
|
schema:
|
||||||
$ref: './hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem'
|
$ref: 'hs-booking-item-schemas.yaml#/components/schemas/HsBookingItem'
|
||||||
"401":
|
"401":
|
||||||
$ref: './error-responses.yaml#/components/responses/Unauthorized'
|
$ref: 'error-responses.yaml#/components/responses/Unauthorized'
|
||||||
"403":
|
"403":
|
||||||
$ref: './error-responses.yaml#/components/responses/Forbidden'
|
$ref: 'error-responses.yaml#/components/responses/Forbidden'
|
||||||
"409":
|
"409":
|
||||||
$ref: './error-responses.yaml#/components/responses/Conflict'
|
$ref: 'error-responses.yaml#/components/responses/Conflict'
|
||||||
|
@ -11,7 +11,7 @@ paths:
|
|||||||
# Items
|
# Items
|
||||||
|
|
||||||
/api/hs/booking/items:
|
/api/hs/booking/items:
|
||||||
$ref: "./hs-booking-items.yaml"
|
$ref: "hs-booking-items.yaml"
|
||||||
|
|
||||||
/api/hs/booking/items/{bookingItemUuid}:
|
/api/hs/booking/items/{bookingItemUuid}:
|
||||||
$ref: "./hs-booking-items-with-uuid.yaml"
|
$ref: "hs-booking-items-with-uuid.yaml"
|
||||||
|
@ -32,9 +32,9 @@ begin
|
|||||||
raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor;
|
raise notice '- using debitor (%): %', relatedDebitor.uuid, relatedDebitor;
|
||||||
insert
|
insert
|
||||||
into hs_booking_item (uuid, debitoruuid, caption, validity, resources)
|
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),
|
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', '[)'), '{ "CPUs": 2, "HDD-storage": 1024 }'::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, '[]'), '{ "CPUs": 1, "SDD-storage": 512, "HDD-storage": 2048 }'::jsonb);
|
(uuid_generate_v4(), relatedDebitor.uuid, 'some Whatever', daterange('20240401', null, '[]'), '{ "CPU": 1, "SDD": 512, "HDD": 2048, "extra": 42 }'::jsonb);
|
||||||
end; $$;
|
end; $$;
|
||||||
--//
|
--//
|
||||||
|
|
||||||
|
@ -69,23 +69,36 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
.body("", lenientlyEquals("""
|
.body("", lenientlyEquals("""
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"caption": "some ManagedServer",
|
"caption": "some ManagedServer",
|
||||||
"validFrom": "2022-10-01",
|
"validFrom": "2022-10-01",
|
||||||
"validTo": null,
|
"validTo": null,
|
||||||
"resources": { CPUs: 2, SDD-storage: 512 }
|
"resources": {
|
||||||
},
|
"CPU": 2,
|
||||||
{
|
"SDD": 512,
|
||||||
"caption": "some CloudServer",
|
"extra": 42
|
||||||
"validFrom": "2023-01-15",
|
}
|
||||||
"validTo": "2024-04-14",
|
},
|
||||||
"resources": { CPUs: 2, HDD-storage: 1024 }
|
{
|
||||||
},
|
"caption": "some CloudServer",
|
||||||
{
|
"validFrom": "2023-01-15",
|
||||||
"caption": "some Whatever",
|
"validTo": "2024-04-14",
|
||||||
"validFrom": "2024-04-01",
|
"resources": {
|
||||||
"validTo": null,
|
"CPU": 2,
|
||||||
"resources": { CPUs: 1, HDD-storage: 2048, SDD-storage: 512 }
|
"HDD": 1024,
|
||||||
}
|
"extra": 42
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"caption": "some Whatever",
|
||||||
|
"validFrom": "2024-04-01",
|
||||||
|
"validTo": null,
|
||||||
|
"resources": {
|
||||||
|
"CPU": 1,
|
||||||
|
"HDD": 2048,
|
||||||
|
"SDD": 512,
|
||||||
|
"extra": 42
|
||||||
|
}
|
||||||
|
}
|
||||||
]
|
]
|
||||||
"""));
|
"""));
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
@ -109,7 +122,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
{
|
{
|
||||||
"debitorUuid": "%s",
|
"debitorUuid": "%s",
|
||||||
"caption": "some new booking",
|
"caption": "some new booking",
|
||||||
"resources": { "something": 12 },
|
"resources": { "CPU": 12, "extra": 42 },
|
||||||
"validFrom": "2022-10-13"
|
"validFrom": "2022-10-13"
|
||||||
}
|
}
|
||||||
""".formatted(givenDebitor.getUuid()))
|
""".formatted(givenDebitor.getUuid()))
|
||||||
@ -124,7 +137,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
"caption": "some new booking",
|
"caption": "some new booking",
|
||||||
"validFrom": "2022-10-13",
|
"validFrom": "2022-10-13",
|
||||||
"validTo": null,
|
"validTo": null,
|
||||||
"resources": { "something": 12 }
|
"resources": { "CPU": 12 }
|
||||||
}
|
}
|
||||||
"""))
|
"""))
|
||||||
.header("Location", startsWith("http://localhost"))
|
.header("Location", startsWith("http://localhost"))
|
||||||
@ -162,7 +175,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
"caption": "some CloudServer",
|
"caption": "some CloudServer",
|
||||||
"validFrom": "2023-01-15",
|
"validFrom": "2023-01-15",
|
||||||
"validTo": "2024-04-14",
|
"validTo": "2024-04-14",
|
||||||
"resources": { CPUs: 2, HDD-storage: 1024 }
|
"resources": { CPU: 2, HDD: 1024 }
|
||||||
}
|
}
|
||||||
""")); // @formatter:on
|
""")); // @formatter:on
|
||||||
}
|
}
|
||||||
@ -207,7 +220,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
"caption": "some CloudServer",
|
"caption": "some CloudServer",
|
||||||
"validFrom": "2023-01-15",
|
"validFrom": "2023-01-15",
|
||||||
"validTo": "2024-04-14",
|
"validTo": "2024-04-14",
|
||||||
"resources": { CPUs: 2, HDD-storage: 1024 }
|
"resources": { CPU: 2, HDD: 1024 }
|
||||||
}
|
}
|
||||||
""")); // @formatter:on
|
""")); // @formatter:on
|
||||||
}
|
}
|
||||||
@ -219,7 +232,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
@Test
|
@Test
|
||||||
void globalAdmin_canPatchAllUpdatablePropertiesOfBookingItem() {
|
void globalAdmin_canPatchAllUpdatablePropertiesOfBookingItem() {
|
||||||
|
|
||||||
final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111);
|
final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111, entry("something", 1));
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -230,9 +243,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
"validFrom": "2020-06-05",
|
"validFrom": "2020-06-05",
|
||||||
"validTo": "2022-12-31",
|
"validTo": "2022-12-31",
|
||||||
"resources": {
|
"resources": {
|
||||||
"CPUs": "4",
|
"CPU": "4",
|
||||||
"HDD_storage": null,
|
"HDD": null,
|
||||||
"SSD-storage": "4096"
|
"SSD": "4096"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""")
|
""")
|
||||||
@ -248,8 +261,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
"validFrom": "2020-06-05",
|
"validFrom": "2020-06-05",
|
||||||
"validTo": "2022-12-31",
|
"validTo": "2022-12-31",
|
||||||
"resources": {
|
"resources": {
|
||||||
"CPUs": "2",
|
"CPU": "4",
|
||||||
"SSD-storage": "2048"
|
"SSD": "4096",
|
||||||
|
"something": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""")); // @formatter:on
|
""")); // @formatter:on
|
||||||
@ -269,9 +283,9 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
void globalAdmin_canPatchJustValidToOfArbitraryBookingItem() {
|
void globalAdmin_canPatchJustValidToOfArbitraryBookingItem() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
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()
|
.given()
|
||||||
.header("current-user", "superuser-alex@hostsharing.net")
|
.header("current-user", "superuser-alex@hostsharing.net")
|
||||||
.contentType(ContentType.JSON)
|
.contentType(ContentType.JSON)
|
||||||
@ -292,7 +306,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
"validFrom": "2022-11-01",
|
"validFrom": "2022-11-01",
|
||||||
"validTo": "2022-12-31",
|
"validTo": "2022-12-31",
|
||||||
"resources": {
|
"resources": {
|
||||||
"CPUs": 5
|
"something": 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
""")); // @formatter:on
|
""")); // @formatter:on
|
||||||
@ -310,7 +324,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
void globalAdmin_canNotPatchReferenceOfArbitraryBookingItem() {
|
void globalAdmin_canNotPatchReferenceOfArbitraryBookingItem() {
|
||||||
|
|
||||||
context.define("superuser-alex@hostsharing.net");
|
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
|
final var location = RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -344,7 +358,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
@Test
|
@Test
|
||||||
void globalAdmin_canDeleteArbitraryBookingItem() {
|
void globalAdmin_canDeleteArbitraryBookingItem() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111);
|
final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111, entry("something", 1));
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -362,7 +376,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
@Test
|
@Test
|
||||||
void normalUser_canNotDeleteUnrelatedBookingItem() {
|
void normalUser_canNotDeleteUnrelatedBookingItem() {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111);
|
final var givenBookingItem = givenSomeTemporaryBookingItemForDebitorNumber(1000111, entry("something", 1));
|
||||||
|
|
||||||
RestAssured // @formatter:off
|
RestAssured // @formatter:off
|
||||||
.given()
|
.given()
|
||||||
@ -378,7 +392,8 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private HsBookingItemEntity givenSomeTemporaryBookingItemForDebitorNumber(final int debitorNumber) {
|
private HsBookingItemEntity givenSomeTemporaryBookingItemForDebitorNumber(final int debitorNumber,
|
||||||
|
final Map.Entry<String, Integer> resources) {
|
||||||
return jpaAttempt.transacted(() -> {
|
return jpaAttempt.transacted(() -> {
|
||||||
context.define("superuser-alex@hostsharing.net");
|
context.define("superuser-alex@hostsharing.net");
|
||||||
final var givenDebitor = debitorRepo.findDebitorByDebitorNumber(debitorNumber).get(0);
|
final var givenDebitor = debitorRepo.findDebitorByDebitorNumber(debitorNumber).get(0);
|
||||||
@ -386,7 +401,7 @@ class HsBookingItemControllerAcceptanceTest extends ContextBasedTestWithCleanup
|
|||||||
.uuid(UUID.randomUUID())
|
.uuid(UUID.randomUUID())
|
||||||
.debitor(givenDebitor)
|
.debitor(givenDebitor)
|
||||||
.caption("some test-booking")
|
.caption("some test-booking")
|
||||||
.resources(Map.ofEntries(entry("something", 1)))
|
.resources(Map.ofEntries(resources))
|
||||||
.validity(Range.closedOpen(
|
.validity(Range.closedOpen(
|
||||||
LocalDate.parse("2022-11-01"), LocalDate.parse("2023-03-31")))
|
LocalDate.parse("2022-11-01"), LocalDate.parse("2023-03-31")))
|
||||||
.build();
|
.build();
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package net.hostsharing.hsadminng.hs.booking.item;
|
package net.hostsharing.hsadminng.hs.booking.item;
|
||||||
|
|
||||||
import io.hypersistence.utils.hibernate.type.range.Range;
|
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.booking.generated.api.v1.model.HsBookingItemPatchResource;
|
||||||
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
import net.hostsharing.hsadminng.hs.office.debitor.HsOfficeDebitorEntity;
|
||||||
import net.hostsharing.hsadminng.rbac.test.PatchUnitTestBase;
|
import net.hostsharing.hsadminng.rbac.test.PatchUnitTestBase;
|
||||||
@ -13,11 +12,14 @@ import org.mockito.junit.jupiter.MockitoExtension;
|
|||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static net.hostsharing.hsadminng.hs.booking.item.HsBookingItemEntityPatcher.objectToMap;
|
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.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.junit.jupiter.api.TestInstance.Lifecycle.PER_CLASS;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
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_FROM = LocalDate.parse("2022-10-30");
|
||||||
private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31");
|
private static final LocalDate PATCHED_VALID_TO = LocalDate.parse("2022-12-31");
|
||||||
|
|
||||||
private static final ArbitraryBookingResourcesJsonResource INITIAL_RESOURCES = new ArbitraryBookingResourcesJsonResource() {
|
private static final Map<String, Object> INITIAL_RESOURCES = patchMap(
|
||||||
Integer cpus = 1;
|
entry("CPU", 1),
|
||||||
Integer hddStorage = 1024;
|
entry("HDD", 1024),
|
||||||
};
|
entry("MEM", 64)
|
||||||
private static final ArbitraryBookingResourcesJsonResource PATCHED_RESOURCES = new ArbitraryBookingResourcesJsonResource() {
|
);
|
||||||
Integer cpus = 2;
|
private static final Map<String, Object> PATCH_RESOURCES = patchMap(
|
||||||
Integer sddStorage = 256;
|
entry("CPU", 2),
|
||||||
Integer hddStorage = null;
|
entry("HDD", null),
|
||||||
};
|
entry("SDD", 256)
|
||||||
|
);
|
||||||
|
private static final Map<String, Object> PATCHED_RESOURCES = patchMap(
|
||||||
|
entry("CPU", 2),
|
||||||
|
entry("SDD", 256),
|
||||||
|
entry("MEM", 64)
|
||||||
|
);
|
||||||
|
|
||||||
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";
|
||||||
|
|
||||||
@ -90,9 +99,9 @@ class HsBookingItemEntityPatcherUnitTest extends PatchUnitTestBase<
|
|||||||
new SimpleProperty<>(
|
new SimpleProperty<>(
|
||||||
"resources",
|
"resources",
|
||||||
HsBookingItemPatchResource::setResources,
|
HsBookingItemPatchResource::setResources,
|
||||||
PATCHED_RESOURCES,
|
PATCH_RESOURCES,
|
||||||
HsBookingItemEntity::putResources,
|
HsBookingItemEntity::putResources,
|
||||||
objectToMap(PATCHED_RESOURCES))
|
PATCHED_RESOURCES)
|
||||||
.notNullable(),
|
.notNullable(),
|
||||||
new JsonNullableProperty<>(
|
new JsonNullableProperty<>(
|
||||||
"validfrom",
|
"validfrom",
|
||||||
|
@ -157,9 +157,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
|
|||||||
// then
|
// then
|
||||||
allTheseBookingItemsAreReturned(
|
allTheseBookingItemsAreReturned(
|
||||||
result,
|
result,
|
||||||
"HsBookingItemEntity(D-1000212, [2022-10-01,), some ManagedServer, { CPUs: 2, 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, { CPUs: 2, HDD-storage: 1024 })",
|
"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, { CPUs: 1, HDD-storage: 2048, SDD-storage: 512 })");
|
"HsBookingItemEntity(D-1000212, [2024-04-01,), some Whatever, { CPU: 1, HDD: 2048, SDD: 512, extra: 42 })");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -174,9 +174,9 @@ class HsBookingItemRepositoryIntegrationTest extends ContextBasedTestWithCleanup
|
|||||||
// then:
|
// then:
|
||||||
exactlyTheseBookingItemsAreReturned(
|
exactlyTheseBookingItemsAreReturned(
|
||||||
result,
|
result,
|
||||||
"HsBookingItemEntity(D-1000111, [2022-10-01,), some ManagedServer, { CPUs: 2, 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, { CPUs: 2, HDD-storage: 1024 })",
|
"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, { CPUs: 1, HDD-storage: 2048, SDD-storage: 512 })");
|
"HsBookingItemEntity(D-1000111, [2024-04-01,), some Whatever, { CPU: 1, HDD: 2048, SDD: 512, extra: 42 })");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user