From 867c630f1b0053dadcdb9a433e7632f754633555 Mon Sep 17 00:00:00 2001 From: Jan Kreutzfeld Date: Wed, 19 Jul 2023 22:09:11 +0200 Subject: [PATCH 1/5] fix(recursion): Fix BPN handling in delegates The BPN is now correctly taken from the submodels and passed down the recursive chain instead of always taken from the JobParameter. If no BPN is available, a Tombstone is created now as well. --- .../job/AASRecursiveJobHandler.java | 5 +- .../aaswrapper/job/AASTransferProcess.java | 5 +- .../job/AASTransferProcessManager.java | 3 +- .../irs/aaswrapper/job/ItemDataRequest.java | 7 +- .../job/delegate/AbstractDelegate.java | 12 +++- .../aaswrapper/job/delegate/BpdmDelegate.java | 7 +- .../job/delegate/DigitalTwinDelegate.java | 7 +- .../job/delegate/RelationshipDelegate.java | 64 ++++++++++++------- .../job/delegate/SubmodelDelegate.java | 16 ++++- .../configuration/RegistryConfiguration.java | 20 ------ .../tractusx/irs/IrsFunctionalTest.java | 22 +++++-- .../job/AASTransferProcessManagerTest.java | 12 ++-- .../job/delegate/BpdmDelegateTest.java | 21 +++--- .../job/delegate/DigitalTwinDelegateTest.java | 15 +++-- .../delegate/RelationshipDelegateTest.java | 11 +++- .../job/delegate/SubmodelDelegateTest.java | 18 ++++-- ...rsItemGraphQueryServiceSpringBootTest.java | 17 +++-- .../irs/edc/client/EdcSubmodelClient.java | 2 +- .../tractusx/irs/component/Tombstone.java | 12 +++- 19 files changed, 169 insertions(+), 107 deletions(-) diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASRecursiveJobHandler.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASRecursiveJobHandler.java index c997a7aac4..d79b069e0a 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASRecursiveJobHandler.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASRecursiveJobHandler.java @@ -25,6 +25,7 @@ import java.util.stream.Stream; import lombok.extern.slf4j.Slf4j; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.connector.job.MultiTransferJob; import org.eclipse.tractusx.irs.connector.job.RecursiveJobHandler; @@ -44,7 +45,9 @@ public AASRecursiveJobHandler(final TreeRecursiveLogic logic) { public Stream initiate(final MultiTransferJob job) { log.info("Initiating request for job {}", job.getJobIdString()); final var partId = job.getGlobalAssetId(); - final var dataRequest = ItemDataRequest.rootNode(partId); + final var bpn = job.getJobParameter().getBpn(); + final var dataRequest = ItemDataRequest.rootNode( + PartChainIdentificationKey.builder().globalAssetId(partId).bpn(bpn).build()); return Stream.of(dataRequest); } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcess.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcess.java index 109a4704ba..f64d245675 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcess.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcess.java @@ -29,6 +29,7 @@ import lombok.Getter; import lombok.NoArgsConstructor; import lombok.ToString; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.connector.job.TransferProcess; /** @@ -40,12 +41,12 @@ @ToString public class AASTransferProcess implements TransferProcess { - private final List idsToProcess = new ArrayList<>(); + private final List idsToProcess = new ArrayList<>(); @SuppressWarnings("PMD.ShortVariable") private String id; private Integer depth; - public void addIdsToProcess(final List childIds) { + public void addIdsToProcess(final List childIds) { idsToProcess.addAll(childIds); } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcessManager.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcessManager.java index e394066f32..4d41531843 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcessManager.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcessManager.java @@ -34,6 +34,7 @@ import org.eclipse.tractusx.irs.common.persistence.BlobPersistence; import org.eclipse.tractusx.irs.common.persistence.BlobPersistenceException; import org.eclipse.tractusx.irs.component.JobParameter; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.connector.job.ResponseStatus; import org.eclipse.tractusx.irs.connector.job.TransferInitiateResponse; import org.eclipse.tractusx.irs.connector.job.TransferProcessManager; @@ -80,7 +81,7 @@ private Runnable getRunnable(final ItemDataRequest dataRequest, return () -> { final AASTransferProcess aasTransferProcess = new AASTransferProcess(processId, dataRequest.getDepth()); - final String itemId = dataRequest.getItemId(); + final PartChainIdentificationKey itemId = dataRequest.getItemId(); log.info("Starting processing Digital Twin Registry with itemId {}", itemId); final ItemContainer itemContainer = abstractDelegate.process(ItemContainer.builder(), jobData, diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/ItemDataRequest.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/ItemDataRequest.java index c55dedbfe8..9c20123fe5 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/ItemDataRequest.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/ItemDataRequest.java @@ -23,6 +23,7 @@ package org.eclipse.tractusx.irs.aaswrapper.job; import lombok.Value; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.connector.job.DataRequest; /** @@ -31,14 +32,14 @@ @Value public class ItemDataRequest implements DataRequest { - private final String itemId; + private final PartChainIdentificationKey itemId; private final Integer depth; - public static ItemDataRequest rootNode(final String itemId) { + public static ItemDataRequest rootNode(final PartChainIdentificationKey itemId) { return new ItemDataRequest(itemId, 0); } - public static ItemDataRequest nextDepthNode(final String itemId, final Integer currentDepth) { + public static ItemDataRequest nextDepthNode(final PartChainIdentificationKey itemId, final Integer currentDepth) { return new ItemDataRequest(itemId, currentDepth + 1); } } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/AbstractDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/AbstractDelegate.java index 201b504304..6d62200fd4 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/AbstractDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/AbstractDelegate.java @@ -35,6 +35,7 @@ import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; import org.eclipse.tractusx.irs.component.JobParameter; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.assetadministrationshell.Endpoint; import org.eclipse.tractusx.irs.edc.client.EdcSubmodelFacade; import org.eclipse.tractusx.irs.edc.client.ItemNotFoundInCatalogException; @@ -62,7 +63,7 @@ public abstract class AbstractDelegate { * and Tombstones (if requests fail). */ public abstract ItemContainer process(ItemContainer.ItemContainerBuilder itemContainerBuilder, JobParameter jobData, - AASTransferProcess aasTransferProcess, String itemId); + AASTransferProcess aasTransferProcess, PartChainIdentificationKey itemId); /** * Delegates processing to next step if exists or returns filled {@link ItemContainer} @@ -75,7 +76,8 @@ public abstract ItemContainer process(ItemContainer.ItemContainerBuilder itemCon * @return item container with filled data */ protected ItemContainer next(final ItemContainer.ItemContainerBuilder itemContainerBuilder, - final JobParameter jobData, final AASTransferProcess aasTransferProcess, final String itemId) { + final JobParameter jobData, final AASTransferProcess aasTransferProcess, + final PartChainIdentificationKey itemId) { if (this.nextStep != null) { return this.nextStep.process(itemContainerBuilder, jobData, aasTransferProcess, itemId); } @@ -91,7 +93,11 @@ protected String requestSubmodelAsString(final EdcSubmodelFacade submodelFacade, for (final String connectorEndpoint : connectorEndpoints) { addSubmodelToList(submodelFacade, endpoint, submodelPayload, connectorEndpoint); } - return submodelPayload.stream().findFirst().orElseThrow(); + return submodelPayload.stream() + .findFirst() + .orElseThrow(() -> new EdcClientException(String.format( + "Called %s connectorEndpoints but did not get any submodels. Connectors: '%s'", + connectorEndpoints.size(), String.join(", ", connectorEndpoints)))); } private void addSubmodelToList(final EdcSubmodelFacade submodelFacade, final Endpoint endpoint, diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/BpdmDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/BpdmDelegate.java index 0e084faadd..dfe391c949 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/BpdmDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/BpdmDelegate.java @@ -31,6 +31,7 @@ import org.eclipse.tractusx.irs.bpdm.BpdmFacade; import org.eclipse.tractusx.irs.component.Bpn; import org.eclipse.tractusx.irs.component.JobParameter; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.Tombstone; import org.eclipse.tractusx.irs.component.enums.ProcessStep; import org.springframework.web.client.RestClientException; @@ -53,7 +54,7 @@ public BpdmDelegate(final AbstractDelegate nextStep, final BpdmFacade bpdmFacade @Override public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContainerBuilder, - final JobParameter jobData, final AASTransferProcess aasTransferProcess, final String itemId) { + final JobParameter jobData, final AASTransferProcess aasTransferProcess, final PartChainIdentificationKey itemId) { if (jobData.isLookupBPNs()) { log.debug("BPN Lookup enabled, collecting BPN information"); @@ -65,12 +66,12 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai try { itemContainerBuilder.build() .getBpns() - .forEach(bpn -> lookupBPN(itemContainerBuilder, itemId, bpn, + .forEach(bpn -> lookupBPN(itemContainerBuilder, itemId.getGlobalAssetId(), bpn, requestMetric)); } catch (final RestClientException e) { log.info("Business Partner endpoint could not be retrieved for Item: {}. Creating Tombstone.", itemId); requestMetric.incrementFailed(); - itemContainerBuilder.tombstone(Tombstone.from(itemId, null, e, retryCount, ProcessStep.BPDM_REQUEST)); + itemContainerBuilder.tombstone(Tombstone.from(itemId.getGlobalAssetId(), null, e, retryCount, ProcessStep.BPDM_REQUEST)); } } else { log.debug("BPN lookup disabled, no BPN information will be collected."); diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java index 1f07fa6b03..d7ecd56cc5 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java @@ -28,6 +28,7 @@ import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; import org.eclipse.tractusx.irs.component.JobParameter; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.Tombstone; import org.eclipse.tractusx.irs.component.enums.ProcessStep; import org.eclipse.tractusx.irs.registryclient.DigitalTwinRegistryKey; @@ -52,15 +53,15 @@ public DigitalTwinDelegate(final AbstractDelegate nextStep, @Override public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContainerBuilder, final JobParameter jobData, - final AASTransferProcess aasTransferProcess, final String itemId) { + final AASTransferProcess aasTransferProcess, final PartChainIdentificationKey itemId) { try { itemContainerBuilder.shell(digitalTwinRegistryService.fetchShells( - List.of(new DigitalTwinRegistryKey(itemId, jobData.getBpn())) + List.of(new DigitalTwinRegistryKey(itemId.getGlobalAssetId(), itemId.getBpn())) ).stream().findFirst().orElseThrow()); } catch (final RestClientException | RegistryServiceException e) { log.info("Shell Endpoint could not be retrieved for Item: {}. Creating Tombstone.", itemId); - itemContainerBuilder.tombstone(Tombstone.from(itemId, null, e, retryCount, ProcessStep.DIGITAL_TWIN_REQUEST)); + itemContainerBuilder.tombstone(Tombstone.from(itemId.getGlobalAssetId(), null, e, retryCount, ProcessStep.DIGITAL_TWIN_REQUEST)); } if (expectedDepthOfTreeIsNotReached(jobData.getDepth(), aasTransferProcess.getDepth())) { diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java index 1de59262ed..64593084a7 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java @@ -25,12 +25,12 @@ import java.util.List; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; import org.eclipse.tractusx.irs.component.Bpn; -import org.eclipse.tractusx.irs.component.GlobalAssetIdentification; import org.eclipse.tractusx.irs.component.JobParameter; -import org.eclipse.tractusx.irs.component.LinkedItem; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.Relationship; import org.eclipse.tractusx.irs.component.Tombstone; import org.eclipse.tractusx.irs.component.assetadministrationshell.Endpoint; @@ -66,7 +66,8 @@ public RelationshipDelegate(final AbstractDelegate nextStep, final EdcSubmodelFa @Override public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContainerBuilder, - final JobParameter jobData, final AASTransferProcess aasTransferProcess, final String itemId) { + final JobParameter jobData, final AASTransferProcess aasTransferProcess, + final PartChainIdentificationKey itemId) { final RelationshipAspect relationshipAspect = RelationshipAspect.from(jobData.getBomLifecycle(), jobData.getDirection()); @@ -76,24 +77,34 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai .findFirst() .ifPresent(shell -> shell.findRelationshipEndpointAddresses( AspectType.fromValue(relationshipAspect.getName())) - .forEach(endpoint -> processEndpoint(endpoint, jobData, - relationshipAspect, aasTransferProcess, - itemContainerBuilder, itemId))); + .forEach(endpoint -> processEndpoint(endpoint, relationshipAspect, + aasTransferProcess, itemContainerBuilder, itemId))); return next(itemContainerBuilder, jobData, aasTransferProcess, itemId); } - private void processEndpoint(final Endpoint endpoint, final JobParameter jobData, - final RelationshipAspect relationshipAspect, final AASTransferProcess aasTransferProcess, - final ItemContainer.ItemContainerBuilder itemContainerBuilder, final String itemId) { + private void processEndpoint(final Endpoint endpoint, final RelationshipAspect relationshipAspect, + final AASTransferProcess aasTransferProcess, final ItemContainer.ItemContainerBuilder itemContainerBuilder, + final PartChainIdentificationKey itemId) { + + if (StringUtils.isBlank(itemId.getBpn())) { + log.warn("Could not process item with id {} because no BPN was provided. Creating Tombstone.", + itemId.getGlobalAssetId()); + itemContainerBuilder.tombstone( + Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), + "Can't get relationship without a BPN", retryCount, ProcessStep.SUBMODEL_REQUEST)); + return; + } + try { final String submodelRawPayload = requestSubmodelAsString(submodelFacade, connectorEndpointsService, - endpoint, jobData.getBpn()); + endpoint, itemId.getBpn()); final var relationships = jsonUtil.fromString(submodelRawPayload, relationshipAspect.getSubmodelClazz()) .asRelationships(); - final List idsToProcess = getIdsToProcess(relationships, relationshipAspect.getDirection()); + final List idsToProcess = getIdsToProcess(relationships, + relationshipAspect.getDirection()); log.info("Processing Relationships with {} items", idsToProcess.size()); @@ -104,13 +115,13 @@ private void processEndpoint(final Endpoint endpoint, final JobParameter jobData log.info("Submodel Endpoint could not be retrieved for Endpoint: {}. Creating Tombstone.", endpoint.getProtocolInformation().getHref()); itemContainerBuilder.tombstone( - Tombstone.from(itemId, endpoint.getProtocolInformation().getHref(), e, retryCount, - ProcessStep.SUBMODEL_REQUEST)); + Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, + retryCount, ProcessStep.SUBMODEL_REQUEST)); } catch (final JsonParseException e) { log.info("Submodel payload did not match the expected AspectType. Creating Tombstone."); itemContainerBuilder.tombstone( - Tombstone.from(itemId, endpoint.getProtocolInformation().getHref(), e, retryCount, - ProcessStep.SUBMODEL_REQUEST)); + Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, + retryCount, ProcessStep.SUBMODEL_REQUEST)); } } @@ -118,25 +129,32 @@ private static List getBpnsFrom(final List relationships) { return relationships.stream().map(Relationship::getBpn).map(Bpn::withManufacturerId).toList(); } - private List getIdsToProcess(final List relationships, final Direction direction) { + private List getIdsToProcess(final List relationships, + final Direction direction) { return switch (direction) { case DOWNWARD -> getChildIds(relationships); case UPWARD -> getParentIds(relationships); }; } - private List getParentIds(final List relationships) { + private List getParentIds(final List relationships) { return relationships.stream() - .map(Relationship::getCatenaXId) - .map(GlobalAssetIdentification::getGlobalAssetId) + .map(relationship -> PartChainIdentificationKey.builder() + .globalAssetId(relationship.getCatenaXId() + .getGlobalAssetId()) + .bpn(relationship.getBpn()) + .build()) .toList(); } - private List getChildIds(final List relationships) { + private List getChildIds(final List relationships) { return relationships.stream() - .map(Relationship::getLinkedItem) - .map(LinkedItem::getChildCatenaXId) - .map(GlobalAssetIdentification::getGlobalAssetId) + .map(relationship -> PartChainIdentificationKey.builder() + .globalAssetId(relationship.getLinkedItem() + .getChildCatenaXId() + .getGlobalAssetId()) + .bpn(relationship.getBpn()) + .build()) .toList(); } } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegate.java index 52fa9432c7..701cc79f0e 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegate.java @@ -28,9 +28,11 @@ import io.github.resilience4j.retry.RetryRegistry; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; import org.eclipse.tractusx.irs.component.JobParameter; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.Submodel; import org.eclipse.tractusx.irs.component.Tombstone; import org.eclipse.tractusx.irs.component.assetadministrationshell.SubmodelDescriptor; @@ -75,7 +77,8 @@ public SubmodelDelegate(final EdcSubmodelFacade submodelFacade, final SemanticsH @Override public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContainerBuilder, - final JobParameter jobData, final AASTransferProcess aasTransferProcess, final String itemId) { + final JobParameter jobData, final AASTransferProcess aasTransferProcess, + final PartChainIdentificationKey itemId) { itemContainerBuilder.build().getShells().stream().findFirst().ifPresent(shell -> { final List aasSubmodelDescriptors = shell.getSubmodelDescriptors(); @@ -87,7 +90,8 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai if (jobData.isCollectAspects()) { log.info("Collecting Submodels."); filteredSubmodelDescriptorsByAspectType.forEach(submodelDescriptor -> itemContainerBuilder.submodels( - getSubmodels(submodelDescriptor, itemContainerBuilder, itemId, jobData.getBpn()))); + getSubmodels(submodelDescriptor, itemContainerBuilder, itemId.getGlobalAssetId(), + itemId.getBpn()))); } log.debug("Unfiltered SubmodelDescriptor: {}", aasSubmodelDescriptors); log.debug("Filtered SubmodelDescriptor: {}", filteredSubmodelDescriptorsByAspectType); @@ -103,6 +107,14 @@ private List getSubmodels(final SubmodelDescriptor submodelDescriptor, final ItemContainer.ItemContainerBuilder itemContainerBuilder, final String itemId, final String bpn) { final List submodels = new ArrayList<>(); submodelDescriptor.getEndpoints().forEach(endpoint -> { + + if (StringUtils.isBlank(bpn)) { + log.warn("Could not process item with id {} because no BPN was provided. Creating Tombstone.", itemId); + itemContainerBuilder.tombstone(Tombstone.from(itemId, endpoint.getProtocolInformation().getHref(), + "Can't get submodel without a BPN", retryCount, ProcessStep.SUBMODEL_REQUEST)); + return; + } + try { final String jsonSchema = semanticsHubFacade.getModelJsonSchema(submodelDescriptor.getAspectType()); final String submodelRawPayload = requestSubmodelAsString(submodelFacade, connectorEndpointsService, diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/RegistryConfiguration.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/RegistryConfiguration.java index 3450d34f26..4c51d7a8cf 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/RegistryConfiguration.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/configuration/RegistryConfiguration.java @@ -22,8 +22,6 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.configuration; -import java.util.HashMap; - import org.eclipse.tractusx.irs.edc.client.EdcSubmodelFacade; import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; import org.eclipse.tractusx.irs.registryclient.central.CentralDigitalTwinRegistryService; @@ -35,7 +33,6 @@ import org.eclipse.tractusx.irs.registryclient.decentral.EndpointDataForConnectorsService; import org.eclipse.tractusx.irs.registryclient.discovery.ConnectorEndpointsService; import org.eclipse.tractusx.irs.registryclient.discovery.DiscoveryFinderClientImpl; -import org.eclipse.tractusx.irs.registryclient.discovery.LocalDataDiscovery; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; @@ -82,27 +79,10 @@ public DecentralDigitalTwinRegistryService decentralDigitalTwinRegistryService( } @Bean - @Profile({ "!local && !stubtest" }) public ConnectorEndpointsService connectorEndpointsService( @Qualifier(RestTemplateConfig.DTR_REST_TEMPLATE) final RestTemplate dtrRestTemplate, @Value("${digitalTwinRegistry.discoveryFinderUrl:}") final String finderUrl) { return new ConnectorEndpointsService(new DiscoveryFinderClientImpl(finderUrl, dtrRestTemplate)); } - @Bean - @Profile({ "local", - "stubtest" - }) - public LocalDataDiscovery discoveryFinderClient() { - return new LocalDataDiscovery(new HashMap<>()); - } - - @Bean - @Profile({ "local", - "stubtest" - }) - public ConnectorEndpointsService localDiscoveryConnector(final LocalDataDiscovery discoveryFinderClient) { - return new ConnectorEndpointsService(discoveryFinderClient); - } - } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java index 4565e96941..3c81db74c0 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsFunctionalTest.java @@ -23,6 +23,8 @@ package org.eclipse.tractusx.irs; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; import static org.springframework.security.oauth2.jwt.JwtClaimNames.SUB; import java.time.Instant; @@ -37,7 +39,8 @@ import org.eclipse.tractusx.irs.component.RegisterJob; import org.eclipse.tractusx.irs.component.enums.JobState; import org.eclipse.tractusx.irs.controllers.IrsController; -import org.eclipse.tractusx.irs.registryclient.discovery.LocalDataDiscovery; +import org.eclipse.tractusx.irs.data.StringMapper; +import org.eclipse.tractusx.irs.registryclient.discovery.ConnectorEndpointsService; import org.eclipse.tractusx.irs.testing.containers.MinioContainer; import org.eclipse.tractusx.irs.util.TestMother; import org.jetbrains.annotations.NotNull; @@ -47,6 +50,7 @@ import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.ApplicationContextInitializer; import org.springframework.context.ConfigurableApplicationContext; import org.springframework.security.core.authority.SimpleGrantedAuthority; @@ -75,8 +79,6 @@ class IrsFunctionalTest { new MinioContainer.CredentialsProvider(ACCESS_KEY, SECRET_KEY)).withReuse(true); @Autowired private IrsController controller; - @Autowired - private LocalDataDiscovery discovery; @BeforeAll static void startContainer() { @@ -88,10 +90,14 @@ static void stopContainer() { minioContainer.stop(); } + @MockBean + private ConnectorEndpointsService connectorEndpointsService; + @Test void shouldStartJobAndRetrieveResult() { final RegisterJob registerJob = TestMother.registerJobWithoutDepth(); - discovery.registerMapping(registerJob.getKey().getBpn(), "singleLevelBomAsBuilt"); + when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn( + List.of("http://localhost/discovery")); thereIsJwtAuthentication(); @@ -121,7 +127,8 @@ void shouldStartJobAndRetrieveResult() { @Test void shouldFillSummaryWithoutBPNLookup() { final RegisterJob registerJob = TestMother.registerJobWithoutDepth(); - discovery.registerMapping(registerJob.getKey().getBpn(), "singleLevelBomAsBuilt"); + when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn( + List.of("http://localhost/discovery")); thereIsJwtAuthentication(); @@ -147,7 +154,8 @@ void shouldFillSummaryWithoutBPNLookup() { @Test void shouldFillSummaryWithBPNLookup() { final RegisterJob registerJob = TestMother.registerJobWithLookupBPNs(); - discovery.registerMapping(registerJob.getKey().getBpn(), "singleLevelBomAsBuilt"); + when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn( + List.of("http://localhost/discovery")); thereIsJwtAuthentication(); final JobHandle jobHandle = controller.registerJobForGlobalAssetId(registerJob); @@ -174,7 +182,7 @@ private void thereIsJwtAuthentication() { List.of(new SimpleGrantedAuthority("view_irs"))); jwtAuthenticationToken.setAuthenticated(true); SecurityContext securityContext = Mockito.mock(SecurityContext.class); - Mockito.when(securityContext.getAuthentication()).thenReturn(jwtAuthenticationToken); + when(securityContext.getAuthentication()).thenReturn(jwtAuthenticationToken); SecurityContextHolder.setContext(securityContext); } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcessManagerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcessManagerTest.java index 40cc2730d9..9d37068b8b 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcessManagerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/AASTransferProcessManagerTest.java @@ -22,8 +22,8 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.aaswrapper.job; -import static org.eclipse.tractusx.irs.util.TestMother.jobParameter; import static org.assertj.core.api.Assertions.assertThat; +import static org.eclipse.tractusx.irs.util.TestMother.jobParameter; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -34,6 +34,7 @@ import org.eclipse.tractusx.irs.InMemoryBlobStore; import org.eclipse.tractusx.irs.aaswrapper.job.delegate.DigitalTwinDelegate; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.connector.job.ResponseStatus; import org.eclipse.tractusx.irs.connector.job.TransferInitiateResponse; import org.eclipse.tractusx.irs.util.TestMother; @@ -49,12 +50,14 @@ class AASTransferProcessManagerTest { DigitalTwinDelegate digitalTwinProcessor = mock(DigitalTwinDelegate.class); ExecutorService pool = mock(ExecutorService.class); - final AASTransferProcessManager manager = new AASTransferProcessManager(digitalTwinProcessor, pool, new InMemoryBlobStore()); + final AASTransferProcessManager manager = new AASTransferProcessManager(digitalTwinProcessor, pool, + new InMemoryBlobStore()); @Test void shouldExecuteThreadForProcessing() { // given - final ItemDataRequest itemDataRequest = ItemDataRequest.rootNode(UUID.randomUUID().toString()); + final ItemDataRequest itemDataRequest = ItemDataRequest.rootNode( + PartChainIdentificationKey.builder().globalAssetId(UUID.randomUUID().toString()).bpn("bpn123").build()); // when manager.initiateRequest(itemDataRequest, s -> { @@ -68,7 +71,8 @@ void shouldExecuteThreadForProcessing() { @Test void shouldInitiateProcessingAndReturnOkStatus() { // given - final ItemDataRequest itemDataRequest = ItemDataRequest.rootNode(UUID.randomUUID().toString()); + final ItemDataRequest itemDataRequest = ItemDataRequest.rootNode( + PartChainIdentificationKey.builder().globalAssetId(UUID.randomUUID().toString()).bpn("bpn123").build()); // when final TransferInitiateResponse initiateResponse = manager.initiateRequest(itemDataRequest, s -> { diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/BpdmDelegateTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/BpdmDelegateTest.java index f67672f97c..9e6fe30d47 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/BpdmDelegateTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/BpdmDelegateTest.java @@ -36,6 +36,7 @@ import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; import org.eclipse.tractusx.irs.bpdm.BpdmFacade; import org.eclipse.tractusx.irs.component.Bpn; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.enums.ProcessStep; import org.junit.jupiter.api.Test; import org.springframework.web.client.RestClientException; @@ -53,7 +54,7 @@ void shouldFillItemContainerWithBpn() { // when final ItemContainer result = bpdmDelegate.process(itemContainer, jobParameterCollectBpns(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); @@ -61,6 +62,10 @@ void shouldFillItemContainerWithBpn() { assertThat(result.getBpns().stream().findFirst().get().getManufacturerName()).isEqualTo("Tier A"); } + private static PartChainIdentificationKey createKey() { + return PartChainIdentificationKey.builder().globalAssetId("itemId").build(); + } + @Test void shouldCreateTombstoneForNotValidBpn() { // given @@ -69,7 +74,7 @@ void shouldCreateTombstoneForNotValidBpn() { // when final ItemContainer result = bpdmDelegate.process(itemContainer, jobParameterCollectBpns(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); @@ -88,7 +93,7 @@ void shouldCatchRestClientExceptionAndPutTombstone() { // when final ItemContainer result = bpdmDelegate.process(itemContainerWithShell, jobParameterCollectBpns(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); @@ -106,7 +111,7 @@ void shouldCreateTombstoneForMissingBpnForGivenManufacturerId() { // when final ItemContainer result = bpdmDelegate.process(itemContainer, jobParameterCollectBpns(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); @@ -125,7 +130,7 @@ void shouldNotResolveBPNsWithoutFlag() { // when final ItemContainer result = bpdmDelegate.process(itemContainer, jobParameter(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); @@ -141,7 +146,7 @@ void shouldResolveBPNsWhenFlagIsTrue() { // when final ItemContainer result = bpdmDelegate.process(itemContainer, jobParameterCollectBpns(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); @@ -159,7 +164,7 @@ void shouldIncrementFailedMetricWhenFacadeResultIsEmpty() { // when final ItemContainer result = bpdmDelegate.process(itemContainer, jobParameterCollectBpns(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); @@ -177,7 +182,7 @@ void shouldIncrementFailedMetricWhenExceptionIsThrown() { // when final ItemContainer result = bpdmDelegate.process(itemContainer, jobParameterCollectBpns(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegateTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegateTest.java index 7e3df757a2..1808ba8aa8 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegateTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegateTest.java @@ -22,10 +22,10 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.aaswrapper.job.delegate; +import static org.assertj.core.api.Assertions.assertThat; import static org.eclipse.tractusx.irs.util.TestMother.jobParameter; import static org.eclipse.tractusx.irs.util.TestMother.shellDescriptor; import static org.eclipse.tractusx.irs.util.TestMother.submodelDescriptorWithoutEndpoint; -import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -35,6 +35,7 @@ import io.github.resilience4j.retry.RetryRegistry; import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.enums.ProcessStep; import org.eclipse.tractusx.irs.registryclient.DigitalTwinRegistryService; import org.eclipse.tractusx.irs.registryclient.exceptions.RegistryServiceException; @@ -49,18 +50,22 @@ class DigitalTwinDelegateTest { @Test void shouldFillItemContainerWithShell() throws RegistryServiceException { // given - when(digitalTwinRegistryService.fetchShells(any())).thenReturn(List.of(shellDescriptor( - List.of(submodelDescriptorWithoutEndpoint("any"))))); + when(digitalTwinRegistryService.fetchShells(any())).thenReturn( + List.of(shellDescriptor(List.of(submodelDescriptorWithoutEndpoint("any"))))); // when final ItemContainer result = digitalTwinDelegate.process(ItemContainer.builder(), jobParameter(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); assertThat(result.getShells()).isNotEmpty(); } + private static PartChainIdentificationKey createKey() { + return PartChainIdentificationKey.builder().globalAssetId("itemId").build(); + } + @Test void shouldCatchRestClientExceptionAndPutTombstone() throws RegistryServiceException { // given @@ -69,7 +74,7 @@ void shouldCatchRestClientExceptionAndPutTombstone() throws RegistryServiceExcep // when final ItemContainer result = digitalTwinDelegate.process(ItemContainer.builder(), jobParameter(), - new AASTransferProcess("id", 0), "itemId"); + new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegateTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegateTest.java index 41d9d3629c..76c4d72236 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegateTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegateTest.java @@ -39,6 +39,7 @@ import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.enums.ProcessStep; import org.eclipse.tractusx.irs.edc.client.EdcSubmodelFacade; import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; @@ -73,7 +74,7 @@ void shouldFillItemContainerWithRelationshipAndAddChildIdsToProcess() // when final ItemContainer result = relationshipDelegate.process(itemContainerWithShell, jobParameter(), - aasTransferProcess, "itemId"); + aasTransferProcess, createKey()); // then assertThat(result).isNotNull(); @@ -96,7 +97,7 @@ void shouldCatchRestClientExceptionAndPutTombstone() throws EdcClientException { // when final ItemContainer result = relationshipDelegate.process(itemContainerWithShell, jobParameter(), - new AASTransferProcess(), "itemId"); + new AASTransferProcess(), createKey()); // then assertThat(result).isNotNull(); @@ -120,7 +121,7 @@ void shouldCatchJsonParseExceptionAndPutTombstone() throws EdcClientException { // when final ItemContainer result = relationshipDelegate.process(itemContainerWithShell, jobParameter(), - new AASTransferProcess(), "itemId"); + new AASTransferProcess(), createKey()); // then assertThat(result).isNotNull(); @@ -130,4 +131,8 @@ void shouldCatchJsonParseExceptionAndPutTombstone() throws EdcClientException { ProcessStep.SUBMODEL_REQUEST); } + private static PartChainIdentificationKey createKey() { + return PartChainIdentificationKey.builder().globalAssetId("itemId").bpn("bpn123").build(); + } + } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegateTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegateTest.java index 5a3521c002..bed5d8e86d 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegateTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegateTest.java @@ -35,6 +35,7 @@ import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; +import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.enums.ProcessStep; import org.eclipse.tractusx.irs.data.JsonParseException; import org.eclipse.tractusx.irs.edc.client.EdcSubmodelFacade; @@ -74,13 +75,17 @@ void shouldFilterSubmodelDescriptorsByAspectTypeFilter() { // when final ItemContainer result = submodelDelegate.process(itemContainerShellWithTwoSubmodels, jobParameterFilter(), - new AASTransferProcess(), "itemId"); + new AASTransferProcess(), createKey()); // then assertThat(result).isNotNull(); assertThat(result.getShells().get(0).getSubmodelDescriptors()).isEmpty(); } + private static PartChainIdentificationKey createKey() { + return PartChainIdentificationKey.builder().globalAssetId("itemId").bpn("bpn123").build(); + } + @Test void shouldCatchJsonParseExceptionAndPutTombstone() throws SchemaNotFoundException { // given @@ -97,7 +102,7 @@ void shouldCatchJsonParseExceptionAndPutTombstone() throws SchemaNotFoundExcepti when(semanticsHubFacade.getModelJsonSchema(any())).thenThrow( new JsonParseException(new Exception("Payload did not match expected submodel"))); final ItemContainer result = submodelDelegate.process(itemContainerShellWithTwoSubmodels, - jobParameterCollectAspects(), new AASTransferProcess(), "itemId"); + jobParameterCollectAspects(), new AASTransferProcess(), createKey()); // then assertThat(result).isNotNull(); @@ -123,7 +128,7 @@ void shouldCatchUsagePolicyExceptionAndPutTombstone() throws EdcClientException when(submodelFacade.getSubmodelRawPayload(any(), any(), any())).thenThrow(new UsagePolicyException("itemId")); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of("connector.endpoint.nl")); final ItemContainer result = submodelDelegate.process(itemContainerShellWithTwoSubmodels, - jobParameterCollectAspects(), new AASTransferProcess(), "itemId"); + jobParameterCollectAspects(), new AASTransferProcess(), createKey()); // then assertThat(result).isNotNull(); @@ -151,12 +156,13 @@ void shouldRequestForAllEndpoints() throws EdcClientException, InvalidSchemaExce when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn( List.of("connector.endpoint.n1", "connector.endpoint.n2")); final ItemContainer result = submodelDelegate.process(itemContainerShellWithOneSubmodel, - jobParameterCollectAspects(), new AASTransferProcess(), "itemId"); + jobParameterCollectAspects(), new AASTransferProcess(), createKey()); // then assertThat(result).isNotNull(); assertThat(result.getSubmodels()).hasSize(1); - assertThat(result.getSubmodels().get(0).getAspectType()).isEqualTo("urn:bamm:com.catenax.serial_part:1.0.0#SerialPart"); + assertThat(result.getSubmodels().get(0).getAspectType()).isEqualTo( + "urn:bamm:com.catenax.serial_part:1.0.0#SerialPart"); assertThat(result.getTombstones()).isEmpty(); } @@ -176,7 +182,7 @@ void shouldCatchRestClientExceptionAndPutTombstone() throws SchemaNotFoundExcept when(semanticsHubFacade.getModelJsonSchema(any())).thenThrow( new RestClientException("Payload did not match expected submodel")); final ItemContainer result = submodelDelegate.process(itemContainerShellWithTwoSubmodels, - jobParameterCollectAspects(), new AASTransferProcess(), "itemId"); + jobParameterCollectAspects(), new AASTransferProcess(), createKey()); // then assertThat(result).isNotNull(); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java index f4efe32125..790b7441e2 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/services/IrsItemGraphQueryServiceSpringBootTest.java @@ -120,9 +120,8 @@ void registerJobWithoutDepthShouldBuildFullTree() { // given final RegisterJob registerJob = registerJobWithoutDepth(); final int expectedRelationshipsSizeFullTree = 44; // stub - when(connectorEndpointsService.fetchConnectorEndpoints(registerJob.getKey().getBpn())).thenReturn( - List.of("singleLevelBomAsBuilt")); - + when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn( + List.of("http://localhost/discovery")); // when final JobHandle registeredJob = service.registerItemJob(registerJob); @@ -186,8 +185,8 @@ void registerJobShouldCreateTombstonesWhenNotPassingJsonSchemaValidation() throw void registerJobWithDepthShouldBuildTreeUntilGivenDepth() { // given final RegisterJob registerJob = registerJobWithDepthAndAspect(1, null); - when(connectorEndpointsService.fetchConnectorEndpoints(registerJob.getKey().getBpn())).thenReturn( - List.of("singleLevelBomAsBuilt")); + when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn( + List.of("http://localhost/discovery")); final int expectedRelationshipsSizeFirstDepth = 34; // stub @@ -206,8 +205,8 @@ void registerJobWithUpwardDirectionShouldBuildRelationships() { // given final RegisterJob registerJob = registerJobWithDirection("urn:uuid:0b45c63b-0e5e-4232-9074-a05607783c33", Direction.UPWARD); - when(connectorEndpointsService.fetchConnectorEndpoints(registerJob.getKey().getBpn())).thenReturn( - List.of("singleLevelUsageAsBuilt")); + when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn( + List.of("http://localhost/discovery")); final int expectedRelationshipsSizeFirstDepth = 1; // stub @@ -261,8 +260,8 @@ void registerJobWithoutAspectsShouldUseDefault() { final String defaultAspectType = AspectType.SERIAL_PART.toString(); final List emptyAspectTypeFilterList = List.of(); final RegisterJob registerJob = registerJobWithDepthAndAspect(null, emptyAspectTypeFilterList); - when(connectorEndpointsService.fetchConnectorEndpoints(registerJob.getKey().getBpn())).thenReturn( - List.of("singleLevelBomAsBuilt")); + when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn( + List.of("http://localhost/discovery")); // when final JobHandle jobHandle = service.registerItemJob(registerJob); diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java index 10fe4d4551..6c606ff387 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClient.java @@ -89,7 +89,7 @@ public CompletableFuture getSubmodelRawPayload(final String connectorEnd if ("urn:uuid:c35ee875-5443-4a2d-bc14-fdacd64b9446".equals(assetId)) { throw new EdcClientException("Dummy Exception"); } - final Map submodel = testdataCreator.createSubmodelForId(assetId + "_" + connectorEndpoint); + final Map submodel = testdataCreator.createSubmodelForId(assetId + "_" + submodelSuffix); return CompletableFuture.completedFuture(StringMapper.mapToString(submodel)); } diff --git a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java index f55e3b4289..8979d3191d 100644 --- a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java +++ b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java @@ -44,8 +44,8 @@ public class Tombstone { public static final int CATENA_X_ID_LENGTH = 45; @Schema(description = "CATENA-X global asset id in the format urn:uuid:uuid4.", - example = "urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0", - minLength = CATENA_X_ID_LENGTH, maxLength = CATENA_X_ID_LENGTH, + example = "urn:uuid:6c311d29-5753-46d4-b32c-19b918ea93b0", minLength = CATENA_X_ID_LENGTH, + maxLength = CATENA_X_ID_LENGTH, pattern = "^urn:uuid:[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$") private final String catenaXId; private final String endpointURL; @@ -53,11 +53,17 @@ public class Tombstone { public static Tombstone from(final String catenaXId, final String endpointURL, final Exception exception, final int retryCount, final ProcessStep processStep) { + return from(catenaXId, endpointURL, exception.getMessage(), retryCount, processStep); + } + + public static Tombstone from(final String catenaXId, final String endpointURL, final String errorDetails, + final int retryCount, final ProcessStep processStep) { + final ProcessingError processingError = ProcessingError.builder() .withProcessStep(processStep) .withRetryCounter(retryCount) .withLastAttempt(ZonedDateTime.now(ZoneOffset.UTC)) - .withErrorDetail(exception.getMessage()) + .withErrorDetail(errorDetails) .build(); return Tombstone.builder() .endpointURL(endpointURL) From ee74c8ad3898b0c6ac1ebff70a31d02c900c5e3a Mon Sep 17 00:00:00 2001 From: Jan Kreutzfeld Date: Wed, 19 Jul 2023 22:13:10 +0200 Subject: [PATCH 2/5] fix(recursion): Update changelog --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index b659a7b6db..8f15efd20b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed +- BPN is now passed on correctly while traversing the item graph +- Tombstone is created if no BPN is available for a child item ## [3.2.1] - 2023-07-19 ### Fixed From 7319bf01f2a5474804113382cf157659d6e00570 Mon Sep 17 00:00:00 2001 From: Jan Kreutzfeld Date: Thu, 20 Jul 2023 10:43:48 +0200 Subject: [PATCH 3/5] fix(recursion): Add unit tests for BPN check --- .../delegate/RelationshipDelegateTest.java | 19 +++++++++++++++ .../job/delegate/SubmodelDelegateTest.java | 23 +++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegateTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegateTest.java index 76c4d72236..f82884c95b 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegateTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegateTest.java @@ -82,6 +82,25 @@ void shouldFillItemContainerWithRelationshipAndAddChildIdsToProcess() assertThat(aasTransferProcess.getIdsToProcess()).isNotEmpty(); } + @Test + void shouldPutTombstoneForMissingBpn() throws EdcClientException { + final ItemContainer.ItemContainerBuilder itemContainerWithShell = ItemContainer.builder() + .shell(shellDescriptor( + List.of(submodelDescriptor( + singleLevelBomAsBuiltAspectName, + "address")))); + // when + final ItemContainer result = relationshipDelegate.process(itemContainerWithShell, jobParameter(), + new AASTransferProcess(), PartChainIdentificationKey.builder().globalAssetId("testId").build()); + + // then + assertThat(result).isNotNull(); + assertThat(result.getTombstones()).hasSize(1); + assertThat(result.getTombstones().get(0).getCatenaXId()).isEqualTo("testId"); + assertThat(result.getTombstones().get(0).getProcessingError().getProcessStep()).isEqualTo( + ProcessStep.SUBMODEL_REQUEST); + } + @Test void shouldCatchRestClientExceptionAndPutTombstone() throws EdcClientException { // given diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegateTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegateTest.java index bed5d8e86d..b76095b098 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegateTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegateTest.java @@ -112,6 +112,29 @@ void shouldCatchJsonParseExceptionAndPutTombstone() throws SchemaNotFoundExcepti ProcessStep.SCHEMA_VALIDATION); } + + @Test + void shouldPutTombstoneForMissingBpn() { + final ItemContainer.ItemContainerBuilder itemContainerShellWithTwoSubmodels = ItemContainer.builder() + .shell(shellDescriptor( + List.of(submodelDescriptor( + "urn:bamm:com.catenax.serial_part:1.0.0#SerialPart", + "testSerialPartEndpoint"), + submodelDescriptor( + "urn:bamm:com.catenax.single_level_bom_as_built:1.0.0#SingleLevelBomAsBuilt", + "testSingleLevelBomAsBuiltEndpoint")))); + + // when + final ItemContainer result = submodelDelegate.process(itemContainerShellWithTwoSubmodels, jobParameterCollectAspects(), + new AASTransferProcess(), PartChainIdentificationKey.builder().globalAssetId("testId").build()); + + // then + assertThat(result).isNotNull(); + assertThat(result.getTombstones()).hasSize(2); + assertThat(result.getTombstones().get(0).getCatenaXId()).isEqualTo("testId"); + assertThat(result.getTombstones().get(0).getProcessingError().getProcessStep()).isEqualTo( + ProcessStep.SUBMODEL_REQUEST); + } @Test void shouldCatchUsagePolicyExceptionAndPutTombstone() throws EdcClientException { // given From 171bc314d2723d84700a89665df3ca2266183c4a Mon Sep 17 00:00:00 2001 From: Jan Kreutzfeld Date: Thu, 20 Jul 2023 11:01:48 +0200 Subject: [PATCH 4/5] chore(release): Prepare release of IRS 3.3.0 --- CHANGELOG.md | 9 ++++++--- charts/irs-helm/CHANGELOG.md | 4 ++++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8f15efd20b..94baf72226 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] -### Fixed -- BPN is now passed on correctly while traversing the item graph + +## [3.3.0] - 2023-07-20 +### Changed +- BPN is now taken from the submodel data while traversing the item graph - Tombstone is created if no BPN is available for a child item ## [3.2.1] - 2023-07-19 @@ -285,7 +287,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Unresolved - **Select Aspects you need** You are able to select the needed aspects for which you want to collect the correct endpoint information. -[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.2.1...HEAD +[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.3.0...HEAD +[3.3.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.2.1...3.3.0 [3.2.1]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.2.0...3.2.1 [3.2.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.1.0...3.2.0 [3.1.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/3.0.1...3.1.0 diff --git a/charts/irs-helm/CHANGELOG.md b/charts/irs-helm/CHANGELOG.md index 1d4b058eeb..82cf2e82b8 100644 --- a/charts/irs-helm/CHANGELOG.md +++ b/charts/irs-helm/CHANGELOG.md @@ -6,6 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [6.3.0] - 2023-07-20 +### Changed +- Update IRS version to 3.3.0 + ## [6.2.1] - 2023-07-19 ### Changed - Update IRS version to 3.2.1 From 4387395232b7429aa5d74fe3fff7b91035f9e2a8 Mon Sep 17 00:00:00 2001 From: ds-jkreutzfeld Date: Thu, 20 Jul 2023 09:10:17 +0000 Subject: [PATCH 5/5] chore(release): Prepare release for Helm version 6.3.0 --- charts/irs-helm/Chart.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/charts/irs-helm/Chart.yaml b/charts/irs-helm/Chart.yaml index 97087f9bed..692931f28a 100644 --- a/charts/irs-helm/Chart.yaml +++ b/charts/irs-helm/Chart.yaml @@ -35,12 +35,12 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 6.2.1 +version: 6.3.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to # follow Semantic Versioning. They should reflect the version the application is using. # It is recommended to use it with quotes. -appVersion: "3.2.1" +appVersion: "3.3.0" dependencies: - name: common repository: https://charts.bitnami.com/bitnami