Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/639 handle policy expiration #1041

Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
3b6739f
feature: #639 update irs-lib
ds-lcapellino Jun 11, 2024
30c995a
Merge branch 'main' into feature/639-handle-policy-expiration
ds-lcapellino Jun 12, 2024
88b7fd5
feature: #639 adapt integration tests
ds-lcapellino Jun 17, 2024
e292065
feature: #639 adapt integration tests
ds-lcapellino Jun 17, 2024
e1eb275
feature: #639 fix integration tests
ds-lcapellino Jun 18, 2024
81d839a
feature: #639 remove PolicyCheckerService.isValid() check
ds-lcapellino Jun 18, 2024
ef77bc0
Merge branch 'main' into feature/639-handle-policy-expiration
ds-lcapellino Jun 19, 2024
fc5f75b
Merge branch 'main' into feature/639-handle-policy-expiration
ds-lcapellino Jun 19, 2024
8efea7e
Merge branch 'main' into feature/639-handle-policy-expiration
ds-lcapellino Jun 27, 2024
32536c8
feature: #639 test
ds-lcapellino Jun 28, 2024
e86bfba
feature: #639 test
ds-lcapellino Jun 28, 2024
1059d7e
Merge branch 'main' into feature/639-handle-policy-expiration
ds-lcapellino Jun 28, 2024
19fc8e9
feature: #639 test
ds-lcapellino Jun 28, 2024
5568cbf
feature: #639 fix integration tests
ds-lcapellino Jun 28, 2024
fa8349b
feature: #639 don't show sql
ds-lcapellino Jun 28, 2024
bf9db9f
feature: #639 refactor
ds-lcapellino Jul 1, 2024
6540dd2
Merge branch 'main' into feature/639-handle-policy-expiration
ds-lcapellino Jul 1, 2024
8e229fd
feature: #639 update irs-client-lib.version
ds-lcapellino Jul 1, 2024
932eedc
Merge remote-tracking branch 'ds-lcapellino/feature/639-handle-policy…
ds-lcapellino Jul 1, 2024
1d7215e
feature: #639 update irs-client-lib.version
ds-lcapellino Jul 2, 2024
5659c08
feature: #639 fix integration tests
ds-lcapellino Jul 2, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ SPDX-License-Identifier: Apache-2.0
<junit-bom.version>5.10.2</junit-bom.version>
<awaitility.version>4.2.1</awaitility.version>
<!-- TODO https://github.com/eclipse-tractusx/traceability-foss/issues/978 update to the cx release version of irs lib IMPORTANT NO SNAPSHOT-->
<irs-client-lib.version>2.0.5</irs-client-lib.version>
<irs-client-lib.version>2.1.0-SNAPSHOT</irs-client-lib.version>
<json-schema-validator.version>5.4.0</json-schema-validator.version>
<!-- Sonar related properties -->
<sonar.java.coveragePlugin>jacoco</sonar.java.coveragePlugin>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.eclipse.tractusx.traceability.notification.domain.base.exception;

public class ContractNegotiationException extends RuntimeException {

public ContractNegotiationException(final String message, final Throwable exception) {
super(message, exception);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ private String negotiateContractAgreement(final String receiverEdcUrl, final Cat
.orElseThrow()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently the issue is that on the getCatalog call within the class NotificationsEdcFacade between line 157 and 164 we filter out all elements which are invalid.
Instead of filtering them out we need to catch them in a different exception.

e.g. PolicyExpiredException

This policy then will be cached again in EdcNotificationServiceImpl#handleSendingNotification, where we need to enrich the error message into the notification.

At the end we will have the info in the frontend that it was not possible to send it out due to policy issues.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PolicyCheckerService was adapted according to the requirements in issue #639. Please see eclipse-tractusx/item-relationship-service@6e8880b#diff-b63cc42711ba192e7a2ff818eaad3bf34984ebf1f30d53b2f5df2abfa468e623 fore reference.
This handles "NotificationsEdcFacade between line 157 and 164".

UsagePolicyExpiredException was also added: eclipse-tractusx/item-relationship-service@6e8880b#diff-3db264f1f24f39482d77c13221eaba18eba63de4620a7598ba4a1d404623e8ce
This is thrown, if the policy is expired during contract negotiation.

Copy link
Contributor

@ds-mwesener ds-mwesener Jun 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now the filter is gone. That is good. Still some things missing.

When the client library throws an exception within the contract negotiation (the point were you changed the exceptions) it will throw an exception and based on the logic of trace-x it will be catched and always mapped to the generic "NegotiationException" which is for our usage not enough.

We need to know if the policy was expired, or the policy constraints are incorrect or the policy is missing.

Therefore please catch those exceptions and pass them to the errorEnricher. To make sure we have that information in the frontend available.

If this is not manageable within the story - please recheck with product owner if new issue can be created for following up on that one.

.getContractAgreementId();
} catch (Exception e) {
throw new ContractNegotiationException("Failed to negotiate contract agreement. ", e);
throw new ContractNegotiationException("Failed to negotiate contract agreement: " + e.getMessage(), e);
}
}

Expand Down Expand Up @@ -155,14 +155,6 @@ private CatalogItem getCatalogItem(final NotificationMessage notification, final
.build())
.build()
).stream()
.filter(catalogItem -> {
log.info("-- catalog item check --");
log.info("Item {}: {}", catalogItem.getItemId(), catalogItem);
boolean isValid = policyCheckerService.isValid(catalogItem.getPolicy(), notification.getSentTo()
);
log.info("IsValid : {}", isValid);
return isValid;
})
.findFirst()
.orElseThrow();
} catch (Exception e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ void givenCorrectInvestigationMessageButSendRequestThrowsException_whenStartEdcT
when(notificationRepository.findByEdcNotificationId(any())).thenReturn(Optional.of(notification));
when(edcProperties.getIdsPath()).thenReturn(idsPath);
when(edcCatalogFacade.fetchCatalogItems(any())).thenReturn(List.of(catalogItem));
when(policyCheckerService.isValid(null, null)).thenReturn(true);
when(contractNegotiationService.negotiate(receiverEdcUrl + idsPath, catalogItem, null, null))
.thenReturn(NegotiationResponse.builder().contractAgreementId(agreementId).build());
when(endpointDataReference.getEndpoint()).thenReturn("endpoint");
Expand Down Expand Up @@ -122,7 +121,6 @@ void givenCorrectInvestigationMessageButNegotiateContractAgreementHasNoCatalogIt
final String idsPath = "/api/v1/dsp";
when(edcProperties.getIdsPath()).thenReturn(idsPath);
when(edcCatalogFacade.fetchCatalogItems(any())).thenReturn(List.of(catalogItem));
when(policyCheckerService.isValid(null, null)).thenReturn(true);
when(contractNegotiationService.negotiate(receiverEdcUrl + idsPath, catalogItem, null, null))
.thenReturn(null);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package org.eclipse.tractusx.traceability.integration;

import groovy.json.JsonBuilder;
import io.restassured.RestAssured;
import org.awaitility.Awaitility;
import org.eclipse.tractusx.traceability.integration.common.config.PostgreSQLConfig;
import org.eclipse.tractusx.traceability.integration.common.config.RestAssuredConfig;
Expand All @@ -33,6 +34,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.ContextConfiguration;

Expand All @@ -56,8 +58,12 @@ public class IntegrationTestSpecification {
@Autowired
DatabaseSupport databaseSupport;

@LocalServerPort
private Integer port;

@BeforeEach
void beforeEach() throws JoseException {
RestAssured.port = port;
oAuth2ApiSupport.oauth2ApiReturnsTechnicalUserToken();
oAuth2ApiSupport.oauth2ApiReturnsJwkCerts(oAuth2Support.jwk());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
/********************************************************************************
* Copyright (c) 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.traceability.integration.notification.investigation;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.restassured.http.ContentType;
import lombok.val;
import notification.request.NotificationSeverityRequest;
import notification.request.NotificationTypeRequest;
import notification.request.StartNotificationRequest;
import org.eclipse.tractusx.traceability.assets.domain.asbuilt.repository.AssetAsBuiltRepository;
import org.eclipse.tractusx.traceability.common.request.OwnPageable;
import org.eclipse.tractusx.traceability.common.request.PageableFilterRequest;
import org.eclipse.tractusx.traceability.common.request.SearchCriteriaRequestParam;
import org.eclipse.tractusx.traceability.integration.IntegrationTestSpecification;
import org.eclipse.tractusx.traceability.integration.common.support.AssetsSupport;
import org.eclipse.tractusx.traceability.integration.common.support.DiscoveryFinderSupport;
import org.eclipse.tractusx.traceability.integration.common.support.EdcSupport;
import org.eclipse.tractusx.traceability.integration.common.support.IrsApiSupport;
import org.eclipse.tractusx.traceability.integration.common.support.NotificationApiSupport;
import org.eclipse.tractusx.traceability.integration.common.support.NotificationMessageSupport;
import org.eclipse.tractusx.traceability.integration.common.support.NotificationSupport;
import org.eclipse.tractusx.traceability.integration.common.support.OAuth2ApiSupport;
import org.eclipse.tractusx.traceability.notification.domain.notification.service.NotificationReceiverService;
import org.hamcrest.Matchers;
import org.jose4j.lang.JoseException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.DynamicPropertyRegistry;
import org.springframework.test.context.DynamicPropertySource;

import java.util.Collections;
import java.util.List;

import static io.restassured.RestAssured.given;
import static org.eclipse.tractusx.traceability.common.security.JwtRole.SUPERVISOR;

public class InvestigationPolicyExpirationIT extends IntegrationTestSpecification {
@Autowired
NotificationReceiverService notificationReceiverService;
@Autowired
AssetsSupport assetsSupport;
@Autowired
NotificationMessageSupport notificationMessageSupport;
@Autowired
NotificationSupport notificationSupport;
@Autowired
AssetAsBuiltRepository assetAsBuiltRepository;
@Autowired
NotificationApiSupport notificationApiSupport;
@Autowired
EdcSupport edcSupport;

@Autowired
DiscoveryFinderSupport discoveryFinderSupport;

@Autowired
OAuth2ApiSupport oauth2ApiSupport;

@Autowired
IrsApiSupport irsApiSupport;

ObjectMapper objectMapper;


@DynamicPropertySource
static void dynamicProperties(DynamicPropertyRegistry registry) {
registry.add("traceability.validUntil", () -> "2020-07-04T16:01:05.309Z");
registry.add("server.port", () -> "9997");
registry.add("management.server.port", () -> "8083");
}

@BeforeEach
void setUp() {
objectMapper = new ObjectMapper();
}

@Test
void shouldNotApproveInvestigationStatus_whenPolicyIsExpired() throws JoseException, com.fasterxml.jackson.core.JsonProcessingException {
// given
irsApiSupport.irsApiReturnsPolicies();
discoveryFinderSupport.discoveryFinderWillReturnEndpointAddress();
discoveryFinderSupport.discoveryFinderWillReturnConnectorEndpoints();
oauth2ApiSupport.oauth2ApiReturnsDtrToken();
edcSupport.performSupportActionsForAsyncNotificationMessageExecutor();
List<String> partIds = List.of(
"urn:uuid:fe99da3d-b0de-4e80-81da-882aebcca978", // BPN: BPNL00000003AYRE
"urn:uuid:0ce83951-bc18-4e8f-892d-48bad4eb67ef" // BPN: BPNL00000003AXS3
);
String description = "at least 15 characters long investigation description";

assetsSupport.defaultAssetsStored();
val startInvestigationRequest = StartNotificationRequest.builder()
.affectedPartIds(partIds)
.description(description)
.severity(NotificationSeverityRequest.MINOR)
.type(NotificationTypeRequest.INVESTIGATION)
.receiverBpn("BPNL00000003CNKC")
.build();

// when
val investigationId = notificationApiSupport.createNotificationRequest_withDefaultAssetsStored(oAuth2Support.jwtAuthorization(SUPERVISOR), startInvestigationRequest, 201);


notificationSupport.assertInvestigationsSize(1);

given()
.contentType(ContentType.JSON)
.header(oAuth2Support.jwtAuthorization(SUPERVISOR))
.when()
.post("/api/notifications/{investigationId}/approve", investigationId)
.then()
.log().all()
.statusCode(503);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

503?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the current implementation in case something fails, when trying to send notifications. Maybe HTTP 500 suits better

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion a 400 would match better, since the policy is part of a notification negotiation.


// then
given()
.header(oAuth2Support.jwtAuthorization(SUPERVISOR))
.body(new PageableFilterRequest(new OwnPageable(0, 10, Collections.emptyList()), new SearchCriteriaRequestParam(List.of("channel,EQUAL,SENDER,AND"))))
.contentType(ContentType.JSON)
.when()
.post("/api/notifications/filter")
.then()
.log().all()
.statusCode(200)
.body("page", Matchers.is(0))
.body("pageSize", Matchers.is(10))
.body("content", Matchers.hasSize(1))
.body("content[0].sendTo", Matchers.is(Matchers.not(Matchers.blankOrNullString())))
.body("content[0].messages[0].errorMessage", Matchers.is("Failed to negotiate contract agreement: Consumption of asset '40276218-e31b-4c35-a7c8-017e8edb702e' is not permitted as the required catalog offer policies are expired."))
.body("content[0].messages[1].errorMessage", Matchers.is("Failed to negotiate contract agreement: Consumption of asset '40276218-e31b-4c35-a7c8-017e8edb702e' is not permitted as the required catalog offer policies are expired."));

notificationMessageSupport.assertMessageSize(2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -577,5 +577,4 @@ void shouldBeCreatedBySender() throws JoseException, JsonProcessingException {
.body("pageSize", Matchers.is(10))
.body("content", Matchers.hasSize(1));
}

}
Loading