diff --git a/CHANGELOG.md b/CHANGELOG.md index 7a6eb265ac..6512090241 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,8 @@ _**For better traceability add the corresponding GitHub issue number in each cha - Added AssetAdministrationShellDescriptor specificAssetIds support for externalSubjectId required for data provisioning - Registering a job - aspects array is now accepting full urn of aspect model instead of name only, eg. 'urn:bamm:io.catenax.single_level_bom_as_built:2.0.0#SingleLevelBomAsBuilt' instead 'SingleLevelBomAsBuilt'. #439 - Changed the version of irs-registry-client from 1.6.0-SNAPSHOT to 1.6.0 +- Policies can now be registered for certain bpnls. #199 + ## Fixed - Fixed missing timeouts including configuration. #448 diff --git a/charts/irs-helm/templates/configmap-spring-app-config.yaml b/charts/irs-helm/templates/configmap-spring-app-config.yaml index 54180b10d6..7225bd3182 100644 --- a/charts/irs-helm/templates/configmap-spring-app-config.yaml +++ b/charts/irs-helm/templates/configmap-spring-app-config.yaml @@ -161,8 +161,6 @@ data: {{- end }} {{- end }} - apiAllowedBpn: {{ tpl (.Values.bpn | default "") . | quote }} - {{- if .Values.config.content }} {{- tpl (toYaml .Values.config.content) . | nindent 4 }} {{- end }} diff --git a/docs/src/api/irs-api.yaml b/docs/src/api/irs-api.yaml index 1e08bb0b51..406fcf0808 100644 --- a/docs/src/api/irs-api.yaml +++ b/docs/src/api/irs-api.yaml @@ -794,7 +794,15 @@ paths: /irs/policies: get: description: Lists the registered policies that should be accepted in EDC negotiation. - operationId: getAllowedPolicies + operationId: getAllowedPoliciesByBpn + parameters: + - name: bpnls + in: query + required: false + schema: + type: array + items: + type: string responses: "200": content: @@ -823,7 +831,7 @@ paths: $ref: '#/components/schemas/ErrorResponse' description: Authorization refused by server. security: - - api_key: [] + - api_key: [ ] summary: Lists the registered policies that should be accepted in EDC negotiation. tags: - Item Relationship Service @@ -871,16 +879,15 @@ paths: summary: Register a policy that should be accepted in EDC negotiation. tags: - Item Relationship Service - /irs/policies/{policyId}: - delete: - description: Removes a policy that should no longer be accepted in EDC negotiation. - operationId: deleteAllowedPolicy - parameters: - - in: path - name: policyId - required: true - schema: - type: string + put: + description: Updates an existing policy. + operationId: updateAllowedPolicy + requestBody: + content: + application/json: + schema: + $ref: '#/components/schemas/UpdatePolicyRequest' + required: true responses: "200": description: OK @@ -892,7 +899,7 @@ paths: $ref: '#/components/examples/error-response-400' schema: $ref: '#/components/schemas/ErrorResponse' - description: Policy deletion failed. + description: Policy update failed. "401": content: application/json: @@ -912,25 +919,20 @@ paths: $ref: '#/components/schemas/ErrorResponse' description: Authorization refused by server. security: - - api_key: [] - summary: Removes a policy that should no longer be accepted in EDC negotiation. + - api_key: [ ] + summary: Updates an existing policy. tags: - Item Relationship Service - put: - description: Updates an existing policy with new validUntil value. - operationId: updateAllowedPolicy + /irs/policies/{policyId}: + delete: + description: Removes a policy that should no longer be accepted in EDC negotiation. + operationId: deleteAllowedPolicy parameters: - in: path name: policyId required: true schema: type: string - requestBody: - content: - application/json: - schema: - $ref: '#/components/schemas/UpdatePolicyRequest' - required: true responses: "200": description: OK @@ -942,7 +944,7 @@ paths: $ref: '#/components/examples/error-response-400' schema: $ref: '#/components/schemas/ErrorResponse' - description: Policy update failed. + description: Policy deletion failed. "401": content: application/json: @@ -963,7 +965,7 @@ paths: description: Authorization refused by server. security: - api_key: [] - summary: Updates an existing policy with new validUntil value. + summary: Removes a policy that should no longer be accepted in EDC negotiation. tags: - Item Relationship Service components: @@ -1736,9 +1738,9 @@ components: description: Request to add a policy properties: payload: - type: object - additionalProperties: - $ref: '#/components/schemas/JsonValue' + type: array + items: + $ref: '#/components/schemas/JsonObject' example: payload: '@context': @@ -1758,23 +1760,14 @@ components: '@id': 'odrl:eq' 'odrl:rightOperand': ID 3.1 Trace validUntil: '2025-12-12T23:59:59.999Z' - properties: - empty: - type: boolean - valueType: - type: string - enum: - - 'ARRAY' - - 'OBJECT' - - 'STRING' - - 'NUMBER' - - 'TRUE' - - 'FALSE' - - 'NULL' validUntil: type: string format: date-time description: Timestamp after which the policy will no longer be accepted in negotiations + businessPartnerNumbers: + type: array + items: + type: string required: - payload - validUntil @@ -2237,6 +2230,41 @@ components: items: $ref: '#/components/schemas/Tombstone' maxItems: 2147483647 + JsonObject: + type: object + additionalProperties: false + properties: + valueType: + type: string + enum: + - 'ARRAY' + - 'OBJECT' + - 'STRING' + - 'NUMBER' + - 'TRUE' + - 'FALSE' + - 'NULL' + empty: + type: boolean + example: + payload: + '@context': + odrl: http://www.w3.org/ns/odrl/2/ + '@id': policy-id + policy: + 'odrl:permission': + - 'odrl:action': USE + 'odrl:constraint': + 'odrl:and': + - 'odrl:leftOperand': Membership + 'odrl:operator': + '@id': 'odrl:eq' + 'odrl:rightOperand': active + - 'odrl:leftOperand': PURPOSE + 'odrl:operator': + '@id': 'odrl:eq' + 'odrl:rightOperand': ID 3.1 Trace + validUntil: '2025-12-12T23:59:59.999Z' JsonValue: type: object additionalProperties: false @@ -2938,6 +2966,14 @@ components: additionalProperties: false description: Request to add a policy properties: + businessPartnerNumbers: + type: array + items: + type: string + policiesIds: + type: array + items: + type: string validUntil: type: string format: date-time 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 5823cff156..0f3664fc39 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 @@ -98,22 +98,22 @@ protected SubmodelDescriptor requestSubmodel(final EdcSubmodelFacade submodelFac log.debug("Using dspEndpoint of subprotocolBody '{}' to get submodel payload", subprotocolBody); return submodelFacade.getSubmodelPayload(dspEndpoint.get(), digitalTwinRegistryEndpoint.getProtocolInformation().getHref(), - extractAssetId(subprotocolBody)); + extractAssetId(subprotocolBody), bpn); } else { log.info("SubprotocolBody does not contain '{}'. Using Discovery Service as fallback.", DSP_ENDPOINT); final List connectorEndpoints = connectorEndpointsService.fetchConnectorEndpoints(bpn); - return getSubmodel(submodelFacade, digitalTwinRegistryEndpoint, connectorEndpoints); + return getSubmodel(submodelFacade, digitalTwinRegistryEndpoint, connectorEndpoints, bpn); } } private SubmodelDescriptor getSubmodel(final EdcSubmodelFacade submodelFacade, final Endpoint digitalTwinRegistryEndpoint, - final List connectorEndpoints) throws EdcClientException { + final List connectorEndpoints, final String bpn) throws EdcClientException { for (final String connectorEndpoint : connectorEndpoints) { try { return submodelFacade.getSubmodelPayload(connectorEndpoint, digitalTwinRegistryEndpoint.getProtocolInformation().getHref(), - extractAssetId(digitalTwinRegistryEndpoint.getProtocolInformation().getSubprotocolBody())); + extractAssetId(digitalTwinRegistryEndpoint.getProtocolInformation().getSubprotocolBody()), bpn); } catch (EdcClientException e) { log.info("EdcClientException while accessing digitalTwinRegistryEndpoint '{}'", connectorEndpoint, e); } 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 7b2d866bd8..936aa6ebbc 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 @@ -76,9 +76,9 @@ public DecentralDigitalTwinRegistryService decentralDigitalTwinRegistryService( @Value("${digitalTwinRegistry.lookupShellsTemplate:}") final String lookupShellsTemplate, final EdcConfiguration edcConfiguration) { - final EdcEndpointReferenceRetriever endpointReferenceRetriever = (edcConnectorEndpoint, assetType, assetValue) -> { + final EdcEndpointReferenceRetriever endpointReferenceRetriever = (edcConnectorEndpoint, assetType, assetValue, bpn) -> { try { - return facade.getEndpointReferencesForAsset(edcConnectorEndpoint, assetType, assetValue); + return facade.getEndpointReferencesForAsset(edcConnectorEndpoint, assetType, assetValue, bpn); } catch (EdcClientException e) { throw new EdcRetrieverException(e); } diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/controller/mock/MockedNotificationReceiverController.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/controller/mock/MockedNotificationReceiverController.java index a6e6bffabb..4f1eb9410e 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/controller/mock/MockedNotificationReceiverController.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/controller/mock/MockedNotificationReceiverController.java @@ -107,7 +107,7 @@ public void receiveNotification( final EdcNotification edcRequest = edcRequest(notificationId, originalNotificationId, senderEdc, senderBpn, recipientBpn, notificationContent); - final var response = edcSubmodelFacade.sendNotification(recipientUrl, "ess-response-asset", edcRequest); + final var response = edcSubmodelFacade.sendNotification(recipientUrl, "ess-response-asset", edcRequest, recipientBpn); if (!response.deliveredSuccessfully()) { throw new EdcClientException( "EDC Provider did not accept message with notificationId " + notificationId); diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EdcNotificationSender.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EdcNotificationSender.java index 3987c12624..ebaa775c83 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EdcNotificationSender.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/ess/service/EdcNotificationSender.java @@ -76,7 +76,7 @@ public void sendEdcNotification(final EdcNotification getBlob(final String sourceBlobName) { return Optional.ofNullable(store.get(sourceBlobName)); } + @Override + public Map getAllBlobs() { + return store; + } + @Override public Collection findBlobByPrefix(final String prefix) { return store.entrySet() diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/AbstractDelegateTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/AbstractDelegateTest.java index f38685a3a8..b4e81769db 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/AbstractDelegateTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/AbstractDelegateTest.java @@ -62,7 +62,7 @@ void setUp() { @Test void shouldUseDspEndpointIfPresent() throws EdcClientException { // Arrange - when(submodelFacade.getSubmodelPayload(any(), any(), any())).thenReturn(new SubmodelDescriptor("cid", "test")); + when(submodelFacade.getSubmodelPayload(any(), any(), any(), any())).thenReturn(new SubmodelDescriptor("cid", "test")); final Endpoint endpoint = Endpoint.builder() .protocolInformation(ProtocolInformation.builder() .href("http://dataplane.test/123") @@ -77,7 +77,7 @@ void shouldUseDspEndpointIfPresent() throws EdcClientException { // Assert assertThat(submodel).isEqualTo("test"); - verify(submodelFacade, times(1)).getSubmodelPayload("http://edc.test", "http://dataplane.test/123", "123"); + verify(submodelFacade, times(1)).getSubmodelPayload("http://edc.test", "http://dataplane.test/123", "123", "BPN123"); } @Test @@ -85,9 +85,9 @@ void shouldUseDiscoveryFinderIfDspEndpointNotPresent() throws EdcClientException // Arrange final String connector1 = "http://edc.test1"; final String connector2 = "http://edc.test2"; - when(submodelFacade.getSubmodelPayload(eq(connector1), any(), any())).thenThrow( + when(submodelFacade.getSubmodelPayload(eq(connector1), any(), any(), any())).thenThrow( new EdcClientException("test")); - when(submodelFacade.getSubmodelPayload(eq(connector2), any(), any())).thenReturn(new SubmodelDescriptor("cid", "test")); + when(submodelFacade.getSubmodelPayload(eq(connector2), any(), any(), any())).thenReturn(new SubmodelDescriptor("cid", "test")); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of(connector1, connector2)); final String dataplaneUrl = "http://dataplane.test/123"; final Endpoint endpoint = Endpoint.builder() @@ -104,8 +104,8 @@ void shouldUseDiscoveryFinderIfDspEndpointNotPresent() throws EdcClientException // Assert assertThat(submodel).isEqualTo("test"); - verify(submodelFacade, times(1)).getSubmodelPayload(connector1, dataplaneUrl, "123"); - verify(submodelFacade, times(1)).getSubmodelPayload(connector2, dataplaneUrl, "123"); + verify(submodelFacade, times(1)).getSubmodelPayload(connector1, dataplaneUrl, "123", "BPN123"); + verify(submodelFacade, times(1)).getSubmodelPayload(connector2, dataplaneUrl, "123", "BPN123"); verify(connectorEndpointsService, times(1)).fetchConnectorEndpoints(bpn); } @@ -114,7 +114,7 @@ void shouldThrowGenericEdcClientExceptionIfAllEndpointsThrowExceptions() throws // Arrange final String connector1 = "http://edc.test1"; final String connector2 = "http://edc.test2"; - when(submodelFacade.getSubmodelPayload(any(), any(), any())).thenThrow(new EdcClientException("test")); + when(submodelFacade.getSubmodelPayload(any(), any(), any(), any())).thenThrow(new EdcClientException("test")); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of(connector1, connector2)); final String dataplaneUrl = "http://dataplane.test/123"; final Endpoint endpoint = Endpoint.builder() @@ -131,8 +131,8 @@ void shouldThrowGenericEdcClientExceptionIfAllEndpointsThrowExceptions() throws bpn)); // Assert - verify(submodelFacade, times(1)).getSubmodelPayload(connector1, dataplaneUrl, "123"); - verify(submodelFacade, times(1)).getSubmodelPayload(connector2, dataplaneUrl, "123"); + verify(submodelFacade, times(1)).getSubmodelPayload(connector1, dataplaneUrl, "123", "BPN123"); + verify(submodelFacade, times(1)).getSubmodelPayload(connector2, dataplaneUrl, "123", "BPN123"); verify(connectorEndpointsService, times(1)).fetchConnectorEndpoints(bpn); } } \ No newline at end of file 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 62159f16b2..fc82ff803c 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 @@ -69,7 +69,7 @@ void shouldFillItemContainerWithRelationshipAndAddChildIdsToProcess() // given final String payload = Files.readString( Paths.get(Objects.requireNonNull(getClass().getResource("/singleLevelBomAsBuilt.json")).toURI())); - when(submodelFacade.getSubmodelPayload(anyString(), anyString(), anyString())).thenReturn(new SubmodelDescriptor("cid", payload)); + when(submodelFacade.getSubmodelPayload(anyString(), anyString(), anyString(), any())).thenReturn(new SubmodelDescriptor("cid", payload)); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of("http://localhost")); final ItemContainer.ItemContainerBuilder itemContainerWithShell = ItemContainer.builder() @@ -96,7 +96,7 @@ void shouldFillItemContainerWithUpwardRelationshipAndAddChildIdsToProcess() // given final String payload = Files.readString( Paths.get(Objects.requireNonNull(getClass().getResource("/singleLevelUsageAsBuilt.json")).toURI())); - when(submodelFacade.getSubmodelPayload(anyString(), anyString(), anyString())).thenReturn(new SubmodelDescriptor("cid", payload)); + when(submodelFacade.getSubmodelPayload(anyString(), anyString(), anyString(), any())).thenReturn(new SubmodelDescriptor("cid", payload)); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of("http://localhost")); final ItemContainer.ItemContainerBuilder itemContainerWithShell = ItemContainer.builder() @@ -140,7 +140,7 @@ void shouldPutTombstoneForMissingBpn() { @Test void shouldCatchRestClientExceptionAndPutTombstone() throws EdcClientException { // given - when(submodelFacade.getSubmodelPayload(anyString(), anyString(), anyString())).thenThrow( + when(submodelFacade.getSubmodelPayload(anyString(), anyString(), anyString(), any())).thenThrow( new EdcClientException("Unable to call endpoint")); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of("http://localhost")); @@ -165,7 +165,7 @@ void shouldCatchRestClientExceptionAndPutTombstone() throws EdcClientException { @Test void shouldCatchJsonParseExceptionAndPutTombstone() throws EdcClientException { // given - when(submodelFacade.getSubmodelPayload(anyString(), anyString(), anyString())).thenThrow( + when(submodelFacade.getSubmodelPayload(anyString(), anyString(), anyString(), any())).thenThrow( new EdcClientException(new Exception("Payload did not match expected submodel"))); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of("http://localhost")); final ItemContainer.ItemContainerBuilder itemContainerWithShell = ItemContainer.builder() @@ -197,7 +197,7 @@ void shouldCatchUsagePolicyExceptionAndPutTombstone() throws EdcClientException "address"))))); // when - when(submodelFacade.getSubmodelPayload(any(), any(), any())).thenThrow(new UsagePolicyException("itemId", null, businessPartnerNumber)); + when(submodelFacade.getSubmodelPayload(any(), any(), any(), any())).thenThrow(new UsagePolicyException("itemId", null, businessPartnerNumber)); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of("connector.endpoint.nl")); final ItemContainer result = relationshipDelegate.process(itemContainerWithShell, jobParameter(), new AASTransferProcess(), createKey()); 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 efba84d9a8..f96b066866 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 @@ -152,7 +152,7 @@ void shouldCatchUsagePolicyExceptionAndPutTombstone() throws EdcClientException "testSingleLevelBomAsBuiltEndpoint"))))); // when - when(submodelFacade.getSubmodelPayload(any(), any(), any())).thenThrow(new UsagePolicyException("itemId", null, businessPartnerNumber)); + when(submodelFacade.getSubmodelPayload(any(), any(), any(), any())).thenThrow(new UsagePolicyException("itemId", null, businessPartnerNumber)); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of("connector.endpoint.nl")); final ItemContainer result = submodelDelegate.process(itemContainerShellWithTwoSubmodels, jobParameterCollectAspects(), new AASTransferProcess(), createKey()); @@ -177,7 +177,7 @@ void shouldRequestForAllEndpoints() throws EdcClientException, InvalidSchemaExce ""))))); // when - when(submodelFacade.getSubmodelPayload(any(), any(), any())).thenThrow( + when(submodelFacade.getSubmodelPayload(any(), any(), any(), any())).thenThrow( new ItemNotFoundInCatalogException("test", "itemId")).thenReturn(new SubmodelDescriptor("cid", """ {"test": "test"} """)); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/mock/MockedNotificationReceiverControllerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/mock/MockedNotificationReceiverControllerTest.java index 4060cbeb86..4310d5582e 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/mock/MockedNotificationReceiverControllerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/controller/mock/MockedNotificationReceiverControllerTest.java @@ -68,7 +68,7 @@ class MockedNotificationReceiverControllerTest { void shouldReceiveNotificationAndSendMockedNotificationResult() throws Exception { final String bpn = "BPN1"; when(edcDiscoveryMockConfig.getMockEdcResult()).thenReturn(Map.of(bpn, SupplyChainImpacted.YES)); - when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class))).thenReturn( + when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class), anyString())).thenReturn( () -> true); RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest())); RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(new MockHttpServletRequest())); @@ -82,7 +82,7 @@ void shouldReceiveNotificationAndSendMockedNotificationResult() throws Exception .content(notificationContent) .build()); - verify(edcSubmodelFacade).sendNotification(anyString(), anyString(), any(EdcNotification.class)); + verify(edcSubmodelFacade).sendNotification(anyString(), anyString(), any(EdcNotification.class), anyString()); } @Test diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EdcNotificationSenderTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EdcNotificationSenderTest.java index f9e785a8f4..c01c2ebe31 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EdcNotificationSenderTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/EdcNotificationSenderTest.java @@ -24,6 +24,7 @@ package org.eclipse.tractusx.irs.ess.service; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -64,7 +65,7 @@ void shouldSendEdcNotificationWithSuccess() throws EdcClientException { // given final EdcNotification edcNotification = prepareNotification( "notification-id"); - when(edcSubmodelFacade.sendNotification(anyString(), anyString(), notificationCaptor.capture())).thenReturn( + when(edcSubmodelFacade.sendNotification(anyString(), anyString(), notificationCaptor.capture(), any())).thenReturn( () -> true); when(connectorEndpointsService.fetchConnectorEndpoints("senderBpn")).thenReturn(List.of("senderEdc")); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/InvestigationJobProcessingEventListenerTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/InvestigationJobProcessingEventListenerTest.java index c811a1817f..53bf84b9bb 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/InvestigationJobProcessingEventListenerTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/ess/service/InvestigationJobProcessingEventListenerTest.java @@ -101,7 +101,7 @@ void shouldSendEdcNotificationWhenJobCompleted() throws EdcClientException { // given final String edcBaseUrl = "http://edc-server-url.com"; when(connectorEndpointsService.fetchConnectorEndpoints(anyString())).thenReturn(List.of(edcBaseUrl)); - when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class))).thenReturn( + when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class), any())).thenReturn( () -> true); final JobProcessingFinishedEvent jobProcessingFinishedEvent = new JobProcessingFinishedEvent(jobId.toString(), JobState.COMPLETED.name(), "", Optional.empty()); @@ -111,7 +111,7 @@ void shouldSendEdcNotificationWhenJobCompleted() throws EdcClientException { // then verify(this.edcSubmodelFacade, times(1)).sendNotification(eq(edcBaseUrl), anyString(), - any(EdcNotification.class)); + any(EdcNotification.class), any()); } @Test @@ -121,7 +121,7 @@ void shouldStopProcessingIfNoRelationshipContainsBPN() throws EdcClientException List.of(createRelationship("asPlanned", null, "testParent", "testChild"))); final String edcBaseUrl = "http://edc-server-url.com"; when(connectorEndpointsService.fetchConnectorEndpoints(anyString())).thenReturn(List.of(edcBaseUrl)); - when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class))).thenReturn( + when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class), any())).thenReturn( () -> true); final JobProcessingFinishedEvent jobProcessingFinishedEvent = new JobProcessingFinishedEvent(jobId.toString(), JobState.COMPLETED.name(), "", Optional.empty()); @@ -142,7 +142,7 @@ void shouldHandleCaseWhenRelationshipDoesNotContainBPN() throws EdcClientExcepti createRelationship("asPlanned", null, "parentId2", "childId2"))); final String edcBaseUrl = "http://edc-server-url.com"; when(connectorEndpointsService.fetchConnectorEndpoints(anyString())).thenReturn(List.of(edcBaseUrl)); - when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class))).thenReturn( + when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class), any())).thenReturn( () -> true); final JobProcessingFinishedEvent jobProcessingFinishedEvent = new JobProcessingFinishedEvent(jobId.toString(), JobState.COMPLETED.name(), "", Optional.empty()); @@ -152,7 +152,7 @@ void shouldHandleCaseWhenRelationshipDoesNotContainBPN() throws EdcClientExcepti // then verify(this.edcSubmodelFacade, times(1)).sendNotification(eq(edcBaseUrl), anyString(), - any(EdcNotification.class)); + any(EdcNotification.class), any()); } @Test @@ -161,7 +161,7 @@ void shouldTriggerCorrectNotificationOnNextLevel() throws EdcClientException { createMockForJobIdAndShell(jobId, "bpn", List.of(createRelationship("asPlanned", "BPN1", "parentId1", "childId1"))); final String edcBaseUrl = "http://edc-server-url.com"; - when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class))).thenReturn( + when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class), any())).thenReturn( () -> true); when(connectorEndpointsService.fetchConnectorEndpoints(anyString())).thenReturn(List.of(edcBaseUrl)); final JobProcessingFinishedEvent jobProcessingFinishedEvent = new JobProcessingFinishedEvent(jobId.toString(), @@ -172,7 +172,7 @@ void shouldTriggerCorrectNotificationOnNextLevel() throws EdcClientException { // then verify(this.edcSubmodelFacade, times(1)).sendNotification(eq(edcBaseUrl), eq("notify-request-asset-recursive"), - edcNotificationCaptor.capture()); + edcNotificationCaptor.capture(), any()); assertThat(edcNotificationCaptor.getValue().getHeader().getNotificationType()).isEqualTo( "ess-supplier-request"); final InvestigationNotificationContent content = (InvestigationNotificationContent) edcNotificationCaptor.getValue() @@ -192,7 +192,7 @@ void shouldStopProcessingIfNoEdcAddressIsDiscovered() throws EdcClientException jobProcessingEventListener.handleJobProcessingFinishedEvent(jobProcessingFinishedEvent); // then - verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class)); + verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class), any()); } @Test @@ -207,7 +207,7 @@ void shouldSendCallbackIfNoMoreRelationshipsAreFound() throws EdcClientException jobProcessingEventListener.handleJobProcessingFinishedEvent(jobProcessingFinishedEvent); // then - verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class)); + verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class), any()); verify(this.recursiveNotificationHandler, times(1)).handleNotification(any(), eq(SupplyChainImpacted.NO), eq("bpn"), eq(0)); } @@ -226,7 +226,7 @@ void shouldStopProcessingIfOneOfEdcAddressesIsNotDiscovered() throws EdcClientEx jobProcessingEventListener.handleJobProcessingFinishedEvent(jobProcessingFinishedEvent); // then - verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class)); + verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class), any()); } @Test @@ -238,7 +238,7 @@ void shouldSendEdcRecursiveNotificationWhenJobCompleted() throws EdcClientExcept "urn:uuid:86f69643-3b90-4e34-90bf-789edcf40e7e"))); final String edcBaseUrl = "http://edc-server-url.com"; when(connectorEndpointsService.fetchConnectorEndpoints(anyString())).thenReturn(List.of(edcBaseUrl)); - when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class))).thenReturn( + when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class), any())).thenReturn( () -> true); final JobProcessingFinishedEvent jobProcessingFinishedEvent = new JobProcessingFinishedEvent( recursiveJobId.toString(), JobState.COMPLETED.name(), "", Optional.empty()); @@ -248,7 +248,7 @@ void shouldSendEdcRecursiveNotificationWhenJobCompleted() throws EdcClientExcept // then verify(this.edcSubmodelFacade, times(1)).sendNotification(eq(edcBaseUrl), eq(ASSET_ID_REQUEST_RECURSIVE), - edcNotificationCaptor.capture()); + edcNotificationCaptor.capture(), any()); assertThat(edcNotificationCaptor.getValue().getHeader().getNotificationType()).isEqualTo( "ess-supplier-request"); } @@ -259,7 +259,7 @@ void shouldSendEdcRecursiveNotificationWithMultipleIncidentBPNSs() throws EdcCli createMockForJobIdAndShell(jobId, "bpn", List.of(createRelationship("asPlanned", "BPN1", "parentId1", "childId1")), List.of("BPN1", "BPN2")); final String edcBaseUrl = "http://edc-server-url.com"; - when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class))).thenReturn( + when(edcSubmodelFacade.sendNotification(anyString(), anyString(), any(EdcNotification.class), any())).thenReturn( () -> true); when(connectorEndpointsService.fetchConnectorEndpoints(anyString())).thenReturn(List.of(edcBaseUrl)); final JobProcessingFinishedEvent jobProcessingFinishedEvent = new JobProcessingFinishedEvent(jobId.toString(), @@ -270,14 +270,14 @@ void shouldSendEdcRecursiveNotificationWithMultipleIncidentBPNSs() throws EdcCli // then verify(this.edcSubmodelFacade, times(1)).sendNotification(eq(edcBaseUrl), eq("notify-request-asset-recursive"), - edcNotificationCaptor.capture()); + edcNotificationCaptor.capture(), any()); final InvestigationNotificationContent content = (InvestigationNotificationContent) edcNotificationCaptor.getValue() .getContent(); assertThat(edcNotificationCaptor.getValue().getHeader().getNotificationType()).isEqualTo( "ess-supplier-request"); assertThat(content.getIncidentBPNSs()).containsAll(List.of("BPN1", "BPN2")); assertThat(content.getConcernedCatenaXIds()).containsAll(List.of("childId1")); - verify(this.edcSubmodelFacade, times(1)).sendNotification(any(), any(), any(EdcNotification.class)); + verify(this.edcSubmodelFacade, times(1)).sendNotification(any(), any(), any(EdcNotification.class), any()); } @Test @@ -292,7 +292,7 @@ void shouldCreateTombstoneWhenAspectModelsMissing() throws EdcClientException { jobProcessingEventListener.handleJobProcessingFinishedEvent(finishedEvent); // then - verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class)); + verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class), any()); final Optional job = bpnInvestigationJobCache.findByJobId(jobId); assertThat(job).isPresent(); assertThat(job.get().getJobSnapshot().getTombstones()).hasSize(2); @@ -310,7 +310,7 @@ void shouldCreateTombstoneWhenSiteIdIsMissing() throws EdcClientException { jobProcessingEventListener.handleJobProcessingFinishedEvent(finishedEvent); // then - verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class)); + verify(this.edcSubmodelFacade, times(0)).sendNotification(anyString(), anyString(), any(EdcNotification.class), any()); final Optional job = bpnInvestigationJobCache.findByJobId(jobId); assertThat(job).isPresent(); assertThat(job.get().getJobSnapshot().getTombstones()).hasSize(1); diff --git a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/persistence/BlobPersistence.java b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/persistence/BlobPersistence.java index d8a38fe6be..03e2256ff5 100644 --- a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/persistence/BlobPersistence.java +++ b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/persistence/BlobPersistence.java @@ -26,6 +26,7 @@ import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; /** @@ -33,10 +34,14 @@ */ public interface BlobPersistence { + String DEFAULT_BLOB_NAME = "default"; + void putBlob(String targetBlobName, byte[] blob) throws BlobPersistenceException; Optional getBlob(String sourceBlobName) throws BlobPersistenceException; + Map getAllBlobs() throws BlobPersistenceException; + Collection findBlobByPrefix(String prefix) throws BlobPersistenceException; boolean delete(String blobId, List processIds) throws BlobPersistenceException; diff --git a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/persistence/MinioBlobPersistence.java b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/persistence/MinioBlobPersistence.java index 5bbe56598c..d05906cf32 100644 --- a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/persistence/MinioBlobPersistence.java +++ b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/persistence/MinioBlobPersistence.java @@ -29,7 +29,9 @@ import java.security.NoSuchAlgorithmException; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; import java.util.stream.Stream; import java.util.stream.StreamSupport; @@ -78,14 +80,17 @@ public MinioBlobPersistence(final String endpoint, final String accessKey, final this(bucketName, createClient(endpoint, accessKey, secretKey), daysToLive); } - public MinioBlobPersistence(final String bucketName, final MinioClient client, final int daysToLive) throws BlobPersistenceException { + public MinioBlobPersistence(final String bucketName, final MinioClient client, final int daysToLive) + throws BlobPersistenceException { this.bucketName = bucketName; this.minioClient = client; this.daysToLive = daysToLive; try { createBucketIfNotExists(bucketName); - } catch (ServerException | InsufficientDataException | ErrorResponseException | IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException e) { + } catch (ServerException | InsufficientDataException | ErrorResponseException | IOException + | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException + | InternalException e) { throw new BlobPersistenceException("Encountered error while trying to create min.io client", e); } } @@ -140,7 +145,9 @@ public void putBlob(final String targetBlobName, final byte[] blob) throws BlobP .stream(byteArrayInputStream, byteArrayInputStream.available(), -1) .build()); log.debug("Saving to bucket name {} with object name {}", bucketName, targetBlobName); - } catch (ServerException | InsufficientDataException | ErrorResponseException | IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException e) { + } catch (ServerException | InsufficientDataException | ErrorResponseException | IOException + | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException + | InternalException e) { throw new BlobPersistenceException("Encountered error while trying to store blob", e); } } @@ -155,7 +162,8 @@ public Optional getBlob(final String sourceBlobName) throws BlobPersiste return Optional.empty(); } throw createLoadFailedException(e); - } catch (ServerException | InsufficientDataException | IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException e) { + } catch (ServerException | InsufficientDataException | IOException | NoSuchAlgorithmException + | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException e) { throw createLoadFailedException(e); } try (response) { @@ -163,7 +171,31 @@ public Optional getBlob(final String sourceBlobName) throws BlobPersiste } catch (IOException e) { throw createLoadFailedException(e); } + } + + /** + * @return Map of bpn to matching blobs + */ + @Override + public Map getAllBlobs() throws BlobPersistenceException { + final Iterable> items = getItems(); + final Map result = new ConcurrentHashMap<>(); + for (final Result item : items) { + try { + final String objectName = item.get().objectName(); + try (GetObjectResponse response = minioClient.getObject( + GetObjectArgs.builder().bucket(bucketName).object(objectName).build())) { + result.put(objectName, response.readAllBytes()); + } + } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException + | InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException + | XmlParserException e) { + throw createLoadFailedException(e); + } + } + + return result; } private BlobPersistenceException createLoadFailedException(final Throwable cause) { @@ -194,7 +226,8 @@ public boolean delete(final String sourceBlobName, final List processIds } else { throw new BlobPersistenceException("Encountered error while trying to delete blob", e); } - } catch (ServerException | InsufficientDataException | IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException e) { + } catch (ServerException | InsufficientDataException | IOException | NoSuchAlgorithmException + | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException e) { throw new BlobPersistenceException("Encountered error while trying to delete blob", e); } } @@ -203,7 +236,9 @@ private void deleteConnectedProcessesBlobs(final List processIds) { processIds.forEach(processId -> { try { minioClient.removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(processId).build()); - } catch (ServerException | InsufficientDataException | IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException | ErrorResponseException e) { + } catch (ServerException | InsufficientDataException | IOException | NoSuchAlgorithmException + | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException + | ErrorResponseException e) { log.info("No object data with process Id {} found", processId); } }); @@ -221,10 +256,16 @@ private Stream getBlobIfPresent(final String sourceBlobName) { private Stream getItem(final Result result) { try { return Stream.of(result.get()); - } catch (ServerException | InsufficientDataException | ErrorResponseException | IOException | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException | InternalException e) { + } catch (ServerException | InsufficientDataException | ErrorResponseException | IOException + | NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException + | InternalException e) { log.error("Encountered error while trying to retrieve result content", e); return Stream.empty(); } } + private Iterable> getItems() { + return minioClient.listObjects(ListObjectsArgs.builder().bucket(bucketName).build()); + } + } diff --git a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/persistence/MinioBlobPersistenceTest.java b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/persistence/MinioBlobPersistenceTest.java index e62a2ae9e6..c0bc89d951 100644 --- a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/persistence/MinioBlobPersistenceTest.java +++ b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/persistence/MinioBlobPersistenceTest.java @@ -32,10 +32,18 @@ import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; import java.nio.charset.StandardCharsets; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.util.Collection; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Stream; @@ -43,8 +51,16 @@ import io.minio.MinioClient; import io.minio.Result; import io.minio.errors.ErrorResponseException; +import io.minio.errors.InsufficientDataException; +import io.minio.errors.InternalException; +import io.minio.errors.InvalidResponseException; +import io.minio.errors.ServerException; +import io.minio.errors.XmlParserException; +import io.minio.messages.Contents; import io.minio.messages.ErrorResponse; import io.minio.messages.Item; +import lombok.AllArgsConstructor; +import okhttp3.Headers; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -217,4 +233,36 @@ void shouldNotFindBlobByPrefix() throws Exception { assertThat(blobsByPrefix).isEmpty(); } + @Test + void shouldReturnAllBlobs() throws BlobPersistenceException, ServerException, InsufficientDataException, ErrorResponseException, + IOException, NoSuchAlgorithmException, InvalidKeyException, InvalidResponseException, XmlParserException, + InternalException { + final String name = "test-name"; + when(client.listObjects(any())).thenReturn(List.of(new Result<>(new TestItem(name)))); + + final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); + objectOutputStream.writeUTF(""); + InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray()); + ObjectInputStream outputStream = new ObjectInputStream(inputStream); + + when(client.getObject(any())).thenReturn(new GetObjectResponse(null, null, null, null, outputStream)); + + // act + final Map allBlobs = testee.getAllBlobs(); + + // assert + assertThat(allBlobs.get(name)).isNotNull(); + } + + @AllArgsConstructor + static class TestItem extends Item { + + private final String name; + + @Override + public String objectName() { + return name; + } + } } \ No newline at end of file diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java index 9abecd843e..00205d2ec7 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationService.java @@ -65,7 +65,7 @@ public class ContractNegotiationService { private final EdcConfiguration config; public NegotiationResponse negotiate(final String providerConnectorUrl, final CatalogItem catalogItem, - final EndpointDataReferenceStatus endpointDataReferenceStatus) + final EndpointDataReferenceStatus endpointDataReferenceStatus, final String bpn) throws ContractNegotiationException, UsagePolicyException, TransferProcessException { EndpointDataReferenceStatus resultEndpointDataReferenceStatus; @@ -85,7 +85,7 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca switch (resultEndpointDataReferenceStatus.tokenStatus()) { case REQUIRED_NEW -> { final CompletableFuture responseFuture = startNewNegotiation(providerConnectorUrl, - catalogItem); + catalogItem, bpn); negotiationResponse = Objects.requireNonNull(getNegotiationResponse(responseFuture)); contractAgreementId = negotiationResponse.getContractAgreementId(); } @@ -120,10 +120,10 @@ public NegotiationResponse negotiate(final String providerConnectorUrl, final Ca } private CompletableFuture startNewNegotiation(final String providerConnectorUrl, - final CatalogItem catalogItem) throws UsagePolicyException { + final CatalogItem catalogItem, final String bpn) throws UsagePolicyException { log.info("Staring new contract negotiation."); - if (!policyCheckerService.isValid(catalogItem.getPolicy())) { + if (!policyCheckerService.isValid(catalogItem.getPolicy(), bpn)) { log.info("Policy was not allowed, canceling negotiation."); throw new UsagePolicyException(catalogItem.getItemId(), catalogItem.getPolicy(), catalogItem.getConnectorId()); 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 0d8fae946e..b1222f6f43 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 @@ -37,20 +37,20 @@ /** * Public API facade for EDC domain */ -@SuppressWarnings("PMD.ExcessiveImports") +@SuppressWarnings({"PMD.ExcessiveImports", "PMD.UseObjectForClearerAPI"}) public interface EdcSubmodelClient { CompletableFuture getSubmodelPayload(String connectorEndpoint, String submodelDataplaneUrl, - String assetId) throws EdcClientException; + String assetId, String bpn) throws EdcClientException; CompletableFuture sendNotification(String submodelEndpointAddress, String assetId, - EdcNotification notification) throws EdcClientException; + EdcNotification notification, String bpn) throws EdcClientException; List> getEndpointReferencesForAsset(String endpointAddress, - String filterKey, String filterValue) throws EdcClientException; + String filterKey, String filterValue, String bpn) throws EdcClientException; List> getEndpointReferencesForAsset(String endpointAddress, - String filterKey, String filterValue, EndpointDataReferenceStatus cachedEndpointDataReference) + String filterKey, String filterValue, EndpointDataReferenceStatus cachedEndpointDataReference, String bpn) throws EdcClientException; } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java index 4160a53f84..601fa53403 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientImpl.java @@ -64,7 +64,8 @@ @Slf4j @RequiredArgsConstructor @SuppressWarnings({ "PMD.TooManyMethods", - "PMD.ExcessiveImports" + "PMD.ExcessiveImports", + "PMD.UseObjectForClearerAPI" }) public class EdcSubmodelClientImpl implements EdcSubmodelClient { @@ -147,15 +148,14 @@ private Optional sendSubmodelNotification(final String @Override public CompletableFuture getSubmodelPayload(final String connectorEndpoint, - final String submodelDataplaneUrl, final String assetId) throws EdcClientException { + final String submodelDataplaneUrl, final String assetId, final String bpn) throws EdcClientException { final CheckedSupplier> waitingForSubmodelRetrieval = () -> { - log.info("Requesting raw SubmodelPayload for endpoint '{}'.", connectorEndpoint); final StopWatch stopWatch = new StopWatch(); stopWatch.start("Get EDC Submodel task for raw payload, endpoint " + connectorEndpoint); - final EndpointDataReference dataReference = getEndpointDataReference(connectorEndpoint, assetId); + final EndpointDataReference dataReference = getEndpointDataReference(connectorEndpoint, assetId, bpn); return pollingService.createJob() .action(() -> retrieveSubmodelData(submodelDataplaneUrl, stopWatch, dataReference)) @@ -168,7 +168,7 @@ public CompletableFuture getSubmodelPayload(final String con return execute(connectorEndpoint, waitingForSubmodelRetrieval); } - private EndpointDataReference getEndpointDataReference(final String connectorEndpoint, final String assetId) + private EndpointDataReference getEndpointDataReference(final String connectorEndpoint, final String assetId, final String bpn) throws EdcClientException { final EndpointDataReference result; @@ -180,18 +180,18 @@ private EndpointDataReference getEndpointDataReference(final String connectorEnd log.info("Endpoint data reference found in cache with token status valid, reusing cache record."); result = cachedReference.endpointDataReference(); } else { - result = getEndpointDataReferenceAndAddToStorage(connectorEndpoint, assetId, cachedReference); + result = getEndpointDataReferenceAndAddToStorage(connectorEndpoint, assetId, cachedReference, bpn); } return result; } private EndpointDataReference getEndpointDataReferenceAndAddToStorage(final String connectorEndpoint, - final String assetId, final EndpointDataReferenceStatus cachedEndpointDataReference) + final String assetId, final EndpointDataReferenceStatus cachedEndpointDataReference, final String bpn) throws EdcClientException { try { final EndpointDataReference endpointDataReference = awaitEndpointReferenceForAsset(connectorEndpoint, - NAMESPACE_EDC_ID, assetId, cachedEndpointDataReference).get(); + NAMESPACE_EDC_ID, assetId, cachedEndpointDataReference, bpn).get(); endpointDataReferenceCacheService.putEndpointDataReferenceIntoStorage(assetId, endpointDataReference); return endpointDataReference; @@ -205,12 +205,11 @@ private EndpointDataReference getEndpointDataReferenceAndAddToStorage(final Stri @Override public CompletableFuture sendNotification(final String connectorEndpoint, - final String assetId, final EdcNotification notification) throws EdcClientException { - + final String assetId, final EdcNotification notification, final String bpn) throws EdcClientException { return execute(connectorEndpoint, () -> { final StopWatch stopWatch = new StopWatch(); stopWatch.start("Send EDC notification task, endpoint " + connectorEndpoint); - final EndpointDataReference endpointDataReference = getEndpointDataReference(connectorEndpoint, assetId); + final EndpointDataReference endpointDataReference = getEndpointDataReference(connectorEndpoint, assetId, bpn); return sendNotificationAsync(assetId, notification, stopWatch, endpointDataReference); }); @@ -218,16 +217,15 @@ public CompletableFuture sendNotification(final String @Override public List> getEndpointReferencesForAsset(final String endpointAddress, - final String filterKey, final String filterValue) throws EdcClientException { + final String filterKey, final String filterValue, final String bpn) throws EdcClientException { return execute(endpointAddress, () -> getEndpointReferencesForAsset(endpointAddress, filterKey, filterValue, - new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW))); + new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW), bpn)); } @Override public List> getEndpointReferencesForAsset(final String endpointAddress, final String filterKey, final String filterValue, - final EndpointDataReferenceStatus endpointDataReferenceStatus) throws EdcClientException { - + final EndpointDataReferenceStatus endpointDataReferenceStatus, final String bpn) throws EdcClientException { final StopWatch stopWatch = new StopWatch(); stopWatch.start("Get EDC Submodel task for shell descriptor, endpoint " + endpointAddress); @@ -250,7 +248,7 @@ public List> getEndpointReferencesForAs final NegotiationResponse negotiationResponse; try { - negotiationResponse = negotiateContract(endpointDataReferenceStatus, contractOffer, providerWithSuffix); + negotiationResponse = negotiateContract(endpointDataReferenceStatus, contractOffer, providerWithSuffix, bpn); final String storageId = getStorageId(endpointDataReferenceStatus, negotiationResponse); @@ -271,11 +269,11 @@ public List> getEndpointReferencesForAs } private NegotiationResponse negotiateContract(final EndpointDataReferenceStatus endpointDataReferenceStatus, - final CatalogItem catalogItem, final String providerWithSuffix) throws EdcClientException { + final CatalogItem catalogItem, final String providerWithSuffix, final String bpn) throws EdcClientException { final NegotiationResponse response; try { response = contractNegotiationService.negotiate(providerWithSuffix, catalogItem, - endpointDataReferenceStatus); + endpointDataReferenceStatus, bpn); } catch (TransferProcessException | UsagePolicyException | ContractNegotiationException e) { throw new EdcClientException(("Negotiation failed for endpoint '%s', " + "tokenStatus '%s', " + "providerWithSuffix '%s', catalogItem '%s'").formatted( @@ -287,7 +285,7 @@ private NegotiationResponse negotiateContract(final EndpointDataReferenceStatus private CompletableFuture awaitEndpointReferenceForAsset(final String endpointAddress, final String filterKey, final String filterValue, - final EndpointDataReferenceStatus endpointDataReferenceStatus) throws EdcClientException { + final EndpointDataReferenceStatus endpointDataReferenceStatus, final String bpn) throws EdcClientException { final StopWatch stopWatch = new StopWatch(); stopWatch.start("Get EDC Submodel task for shell descriptor, endpoint " + endpointAddress); @@ -296,7 +294,7 @@ private CompletableFuture awaitEndpointReferenceForAsset( final List items = catalogFacade.fetchCatalogByFilter(providerWithSuffix, filterKey, filterValue); final NegotiationResponse response = contractNegotiationService.negotiate(providerWithSuffix, - items.stream().findFirst().orElseThrow(), endpointDataReferenceStatus); + items.stream().findFirst().orElseThrow(), endpointDataReferenceStatus, bpn); final String storageId = getStorageId(endpointDataReferenceStatus, response); diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStub.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStub.java index 5fb8796813..9ac58b2bd1 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStub.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStub.java @@ -41,6 +41,7 @@ /** * Submodel facade stub used in local environment */ +@SuppressWarnings("PMD.UseObjectForClearerAPI") public class EdcSubmodelClientLocalStub implements EdcSubmodelClient { private final SubmodelTestdataCreator testdataCreator; @@ -52,7 +53,7 @@ public EdcSubmodelClientLocalStub(final CxTestDataContainer cxTestDataContainer) @Override public CompletableFuture getSubmodelPayload(final String connectorEndpoint, - final String submodelDataplaneUrl, final String assetId) throws EdcClientException { + final String submodelDataplaneUrl, final String assetId, final String bpn) throws EdcClientException { if ("urn:uuid:c35ee875-5443-4a2d-bc14-fdacd64b9446".equals(assetId)) { throw new EdcClientException("Dummy Exception"); } @@ -63,7 +64,7 @@ public CompletableFuture getSubmodelPayload(final String con @Override public CompletableFuture sendNotification(final String submodelEndpointAddress, - final String assetId, final EdcNotification notification) { + final String assetId, final EdcNotification notification, final String bpn) { // not actually sending anything, just return success response return CompletableFuture.completedFuture(() -> true); } @@ -71,13 +72,13 @@ public CompletableFuture sendNotification(final String @Override public List> getEndpointReferencesForAsset(final String endpointAddress, final String filterKey, final String filterValue, - final EndpointDataReferenceStatus cachedEndpointDataReference) throws EdcClientException { + final EndpointDataReferenceStatus cachedEndpointDataReference, final String bpn) throws EdcClientException { throw new EdcClientException("Not implemented"); } @Override public List> getEndpointReferencesForAsset(final String endpointAddress, - final String filterKey, final String filterValue) throws EdcClientException { + final String filterKey, final String filterValue, final String bpn) throws EdcClientException { throw new EdcClientException("Not implemented"); } } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java index 20ee2f59bc..e99107d1de 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacade.java @@ -43,7 +43,7 @@ */ @Slf4j @RequiredArgsConstructor -@SuppressWarnings("PMD.AvoidDuplicateLiterals") +@SuppressWarnings({"PMD.AvoidDuplicateLiterals", "PMD.UseObjectForClearerAPI"}) public class EdcSubmodelFacade { private final EdcSubmodelClient client; @@ -52,9 +52,9 @@ public class EdcSubmodelFacade { @SuppressWarnings("PMD.PreserveStackTrace") public SubmodelDescriptor getSubmodelPayload(final String connectorEndpoint, final String submodelDataplaneUrl, - final String assetId) throws EdcClientException { + final String assetId, final String bpn) throws EdcClientException { try { - return client.getSubmodelPayload(connectorEndpoint, submodelDataplaneUrl, assetId) + return client.getSubmodelPayload(connectorEndpoint, submodelDataplaneUrl, assetId, bpn) .get(config.getAsyncTimeoutMillis(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { log.debug("InterruptedException occurred.", e); @@ -74,10 +74,10 @@ public SubmodelDescriptor getSubmodelPayload(final String connectorEndpoint, fin @SuppressWarnings("PMD.PreserveStackTrace") public EdcNotificationResponse sendNotification(final String submodelEndpointAddress, final String assetId, - final EdcNotification notification) throws EdcClientException { + final EdcNotification notification, final String bpn) throws EdcClientException { try { log.debug("Sending EDC Notification '{}'", notification); - return client.sendNotification(submodelEndpointAddress, assetId, notification) + return client.sendNotification(submodelEndpointAddress, assetId, notification, bpn) .get(config.getAsyncTimeoutMillis(), TimeUnit.MILLISECONDS); } catch (InterruptedException e) { Thread.currentThread().interrupt(); @@ -94,8 +94,8 @@ public EdcNotificationResponse sendNotification(final String submodelEndpointAdd } public List> getEndpointReferencesForAsset(final String endpointAddress, - final String filterKey, final String filterValue) throws EdcClientException { - return client.getEndpointReferencesForAsset(endpointAddress, filterKey, filterValue); + final String filterKey, final String filterValue, final String bpn) throws EdcClientException { + return client.getEndpointReferencesForAsset(endpointAddress, filterKey, filterValue, bpn); } } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/policy/AcceptedPoliciesProvider.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/policy/AcceptedPoliciesProvider.java index 8f4ffbce3d..c33707d3ba 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/policy/AcceptedPoliciesProvider.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/policy/AcceptedPoliciesProvider.java @@ -33,7 +33,7 @@ * Provides policies to be accepted during EDC negotiation */ public interface AcceptedPoliciesProvider { - List getAcceptedPolicies(); + List getAcceptedPolicies(String bpn); /** * Default provider if no other beans are loaded. @@ -46,7 +46,7 @@ class DefaultAcceptedPoliciesProvider implements AcceptedPoliciesProvider { private final List acceptedPolicies = new ArrayList<>(); @Override - public List getAcceptedPolicies() { + public List getAcceptedPolicies(final String bpn) { return List.copyOf(acceptedPolicies); } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/policy/PolicyCheckerService.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/policy/PolicyCheckerService.java index 0dbe398aad..062bdafad8 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/policy/PolicyCheckerService.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/policy/PolicyCheckerService.java @@ -43,8 +43,8 @@ public class PolicyCheckerService { private final AcceptedPoliciesProvider policyStore; private final ConstraintCheckerService constraintCheckerService; - public boolean isValid(final Policy policy) { - return policy.getPermissions().stream().allMatch(permission -> isValid(permission, getValidStoredPolicies())); + public boolean isValid(final Policy policy, final String bpn) { + return policy.getPermissions().stream().allMatch(permission -> isValid(permission, getValidStoredPolicies(bpn))); } private boolean isValid(final Permission permission, final List validStoredPolicies) { @@ -53,8 +53,8 @@ private boolean isValid(final Permission permission, final List acceptedPolicy.policy(), permission.getConstraints())); } - private List getValidStoredPolicies() { - return policyStore.getAcceptedPolicies() + private List getValidStoredPolicies(final String bpn) { + return policyStore.getAcceptedPolicies(bpn) .stream() .filter(p -> p.validUntil().isAfter(OffsetDateTime.now())) .toList(); diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java index 8ac92edb92..18ee578180 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/ContractNegotiationServiceTest.java @@ -84,7 +84,7 @@ void shouldNegotiateSuccessfully() final var assetId = "testTarget"; final String offerId = "offerId"; final CatalogItem catalogItem = createCatalogItem(assetId, offerId); - when(policyCheckerService.isValid(any())).thenReturn(Boolean.TRUE); + when(policyCheckerService.isValid(any(), any())).thenReturn(Boolean.TRUE); when(edcControlPlaneClient.startNegotiations(any())).thenReturn( Response.builder().responseId("negotiationId").build()); CompletableFuture response = CompletableFuture.completedFuture( @@ -97,7 +97,7 @@ void shouldNegotiateSuccessfully() // act NegotiationResponse result = testee.negotiate(CONNECTOR_URL, catalogItem, - new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); + new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW), "bpn"); // assert assertThat(result).isNotNull(); @@ -110,7 +110,7 @@ void shouldThrowErrorWhenRetrievingNegotiationResult() { final var assetId = "testTarget"; final String offerId = "offerId"; final CatalogItem catalogItem = createCatalogItem(assetId, offerId); - when(policyCheckerService.isValid(any())).thenReturn(Boolean.TRUE); + when(policyCheckerService.isValid(any(), any())).thenReturn(Boolean.TRUE); when(edcControlPlaneClient.startNegotiations(any())).thenReturn( Response.builder().responseId("negotiationId").build()); CompletableFuture response = CompletableFuture.failedFuture( @@ -119,7 +119,7 @@ void shouldThrowErrorWhenRetrievingNegotiationResult() { // act & assert assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus(null, - EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW))).isInstanceOf(EdcClientException.class); + EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW), "bpn")).isInstanceOf(EdcClientException.class); } @Test @@ -128,7 +128,7 @@ void shouldThrowErrorWhenRetrievingTransferResult() { final var assetId = "testTarget"; final String offerId = "offerId"; final CatalogItem catalogItem = createCatalogItem(assetId, offerId); - when(policyCheckerService.isValid(any())).thenReturn(Boolean.TRUE); + when(policyCheckerService.isValid(any(), any())).thenReturn(Boolean.TRUE); when(edcControlPlaneClient.startNegotiations(any())).thenReturn( Response.builder().responseId("negotiationId").build()); @@ -144,7 +144,7 @@ void shouldThrowErrorWhenRetrievingTransferResult() { // act & assert assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus(null, - EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW))).isInstanceOf(EdcClientException.class); + EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW), "bpn")).isInstanceOf(EdcClientException.class); } @Test @@ -156,11 +156,11 @@ void shouldThrowErrorWhenPolicyCheckerReturnFalse() { .policy(createPolicy(assetId)) .assetPropId(assetId) .build(); - when(policyCheckerService.isValid(any())).thenReturn(Boolean.FALSE); + when(policyCheckerService.isValid(any(), any())).thenReturn(Boolean.FALSE); // act & assert assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus(null, - EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW))).isInstanceOf(EdcClientException.class); + EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW), "bpn")).isInstanceOf(EdcClientException.class); } @Test @@ -170,7 +170,7 @@ void shouldStartNegotiationProcessWhenTokenStatusIsRequiredNew() final var assetId = "testTarget"; final String offerId = "offerId"; final CatalogItem catalogItem = createCatalogItem(assetId, offerId); - when(policyCheckerService.isValid(any())).thenReturn(Boolean.TRUE); + when(policyCheckerService.isValid(any(), any())).thenReturn(Boolean.TRUE); when(edcControlPlaneClient.startNegotiations(any())).thenReturn( Response.builder().responseId("negotiationId").build()); CompletableFuture negotiationResponse = CompletableFuture.completedFuture( @@ -183,7 +183,7 @@ void shouldStartNegotiationProcessWhenTokenStatusIsRequiredNew() // when testee.negotiate(CONNECTOR_URL, catalogItem, - new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW)); + new EndpointDataReferenceStatus(null, EndpointDataReferenceStatus.TokenStatus.REQUIRED_NEW), "bpn"); // then verify(edcControlPlaneClient).startNegotiations(any()); @@ -196,7 +196,7 @@ void shouldStartNegotiationProcessWhenTokenStatusIsMissing() final var assetId = "testTarget"; final String offerId = "offerId"; final CatalogItem catalogItem = createCatalogItem(assetId, offerId); - when(policyCheckerService.isValid(any())).thenReturn(Boolean.TRUE); + when(policyCheckerService.isValid(any(), any())).thenReturn(Boolean.TRUE); when(edcControlPlaneClient.startNegotiations(any())).thenReturn( Response.builder().responseId("negotiationId").build()); CompletableFuture negotiationResponse = CompletableFuture.completedFuture( @@ -208,7 +208,7 @@ void shouldStartNegotiationProcessWhenTokenStatusIsMissing() CompletableFuture.completedFuture(TransferProcessResponse.builder().build())); // when - testee.negotiate(CONNECTOR_URL, catalogItem, null); + testee.negotiate(CONNECTOR_URL, catalogItem, null, "bpn"); // then verify(edcControlPlaneClient).startNegotiations(any()); @@ -231,7 +231,7 @@ void shouldNotStartNewNegotiationWhenTokenIsExpired() // when testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus( EndpointDataReference.Builder.newInstance().authKey("").authCode(encodedAuthCode).endpoint("").build(), - EndpointDataReferenceStatus.TokenStatus.EXPIRED)); + EndpointDataReferenceStatus.TokenStatus.EXPIRED), "bpn"); // then verify(edcControlPlaneClient, never()).startNegotiations(any()); @@ -248,7 +248,7 @@ void shouldThrowInvalidStateExceptionWhenTokenIsValid() { // then assertThatThrownBy(() -> testee.negotiate(CONNECTOR_URL, catalogItem, new EndpointDataReferenceStatus( EndpointDataReference.Builder.newInstance().authKey("").endpoint("").authCode("").build(), - EndpointDataReferenceStatus.TokenStatus.VALID))).isInstanceOf(IllegalStateException.class); + EndpointDataReferenceStatus.TokenStatus.VALID), "bpn")).isInstanceOf(IllegalStateException.class); } } \ No newline at end of file diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStubTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStubTest.java index 9be5557c9c..f979c91a8e 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStubTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientLocalStubTest.java @@ -47,6 +47,6 @@ void shouldThrowExceptionFor() { String assetId = "urn:uuid:c35ee875-5443-4a2d-bc14-fdacd64b9446"; // when - assertThrows(EdcClientException.class, () -> edcSubmodelClientLocalStub.getSubmodelPayload("", "", assetId)); + assertThrows(EdcClientException.class, () -> edcSubmodelClientLocalStub.getSubmodelPayload("", "", assetId, "")); } } \ No newline at end of file diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java index c65a83b62c..f800bc7a5a 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelClientTest.java @@ -136,7 +136,7 @@ void shouldRetrieveValidRelationship() throws Exception { when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("itemId").build())); when(contractNegotiationService.negotiate(any(), any(), - eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( + eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)), any())).thenReturn( NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference ref = TestMother.endpointDataReference(agreementId); when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( @@ -147,7 +147,7 @@ void shouldRetrieveValidRelationship() throws Exception { new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act - final var result = testee.getSubmodelPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); + final var result = testee.getSubmodelPayload(ENDPOINT_ADDRESS, "suffix", "assetId", "bpn"); final String resultingRelationships = result.get(5, TimeUnit.SECONDS).getPayload(); // assert @@ -163,7 +163,7 @@ void shouldSendNotificationSuccessfully() throws Exception { final EdcNotification notification = EdcNotification.builder().build(); when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("itemId").build())); - when(contractNegotiationService.negotiate(any(), any(), any())).thenReturn( + when(contractNegotiationService.negotiate(any(), any(), any(), any())).thenReturn( NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference ref = mock(EndpointDataReference.class); when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( @@ -173,7 +173,7 @@ void shouldSendNotificationSuccessfully() throws Exception { new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act - final var result = testee.sendNotification(CONNECTOR_ENDPOINT, "notify-request-asset", notification); + final var result = testee.sendNotification(CONNECTOR_ENDPOINT, "notify-request-asset", notification, "bpn"); final EdcNotificationResponse response = result.get(5, TimeUnit.SECONDS); // assert @@ -204,7 +204,7 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsBuil new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act - final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) + final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID, "bpn") .get(5, TimeUnit.SECONDS) .getPayload(); @@ -225,7 +225,7 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsPlan new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act - final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) + final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID, "bpn") .get(5, TimeUnit.SECONDS) .getPayload(); @@ -246,7 +246,7 @@ void shouldReturnRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelBomAsSpec new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act - final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) + final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID, "bpn") .get(5, TimeUnit.SECONDS) .getPayload(); @@ -267,7 +267,7 @@ void shouldReturnEmptyRelationshipsWhenRequestingWithCatenaXIdAndSingleLevelUsag new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act - final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) + final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID, "bpn") .get(5, TimeUnit.SECONDS) .getPayload(); @@ -289,7 +289,7 @@ void shouldReturnEmptyRelationshipsWhenRequestingWithNotExistingCatenaXIdAndSing new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act - final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID) + final String submodelResponse = testee.getSubmodelPayload("http://localhost/", "/submodel", ASSET_ID, "bpn") .get(5, TimeUnit.SECONDS) .getPayload(); @@ -311,7 +311,7 @@ void shouldReturnRawSerialPartWhenExisting() throws Exception { // act final String submodelResponse = testee.getSubmodelPayload("https://connector.endpoint.com", - "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID) + "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID, "bpn") .get(5, TimeUnit.SECONDS) .getPayload(); @@ -335,7 +335,7 @@ void shouldUseDecodedTargetId() throws Exception { // act final String submodelResponse = testee.getSubmodelPayload("https://connector.endpoint.com", - "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID) + "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", ASSET_ID, "bpn") .get(5, TimeUnit.SECONDS) .getPayload(); @@ -359,7 +359,7 @@ void shouldReturnSameRelationshipsForDifferentDirections() throws Exception { // act final String relationshipsJson = testee.getSubmodelPayload("http://localhost/", "_singleLevelBomAsBuilt", - ASSET_ID).get(5, TimeUnit.SECONDS).getPayload(); + ASSET_ID, "bpn").get(5, TimeUnit.SECONDS).getPayload(); final var relationships = StringMapper.mapFromString(relationshipsJson, RelationshipAspect.from(asBuilt, Direction.DOWNWARD).getSubmodelClazz()).asRelationships(); @@ -372,7 +372,7 @@ void shouldReturnSameRelationshipsForDifferentDirections() throws Exception { prepareTestdata(childCatenaXId.getGlobalAssetId(), "_singleLevelUsageAsBuilt"); final String singleLevelUsageRelationshipsJson = testee.getSubmodelPayload("http://localhost/", - "_singleLevelUsageAsBuilt", ASSET_ID).get(5, TimeUnit.SECONDS).getPayload(); + "_singleLevelUsageAsBuilt", ASSET_ID, "bpn").get(5, TimeUnit.SECONDS).getPayload(); final var singleLevelUsageRelationships = StringMapper.mapFromString(singleLevelUsageRelationshipsJson, RelationshipAspect.from(asBuilt, Direction.UPWARD).getSubmodelClazz()).asRelationships(); @@ -395,7 +395,7 @@ void shouldRetrieveEndpointReferenceForAsset() throws Exception { when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("asset-id").build())); when(contractNegotiationService.negotiate(any(), any(), - eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( + eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)), any())).thenReturn( NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference expected = mock(EndpointDataReference.class); when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( @@ -403,7 +403,7 @@ void shouldRetrieveEndpointReferenceForAsset() throws Exception { // act final var result = testee.getEndpointReferencesForAsset(ENDPOINT_ADDRESS, filterKey, filterValue, - new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); + new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW), "bpn"); final EndpointDataReference actual = result.get(0).get(5, TimeUnit.SECONDS); // assert @@ -421,14 +421,14 @@ void shouldRetrieveEndpointReferenceForAsset2() throws Exception { when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("asset-id").build())); when(contractNegotiationService.negotiate(any(), any(), - eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( + eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)), any())).thenReturn( NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference expected = mock(EndpointDataReference.class); when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( Optional.ofNullable(expected)); // act - final var result = testee.getEndpointReferencesForAsset(ENDPOINT_ADDRESS, filterKey, filterValue); + final var result = testee.getEndpointReferencesForAsset(ENDPOINT_ADDRESS, filterKey, filterValue, "bpn"); final EndpointDataReference actual = result.get(0).get(5, TimeUnit.SECONDS); // assert @@ -445,11 +445,11 @@ void shouldUseCachedEndpointReferenceValueWhenTokenIsValid() when(edcDataPlaneClient.getData(any(), any())).thenReturn(value); // act - final var resultFuture = testee.getSubmodelPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); + final var resultFuture = testee.getSubmodelPayload(ENDPOINT_ADDRESS, "suffix", "assetId", "bpn"); // assert final String result = resultFuture.get().getPayload(); - verify(contractNegotiationService, never()).negotiate(any(), any(), any()); + verify(contractNegotiationService, never()).negotiate(any(), any(), any(), any()); assertThat(result).isEqualTo(value); } @@ -462,7 +462,7 @@ void shouldCreateCacheRecordWhenTokenIsNotValid() throws EdcClientException { when(catalogFacade.fetchCatalogByFilter(any(), any(), any())).thenReturn( List.of(CatalogItem.builder().itemId("itemId").build())); when(contractNegotiationService.negotiate(any(), any(), - eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( + eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)), any())).thenReturn( NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference ref = mock(EndpointDataReference.class); when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( @@ -471,7 +471,7 @@ void shouldCreateCacheRecordWhenTokenIsNotValid() throws EdcClientException { new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)); // act - testee.getSubmodelPayload(ENDPOINT_ADDRESS, "suffix", "assetId"); + testee.getSubmodelPayload(ENDPOINT_ADDRESS, "suffix", "assetId", "bpn"); // assert verify(endpointDataReferenceCacheService, times(1)).putEndpointDataReferenceIntoStorage("assetId", ref); @@ -482,13 +482,12 @@ private void prepareTestdata(final String catenaXId, final String submodelDataSu final String agreementId = "agreementId"; when(contractNegotiationService.negotiate(any(), any(), - eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)))).thenReturn( + eq(new EndpointDataReferenceStatus(null, TokenStatus.REQUIRED_NEW)), any())).thenReturn( NegotiationResponse.builder().contractAgreementId(agreementId).build()); final EndpointDataReference ref = TestMother.endpointDataReference(agreementId); when(endpointDataReferenceCacheService.getEndpointDataReferenceFromStorage(agreementId)).thenReturn( Optional.ofNullable(ref)); - final SubmodelTestdataCreator submodelTestdataCreator = new SubmodelTestdataCreator( localTestDataConfiguration.cxTestDataContainer()); final String data = StringMapper.mapToString( diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java index 2c0b6884e7..95f81b1fc7 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/EdcSubmodelFacadeTest.java @@ -76,11 +76,11 @@ void shouldThrowExecutionExceptionForSubmodel() throws EdcClientException { // arrange final ExecutionException e = new ExecutionException(new EdcClientException("test")); final CompletableFuture future = CompletableFuture.failedFuture(e); - when(client.getSubmodelPayload(any(), any(), any())).thenReturn(future); + when(client.getSubmodelPayload(any(), any(), any(), any())).thenReturn(future); // act ThrowableAssert.ThrowingCallable action = () -> testee.getSubmodelPayload(CONNECTOR_ENDPOINT, - SUBMODEL_SUFIX, ASSET_ID); + SUBMODEL_SUFIX, ASSET_ID, "bpn"); // assert assertThatThrownBy(action).isInstanceOf(EdcClientException.class); @@ -90,11 +90,11 @@ void shouldThrowExecutionExceptionForSubmodel() throws EdcClientException { void shouldThrowEdcClientExceptionForSubmodel() throws EdcClientException { // arrange final EdcClientException e = new EdcClientException("test"); - when(client.getSubmodelPayload(any(), any(), any())).thenThrow(e); + when(client.getSubmodelPayload(any(), any(), any(), any())).thenThrow(e); // act ThrowableAssert.ThrowingCallable action = () -> testee.getSubmodelPayload(CONNECTOR_ENDPOINT, - SUBMODEL_SUFIX, ASSET_ID); + SUBMODEL_SUFIX, ASSET_ID, "bpn"); // assert assertThatThrownBy(action).isInstanceOf(EdcClientException.class); @@ -107,10 +107,10 @@ void shouldRestoreInterruptOnInterruptExceptionForSubmodel() final CompletableFuture future = mock(CompletableFuture.class); final InterruptedException e = new InterruptedException(); when(future.get(config.getAsyncTimeoutMillis(), TimeUnit.MILLISECONDS)).thenThrow(e); - when(client.getSubmodelPayload(any(), any(), any())).thenReturn(future); + when(client.getSubmodelPayload(any(), any(), any(), any())).thenReturn(future); // act - testee.getSubmodelPayload(CONNECTOR_ENDPOINT, SUBMODEL_SUFIX, ASSET_ID); + testee.getSubmodelPayload(CONNECTOR_ENDPOINT, SUBMODEL_SUFIX, ASSET_ID, "bpn"); // assert assertThat(Thread.currentThread().isInterrupted()).isTrue(); @@ -129,10 +129,10 @@ void shouldRestoreInterruptOnInterruptExceptionForNotification() final CompletableFuture future = mock(CompletableFuture.class); final InterruptedException e = new InterruptedException(); when(future.get(config.getAsyncTimeoutMillis(), TimeUnit.MILLISECONDS)).thenThrow(e); - when(client.sendNotification(any(), any(), any())).thenReturn(future); + when(client.sendNotification(any(), any(), any(), any())).thenReturn(future); // act - testee.sendNotification("", "notify-request-asset", null); + testee.sendNotification("", "notify-request-asset", null, "bpn"); // assert assertThat(Thread.currentThread().isInterrupted()).isTrue(); @@ -143,10 +143,10 @@ void shouldThrowExecutionExceptionForNotification() throws EdcClientException { // arrange final ExecutionException e = new ExecutionException(new EdcClientException("test")); final CompletableFuture future = CompletableFuture.failedFuture(e); - when(client.sendNotification(any(), any(), any())).thenReturn(future); + when(client.sendNotification(any(), any(), any(), any())).thenReturn(future); // act - ThrowableAssert.ThrowingCallable action = () -> testee.sendNotification("", "notify-request-asset", null); + ThrowableAssert.ThrowingCallable action = () -> testee.sendNotification("", "notify-request-asset", null, "bpn"); // assert assertThatThrownBy(action).isInstanceOf(EdcClientException.class); @@ -156,10 +156,10 @@ void shouldThrowExecutionExceptionForNotification() throws EdcClientException { void shouldThrowEdcClientExceptionForNotification() throws EdcClientException { // arrange final EdcClientException e = new EdcClientException("test"); - when(client.sendNotification(any(), any(), any())).thenThrow(e); + when(client.sendNotification(any(), any(), any(), any())).thenThrow(e); // act - ThrowableAssert.ThrowingCallable action = () -> testee.sendNotification("", "notify-request-asset", null); + ThrowableAssert.ThrowingCallable action = () -> testee.sendNotification("", "notify-request-asset", null, "bpn"); // assert assertThatThrownBy(action).isInstanceOf(EdcClientException.class); @@ -174,10 +174,10 @@ class GetEndpointReferencesForAssetTests { void shouldThrowEdcClientExceptionForEndpointReference() throws EdcClientException { // arrange final EdcClientException e = new EdcClientException("test"); - when(client.getEndpointReferencesForAsset(any(), any(), any())).thenThrow(e); + when(client.getEndpointReferencesForAsset(any(), any(), any(), any())).thenThrow(e); // act - ThrowableAssert.ThrowingCallable action = () -> testee.getEndpointReferencesForAsset("", "", ""); + ThrowableAssert.ThrowingCallable action = () -> testee.getEndpointReferencesForAsset("", "", "", ""); // assert assertThatThrownBy(action).isInstanceOf(EdcClientException.class); @@ -187,12 +187,12 @@ void shouldThrowEdcClientExceptionForEndpointReference() throws EdcClientExcepti void shouldReturnFailedFuture() throws EdcClientException { // arrange - when(client.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(client.getEndpointReferencesForAsset(any(), any(), any(), any())).thenReturn( List.of(CompletableFuture.failedFuture(new EdcClientException("test")))); // act final List> results = testee.getEndpointReferencesForAsset("", "", - ""); + "", ""); // assert assertThat(results).hasSize(1); diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java index 23510866e6..a7fafce3b5 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelFacadeWiremockTest.java @@ -33,6 +33,7 @@ import static org.eclipse.tractusx.irs.testing.wiremock.SubmodelFacadeWiremockSupport.PATH_DATAPLANE_PUBLIC; import static org.eclipse.tractusx.irs.testing.wiremock.WireMockConfig.responseWithStatus; import static org.eclipse.tractusx.irs.testing.wiremock.WireMockConfig.restTemplateProxy; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -131,7 +132,7 @@ void configureSystemUnderTest(WireMockRuntimeInfo wireMockRuntimeInfo) { storage); acceptedPoliciesProvider = mock(AcceptedPoliciesProvider.class); - when(acceptedPoliciesProvider.getAcceptedPolicies()).thenReturn(List.of(new AcceptedPolicy(policy("IRS Policy", + when(acceptedPoliciesProvider.getAcceptedPolicies("BPN")).thenReturn(List.of(new AcceptedPolicy(policy("IRS Policy", List.of(new Permission(PolicyType.USE, new Constraints( List.of(new Constraint("Membership", new Operator(OperatorType.EQ), "active"), new Constraint("FrameworkAgreement.traceability", new Operator(OperatorType.EQ), @@ -154,9 +155,18 @@ void shouldReturnAssemblyPartRelationshipAsString() givenThat(get(urlPathEqualTo(SUBMODEL_DATAPLANE_PATH)).willReturn( responseWithStatus(200).withBodyFile("singleLevelBomAsBuilt.json"))); + final List andConstraints = List.of( + new Constraint("Membership", new Operator(OperatorType.EQ), "active"), new Constraint("FrameworkAgreement.traceability", new Operator(OperatorType.EQ), "active")); + final ArrayList orConstraints = new ArrayList<>(); + final Permission permission = new Permission(PolicyType.USE, + new Constraints(andConstraints, orConstraints)); + final AcceptedPolicy acceptedPolicy = new AcceptedPolicy(policy("IRS Policy", List.of(permission)), + OffsetDateTime.now().plusYears(1)); + when(acceptedPoliciesProvider.getAcceptedPolicies(eq("bpn"))).thenReturn(List.of(acceptedPolicy)); + // Act final String submodel = edcSubmodelClient.getSubmodelPayload(CONNECTOR_ENDPOINT_URL, SUBMODEL_DATAPLANE_URL, - ASSET_ID).get().getPayload(); + ASSET_ID, "bpn").get().getPayload(); // Assert assertThat(submodel).contains("\"catenaXId\": \"urn:uuid:fe99da3d-b0de-4e80-81da-882aebcca978\""); @@ -170,9 +180,18 @@ void shouldReturnMaterialForRecyclingAsString() givenThat(get(urlPathEqualTo(SUBMODEL_DATAPLANE_PATH)).willReturn( responseWithStatus(200).withBodyFile("materialForRecycling.json"))); + final List andConstraints = List.of( + new Constraint("Membership", new Operator(OperatorType.EQ), "active"), new Constraint("FrameworkAgreement.traceability", new Operator(OperatorType.EQ), "active")); + final ArrayList orConstraints = new ArrayList<>(); + final Permission permission = new Permission(PolicyType.USE, + new Constraints(andConstraints, orConstraints)); + final AcceptedPolicy acceptedPolicy = new AcceptedPolicy(policy("IRS Policy", List.of(permission)), + OffsetDateTime.now().plusYears(1)); + when(acceptedPoliciesProvider.getAcceptedPolicies(eq("bpn"))).thenReturn(List.of(acceptedPolicy)); + // Act final String submodel = edcSubmodelClient.getSubmodelPayload(CONNECTOR_ENDPOINT_URL, SUBMODEL_DATAPLANE_URL, - ASSET_ID).get().getPayload(); + ASSET_ID, "bpn").get().getPayload(); // Assert assertThat(submodel).contains("\"materialName\": \"Cooper\","); @@ -185,9 +204,18 @@ void shouldReturnObjectAsStringWhenResponseNotJSON() prepareNegotiation(); givenThat(get(urlPathEqualTo(SUBMODEL_DATAPLANE_PATH)).willReturn(responseWithStatus(200).withBody("test"))); + final List andConstraints = List.of( + new Constraint("Membership", new Operator(OperatorType.EQ), "active"), new Constraint("FrameworkAgreement.traceability", new Operator(OperatorType.EQ), "active")); + final ArrayList orConstraints = new ArrayList<>(); + final Permission permission = new Permission(PolicyType.USE, + new Constraints(andConstraints, orConstraints)); + final AcceptedPolicy acceptedPolicy = new AcceptedPolicy(policy("IRS Policy", List.of(permission)), + OffsetDateTime.now().plusYears(1)); + when(acceptedPoliciesProvider.getAcceptedPolicies(eq("bpn"))).thenReturn(List.of(acceptedPolicy)); + // Act final String submodel = edcSubmodelClient.getSubmodelPayload(CONNECTOR_ENDPOINT_URL, SUBMODEL_DATAPLANE_URL, - ASSET_ID).get().getPayload(); + ASSET_ID, "bpn").get().getPayload(); // Assert assertThat(submodel).isEqualTo("test"); @@ -203,7 +231,7 @@ void shouldThrowExceptionWhenPoliciesAreNotAccepted() { final AcceptedPolicy acceptedPolicy = new AcceptedPolicy(policy("IRS Policy", List.of(permission)), OffsetDateTime.now().plusYears(1)); - when(acceptedPoliciesProvider.getAcceptedPolicies()).thenReturn(List.of(acceptedPolicy)); + when(acceptedPoliciesProvider.getAcceptedPolicies("bpn")).thenReturn(List.of(acceptedPolicy)); prepareNegotiation(); givenThat(get(urlPathEqualTo(SUBMODEL_DATAPLANE_PATH)).willReturn(responseWithStatus(200).withBody("test"))); @@ -211,7 +239,7 @@ void shouldThrowExceptionWhenPoliciesAreNotAccepted() { // Act & Assert final String errorMessage = "Consumption of asset '58505404-4da1-427a-82aa-b79482bcd1f0' is not permitted as the required catalog offer policies do not comply with defined IRS policies."; assertThatExceptionOfType(UsagePolicyException.class).isThrownBy( - () -> edcSubmodelClient.getSubmodelPayload(CONNECTOR_ENDPOINT_URL, SUBMODEL_DATAPLANE_URL, ASSET_ID) + () -> edcSubmodelClient.getSubmodelPayload(CONNECTOR_ENDPOINT_URL, SUBMODEL_DATAPLANE_URL, ASSET_ID, "bpn") .get()).withMessageEndingWith(errorMessage); } @@ -222,9 +250,18 @@ void shouldThrowExceptionWhenResponse_400() { givenThat(get(urlPathEqualTo(SUBMODEL_DATAPLANE_PATH)).willReturn( responseWithStatus(400).withBody("{ error: '400'}"))); + final List andConstraints = List.of( + new Constraint("Membership", new Operator(OperatorType.EQ), "active"), new Constraint("FrameworkAgreement.traceability", new Operator(OperatorType.EQ), "active")); + final ArrayList orConstraints = new ArrayList<>(); + final Permission permission = new Permission(PolicyType.USE, + new Constraints(andConstraints, orConstraints)); + final AcceptedPolicy acceptedPolicy = new AcceptedPolicy(policy("IRS Policy", List.of(permission)), + OffsetDateTime.now().plusYears(1)); + when(acceptedPoliciesProvider.getAcceptedPolicies(eq("bpn"))).thenReturn(List.of(acceptedPolicy)); + // Act final ThrowableAssert.ThrowingCallable throwingCallable = () -> edcSubmodelClient.getSubmodelPayload( - CONNECTOR_ENDPOINT_URL, SUBMODEL_DATAPLANE_URL, ASSET_ID).get(5, TimeUnit.SECONDS); + CONNECTOR_ENDPOINT_URL, SUBMODEL_DATAPLANE_URL, ASSET_ID, "bpn").get(5, TimeUnit.SECONDS); // Assert assertThatExceptionOfType(ExecutionException.class).isThrownBy(throwingCallable) @@ -238,9 +275,18 @@ void shouldThrowExceptionWhenResponse_500() { givenThat(get(urlPathEqualTo(SUBMODEL_DATAPLANE_PATH)).willReturn( responseWithStatus(500).withBody("{ error: '500'}"))); + final List andConstraints = List.of( + new Constraint("Membership", new Operator(OperatorType.EQ), "active"), new Constraint("FrameworkAgreement.traceability", new Operator(OperatorType.EQ), "active")); + final ArrayList orConstraints = new ArrayList<>(); + final Permission permission = new Permission(PolicyType.USE, + new Constraints(andConstraints, orConstraints)); + final AcceptedPolicy acceptedPolicy = new AcceptedPolicy(policy("IRS Policy", List.of(permission)), + OffsetDateTime.now().plusYears(1)); + when(acceptedPoliciesProvider.getAcceptedPolicies(eq("bpn"))).thenReturn(List.of(acceptedPolicy)); + // Act final ThrowableAssert.ThrowingCallable throwingCallable = () -> edcSubmodelClient.getSubmodelPayload( - CONNECTOR_ENDPOINT_URL, SUBMODEL_DATAPLANE_URL, ASSET_ID).get(5, TimeUnit.SECONDS); + CONNECTOR_ENDPOINT_URL, SUBMODEL_DATAPLANE_URL, ASSET_ID, "bpn").get(5, TimeUnit.SECONDS); // Assert assertThatExceptionOfType(ExecutionException.class).isThrownBy(throwingCallable) diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java index 75e33e15c4..a3105d789b 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/SubmodelRetryerTest.java @@ -100,7 +100,7 @@ void shouldRetryExecutionOfGetSubmodelOnClientMaxAttemptTimes() { // Act assertThatThrownBy(() -> testee.getSubmodelPayload("https://connector.endpoint.com", "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", - "9300395e-c0a5-4e88-bc57-a3973fec4c26")).hasCauseInstanceOf(HttpServerErrorException.class); + "9300395e-c0a5-4e88-bc57-a3973fec4c26", "bpn")).hasCauseInstanceOf(HttpServerErrorException.class); // Assert verify(restTemplate, times(retryRegistry.getDefaultConfig().getMaxAttempts())).exchange(any(String.class), @@ -119,7 +119,7 @@ void shouldRetryOnAnyRuntimeException() { // Act assertThatThrownBy(() -> testee.getSubmodelPayload("https://connector.endpoint.com", "/shells/{aasIdentifier}/submodels/{submodelIdentifier}/submodel", - "9300395e-c0a5-4e88-bc57-a3973fec4c26")).hasCauseInstanceOf(RuntimeException.class); + "9300395e-c0a5-4e88-bc57-a3973fec4c26", "bpn")).hasCauseInstanceOf(RuntimeException.class); // Assert verify(restTemplate, times(retryRegistry.getDefaultConfig().getMaxAttempts())).exchange(any(String.class), diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/policy/AcceptedPoliciesProviderTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/policy/AcceptedPoliciesProviderTest.java index a0d042703f..e572a6a2da 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/policy/AcceptedPoliciesProviderTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/policy/AcceptedPoliciesProviderTest.java @@ -37,7 +37,7 @@ class AcceptedPoliciesProviderTest { @Test void getAcceptedPolicies() { - final var acceptedPolicies = testee.getAcceptedPolicies(); + final var acceptedPolicies = testee.getAcceptedPolicies("testBpn"); assertThat(acceptedPolicies).isEmpty(); } @@ -45,20 +45,20 @@ void getAcceptedPolicies() { @Test void shouldReturnStoredPolicies() { testee.addAcceptedPolicies(List.of(policy())); - final var acceptedPolicies = testee.getAcceptedPolicies(); + final var acceptedPolicies = testee.getAcceptedPolicies("testBpn"); assertThat(acceptedPolicies).hasSize(1); } @Test void shouldRemoveStoredPolicies() { testee.addAcceptedPolicies(List.of(policy())); - final var acceptedPolicies = testee.getAcceptedPolicies(); + final var acceptedPolicies = testee.getAcceptedPolicies("testBpn"); assertThat(acceptedPolicies).hasSize(1); testee.removeAcceptedPolicies(acceptedPolicies); - assertThat(testee.getAcceptedPolicies()).isEmpty(); + assertThat(testee.getAcceptedPolicies("testBpn")).isEmpty(); } @NotNull private static AcceptedPolicy policy() { diff --git a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/policy/PolicyCheckerServiceTest.java b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/policy/PolicyCheckerServiceTest.java index 1954360597..d3d5de037e 100644 --- a/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/policy/PolicyCheckerServiceTest.java +++ b/irs-edc-client/src/test/java/org/eclipse/tractusx/irs/edc/client/policy/PolicyCheckerServiceTest.java @@ -29,6 +29,7 @@ import static org.eclipse.tractusx.irs.edc.client.testutil.TestMother.createAtomicConstraintPolicy; import static org.eclipse.tractusx.irs.edc.client.testutil.TestMother.createOrConstraintPolicy; import static org.eclipse.tractusx.irs.edc.client.testutil.TestMother.createXOneConstraintPolicy; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.when; import java.time.OffsetDateTime; @@ -52,11 +53,6 @@ class PolicyCheckerServiceTest { @BeforeEach void setUp() { - final var policyList = List.of( - new AcceptedPolicy(policy(TestConstants.ID_3_0_TRACE), OffsetDateTime.now().plusYears(1)), - new AcceptedPolicy(policy(TestConstants.FRAMEWORK_AGREEMENT_TRACEABILITY), - OffsetDateTime.now().plusYears(1))); - when(policyStore.getAcceptedPolicies()).thenReturn(policyList); policyCheckerService = new PolicyCheckerService(policyStore, new ConstraintCheckerService()); } @@ -66,7 +62,7 @@ void shouldRejectWrongPolicy() { final String unknownRightExpression = "Wrong_Trace"; Policy policy = createAtomicConstraintPolicy(TestConstants.PURPOSE, unknownRightExpression); // when - boolean result = policyCheckerService.isValid(policy); + boolean result = policyCheckerService.isValid(policy, "bpn"); // then assertThat(result).isFalse(); @@ -76,9 +72,9 @@ void shouldRejectWrongPolicy() { void shouldRejectWhenPolicyStoreIsEmpty() { // given Policy policy = createAtomicConstraintPolicy(TestConstants.PURPOSE, TestConstants.ID_3_0_TRACE); - when(policyStore.getAcceptedPolicies()).thenReturn(List.of()); + when(policyStore.getAcceptedPolicies(any())).thenReturn(List.of()); // when - boolean result = policyCheckerService.isValid(policy); + boolean result = policyCheckerService.isValid(policy, "bpn"); // then assertThat(result).isFalse(); @@ -91,13 +87,13 @@ void shouldRejectAndConstraintsWhenOnlyOneMatch() { OffsetDateTime.now().plusYears(1)), new AcceptedPolicy(policy(TestConstants.FRAMEWORK_AGREEMENT_DISMANTLER), OffsetDateTime.now().plusYears(1))); - when(policyStore.getAcceptedPolicies()).thenReturn(policyList); + when(policyStore.getAcceptedPolicies(any())).thenReturn(policyList); Policy policy = createAndConstraintPolicy( List.of(createAtomicConstraint(TestConstants.FRAMEWORK_AGREEMENT_TRACEABILITY, TestConstants.STATUS_ACTIVE), createAtomicConstraint(TestConstants.MEMBERSHIP, TestConstants.STATUS_ACTIVE))); // when - boolean result = policyCheckerService.isValid(policy); + boolean result = policyCheckerService.isValid(policy, "bpn"); // then assertThat(result).isFalse(); @@ -116,13 +112,13 @@ void shouldAcceptAndConstraintsWhenAcceptedPolicyContainsMoreConstraintsSuperSet new AcceptedPolicy(policy("and-policy", List.of(constraint1, constraint2, constraint3), List.of()), OffsetDateTime.now().plusYears(1))); - when(policyStore.getAcceptedPolicies()).thenReturn(policyList); + when(policyStore.getAcceptedPolicies(any())).thenReturn(policyList); Policy policy = createAndConstraintPolicy( List.of(createAtomicConstraint(TestConstants.FRAMEWORK_AGREEMENT_TRACEABILITY, TestConstants.STATUS_ACTIVE), createAtomicConstraint(TestConstants.MEMBERSHIP, TestConstants.STATUS_ACTIVE))); // when - boolean result = policyCheckerService.isValid(policy); + boolean result = policyCheckerService.isValid(policy, "bpn"); // then assertThat(result).isTrue(); @@ -141,13 +137,13 @@ void shouldAcceptOrConstraintsWhenAcceptedPolicyContainsMoreConstraintsSuperSetO new AcceptedPolicy(policy("and-policy", List.of(), List.of(constraint1, constraint2, constraint3)), OffsetDateTime.now().plusYears(1))); - when(policyStore.getAcceptedPolicies()).thenReturn(policyList); + when(policyStore.getAcceptedPolicies(any())).thenReturn(policyList); Policy policy = createOrConstraintPolicy( List.of(createAtomicConstraint(TestConstants.FRAMEWORK_AGREEMENT_TRACEABILITY, TestConstants.STATUS_ACTIVE), createAtomicConstraint(TestConstants.MEMBERSHIP, TestConstants.STATUS_ACTIVE))); // when - boolean result = policyCheckerService.isValid(policy); + boolean result = policyCheckerService.isValid(policy, "bpn"); // then assertThat(result).isTrue(); @@ -166,14 +162,14 @@ void shouldAcceptConstraintsWithDefaultPolicy() { final var policyList = List.of(new AcceptedPolicy( policy("default-policy", List.of(constraint1, constraint2, constraint3), List.of(constraint1, constraint2, constraint3)), OffsetDateTime.now().plusYears(1))); - when(policyStore.getAcceptedPolicies()).thenReturn(policyList); + when(policyStore.getAcceptedPolicies(any())).thenReturn(policyList); Policy policy = createOrConstraintPolicy( List.of(createAtomicConstraint(TestConstants.FRAMEWORK_AGREEMENT_TRACEABILITY, TestConstants.STATUS_ACTIVE), createAtomicConstraint(TestConstants.MEMBERSHIP, TestConstants.STATUS_ACTIVE))); // when - boolean result = policyCheckerService.isValid(policy); + boolean result = policyCheckerService.isValid(policy, "bpn"); // then assertThat(result).isTrue(); @@ -186,13 +182,13 @@ void shouldRejectOrConstraintsWhenNoneMatch() { new AcceptedPolicy(policy(TestConstants.FRAMEWORK_AGREEMENT_TEST), OffsetDateTime.now().plusYears(1)), new AcceptedPolicy(policy(TestConstants.FRAMEWORK_AGREEMENT_DISMANTLER), OffsetDateTime.now().plusYears(1))); - when(policyStore.getAcceptedPolicies()).thenReturn(policyList); + when(policyStore.getAcceptedPolicies(any())).thenReturn(policyList); Policy policy = createAndConstraintPolicy( List.of(createAtomicConstraint(TestConstants.FRAMEWORK_AGREEMENT_TRACEABILITY, TestConstants.STATUS_ACTIVE), createAtomicConstraint(TestConstants.MEMBERSHIP, TestConstants.STATUS_ACTIVE))); // when - boolean result = policyCheckerService.isValid(policy); + boolean result = policyCheckerService.isValid(policy, "bpn"); // then assertThat(result).isFalse(); @@ -205,13 +201,13 @@ void shouldRejectXOneConstraintsWhenNoneMatch() { new AcceptedPolicy(policy(TestConstants.FRAMEWORK_AGREEMENT_TEST), OffsetDateTime.now().plusYears(1)), new AcceptedPolicy(policy(TestConstants.FRAMEWORK_AGREEMENT_DISMANTLER), OffsetDateTime.now().plusYears(1))); - when(policyStore.getAcceptedPolicies()).thenReturn(policyList); + when(policyStore.getAcceptedPolicies(any())).thenReturn(policyList); Policy policy = createXOneConstraintPolicy( List.of(createAtomicConstraint(TestConstants.FRAMEWORK_AGREEMENT_TRACEABILITY, TestConstants.STATUS_ACTIVE), createAtomicConstraint(TestConstants.MEMBERSHIP, TestConstants.STATUS_ACTIVE))); // when - boolean result = policyCheckerService.isValid(policy); + boolean result = policyCheckerService.isValid(policy, "bpn"); // then assertThat(result).isFalse(); @@ -223,13 +219,13 @@ void shouldRejectXOneConstraintsWhenMoreThanOneMatch() { final var policyList = List.of(new AcceptedPolicy(policy(TestConstants.FRAMEWORK_AGREEMENT_TRACEABILITY), OffsetDateTime.now().plusYears(1)), new AcceptedPolicy(policy(TestConstants.MEMBERSHIP), OffsetDateTime.now().plusYears(1))); - when(policyStore.getAcceptedPolicies()).thenReturn(policyList); + when(policyStore.getAcceptedPolicies(any())).thenReturn(policyList); Policy policy = createXOneConstraintPolicy( List.of(createAtomicConstraint(TestConstants.FRAMEWORK_AGREEMENT_TRACEABILITY, TestConstants.STATUS_ACTIVE), createAtomicConstraint(TestConstants.MEMBERSHIP, TestConstants.STATUS_ACTIVE))); // when - boolean result = policyCheckerService.isValid(policy); + boolean result = policyCheckerService.isValid(policy, "bpn"); // then assertThat(result).isFalse(); diff --git a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreController.java b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreController.java index 56aa0e1b72..1caf0a65aa 100644 --- a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreController.java +++ b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreController.java @@ -27,6 +27,11 @@ import static org.eclipse.tractusx.irs.common.ApiConstants.UNAUTHORIZED_DESC; import static org.springframework.http.MediaType.APPLICATION_JSON_VALUE; +import java.util.AbstractMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Content; @@ -36,7 +41,6 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.security.SecurityRequirement; import jakarta.validation.Valid; -import java.util.List; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.irs.common.auth.IrsRoles; @@ -56,6 +60,7 @@ import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; @@ -67,17 +72,18 @@ @RequestMapping("irs") @RequiredArgsConstructor @SuppressWarnings({ "PMD.AvoidDuplicateLiterals", - "PMD.ExcessiveImports" + "PMD.ExcessiveImports", + "PMD.UseVarargs" }) public class PolicyStoreController { private final PolicyStoreService service; private final EdcTransformer edcTransformer; + private static final String DEFAULT = "default"; @Operation(operationId = "registerAllowedPolicy", summary = "Register a policy that should be accepted in EDC negotiation.", - security = @SecurityRequirement(name = "api_key"), - tags = { "Item Relationship Service" }, + security = @SecurityRequirement(name = "api_key"), tags = { "Item Relationship Service" }, description = "Register a policy that should be accepted in EDC negotiation.") @ApiResponses(value = { @ApiResponse(responseCode = "201"), @ApiResponse(responseCode = "400", description = "Policy registration failed.", @@ -99,19 +105,25 @@ public class PolicyStoreController { ref = "#/components/examples/error-response-403")) }), }) + @PostMapping("/policies") @ResponseStatus(HttpStatus.CREATED) @PreAuthorize("hasAuthority('" + IrsRoles.ADMIN_IRS + "')") public void registerAllowedPolicy(final @RequestBody CreatePolicyRequest request) { - final Policy policy = edcTransformer.transformToPolicy(request.payload()); - policy.setValidUntil(request.validUntil()); - service.registerPolicy(policy); + request.payload() + .stream() + .map(payload -> { + final Policy policy = edcTransformer.transformToPolicy(payload); + policy.setValidUntil(request.validUntil()); + return policy; + }) + .forEach(policy -> service.registerPolicy(policy, + request.businessPartnerNumbers() == null ? List.of(DEFAULT) : request.businessPartnerNumbers())); } - @Operation(operationId = "getAllowedPolicies", + @Operation(operationId = "getAllowedPoliciesByBpn", summary = "Lists the registered policies that should be accepted in EDC negotiation.", - security = @SecurityRequirement(name = "api_key"), - tags = { "Item Relationship Service" }, + security = @SecurityRequirement(name = "api_key"), tags = { "Item Relationship Service" }, description = "Lists the registered policies that should be accepted in EDC negotiation.") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "Returns the policies.", content = { @Content(mediaType = APPLICATION_JSON_VALUE, array = @ArraySchema( @@ -133,16 +145,18 @@ public void registerAllowedPolicy(final @RequestBody CreatePolicyRequest request @GetMapping("/policies") @ResponseStatus(HttpStatus.OK) @PreAuthorize("hasAuthority('" + IrsRoles.ADMIN_IRS + "')") - public List getPolicies() { - return service.getStoredPolicies().stream() - .map(PolicyResponse::fromPolicy) - .toList(); + public Map> getPolicies(@RequestParam(required = false) final List bpnls) { + return service.getPolicies(bpnls) + .entrySet() + .stream() + .map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(), + entry.getValue().stream().map(PolicyResponse::fromPolicy).toList())) + .collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); } @Operation(operationId = "deleteAllowedPolicy", summary = "Removes a policy that should no longer be accepted in EDC negotiation.", - security = @SecurityRequirement(name = "api_key"), - tags = { "Item Relationship Service" }, + security = @SecurityRequirement(name = "api_key"), tags = { "Item Relationship Service" }, description = "Removes a policy that should no longer be accepted in EDC negotiation.") @ApiResponses(value = { @ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "400", description = "Policy deletion failed.", @@ -171,10 +185,9 @@ public void deleteAllowedPolicy(@PathVariable("policyId") final String policyId) service.deletePolicy(policyId); } - @Operation(operationId = "updateAllowedPolicy", summary = "Updates an existing policy with new validUntil value.", - security = @SecurityRequirement(name = "api_key"), - tags = { "Item Relationship Service" }, - description = "Updates an existing policy with new validUntil value.") + @Operation(operationId = "updateAllowedPolicy", summary = "Updates an existing policy.", + security = @SecurityRequirement(name = "api_key"), tags = { "Item Relationship Service" }, + description = "Updates an existing policy.") @ApiResponses(value = { @ApiResponse(responseCode = "200"), @ApiResponse(responseCode = "400", description = "Policy update failed.", content = { @Content(mediaType = APPLICATION_JSON_VALUE, @@ -195,11 +208,11 @@ public void deleteAllowedPolicy(@PathVariable("policyId") final String policyId) ref = "#/components/examples/error-response-403")) }), }) - @PutMapping("/policies/{policyId}") + @PutMapping("/policies") @ResponseStatus(HttpStatus.OK) @PreAuthorize("hasAuthority('" + IrsRoles.ADMIN_IRS + "')") - public void updateAllowedPolicy(@PathVariable("policyId") final String policyId, - final @Valid @RequestBody UpdatePolicyRequest request) { - service.updatePolicy(policyId, request); + public void updateAllowedPolicy(final @Valid @RequestBody UpdatePolicyRequest request) { + service.updatePolicies(request); } + } diff --git a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/models/CreatePolicyRequest.java b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/models/CreatePolicyRequest.java index 06fbee3f36..3154a363ee 100644 --- a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/models/CreatePolicyRequest.java +++ b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/models/CreatePolicyRequest.java @@ -24,7 +24,9 @@ package org.eclipse.tractusx.irs.policystore.models; import java.time.OffsetDateTime; +import java.util.List; +import io.swagger.v3.oas.annotations.media.ArraySchema; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.json.JsonObject; import jakarta.validation.constraints.NotNull; @@ -36,7 +38,8 @@ @Schema(description = "Request to add a policy") public record CreatePolicyRequest( @NotNull @Schema(description = "Timestamp after which the policy will no longer be accepted in negotiations") OffsetDateTime validUntil, - @NotNull @Schema(example = CreatePolicyRequest.EXAMPLE_PAYLOAD) JsonObject payload) { + @ArraySchema() List businessPartnerNumbers, + @NotNull @Schema(example = CreatePolicyRequest.EXAMPLE_PAYLOAD) List payload) { @SuppressWarnings("java:S2479") // this value is used by open-api to show example payload diff --git a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/models/UpdatePolicyRequest.java b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/models/UpdatePolicyRequest.java index 4b4c455bd3..ead5a738bc 100644 --- a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/models/UpdatePolicyRequest.java +++ b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/models/UpdatePolicyRequest.java @@ -24,6 +24,7 @@ package org.eclipse.tractusx.irs.policystore.models; import java.time.OffsetDateTime; +import java.util.List; import io.swagger.v3.oas.annotations.media.Schema; import jakarta.validation.constraints.NotNull; @@ -33,5 +34,7 @@ */ @Schema(description = "Request to add a policy") public record UpdatePolicyRequest( - @Schema(description = "Timestamp after which the policy will no longer be accepted in negotiations") @NotNull OffsetDateTime validUntil) { + @Schema(description = "Timestamp after which the policy will no longer be accepted in negotiations") @NotNull OffsetDateTime validUntil, + List businessPartnerNumbers, + List policiesIds) { } diff --git a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/persistence/PolicyPersistence.java b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/persistence/PolicyPersistence.java index b2991563c5..84a92b6316 100644 --- a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/persistence/PolicyPersistence.java +++ b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/persistence/PolicyPersistence.java @@ -26,11 +26,13 @@ import static org.eclipse.tractusx.irs.policystore.config.PolicyConfiguration.POLICY_BLOB_PERSISTENCE; import java.io.IOException; -import java.time.OffsetDateTime; +import java.util.AbstractMap; import java.util.ArrayList; import java.util.List; +import java.util.Map; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.stream.Collectors; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -60,19 +62,29 @@ public class PolicyPersistence { */ private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); + private static final String COULD_NOT_READ_POLICY_ERROR_MESSAGE = "Could not read the policies from the store"; + public PolicyPersistence(@Qualifier(POLICY_BLOB_PERSISTENCE) final BlobPersistence policyStorePersistence, final ObjectMapper mapper) { this.policyStorePersistence = policyStorePersistence; this.mapper = mapper; } - public void save(final String bpn, final Policy policy) { - final var policies = readAll(bpn); + public void save(final List bpns, final Policy policy) { + final Map> storedBpnToPolicies = bpns.stream() + .collect(Collectors.toMap(bpn -> bpn, + this::readAll)); + storedBpnToPolicies.forEach((bpn, policies) -> { + checkIfPolicyAlreadyExists(policy, policies); + policies.add(policy); + save(bpn, policies); + }); + } + + private static void checkIfPolicyAlreadyExists(final Policy policy, final List policies) { if (policies.stream().map(Policy::getPolicyId).anyMatch(policy.getPolicyId()::equals)) { throw new PolicyStoreException("Policy with id '" + policy.getPolicyId() + "' already exists!"); } - policies.add(policy); - save(bpn, policies); } public void delete(final String bpn, final String policyId) { @@ -84,18 +96,6 @@ public void delete(final String bpn, final String policyId) { save(bpn, modifiedPolicies); } - public void update(final String bpn, final String policyId, final OffsetDateTime validUntil) { - final var policies = readAll(bpn); - final Policy policy = policies.stream() - .filter(p -> p.getPolicyId().equals(policyId)) - .findFirst() - .orElseThrow(() -> new PolicyStoreException( - "Policy with id '" + policyId + "' doesn't exists!")); - - policy.update(validUntil); - save(bpn, policies); - } - private void save(final String bpn, final List modifiedPolicies) { writeLock(() -> { try { @@ -113,7 +113,7 @@ public List readAll(final String bpn) { try { return mapper.readerForListOf(Policy.class).>readValue(blob); } catch (IOException | RuntimeException e) { - throw new PolicyStoreException("Could not read the policies from the store", e); + throw new PolicyStoreException(COULD_NOT_READ_POLICY_ERROR_MESSAGE, e); } }).map(ArrayList::new).orElseGet(ArrayList::new); @@ -123,6 +123,27 @@ public List readAll(final String bpn) { } + /** + * Returns all policies. + * + * @return policies as map of BPN to list of policies + */ + public Map> readAll() { + try { + return policyStorePersistence.getAllBlobs().entrySet().stream().map(entry -> { + try { + final String bpn = entry.getKey(); + return new AbstractMap.SimpleEntry<>(bpn, + mapper.readerForListOf(Policy.class).>readValue(entry.getValue())); + } catch (IOException e) { + throw new PolicyStoreException(COULD_NOT_READ_POLICY_ERROR_MESSAGE, e); + } + }).collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); + } catch (BlobPersistenceException e) { + throw new PolicyStoreException(COULD_NOT_READ_POLICY_ERROR_MESSAGE, e); + } + } + private void writeLock(final Runnable work) { try { if (!lock.writeLock().tryLock(TIMEOUT, TimeUnit.MILLISECONDS)) { diff --git a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/services/PolicyHelper.java b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/services/PolicyHelper.java new file mode 100644 index 0000000000..98fa17fecf --- /dev/null +++ b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/services/PolicyHelper.java @@ -0,0 +1,48 @@ +/******************************************************************************** + * Copyright (c) 2022,2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.irs.policystore.services; + +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; + +import org.eclipse.tractusx.irs.edc.client.policy.Policy; + +/** + * Helper methods for policies. + */ +public final class PolicyHelper { + + private PolicyHelper() { + } + + public static List findBpnsByPolicyId(final Map> policyMap, final String policyId) { + return policyMap.entrySet().stream().filter(mapEntriesByPolicyId(policyId)).map(Map.Entry::getKey).toList(); + } + + private static Predicate>> mapEntriesByPolicyId(final String policyId) { + return entry -> entry.getValue().stream().anyMatch(havingPolicyId(policyId)); + } + + public static Predicate havingPolicyId(final String policyId) { + return policy -> policy.getPolicyId().equals(policyId); + } + +} diff --git a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/services/PolicyStoreService.java b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/services/PolicyStoreService.java index 3f16e4a90b..725bfd4d97 100644 --- a/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/services/PolicyStoreService.java +++ b/irs-policy-store/src/main/java/org/eclipse/tractusx/irs/policystore/services/PolicyStoreService.java @@ -23,10 +23,19 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.policystore.services; +import static org.eclipse.tractusx.irs.common.persistence.BlobPersistence.DEFAULT_BLOB_NAME; + import java.time.Clock; import java.time.OffsetDateTime; +import java.util.AbstractMap; import java.util.ArrayList; +import java.util.Collection; +import java.util.Comparator; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.irs.edc.client.policy.AcceptedPoliciesProvider; @@ -42,7 +51,6 @@ import org.eclipse.tractusx.irs.policystore.exceptions.PolicyStoreException; import org.eclipse.tractusx.irs.policystore.models.UpdatePolicyRequest; import org.eclipse.tractusx.irs.policystore.persistence.PolicyPersistence; -import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpStatus; import org.springframework.stereotype.Service; import org.springframework.web.server.ResponseStatusException; @@ -55,26 +63,25 @@ public class PolicyStoreService implements AcceptedPoliciesProvider { public static final int DEFAULT_POLICY_LIFETIME_YEARS = 5; - private final String apiAllowedBpn; private final List allowedPoliciesFromConfig; private final PolicyPersistence persistence; private final Clock clock; private static final String MISSING_REQUEST_FIELD_MESSAGE = "Request does not contain all required fields. Missing: %s"; + private static final String DEFAULT = "default"; - public PolicyStoreService(@Value("${apiAllowedBpn:}") final String apiAllowedBpn, - final DefaultAcceptedPoliciesConfig defaultAcceptedPoliciesConfig, final PolicyPersistence persistence, final Clock clock) { - this.apiAllowedBpn = apiAllowedBpn; + public PolicyStoreService(final DefaultAcceptedPoliciesConfig defaultAcceptedPoliciesConfig, + final PolicyPersistence persistence, final Clock clock) { this.allowedPoliciesFromConfig = createDefaultPolicyFromConfig(defaultAcceptedPoliciesConfig); this.persistence = persistence; this.clock = clock; } - public void registerPolicy(final Policy policy) { + public void registerPolicy(final Policy policy, final List businessPartnersNumbers) { validatePolicy(policy); policy.setCreatedOn(OffsetDateTime.now(clock)); log.info("Registering new policy with id {}, valid until {}", policy.getPolicyId(), policy.getValidUntil()); try { - persistence.save(apiAllowedBpn, policy); + persistence.save(businessPartnersNumbers, policy); } catch (final PolicyStoreException e) { throw new ResponseStatusException(HttpStatus.BAD_REQUEST, e.getMessage(), e); } @@ -82,20 +89,35 @@ public void registerPolicy(final Policy policy) { /** * Checks whether policy from register policy request has all required fields + * * @param policy policy to register */ private void validatePolicy(final Policy policy) { + if (policy.getPermissions() == null) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, String.format(MISSING_REQUEST_FIELD_MESSAGE, "odrl:permission")); + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + String.format(MISSING_REQUEST_FIELD_MESSAGE, "odrl:permission")); } + if (policy.getPermissions().stream().anyMatch(p -> p.getConstraint() == null)) { - throw new ResponseStatusException(HttpStatus.BAD_REQUEST, String.format(MISSING_REQUEST_FIELD_MESSAGE, "odrl:constraint")); + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, + String.format(MISSING_REQUEST_FIELD_MESSAGE, "odrl:constraint")); + } + } + + public Map> getPolicies(final List bpns) { + if (bpns == null) { + return getAllStoredPolicies(); + } else { + return bpns.stream().map(bpn -> new AbstractMap.SimpleEntry<>(bpn, getStoredPolicies(List.of(bpn)))).collect(Collectors.toMap(AbstractMap.SimpleEntry::getKey, AbstractMap.SimpleEntry::getValue)); } } - public List getStoredPolicies() { - log.info("Reading all stored polices for BPN {}", apiAllowedBpn); - final var storedPolicies = persistence.readAll(apiAllowedBpn); + public List getStoredPolicies(final List bpns) { + log.info("Reading all stored polices for BPN {}", bpns); + final List storedPolicies = new LinkedList<>(); + bpns.forEach(bpn -> storedPolicies.addAll(persistence.readAll(bpn))); + if (storedPolicies.isEmpty()) { log.info("Policy store is empty, returning default values from config"); return allowedPoliciesFromConfig; @@ -104,28 +126,76 @@ public List getStoredPolicies() { } } + public Map> getAllStoredPolicies() { + final Map> bpnToPolicies = persistence.readAll(); + if (bpnToPolicies.isEmpty()) { + return Map.of("", allowedPoliciesFromConfig); + } + return bpnToPolicies; + } + public void deletePolicy(final String policyId) { try { + log.info("Getting all policies to find correct bpn number"); + final List bpnsContainingPolicyId = PolicyHelper.findBpnsByPolicyId(getAllStoredPolicies(), + policyId); + log.info("Deleting policy with id {}", policyId); - persistence.delete(apiAllowedBpn, policyId); + bpnsContainingPolicyId.forEach(bpn -> persistence.delete(bpn, policyId)); } catch (final PolicyStoreException e) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage(), e); } } - public void updatePolicy(final String policyId, final UpdatePolicyRequest request) { + public void updatePolicies(final UpdatePolicyRequest request) { + for (final String policyId : request.policiesIds()) { + updatePolicy(policyId, request.validUntil(), request.businessPartnerNumbers() == null ? List.of(DEFAULT) : request.businessPartnerNumbers()); + } + } + + public void updatePolicy(final String policyId, final OffsetDateTime validUntil, final List bpns) { try { log.info("Updating policy with id {}", policyId); - persistence.update(apiAllowedBpn, policyId, request.validUntil()); + final List bpnsContainingPolicyId = PolicyHelper.findBpnsByPolicyId(getAllStoredPolicies(), + policyId); + + final Policy policyToUpdate = getStoredPolicies(bpnsContainingPolicyId).stream() + .filter(PolicyHelper.havingPolicyId( + policyId)) + .findAny() + .orElseThrow( + () -> new PolicyStoreException( + "Policy with id '" + + policyId + + "' doesn't exists!")); + + policyToUpdate.update(validUntil); + bpnsContainingPolicyId.forEach(bpn -> persistence.delete(bpn, policyId)); + persistence.save(bpns, policyToUpdate); } catch (final PolicyStoreException e) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, e.getMessage(), e); } } @Override - public List getAcceptedPolicies() { - return getStoredPolicies().stream().map(this::toAcceptedPolicy).toList(); + public List getAcceptedPolicies(final String bpn) { + if (bpn == null) { + return getAllStoredPolicies().values() + .stream() + .flatMap(Collection::stream) + .map(this::toAcceptedPolicy) + .toList(); + } + + final ArrayList policies = new ArrayList<>(); + policies.addAll(getStoredPolicies(List.of(bpn))); + policies.addAll(getStoredPolicies(List.of(DEFAULT_BLOB_NAME))); + + final TreeSet result = new TreeSet<>(Comparator.comparing(Policy::getPolicyId)); + result.addAll(policies); + + return result.stream().map(this::toAcceptedPolicy).toList(); } private AcceptedPolicy toAcceptedPolicy(final Policy policy) { diff --git a/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreControllerTest.java b/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreControllerTest.java index f685cd33ab..b504e5bdab 100644 --- a/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreControllerTest.java +++ b/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/controllers/PolicyStoreControllerTest.java @@ -25,6 +25,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -32,6 +33,7 @@ import java.time.OffsetDateTime; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.stream.Collectors; import jakarta.json.Json; @@ -121,10 +123,10 @@ void registerAllowedPolicy() { // act testee.registerAllowedPolicy( - new CreatePolicyRequest(now.plusMinutes(1), jsonObject.get("payload").asJsonObject())); + new CreatePolicyRequest(now.plusMinutes(1), null, List.of(jsonObject.get("payload").asJsonObject()))); // assert - verify(service).registerPolicy(any()); + verify(service).registerPolicy(any(), eq(List.of("default"))); } @Test @@ -132,13 +134,30 @@ void getPolicies() { // arrange final List policies = List.of( new Policy("testId", OffsetDateTime.now(), OffsetDateTime.now(), createPermissions())); - when(service.getStoredPolicies()).thenReturn(policies); + final String bpn = "bpn1"; + when(service.getPolicies(List.of(bpn))).thenReturn(Map.of(bpn, policies)); // act - final List returnedPolicies = testee.getPolicies(); + final Map> returnedPolicies = testee.getPolicies(List.of(bpn)); // assert - assertThat(returnedPolicies).isEqualTo( + assertThat(returnedPolicies.get(bpn)).isEqualTo( + policies.stream().map(PolicyResponse::fromPolicy).collect(Collectors.toList())); + } + + @Test + void getAllPolicies() { + // arrange + final List policies = List.of( + new Policy("testId", OffsetDateTime.now(), OffsetDateTime.now(), createPermissions())); + final String bpn = "bpn1"; + when(service.getPolicies(null)).thenReturn(Map.of(bpn, policies)); + + // act + final Map> returnedPolicies = testee.getPolicies(null); + + // assert + assertThat(returnedPolicies).containsEntry(bpn, policies.stream().map(PolicyResponse::fromPolicy).collect(Collectors.toList())); } @@ -154,14 +173,14 @@ void deleteAllowedPolicy() { @Test void updateAllowedPolicy() { // arrange - final UpdatePolicyRequest request = new UpdatePolicyRequest(OffsetDateTime.now()); + final String policyId = "policyId"; + final UpdatePolicyRequest request = new UpdatePolicyRequest(OffsetDateTime.now(), List.of("bpn"),List.of(policyId)); // act - final String policyId = "policyId"; - testee.updateAllowedPolicy(policyId, request); + testee.updateAllowedPolicy(request); // assert - verify(service).updatePolicy(policyId, request); + verify(service).updatePolicies(request); } private List createPermissions() { diff --git a/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/persistence/PolicyPersistenceTest.java b/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/persistence/PolicyPersistenceTest.java index 7fe7aedbc1..60a48e3c00 100644 --- a/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/persistence/PolicyPersistenceTest.java +++ b/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/persistence/PolicyPersistenceTest.java @@ -36,6 +36,7 @@ import java.time.OffsetDateTime; import java.util.List; +import java.util.Map; import java.util.Optional; import com.fasterxml.jackson.core.JsonProcessingException; @@ -73,7 +74,19 @@ void save() throws BlobPersistenceException { final var policy = new Policy("test", OffsetDateTime.now(), OffsetDateTime.now(), emptyList()); // act - testee.save("testBpn", policy); + testee.save(List.of("testBpn"), policy); + + // assert + verify(mockPersistence).putBlob(anyString(), any()); + } + + @Test + void saveWithoutBpn() throws BlobPersistenceException { + // arrange + final var policy = new Policy("test", OffsetDateTime.now(), OffsetDateTime.now(), emptyList()); + + // act + testee.save(List.of("default"), policy); // assert verify(mockPersistence).putBlob(anyString(), any()); @@ -87,7 +100,8 @@ void saveDuplicate() throws BlobPersistenceException, JsonProcessingException { when(mockPersistence.getBlob(anyString())).thenReturn(Optional.of(mapper.writeValueAsBytes(policies))); // act & assert - assertThatThrownBy(() -> testee.save("testBpn", policy)).isInstanceOf(PolicyStoreException.class); + final List bpn = List.of("testBpn"); + assertThatThrownBy(() -> testee.save(bpn, policy)).isInstanceOf(PolicyStoreException.class); } @Test @@ -98,7 +112,8 @@ void saveWithError() throws BlobPersistenceException { new BlobPersistenceException("test", new IllegalStateException())); // act & assert - assertThatThrownBy(() -> testee.save("testBpn", policy)).isInstanceOf(PolicyStoreException.class); + final List bpn = List.of("testBpn"); + assertThatThrownBy(() -> testee.save(bpn, policy)).isInstanceOf(PolicyStoreException.class); } @Test @@ -109,7 +124,8 @@ void saveWithWriteError() throws BlobPersistenceException { .putBlob(any(), any()); // act & assert - assertThatThrownBy(() -> testee.save("testBpn", policy)).isInstanceOf(PolicyStoreException.class); + final List bpn = List.of("testBpn"); + assertThatThrownBy(() -> testee.save(bpn, policy)).isInstanceOf(PolicyStoreException.class); } @Test @@ -127,21 +143,6 @@ void delete() throws BlobPersistenceException, JsonProcessingException { verify(mockPersistence).putBlob(anyString(), any()); } - @Test - void update() throws BlobPersistenceException, JsonProcessingException { - // arrange - final String policyId = "test"; - final var policy = new Policy(policyId, OffsetDateTime.now(), OffsetDateTime.now(), emptyList()); - final var policies = List.of(policy); - when(mockPersistence.getBlob(anyString())).thenReturn(Optional.of(mapper.writeValueAsBytes(policies))); - - // act - testee.update("testBpn", policyId, OffsetDateTime.now()); - - // assert - verify(mockPersistence).putBlob(anyString(), any()); - } - @Test void deleteShouldThrowExceptionIfPolicyWithIdDoesntExists() throws BlobPersistenceException, JsonProcessingException { // arrange @@ -153,25 +154,28 @@ void deleteShouldThrowExceptionIfPolicyWithIdDoesntExists() throws BlobPersisten } @Test - void updateShouldThrowExceptionIfPolicyWithIdDoesntExists() throws BlobPersistenceException, JsonProcessingException { + void readAll() throws BlobPersistenceException, JsonProcessingException { // arrange - final OffsetDateTime now = OffsetDateTime.now(); - final var policy = new Policy("policyId", now, now, emptyList()); - when(mockPersistence.getBlob(anyString())).thenReturn(Optional.of(mapper.writeValueAsBytes(List.of(policy)))); + final var policy = new Policy("test", OffsetDateTime.now(), OffsetDateTime.now(), emptyList()); + final var policies = List.of(policy); + when(mockPersistence.getBlob(anyString())).thenReturn(Optional.of(mapper.writeValueAsBytes(policies))); // act - assertThrows(PolicyStoreException.class, () -> testee.update("testBpn", "notExistingPolicyId", now)); + final var readPolicies = testee.readAll("testBpn"); + + // assert + assertThat(readPolicies).hasSize(1); } @Test - void readAll() throws BlobPersistenceException, JsonProcessingException { + void whenReadAllShouldReturnCorrect() throws BlobPersistenceException, JsonProcessingException { // arrange final var policy = new Policy("test", OffsetDateTime.now(), OffsetDateTime.now(), emptyList()); final var policies = List.of(policy); - when(mockPersistence.getBlob(anyString())).thenReturn(Optional.of(mapper.writeValueAsBytes(policies))); + when(mockPersistence.getAllBlobs()).thenReturn(Map.of("bpn1", mapper.writeValueAsBytes(policies))); // act - final var readPolicies = testee.readAll("testBpn"); + final var readPolicies = testee.readAll(); // assert assertThat(readPolicies).hasSize(1); diff --git a/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/services/PolicyHelperTest.java b/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/services/PolicyHelperTest.java new file mode 100644 index 0000000000..1362d7a7bb --- /dev/null +++ b/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/services/PolicyHelperTest.java @@ -0,0 +1,53 @@ +/******************************************************************************** + * Copyright (c) 2022,2024 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) + * Copyright (c) 2021,2024 Contributors to the Eclipse Foundation + * + * See the NOTICE file(s) distributed with this work for additional + * information regarding copyright ownership. + * + * This program and the accompanying materials are made available under the + * terms of the Apache License, Version 2.0 which is available at + * https://www.apache.org/licenses/LICENSE-2.0. + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations + * under the License. + * + * SPDX-License-Identifier: Apache-2.0 + ********************************************************************************/ +package org.eclipse.tractusx.irs.policystore.services; + +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +import java.util.HashMap; +import java.util.List; + +import org.eclipse.tractusx.irs.edc.client.policy.Policy; +import org.junit.jupiter.api.Test; + +class PolicyHelperTest { + + @Test + void shouldFilterMapByPolicyId() { + + // ARRANGE + final HashMap> policyMap = new HashMap<>(); + final String policyIdToFind = "policyIdToFind"; + policyMap.put("BPN1", List.of(Policy.builder().policyId(policyIdToFind).build(), + Policy.builder().policyId("policy1").build())); + policyMap.put("BPN2", List.of(Policy.builder().policyId("policy2").build(), + Policy.builder().policyId(policyIdToFind).build())); + policyMap.put("BPN3", + List.of(Policy.builder().policyId("policy3").build(), Policy.builder().policyId("policy4").build())); + policyMap.put("BPN4", List.of(Policy.builder().policyId(policyIdToFind).build())); + + // ACT + final List result = PolicyHelper.findBpnsByPolicyId(policyMap, policyIdToFind); + + // ASSERT + assertThat(result).containsExactlyInAnyOrder("BPN1", "BPN2", "BPN4"); + } + +} diff --git a/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/services/PolicyStoreServiceTest.java b/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/services/PolicyStoreServiceTest.java index e218ca2b94..93a0f38afe 100644 --- a/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/services/PolicyStoreServiceTest.java +++ b/irs-policy-store/src/test/java/org/eclipse/tractusx/irs/policystore/services/PolicyStoreServiceTest.java @@ -24,11 +24,13 @@ package org.eclipse.tractusx.irs.policystore.services; import static java.util.Collections.emptyList; +import static java.util.Collections.emptyMap; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -36,6 +38,7 @@ import java.time.OffsetDateTime; import java.util.Collections; import java.util.List; +import java.util.Map; import org.eclipse.tractusx.irs.edc.client.policy.Constraint; import org.eclipse.tractusx.irs.edc.client.policy.Constraints; @@ -74,7 +77,7 @@ class PolicyStoreServiceTest { void setUp() { final DefaultAcceptedPoliciesConfig defaultAcceptedPoliciesConfig = new DefaultAcceptedPoliciesConfig(); defaultAcceptedPoliciesConfig.setAcceptedPolicies(List.of()); - testee = new PolicyStoreService(BPN, defaultAcceptedPoliciesConfig, persistence, clock); + testee = new PolicyStoreService(defaultAcceptedPoliciesConfig, persistence, clock); } @Test @@ -84,10 +87,10 @@ void registerPolicy() { final Policy policy = new Policy("testId", now, now.plusMinutes(1), emptyList()); // act - testee.registerPolicy(policy); + testee.registerPolicy(policy, List.of(BPN)); // assert - verify(persistence).save(eq(BPN), any()); + verify(persistence).save(eq(List.of(BPN)), any()); } @Test @@ -97,10 +100,10 @@ void registerPolicyWithPermission() { final Policy policy = new Policy("testId", now, now.plusMinutes(1), createPermissions()); // act - testee.registerPolicy(policy); + testee.registerPolicy(policy, List.of(BPN)); // assert - verify(persistence).save(eq(BPN), policyCaptor.capture()); + verify(persistence).save(eq(List.of(BPN)), policyCaptor.capture()); assertThat(policyCaptor.getValue()).isNotNull(); List permissionList = policyCaptor.getValue().getPermissions(); @@ -115,10 +118,11 @@ void registerPolicyShouldThrowResponseStatusException() { final String policyId = "testId"; final OffsetDateTime now = OffsetDateTime.now(clock); final Policy policy = new Policy(policyId, now, now.plusMinutes(1), createPermissions()); - doThrow(new PolicyStoreException("")).when(persistence).save(eq(BPN), any()); + doThrow(new PolicyStoreException("")).when(persistence).save(any(), any()); // assert - assertThrows(ResponseStatusException.class, () -> testee.registerPolicy(policy)); + final List bpns = List.of(BPN); + assertThrows(ResponseStatusException.class, () -> testee.registerPolicy(policy, bpns)); } @Test @@ -128,7 +132,7 @@ void getStoredPolicies() { when(persistence.readAll(BPN)).thenReturn(policies); // act - final var storedPolicies = testee.getStoredPolicies(); + final var storedPolicies = testee.getStoredPolicies(List.of(BPN)); // assert assertThat(storedPolicies).hasSize(3); @@ -143,10 +147,10 @@ void getDefaultStoredPoliciesWhenEmpty() { EXAMPLE_ACCEPTED_LEFT_OPERAND, "eq", EXAMPLE_ALLOWED_NAME); final DefaultAcceptedPoliciesConfig defaultAcceptedPoliciesConfig = new DefaultAcceptedPoliciesConfig(); defaultAcceptedPoliciesConfig.setAcceptedPolicies(List.of(acceptedPolicy1, acceptedPolicy2)); - testee = new PolicyStoreService(BPN, defaultAcceptedPoliciesConfig, persistence, clock); + testee = new PolicyStoreService(defaultAcceptedPoliciesConfig, persistence, clock); // act - final var defaultPolicies = testee.getStoredPolicies(); + final var defaultPolicies = testee.getStoredPolicies(List.of(BPN)); // assert assertThat(defaultPolicies).hasSize(1); @@ -175,6 +179,9 @@ private Constraints createConstraints() { @Test void deletePolicy() { + // arrange + when(persistence.readAll()).thenReturn(Map.of(BPN, List.of(new Policy("testId", null, null, null)))); + // act testee.deletePolicy("testId"); @@ -186,6 +193,7 @@ void deletePolicy() { void deletePolicyShouldThrowResponseStatusException() { // act final String policyId = "testId"; + when(persistence.readAll()).thenReturn(Map.of(BPN, List.of(new Policy("testId", null, null, null)))); doThrow(new PolicyStoreException("")).when(persistence).delete(BPN, policyId); // assert @@ -193,50 +201,165 @@ void deletePolicyShouldThrowResponseStatusException() { } @Test - void updatePolicy() { - // act - final String policyId = "testId"; - final OffsetDateTime validUntil = OffsetDateTime.now(); - testee.updatePolicy(policyId, new UpdatePolicyRequest(validUntil)); + void whenRegisterPolicyWithMissingPermissionsShouldThrowException() { + // arrange + final Policy policy = new Policy(); + // act // assert - verify(persistence).update(BPN, policyId, validUntil); + assertThrows(ResponseStatusException.class, () -> testee.registerPolicy(policy, null)); } @Test - void updatePolicyShouldThrowResponseStatusException() { - // act - final String policyId = "testId"; - final OffsetDateTime validUntil = OffsetDateTime.now(); - doThrow(new PolicyStoreException("")).when(persistence).update(BPN, policyId, validUntil); - final UpdatePolicyRequest request = new UpdatePolicyRequest(validUntil); + void whenRegisterPolicyWithMissingConstraintShouldThrowException() { + // arrange + final Policy policy = Policy.builder() + .permissions(List.of(Permission.builder() + .constraint( + new Constraints(emptyList(), emptyList())) + .build(), Permission.builder().build())) + .build(); + // act // assert - assertThrows(ResponseStatusException.class, () -> testee.updatePolicy(policyId, request)); + assertThrows(ResponseStatusException.class, () -> testee.registerPolicy(policy, null)); } @Test - void whenRegisterPolicyWithMissingPermissionsShouldThrowException() { + void whenUpdate() { // arrange - final Policy policy = new Policy(); + final String policyId = "testId"; + + final String originalBpn = "bpn2"; + final String expectedBpn = "bpn1"; + + final OffsetDateTime createdOn = OffsetDateTime.now(clock).minusDays(10); + final OffsetDateTime originalValidUntil = createdOn.plusMinutes(1); + final OffsetDateTime expectedValidUntil = createdOn.plusDays(3); + + final List permissions = emptyList(); + + final Policy testPolicy = new Policy(policyId, createdOn, originalValidUntil, permissions); + when(persistence.readAll()).thenReturn(Map.of(originalBpn, List.of(testPolicy))); + when(persistence.readAll(originalBpn)).thenReturn( + List.of(new Policy(policyId, createdOn, originalValidUntil, permissions))); // act + testee.updatePolicies(new UpdatePolicyRequest(expectedValidUntil, List.of(expectedBpn), List.of(policyId))); + // assert - assertThrows(ResponseStatusException.class, () -> testee.registerPolicy(policy)); + verify(persistence).delete(originalBpn, policyId); + + final var policyCaptor = ArgumentCaptor.forClass(Policy.class); + verify(persistence).save(eq(List.of(expectedBpn)), policyCaptor.capture()); + assertThat(policyCaptor.getValue().getCreatedOn()).isEqualTo(createdOn); + assertThat(policyCaptor.getValue().getValidUntil()).isEqualTo(expectedValidUntil); } + @SuppressWarnings("unchecked") @Test - void whenRegisterPolicyWithMissingConstraintShouldThrowException() { + void updatePolicies_shouldAddPolicyToEachBpn() { + + // ARRANGE + final String policyId = "testId"; + + final OffsetDateTime createdOn = OffsetDateTime.now(clock).minusDays(10); + final OffsetDateTime validUntil = createdOn.plusDays(14); + + final List permissions = emptyList(); + + // BPN1 without any policies + + // BPN2 with testPolicy + final Policy testPolicy = new Policy(policyId, createdOn, validUntil, permissions); + when(persistence.readAll()).thenReturn(Map.of("bpn2", List.of(testPolicy))); + when(persistence.readAll("bpn2")).thenReturn(List.of(testPolicy)); + + // ACT + testee.updatePolicies(new UpdatePolicyRequest(validUntil, List.of("bpn1", "bpn2"), List.of(policyId))); + + // ASSERT + verify(persistence).delete("bpn2", policyId); + + final var bpnsCaptor = ArgumentCaptor.forClass(List.class); + final var policyCaptor = ArgumentCaptor.forClass(Policy.class); + verify(persistence).save(bpnsCaptor.capture(), policyCaptor.capture()); + + // policy added to each BPN + assertThat(policyCaptor.getValue().getPolicyId()).isEqualTo(policyId); + assertThat(bpnsCaptor.getValue()).containsAll(List.of("bpn1", "bpn2")); + } + + @SuppressWarnings("unchecked") + @Test + void updatePolicies_shouldAddBpnsToEachPolicy() { + + // ARRANGE + final String policyId1 = "testId1"; + final String policyId2 = "testId2"; + + final String bpn1 = "bpn1"; + final String bpn2 = "bpn2"; + + final OffsetDateTime createdOn = OffsetDateTime.now(clock).minusDays(10); + final OffsetDateTime originalValidUntil = createdOn.plusMinutes(1); + + final List permissions = emptyList(); + + final Policy testPolicy1 = new Policy(policyId1, createdOn, originalValidUntil, permissions); + final Policy testPolicy2 = new Policy(policyId2, createdOn, originalValidUntil, permissions); + + // BPN1 without any policies + + // BPN2 with testPolicy1 and testPolicy2 + when(persistence.readAll()).thenReturn(Map.of(bpn2, List.of(testPolicy1, testPolicy2))); + when(persistence.readAll(bpn2)).thenReturn( + List.of(new Policy(policyId1, createdOn, originalValidUntil, permissions), + new Policy(policyId2, createdOn, originalValidUntil, permissions))); + + // ACT + testee.updatePolicies( + new UpdatePolicyRequest(originalValidUntil, List.of(bpn1, bpn2), List.of(policyId1, policyId2))); + + // ASSERT + verify(persistence).delete(bpn2, policyId1); + verify(persistence).delete(bpn2, policyId2); + + final var bpnsCaptor = ArgumentCaptor.forClass(List.class); + final var policyCaptor = ArgumentCaptor.forClass(Policy.class); + verify(persistence, times(2)).save(bpnsCaptor.capture(), policyCaptor.capture()); + + // each BPNs added to policy 1 + assertThat(policyCaptor.getAllValues().get(0).getPolicyId()).isEqualTo(policyId1); + assertThat(bpnsCaptor.getAllValues().get(0)).containsAll(List.of("bpn1", "bpn2")); + + // each BPNs added to policy 2 + assertThat(bpnsCaptor.getAllValues().get(1)).containsAll(List.of("bpn1", "bpn2")); + assertThat(policyCaptor.getAllValues().get(1).getPolicyId()).isEqualTo(policyId2); + } + + @Test + void shouldReturnDefaultPolicyWhenBpnIsEmpty() { // arrange - final Policy policy = Policy.builder() - .permissions(List.of( - Permission.builder().constraint(new Constraints(emptyList(), emptyList())).build(), - Permission.builder().build() - )) - .build(); + when(persistence.readAll()).thenReturn(emptyMap()); // act + final var acceptedPolicies = testee.getAcceptedPolicies(null); + // assert - assertThrows(ResponseStatusException.class, () -> testee.registerPolicy(policy)); + assertThat(acceptedPolicies.get(0).policy().getPolicyId()).isEqualTo("default-policy"); } + + @Test + void updatePolicyShouldThrowResponseStatusException() { + // act + final String policyId = "testId"; + final OffsetDateTime validUntil = OffsetDateTime.now(); + doThrow(new PolicyStoreException("")).when(persistence).readAll(); + + // assert + final List bpn = List.of("bpn"); + assertThrows(ResponseStatusException.class, () -> testee.updatePolicy(policyId, validUntil, bpn)); + } + } \ No newline at end of file diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java index cb15729950..37a322a9a9 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DefaultConfiguration.java @@ -73,6 +73,7 @@ public class DefaultConfiguration { private static final String CONFIG_VALUE_DECENTRAL = "decentral"; private static final String CONFIG_VALUE_CENTRAL = "central"; private static final int POOL_SIZE = 20; + private static final String DEFAULT = "default"; @Bean @ConditionalOnProperty(prefix = CONFIG_PREFIX, name = CONFIG_FIELD_TYPE, havingValue = CONFIG_VALUE_CENTRAL) @@ -118,9 +119,9 @@ public ConnectorEndpointsService connectorEndpointsService(final DiscoveryFinder @ConditionalOnProperty(prefix = CONFIG_PREFIX, name = CONFIG_FIELD_TYPE, havingValue = CONFIG_VALUE_DECENTRAL) public EndpointDataForConnectorsService endpointDataForConnectorsService(final EdcSubmodelFacade facade) { - final EdcEndpointReferenceRetriever edcEndpointReferenceRetriever = (edcConnectorEndpoint, assetType, assetValue) -> { + final EdcEndpointReferenceRetriever edcEndpointReferenceRetriever = (edcConnectorEndpoint, assetType, assetValue, bpn) -> { try { - return facade.getEndpointReferencesForAsset(edcConnectorEndpoint, assetType, assetValue); + return facade.getEndpointReferencesForAsset(edcConnectorEndpoint, assetType, assetValue, DEFAULT); } catch (EdcClientException e) { throw new EdcRetrieverException(e); } diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java index ab5b05e50c..5157d5293c 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryService.java @@ -159,7 +159,7 @@ private CompletableFuture> fetchShellDescriptors(final Set c log.info("Found {} connector endpoints for bpn '{}'", edcUrls.size(), bpn); calledEndpoints.addAll(edcUrls); - return fetchShellDescriptorsForConnectorEndpoints(keys, edcUrls); + return fetchShellDescriptorsForConnectorEndpoints(keys, edcUrls, bpn); } finally { watch.stop(); @@ -168,10 +168,10 @@ private CompletableFuture> fetchShellDescriptors(final Set c } private CompletableFuture> fetchShellDescriptorsForConnectorEndpoints( - final List keys, final List edcUrls) { + final List keys, final List edcUrls, final String bpn) { final var service = endpointDataForConnectorsService; - final var shellsFuture = service.createFindEndpointDataForConnectorsFutures(edcUrls) + final var shellsFuture = service.createFindEndpointDataForConnectorsFutures(edcUrls, bpn) .stream() .map(edrFuture -> edrFuture.thenCompose(edr -> CompletableFuture.supplyAsync( () -> fetchShellDescriptorsForKey(keys, edr)))) @@ -284,7 +284,7 @@ private Collection lookupShellIds(final String bpn) throws RegistryServi log.info("Looking up shell ids for bpn '{}' with connector endpoints {}", bpn, edcUrls); final var endpointDataReferenceFutures = endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures( - edcUrls); + edcUrls, bpn); return lookupShellIds(bpn, endpointDataReferenceFutures); diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java index d27f5748c7..3b76116a3a 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EdcEndpointReferenceRetriever.java @@ -39,9 +39,11 @@ public interface EdcEndpointReferenceRetriever { * @param edcConnectorEndpoint the endpoint URL * @param assetType the asset type id * @param assetValue the asset type value + * @param bpn bpn value * @return the endpoint data references as list of futures * @throws EdcRetrieverException on any EDC errors */ + @SuppressWarnings("PMD.UseObjectForClearerAPI") List> getEndpointReferencesForAsset(String edcConnectorEndpoint, - String assetType, String assetValue) throws EdcRetrieverException; + String assetType, String assetValue, String bpn) throws EdcRetrieverException; } diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java index 7b2af22161..c65abe5f1e 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsService.java @@ -47,7 +47,7 @@ public class EndpointDataForConnectorsService { private final EdcEndpointReferenceRetriever edcSubmodelFacade; public List> createFindEndpointDataForConnectorsFutures( - final List edcUrls) { + final List edcUrls, final String bpn) { final var watch = new StopWatch(); final String msg = "Creating futures to get EndpointDataReferences for endpoints: %s".formatted(edcUrls); @@ -58,7 +58,7 @@ public List> createFindEndpointDataForC try { log.info("Creating futures to get EndpointDataReferences for endpoints: {}", edcUrls); futures = edcUrls.stream() - .flatMap(edcUrl -> createGetEndpointReferencesForAssetFutures(edcUrl).stream()) + .flatMap(edcUrl -> createGetEndpointReferencesForAssetFutures(edcUrl, bpn).stream()) .toList(); return futures; } finally { @@ -69,7 +69,7 @@ public List> createFindEndpointDataForC } private List> createGetEndpointReferencesForAssetFutures( - final String edcUrl) { + final String edcUrl, final String bpn) { final var watch = new StopWatch(); final String msg = "Trying to retrieve EndpointDataReference for connector '%s'".formatted(edcUrl); @@ -78,7 +78,7 @@ private List> createGetEndpointReferenc try { return edcSubmodelFacade.getEndpointReferencesForAsset(edcUrl, DT_REGISTRY_ASSET_TYPE, - DT_REGISTRY_ASSET_VALUE); + DT_REGISTRY_ASSET_VALUE, bpn); } catch (EdcRetrieverException e) { log.warn("Exception occurred when retrieving EndpointDataReference from connector '{}'", edcUrl, e); return List.of(CompletableFuture.failedFuture(e)); diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/DefaultConfigurationTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/DefaultConfigurationTest.java index 79fff0dda1..e6fdc50904 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/DefaultConfigurationTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/DefaultConfigurationTest.java @@ -87,13 +87,13 @@ void endpointDataForConnectorsService() throws EdcClientException { final var mock = mock(EdcSubmodelFacade.class); final var endpointAddress = "endpointaddress"; final var endpointDataReference = EndpointDataReference.Builder.newInstance().endpoint(endpointAddress).build(); - when(mock.getEndpointReferencesForAsset(eq(endpointAddress), any(), any())).thenReturn( + when(mock.getEndpointReferencesForAsset(eq(endpointAddress), any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); // ACT final var endpointDataForConnectorsService = testee.endpointDataForConnectorsService(mock); - endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures(List.of(endpointAddress)) // + endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures(List.of(endpointAddress), "bpn") // .forEach(future -> { try { future.get(); @@ -106,17 +106,17 @@ void endpointDataForConnectorsService() throws EdcClientException { }); // ASSERT - verify(mock).getEndpointReferencesForAsset(eq(endpointAddress), any(), any()); + verify(mock).getEndpointReferencesForAsset(eq(endpointAddress), any(), any(), any()); } @Test void endpointDataForConnectorsService_withException() throws EdcClientException { final var mock = mock(EdcSubmodelFacade.class); - when(mock.getEndpointReferencesForAsset(any(), any(), any())).thenThrow(new EdcClientException("test")); + when(mock.getEndpointReferencesForAsset(any(), any(), any(), any())).thenThrow(new EdcClientException("test")); final var endpointDataForConnectorsService = testee.endpointDataForConnectorsService(mock); final var dummyEndpoints = List.of("test"); - endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures(dummyEndpoints).forEach(future -> { + endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures(dummyEndpoints, "bpn").forEach(future -> { assertThatThrownBy(future::get).isInstanceOf(ExecutionException.class) .extracting(Throwable::getCause) .isInstanceOf(EdcRetrieverException.class); diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceTest.java index a2c2dace14..74a2197551 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceTest.java @@ -99,7 +99,7 @@ void shouldReturnExpectedShell() throws RegistryServiceException { when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of("address")); final var endpointDataRefFutures = List.of(completedFuture(endpointDataReference)); - when(endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures(anyList())).thenReturn( + when(endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures(anyList(), any())).thenReturn( endpointDataRefFutures); when(decentralDigitalTwinRegistryClient.getAllAssetAdministrationShellIdsByAssetLink(any(), @@ -129,7 +129,7 @@ void whenInterruptedExceptionOccurs() throws ExecutionException, InterruptedExce completedFuture(endpointDataReference("url.to.host1")), // completedFuture(endpointDataReference("url.to.host2"))); when(endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures( - connectorEndpoints)).thenReturn(dataRefFutures); + connectorEndpoints, "bpn")).thenReturn(dataRefFutures); when(decentralDigitalTwinRegistryClient.getAllAssetAdministrationShellIdsByAssetLink(any(), anyList())).thenReturn(lookupShellsResponse); @@ -163,7 +163,7 @@ void whenExecutionExceptionOccurs() { final var dataRefFutures = List.of(completedFuture(endpointDataReference("url.to.host"))); when(endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures( - connectorEndpoints)).thenReturn(dataRefFutures); + connectorEndpoints, "bpn")).thenReturn(dataRefFutures); when(decentralDigitalTwinRegistryClient.getAllAssetAdministrationShellIdsByAssetLink(any(), anyList())).thenReturn(lookupShellsResponse); @@ -227,7 +227,7 @@ void shouldReturnTheExpectedGlobalAssetId() throws RegistryServiceException { .result(List.of(digitalTwinRegistryKey.shellId())) .build(); when(connectorEndpointsService.fetchConnectorEndpoints(any())).thenReturn(List.of("address")); - when(endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures(anyList())).thenReturn( + when(endpointDataForConnectorsService.createFindEndpointDataForConnectorsFutures(anyList(), any())).thenReturn( dataRefFutures); when(decentralDigitalTwinRegistryClient.getAllAssetAdministrationShellIdsByAssetLink(any(), anyList())).thenReturn(lookupShellsResponse); diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java index 3086e13764..d4a816441a 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/DecentralDigitalTwinRegistryServiceWiremockTest.java @@ -118,7 +118,7 @@ void shouldDiscoverEDCAndRequestRegistry() throws RegistryServiceException, EdcR givenThat(getShellDescriptor200()); final var endpointDataReference = endpointDataReference("assetId"); - when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); // Act @@ -167,7 +167,7 @@ void shouldThrowInCaseOfLookupShellsError() throws EdcRetrieverException { givenThat(postEdcDiscovery200()); final var endpointDataReference = endpointDataReference("assetId"); - when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); givenThat(getLookupShells404()); @@ -188,7 +188,7 @@ void shouldThrowInCaseOfShellDescriptorsError() throws EdcRetrieverException { givenThat(postEdcDiscovery200()); final var endpointDataReference = endpointDataReference("assetId"); - when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); givenThat(getLookupShells200()); @@ -211,7 +211,7 @@ void shouldThrowExceptionOnEmptyShells() throws EdcRetrieverException { givenThat(postEdcDiscovery200()); final var endpointDataReference = endpointDataReference("assetId"); - when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); givenThat(getLookupShells200Empty()); @@ -241,7 +241,7 @@ void lookupShellIdentifiers_oneEDC_oneDTR() throws RegistryServiceException, Edc // simulate endpoint data reference final var endpointDataReference = endpointDataReference("assetId"); - when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); // Act @@ -272,9 +272,9 @@ void lookupShellIdentifiers_multipleEDCs_oneDTR(String title, // simulate endpoint data reference final var endpointDataReference = endpointDataReference("assetId"); - when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc1Url), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc1Url), any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference))); - when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc2Url), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc2Url), any(), any(), any())).thenReturn( endpointDataReferenceForAssetFutures); // Act @@ -317,9 +317,9 @@ void lookupShellIdentifiers_multipleEDCs_multipleDTRs() throws RegistryServiceEx // simulate endpoint data reference final var endpointDataReference1 = endpointDataReference("dtr1-assetId"); final var endpointDataReference2 = endpointDataReference("dtr2-assetId"); - when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc1Url), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc1Url), any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference1))); - when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc2Url), any(), any())).thenReturn( + when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(eq(edc2Url), any(), any(), any())).thenReturn( List.of(CompletableFuture.completedFuture(endpointDataReference2))); // Act & Assert diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsServiceTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsServiceTest.java index b4a8b9f922..3181ef0310 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsServiceTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/decentral/EndpointDataForConnectorsServiceTest.java @@ -45,14 +45,15 @@ class EndpointDataForConnectorsServiceTest { private static final String DT_REGISTRY_ASSET_TYPE = "https://w3id.org/edc/v0.0.1/ns/type"; private static final String DT_REGISTRY_ASSET_VALUE = "data.core.digitalTwinRegistry"; - private static final String connectionOneAddress = "connectionOneAddress"; - private static final String connectionTwoAddress = "connectionTwoAddress"; + private static final String CONNECTION_ONE_ADDRESS = "connectionOneAddress"; + private static final String CONNECTION_TWO_ADDRESS = "connectionTwoAddress"; + private static final String BPN = "bpn"; private static final EndpointDataReference CONNECTION_ONE_DATA_REF = // - EndpointDataReference.Builder.newInstance().endpoint(connectionOneAddress).build(); + EndpointDataReference.Builder.newInstance().endpoint(CONNECTION_ONE_ADDRESS).build(); private static final EndpointDataReference CONNECTION_TWO_DATA_REF = // - EndpointDataReference.Builder.newInstance().endpoint(connectionTwoAddress).build(); + EndpointDataReference.Builder.newInstance().endpoint(CONNECTION_TWO_ADDRESS).build(); private final EdcEndpointReferenceRetriever edcSubmodelFacade = mock(EdcEndpointReferenceRetriever.class); @@ -62,20 +63,20 @@ class EndpointDataForConnectorsServiceTest { void shouldReturnExpectedEndpointDataReference() throws EdcRetrieverException { // GIVEN - when(edcSubmodelFacade.getEndpointReferencesForAsset(connectionOneAddress, DT_REGISTRY_ASSET_TYPE, - DT_REGISTRY_ASSET_VALUE)).thenReturn( + when(edcSubmodelFacade.getEndpointReferencesForAsset(CONNECTION_ONE_ADDRESS, DT_REGISTRY_ASSET_TYPE, + DT_REGISTRY_ASSET_VALUE, BPN)).thenReturn( List.of(CompletableFuture.completedFuture(CONNECTION_ONE_DATA_REF))); // WHEN final List> endpointDataReferences = sut.createFindEndpointDataForConnectorsFutures( - Collections.singletonList(connectionOneAddress)); + Collections.singletonList(CONNECTION_ONE_ADDRESS), BPN); // THEN assertThat(endpointDataReferences).isNotEmpty() .extracting(CompletableFuture::get) .isNotEmpty() .extracting(EndpointDataReference::getEndpoint) - .contains(connectionOneAddress); + .contains(CONNECTION_ONE_ADDRESS); } @Test @@ -84,20 +85,20 @@ void shouldReturnExpectedEndpointDataReferenceFromSecondConnectionEndpoint() thr // GIVEN // a first endpoint failing (1) - when(edcSubmodelFacade.getEndpointReferencesForAsset(connectionOneAddress, DT_REGISTRY_ASSET_TYPE, - DT_REGISTRY_ASSET_VALUE)).thenThrow( + when(edcSubmodelFacade.getEndpointReferencesForAsset(CONNECTION_ONE_ADDRESS, DT_REGISTRY_ASSET_TYPE, + DT_REGISTRY_ASSET_VALUE, BPN)).thenThrow( new EdcRetrieverException(new EdcClientException("EdcClientException"))); // and a second endpoint returning successfully (2) - when(edcSubmodelFacade.getEndpointReferencesForAsset(connectionTwoAddress, DT_REGISTRY_ASSET_TYPE, - DT_REGISTRY_ASSET_VALUE)).thenReturn( + when(edcSubmodelFacade.getEndpointReferencesForAsset(CONNECTION_TWO_ADDRESS, DT_REGISTRY_ASSET_TYPE, + DT_REGISTRY_ASSET_VALUE, BPN)).thenReturn( List.of(CompletableFuture.completedFuture(CONNECTION_TWO_DATA_REF))); // WHEN final List> dataRefFutures = // - sut.createFindEndpointDataForConnectorsFutures(List.of(connectionOneAddress, // (1) - connectionTwoAddress // (2) - )); + sut.createFindEndpointDataForConnectorsFutures(List.of(CONNECTION_ONE_ADDRESS, // (1) + CONNECTION_TWO_ADDRESS // (2) + ), BPN); // THEN final List dataReferences = // @@ -108,7 +109,7 @@ void shouldReturnExpectedEndpointDataReferenceFromSecondConnectionEndpoint() thr assertThat(dataReferences).isNotEmpty() // .extracting(EndpointDataReference::getEndpoint) // - .contains(connectionTwoAddress); + .contains(CONNECTION_TWO_ADDRESS); } private static EndpointDataReference executeFutureMappingErrorsToNull( @@ -126,15 +127,15 @@ void shouldThrowExceptionWhenConnectorEndpointsNotReachable() throws EdcRetrieve // GIVEN when(edcSubmodelFacade.getEndpointReferencesForAsset(anyString(), eq(DT_REGISTRY_ASSET_TYPE), - eq(DT_REGISTRY_ASSET_VALUE))).thenThrow( + eq(DT_REGISTRY_ASSET_VALUE), eq(BPN))).thenThrow( new EdcRetrieverException(new EdcClientException("EdcClientException"))); // WHEN final var exceptions = new ArrayList<>(); // THEN - final List connectorEndpoints = List.of(connectionOneAddress, connectionTwoAddress); - sut.createFindEndpointDataForConnectorsFutures(connectorEndpoints) // + final List connectorEndpoints = List.of(CONNECTION_ONE_ADDRESS, CONNECTION_TWO_ADDRESS); + sut.createFindEndpointDataForConnectorsFutures(connectorEndpoints, BPN) // .forEach(future -> { try { future.get(); diff --git a/local/testing/request-collection/IRS_Request_Collection.json b/local/testing/request-collection/IRS_Request_Collection.json index 0722d60f79..f1c6743d34 100644 --- a/local/testing/request-collection/IRS_Request_Collection.json +++ b/local/testing/request-collection/IRS_Request_Collection.json @@ -1,15 +1,15 @@ { "_type": "export", "__export_format": 4, - "__export_date": "2024-03-10T13:23:40.100Z", - "__export_source": "insomnia.desktop.app:v2023.5.8", + "__export_date": "2024-03-22T09:31:33.166Z", + "__export_source": "insomnia.desktop.app:v8.6.1", "resources": [ { - "_id": "req_87f0d66bd32b4f2d8551791af7f2e2ed", - "parentId": "fld_6d020c1b8cd44f51b9a2edfff562caf1", - "modified": 1705006817408, + "_id": "req_2d5a4fb5ec0845059533cb9904910156", + "parentId": "fld_c751e5e73d5248a3ae22a44bafae7906", + "modified": 1711099785377, "created": 1705005887617, - "url": "{{IRS_HOST}}/irs/policies", + "url": "{{IRS_HOST}}/irs/policies?bpnls=BPNL00000001CRHK", "name": "Get all policies", "description": "", "method": "GET", @@ -25,6 +25,7 @@ }, "metaSortKey": -1705005887617, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -34,8 +35,8 @@ "_type": "request" }, { - "_id": "fld_6d020c1b8cd44f51b9a2edfff562caf1", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_c751e5e73d5248a3ae22a44bafae7906", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1687243055015, "created": 1687243055015, "name": "Policy Store", @@ -46,8 +47,8 @@ "_type": "request_group" }, { - "_id": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", - "parentId": "wrk_565df8abe30f4da29d8bffcde97927d7", + "_id": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", + "parentId": "wrk_d83bab75184e43adadd63001907af70d", "modified": 1691572726194, "created": 1680682418636, "name": "IRS DEMO Collection", @@ -58,18 +59,18 @@ "_type": "request_group" }, { - "_id": "wrk_565df8abe30f4da29d8bffcde97927d7", + "_id": "wrk_d83bab75184e43adadd63001907af70d", "parentId": null, - "modified": 1680682438221, - "created": 1680682419747, + "modified": 1711099756361, + "created": 1711099756361, "name": "IRS", "description": "", "scope": "collection", "_type": "workspace" }, { - "_id": "req_5696fa47e33c407cbb7a2deac8ddbcd2", - "parentId": "fld_6d020c1b8cd44f51b9a2edfff562caf1", + "_id": "req_ab9376672bd94bd783aa97f36646981b", + "parentId": "fld_c751e5e73d5248a3ae22a44bafae7906", "modified": 1702990529632, "created": 1687243204155, "url": "{{IRS_HOST}}/irs/policies/{% prompt 'policyId', '', 'traceability-test', '', false, true %}", @@ -88,6 +89,7 @@ }, "metaSortKey": -1685602897140.75, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -97,17 +99,17 @@ "_type": "request" }, { - "_id": "req_34b6d543720247a7bcad402cab2d2f7f", - "parentId": "fld_6d020c1b8cd44f51b9a2edfff562caf1", - "modified": 1702990565006, + "_id": "req_a68c5fa596ee4b738eefd6b7b4e2bd7a", + "parentId": "fld_c751e5e73d5248a3ae22a44bafae7906", + "modified": 1711099840007, "created": 1693576003390, - "url": "{{IRS_HOST}}/irs/policies/{% prompt 'id', '', 'traceability-test', '', false, true %}", + "url": "{{IRS_HOST}}/irs/policies", "name": "Update policy", "description": "", "method": "PUT", "body": { "mimeType": "application/json", - "text": "{\n \"validUntil\": \"2025-12-12T23:59:59.999Z\"\n}" + "text": "{\n \"validUntil\": \"2025-12-12T23:59:59.999Z\",\n\t\"businessPartnerNumbers\": [\n\t\t\"BPNL00000001CRHK\"\n\t],\n\t\"policiesIds\": [\n\t\t\"policyId\"\n\t]\n}" }, "parameters": [], "headers": [ @@ -125,6 +127,7 @@ }, "metaSortKey": -1684874704117.875, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -134,9 +137,9 @@ "_type": "request" }, { - "_id": "req_82102b5d71704eae97e5b50dad29a262", - "parentId": "fld_6d020c1b8cd44f51b9a2edfff562caf1", - "modified": 1707126688041, + "_id": "req_95aa08cefddc4743afc85fcabf40e4ee", + "parentId": "fld_c751e5e73d5248a3ae22a44bafae7906", + "modified": 1711099862861, "created": 1687243182397, "url": "{{IRS_HOST}}/irs/policies", "name": "Register policy", @@ -144,7 +147,7 @@ "method": "POST", "body": { "mimeType": "application/json", - "text": "{\n\t\"validUntil\": \"2025-12-12T23:59:59.999Z\",\n\t\"payload\": {\n\t\t\"@context\": {\n\t\t\t\"odrl\": \"http://www.w3.org/ns/odrl/2/\"\n\t\t},\n\t\t\"@id\": \"policy-id12\",\n\t\t\"policy\": {\n\t\t\t\"odrl:permission\": [\n\t\t\t\t{\n\t\t\t\t\t\"odrl:action\": \"USE\",\n\t\t\t\t\t\"odrl:constraint\": {\n\t\t\t\t\t\t\"odrl:and\": [\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"odrl:leftOperand\": \"Membership\",\n\t\t\t\t\t\t\t\t\"odrl:operator\": {\n\t\t\t\t\t\t\t\t\t\"@id\": \"odrl:eq\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"odrl:rightOperand\": \"active\"\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\"odrl:leftOperand\": \"PURPOSE\",\n\t\t\t\t\t\t\t\t\"odrl:operator\": {\n\t\t\t\t\t\t\t\t\t\"@id\": \"odrl:eq\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\"odrl:rightOperand\": \"ID 3.1 Trace\"\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t]\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t]\n\t\t}\n\t}\n}" + "text": "{\n\t\"validUntil\": \"2025-12-12T23:59:59.999Z\",\n\t\"businessPartnerNumbers\": [\n\t\t\"BPNL00000001CRHK\"\n\t],\n\t\"payload\": [\n\t\t{\n\t\t\t\"@context\": {\n\t\t\t\t\"odrl\": \"http://www.w3.org/ns/odrl/2/\"\n\t\t\t},\n\t\t\t\"@id\": \"test-1\",\n\t\t\t\"policy\": {\n\t\t\t\t\"odrl:permission\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"odrl:action\": \"USE\",\n\t\t\t\t\t\t\"odrl:constraint\": {\n\t\t\t\t\t\t\t\"odrl:and\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"odrl:leftOperand\": \"Membership\",\n\t\t\t\t\t\t\t\t\t\"odrl:operator\": {\n\t\t\t\t\t\t\t\t\t\t\"@id\": \"odrl:eq\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"odrl:rightOperand\": \"active\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"odrl:leftOperand\": \"PURPOSE\",\n\t\t\t\t\t\t\t\t\t\"odrl:operator\": {\n\t\t\t\t\t\t\t\t\t\t\"@id\": \"odrl:eq\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"odrl:rightOperand\": \"ID 3.1 Trace\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t},\n\t\t{\n\t\t\t\"@context\": {\n\t\t\t\t\"odrl\": \"http://www.w3.org/ns/odrl/2/\"\n\t\t\t},\n\t\t\t\"@id\": \"test-12\",\n\t\t\t\"policy\": {\n\t\t\t\t\"odrl:permission\": [\n\t\t\t\t\t{\n\t\t\t\t\t\t\"odrl:action\": \"USE\",\n\t\t\t\t\t\t\"odrl:constraint\": {\n\t\t\t\t\t\t\t\"odrl:and\": [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"odrl:leftOperand\": \"Membership\",\n\t\t\t\t\t\t\t\t\t\"odrl:operator\": {\n\t\t\t\t\t\t\t\t\t\t\"@id\": \"odrl:eq\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"odrl:rightOperand\": \"active\"\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\t\"odrl:leftOperand\": \"PURPOSE\",\n\t\t\t\t\t\t\t\t\t\"odrl:operator\": {\n\t\t\t\t\t\t\t\t\t\t\"@id\": \"odrl:eq\"\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t\"odrl:rightOperand\": \"ID 3.1 Trace\"\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t]\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t]\n\t\t\t}\n\t\t}\n\t]\n}" }, "parameters": [], "headers": [ @@ -162,6 +165,7 @@ }, "metaSortKey": -1683962737633.5, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -171,8 +175,8 @@ "_type": "request" }, { - "_id": "req_01d928eddda6422eae8f9e6722997640", - "parentId": "fld_bd90851d07ce4f4bad16dc5665dcf3c1", + "_id": "req_b22ea4121d2249e0830489b188ec21e4", + "parentId": "fld_5930ffca903d46feb1793ebd290dde47", "modified": 1706003275081, "created": 1680682418619, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/shell-descriptors/{% prompt 'aasIdentifier', '', _.GLOBAL_ASSET_ID, '', false, true %}", @@ -193,6 +197,7 @@ "authentication": {}, "metaSortKey": -1680682418619, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -202,8 +207,8 @@ "_type": "request" }, { - "_id": "fld_bd90851d07ce4f4bad16dc5665dcf3c1", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_5930ffca903d46feb1793ebd290dde47", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1691504187689, "created": 1680682418630, "name": "Digital Twin Registry", @@ -214,8 +219,8 @@ "_type": "request_group" }, { - "_id": "req_c6d045b660f949499151f63e60f51225", - "parentId": "fld_bd90851d07ce4f4bad16dc5665dcf3c1", + "_id": "req_ca1125488c45483c9ddda17955067893", + "parentId": "fld_5930ffca903d46feb1793ebd290dde47", "modified": 1706002920212, "created": 1690529035794, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/shell-descriptors", @@ -236,6 +241,7 @@ "authentication": {}, "metaSortKey": -1680682418614, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -245,8 +251,8 @@ "_type": "request" }, { - "_id": "req_c183c331cf2c418e8e89ce95dee5ddbd", - "parentId": "fld_bd90851d07ce4f4bad16dc5665dcf3c1", + "_id": "req_6735560470e644d2b0378e7bddf1b99e", + "parentId": "fld_5930ffca903d46feb1793ebd290dde47", "modified": 1706003278149, "created": 1680682418609, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells", @@ -315,6 +321,7 @@ "authentication": {}, "metaSortKey": -1680682418609, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -324,8 +331,8 @@ "_type": "request" }, { - "_id": "req_24a9b4f03e7a498dbc51aecea0ca3492", - "parentId": "fld_bd90851d07ce4f4bad16dc5665dcf3c1", + "_id": "req_837d51ff21e140ab96da276abdaaef54", + "parentId": "fld_5930ffca903d46feb1793ebd290dde47", "modified": 1706003280850, "created": 1680682418595, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells", @@ -352,6 +359,7 @@ "authentication": {}, "metaSortKey": -1680682418595, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -361,8 +369,8 @@ "_type": "request" }, { - "_id": "req_5fb54d629b714382ae77c4918a848844", - "parentId": "fld_bd90851d07ce4f4bad16dc5665dcf3c1", + "_id": "req_9332ba908a3648328059a85fc5583ac9", + "parentId": "fld_5930ffca903d46feb1793ebd290dde47", "modified": 1706003354109, "created": 1680682418581, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells", @@ -389,6 +397,7 @@ "authentication": {}, "metaSortKey": -1680682418581, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -398,8 +407,8 @@ "_type": "request" }, { - "_id": "req_0231f2221b0b4c52b6f8f82654b40b97", - "parentId": "fld_bd90851d07ce4f4bad16dc5665dcf3c1", + "_id": "req_0b28f257a75249d084c0cedad0e3c655", + "parentId": "fld_5930ffca903d46feb1793ebd290dde47", "modified": 1706003284715, "created": 1680682418570, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells/query", @@ -427,6 +436,7 @@ "authentication": {}, "metaSortKey": -1680682418570, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -436,8 +446,8 @@ "_type": "request" }, { - "_id": "req_0e9e498304f1450db30ccd7633c1d044", - "parentId": "fld_bd90851d07ce4f4bad16dc5665dcf3c1", + "_id": "req_f593512f0af543a6b70242da819df2db", + "parentId": "fld_5930ffca903d46feb1793ebd290dde47", "modified": 1706003286642, "created": 1691408320970, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/lookup/shells/query", @@ -465,6 +475,7 @@ "authentication": {}, "metaSortKey": -1680682418560.5, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -474,8 +485,8 @@ "_type": "request" }, { - "_id": "req_c45556a411394ae7acaf7b0d7a52c64c", - "parentId": "fld_bd90851d07ce4f4bad16dc5665dcf3c1", + "_id": "req_bbb801fd3b2b444bb3318a8de92918a9", + "parentId": "fld_5930ffca903d46feb1793ebd290dde47", "modified": 1706003289343, "created": 1689167429413, "url": "{{DIGITAL_TWIN_REGISTRY}}/api/v3.0/shell-descriptors/{% prompt 'id', '', '', '', false, true %}", @@ -504,6 +515,7 @@ "authentication": {}, "metaSortKey": -1680682418470, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -513,8 +525,8 @@ "_type": "request" }, { - "_id": "req_4598fa44ca1e445f84dcc88b69e68b2d", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_7ea6d52eea2442ba82a8255041f3cb39", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991054859, "created": 1680682418551, "url": "{{IRS_HOST}}/irs/jobs", @@ -541,6 +553,7 @@ }, "metaSortKey": -1680682418551, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -550,8 +563,8 @@ "_type": "request" }, { - "_id": "fld_99916d6788d445df86cffea2202c7faf", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_80d0dfda7d9849f8923030bcb64169a7", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1680682418562, "created": 1680682418562, "name": "IRS Test Collection", @@ -562,8 +575,8 @@ "_type": "request_group" }, { - "_id": "req_1789ac98712b4774a9478e25eb589bf0", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_b5a068e9bd7044c699f03ee26a1c7499", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991058493, "created": 1680682418539, "url": "{{IRS_HOST}}/irs/jobs", @@ -590,6 +603,7 @@ }, "metaSortKey": -1680682418539, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -599,8 +613,8 @@ "_type": "request" }, { - "_id": "req_3a2d07190c9546378a10b66b6ff4f462", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_f32ea4db7e4e4c0fa9a4058f20ab3a58", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991063641, "created": 1680682418524, "url": "{{IRS_HOST}}/irs/jobs", @@ -627,6 +641,7 @@ }, "metaSortKey": -1680682418524, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -636,8 +651,8 @@ "_type": "request" }, { - "_id": "req_8a3d036a282e403481b73587111f6aa7", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_fa7ee06927f942a88dcf9d047a59dd22", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991067797, "created": 1680682418514, "url": "{{IRS_HOST}}/irs/jobs", @@ -664,6 +679,7 @@ }, "metaSortKey": -1680682418514, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -673,8 +689,8 @@ "_type": "request" }, { - "_id": "req_3dfcf0469334429f8ed26e7cb3b1e7b4", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_0a75e90c3b8c4f4cb2088d456b0d1d98", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991071709, "created": 1680682418504, "url": "{{IRS_HOST}}/irs/jobs", @@ -701,6 +717,7 @@ }, "metaSortKey": -1680682418504, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -710,8 +727,8 @@ "_type": "request" }, { - "_id": "req_8bf909bae9f54371a9056e6c4b9eefca", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_4424152376ce49e1b00d404b4346b9e4", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991076696, "created": 1695042901876, "url": "{{IRS_HOST}}/irs/jobs", @@ -738,6 +755,7 @@ }, "metaSortKey": -1680682418496, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -747,8 +765,8 @@ "_type": "request" }, { - "_id": "req_dc785af1908140b4b28e72a7b89c10e2", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_b8bcd1059fa0428fa74db6e0df9a549c", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076144872, "created": 1680682418488, "url": "{{IRS_HOST}}/irs/jobs", @@ -775,6 +793,7 @@ }, "metaSortKey": -1680682418488, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -784,8 +803,8 @@ "_type": "request" }, { - "_id": "req_1d2d60468a46479aa620856c3af9edad", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_1f8b0bee14394eebbd17f2a845491f5b", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076455844, "created": 1680682418479, "url": "{{IRS_HOST}}/irs/jobs", @@ -812,6 +831,7 @@ }, "metaSortKey": -1680682418479, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -821,8 +841,8 @@ "_type": "request" }, { - "_id": "req_e4781ee7f21c4269877a90c7b3763747", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_3d4c81094d24462c9f6eb69069dabfcf", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076515556, "created": 1680682418469, "url": "{{IRS_HOST}}/irs/jobs", @@ -849,6 +869,7 @@ }, "metaSortKey": -1680682418469, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -858,8 +879,8 @@ "_type": "request" }, { - "_id": "req_4454faa5384d4e1a9eed077d9bb439d3", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_d11875dae2e142cd99de8db2594b5749", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076741632, "created": 1680682418442, "url": "{{IRS_HOST}}/irs/jobs", @@ -886,6 +907,7 @@ }, "metaSortKey": -1680682418442, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -895,8 +917,8 @@ "_type": "request" }, { - "_id": "req_14d8a81103934ca8bde6a913419b6965", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_3664de01c8554ff89c651dff9e0821ab", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076751758, "created": 1680682418432, "url": "{{IRS_HOST}}/irs/jobs", @@ -923,6 +945,7 @@ }, "metaSortKey": -1680682418432, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -932,8 +955,8 @@ "_type": "request" }, { - "_id": "req_4d162553ba09443686bb9e8e90e01f97", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_60839c35d2124c9fbb593969fcc552df", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076760570, "created": 1695192937155, "url": "{{IRS_HOST}}/irs/jobs", @@ -960,6 +983,7 @@ }, "metaSortKey": -1680682418428, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -969,8 +993,8 @@ "_type": "request" }, { - "_id": "req_2bdd38ac17234d7286dc03f0c2741d25", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_5215512817494d63918383988c06144c", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076769119, "created": 1695192971825, "url": "{{IRS_HOST}}/irs/jobs", @@ -997,6 +1021,7 @@ }, "metaSortKey": -1680682418426, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1006,8 +1031,8 @@ "_type": "request" }, { - "_id": "req_56ce00c13b6e42329fb3ed6d18a134eb", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_050aba71af544728bf13966232a68c94", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076214310, "created": 1680682418424, "url": "{{IRS_HOST}}/irs/jobs", @@ -1034,6 +1059,7 @@ }, "metaSortKey": -1680682418424, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1043,8 +1069,8 @@ "_type": "request" }, { - "_id": "req_c4e086d67cb64786b235745f4e56f24c", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_245ceb95afa8407ba017e6143e942557", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991130711, "created": 1680682418414, "url": "{{IRS_HOST}}/irs/jobs", @@ -1071,6 +1097,7 @@ }, "metaSortKey": -1680682418414, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1080,8 +1107,8 @@ "_type": "request" }, { - "_id": "req_2571426d88934df39d76364ce94533a9", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_5c0c50a042914805a4f00cc38e6ec327", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076937249, "created": 1680682418401, "url": "{{IRS_HOST}}/irs/jobs", @@ -1108,6 +1135,7 @@ }, "metaSortKey": -1680682418401, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1117,8 +1145,8 @@ "_type": "request" }, { - "_id": "req_f0b3da6d108f475cb429c99bd9c57dc5", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_fd882f9ee36c4efaaaaad5ee15110e95", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076677384, "created": 1680682418392, "url": "{{IRS_HOST}}/irs/jobs", @@ -1145,6 +1173,7 @@ }, "metaSortKey": -1680682418392, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1154,8 +1183,8 @@ "_type": "request" }, { - "_id": "req_f8f3e3d937e341e388abd88454f31cc2", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_7c176ef2953f4ef3a9bafdf1fdc4f59c", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076237949, "created": 1683184048412, "url": "{{IRS_HOST}}/irs/jobs", @@ -1182,6 +1211,7 @@ }, "metaSortKey": -1680682418386.5, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1191,8 +1221,8 @@ "_type": "request" }, { - "_id": "req_6d86d4ad672a454f85f03672926d6f3c", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_e72bfa320e9d44c7b5df861133034f65", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076397373, "created": 1693493383337, "url": "{{IRS_HOST}}/irs/jobs", @@ -1219,6 +1249,7 @@ }, "metaSortKey": -1680682418382.375, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1228,8 +1259,8 @@ "_type": "request" }, { - "_id": "req_9f6f900788a94461a3856dff0fd3102b", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_d0b0ebd7ab684c038163cbda0d8e38b2", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076245754, "created": 1693493584873, "url": "{{IRS_HOST}}/irs/jobs", @@ -1256,6 +1287,7 @@ }, "metaSortKey": -1680682418381.6875, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1265,8 +1297,8 @@ "_type": "request" }, { - "_id": "req_b4dabeb86fed4de5b54c32a250f94196", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_daed8469e6804426b06e685c13c5a2ee", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076391502, "created": 1693493594373, "url": "{{IRS_HOST}}/irs/jobs", @@ -1293,6 +1325,7 @@ }, "metaSortKey": -1680682418381.3438, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1302,8 +1335,8 @@ "_type": "request" }, { - "_id": "req_35ef2aef21804c3cb86a9aabc7eba0ab", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_3ee66542ae4d4bd086097cc127901a0d", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1710076385497, "created": 1693493604521, "url": "{{IRS_HOST}}/irs/jobs", @@ -1330,6 +1363,7 @@ }, "metaSortKey": -1680682418381.1719, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1339,8 +1373,8 @@ "_type": "request" }, { - "_id": "req_d27e4316d77c4a48adbe27e65390cda8", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_db0100a82fdc4bd7ac88f5fcbfc951f7", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991173689, "created": 1680682418381, "url": "{{IRS_HOST}}/irs/jobs", @@ -1370,6 +1404,7 @@ }, "metaSortKey": -1680682418381, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1379,8 +1414,8 @@ "_type": "request" }, { - "_id": "req_d8fdde14cf9144ff805a51ff292b9382", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_bf1ded5777714303b33ecc6d802d65ac", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991177973, "created": 1680682418372, "url": "{{IRS_HOST}}/irs/jobs", @@ -1410,6 +1445,7 @@ }, "metaSortKey": -1680682418372, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1419,8 +1455,8 @@ "_type": "request" }, { - "_id": "req_19d3cc30b4644dd8957cf980f3ee10ff", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_6dbc72ee2c494a1784766b54862ed682", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991182139, "created": 1680682418358, "url": "{{IRS_HOST}}/irs/jobs", @@ -1450,6 +1486,7 @@ }, "metaSortKey": -1680682418358, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1459,8 +1496,8 @@ "_type": "request" }, { - "_id": "req_7801aee13dd5435a8db10338a2d4f95b", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_ac1c2b21900440d4901111176675e2ff", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991186114, "created": 1680682418348, "url": "{{IRS_HOST}}/irs/jobs", @@ -1484,6 +1521,7 @@ }, "metaSortKey": -1680682418348, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1493,8 +1531,8 @@ "_type": "request" }, { - "_id": "req_1687b685ea5949c89c8c61e483dc60f0", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_53fd3aefa06945f8aea85d3b3c322699", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991190326, "created": 1680682418339, "url": "{{IRS_HOST}}/irs/jobs", @@ -1524,6 +1562,7 @@ }, "metaSortKey": -1680682418339, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1533,8 +1572,8 @@ "_type": "request" }, { - "_id": "req_d4d21a45adbc4398a37eb64325f96277", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_0f0101575ead4084b46710bfb0091f3f", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991196283, "created": 1680682418325, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", @@ -1564,6 +1603,7 @@ }, "metaSortKey": -1680682418325, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1573,8 +1613,8 @@ "_type": "request" }, { - "_id": "req_9baf580bb6384fcea6cd181bc4019c97", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_c50ba332341e4018b4313e7e72695954", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991200399, "created": 1680682418316, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", @@ -1598,6 +1638,7 @@ }, "metaSortKey": -1680682418316, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1607,8 +1648,8 @@ "_type": "request" }, { - "_id": "req_ea9dc2c81dae4b4e945c52ed81a233b9", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_bfcb98fc286a4be79030c9513ed9735f", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991205447, "created": 1680682418307, "url": "{{IRS_HOST}}/irs/jobs/test", @@ -1632,6 +1673,7 @@ }, "metaSortKey": -1680682418307, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1641,8 +1683,8 @@ "_type": "request" }, { - "_id": "req_0808b16bfb534c7e859834972a64ffd0", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_35c58b65dd9d4582ab9472ad1c9d3e3b", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991214202, "created": 1680682418297, "url": "{{IRS_HOST}}/irs/jobs/00000000-0000-0000-0000-000000000000", @@ -1666,6 +1708,7 @@ }, "metaSortKey": -1680682418297, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1675,8 +1718,8 @@ "_type": "request" }, { - "_id": "req_c28839aad9394b2bbda87017500ed616", - "parentId": "fld_99916d6788d445df86cffea2202c7faf", + "_id": "req_896fa0136d6e49d69a938f4de5811bad", + "parentId": "fld_80d0dfda7d9849f8923030bcb64169a7", "modified": 1702991218362, "created": 1680682418280, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", @@ -1700,6 +1743,7 @@ }, "metaSortKey": -1680682418280, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1709,8 +1753,8 @@ "_type": "request" }, { - "_id": "req_d8919afd30d44d1a846084157de8c69d", - "parentId": "fld_9bf5f1410d1b4472b588bfe79bae6d2d", + "_id": "req_69f863ad2c674907ad29581828ba5c43", + "parentId": "fld_7a3a1e3a4fe8428098021e110a52ba0d", "modified": 1705942015684, "created": 1682672699249, "url": "{{ _.BPN_DISCOVERY }}/api/administration/connectors/bpnDiscovery/search", @@ -1738,6 +1782,7 @@ }, "metaSortKey": -1683630902023, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1747,8 +1792,8 @@ "_type": "request" }, { - "_id": "fld_9bf5f1410d1b4472b588bfe79bae6d2d", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_7a3a1e3a4fe8428098021e110a52ba0d", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1683630931664, "created": 1683630887514, "name": "Discovery", @@ -1759,8 +1804,8 @@ "_type": "request_group" }, { - "_id": "req_01422217227b452a98e7db4cb60ca5bd", - "parentId": "fld_9bf5f1410d1b4472b588bfe79bae6d2d", + "_id": "req_7ba23e27b73845c9a9b566c72f4f0c29", + "parentId": "fld_7a3a1e3a4fe8428098021e110a52ba0d", "modified": 1705942027574, "created": 1683031718699, "url": "{{ _.DISCOVERY_FINDER }}/api/administration/connectors/discovery/search", @@ -1788,6 +1833,7 @@ }, "metaSortKey": -1683630901923, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1797,8 +1843,8 @@ "_type": "request" }, { - "_id": "req_1357c99d62684a7b93cde637b6490d11", - "parentId": "fld_9bf5f1410d1b4472b588bfe79bae6d2d", + "_id": "req_4325898bf3df40648ad9cf8b304a58ee", + "parentId": "fld_7a3a1e3a4fe8428098021e110a52ba0d", "modified": 1705942036978, "created": 1683560906453, "url": "{{ _.EDC_DISCOVERY }}/api/administration/connectors/discovery", @@ -1826,6 +1872,7 @@ }, "metaSortKey": -1683630901873, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1835,8 +1882,8 @@ "_type": "request" }, { - "_id": "req_3261038fea10412c9f1daf62c3129529", - "parentId": "fld_b5db89748d844f92a8e2f577faa58f25", + "_id": "req_349d613f763d4102bee054dcfd5da1bc", + "parentId": "fld_1ef343e864c14d44b2f8aa660aa7e5ac", "modified": 1710076352238, "created": 1680682418265, "url": "{{IRS_HOST}}/irs/jobs", @@ -1863,6 +1910,7 @@ }, "metaSortKey": -1680682418265, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1872,8 +1920,8 @@ "_type": "request" }, { - "_id": "fld_b5db89748d844f92a8e2f577faa58f25", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_1ef343e864c14d44b2f8aa660aa7e5ac", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1680682418273, "created": 1680682418273, "name": "IRS Basic API Calls", @@ -1884,8 +1932,8 @@ "_type": "request_group" }, { - "_id": "req_b5192703cc404e838b2e9f127674b6a9", - "parentId": "fld_b5db89748d844f92a8e2f577faa58f25", + "_id": "req_9b5111fd12ea47639c6621d23ddc528c", + "parentId": "fld_1ef343e864c14d44b2f8aa660aa7e5ac", "modified": 1705942154792, "created": 1680682418238, "url": "{{IRS_HOST}}/irs/jobs/{% response 'body', 'req_b02ac0bfc4704c83a5c5f8b24175d61a', 'b64::JC5pZA==::46b', 'never', 60 %} ", @@ -1915,6 +1963,7 @@ }, "metaSortKey": -1680682418261, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1924,8 +1973,8 @@ "_type": "request" }, { - "_id": "req_5a857366bb044122b7bebd64aa58c4f9", - "parentId": "fld_b5db89748d844f92a8e2f577faa58f25", + "_id": "req_0a7c66ccddb04f9caca830e197aecf64", + "parentId": "fld_1ef343e864c14d44b2f8aa660aa7e5ac", "modified": 1702991288793, "created": 1680682418257, "url": "{{IRS_HOST}}/irs/jobs", @@ -1949,6 +1998,7 @@ }, "metaSortKey": -1680682418257, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -1958,8 +2008,8 @@ "_type": "request" }, { - "_id": "req_08470d1692b24a5eb0be4f34cdac0088", - "parentId": "fld_b5db89748d844f92a8e2f577faa58f25", + "_id": "req_3d05fdc2d1e24d60960031834adf6753", + "parentId": "fld_1ef343e864c14d44b2f8aa660aa7e5ac", "modified": 1702991284435, "created": 1680682418247, "url": "{{IRS_HOST}}/irs/jobs", @@ -2003,6 +2053,7 @@ }, "metaSortKey": -1680682418247, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2012,8 +2063,8 @@ "_type": "request" }, { - "_id": "req_3dc3438d10ec4540ac5273a3e5a9b83e", - "parentId": "fld_b5db89748d844f92a8e2f577faa58f25", + "_id": "req_22194c017aac4261bb344662839de6f5", + "parentId": "fld_1ef343e864c14d44b2f8aa660aa7e5ac", "modified": 1703236659047, "created": 1690384427379, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", @@ -2043,6 +2094,7 @@ }, "metaSortKey": -1680682418238, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2052,8 +2104,8 @@ "_type": "request" }, { - "_id": "req_992a742bd2274479bddc627789274c45", - "parentId": "fld_b5db89748d844f92a8e2f577faa58f25", + "_id": "req_95ccc8f10f584a4aaf4d2a0b9c44441b", + "parentId": "fld_1ef343e864c14d44b2f8aa660aa7e5ac", "modified": 1702991276045, "created": 1680682418229, "url": "{{IRS_HOST}}/irs/jobs/{% prompt 'Job ID', '', '', '', false, true %}", @@ -2077,6 +2129,7 @@ }, "metaSortKey": -1680682418229, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2086,8 +2139,8 @@ "_type": "request" }, { - "_id": "req_e3487fdf1f844cc58ff1d5f13cefe638", - "parentId": "fld_b5db89748d844f92a8e2f577faa58f25", + "_id": "req_d677e6e5a736406ba05aea1a9a98595a", + "parentId": "fld_1ef343e864c14d44b2f8aa660aa7e5ac", "modified": 1702991272198, "created": 1682498338739, "url": "{{IRS_HOST}}/irs/aspectmodels", @@ -2111,6 +2164,7 @@ }, "metaSortKey": -1680682418179, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2120,8 +2174,8 @@ "_type": "request" }, { - "_id": "req_98b454b45f5c4cad933df80c0ca8ff5c", - "parentId": "fld_9dceb37ce1154d0095a71bdb36fe4a79", + "_id": "req_b1a92060c1bd47078fbee001952da6d8", + "parentId": "fld_187756e90d514741a65cb9617a3ea41a", "modified": 1705942066941, "created": 1680682418213, "url": "{{ _.SEMANTIC_HUB_URL }}/hub/api/v1/models", @@ -2153,6 +2207,7 @@ }, "metaSortKey": -1680682418213, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2162,8 +2217,8 @@ "_type": "request" }, { - "_id": "fld_9dceb37ce1154d0095a71bdb36fe4a79", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_187756e90d514741a65cb9617a3ea41a", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1680682418222, "created": 1680682418222, "name": "Semantics Hub", @@ -2174,8 +2229,8 @@ "_type": "request_group" }, { - "_id": "req_7c6af0f0d72e4c29a504e44aa4acf2dc", - "parentId": "fld_9dceb37ce1154d0095a71bdb36fe4a79", + "_id": "req_bf8fdccfac4141ea871c41d4f7403f5c", + "parentId": "fld_187756e90d514741a65cb9617a3ea41a", "modified": 1705942077015, "created": 1680682418204, "url": "{{ _.SEMANTIC_HUB_URL }}/hub/api/v1/models/urn%3Abamm%3Aio.catenax.serial_part_typization%3A1.0.0%23SerialPartTypization", @@ -2194,6 +2249,7 @@ }, "metaSortKey": -1680682418204, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2203,8 +2259,8 @@ "_type": "request" }, { - "_id": "req_f205a27f8073450cbde5e0398b48bde6", - "parentId": "fld_9dceb37ce1154d0095a71bdb36fe4a79", + "_id": "req_fb25cdceae984425b3aa867c3d5ea866", + "parentId": "fld_187756e90d514741a65cb9617a3ea41a", "modified": 1705942085733, "created": 1680682418192, "url": "{{ _.SEMANTIC_HUB_URL }}/hub/api/v1/models/urn%3Abamm%3Aio.catenax.serial_part_typization%3A1.0.0%23SerialPartTypization/json-schema", @@ -2223,6 +2279,7 @@ }, "metaSortKey": -1680682418192, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2232,8 +2289,8 @@ "_type": "request" }, { - "_id": "req_93454fd3c1084d399b3c2905cee98912", - "parentId": "fld_99d07b61e21942fab3999ca3411b6309", + "_id": "req_fad2ca6d902f401da947308e36bb22ff", + "parentId": "fld_26b4903278b54dc5a940fe28e4dd200a", "modified": 1705942100313, "created": 1680682418174, "url": "{{ _.BPDM_URL }}/v1/api/catena/business-partner/{% prompt 'BPN', '', '', '', false, true %}", @@ -2258,6 +2315,7 @@ }, "metaSortKey": -1680682418174, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2267,8 +2325,8 @@ "_type": "request" }, { - "_id": "fld_99d07b61e21942fab3999ca3411b6309", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_26b4903278b54dc5a940fe28e4dd200a", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1680682418184, "created": 1680682418184, "name": "Business partner data management", @@ -2279,8 +2337,8 @@ "_type": "request_group" }, { - "_id": "req_88256dff324a428fa91d114a88fcd3b4", - "parentId": "fld_97350fd0ea8c496caae4a2ed9eb74c5c", + "_id": "req_1b203a87420e42d5ba75c662ac8f49ee", + "parentId": "fld_048a4c04d1c4419683cb645279444127", "modified": 1702991347797, "created": 1680682418157, "url": "{{IRS_HOST}}/esr/esr-statistics/{% prompt 'globalAssetId', 'Provide global asset ID or use default', _.GLOBAL_ASSET_ID, '', false, true %}/{% prompt 'BOM Lifecycle', '', '', '', false, true %}/{% prompt 'Certificate', '', '', '', false, true %}/submodel", @@ -2304,6 +2362,7 @@ }, "metaSortKey": -1680682418158, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2313,8 +2372,8 @@ "_type": "request" }, { - "_id": "fld_97350fd0ea8c496caae4a2ed9eb74c5c", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_048a4c04d1c4419683cb645279444127", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1680682418167, "created": 1680682418167, "name": "ESR Spike", @@ -2325,8 +2384,8 @@ "_type": "request_group" }, { - "_id": "req_7872f416ad5349db9fbc8198a93438f0", - "parentId": "fld_a374a4f655934a47a494ab91e5ed46e3", + "_id": "req_32cc185810924d6cba6bb783422e919e", + "parentId": "fld_c645034b945b4aa5a34f15c60be2b27c", "modified": 1702991361578, "created": 1680682418143, "url": "{{IRS_HOST}}/ess/bpn/investigations", @@ -2353,6 +2412,7 @@ }, "metaSortKey": -1680682418143, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2362,8 +2422,8 @@ "_type": "request" }, { - "_id": "fld_a374a4f655934a47a494ab91e5ed46e3", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_c645034b945b4aa5a34f15c60be2b27c", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1680682418151, "created": 1680682418151, "name": "ESS Spike", @@ -2374,8 +2434,8 @@ "_type": "request_group" }, { - "_id": "req_88afb1555cd1418a9fed7524d2cfe286", - "parentId": "fld_a374a4f655934a47a494ab91e5ed46e3", + "_id": "req_818115f180424cc287bc730453851346", + "parentId": "fld_c645034b945b4aa5a34f15c60be2b27c", "modified": 1705942138125, "created": 1680682418134, "url": "{{IRS_HOST}}/ess/bpn/investigations/{% response 'body', 'req_ec674952c1114bce8fb71ea1ed6d9ef7', 'b64::JC5pZA==::46b', 'never', 60 %}", @@ -2399,6 +2459,7 @@ }, "metaSortKey": -1680682418138.5, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2408,8 +2469,8 @@ "_type": "request" }, { - "_id": "req_d2307da1ffaa4cee95303f073e8e8025", - "parentId": "fld_a374a4f655934a47a494ab91e5ed46e3", + "_id": "req_2a5fb997e87c439c8d2d75b1278bae3f", + "parentId": "fld_c645034b945b4aa5a34f15c60be2b27c", "modified": 1702991370481, "created": 1680682418134, "url": "{{IRS_HOST}}/ess/bpn/investigations/{% prompt 'Job ID', '', '', '', false, true %}", @@ -2433,6 +2494,7 @@ }, "metaSortKey": -1680682418134, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2442,8 +2504,8 @@ "_type": "request" }, { - "_id": "req_8890c0b2034c48769d06fdefdd8ad27d", - "parentId": "fld_960ae2d3cdb6470a84ae4836eb497c41", + "_id": "req_09e428687b484535af82e17dbf9a68bf", + "parentId": "fld_9b6334cef97a427195690af454455820", "modified": 1710076303275, "created": 1680682418118, "url": "{{IRS_HOST}}/irs/orders", @@ -2470,6 +2532,7 @@ }, "metaSortKey": -1680682418118, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2479,8 +2542,8 @@ "_type": "request" }, { - "_id": "fld_960ae2d3cdb6470a84ae4836eb497c41", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_9b6334cef97a427195690af454455820", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1680682418128, "created": 1680682418128, "name": "Batch Processing", @@ -2491,8 +2554,8 @@ "_type": "request_group" }, { - "_id": "req_899fdffe97094ec1b8360b09ff7f19e4", - "parentId": "fld_960ae2d3cdb6470a84ae4836eb497c41", + "_id": "req_cfe969099893477d95f7f654a588750a", + "parentId": "fld_9b6334cef97a427195690af454455820", "modified": 1702991390349, "created": 1696342619602, "url": "{{IRS_HOST}}/irs/ess/orders", @@ -2519,6 +2582,7 @@ }, "metaSortKey": -1680682418113.5, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2528,8 +2592,8 @@ "_type": "request" }, { - "_id": "req_500399b00f1c4beba49bb0d416693873", - "parentId": "fld_960ae2d3cdb6470a84ae4836eb497c41", + "_id": "req_9aca2c0b52564e64b266ecf2ef22d5e0", + "parentId": "fld_9b6334cef97a427195690af454455820", "modified": 1705006936944, "created": 1705006139836, "url": "{{IRS_HOST}}/irs/orders/{% prompt 'Order ID', '', '', '', false, true %}", @@ -2557,6 +2621,7 @@ }, "metaSortKey": -1680682418111.25, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2566,8 +2631,8 @@ "_type": "request" }, { - "_id": "req_e5c9453b6ca4432dbc41f0719ebc10ee", - "parentId": "fld_960ae2d3cdb6470a84ae4836eb497c41", + "_id": "req_55a45adbf0c9488ab2c912b92a49a103", + "parentId": "fld_9b6334cef97a427195690af454455820", "modified": 1702991398473, "created": 1680682418109, "url": "{{IRS_HOST}}/irs/orders/{% prompt 'Order ID', '', '', '', false, true %}", @@ -2591,6 +2656,7 @@ }, "metaSortKey": -1680682418109, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2600,8 +2666,8 @@ "_type": "request" }, { - "_id": "req_17ef91cf95974a88ab1ea3caac512f2e", - "parentId": "fld_960ae2d3cdb6470a84ae4836eb497c41", + "_id": "req_c2b63b7133fb460db0f6289b75733bc6", + "parentId": "fld_9b6334cef97a427195690af454455820", "modified": 1702991409664, "created": 1680682418099, "url": "{{IRS_HOST}}/irs/orders/{% prompt 'Order ID', '', '', '', false, true %}/batches/{% prompt 'Batch ID', '', '', '', false, true %}", @@ -2625,6 +2691,7 @@ }, "metaSortKey": -1680682418099, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2634,8 +2701,8 @@ "_type": "request" }, { - "_id": "req_4c99e0188bee4399b5b835473f5faf0c", - "parentId": "fld_b3e64009f73b4de58102f62dfddee9da", + "_id": "req_b74cc6344b7c4388b96656993b172d46", + "parentId": "fld_46a973a72ee54858be7b730077f4a0c6", "modified": 1690472186478, "created": 1678358655308, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/catalog/request", @@ -2662,6 +2729,7 @@ }, "metaSortKey": -1686195722939.1875, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2671,8 +2739,8 @@ "_type": "request" }, { - "_id": "fld_b3e64009f73b4de58102f62dfddee9da", - "parentId": "fld_64cab3b2c6fd483e87208b3ff434a03e", + "_id": "fld_46a973a72ee54858be7b730077f4a0c6", + "parentId": "fld_0b9d0531ef3e49efa333cd21a78f8c94", "modified": 1690362660167, "created": 1690362660167, "name": "Catalog", @@ -2683,8 +2751,8 @@ "_type": "request_group" }, { - "_id": "fld_64cab3b2c6fd483e87208b3ff434a03e", - "parentId": "fld_ddabc30cc3ff4b70a7401bcc81101f8f", + "_id": "fld_0b9d0531ef3e49efa333cd21a78f8c94", + "parentId": "fld_7b1b2f5f85934d3d8c82d7c7ce458380", "modified": 1690363778601, "created": 1675675609576, "name": "EDC-Requests", @@ -2695,8 +2763,8 @@ "_type": "request_group" }, { - "_id": "req_3c34357d0ea04bccb4b6213f492673cc", - "parentId": "fld_b3e64009f73b4de58102f62dfddee9da", + "_id": "req_73691ed276bd4771a5f9504075648a79", + "parentId": "fld_46a973a72ee54858be7b730077f4a0c6", "modified": 1691500654267, "created": 1685521485278, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/catalog/request", @@ -2723,6 +2791,7 @@ }, "metaSortKey": -1686195722889.1875, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2732,8 +2801,8 @@ "_type": "request" }, { - "_id": "req_36dd4e98c75b43dcac15252ad1b05469", - "parentId": "fld_b3e64009f73b4de58102f62dfddee9da", + "_id": "req_f063f58ce17c4c04bcd9e8feea08027c", + "parentId": "fld_46a973a72ee54858be7b730077f4a0c6", "modified": 1705940987109, "created": 1691654388376, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/catalog/request", @@ -2760,6 +2829,7 @@ }, "metaSortKey": -1686195722789.1875, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2769,8 +2839,8 @@ "_type": "request" }, { - "_id": "req_b1080c0e01e640afad06e99a8e9c6256", - "parentId": "fld_04c0afc0cea94d8e94c1539812d7f8f9", + "_id": "req_5eb26ad544f147b9a6f145a931e9f500", + "parentId": "fld_f1b0ee70bb2d45b7a32a643ab9a3d1d4", "modified": 1691578280640, "created": 1675675609557, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/contractnegotiations", @@ -2797,6 +2867,7 @@ }, "metaSortKey": -1684146511095, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2806,8 +2877,8 @@ "_type": "request" }, { - "_id": "fld_04c0afc0cea94d8e94c1539812d7f8f9", - "parentId": "fld_64cab3b2c6fd483e87208b3ff434a03e", + "_id": "fld_f1b0ee70bb2d45b7a32a643ab9a3d1d4", + "parentId": "fld_0b9d0531ef3e49efa333cd21a78f8c94", "modified": 1684146626847, "created": 1684146519491, "name": "Negotiation", @@ -2818,8 +2889,8 @@ "_type": "request_group" }, { - "_id": "req_56247bd1dd154ba5b925d7c2347adbb8", - "parentId": "fld_04c0afc0cea94d8e94c1539812d7f8f9", + "_id": "req_4fced7f1dd1c40b3b7ff236a89f1922e", + "parentId": "fld_f1b0ee70bb2d45b7a32a643ab9a3d1d4", "modified": 1690362123962, "created": 1675675609549, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/contractnegotiations/{% prompt 'id', '', '', '', false, true %}", @@ -2843,6 +2914,7 @@ }, "metaSortKey": -1684146511045, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2852,8 +2924,8 @@ "_type": "request" }, { - "_id": "req_61c7b18918854333bf64b6b2a7d30a0e", - "parentId": "fld_04c0afc0cea94d8e94c1539812d7f8f9", + "_id": "req_e62636f85f0d48d6bfb21a16602eacda", + "parentId": "fld_f1b0ee70bb2d45b7a32a643ab9a3d1d4", "modified": 1690362117725, "created": 1685444139708, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/contractnegotiations/{% prompt 'id', '', '', '', false, true %}/cancel", @@ -2872,6 +2944,7 @@ }, "metaSortKey": -1684146511020, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2881,8 +2954,8 @@ "_type": "request" }, { - "_id": "req_bb6f0b86fcdc45e190c8295415554a19", - "parentId": "fld_04c0afc0cea94d8e94c1539812d7f8f9", + "_id": "req_d0b90529e95545af8d9f6ef234d64670", + "parentId": "fld_f1b0ee70bb2d45b7a32a643ab9a3d1d4", "modified": 1690361721223, "created": 1681911985730, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/contractnegotiations/request", @@ -2909,6 +2982,7 @@ }, "metaSortKey": -1684146510995, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2918,8 +2992,8 @@ "_type": "request" }, { - "_id": "req_64bfc1e19445477497857f7e4573cf65", - "parentId": "fld_04c0afc0cea94d8e94c1539812d7f8f9", + "_id": "req_7ef28b43bb8444728eb0bedaf8af2111", + "parentId": "fld_f1b0ee70bb2d45b7a32a643ab9a3d1d4", "modified": 1691578311420, "created": 1675675609541, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/transferprocesses", @@ -2946,6 +3020,7 @@ }, "metaSortKey": -1684146510945, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2955,8 +3030,8 @@ "_type": "request" }, { - "_id": "req_fa5e5cf564a74c8c9a804b7b2b8963e2", - "parentId": "fld_04c0afc0cea94d8e94c1539812d7f8f9", + "_id": "req_04d6350cd308435589ff2d8fb6bb01dc", + "parentId": "fld_f1b0ee70bb2d45b7a32a643ab9a3d1d4", "modified": 1691503370103, "created": 1679993996270, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/transferprocesses/{% prompt 'id', '', '', '', false, true %}", @@ -2980,6 +3055,7 @@ }, "metaSortKey": -1684146510895, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -2989,8 +3065,8 @@ "_type": "request" }, { - "_id": "req_b8f90634a5944b348ea9494c7f17b6a8", - "parentId": "fld_04c0afc0cea94d8e94c1539812d7f8f9", + "_id": "req_4ec26c1537ed4c66ac8d6da53a506c71", + "parentId": "fld_f1b0ee70bb2d45b7a32a643ab9a3d1d4", "modified": 1690361795179, "created": 1675675609525, "url": "{{ _.CONSUMER_CONTROLPLANE }}/management/v2/transferprocesses/request", @@ -3017,6 +3093,7 @@ }, "metaSortKey": -1684146510845, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3026,8 +3103,8 @@ "_type": "request" }, { - "_id": "req_edcebfca1e5a40d6b7f2d99e74db43c3", - "parentId": "fld_04c0afc0cea94d8e94c1539812d7f8f9", + "_id": "req_0d7af3abbb194ed191e482b9b857070e", + "parentId": "fld_f1b0ee70bb2d45b7a32a643ab9a3d1d4", "modified": 1690361763512, "created": 1681910653593, "url": "{{CONSUMER_CONTROLPLANE}}/management/v2/contractagreements/request", @@ -3054,6 +3131,7 @@ }, "metaSortKey": -1684146510795, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3063,8 +3141,8 @@ "_type": "request" }, { - "_id": "req_317357c37d724aa2a25d2243ec444e31", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_633a776c22914478a6899c6f2f757d8e", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690362947546, "created": 1681907482278, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/assets", @@ -3091,6 +3169,7 @@ }, "metaSortKey": -1679911033461.75, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3100,8 +3179,8 @@ "_type": "request" }, { - "_id": "fld_8990e7651c904d5aa52f4c1c0981a60a", - "parentId": "fld_64cab3b2c6fd483e87208b3ff434a03e", + "_id": "fld_ca5fb2ce9c5a4640b827916773279500", + "parentId": "fld_0b9d0531ef3e49efa333cd21a78f8c94", "modified": 1705940929752, "created": 1684146457388, "name": "Provider", @@ -3112,8 +3191,8 @@ "_type": "request_group" }, { - "_id": "req_570c4a14d7db43a18d296cb11f1a1cee", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_52d9308387b04d60a06b43ee1c492478", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690362407763, "created": 1685444139630, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/assets/{% prompt 'id', '', '', '', false, true %}", @@ -3132,6 +3211,7 @@ }, "metaSortKey": -1679911033452.375, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3141,8 +3221,8 @@ "_type": "request" }, { - "_id": "req_c4df9110e0a345cc95afe85a30eac32b", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_1ae8b300301b406eb545df43a353fda9", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690362438115, "created": 1685444139625, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/assets/request", @@ -3169,6 +3249,7 @@ }, "metaSortKey": -1679911033447.6875, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3178,8 +3259,8 @@ "_type": "request" }, { - "_id": "req_0bc18af3230d4046b3e805ad47d7a86d", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_9eff358d42094196924ab55c23d7510d", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690362400081, "created": 1685444139636, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/assets/{% prompt 'id', '', '', '', false, true %}", @@ -3198,6 +3279,7 @@ }, "metaSortKey": -1679911033433.625, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3207,8 +3289,8 @@ "_type": "request" }, { - "_id": "req_bf080627d91545438cb460ad078fc01a", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_5fd712c0594d4b46a349bb56dae21809", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690362581978, "created": 1685444139641, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/policydefinitions", @@ -3235,6 +3317,7 @@ }, "metaSortKey": -1679911033403.9375, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3244,8 +3327,8 @@ "_type": "request" }, { - "_id": "req_06b8fed2305945deafe7dd173618e440", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_8b5ce92a1e96425e8353aba23643cd6b", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690362549290, "created": 1685444139647, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/policydefinitions/{% prompt 'id', '', '', '', false, true %}", @@ -3262,8 +3345,9 @@ "value": "{{ _.EDC_API_KEY }}", "addTo": "header" }, - "metaSortKey": -1679911033364.0937, + "metaSortKey": -1679911033364.0938, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3273,8 +3357,8 @@ "_type": "request" }, { - "_id": "req_ab6433968d444c4fb3980000d98c177e", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_274c9ac5236046919dd4bb71af15dd62", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690362591799, "created": 1685444139653, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/policydefinitions/request", @@ -3301,6 +3385,7 @@ }, "metaSortKey": -1679911033344.1719, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3310,8 +3395,8 @@ "_type": "request" }, { - "_id": "req_2d58d303468d4b42bc2943873356836c", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_e5e4eaf35c7545d7aaacf2388e2a42fc", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690362559324, "created": 1685444139659, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/policydefinitions/{% prompt 'id', '', '', '', false, true %}", @@ -3330,6 +3415,7 @@ }, "metaSortKey": -1679911033299.25, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3339,8 +3425,8 @@ "_type": "request" }, { - "_id": "req_c7751e7ea2a343a1bfdf5a7391d8b1e8", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_92959d74ff4f475b8e357e4958b1c457", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690363080444, "created": 1685444139665, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/contractdefinitions", @@ -3367,6 +3453,7 @@ }, "metaSortKey": -1679911033261.75, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3376,8 +3463,8 @@ "_type": "request" }, { - "_id": "req_4dbe36f239974916b8328f92025f7079", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_3de985b534fd4b23ad77e45e40126706", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690362691392, "created": 1685444139672, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/contractdefinitions/{% prompt 'id', '', '', '', false, true %}", @@ -3396,6 +3483,7 @@ }, "metaSortKey": -1679911033199.25, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3405,8 +3493,8 @@ "_type": "request" }, { - "_id": "req_b6e1779d1fd74edfa3e9861e5a2f85b4", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_730967ca2ad2470bab0d047f7491c460", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690363126919, "created": 1685444139678, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/contractdefinitions/request", @@ -3433,6 +3521,7 @@ }, "metaSortKey": -1679911033174.25, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3442,8 +3531,8 @@ "_type": "request" }, { - "_id": "req_0841b47dec974e11a2ec9db073fb6af0", - "parentId": "fld_8990e7651c904d5aa52f4c1c0981a60a", + "_id": "req_b200c2519b814e159bdde39fd86690a2", + "parentId": "fld_ca5fb2ce9c5a4640b827916773279500", "modified": 1690363136216, "created": 1685444139684, "url": "{{ _.PROVIDER_CONTROLPLANE_1 }}/management/v2/contractdefinitions/{% prompt 'id', '', '', '', false, true %}", @@ -3470,6 +3559,7 @@ }, "metaSortKey": -1679911033149.25, "isPrivate": false, + "pathParameters": [], "settingStoreCookies": true, "settingSendCookies": true, "settingDisableRenderRequestBody": false, @@ -3479,8 +3569,8 @@ "_type": "request" }, { - "_id": "env_d2b7eb1621841465ea24b73343568b286aa8ac9a", - "parentId": "wrk_565df8abe30f4da29d8bffcde97927d7", + "_id": "env_a3894a0a395c481d84f1126ba07bb47c", + "parentId": "wrk_d83bab75184e43adadd63001907af70d", "modified": 1680782486844, "created": 1680782486844, "name": "Base Environment", @@ -3492,8 +3582,8 @@ "_type": "environment" }, { - "_id": "jar_d2b7eb1621841465ea24b73343568b286aa8ac9a", - "parentId": "wrk_565df8abe30f4da29d8bffcde97927d7", + "_id": "jar_13d0657e04f54f6ab1e9903f108f0841", + "parentId": "wrk_d83bab75184e43adadd63001907af70d", "modified": 1709815397125, "created": 1680782486851, "name": "Default Jar", @@ -3530,26 +3620,6 @@ } ], "_type": "cookie_jar" - }, - { - "_id": "spc_22dfe33611af4731965cc2b08febcfdb", - "parentId": "wrk_565df8abe30f4da29d8bffcde97927d7", - "modified": 1680782484284, - "created": 1680782484284, - "fileName": "IRS", - "contents": "", - "contentType": "yaml", - "_type": "api_spec" - }, - { - "_id": "spc_3a573993100a40b3bc2b0a5bd8e5cc48", - "parentId": "wrk_565df8abe30f4da29d8bffcde97927d7", - "modified": 1681726479575, - "created": 1681726479575, - "fileName": "IRS", - "contents": "", - "contentType": "yaml", - "_type": "api_spec" } ] } \ No newline at end of file