From 10516d5cf831478958149523deaa145d668c6b5d Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 26 May 2025 12:16:18 +0200 Subject: [PATCH 1/3] fix product order creation with ref offering --- .../product-ordering-management/api.json | 19 ++++++++++- .../tmforum/common/domain/ReferenceValue.java | 8 +++++ .../productordering/ProductOrderingApiIT.java | 33 ++++++++++++++++--- .../product/ProductOfferingRefValue.java | 6 +++- 4 files changed, 59 insertions(+), 7 deletions(-) diff --git a/api/tm-forum/product-ordering-management/api.json b/api/tm-forum/product-ordering-management/api.json index bf2c53c0..8d32f687 100644 --- a/api/tm-forum/product-ordering-management/api.json +++ b/api/tm-forum/product-ordering-management/api.json @@ -2387,6 +2387,23 @@ "id" ] }, + "ProductOfferingRefValue": { + "type": "object", + "description": "ProductOffering reference value. A product offering represents entities that are orderable from the provider of the catalog, this resource includes pricing information.", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier of a related entity." + }, + "href": { + "type": "string", + "description": "Reference of the related entity." + } + }, + "required": [ + "id" + ] + }, "ProductOrder": { "type": "object", "description": "A Product Order is a type of order which can be used to place an order between a customer and a service provider or between a service provider and a partner and vice versa,", @@ -2842,7 +2859,7 @@ "$ref": "#/definitions/ProductRefOrValue" }, "productOffering": { - "$ref": "#/definitions/ProductOfferingRef" + "$ref": "#/definitions/ProductOfferingRefValue" }, "productOfferingQualificationItem": { "$ref": "#/definitions/ProductOfferingQualificationItemRef" diff --git a/common/src/main/java/org/fiware/tmforum/common/domain/ReferenceValue.java b/common/src/main/java/org/fiware/tmforum/common/domain/ReferenceValue.java index afa66c19..97be2caa 100644 --- a/common/src/main/java/org/fiware/tmforum/common/domain/ReferenceValue.java +++ b/common/src/main/java/org/fiware/tmforum/common/domain/ReferenceValue.java @@ -6,22 +6,30 @@ import org.fiware.tmforum.common.validation.ReferencedEntity; +import com.fasterxml.jackson.annotation.JsonGetter; +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonProperty; + import lombok.Data; +import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @Data @NoArgsConstructor +@EqualsAndHashCode public class ReferenceValue implements ReferencedEntity { private URI id; private URI href; @Override + @JsonIgnore public List getReferencedTypes() { return new ArrayList<>(List.of("")); } @Override + @JsonGetter("id") public URI getEntityId() { return this.id; } diff --git a/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java b/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java index 92fb1c02..b14bacf8 100644 --- a/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java +++ b/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java @@ -91,7 +91,7 @@ public void createProductOrder201() throws Exception { when(clock.instant()).thenReturn(now); HttpResponse productVOHttpResponse = callAndCatch( - () -> productOrderApiTestClient.createProductOrder(null, productCreateVO)); + () -> productOrderApiTestClient.createProductOrder(null, productCreateVO)); assertEquals(HttpStatus.CREATED, productVOHttpResponse.getStatus(), message); String rfId = productVOHttpResponse.body().getId(); expectedProduct.setId(rfId); @@ -235,6 +235,30 @@ private static Stream provideValidProducts() { .productOrderItem(List.of(productOrderItemVO)) .billingAccount(null))); + ProductOrderItemVO productOrderItemOfferingVO = ProductOrderItemVOTestExample.build().atSchemaLocation(null) + .action(OrderItemActionTypeVO.ADD) + .id("urn:order-item") + .appointment(null) + .billingAccount(null) + .product(null) + .productOffering(ProductOfferingRefValueVOTestExample.build().id("urn:product-offering")) + .productOfferingQualificationItem(null) + .quoteItem(null); + + /** + * TODO: this scenario needs a entity with id "urn:product-offering" + * created in the testing context to pass + * + * testEntries.add( + * Arguments.of("A product order with an order item with product offering should have been created.", + * ProductOrderCreateVOTestExample.build().atSchemaLocation(null) + * .productOrderItem(List.of(productOrderItemOfferingVO)) + * .billingAccount(null), + * ProductOrderVOTestExample.build().atSchemaLocation(null) + * .productOrderItem(List.of(productOrderItemOfferingVO)) + * .billingAccount(null))); + */ + CharacteristicVO characteristicVO = CharacteristicVOTestExample.build().atSchemaLocation(null) .name("Characteristic Name") .value("Value"); @@ -426,10 +450,10 @@ private static Stream>> provideInvalidOrde .appointment(null)))); invalidItems.add(new ArgumentPair<>("An order item with an invalid productOffering should not be accepted.", - List.of(ProductOrderItemVOTestExample.build().atSchemaLocation(null) + List.of(ProductOrderItemVOTestExample.build() .billingAccount(null) .product(null) - .productOffering(ProductOfferingRefVOTestExample.build().atSchemaLocation(null)) + .productOffering(ProductOfferingRefValueVOTestExample.build()) .productOfferingQualificationItem(null) .quoteItem(null) .appointment(null)))); @@ -438,7 +462,7 @@ private static Stream>> provideInvalidOrde .billingAccount(null) .product(null) .productOffering( - ProductOfferingRefVOTestExample.build().atSchemaLocation(null).id("urn:ngsi-ld:product-offering:non-existent")) + ProductOfferingRefValueVOTestExample.build().id("urn:ngsi-ld:product-offering:non-existent")) .productOfferingQualificationItem(null) .quoteItem(null) .appointment(null)))); @@ -1550,4 +1574,3 @@ protected String getEntityType() { return ProductOrder.TYPE_PRODUCT_ORDER; } } - diff --git a/product-shared-models/src/main/java/org/fiware/tmforum/product/ProductOfferingRefValue.java b/product-shared-models/src/main/java/org/fiware/tmforum/product/ProductOfferingRefValue.java index df44ba71..d8388abb 100644 --- a/product-shared-models/src/main/java/org/fiware/tmforum/product/ProductOfferingRefValue.java +++ b/product-shared-models/src/main/java/org/fiware/tmforum/product/ProductOfferingRefValue.java @@ -4,12 +4,16 @@ import java.util.List; import org.fiware.tmforum.common.domain.ReferenceValue; +import io.github.wistefan.mapping.annotations.MappingEnabled; +import lombok.EqualsAndHashCode; +@EqualsAndHashCode(callSuper = true) +@MappingEnabled(entityType = ProductOffering.TYPE_PRODUCT_OFFERING) public class ProductOfferingRefValue extends ReferenceValue { @Override public List getReferencedTypes() { // Jackson throws Unsupported Operation exeception in this list - return new ArrayList<>(List.of("product-offering")); + return new ArrayList<>(List.of(ProductOffering.TYPE_PRODUCT_OFFERING)); } } From 84adee692114c6641b473dbc411c884701e8b7d7 Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 26 May 2025 18:48:16 +0200 Subject: [PATCH 2/3] applied PR suggestions and reverted some changes --- .../product-ordering-management/api.json | 19 +----- .../tmforum/common/domain/RefEntity.java | 5 +- .../tmforum/common/domain/ReferenceValue.java | 4 -- .../productordering/TMForumMapper.java | 5 +- .../productordering/ProductOrderingApiIT.java | 59 +++++++++++++------ 5 files changed, 48 insertions(+), 44 deletions(-) diff --git a/api/tm-forum/product-ordering-management/api.json b/api/tm-forum/product-ordering-management/api.json index 8d32f687..bf2c53c0 100644 --- a/api/tm-forum/product-ordering-management/api.json +++ b/api/tm-forum/product-ordering-management/api.json @@ -2387,23 +2387,6 @@ "id" ] }, - "ProductOfferingRefValue": { - "type": "object", - "description": "ProductOffering reference value. A product offering represents entities that are orderable from the provider of the catalog, this resource includes pricing information.", - "properties": { - "id": { - "type": "string", - "description": "Unique identifier of a related entity." - }, - "href": { - "type": "string", - "description": "Reference of the related entity." - } - }, - "required": [ - "id" - ] - }, "ProductOrder": { "type": "object", "description": "A Product Order is a type of order which can be used to place an order between a customer and a service provider or between a service provider and a partner and vice versa,", @@ -2859,7 +2842,7 @@ "$ref": "#/definitions/ProductRefOrValue" }, "productOffering": { - "$ref": "#/definitions/ProductOfferingRefValue" + "$ref": "#/definitions/ProductOfferingRef" }, "productOfferingQualificationItem": { "$ref": "#/definitions/ProductOfferingQualificationItemRef" diff --git a/common/src/main/java/org/fiware/tmforum/common/domain/RefEntity.java b/common/src/main/java/org/fiware/tmforum/common/domain/RefEntity.java index 95c9b9c7..94217428 100644 --- a/common/src/main/java/org/fiware/tmforum/common/domain/RefEntity.java +++ b/common/src/main/java/org/fiware/tmforum/common/domain/RefEntity.java @@ -1,6 +1,6 @@ package org.fiware.tmforum.common.domain; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonGetter; import io.github.wistefan.mapping.annotations.AttributeGetter; import io.github.wistefan.mapping.annotations.AttributeSetter; import io.github.wistefan.mapping.annotations.AttributeType; @@ -46,7 +46,8 @@ protected RefEntity(URI id) { } @Override + @JsonGetter("id") public URI getEntityId() { - return getId(); + return this.id; } } diff --git a/common/src/main/java/org/fiware/tmforum/common/domain/ReferenceValue.java b/common/src/main/java/org/fiware/tmforum/common/domain/ReferenceValue.java index 97be2caa..44a052a9 100644 --- a/common/src/main/java/org/fiware/tmforum/common/domain/ReferenceValue.java +++ b/common/src/main/java/org/fiware/tmforum/common/domain/ReferenceValue.java @@ -7,9 +7,6 @@ import org.fiware.tmforum.common.validation.ReferencedEntity; import com.fasterxml.jackson.annotation.JsonGetter; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonProperty; - import lombok.Data; import lombok.EqualsAndHashCode; import lombok.NoArgsConstructor; @@ -23,7 +20,6 @@ public class ReferenceValue implements ReferencedEntity { private URI href; @Override - @JsonIgnore public List getReferencedTypes() { return new ArrayList<>(List.of("")); } diff --git a/product-ordering-management/src/main/java/org/fiware/tmforum/productordering/TMForumMapper.java b/product-ordering-management/src/main/java/org/fiware/tmforum/productordering/TMForumMapper.java index 010d006e..e0b7c34e 100644 --- a/product-ordering-management/src/main/java/org/fiware/tmforum/productordering/TMForumMapper.java +++ b/product-ordering-management/src/main/java/org/fiware/tmforum/productordering/TMForumMapper.java @@ -7,6 +7,7 @@ import org.fiware.tmforum.common.mapping.BaseMapper; import org.fiware.tmforum.common.mapping.IdHelper; import org.fiware.tmforum.product.Characteristic; +import org.fiware.tmforum.product.ProductOffering; import org.fiware.tmforum.productordering.domain.*; import org.fiware.tmforum.resource.Note; import org.mapstruct.Mapper; @@ -95,6 +96,8 @@ public abstract class TMForumMapper extends BaseMapper { @Mapping(target = "value", source = "charValue") public abstract CharacteristicVO map(Characteristic characteristic); + public abstract ProductOffering map(ProductOfferingRefVO productOfferingRefVO); + public URL map(String value) { if (value == null) { return null; @@ -127,5 +130,3 @@ public String mapFromURI(URI value) { return value.toString(); } } - - diff --git a/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java b/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java index b14bacf8..05db7301 100644 --- a/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java +++ b/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java @@ -1,6 +1,7 @@ package org.fiware.tmforum.productordering; import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.wistefan.mapping.JavaObjectMapper; import io.micronaut.http.HttpResponse; import io.micronaut.http.HttpStatus; import io.micronaut.test.annotation.MockBean; @@ -32,6 +33,8 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import org.fiware.ngsi.model.EntityVO; +import org.fiware.tmforum.product.ProductOffering; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Matchers.any; @@ -45,10 +48,15 @@ public class ProductOrderingApiIT extends AbstractApiIT implements ProductOrderA private String message; private String fieldsParameter; + private final EntitiesApiClient entitiesApiClient; + private final JavaObjectMapper javaObjectMapper; + private final TMForumMapper tmForumMapper; private ProductOrderCreateVO productCreateVO; private ProductOrderUpdateVO productUpdateVO; private ProductOrderVO expectedProduct; + private boolean isSetupDone = false; + private Clock clock = mock(Clock.class); @MockBean(Clock.class) @@ -68,11 +76,25 @@ public TMForumEventHandler eventHandler() { public ProductOrderingApiIT(ProductOrderApiTestClient productOrderApiTestClient, EntitiesApiClient entitiesApiClient, + JavaObjectMapper javaObjectMapper, + TMForumMapper tmForumMapper, ObjectMapper objectMapper, GeneralProperties generalProperties) { super(entitiesApiClient, objectMapper, generalProperties); this.productOrderApiTestClient = productOrderApiTestClient; + this.entitiesApiClient = entitiesApiClient; + this.javaObjectMapper = javaObjectMapper; + this.tmForumMapper = tmForumMapper; + } + + public void createProductOffering(ProductOffering productOfferingVO) { + EntityVO entityVO = javaObjectMapper.toEntityVO(productOfferingVO); + entitiesApiClient.createEntity(entityVO, null).block(); } + public void setup() { + createProductOffering(tmForumMapper.map(ProductOfferingRefVOTestExample.build().atSchemaLocation(null).id("test"))); + } + @ParameterizedTest @MethodSource("provideValidProducts") public void createProductOrder201(String message, ProductOrderCreateVO productCreateVO, @@ -81,6 +103,12 @@ public void createProductOrder201(String message, ProductOrderCreateVO productCr this.message = message; this.productCreateVO = productCreateVO; this.expectedProduct = expectedProduct; + + if (!isSetupDone) { + setup(); + isSetupDone = true; + } + createProductOrder201(); } @@ -91,7 +119,7 @@ public void createProductOrder201() throws Exception { when(clock.instant()).thenReturn(now); HttpResponse productVOHttpResponse = callAndCatch( - () -> productOrderApiTestClient.createProductOrder(null, productCreateVO)); + () -> productOrderApiTestClient.createProductOrder(null, productCreateVO)); assertEquals(HttpStatus.CREATED, productVOHttpResponse.getStatus(), message); String rfId = productVOHttpResponse.body().getId(); expectedProduct.setId(rfId); @@ -241,23 +269,18 @@ private static Stream provideValidProducts() { .appointment(null) .billingAccount(null) .product(null) - .productOffering(ProductOfferingRefValueVOTestExample.build().id("urn:product-offering")) + .productOffering(ProductOfferingRefVOTestExample.build().atSchemaLocation(null).id("urn:ngsi-ld:product-offering:test")) .productOfferingQualificationItem(null) .quoteItem(null); - /** - * TODO: this scenario needs a entity with id "urn:product-offering" - * created in the testing context to pass - * - * testEntries.add( - * Arguments.of("A product order with an order item with product offering should have been created.", - * ProductOrderCreateVOTestExample.build().atSchemaLocation(null) - * .productOrderItem(List.of(productOrderItemOfferingVO)) - * .billingAccount(null), - * ProductOrderVOTestExample.build().atSchemaLocation(null) - * .productOrderItem(List.of(productOrderItemOfferingVO)) - * .billingAccount(null))); - */ + testEntries.add( + Arguments.of("A product order with an order item with product offering should have been created.", + ProductOrderCreateVOTestExample.build().atSchemaLocation(null) + .productOrderItem(List.of(productOrderItemOfferingVO)) + .billingAccount(null), + ProductOrderVOTestExample.build().atSchemaLocation(null) + .productOrderItem(List.of(productOrderItemOfferingVO)) + .billingAccount(null))); CharacteristicVO characteristicVO = CharacteristicVOTestExample.build().atSchemaLocation(null) .name("Characteristic Name") @@ -450,10 +473,10 @@ private static Stream>> provideInvalidOrde .appointment(null)))); invalidItems.add(new ArgumentPair<>("An order item with an invalid productOffering should not be accepted.", - List.of(ProductOrderItemVOTestExample.build() + List.of(ProductOrderItemVOTestExample.build().atSchemaLocation(null) .billingAccount(null) .product(null) - .productOffering(ProductOfferingRefValueVOTestExample.build()) + .productOffering(ProductOfferingRefVOTestExample.build().atSchemaLocation(null)) .productOfferingQualificationItem(null) .quoteItem(null) .appointment(null)))); @@ -462,7 +485,7 @@ private static Stream>> provideInvalidOrde .billingAccount(null) .product(null) .productOffering( - ProductOfferingRefValueVOTestExample.build().id("urn:ngsi-ld:product-offering:non-existent")) + ProductOfferingRefVOTestExample.build().atSchemaLocation(null).id("urn:ngsi-ld:product-offering:non-existent")) .productOfferingQualificationItem(null) .quoteItem(null) .appointment(null)))); From 518ddc13319292cedc57561865dc11f5fa089aa8 Mon Sep 17 00:00:00 2001 From: Marcos Date: Mon, 26 May 2025 20:55:09 +0200 Subject: [PATCH 3/3] fix failing tests --- .../domain/ProductOrderItem.java | 4 +-- .../productordering/ProductOrderingApiIT.java | 26 ++++++++++++------- .../productordering/TestSetupTracker.java | 24 +++++++++++++++++ 3 files changed, 42 insertions(+), 12 deletions(-) create mode 100644 product-ordering-management/src/test/java/org/fiware/tmforum/productordering/TestSetupTracker.java diff --git a/product-ordering-management/src/main/java/org/fiware/tmforum/productordering/domain/ProductOrderItem.java b/product-ordering-management/src/main/java/org/fiware/tmforum/productordering/domain/ProductOrderItem.java index 035497ab..edeaba89 100644 --- a/product-ordering-management/src/main/java/org/fiware/tmforum/productordering/domain/ProductOrderItem.java +++ b/product-ordering-management/src/main/java/org/fiware/tmforum/productordering/domain/ProductOrderItem.java @@ -4,7 +4,7 @@ import org.fiware.tmforum.common.domain.Entity; import org.fiware.tmforum.common.domain.ReferenceValue; import org.fiware.tmforum.product.ProductOfferingQualificationItemRef; -import org.fiware.tmforum.product.ProductOfferingRefValue; +import org.fiware.tmforum.product.ProductOfferingRef; import org.fiware.tmforum.product.ProductRefOrValue; import java.util.List; @@ -22,7 +22,7 @@ public class ProductOrderItem extends Entity { private List itemTotalPrice; private List payment; private ProductRefOrValue product; - private ProductOfferingRefValue productOffering; + private ProductOfferingRef productOffering; private ProductOfferingQualificationItemRef productOfferingQualificationItem; private List productOrderItem; private List productOrderItemRelationship; diff --git a/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java b/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java index 05db7301..4bc7a037 100644 --- a/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java +++ b/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/ProductOrderingApiIT.java @@ -18,6 +18,7 @@ import org.fiware.tmforum.productordering.domain.ProductOrder; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.Arguments; import org.junit.jupiter.params.provider.MethodSource; @@ -54,8 +55,7 @@ public class ProductOrderingApiIT extends AbstractApiIT implements ProductOrderA private ProductOrderCreateVO productCreateVO; private ProductOrderUpdateVO productUpdateVO; private ProductOrderVO expectedProduct; - - private boolean isSetupDone = false; + private final TestSetupTracker setupTracker; private Clock clock = mock(Clock.class); @@ -78,12 +78,15 @@ public ProductOrderingApiIT(ProductOrderApiTestClient productOrderApiTestClient, EntitiesApiClient entitiesApiClient, JavaObjectMapper javaObjectMapper, TMForumMapper tmForumMapper, - ObjectMapper objectMapper, GeneralProperties generalProperties) { + ObjectMapper objectMapper, + GeneralProperties generalProperties, + TestSetupTracker setupTracker) { super(entitiesApiClient, objectMapper, generalProperties); this.productOrderApiTestClient = productOrderApiTestClient; this.entitiesApiClient = entitiesApiClient; this.javaObjectMapper = javaObjectMapper; this.tmForumMapper = tmForumMapper; + this.setupTracker = setupTracker; } public void createProductOffering(ProductOffering productOfferingVO) { @@ -95,6 +98,14 @@ public void setup() { createProductOffering(tmForumMapper.map(ProductOfferingRefVOTestExample.build().atSchemaLocation(null).id("test"))); } + @BeforeEach + public void conditionalSetup() { + if (!setupTracker.isSetupDone()) { + setup(); + setupTracker.markSetupDone(); + } + } + @ParameterizedTest @MethodSource("provideValidProducts") public void createProductOrder201(String message, ProductOrderCreateVO productCreateVO, @@ -103,12 +114,7 @@ public void createProductOrder201(String message, ProductOrderCreateVO productCr this.message = message; this.productCreateVO = productCreateVO; this.expectedProduct = expectedProduct; - - if (!isSetupDone) { - setup(); - isSetupDone = true; - } - + createProductOrder201(); } @@ -119,7 +125,7 @@ public void createProductOrder201() throws Exception { when(clock.instant()).thenReturn(now); HttpResponse productVOHttpResponse = callAndCatch( - () -> productOrderApiTestClient.createProductOrder(null, productCreateVO)); + () -> productOrderApiTestClient.createProductOrder(null, productCreateVO)); assertEquals(HttpStatus.CREATED, productVOHttpResponse.getStatus(), message); String rfId = productVOHttpResponse.body().getId(); expectedProduct.setId(rfId); diff --git a/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/TestSetupTracker.java b/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/TestSetupTracker.java new file mode 100644 index 00000000..d0e31234 --- /dev/null +++ b/product-ordering-management/src/test/java/org/fiware/tmforum/productordering/TestSetupTracker.java @@ -0,0 +1,24 @@ +package org.fiware.tmforum.productordering; + +import jakarta.inject.Singleton; + +/** + * Allows to run a setup function only once in a multi-thread testing scenario + */ + +@Singleton +public class TestSetupTracker { + private boolean setupDone = false; + + public synchronized boolean isSetupDone() { + return setupDone; + } + + public synchronized void markSetupDone() { + this.setupDone = true; + } + + public synchronized void reset() { + this.setupDone = false; + } +}