Skip to content

Commit

Permalink
Merge branch 'main' into feat/568-remove-bpdm-lookup
Browse files Browse the repository at this point in the history
  • Loading branch information
dsmf authored May 2, 2024
2 parents 72f4971 + 83feca1 commit ec31e77
Show file tree
Hide file tree
Showing 11 changed files with 3,777 additions and 3,667 deletions.
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha

## [5.1.0] - 2024-04-30


### Changed

- Removed obsolete entries from acceptedPolicies configuration. #530
Expand Down Expand Up @@ -634,8 +635,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha
### Unresolved
- **Select Aspects you need** You are able to select the needed aspects for which you want to collect the correct endpoint information.

[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/5.1.0...HEAD
[5.1.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/5.0.0...5.1.0
[Unreleased]: https://github.com/eclipse-tractusx/item-relationship-service/compare/5.0.0...HEAD
[5.0.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.9.0...5.0.0
[4.9.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.8.0...4.9.0
[4.8.0]: https://github.com/eclipse-tractusx/item-relationship-service/compare/4.7.0...4.8.0
Expand Down
4 changes: 0 additions & 4 deletions charts/item-relationship-service/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [7.1.0] - 2024-04-30

### Fixed

- Fix for incomplete renaming of Helm chart (see #489)

### Changed

- Update IRS version to 5.1.0

## [7.0.1] - 2024-04-17

Expand Down
4 changes: 2 additions & 2 deletions charts/item-relationship-service/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@ type: application
# This is the chart version. This version number should be incremented each time you make changes
# to the chart and its templates, including the app version.
# Versions are expected to follow Semantic Versioning (https://semver.org/)
version: 7.1.0
version: 7.0.1
# This is the version number of the application being deployed. This version number should be
# incremented each time you make changes to the application. Versions are not expected to
# follow Semantic Versioning. They should reflect the version the application is using.
# It is recommended to use it with quotes.
appVersion: "5.1.0"
appVersion: "5.0.0"
dependencies:
- name: common
repository: https://charts.bitnami.com/bitnami
Expand Down
2 changes: 1 addition & 1 deletion docs/src/api/irs-api.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ info:
description: The API of the Item Relationship Service (IRS) for retrieving item
graphs along the value chain of CATENA-X partners.
title: IRS API
version: 5.1.0
version: 5.0.0
servers:
- url: http://localhost:8080
security:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ end note
"bomLifecycle": "asPlannned",
"collectAspects": true,
"depth": 1,
"direction": "upwards",
"direction": "upward",
"keys": [
{
"bpn": "BPNL0123456789XX",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public class IrsApplication {
/**
* The IRS API version.
*/
public static final String API_VERSION = "5.1.0";
public static final String API_VERSION = "5.0.0";

/**
* The URL prefix for IRS API URLs.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@
import static org.eclipse.tractusx.irs.util.TestMother.registerJobWithoutDepthAndAspect;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.Matchers.not;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
Expand Down Expand Up @@ -74,6 +75,7 @@
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.junit.jupiter.params.provider.ValueSource;
import org.mockito.BDDMockito;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
Expand All @@ -91,9 +93,13 @@

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
properties = { "digitalTwinRegistry.type=central" })
@ActiveProfiles(profiles = { "test", "local" })
@ActiveProfiles(profiles = { "test",
"local"
})
@Import(TestConfig.class)
@ExtendWith({ MockitoExtension.class, SpringExtension.class })
@ExtendWith({ MockitoExtension.class,
SpringExtension.class
})
class IrsControllerTest extends ControllerTest {

private final UUID jobId = UUID.randomUUID();
Expand Down Expand Up @@ -129,42 +135,91 @@ void initiateJobForGlobalAssetId() {
final UUID returnedJob = UUID.randomUUID();
Mockito.when(service.registerItemJob(any())).thenReturn(JobHandle.builder().id(returnedJob).build());

given().port(port).contentType(ContentType.JSON).body(registerJobWithoutDepthAndAspect()).post("/irs/jobs")
.then().statusCode(CREATED.value()).body("id", is(returnedJob.toString()));
given().port(port)
.contentType(ContentType.JSON)
.body(registerJobWithoutDepthAndAspect())
.post("/irs/jobs")
.then()
.statusCode(CREATED.value())
.body("id", is(returnedJob.toString()));
}

@Test
void shouldReturnUnauthorizedStatusWhenAuthenticationIsMissing() {
Mockito.when(authenticationService.getAuthentication(any(HttpServletRequest.class)))
.thenThrow(new BadCredentialsException("Wrong ApiKey"));

given().port(port).contentType(ContentType.JSON).body(registerJobWithoutDepthAndAspect()).post("/irs/jobs")
.then().statusCode(UNAUTHORIZED.value());
.thenThrow(new BadCredentialsException("Wrong ApiKey"));

given().port(port)
.contentType(ContentType.JSON)
.body(registerJobWithoutDepthAndAspect())
.post("/irs/jobs")
.then()
.statusCode(UNAUTHORIZED.value());
}

@Test
void shouldReturnForbiddenStatusWhenRequiredAuthorityIsMissing() {
authenticateWith("view_irs_wrong_authority");

given().port(port).contentType(ContentType.JSON).body(registerJobWithoutDepthAndAspect()).post("/irs/jobs")
.then().statusCode(FORBIDDEN.value());
given().port(port)
.contentType(ContentType.JSON)
.body(registerJobWithoutDepthAndAspect())
.post("/irs/jobs")
.then()
.statusCode(FORBIDDEN.value());
}

@ParameterizedTest
@MethodSource("corruptedJobs")
void shouldReturnBadRequestWhenRegisterJobBodyNotValid(final RegisterJob registerJob) {
authenticateWith(IrsRoles.VIEW_IRS);

given().port(port).contentType(ContentType.JSON).body(registerJob).post("/irs/jobs")
.then().statusCode(BAD_REQUEST.value());
given().port(port)
.contentType(ContentType.JSON)
.body(registerJob)
.post("/irs/jobs")
.then()
.statusCode(BAD_REQUEST.value());
}

@ParameterizedTest
@ValueSource(strings = { "upwards",
"downwards"
})
void shouldReturnBadRequestWhenRegisterJobWithInvalidDirection(String invalidDirection) {
authenticateWith(IrsRoles.VIEW_IRS);

given().port(port)
.contentType(ContentType.JSON)
.body("""
{
"key": {
"globalAssetId": "urn:uuid:c6d2d642-a055-4ddf-87e3-1a3b02c689e3",
"bpn": "BPNL00000000BJTL"
},
"direction": "<DIRECTION>",
"lookupBPNs": true
}
""".replace("<DIRECTION>", invalidDirection))
.post("/irs/jobs")
.then()
.statusCode(BAD_REQUEST.value())
.body("error", containsString("Unsupported direction"))
.body("error", containsString("Must be one of: upward, downward"))
// error message should not contain unvalidated user input for security reasons
.body("error", not(containsString(invalidDirection)));
}

@Test
void shouldReturnBadRequestWhenRegisterJobHasWrongCallbackUrl() {
authenticateWith(IrsRoles.VIEW_IRS);

given().port(port).contentType(ContentType.JSON).body(registerJobWithUrl("hhh://example.com")).post("/irs/jobs")
.then().statusCode(BAD_REQUEST.value());
given().port(port)
.contentType(ContentType.JSON)
.body(registerJobWithUrl("hhh://example.com"))
.post("/irs/jobs")
.then()
.statusCode(BAD_REQUEST.value());
}

@Test
Expand All @@ -174,8 +229,12 @@ void shouldAcceptCorrectCallbackUrl() {
final UUID returnedJob = UUID.randomUUID();
Mockito.when(service.registerItemJob(any())).thenReturn(JobHandle.builder().id(returnedJob).build());

given().port(port).contentType(ContentType.JSON).body(registerJobWithUrl("https://example.com")).post("/irs/jobs")
.then().statusCode(CREATED.value());
given().port(port)
.contentType(ContentType.JSON)
.body(registerJobWithUrl("https://example.com"))
.post("/irs/jobs")
.then()
.statusCode(CREATED.value());
}

@Test
Expand All @@ -191,18 +250,20 @@ void getJobsByState() throws Exception {

final String returnJobAsString = objectMapper.writeValueAsString(returnedJob);

Mockito.when(service.getJobsByState(any(), any())).thenReturn(
new PageResult(new PagedListHolder<>(List.of(returnedJob))));
Mockito.when(service.getJobsByState(any(), any()))
.thenReturn(new PageResult(new PagedListHolder<>(List.of(returnedJob))));

given().port(port).get("/irs/jobs")
.then().statusCode(OK.value())
given().port(port)
.get("/irs/jobs")
.then()
.statusCode(OK.value())
.body(containsString(returnJobAsString))
.body(containsString(returnedJob.getId().toString()))
.body(containsString(returnedJob.getState().toString()))
.body(containsString(returnedJob.getStartedOn().format(DateTimeFormatter.ofPattern(
"yyyy-MM-dd'T'HH:mm:ss.SSS"))))
.body(containsString(returnedJob.getCompletedOn().format(DateTimeFormatter.ofPattern(
"yyyy-MM-dd'T'HH:mm:ss.SSS"))));
.body(containsString(
returnedJob.getStartedOn().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"))))
.body(containsString(
returnedJob.getCompletedOn().format(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS"))));
}

@Test
Expand All @@ -212,19 +273,17 @@ void cancelJobById() {
final Job canceledJob = Job.builder().id(jobId).state(JobState.CANCELED).build();
Mockito.when(this.service.cancelJobById(jobId)).thenReturn(canceledJob);

given().port(port).put("/irs/jobs/" + jobId)
.then().statusCode(OK.value());
given().port(port).put("/irs/jobs/" + jobId).then().statusCode(OK.value());
}

@Test
void cancelJobById_throwEntityNotFoundException() {
authenticateWith(IrsRoles.VIEW_IRS);

BDDMockito.given(this.service.cancelJobById(jobId)).willThrow(
new ResponseStatusException(HttpStatus.NOT_FOUND, "No job exists with id " + jobId));
BDDMockito.given(this.service.cancelJobById(jobId))
.willThrow(new ResponseStatusException(HttpStatus.NOT_FOUND, "No job exists with id " + jobId));

given().port(port).put("/irs/jobs/" + jobId)
.then().statusCode(NOT_FOUND.value());
given().port(port).put("/irs/jobs/" + jobId).then().statusCode(NOT_FOUND.value());
}

@Test
Expand All @@ -233,8 +292,7 @@ void getJobWithMalformedIdShouldReturnBadRequest() {

final String jobIdMalformed = UUID.randomUUID() + "MALFORMED";

given().port(port).get("/irs/jobs/" + jobIdMalformed)
.then().statusCode(BAD_REQUEST.value());
given().port(port).get("/irs/jobs/" + jobIdMalformed).then().statusCode(BAD_REQUEST.value());
}

@Test
Expand All @@ -244,19 +302,23 @@ void shouldReturnBadRequestWhenRegisterJobWithMalformedAspectJson() {
Mockito.when(service.registerItemJob(any())).thenThrow(IllegalArgumentException.class);
final String requestBody = "{ \"aspects\": [ \"MALFORMED\" ], \"globalAssetId\": \"urn:uuid:8a61c8db-561e-4db0-84ec-a693fc5ffdf6\" }";

given().port(port).contentType(ContentType.JSON).body(requestBody).post("/irs/jobs")
.then().statusCode(BAD_REQUEST.value());
given().port(port)
.contentType(ContentType.JSON)
.body(requestBody)
.post("/irs/jobs")
.then()
.statusCode(BAD_REQUEST.value());
}

@Test
void shouldReturnBadRequestWhenCancelingAlreadyCompletedJob() {
authenticateWith(IrsRoles.VIEW_IRS);

BDDMockito.given(this.service.cancelJobById(jobId)).willThrow(new IllegalStateException(
format("Cannot transition from state %s to %s", JobState.COMPLETED, JobState.CANCELED)));
BDDMockito.given(this.service.cancelJobById(jobId))
.willThrow(new IllegalStateException(
format("Cannot transition from state %s to %s", JobState.COMPLETED, JobState.CANCELED)));

given().port(port).put("/irs/jobs/" + jobId)
.then().statusCode(BAD_REQUEST.value());
given().port(port).put("/irs/jobs/" + jobId).then().statusCode(BAD_REQUEST.value());
}

@Test
Expand All @@ -278,8 +340,14 @@ void shouldReturnAspectModels() throws Exception {

BDDMockito.given(this.semanticHubService.getAllAspectModels()).willReturn(aspectModels);

final AspectModels response = given().port(port).get("/irs/aspectmodels")
.then().statusCode(OK.value()).and().extract().response().as(AspectModels.class);
final AspectModels response = given().port(port)
.get("/irs/aspectmodels")
.then()
.statusCode(OK.value())
.and()
.extract()
.response()
.as(AspectModels.class);

assertEquals(aspectModels, response);
}
Expand All @@ -288,8 +356,7 @@ void shouldReturnAspectModels() throws Exception {
void shouldReturnForbiddenStatusForAspectModelsWhenRequiredAuthorityIsMissing() {
authenticateWith("view_irs_wrong_authority");

given().port(port).get("/irs/aspectmodels")
.then().statusCode(FORBIDDEN.value());
given().port(port).get("/irs/aspectmodels").then().statusCode(FORBIDDEN.value());
}

@Test
Expand All @@ -300,10 +367,16 @@ void shouldReturnPartialWhenJobCompleted() {

Mockito.when(this.service.getJobForJobId(eq(jobId), anyBoolean())).thenReturn(runningJob);

given().port(port).queryParam("returnUncompletedJob", true).get("/irs/jobs/" + jobId)
.then().statusCode(PARTIAL_CONTENT.value());
given().port(port).queryParam("returnUncompletedJob", false).get("/irs/jobs/" + jobId)
.then().statusCode(PARTIAL_CONTENT.value());
given().port(port)
.queryParam("returnUncompletedJob", true)
.get("/irs/jobs/" + jobId)
.then()
.statusCode(PARTIAL_CONTENT.value());
given().port(port)
.queryParam("returnUncompletedJob", false)
.get("/irs/jobs/" + jobId)
.then()
.statusCode(PARTIAL_CONTENT.value());
}

@Test
Expand All @@ -314,10 +387,16 @@ void shouldReturnOkWhenJobCompleted() {

Mockito.when(this.service.getJobForJobId(eq(jobId), anyBoolean())).thenReturn(completedJob);

given().port(port).queryParam("returnUncompletedJob", true).get("/irs/jobs/" + jobId)
.then().statusCode(OK.value());
given().port(port).queryParam("returnUncompletedJob", false).get("/irs/jobs/" + jobId)
.then().statusCode(OK.value());
given().port(port)
.queryParam("returnUncompletedJob", true)
.get("/irs/jobs/" + jobId)
.then()
.statusCode(OK.value());
given().port(port)
.queryParam("returnUncompletedJob", false)
.get("/irs/jobs/" + jobId)
.then()
.statusCode(OK.value());
}

}
Loading

0 comments on commit ec31e77

Please sign in to comment.