diff --git a/.github/workflows/cucumber-integration-test-DIL.yaml b/.github/workflows/cucumber-integration-test-DIL.yaml index b3469503b0..53a8375ab4 100644 --- a/.github/workflows/cucumber-integration-test-DIL.yaml +++ b/.github/workflows/cucumber-integration-test-DIL.yaml @@ -9,7 +9,32 @@ concurrency: cancel-in-progress: true jobs: + + check-config: + runs-on: ubuntu-latest + steps: + - name: Check if DIL_REGULAR_USER_API_KEY is defined + run: | + if [[ -z "${{ secrets.DIL_REGULAR_USER_API_KEY }}" ]]; then + echo "Error: Missing secret: Please configure DIL_REGULAR_USER_API_KEY." + exit 1 + fi + - name: Check if DIL_ADMIN_USER_API_KEY is defined + run: | + if [[ -z "${{ secrets.DIL_ADMIN_USER_API_KEY }}" ]]; then + echo "Error: Missing secret: Please configure DIL_ADMIN_USER_API_KEY." + exit 1 + fi + - name: Check if IRS_CUCUMBER_PUBLISH_TOKEN is defined + run: | + if [[ -z "${{ secrets.IRS_CUCUMBER_PUBLISH_TOKEN }}" ]]; then + echo "Error: Missing secret: Please configure IRS_CUCUMBER_PUBLISH_TOKEN." + exit 1 + fi + shell: bash + trigger-integration-test: + needs: check-config uses: ./.github/workflows/cucumber-integration-test.yaml secrets: regularUserApiKey: ${{ secrets.DIL_REGULAR_USER_API_KEY }} diff --git a/.github/workflows/cucumber-integration-test-INT.yaml b/.github/workflows/cucumber-integration-test-INT.yaml index 4e0ead9325..85ac6f3e04 100644 --- a/.github/workflows/cucumber-integration-test-INT.yaml +++ b/.github/workflows/cucumber-integration-test-INT.yaml @@ -9,7 +9,32 @@ concurrency: cancel-in-progress: true jobs: + + check-config: + runs-on: ubuntu-latest + steps: + - name: Check if INT_REGULAR_USER_API_KEY is defined + run: | + if [[ -z "${{ secrets.INT_REGULAR_USER_API_KEY }}" ]]; then + echo "Error: Missing secret: Please configure INT_REGULAR_USER_API_KEY." + exit 1 + fi + - name: Check if INT_ADMIN_USER_API_KEY is defined + run: | + if [[ -z "${{ secrets.INT_ADMIN_USER_API_KEY }}" ]]; then + echo "Error: Missing secret: Please configure INT_ADMIN_USER_API_KEY." + exit 1 + fi + - name: Check if IRS_CUCUMBER_PUBLISH_TOKEN is defined + run: | + if [[ -z "${{ secrets.IRS_CUCUMBER_PUBLISH_TOKEN }}" ]]; then + echo "Error: Missing secret: Please configure IRS_CUCUMBER_PUBLISH_TOKEN." + exit 1 + fi + shell: bash + trigger-integration-test: + needs: check-config uses: ./.github/workflows/cucumber-integration-test.yaml secrets: regularUserApiKey: ${{ secrets.INT_REGULAR_USER_API_KEY }} diff --git a/.github/workflows/cucumber-integration-test.yaml b/.github/workflows/cucumber-integration-test.yaml index 6e417a74fe..a54c48e908 100644 --- a/.github/workflows/cucumber-integration-test.yaml +++ b/.github/workflows/cucumber-integration-test.yaml @@ -15,6 +15,7 @@ on: type: string jobs: + build: runs-on: ubuntu-latest @@ -40,8 +41,8 @@ jobs: ADMIN_USER_API_KEY: ${{ secrets.adminUserApiKey }} ISSUE_FILTER: ${{ inputs.executionFilter }} CUCUMBER_PUBLISH_TOKEN: ${{ secrets.cucumberPublishToken }} - # workaround replacement since injecting the token via environment variable does not work run: | + # workaround replacement since injecting the token via environment variable does not work sed -i "s/CUCUMBER_TOKEN_IRS_PLACEHOLDER/${CUCUMBER_PUBLISH_TOKEN}/g" irs-cucumber-tests/src/test/java/org/eclipse/tractusx/irs/cucumber/RunCucumberTest.java mvn clean verify -P cucumber -Dgroups="$ISSUE_FILTER" -pl irs-cucumber-tests -am --batch-mode 2> irs-cucumber-tests/report-banner.txt diff --git a/.github/workflows/int-setup-testdata.yml b/.github/workflows/int-setup-testdata.yml deleted file mode 100644 index c97771b16d..0000000000 --- a/.github/workflows/int-setup-testdata.yml +++ /dev/null @@ -1,84 +0,0 @@ -name: Integration testdata setup - -on: - workflow_dispatch: - inputs: - testfilePath: - description: 'Path to Testdata file on GitHub' - required: true - type: string - submodelUrls: - description: 'Space-separated list of Submodel server URLs' - required: true - type: string - aasUrl: - description: 'Digital twin registry URL' - required: true - type: string - edcUrls: - description: 'Space-separated list of Provider control plane URLs' - required: true - type: string - edcApiKey: - description: 'API-Key for the provider control plane' - required: true - type: string - esrUrl: - description: 'ESR endpoint Url' - required: false - type: string - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: setup python - uses: actions/setup-python@v5 - with: - python-version: 3.8 #install the python needed - cache: 'pip' - - run: pip install -r local/testing/testdata/requirements.txt - - - name: Delete existing and setup new test data on provider EDC and Registry - if: ${{ github.event.inputs.esrUrl == '' }} - env: - TESTFILE_PATH: ${{ github.event.inputs.testfilePath }} - SUBMODEL_URLs: ${{ github.event.inputs.submodelUrls }} - AAS_URL: ${{ github.event.inputs.aasUrl }} - EDC_URLs: ${{ github.event.inputs.edcUrls }} - EDC_API_KEY: ${{ github.event.inputs.edcApiKey }} - run: | - python local/testing/testdata/reset-env.py \ - -a $AAS_URL \ - -edc $EDC_URLs \ - -k $EDC_API_KEY - python local/testing/testdata/transform-and-upload.py \ - -f $TESTFILE_PATH \ - -s $SUBMODEL_URLs \ - -a $AAS_URL \ - -edc $EDC_URLs \ - -k $EDC_API_KEY - - - name: Delete existing and setup new test data on provider EDC and Registry - if: ${{ github.event.inputs.esrUrl != '' }} - env: - TESTFILE_PATH: ${{ github.event.inputs.testfilePath }} - SUBMODEL_URLs: ${{ github.event.inputs.submodelUrls }} - AAS_URL: ${{ github.event.inputs.aasUrl }} - EDC_URLs: ${{ github.event.inputs.edcUrls }} - EDC_API_KEY: ${{ github.event.inputs.edcApiKey }} - ESR_URL: ${{ github.event.inputs.esrUrl }} - run: | - python local/testing/testdata/reset-env.py \ - -a $AAS_URL \ - -edc $EDC_URLs \ - -k $EDC_API_KEY - python local/testing/testdata/transform-and-upload.py \ - -f $TESTFILE_PATH \ - -s $SUBMODEL_URLs \ - -a $AAS_URL \ - -edc $EDC_URLs \ - -k $EDC_API_KEY - -e $ESR_URL diff --git a/.github/workflows/integration-test-DEV.yaml b/.github/workflows/integration-test-DEV.yaml index d2498bb84d..f314ec76b1 100644 --- a/.github/workflows/integration-test-DEV.yaml +++ b/.github/workflows/integration-test-DEV.yaml @@ -2,6 +2,11 @@ name: IRS DEV Cucumber Integration test execution on: workflow_dispatch: # Trigger manually + inputs: + executionFilter: + description: 'Execution filter' + required: false + default: '!Ignore & !INACTIVE & INTEGRATION_TEST & DEV' push: branches: - 'main' @@ -19,12 +24,40 @@ concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true + + + jobs: + + check-config: + runs-on: ubuntu-latest + steps: + - name: Check if DEV_REGULAR_USER_API_KEY is defined + run: | + if [[ -z "${{ secrets.DEV_REGULAR_USER_API_KEY }}" ]]; then + echo "Error: Missing secret: Please configure DEV_REGULAR_USER_API_KEY." + exit 1 + fi + - name: Check if DEV_ADMIN_USER_API_KEY is defined + run: | + if [[ -z "${{ secrets.DEV_ADMIN_USER_API_KEY }}" ]]; then + echo "Error: Missing secret: Please configure DEV_ADMIN_USER_API_KEY." + exit 1 + fi + - name: Check if IRS_CUCUMBER_PUBLISH_TOKEN is defined + run: | + if [[ -z "${{ secrets.IRS_CUCUMBER_PUBLISH_TOKEN }}" ]]; then + echo "Error: Missing secret: Please configure IRS_CUCUMBER_PUBLISH_TOKEN." + exit 1 + fi + shell: bash + trigger-integration-test: + needs: check-config uses: ./.github/workflows/cucumber-integration-test.yaml secrets: regularUserApiKey: ${{ secrets.DEV_REGULAR_USER_API_KEY }} adminUserApiKey: ${{ secrets.DEV_ADMIN_USER_API_KEY }} cucumberPublishToken: ${{ secrets.IRS_CUCUMBER_PUBLISH_TOKEN }} with: - executionFilter: "!Ignore & !INACTIVE & INTEGRATION_TEST & DEV" + executionFilter: ${{ github.event.inputs.executionFilter || '!Ignore & !INACTIVE & INTEGRATION_TEST & DEV' }} diff --git a/.github/workflows/irs-build.yml b/.github/workflows/irs-build.yml index 21cdfb8d3b..e04ffd449e 100644 --- a/.github/workflows/irs-build.yml +++ b/.github/workflows/irs-build.yml @@ -12,6 +12,7 @@ on: - '!docs/src/api/**' - 'local/**' - 'CHANGELOG.md' + push: branches: - main @@ -43,11 +44,24 @@ jobs: run: | mvn clean verify --batch-mode + check_sonar_configured: + runs-on: ubuntu-latest + steps: + - name: check_sonar_configured + run: | + echo "Checking if sonar is configured: ${{ env.SONAR_CONFIGURED }}" + env: + SONAR_CONFIGURED: ${{ secrets.SONAR_TOKEN != '' && secrets.SONAR_PROJECT_KEY != '' && secrets.SONAR_ORGANIZATION != '' }} + outputs: + sonar_configured: ${{ env.SONAR_CONFIGURED }} + analyze_with_Sonar: + needs: [check_sonar_configured] # No need to run if we cannot use the sonar token if: >- - (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && - github.actor != 'dependabot[bot]' + needs.check_sonar_configured.outputs.sonar_configured == 'true' + && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) + && github.actor != 'dependabot[bot]' runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -85,91 +99,63 @@ jobs: -Dcheckstyle.skip -Dpmd.skip=true build_images: - strategy: - matrix: - image: - - irs-api + env: + IMAGE_NAMESPACE: tractusx + IMAGE_NAME: irs-api + TARGET_PLATFORMS: "linux/amd64" # add 'linux/arm64' once the upgrade to JDK 21 is done runs-on: ubuntu-latest outputs: image-tag: ${{ steps.version.outputs.image_tag }} steps: - uses: actions/checkout@v4 - - name: Build image to make sure Dockerfile is valid - run: | - # RUN --mount=type=cache is used in the IRS Dockerfile to cache directories for maven. - # And the --mount option requires BuildKit. - DOCKER_BUILDKIT=1 docker build --build-arg BUILD_TARGET=${{ matrix.image }} --target ${{ matrix.image }} -t ${{ matrix.image }}:latest . + # Needed to create multi-platform image + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 - - name: Set image version - id: version - run: | - # Strip git ref prefix from version - VERSION=$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\),\1,') - # Strip "v" prefix from tag name - [[ "${{ github.ref }}" == "refs/tags/"* ]] && VERSION=$(echo $VERSION | sed -e 's/^v//') - # Support PR ref versions - [[ "${{ github.ref }}" == "refs/pull/"* ]] && VERSION=PR-$(echo "${{ github.ref }}" | sed -e 's,.*/\(.*\)/merge,\1,') - # Use Docker `latest` tag convention - [ "$VERSION" == "main" ] && VERSION=latest - echo VERSION=$VERSION - echo "::set-output name=image_tag::$VERSION" - - - name: Log in to registry - env: - DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }} - if: >- - env.DOCKER_HUB_USER == '' && - (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && - github.actor != 'dependabot[bot]' - # This is where you will update the PAT to GITHUB_TOKEN - run: echo "${{ secrets.GITHUB_TOKEN }}" | docker login ghcr.io -u ${{ github.actor }} --password-stdin - - - name: Push image (GHCR) - env: - DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }} - if: >- - env.DOCKER_HUB_USER == '' && - (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository) && - github.actor != 'dependabot[bot]' - run: | - IMAGE_ID=ghcr.io/${{ github.repository_owner }}/${{ matrix.image }} - # Change all uppercase to lowercase - IMAGE_ID=$(echo $IMAGE_ID | tr '[A-Z]' '[a-z]') - echo IMAGE_ID=$IMAGE_ID - - docker tag ${{ matrix.image }} $IMAGE_ID:${{ steps.version.outputs.image_tag }} - docker push $IMAGE_ID:${{ steps.version.outputs.image_tag }} - - docker tag ${{ matrix.image }} $IMAGE_ID:$GITHUB_SHA - docker push $IMAGE_ID:$GITHUB_SHA - - - name: Login to Docker Hub - env: - DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }} - if: env.DOCKER_HUB_USER != '' + # Needed to create multi-platform image + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + + # Create SemVer or ref tags dependent of trigger event + - name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: | + ${{ env.IMAGE_NAMESPACE }}/${{ env.IMAGE_NAME }} + # Automatically prepare image tags; See action docs for more examples. + # semver patter will generate tags like these for example :1 :1.2 :1.2.3 + tags: | + type=ref,event=branch + type=ref,event=pr + type=sha,prefix=,format=long + type=semver,pattern={{version}} + type=semver,pattern={{major}} + type=semver,pattern={{major}}.{{minor}} + + - name: DockerHub login + if: github.event_name != 'pull_request' uses: docker/login-action@v3 with: + # Use existing DockerHub credentials present as secrets username: ${{ secrets.DOCKER_HUB_USER }} password: ${{ secrets.DOCKER_HUB_TOKEN }} - - name: Push image (DockerHub) - env: - DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }} - IMAGE_NAMESPACE: tractusx - IMAGE_NAME: irs-api - if: env.DOCKER_HUB_USER != '' - run: | - docker tag ${{ matrix.image }} ${{ env.IMAGE_NAMESPACE }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.image_tag }} - docker push ${{ env.IMAGE_NAMESPACE }}/${{ env.IMAGE_NAME }}:${{ steps.version.outputs.image_tag }} + - name: Build and push + uses: docker/build-push-action@v6 + with: + context: . + # Needed to create multi-platform image + platforms: ${{ env.TARGET_PLATFORMS }} + # Build image for verification purposes on every trigger event. Only push if event is not a PR + push: ${{ github.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} # https://github.com/peter-evans/dockerhub-description - name: Update Docker Hub description - env: - DOCKER_HUB_USER: ${{ secrets.DOCKER_HUB_USER }} - IMAGE_NAMESPACE: tractusx - IMAGE_NAME: irs-api - if: env.DOCKER_HUB_USER != '' && github.event_name != 'pull_request' + if: github.event_name != 'pull_request' uses: peter-evans/dockerhub-description@v4 with: username: ${{ secrets.DOCKER_HUB_USER }} @@ -178,8 +164,7 @@ jobs: readme-filepath: ./DOCKER_NOTICE.md trigger-trivy-image-scan: - if: >- - github.event_name != 'pull_request' + if: github.event_name != 'pull_request' needs: - build_images uses: ./.github/workflows/trivy-docker-hub-scan.yml diff --git a/.github/workflows/irs-load-test.yaml b/.github/workflows/irs-load-test.yaml index 25fa75c633..8c3166c594 100644 --- a/.github/workflows/irs-load-test.yaml +++ b/.github/workflows/irs-load-test.yaml @@ -19,7 +19,32 @@ on: required: false jobs: + + check-config: + runs-on: ubuntu-latest + steps: + - name: Check if OAUTH2_CLIENT_TOKEN_URI is defined + run: | + if [[ -z "${{ secrets.OAUTH2_CLIENT_TOKEN_URI }}" ]]; then + echo "Error: Missing secret: Please configure OAUTH2_CLIENT_TOKEN_URI." + exit 1 + fi + - name: Check if OAUTH2_CLIENT_SECRET is defined + run: | + if [[ -z "${{ secrets.OAUTH2_CLIENT_SECRET }}" ]]; then + echo "Error: Missing secret: Please configure OAUTH2_CLIENT_SECRET." + exit 1 + fi + - name: Check if OAUTH2_CLIENT_ID is defined + run: | + if [[ -z "${{ secrets.OAUTH2_CLIENT_ID }}" ]]; then + echo "Error: Missing secret: Please configure OAUTH2_CLIENT_ID." + exit 1 + fi + shell: bash + gatling-test: + needs: check-config runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/owasp.yml b/.github/workflows/owasp.yml index 7fc31acbcf..6fb83925ab 100644 --- a/.github/workflows/owasp.yml +++ b/.github/workflows/owasp.yml @@ -1,6 +1,8 @@ name: "OWASP dependency scanner" on: + workflow_dispatch: # Additionally allow to trigger manually + push: branches: main paths-ignore: diff --git a/.github/workflows/int-test-automation.yml b/.github/workflows/smoketest.yml similarity index 97% rename from .github/workflows/int-test-automation.yml rename to .github/workflows/smoketest.yml index d9ac02bdff..e648281acb 100644 --- a/.github/workflows/int-test-automation.yml +++ b/.github/workflows/smoketest.yml @@ -1,4 +1,4 @@ -name: IRS integration tests +name: IRS smoke tests on: workflow_dispatch: diff --git a/CHANGELOG.md b/CHANGELOG.md index 048f414a85..aadcf2980f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,11 +8,22 @@ _**For better traceability add the corresponding GitHub issue number in each cha ## [Unreleased] +### Added + +### Fixed + +- Access and Usage Policy Validation flow correction. #757 + +### Changed + +- Replaced technical error message when trying to delete the configured default policy with a user-friendly message. + + ## [5.2.0] - 2024-07-03 ### Fixed -- Fixed ESS Investigation job processing not starting #579 +- Fixed ESS Investigation job processing not starting. #579 - Policy store API returns 'rightOperand' without 'odrl:' prefix now (see traceability-foss/issues/970). - Fixed trivy workflow to fail only on CRITICAL, HIGH (according to https://github.com/eclipse-tractusx/eclipse-tractusx.github.io/pull/949/files). @@ -58,6 +69,11 @@ _**For better traceability add the corresponding GitHub issue number in each cha or `edc:type`: `data.core.digitalTwinRegistry`. #616 - Fix missing and malformed properties for EDC policy transformation. #648 +## Fixed + +- Propagates exceptions to have more detail in tombstone. #538 + + ## [5.1.2] - 2024-05-13 ### Fixed @@ -98,11 +114,11 @@ _**For better traceability add the corresponding GitHub issue number in each cha ## [5.0.0] - 2024-04-16 ### Added - - SAMM models can now be added locally #488 - Introduced new Cucumber Tests to cover Industry Core 2.0.0 compatibility #488 + ### Fixed - Policy store API fixes. #199, #505 @@ -118,6 +134,7 @@ _**For better traceability add the corresponding GitHub issue number in each cha - RestClientExceptions are handled correctly in BpdmFacade now. #405 - Fixed Base64 encoding and decoding for locally provided Semantic Models #488 + ## [4.9.0] - 2024-04-03 ### Added - Extended EdcPolicyDefinitionService to check if a policy in the edc exists diff --git a/DEPENDENCIES b/DEPENDENCIES index 409e609d91..79befad7bb 100644 --- a/DEPENDENCIES +++ b/DEPENDENCIES @@ -134,33 +134,33 @@ maven/mavencentral/io.github.resilience4j/resilience4j-retry/2.1.0, Apache-2.0, maven/mavencentral/io.github.resilience4j/resilience4j-spring-boot3/2.1.0, Apache-2.0, approved, #10913 maven/mavencentral/io.github.resilience4j/resilience4j-spring6/2.1.0, Apache-2.0, approved, #10915 maven/mavencentral/io.github.resilience4j/resilience4j-timelimiter/2.1.0, Apache-2.0, approved, #10166 -maven/mavencentral/io.micrometer/micrometer-commons/1.11.11, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #9243 -maven/mavencentral/io.micrometer/micrometer-core/1.11.11, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #9238 -maven/mavencentral/io.micrometer/micrometer-observation/1.11.11, Apache-2.0, approved, #9242 +maven/mavencentral/io.micrometer/micrometer-commons/1.11.12, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #9243 +maven/mavencentral/io.micrometer/micrometer-core/1.11.12, Apache-2.0 AND (Apache-2.0 AND MIT), approved, #9238 +maven/mavencentral/io.micrometer/micrometer-observation/1.11.12, Apache-2.0, approved, #9242 maven/mavencentral/io.micrometer/micrometer-registry-prometheus/1.11.4, Apache-2.0, approved, #9805 maven/mavencentral/io.minio/minio/8.5.9, Apache-2.0, approved, #9097 maven/mavencentral/io.netty.incubator/netty-incubator-transport-classes-io_uring/0.0.21.Final, Apache-2.0, approved, #9622 maven/mavencentral/io.netty.incubator/netty-incubator-transport-native-io_uring/0.0.21.Final, GPL-2.0-only WITH Linux-syscall-note OR MIT AND Apache-2.0 AND MIT, approved, #9649 -maven/mavencentral/io.netty/netty-buffer/4.1.109.Final, Apache-2.0, approved, CQ21842 -maven/mavencentral/io.netty/netty-codec-dns/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-codec-http/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-codec-http2/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-codec-mqtt/4.1.109.Final, Apache-2.0 OR LicenseRef-Public-Domain OR BSD-2-Clause OR MIT, approved, CQ15280 -maven/mavencentral/io.netty/netty-codec-socks/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-codec/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-common/4.1.109.Final, Apache-2.0 AND MIT AND CC0-1.0, approved, CQ21843 -maven/mavencentral/io.netty/netty-handler-proxy/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-handler/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-resolver-dns-classes-macos/4.1.109.Final, Apache-2.0, approved, #6367 -maven/mavencentral/io.netty/netty-resolver-dns-native-macos/4.1.109.Final, Apache-2.0, approved, #7004 -maven/mavencentral/io.netty/netty-resolver-dns/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-resolver/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-buffer/4.1.110.Final, Apache-2.0, approved, CQ21842 +maven/mavencentral/io.netty/netty-codec-dns/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-codec-http/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-codec-http2/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-codec-mqtt/4.1.110.Final, Apache-2.0 OR LicenseRef-Public-Domain OR BSD-2-Clause OR MIT, approved, CQ15280 +maven/mavencentral/io.netty/netty-codec-socks/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-codec/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-common/4.1.110.Final, Apache-2.0 AND MIT AND CC0-1.0, approved, CQ21843 +maven/mavencentral/io.netty/netty-handler-proxy/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-handler/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-resolver-dns-classes-macos/4.1.110.Final, Apache-2.0, approved, #6367 +maven/mavencentral/io.netty/netty-resolver-dns-native-macos/4.1.110.Final, Apache-2.0, approved, #7004 +maven/mavencentral/io.netty/netty-resolver-dns/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-resolver/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 maven/mavencentral/io.netty/netty-tcnative-boringssl-static/2.0.65.Final, Apache-2.0 OR LicenseRef-Public-Domain OR BSD-2-Clause OR MIT, approved, CQ15280 maven/mavencentral/io.netty/netty-tcnative-classes/2.0.65.Final, Apache-2.0, approved, clearlydefined -maven/mavencentral/io.netty/netty-transport-classes-epoll/4.1.109.Final, Apache-2.0, approved, #6366 -maven/mavencentral/io.netty/netty-transport-native-epoll/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-transport-native-unix-common/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 -maven/mavencentral/io.netty/netty-transport/4.1.109.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-transport-classes-epoll/4.1.110.Final, Apache-2.0, approved, #6366 +maven/mavencentral/io.netty/netty-transport-native-epoll/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-transport-native-unix-common/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 +maven/mavencentral/io.netty/netty-transport/4.1.110.Final, Apache-2.0 AND BSD-3-Clause AND MIT, approved, CQ20926 maven/mavencentral/io.opentelemetry/opentelemetry-api/1.25.0, Apache-2.0, approved, clearlydefined maven/mavencentral/io.opentelemetry/opentelemetry-api/1.32.0, Apache-2.0, approved, #11682 maven/mavencentral/io.opentelemetry/opentelemetry-context/1.25.0, Apache-2.0, approved, clearlydefined @@ -192,10 +192,10 @@ maven/mavencentral/jakarta.ws.rs/jakarta.ws.rs-api/3.1.0, EPL-2.0 OR GPL-2.0-onl maven/mavencentral/jakarta.xml.bind/jakarta.xml.bind-api/4.0.2, BSD-3-Clause, approved, ee4j.jaxb maven/mavencentral/javax.jms/javax.jms-api/2.0.1, CDDL-1.1 OR GPL-2.0 WITH Classpath-exception-2.0, approved, #1516 maven/mavencentral/junit/junit/4.13.2, EPL-2.0, approved, CQ23636 -maven/mavencentral/net.bytebuddy/byte-buddy-agent/1.14.13, Apache-2.0, approved, #7164 +maven/mavencentral/net.bytebuddy/byte-buddy-agent/1.14.16, Apache-2.0, approved, #7164 maven/mavencentral/net.bytebuddy/byte-buddy-agent/1.14.4, Apache-2.0, approved, #7164 maven/mavencentral/net.bytebuddy/byte-buddy/1.12.21, Apache-2.0 AND BSD-3-Clause, approved, #1811 -maven/mavencentral/net.bytebuddy/byte-buddy/1.14.13, Apache-2.0 AND BSD-3-Clause, approved, #7163 +maven/mavencentral/net.bytebuddy/byte-buddy/1.14.16, Apache-2.0 AND BSD-3-Clause, approved, #7163 maven/mavencentral/net.datafaker/datafaker/1.9.0, Apache-2.0, approved, #8797 maven/mavencentral/net.debasishg/redisclient_2.13/3.42, Apache-2.0, approved, clearlydefined maven/mavencentral/net.java.dev.jna/jna/5.12.1, Apache-2.0 OR LGPL-2.1-or-later, approved, #3217 @@ -225,9 +225,10 @@ maven/mavencentral/org.apache.logging.log4j/log4j-core/2.20.0, Apache-2.0 AND (A maven/mavencentral/org.apache.logging.log4j/log4j-jul/2.20.0, Apache-2.0, approved, clearlydefined maven/mavencentral/org.apache.logging.log4j/log4j-slf4j2-impl/2.20.0, Apache-2.0, approved, #8801 maven/mavencentral/org.apache.logging.log4j/log4j-to-slf4j/2.20.0, Apache-2.0, approved, #8799 -maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-core/10.1.20, Apache-2.0 AND (EPL-2.0 OR (GPL-2.0 WITH Classpath-exception-2.0)) AND CDDL-1.0 AND (CDDL-1.1 OR (GPL-2.0-only WITH Classpath-exception-2.0)) AND EPL-2.0, approved, #15195 -maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-el/10.1.20, Apache-2.0, approved, #6997 -maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-websocket/10.1.20, Apache-2.0, approved, #7920 +maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-core/10.1.24, Apache-2.0 AND (EPL-2.0 OR (GPL-2.0 WITH Classpath-exception-2.0)) AND CDDL-1.0 AND (CDDL-1.1 OR (GPL-2.0-only WITH Classpath-exception-2.0)) AND EPL-2.0, approved, #15195 +maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-core/10.1.25, Apache-2.0 AND (EPL-2.0 OR (GPL-2.0 WITH Classpath-exception-2.0)) AND CDDL-1.0 AND (CDDL-1.1 OR (GPL-2.0-only WITH Classpath-exception-2.0)) AND EPL-2.0, approved, #15195 +maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-el/10.1.24, Apache-2.0, approved, #6997 +maven/mavencentral/org.apache.tomcat.embed/tomcat-embed-websocket/10.1.24, Apache-2.0, approved, #7920 maven/mavencentral/org.apiguardian/apiguardian-api/1.1.2, Apache-2.0, approved, clearlydefined maven/mavencentral/org.aspectj/aspectjweaver/1.9.22, Apache-2.0 AND BSD-3-Clause AND EPL-1.0 AND BSD-3-Clause AND Apache-1.1, approved, #15252 maven/mavencentral/org.assertj/assertj-core/3.24.2, Apache-2.0, approved, #6161 @@ -305,12 +306,12 @@ maven/mavencentral/org.eclipse.tractusx.edc/core-spi/0.6.0, Apache-2.0, approved maven/mavencentral/org.eclipse.tractusx.edc/edr-api/0.6.0, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.edc/edr-spi/0.6.0, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.irs/irs-api/0.0.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx -maven/mavencentral/org.eclipse.tractusx.irs/irs-common/2.1.4, Apache-2.0, approved, automotive.tractusx -maven/mavencentral/org.eclipse.tractusx.irs/irs-edc-client/2.1.4, Apache-2.0, approved, automotive.tractusx -maven/mavencentral/org.eclipse.tractusx.irs/irs-models/2.1.4, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.irs/irs-common/2.1.5-SNAPSHOT, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.irs/irs-edc-client/2.1.5-SNAPSHOT, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.irs/irs-models/2.1.5-SNAPSHOT, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.eclipse.tractusx.irs/irs-policy-store/0.0.2-SNAPSHOT, Apache-2.0, approved, automotive.tractusx -maven/mavencentral/org.eclipse.tractusx.irs/irs-registry-client/2.1.4, Apache-2.0, approved, automotive.tractusx -maven/mavencentral/org.eclipse.tractusx.irs/irs-testing/2.1.4, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.irs/irs-registry-client/2.1.5-SNAPSHOT, Apache-2.0, approved, automotive.tractusx +maven/mavencentral/org.eclipse.tractusx.irs/irs-testing/2.1.5-SNAPSHOT, Apache-2.0, approved, automotive.tractusx maven/mavencentral/org.glassfish/jakarta.json/2.0.1, EPL-2.0 OR GPL-2.0-only with Classpath-exception-2.0, approved, ee4j.jsonp maven/mavencentral/org.hamcrest/hamcrest-core/2.2, BSD-3-Clause, approved, clearlydefined maven/mavencentral/org.hamcrest/hamcrest/2.2, BSD-3-Clause, approved, clearlydefined @@ -372,27 +373,27 @@ maven/mavencentral/org.slf4j/slf4j-api/2.0.13, MIT, approved, #5915 maven/mavencentral/org.springdoc/springdoc-openapi-starter-common/2.2.0, Apache-2.0, approved, clearlydefined maven/mavencentral/org.springdoc/springdoc-openapi-starter-webmvc-api/2.2.0, Apache-2.0, approved, clearlydefined maven/mavencentral/org.springdoc/springdoc-openapi-starter-webmvc-ui/2.2.0, Apache-2.0, approved, clearlydefined -maven/mavencentral/org.springframework.boot/spring-boot-actuator-autoconfigure/3.1.11, Apache-2.0, approved, #9348 -maven/mavencentral/org.springframework.boot/spring-boot-actuator/3.1.11, Apache-2.0, approved, #9342 -maven/mavencentral/org.springframework.boot/spring-boot-autoconfigure/3.1.11, Apache-2.0, approved, #9341 -maven/mavencentral/org.springframework.boot/spring-boot-configuration-metadata/3.1.11, Apache-2.0, approved, #11032 -maven/mavencentral/org.springframework.boot/spring-boot-properties-migrator/3.1.11, Apache-2.0, approved, #10675 -maven/mavencentral/org.springframework.boot/spring-boot-starter-actuator/3.1.11, Apache-2.0, approved, #9344 -maven/mavencentral/org.springframework.boot/spring-boot-starter-aop/3.1.11, Apache-2.0, approved, #9338 -maven/mavencentral/org.springframework.boot/spring-boot-starter-json/3.1.11, Apache-2.0, approved, #9336 -maven/mavencentral/org.springframework.boot/spring-boot-starter-log4j2/3.1.11, Apache-2.0, approved, #8800 -maven/mavencentral/org.springframework.boot/spring-boot-starter-logging/3.1.11, Apache-2.0, approved, #9343 -maven/mavencentral/org.springframework.boot/spring-boot-starter-oauth2-client/3.1.11, Apache-2.0, approved, #8806 -maven/mavencentral/org.springframework.boot/spring-boot-starter-security/3.1.11, Apache-2.0, approved, #9337 -maven/mavencentral/org.springframework.boot/spring-boot-starter-test/3.1.11, Apache-2.0, approved, #9353 -maven/mavencentral/org.springframework.boot/spring-boot-starter-tomcat/3.1.11, Apache-2.0, approved, #9351 -maven/mavencentral/org.springframework.boot/spring-boot-starter-validation/3.1.11, Apache-2.0, approved, #9335 -maven/mavencentral/org.springframework.boot/spring-boot-starter-web/3.1.11, Apache-2.0, approved, #9347 -maven/mavencentral/org.springframework.boot/spring-boot-starter/3.1.11, Apache-2.0, approved, #9349 -maven/mavencentral/org.springframework.boot/spring-boot-test-autoconfigure/3.1.11, Apache-2.0, approved, #9339 -maven/mavencentral/org.springframework.boot/spring-boot-test/3.1.11, Apache-2.0, approved, #9346 -maven/mavencentral/org.springframework.boot/spring-boot/3.1.11, Apache-2.0, approved, #9352 -maven/mavencentral/org.springframework.data/spring-data-commons/3.1.11, Apache-2.0, approved, #8805 +maven/mavencentral/org.springframework.boot/spring-boot-actuator-autoconfigure/3.1.12, Apache-2.0, approved, #9348 +maven/mavencentral/org.springframework.boot/spring-boot-actuator/3.1.12, Apache-2.0, approved, #9342 +maven/mavencentral/org.springframework.boot/spring-boot-autoconfigure/3.1.12, Apache-2.0, approved, #9341 +maven/mavencentral/org.springframework.boot/spring-boot-configuration-metadata/3.1.12, Apache-2.0, approved, #11032 +maven/mavencentral/org.springframework.boot/spring-boot-properties-migrator/3.1.12, Apache-2.0, approved, #10675 +maven/mavencentral/org.springframework.boot/spring-boot-starter-actuator/3.1.12, Apache-2.0, approved, #9344 +maven/mavencentral/org.springframework.boot/spring-boot-starter-aop/3.1.12, Apache-2.0, approved, #9338 +maven/mavencentral/org.springframework.boot/spring-boot-starter-json/3.1.12, Apache-2.0, approved, #9336 +maven/mavencentral/org.springframework.boot/spring-boot-starter-log4j2/3.1.12, Apache-2.0, approved, #8800 +maven/mavencentral/org.springframework.boot/spring-boot-starter-logging/3.1.12, Apache-2.0, approved, #9343 +maven/mavencentral/org.springframework.boot/spring-boot-starter-oauth2-client/3.1.12, Apache-2.0, approved, #8806 +maven/mavencentral/org.springframework.boot/spring-boot-starter-security/3.1.12, Apache-2.0, approved, #9337 +maven/mavencentral/org.springframework.boot/spring-boot-starter-test/3.1.12, Apache-2.0, approved, #9353 +maven/mavencentral/org.springframework.boot/spring-boot-starter-tomcat/3.1.12, Apache-2.0, approved, #9351 +maven/mavencentral/org.springframework.boot/spring-boot-starter-validation/3.1.12, Apache-2.0, approved, #9335 +maven/mavencentral/org.springframework.boot/spring-boot-starter-web/3.1.12, Apache-2.0, approved, #9347 +maven/mavencentral/org.springframework.boot/spring-boot-starter/3.1.12, Apache-2.0, approved, #9349 +maven/mavencentral/org.springframework.boot/spring-boot-test-autoconfigure/3.1.12, Apache-2.0, approved, #9339 +maven/mavencentral/org.springframework.boot/spring-boot-test/3.1.12, Apache-2.0, approved, #9346 +maven/mavencentral/org.springframework.boot/spring-boot/3.1.12, Apache-2.0, approved, #9352 +maven/mavencentral/org.springframework.data/spring-data-commons/3.1.12, Apache-2.0, approved, #8805 maven/mavencentral/org.springframework.security/spring-security-config/6.1.9, Apache-2.0, approved, #9736 maven/mavencentral/org.springframework.security/spring-security-core/6.1.9, Apache-2.0, approved, #9801 maven/mavencentral/org.springframework.security/spring-security-crypto/6.1.9, Apache-2.0 AND ISC, approved, #9735 @@ -401,15 +402,16 @@ maven/mavencentral/org.springframework.security/spring-security-oauth2-core/6.1. maven/mavencentral/org.springframework.security/spring-security-oauth2-jose/6.1.9, Apache-2.0, approved, #9345 maven/mavencentral/org.springframework.security/spring-security-test/6.1.9, Apache-2.0, approved, #10674 maven/mavencentral/org.springframework.security/spring-security-web/6.1.9, Apache-2.0, approved, #9800 -maven/mavencentral/org.springframework/spring-aop/6.0.19, Apache-2.0, approved, #5940 -maven/mavencentral/org.springframework/spring-beans/6.0.19, Apache-2.0, approved, #5937 -maven/mavencentral/org.springframework/spring-context/6.0.19, Apache-2.0, approved, #5936 -maven/mavencentral/org.springframework/spring-core/6.0.19, Apache-2.0 AND BSD-3-Clause, approved, #5948 -maven/mavencentral/org.springframework/spring-expression/6.0.19, Apache-2.0, approved, #3284 -maven/mavencentral/org.springframework/spring-jcl/6.0.19, Apache-2.0, approved, #3283 -maven/mavencentral/org.springframework/spring-test/6.0.19, Apache-2.0, approved, #7003 -maven/mavencentral/org.springframework/spring-web/6.0.19, Apache-2.0, approved, #5942 -maven/mavencentral/org.springframework/spring-webmvc/6.0.19, Apache-2.0, approved, #5944 +maven/mavencentral/org.springframework/spring-aop/6.0.21, Apache-2.0, approved, #5940 +maven/mavencentral/org.springframework/spring-beans/6.0.20, Apache-2.0, approved, #5937 +maven/mavencentral/org.springframework/spring-beans/6.0.21, Apache-2.0, approved, #5937 +maven/mavencentral/org.springframework/spring-context/6.0.21, Apache-2.0, approved, #5936 +maven/mavencentral/org.springframework/spring-core/6.0.21, Apache-2.0 AND BSD-3-Clause, approved, #5948 +maven/mavencentral/org.springframework/spring-expression/6.0.21, Apache-2.0, approved, #3284 +maven/mavencentral/org.springframework/spring-jcl/6.0.21, Apache-2.0, approved, #3283 +maven/mavencentral/org.springframework/spring-test/6.0.21, Apache-2.0, approved, #7003 +maven/mavencentral/org.springframework/spring-web/6.0.21, Apache-2.0, approved, #5942 +maven/mavencentral/org.springframework/spring-webmvc/6.0.21, Apache-2.0, approved, #5944 maven/mavencentral/org.testcontainers/junit-jupiter/1.18.3, MIT, approved, #7941 maven/mavencentral/org.testcontainers/junit-jupiter/1.19.7, MIT, approved, #10344 maven/mavencentral/org.testcontainers/testcontainers/1.18.3, MIT, approved, #7938 diff --git a/TESTS.md b/TESTS.md index b7e9059acd..e19b86d9bc 100644 --- a/TESTS.md +++ b/TESTS.md @@ -47,7 +47,7 @@ Wiremock Tests and their corresponding utilities are marked by the suffix `Wirem ### Smoke Tests - The smoke test can be found under `irs-integration-tests/src/test/java/org/eclipse/tractusx/irs/smoketest/ItemGraphSmokeTest.java`. -- It is executed via the GitHub workflow [IRS integration tests](.github/workflows/int-test-automation.yml). +- It is executed via the GitHub workflow [IRS integration tests](.github/workflows/smoketest.yml). ### Regression Tests diff --git a/charts/item-relationship-service/CHANGELOG.md b/charts/item-relationship-service/CHANGELOG.md index 132c122345..d86f90b940 100644 --- a/charts/item-relationship-service/CHANGELOG.md +++ b/charts/item-relationship-service/CHANGELOG.md @@ -6,9 +6,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] -## [7.2.0] - 2024-07-03 - +## [7.2.1] - 2024-07-10 +- Update bitnami/common to 2.x.x +## [7.2.0] - 2024-07-03 ### Changed - Update IRS version to 5.2.0 diff --git a/charts/item-relationship-service/Chart.yaml b/charts/item-relationship-service/Chart.yaml index 8bb96931c7..562b85296a 100644 --- a/charts/item-relationship-service/Chart.yaml +++ b/charts/item-relationship-service/Chart.yaml @@ -35,7 +35,7 @@ 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.2.0 +version: 7.2.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. @@ -44,7 +44,7 @@ appVersion: "5.2.0" dependencies: - name: common repository: https://charts.bitnami.com/bitnami - version: 1.x.x + version: 2.x.x - name: minio repository: https://charts.min.io/ version: 5.0.1 diff --git a/docs/src/api/irs-api.yaml b/docs/src/api/irs-api.yaml index ad01c467e1..b51cc259b3 100644 --- a/docs/src/api/irs-api.yaml +++ b/docs/src/api/irs-api.yaml @@ -860,7 +860,7 @@ paths: - api_key: [] summary: Lists the registered policies that should be accepted in EDC negotiation. tags: - - Policy Store API + - Policy Store API post: description: Register a policy that should be accepted in EDC negotiation. operationId: registerAllowedPolicy @@ -917,7 +917,7 @@ paths: - api_key: [] summary: Register a policy that should be accepted in EDC negotiation. tags: - - Policy Store API + - Policy Store API put: description: Updates existing policies. operationId: updateAllowedPolicy @@ -970,7 +970,7 @@ paths: - api_key: [] summary: Updates existing policies. tags: - - Policy Store API + - Policy Store API /irs/policies/paged: get: description: | @@ -978,30 +978,30 @@ paths: - **Filtering:** `search=,[EQUALS|STARTS_WITH|BEFORE_LOCAL_DATE|AFTER_LOCAL_DATE],`. - Example: 'search=BPN,STARTS_WITH,BPNL12&search=policyId,STARTS_WITH,policy2'. + Example: `search=BPN,STARTS_WITH,BPNL12&search=policyId,STARTS_WITH,policy2`. - **Sorting:** `sort=,[asc|desc]`. - Example: 'sort=BPN,asc&sort=policyId,desc'. + Example: `sort=BPN,asc&sort=policyId,desc`. - **Paging:** Example: `page=1&size=20` operationId: getPoliciesPaged parameters: - - description: List of business partner numbers. - in: query - name: businessPartnerNumbers - required: false - schema: - type: array - items: - type: string + - description: List of business partner numbers. + in: query + name: businessPartnerNumbers + required: false + schema: + type: array + items: + type: string responses: "200": content: application/json: examples: - error: + success: $ref: '#/components/examples/get-policies-paged-result' schema: $ref: '#/components/schemas/Page' @@ -1025,10 +1025,10 @@ paths: $ref: '#/components/schemas/ErrorResponse' description: Authorization refused by server. security: - - api_key: [ ] + - api_key: [] summary: Find policies. tags: - - Policy Store API + - Policy Store API /irs/policies/{policyId}: delete: description: Removes a policy that should no longer be accepted in EDC negotiation. @@ -1073,7 +1073,7 @@ paths: - api_key: [] summary: Removes a policy that should no longer be accepted in EDC negotiation. tags: - - Policy Store API + - Policy Store API /irs/policies/{policyId}/bpnl/{bpnl}: delete: description: Removes a policy from BPNL that should no longer be accepted in @@ -1126,7 +1126,7 @@ paths: summary: Removes a policy from BPNL that should no longer be accepted in EDC negotiation. tags: - - Policy Store API + - Policy Store API components: examples: aspect-models-list: @@ -1520,44 +1520,44 @@ components: get-policies-paged-result: value: content: - - bpn: BPNL1234567890AB - policy: - createdOn: 2024-07-08T12:01:19.4677109+02:00 - permissions: - - action: use - constraint: - and: [ ] - or: - - leftOperand: Membership - operator: - '@id': eq - rightOperand: active - - leftOperand: FrameworkAgreement.traceability - operator: - '@id': eq - rightOperand: active - - leftOperand: PURPOSE - operator: - '@id': eq - rightOperand: ID 3.1 Trace - - action: access - constraint: - and: [ ] - or: - - leftOperand: Membership - operator: - '@id': eq - rightOperand: active - - leftOperand: FrameworkAgreement.traceability - operator: - '@id': eq - rightOperand: active - - leftOperand: PURPOSE - operator: - '@id': eq - rightOperand: ID 3.1 Trace - policyId: 13a8523f-c80a-40b8-9e43-faab47fbceaa - validUntil: 2025-07-08T12:01:19.4677109+02:00 + - bpn: BPNL1234567890AB + policy: + createdOn: 2024-07-08T12:01:19.4677109+02:00 + permissions: + - action: use + constraint: + and: [] + or: + - leftOperand: Membership + operator: + '@id': eq + rightOperand: active + - leftOperand: FrameworkAgreement.traceability + operator: + '@id': eq + rightOperand: active + - leftOperand: PURPOSE + operator: + '@id': eq + rightOperand: ID 3.1 Trace + - action: access + constraint: + and: [] + or: + - leftOperand: Membership + operator: + '@id': eq + rightOperand: active + - leftOperand: FrameworkAgreement.traceability + operator: + '@id': eq + rightOperand: active + - leftOperand: PURPOSE + operator: + '@id': eq + rightOperand: ID 3.1 Trace + policyId: 13a8523f-c80a-40b8-9e43-faab47fbceaa + validUntil: 2025-07-08T12:01:19.4677109+02:00 empty: false first: false last: true @@ -2572,6 +2572,10 @@ components: format: int32 maximum: 2147483647 minimum: 0 + rootCauses: + type: array + items: + type: string ProtocolInformation: type: object additionalProperties: false diff --git a/docs/src/docs/arc42/cross-cutting/safety-security.adoc b/docs/src/docs/arc42/cross-cutting/safety-security.adoc index 7a0458baf4..4a5b22c172 100644 --- a/docs/src/docs/arc42/cross-cutting/safety-security.adoc +++ b/docs/src/docs/arc42/cross-cutting/safety-security.adoc @@ -12,24 +12,25 @@ This behavior is shown in the table below. ==== Rights and Roles Matrix of IRS |=== -| Category | Action | Endpoint | view_irs | admin_irs -| Policy Store | Add policy | POST /irs/policies | | x -| | Get policies | GET /irs/policies | | x -| | Update policy | PUT /irs/policies/{policyId} | | x -| | Delete policy | DELETE /irs/policies/{policyId} | | x -| Aspect models | Get aspect models | GET /irs/aspectmodels | x | x -| Job processing | Register job | POST /irs/jobs | x | x -| | Get jobs | GET /irs/jobs | x | x -| | Get job | GET /irs/jobs/{jobId} | x | x -| | Cancel job | PUT /irs/jobs/{jobId} | x | x -| Batch processing | Register order | POST /irs/orders | x | x -| | Get order | GET /irs/orders/{orderId} | x | x -| | Cancel order | PUT /irs/orders/{orderId} | x | x -| | Get batch | GET /irs/orders/{orderId}/batches/{batchId} | x | x +| Category | Action | Endpoint | view_irs | admin_irs +| Policy Store | Add policy | POST /irs/policies | | x +| | Get policies | GET /irs/policies | | x +| | Find policies (paged) | GET /irs/policies/paged | | x +| | Update policy | PUT /irs/policies/{policyId} | | x +| | Delete policy | DELETE /irs/policies/{policyId} | | x +| Aspect models | Get aspect models | GET /irs/aspectmodels | x | x +| Job processing | Register job | POST /irs/jobs | x | x +| | Get jobs | GET /irs/jobs | x | x +| | Get job | GET /irs/jobs/{jobId} | x | x +| | Cancel job | PUT /irs/jobs/{jobId} | x | x +| Batch processing | Register order | POST /irs/orders | x | x +| | Get order | GET /irs/orders/{orderId} | x | x +| | Cancel order | PUT /irs/orders/{orderId} | x | x +| | Get batch | GET /irs/orders/{orderId}/batches/{batchId} | x | x | Environmental- and -Social Standards | Register investigation job | POST /ess/bpn/investigations | x | x -| | Get investigation job | GET /ess/bpn/investigations{id} | x | x -| | Accept notifications | POST /ess/notification/receive | x | x +Social Standards | Register investigation job | POST /ess/bpn/investigations | x | x +| | Get investigation job | GET /ess/bpn/investigations{id} | x | x +| | Accept notifications | POST /ess/notification/receive | x | x |=== Legend: x = full access to all resources diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java index dbec718442..5a50fd5887 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegate.java @@ -23,12 +23,16 @@ ********************************************************************************/ package org.eclipse.tractusx.irs.aaswrapper.job.delegate; +import java.util.Collection; import java.util.List; +import java.util.Objects; +import io.github.resilience4j.core.functions.Either; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; +import org.eclipse.tractusx.irs.common.ExceptionUtils; import org.eclipse.tractusx.irs.component.JobParameter; import org.eclipse.tractusx.irs.component.PartChainIdentificationKey; import org.eclipse.tractusx.irs.component.Shell; @@ -69,10 +73,14 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai try { final var dtrKeys = List.of(new DigitalTwinRegistryKey(itemId.getGlobalAssetId(), itemId.getBpn())); - final Shell shell = digitalTwinRegistryService.fetchShells(dtrKeys).stream() - // we use findFirst here, because we query only for one - // DigitalTwinRegistryKey here - .findFirst().orElseThrow(); + final var eithers = digitalTwinRegistryService.fetchShells(dtrKeys); + final var shell = eithers.stream() + // we use findFirst here, because we query only for one + // DigitalTwinRegistryKey here + .map(Either::getOrNull) + .filter(Objects::nonNull) + .findFirst() + .orElseThrow(() -> shellNotFound(eithers)); itemContainerBuilder.shell( jobData.isAuditContractNegotiation() ? shell : shell.withoutContractAgreementId()); @@ -81,7 +89,8 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai // otherwise Jobs stay in state RUNNING forever log.info("Shell Endpoint could not be retrieved for Item: {}. Creating Tombstone.", itemId); itemContainerBuilder.tombstone( - Tombstone.from(itemId.getGlobalAssetId(), null, e, retryCount, ProcessStep.DIGITAL_TWIN_REQUEST)); + Tombstone.from(itemId.getGlobalAssetId(), null, e, e.getSuppressed(), retryCount, + ProcessStep.DIGITAL_TWIN_REQUEST)); } if (expectedDepthOfTreeIsNotReached(jobData.getDepth(), aasTransferProcess.getDepth())) { @@ -92,6 +101,12 @@ public ItemContainer process(final ItemContainer.ItemContainerBuilder itemContai return itemContainerBuilder.build(); } + private static RegistryServiceException shellNotFound(final Collection> eithers) { + final RegistryServiceException shellNotFound = new RegistryServiceException("Shell not found"); + ExceptionUtils.addSuppressedExceptions(eithers, shellNotFound); + return shellNotFound; + } + private boolean expectedDepthOfTreeIsNotReached(final int expectedDepth, final int currentDepth) { log.info("Expected tree depth is {}, current depth is {}", expectedDepth, currentDepth); return currentDepth < expectedDepth; diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java index 7f774d410f..f45dca48e2 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/RelationshipDelegate.java @@ -41,6 +41,7 @@ import org.eclipse.tractusx.irs.data.JsonParseException; import org.eclipse.tractusx.irs.edc.client.EdcSubmodelFacade; import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; +import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyExpiredException; import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyPermissionException; import org.eclipse.tractusx.irs.edc.client.relationships.RelationshipAspect; import org.eclipse.tractusx.irs.registryclient.discovery.ConnectorEndpointsService; @@ -114,7 +115,7 @@ private void processEndpoint(final Endpoint endpoint, final RelationshipAspect r aasTransferProcess.addIdsToProcess(idsToProcess); itemContainerBuilder.relationships(relationships); itemContainerBuilder.bpns(getBpnsFrom(relationships)); - } catch (final UsagePolicyPermissionException e) { + } catch (final UsagePolicyPermissionException | UsagePolicyExpiredException e) { log.info("Encountered usage policy exception: {}. Creating Tombstone.", e.getMessage()); itemContainerBuilder.tombstone( Tombstone.from(itemId.getGlobalAssetId(), endpoint.getProtocolInformation().getHref(), e, 0, diff --git a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegate.java b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegate.java index f9f0f2d3a9..ca92b2f799 100644 --- a/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegate.java +++ b/irs-api/src/main/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/SubmodelDelegate.java @@ -41,6 +41,7 @@ import org.eclipse.tractusx.irs.data.JsonParseException; import org.eclipse.tractusx.irs.edc.client.EdcSubmodelFacade; import org.eclipse.tractusx.irs.edc.client.exceptions.EdcClientException; +import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyExpiredException; import org.eclipse.tractusx.irs.edc.client.exceptions.UsagePolicyPermissionException; import org.eclipse.tractusx.irs.registryclient.discovery.ConnectorEndpointsService; import org.eclipse.tractusx.irs.semanticshub.SemanticsHubFacade; @@ -142,8 +143,8 @@ private List getSubmodels(final SubmodelDescriptor submodelDescriptor, itemContainerBuilder.tombstone(Tombstone.from(itemId, endpoint.getProtocolInformation().getHref(), e, 0, ProcessStep.SCHEMA_REQUEST)); log.info("Cannot load JSON schema for validation. Creating Tombstone."); - } catch (final UsagePolicyPermissionException e) { - log.info("Encountered usage policy exception: {}. Creating Tombstone.", e.getMessage()); + } catch (final UsagePolicyPermissionException | UsagePolicyExpiredException e) { + log.info("Encountered usage policy permission exception: {}. Creating Tombstone.", e.getMessage()); itemContainerBuilder.tombstone(Tombstone.from(itemId, endpoint.getProtocolInformation().getHref(), e, 0, ProcessStep.USAGE_POLICY_VALIDATION, e.getBusinessPartnerNumber(), jsonUtil.asMap(e.getPolicy()))); diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsWireMockIntegrationTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsWireMockIntegrationTest.java index 6a3ae93082..477f072e5b 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsWireMockIntegrationTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/IrsWireMockIntegrationTest.java @@ -59,6 +59,7 @@ import org.eclipse.tractusx.irs.component.JobHandle; import org.eclipse.tractusx.irs.component.Jobs; import org.eclipse.tractusx.irs.component.RegisterJob; +import org.eclipse.tractusx.irs.component.Tombstone; import org.eclipse.tractusx.irs.component.enums.JobState; import org.eclipse.tractusx.irs.edc.client.EndpointDataReferenceStorage; import org.eclipse.tractusx.irs.semanticshub.AspectModels; @@ -276,6 +277,102 @@ void shouldStartRecursiveProcesses() { WiremockSupport.verifyNegotiationCalls(6); } + @Test + void shouldCreateDetailedTombstoneForMissmatchPolicy() { + // Arrange + final String globalAssetId = "urn:uuid:334cce52-1f52-4bc9-9dd1-410bbe497bbc"; + + WiremockSupport.successfulSemanticModelRequest(); + WiremockSupport.successfulSemanticHubRequests(); + WiremockSupport.successfulDiscovery(); + + failedRegistryRequestMissmatchPolicy(); + + final RegisterJob request = WiremockSupport.jobRequest(globalAssetId, TEST_BPN, 4); + + // Act + final JobHandle jobHandle = irsService.registerItemJob(request); + + // Assert + assertThat(jobHandle.getId()).isNotNull(); + waitForCompletion(jobHandle); + final Jobs jobForJobId = irsService.getJobForJobId(jobHandle.getId(), false); + + assertThat(jobForJobId.getJob().getState()).isEqualTo(JobState.COMPLETED); + assertThat(jobForJobId.getShells()).isEmpty(); + assertThat(jobForJobId.getRelationships()).isEmpty(); + assertThat(jobForJobId.getSubmodels()).isEmpty(); + assertThat(jobForJobId.getTombstones()).hasSize(1); + final Tombstone actualTombstone = jobForJobId.getTombstones().get(0); + assertThat(actualTombstone.getProcessingError().getRootCauses()).hasSize(1); + assertThat(actualTombstone.getProcessingError().getRootCauses().get(0)).contains( + "Asset could not be negotiated for providerWithSuffix 'https://test.edc.io/api/v1/dsp', BPN 'BPNL00000000TEST', catalogItem"); + } + + @Test + void shouldCreateDetailedTombstoneForEdcErrors() { + // Arrange + final String globalAssetId = "urn:uuid:334cce52-1f52-4bc9-9dd1-410bbe497bbc"; + + WiremockSupport.successfulSemanticModelRequest(); + WiremockSupport.successfulSemanticHubRequests(); + WiremockSupport.successfulDiscovery(); + + failedRegistryRequestEdcError(); + + final RegisterJob request = WiremockSupport.jobRequest(globalAssetId, TEST_BPN, 4); + + // Act + final JobHandle jobHandle = irsService.registerItemJob(request); + + // Assert + assertThat(jobHandle.getId()).isNotNull(); + waitForCompletion(jobHandle); + final Jobs jobForJobId = irsService.getJobForJobId(jobHandle.getId(), false); + + assertThat(jobForJobId.getJob().getState()).isEqualTo(JobState.COMPLETED); + assertThat(jobForJobId.getShells()).isEmpty(); + assertThat(jobForJobId.getRelationships()).isEmpty(); + assertThat(jobForJobId.getSubmodels()).isEmpty(); + assertThat(jobForJobId.getTombstones()).hasSize(1); + final Tombstone actualTombstone = jobForJobId.getTombstones().get(0); + assertThat(actualTombstone.getProcessingError().getRootCauses()).hasSize(1); + assertThat(actualTombstone.getProcessingError().getRootCauses().get(0)).contains( + "502 Bad Gateway"); + } + + @Test + void shouldCreateDetailedTombstoneForDiscoveryErrors() { + // Arrange + final String globalAssetId = "urn:uuid:334cce52-1f52-4bc9-9dd1-410bbe497bbc"; + + WiremockSupport.successfulSemanticModelRequest(); + WiremockSupport.successfulSemanticHubRequests(); + WiremockSupport.failedEdcDiscovery(); + + failedRegistryRequestEdcError(); + + final RegisterJob request = WiremockSupport.jobRequest(globalAssetId, TEST_BPN, 4); + + // Act + final JobHandle jobHandle = irsService.registerItemJob(request); + + // Assert + assertThat(jobHandle.getId()).isNotNull(); + waitForCompletion(jobHandle); + final Jobs jobForJobId = irsService.getJobForJobId(jobHandle.getId(), false); + + assertThat(jobForJobId.getJob().getState()).isEqualTo(JobState.COMPLETED); + assertThat(jobForJobId.getShells()).isEmpty(); + assertThat(jobForJobId.getRelationships()).isEmpty(); + assertThat(jobForJobId.getSubmodels()).isEmpty(); + assertThat(jobForJobId.getTombstones()).hasSize(1); + final Tombstone actualTombstone = jobForJobId.getTombstones().get(0); + assertThat(actualTombstone.getProcessingError().getRootCauses()).hasSize(1); + assertThat(actualTombstone.getProcessingError().getRootCauses().get(0)).contains( + "No EDC Endpoints could be discovered for BPN '%s'".formatted(TEST_BPN)); + } + private void successfulRegistryAndDataRequest(final String globalAssetId, final String idShort, final String bpn, final String batchFileName, final String sbomFileName) { @@ -306,6 +403,24 @@ private void successfulNegotiation(final String edcAssetId) { endpointDataReferenceStorage.put(contractAgreementId, createEndpointDataReference(contractAgreementId)); } + private void failedRegistryRequestMissmatchPolicy() { + final String registryEdcAssetId = "registry-asset"; + failedPolicyMissmatchNegotiation(registryEdcAssetId); + } + + private void failedRegistryRequestEdcError() { + failedNegotiation(); + } + + private void failedPolicyMissmatchNegotiation(final String edcAssetId) { + final String contractAgreementId = "%s:%s:%s".formatted(randomUUID(), edcAssetId, randomUUID()); + SubmodelFacadeWiremockSupport.prepareMissmatchPolicyCatalog(edcAssetId, contractAgreementId); + } + + private void failedNegotiation() { + SubmodelFacadeWiremockSupport.prepareFailingCatalog(); + } + private void waitForCompletion(final JobHandle jobHandle) { Awaitility.await() .timeout(Duration.ofSeconds(35)) diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/WiremockSupport.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/WiremockSupport.java index ae50633ce3..5c73b9dc13 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/WiremockSupport.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/WiremockSupport.java @@ -99,6 +99,11 @@ static void successfulDiscovery() { stubFor(DiscoveryServiceWiremockSupport.postEdcDiscovery200()); } + static void failedEdcDiscovery() { + stubFor(DiscoveryServiceWiremockSupport.postDiscoveryFinder200()); + stubFor(DiscoveryServiceWiremockSupport.postEdcDiscovery200Empty()); + } + static String encodedId(final String shellId) { return encodeBase64String(shellId.getBytes(StandardCharsets.UTF_8)); } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegateTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegateTest.java index 25b9a78cc9..c5347581b3 100644 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegateTest.java +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/aaswrapper/job/delegate/DigitalTwinDelegateTest.java @@ -35,6 +35,7 @@ import java.util.List; +import io.github.resilience4j.core.functions.Either; import io.github.resilience4j.retry.RetryRegistry; import org.eclipse.tractusx.irs.aaswrapper.job.AASTransferProcess; import org.eclipse.tractusx.irs.aaswrapper.job.ItemContainer; @@ -55,7 +56,7 @@ class DigitalTwinDelegateTest { void shouldFillItemContainerWithShell() throws RegistryServiceException { // given when(digitalTwinRegistryService.fetchShells(any())).thenReturn( - List.of(shell("", shellDescriptor(List.of(submodelDescriptorWithoutHref("any")))))); + List.of(Either.right(shell("", shellDescriptor(List.of(submodelDescriptorWithoutHref("any"))))))); // when final ItemContainer result = digitalTwinDelegate.process(ItemContainer.builder(), jobParameter(), @@ -72,11 +73,11 @@ void shouldFillItemContainerWithShell() throws RegistryServiceException { void shouldFillItemContainerWithShellAndContractAgreementIdWhenAuditFlag() throws RegistryServiceException { // given when(digitalTwinRegistryService.fetchShells(any())).thenReturn( - List.of(shell("", shellDescriptor(List.of(submodelDescriptorWithoutHref("any")))))); + List.of(Either.right(shell("", shellDescriptor(List.of(submodelDescriptorWithoutHref("any"))))))); // when - final ItemContainer result = digitalTwinDelegate.process(ItemContainer.builder(), jobParameterAuditContractNegotiation(), - new AASTransferProcess("id", 0), createKey()); + final ItemContainer result = digitalTwinDelegate.process(ItemContainer.builder(), + jobParameterAuditContractNegotiation(), new AASTransferProcess("id", 0), createKey()); // then assertThat(result).isNotNull(); @@ -86,10 +87,11 @@ void shouldFillItemContainerWithShellAndContractAgreementIdWhenAuditFlag() throw } @Test - void shouldFillItemContainerWithShellAndSubmodelDescriptorsWhenDepthReached() throws RegistryServiceException { + void shouldFillItemContainerWithShellAndSubmodelDescriptorsWhenDepthReached() + throws RegistryServiceException { // given when(digitalTwinRegistryService.fetchShells(any())).thenReturn( - List.of(shell("", shellDescriptor(List.of(submodelDescriptorWithoutHref("any")))))); + List.of(Either.right(shell("", shellDescriptor(List.of(submodelDescriptorWithoutHref("any"))))))); final JobParameter jobParameter = JobParameter.builder().depth(1).aspects(List.of()).build(); // when @@ -132,7 +134,8 @@ void shouldCreateTombstoneIfBPNEmpty() { assertThat(result).isNotNull(); assertThat(result.getTombstones()).hasSize(1); assertThat(result.getTombstones().get(0).getCatenaXId()).isEqualTo("itemId"); - assertThat(result.getTombstones().get(0).getProcessingError().getErrorDetail()).isEqualTo("Can't get relationship without a BPN"); + assertThat(result.getTombstones().get(0).getProcessingError().getErrorDetail()).isEqualTo( + "Can't get relationship without a BPN"); assertThat(result.getTombstones().get(0).getProcessingError().getProcessStep()).isEqualTo( ProcessStep.DIGITAL_TWIN_REQUEST); } @@ -140,6 +143,7 @@ void shouldCreateTombstoneIfBPNEmpty() { private static PartChainIdentificationKey createKey() { return PartChainIdentificationKey.builder().globalAssetId("itemId").bpn("bpn123").build(); } + private static PartChainIdentificationKey createKeyWithoutBpn() { return PartChainIdentificationKey.builder().globalAssetId("itemId").build(); } diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/component/TombstoneTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/component/TombstoneTest.java new file mode 100644 index 0000000000..bded98daed --- /dev/null +++ b/irs-api/src/test/java/org/eclipse/tractusx/irs/component/TombstoneTest.java @@ -0,0 +1,144 @@ +/******************************************************************************** + * 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.component; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import io.github.resilience4j.retry.RetryRegistry; +import org.eclipse.tractusx.irs.component.enums.ProcessStep; +import org.junit.jupiter.api.Test; + +class TombstoneTest { + + @Test + void fromTombstoneTest() { + // arrange + final String catenaXId = "5e3e9060-ba73-4d5d-a6c8-dfd5123f4d99"; + final IllegalArgumentException illegalArgumentException = new IllegalArgumentException( + "Some funny error occur"); + final String endPointUrl = "http://localhost/dummy/interfaceinformation/urn:uuid:8a61c8db-561e-4db0-84ec-a693fc5ffdf6"; + + final ProcessingError processingError = ProcessingError.builder() + .withProcessStep(ProcessStep.SUBMODEL_REQUEST) + .withRetryCounter(RetryRegistry.ofDefaults() + .getDefaultConfig() + .getMaxAttempts()) + .withLastAttempt(ZonedDateTime.now(ZoneOffset.UTC)) + .withErrorDetail("Some funny error occur") + .build(); + + final Tombstone expectedTombstone = Tombstone.builder() + .catenaXId(catenaXId) + .endpointURL(endPointUrl) + .processingError(processingError) + .build(); + + //act + final Tombstone tombstone = Tombstone.from(catenaXId, endPointUrl, illegalArgumentException, + RetryRegistry.ofDefaults().getDefaultConfig().getMaxAttempts(), ProcessStep.SUBMODEL_REQUEST); + + // assert + assertThat(tombstone).isNotNull(); + assertThat(tombstone.getProcessingError().getErrorDetail()).isEqualTo(processingError.getErrorDetail()); + assertThat(tombstone.getProcessingError().getRetryCounter()).isEqualTo(processingError.getRetryCounter()); + assertThat(zonedDateTimeExcerpt(tombstone.getProcessingError().getLastAttempt())).isEqualTo( + zonedDateTimeExcerpt(processingError.getLastAttempt())); + assertThat(tombstone.getCatenaXId()).isEqualTo(expectedTombstone.getCatenaXId()); + assertThat(tombstone.getEndpointURL()).isEqualTo(expectedTombstone.getEndpointURL()); + assertThat(tombstone.getProcessingError().getRetryCounter()).isEqualTo( + expectedTombstone.getProcessingError().getRetryCounter()); + } + + @Test + void shouldUseSuppressedExceptionWhenPresent() { + // arrange + final String mainExceptionMessage = "Exception occurred."; + final Exception exception = new Exception(mainExceptionMessage); + final String suppressedExceptionMessage = "Suppressed Exception which occurred deeper."; + exception.addSuppressed(new Exception(suppressedExceptionMessage)); + final Throwable[] suppressed = exception.getSuppressed(); + + // act + final Tombstone from = Tombstone.from("testId", "testUrl", exception, suppressed, 1, + ProcessStep.DIGITAL_TWIN_REQUEST); + + // assert + assertThat(from.getProcessingError().getErrorDetail()).isEqualTo(exception.getMessage()); + assertThat(from.getProcessingError().getRootCauses()).contains(suppressedExceptionMessage); + } + + @Test + void shouldUseDeepSuppressedExceptionWhenPresent() { + // arrange + final Exception exception = new Exception("Exception occurred."); + + final Exception rootCause = new Exception("Wrapper exception to the root cause"); + rootCause.addSuppressed(new Exception("Root cause of the exception")); + + final Exception suppressedWrapperException = new Exception( + "Suppressed Exception which was added through Futures.", rootCause); + exception.addSuppressed(suppressedWrapperException); + + final Throwable[] suppressed = exception.getSuppressed(); + + // act + final Tombstone from = Tombstone.from("testId", "testUrl", exception, suppressed, 1, + ProcessStep.DIGITAL_TWIN_REQUEST); + + // assert + assertThat(from.getProcessingError().getErrorDetail()).isEqualTo(exception.getMessage()); + assertThat(from.getProcessingError().getRootCauses()).contains("Root cause of the exception"); + } + + @Test + void shouldUseExceptionMessageWhenSuppressedExceptionNotPresent() { + // arrange + final String mainExceptionMessage = "Exception occurred."; + final Exception exception = new Exception(mainExceptionMessage); + final Throwable[] suppressed = exception.getSuppressed(); + + // act + final Tombstone from = Tombstone.from("testId", "testUrl", exception, suppressed, 1, + ProcessStep.DIGITAL_TWIN_REQUEST); + + // assert + assertThat(from.getProcessingError().getErrorDetail()).isEqualTo(exception.getMessage()); + assertThat(from.getProcessingError().getRootCauses()).isEmpty(); + } + + private String zonedDateTimeExcerpt(ZonedDateTime dateTime) { + return new StringBuilder().append(dateTime.getYear()) + .append("-") + .append(dateTime.getMonth()) + .append("-") + .append(dateTime.getDayOfMonth()) + .append("T") + .append(dateTime.getHour()) + .append(":") + .append(dateTime.getMinute()) + .append(":") + .append(dateTime.getSecond()) + .toString(); + } + +} diff --git a/irs-api/src/test/java/org/eclipse/tractusx/irs/component/tombstone/TombStoneTest.java b/irs-api/src/test/java/org/eclipse/tractusx/irs/component/tombstone/TombStoneTest.java deleted file mode 100644 index bd8a0b97c6..0000000000 --- a/irs-api/src/test/java/org/eclipse/tractusx/irs/component/tombstone/TombStoneTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/******************************************************************************** - * Copyright (c) 2022,2024 - * 2022: ZF Friedrichshafen AG - * 2022: ISTOS GmbH - * 2022,2024: Bayerische Motoren Werke Aktiengesellschaft (BMW AG) - * 2022,2023: BOSCH 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.component.tombstone; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.time.ZoneOffset; -import java.time.ZonedDateTime; - -import io.github.resilience4j.retry.RetryRegistry; -import org.eclipse.tractusx.irs.component.ProcessingError; -import org.eclipse.tractusx.irs.component.Tombstone; -import org.eclipse.tractusx.irs.component.enums.ProcessStep; -import org.junit.jupiter.api.Test; - -class TombStoneTest { - - Tombstone tombstone; - - @Test - void fromTombstoneTest() { - // arrange - String catenaXId = "5e3e9060-ba73-4d5d-a6c8-dfd5123f4d99"; - IllegalArgumentException illegalArgumentException = new IllegalArgumentException("Some funny error occur"); - String endPointUrl = "http://localhost/dummy/interfaceinformation/urn:uuid:8a61c8db-561e-4db0-84ec-a693fc5ffdf6"; - - ProcessingError processingError = ProcessingError.builder() - .withProcessStep(ProcessStep.SUBMODEL_REQUEST) - .withRetryCounter(RetryRegistry.ofDefaults() - .getDefaultConfig() - .getMaxAttempts()) - .withLastAttempt(ZonedDateTime.now(ZoneOffset.UTC)) - .withErrorDetail("Some funny error occur") - .build(); - - Tombstone expectedTombstone = Tombstone.builder() - .catenaXId(catenaXId) - .endpointURL(endPointUrl) - .processingError(processingError) - .build(); - - //act - tombstone = Tombstone.from(catenaXId, endPointUrl, illegalArgumentException, - RetryRegistry.ofDefaults().getDefaultConfig().getMaxAttempts(), ProcessStep.SUBMODEL_REQUEST); - - // assert - assertThat(tombstone).isNotNull(); - assertThat(tombstone.getProcessingError().getErrorDetail()).isEqualTo(processingError.getErrorDetail()); - assertThat(tombstone.getProcessingError().getRetryCounter()).isEqualTo(processingError.getRetryCounter()); - assertThat(zonedDateTimeExcerpt(tombstone.getProcessingError().getLastAttempt())).isEqualTo( - zonedDateTimeExcerpt(processingError.getLastAttempt())); - assertThat(tombstone.getCatenaXId()).isEqualTo(expectedTombstone.getCatenaXId()); - assertThat(tombstone.getEndpointURL()).isEqualTo(expectedTombstone.getEndpointURL()); - assertThat(tombstone.getProcessingError().getRetryCounter()).isEqualTo( - expectedTombstone.getProcessingError().getRetryCounter()); - } - - private String zonedDateTimeExcerpt(ZonedDateTime dateTime) { - return new StringBuilder().append(dateTime.getYear()) - .append("-") - .append(dateTime.getMonth()) - .append("-") - .append(dateTime.getDayOfMonth()) - .append("T") - .append(dateTime.getHour()) - .append(":") - .append(dateTime.getMinute()) - .append(":") - .append(dateTime.getSecond()) - .toString(); - } - -} diff --git a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/ExceptionUtils.java b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/ExceptionUtils.java new file mode 100644 index 0000000000..59541693e3 --- /dev/null +++ b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/ExceptionUtils.java @@ -0,0 +1,51 @@ +/******************************************************************************** + * 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.common; + +import java.util.Collection; + +import io.github.resilience4j.core.functions.Either; + +/** + * Utilities for exception handling + */ +public final class ExceptionUtils { + + private ExceptionUtils() { + // private constructor, utility class + } + + /** + * Adds all exceptions from left side of the given Eithers to the exception. + * + * @param eithers the {@link Either}s + * @param exception the exception + * @param the exception type (left-hand side of {@link Either}) + * @param the object type (right-hand side of {@link Either}) + */ + public static void addSuppressedExceptions(final Collection> eithers, + final Exception exception) { + for (final Either either : eithers) { + if (either.isLeft() && either.getLeft() != null) { + exception.addSuppressed(either.getLeft()); + } + } + } +} diff --git a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinder.java b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinder.java index 7895c9f8c1..4a69271811 100644 --- a/irs-common/src/main/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinder.java +++ b/irs-common/src/main/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinder.java @@ -78,12 +78,19 @@ public CompletableFuture getFastestResult(final List log.debug("All of the futures completed"); if (ex != null) { - log.warn("All failed: " + System.lineSeparator() // + log.warn("All failed: " + System.lineSeparator() + // TODO (#538) can we remove logging here and log only up in call hierarchy + exceptions.stream() .map(ExceptionUtils::getStackTrace) .collect(Collectors.joining(System.lineSeparator())), ex); - overallFuture.completeExceptionally(new CompletionExceptions("None successful", exceptions)); + final CompletionExceptions noneSuccessful = new CompletionExceptions("None successful"); + for (final Throwable exception : exceptions) { + noneSuccessful.addSuppressed(exception); + } + + overallFuture.completeExceptionally(noneSuccessful); + } else { overallFuture.complete(null); } @@ -139,11 +146,8 @@ private static Function collectingExceptionsAndThrow(final Lis @ToString public static class CompletionExceptions extends CompletionException { - private final List causes; - - public CompletionExceptions(final String msg, final List causes) { + public CompletionExceptions(final String msg) { super(msg); - this.causes = causes; } } diff --git a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/ExceptionUtilsTest.java b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/ExceptionUtilsTest.java new file mode 100644 index 0000000000..69fa88d06a --- /dev/null +++ b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/ExceptionUtilsTest.java @@ -0,0 +1,56 @@ +/******************************************************************************** + * 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.common; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.ArrayList; +import java.util.List; + +import io.github.resilience4j.core.functions.Either; +import org.junit.jupiter.api.Test; + +/** + * Test for class {@link ExceptionUtils} + */ +class ExceptionUtilsTest { + + @Test + void addSuppressedExceptionsTest() { + + // ARRANGE + final List> eithers = new ArrayList<>(); + eithers.add(Either.left(new RuntimeException("Some runtime exception"))); + eithers.add(Either.right("Some string")); + eithers.add(Either.left(new IllegalArgumentException("Another exception"))); + eithers.add(Either.left(null)); + + final Exception mainException = new Exception("Main exception"); + + // ACT + ExceptionUtils.addSuppressedExceptions(eithers, mainException); + + // ASSERT + final Throwable[] suppressedExceptions = mainException.getSuppressed(); + assertEquals(2, suppressedExceptions.length); // Expecting two suppressed exceptions + assertEquals("Some runtime exception", suppressedExceptions[0].getMessage()); + assertEquals("Another exception", suppressedExceptions[1].getMessage()); + } +} \ No newline at end of file diff --git a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinderTest.java b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinderTest.java index 06e51406ad..c13692265c 100644 --- a/irs-common/src/test/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinderTest.java +++ b/irs-common/src/test/java/org/eclipse/tractusx/irs/common/util/concurrent/ResultFinderTest.java @@ -28,6 +28,7 @@ import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import java.util.Arrays; import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; @@ -106,10 +107,11 @@ void withAllCompletableFuturesFailing_itShouldThrow() { .extracting(Throwable::getCause) .isInstanceOf(ResultFinder.CompletionExceptions.class) .extracting(collectedFailures -> (ResultFinder.CompletionExceptions) collectedFailures) - .extracting(ResultFinder.CompletionExceptions::getCauses) + .extracting(ResultFinder.CompletionExceptions::getSuppressed) .describedAs("should have collected all exceptions") - .satisfies(causes -> assertThat( - causes.stream().map(Throwable::getMessage).toList()).containsExactlyInAnyOrder( + .satisfies(causes -> assertThat(Arrays.stream(causes) + .map(Throwable::getMessage) + .toList()).containsExactlyInAnyOrder( "java.lang.RuntimeException: failing 1", "java.lang.RuntimeException: failing 2", "java.lang.RuntimeException: failing 3")); 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 9a0ed6bec3..acb0039045 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 @@ -319,12 +319,13 @@ private NegotiationResponse negotiateContract(final EndpointDataReferenceStatus try { response = contractNegotiationService.negotiate(providerWithSuffix, catalogItem, endpointDataReferenceStatus, bpn); - } catch (TransferProcessException | UsagePolicyPermissionException | UsagePolicyExpiredException - | ContractNegotiationException e) { + } catch (TransferProcessException | ContractNegotiationException e) { throw new EdcClientException(("Negotiation failed for endpoint '%s', " + "tokenStatus '%s', " + "providerWithSuffix '%s', catalogItem '%s'").formatted( endpointDataReferenceStatus.endpointDataReference(), endpointDataReferenceStatus.tokenStatus(), - providerWithSuffix, endpointDataReferenceStatus), e); + providerWithSuffix, catalogItem), e); + } catch (UsagePolicyExpiredException | UsagePolicyPermissionException e) { + throw new EdcClientException("Asset could not be negotiated for providerWithSuffix '%s', BPN '%s', catalogItem '%s'".formatted(providerWithSuffix, bpn, catalogItem), e); } return response; } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/EdcClientException.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/EdcClientException.java index 8066f5e431..0bf3c24cc4 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/EdcClientException.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/EdcClientException.java @@ -39,4 +39,5 @@ public EdcClientException(final Throwable cause) { public EdcClientException(final String msg) { super(msg); } + } diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/PolicyException.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/PolicyException.java new file mode 100644 index 0000000000..4ec2799742 --- /dev/null +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/PolicyException.java @@ -0,0 +1,37 @@ +/******************************************************************************** + * 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.edc.client.exceptions; + +import org.eclipse.edc.policy.model.Policy; + +/** + * This interface provides get-methods for fine-grained policy exceptions + */ +public interface PolicyException { + /** + * @return the corresponding bpn of the policy + */ + String getBusinessPartnerNumber(); + + /** + * @return the policy that caused the exception + */ + Policy getPolicy(); +} diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyExpiredException.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyExpiredException.java index 22c04f1bb2..64549c5548 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyExpiredException.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyExpiredException.java @@ -29,7 +29,7 @@ * Usage Policy Expired Exception errors in the contract negotiation. */ @Getter -public class UsagePolicyExpiredException extends EdcClientException { +public class UsagePolicyExpiredException extends EdcClientException implements PolicyException { private final transient Policy policy; private final String businessPartnerNumber; diff --git a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyPermissionException.java b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyPermissionException.java index f894ddc794..8cac631067 100644 --- a/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyPermissionException.java +++ b/irs-edc-client/src/main/java/org/eclipse/tractusx/irs/edc/client/exceptions/UsagePolicyPermissionException.java @@ -33,7 +33,7 @@ * Usage Policy Permission Exception errors in the contract negotiation. */ @Getter -public class UsagePolicyPermissionException extends EdcClientException { +public class UsagePolicyPermissionException extends EdcClientException implements PolicyException { private final transient Policy policy; private final String businessPartnerNumber; diff --git a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/ProcessingError.java b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/ProcessingError.java index 16dac4e96b..74878c299e 100644 --- a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/ProcessingError.java +++ b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/ProcessingError.java @@ -24,6 +24,7 @@ package org.eclipse.tractusx.irs.component; import java.time.ZonedDateTime; +import java.util.List; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; @@ -44,6 +45,7 @@ public class ProcessingError { private ProcessStep processStep; private String errorDetail; private ZonedDateTime lastAttempt; + private List rootCauses; @Schema(implementation = Integer.class) @Min(0) diff --git a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java index d16b22a5b3..632485c3e0 100644 --- a/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java +++ b/irs-models/src/main/java/org/eclipse/tractusx/irs/component/Tombstone.java @@ -25,7 +25,10 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.List; import java.util.Map; +import java.util.stream.Stream; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; @@ -83,6 +86,38 @@ public static Tombstone from(final String catenaXId, final String endpointURL, f .build(); } + public static Tombstone from(final String globalAssetId, final String endpointURL, final Throwable exception, + final Throwable[] suppressed, final int retryCount, final ProcessStep processStep) { + final ProcessingError processingError = + withProcessingError(processStep, retryCount, exception.getMessage(), suppressed); + return Tombstone.builder() + .endpointURL(endpointURL) + .catenaXId(globalAssetId) + .processingError(processingError) + .build(); + } + + private static ProcessingError withProcessingError(final ProcessStep processStep, final int retryCount, + final String message, final Throwable... suppressed) { + final List rootCauses = Arrays.stream(suppressed).flatMap(Tombstone::getErrorMessages).toList(); + + return ProcessingError.builder() + .withProcessStep(processStep) + .withRetryCounter(retryCount) + .withLastAttempt(ZonedDateTime.now(ZoneOffset.UTC)) + .withErrorDetail(message) + .withRootCauses(rootCauses) + .build(); + } + + private static Stream getErrorMessages(final Throwable throwable) { + final Throwable cause = throwable.getCause(); + if (cause != null && hasSuppressedExceptions(cause)) { + return Arrays.stream(throwable.getCause().getSuppressed()).map(Throwable::getMessage); + } + return Stream.of(throwable.getMessage()); + } + private static ProcessingError withProcessingError(final ProcessStep processStep, final int retryCount, final String exception) { return ProcessingError.builder() @@ -93,4 +128,7 @@ private static ProcessingError withProcessingError(final ProcessStep processStep .build(); } + private static boolean hasSuppressedExceptions(final Throwable exception) { + return exception.getSuppressed().length > 0; + } } diff --git a/irs-parent-spring-boot/pom.xml b/irs-parent-spring-boot/pom.xml index 879e62f3b6..7727ccef78 100644 --- a/irs-parent-spring-boot/pom.xml +++ b/irs-parent-spring-boot/pom.xml @@ -23,6 +23,18 @@ ${springboot.version} pom import + + + org.apache.tomcat.embed + tomcat-embed-core + + + + + + org.apache.tomcat.embed + tomcat-embed-core + 10.1.25 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 abb43ba73f..2aa0e850ac 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 @@ -214,15 +214,15 @@ public Map> getPolicies(// @ResponseStatus(HttpStatus.OK) @Operation(summary = "Find policies.", // description = """ - Fetch a page of policies with options to filter and sort. + Fetch a page of policies with options to filter and sort. - - **Filtering:** + - **Filtering:** `search=,[EQUALS|STARTS_WITH|BEFORE_LOCAL_DATE|AFTER_LOCAL_DATE],`. - Example: 'search=BPN,STARTS_WITH,BPNL12&search=policyId,STARTS_WITH,policy2'. + Example: `search=BPN,STARTS_WITH,BPNL12&search=policyId,STARTS_WITH,policy2`. - - **Sorting:** + - **Sorting:** `sort=,[asc|desc]`. - Example: 'sort=BPN,asc&sort=policyId,desc'. + Example: `sort=BPN,asc&sort=policyId,desc`. - **Paging:** Example: `page=1&size=20` @@ -234,7 +234,7 @@ public Map> getPolicies(// description = "Successfully retrieved the paged policies", content = @Content(mediaType = APPLICATION_JSON_VALUE, schema = @Schema(implementation = Page.class), - examples = @ExampleObject(name = "error", + examples = @ExampleObject(name = "success", ref = "#/components/examples/get-policies-paged-result"))), @ApiResponse(responseCode = "401", description = UNAUTHORIZED_DESC, 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 064de544d7..9019a04761 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 @@ -29,7 +29,6 @@ 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; @@ -41,6 +40,7 @@ import jakarta.json.JsonObject; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.eclipse.tractusx.irs.edc.client.policy.AcceptedPoliciesProvider; import org.eclipse.tractusx.irs.edc.client.policy.AcceptedPolicy; import org.eclipse.tractusx.irs.edc.client.policy.Constraint; @@ -175,6 +175,10 @@ public List getStoredPolicies(final List bpnls) { } } + public List getConfiguredDefaultPolicies() { + return allowedPoliciesFromConfig.stream().map(this::toAcceptedPolicy).toList(); + } + public Map> getAllStoredPolicies() { final Map> bpnToPolicies = persistence.readAll(); if (bpnToPolicies.isEmpty()) { @@ -184,19 +188,23 @@ public Map> getAllStoredPolicies() { } public void deletePolicy(final String policyId) { + log.info("Getting all policies to find correct BPN"); final List bpnsContainingPolicyId = PolicyHelper.findBpnsByPolicyId(getAllStoredPolicies(), policyId); if (bpnsContainingPolicyId.isEmpty()) { throw new ResponseStatusException(HttpStatus.NOT_FOUND, "Policy with id '%s' not found".formatted(policyId)); - } - - try { - log.info("Deleting policy with id {}", policyId); - bpnsContainingPolicyId.forEach(bpn -> persistence.delete(bpn, policyId)); - } catch (final PolicyStoreException e) { - throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e); + } else if (bpnsContainingPolicyId.stream().noneMatch(StringUtils::isNotEmpty)) { + throw new ResponseStatusException(HttpStatus.BAD_REQUEST, "A configured default policy cannot be deleted. " + + "It can be overridden by defining a default policy via the API instead."); + } else { + try { + log.info("Deleting policy with id {}", policyId); + bpnsContainingPolicyId.forEach(bpn -> persistence.delete(bpn, policyId)); + } catch (final PolicyStoreException e) { + throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, e.getMessage(), e); + } } } @@ -267,13 +275,12 @@ private Optional findPolicy(final String policyId, final List bp public List getAcceptedPolicies(final String bpn) { if (bpn == null) { - return getAllPolicies(); + return getConfiguredDefaultPolicies(); } final List storedPolicies = getStoredPolicies(List.of(bpn)); final Stream result = sortByPolicyId(storedPolicies); return result.map(this::toAcceptedPolicy).toList(); - } private static Stream sortByPolicyId(final List policies) { @@ -282,14 +289,6 @@ private static Stream sortByPolicyId(final List policies) { return result.stream(); } - private List getAllPolicies() { - return getAllStoredPolicies().values() - .stream() - .flatMap(Collection::stream) - .map(this::toAcceptedPolicy) - .toList(); - } - private AcceptedPolicy toAcceptedPolicy(final Policy policy) { return new AcceptedPolicy(policy, policy.getValidUntil()); } 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 ff40670cfb..c9a5534fd3 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,7 +24,6 @@ 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.assertj.core.api.Assertions.assertThatThrownBy; import static org.mockito.ArgumentMatchers.any; @@ -312,9 +311,6 @@ class GetAcceptedPoliciesTests { @Test void getAcceptedPolicies_whenParameterBpnIsNull_shouldReturnTheConfiguredDefaultPolicy() { - // ARRANGE - when(persistenceMock.readAll()).thenReturn(emptyMap()); - // ACT final var acceptedPolicies = testee.getAcceptedPolicies(null); diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DigitalTwinRegistryService.java index 153acd3140..bd8894babb 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/DigitalTwinRegistryService.java @@ -25,6 +25,7 @@ import java.util.Collection; +import io.github.resilience4j.core.functions.Either; import org.eclipse.tractusx.irs.component.Shell; import org.eclipse.tractusx.irs.registryclient.exceptions.RegistryServiceException; @@ -39,7 +40,7 @@ public interface DigitalTwinRegistryService { * @param bpn the BPN to retrieve the shells for * @return the collection of asset administration shells */ - default Collection lookupShellsByBPN(final String bpn) throws RegistryServiceException { + default Collection> lookupShellsByBPN(final String bpn) throws RegistryServiceException { return fetchShells(lookupShellIdentifiers(bpn)).stream().toList(); } @@ -69,6 +70,6 @@ default Collection lookupShells(final String bpn) throws * @param identifiers the shell identifiers * @return the shell descriptors */ - Collection fetchShells(Collection identifiers) + Collection> fetchShells(Collection identifiers) throws RegistryServiceException; } diff --git a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/central/CentralDigitalTwinRegistryService.java b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/central/CentralDigitalTwinRegistryService.java index 538e8cfce6..92efd31b35 100644 --- a/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/central/CentralDigitalTwinRegistryService.java +++ b/irs-registry-client/src/main/java/org/eclipse/tractusx/irs/registryclient/central/CentralDigitalTwinRegistryService.java @@ -27,6 +27,7 @@ import java.util.Collections; import java.util.List; +import io.github.resilience4j.core.functions.Either; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.tractusx.irs.component.Shell; @@ -44,12 +45,13 @@ public class CentralDigitalTwinRegistryService implements DigitalTwinRegistrySer private final DigitalTwinRegistryClient digitalTwinRegistryClient; @Override - public Collection fetchShells(final Collection keys) { + public Collection> fetchShells(final Collection keys) { return keys.stream().map(key -> { final String aaShellIdentification = getAAShellIdentificationOrGlobalAssetId(key.shellId()); log.info("Retrieved AAS Identification {} for globalAssetId {}", aaShellIdentification, key.shellId()); - return new Shell("", digitalTwinRegistryClient.getAssetAdministrationShellDescriptor(aaShellIdentification)); + return Either.right(new Shell("", + digitalTwinRegistryClient.getAssetAdministrationShellDescriptor(aaShellIdentification))); }).toList(); } 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 ea3ec0833d..8706884183 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 @@ -35,9 +35,11 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import io.github.resilience4j.core.functions.Either; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; +import org.eclipse.tractusx.irs.common.ExceptionUtils; import org.eclipse.tractusx.irs.common.util.concurrent.ResultFinder; import org.eclipse.tractusx.irs.component.Shell; import org.eclipse.tractusx.irs.component.assetadministrationshell.AssetAdministrationShellDescriptor; @@ -56,7 +58,9 @@ */ @RequiredArgsConstructor @Slf4j -@SuppressWarnings("PMD.TooManyMethods") +@SuppressWarnings({ "PMD.TooManyMethods", + "PMD.ExcessiveImports" +}) public class DecentralDigitalTwinRegistryService implements DigitalTwinRegistryService { private static final String TOOK_MS = "{} took {} ms"; @@ -85,7 +89,7 @@ private static Stream>> groupKeys @Override @SuppressWarnings("PMD.AvoidCatchingGenericException") - public Collection fetchShells(final Collection keys) + public Collection> fetchShells(final Collection keys) throws RegistryServiceException { final var watch = new StopWatch(); @@ -96,7 +100,7 @@ public Collection fetchShells(final Collection ke try { final var calledEndpoints = new HashSet(); - final var collectedShells = groupKeysByBpn(keys).flatMap(entry -> { + final List> collectedShells = groupKeysByBpn(keys).flatMap(entry -> { try { return fetchShellDescriptors(entry, calledEndpoints); @@ -104,14 +108,18 @@ public Collection fetchShells(final Collection ke // catching generic exception is intended here, // otherwise Jobs stay in state RUNNING forever log.warn(e.getMessage(), e); - return Stream.empty(); + return Stream.of(Either.left(e)); } }).toList(); - if (collectedShells.isEmpty()) { + if (collectedShells.stream().noneMatch(Either::isRight)) { log.info("No shells found"); - throw new ShellNotFoundException("Unable to find any of the requested shells", calledEndpoints); + + final ShellNotFoundException shellNotFoundException = new ShellNotFoundException( + "Unable to find any of the requested shells", calledEndpoints); + ExceptionUtils.addSuppressedExceptions(collectedShells, shellNotFoundException); + throw shellNotFoundException; } else { log.info("Found {} shell(s) for {} key(s)", collectedShells.size(), keys.size()); return collectedShells; @@ -123,8 +131,9 @@ public Collection fetchShells(final Collection ke } } - private Stream fetchShellDescriptors(final Map.Entry> entry, - final Set calledEndpoints) throws TimeoutException { + private Stream> fetchShellDescriptors( + final Map.Entry> entry, final Set calledEndpoints) + throws TimeoutException { try { @@ -135,15 +144,15 @@ private Stream fetchShellDescriptors(final Map.Entry> fetchShellDescriptors(final Set calledEndpoints, final String bpn, - final List keys) { + private CompletableFuture>> fetchShellDescriptors(final Set calledEndpoints, + final String bpn, final List keys) throws RegistryServiceException { final var watch = new StopWatch(); final String msg = "Fetching %s shells for bpn '%s'".formatted(keys.size(), bpn); @@ -153,6 +162,9 @@ private CompletableFuture> fetchShellDescriptors(final Set c try { final var edcUrls = connectorEndpointsService.fetchConnectorEndpoints(bpn); + if (edcUrls.isEmpty()) { + throw new RegistryServiceException("No EDC Endpoints could be discovered for BPN '%s'".formatted(bpn)); + } log.info("Found {} connector endpoints for bpn '{}'", edcUrls.size(), bpn); calledEndpoints.addAll(edcUrls); @@ -165,7 +177,7 @@ private CompletableFuture> fetchShellDescriptors(final Set c } } - private CompletableFuture> fetchShellDescriptorsForConnectorEndpoints( + private CompletableFuture>> fetchShellDescriptorsForConnectorEndpoints( final List keys, final List edcUrls, final String bpn) { final var service = endpointDataForConnectorsService; @@ -180,7 +192,7 @@ private CompletableFuture> fetchShellDescriptorsForConnectorEndpoint return resultFinder.getFastestResult(shellsFuture); } - private List fetchShellDescriptorsForKey(final List keys, + private List> fetchShellDescriptorsForKey(final List keys, final EndpointDataReference endpointDataReference) { final var watch = new StopWatch(); @@ -191,8 +203,9 @@ private List fetchShellDescriptorsForKey(final List new Shell(endpointDataReference.getContractId(), - fetchShellDescriptor(endpointDataReference, key))) + .map(key -> Either.right( + new Shell(endpointDataReference.getContractId(), + fetchShellDescriptor(endpointDataReference, key)))) .toList(); } finally { watch.stop(); @@ -333,8 +346,8 @@ private Collection lookupShellIds(final String bpn, final EndpointDataRe try { return decentralDigitalTwinRegistryClient.getAllAssetAdministrationShellIdsByAssetLink( - endpointDataReference, - IdentifierKeyValuePair.builder().name("manufacturerId").value(bpn).build()).getResult(); + endpointDataReference, IdentifierKeyValuePair.builder().name("manufacturerId").value(bpn).build()) + .getResult(); } finally { watch.stop(); log.info(TOOK_MS, watch.getLastTaskName(), watch.getLastTaskTimeMillis()); diff --git a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/central/CentralDigitalTwinRegistryServiceTest.java b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/central/CentralDigitalTwinRegistryServiceTest.java index 4964d32587..8b148026c4 100644 --- a/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/central/CentralDigitalTwinRegistryServiceTest.java +++ b/irs-registry-client/src/test/java/org/eclipse/tractusx/irs/registryclient/central/CentralDigitalTwinRegistryServiceTest.java @@ -37,6 +37,7 @@ import java.util.Collections; import java.util.List; +import io.github.resilience4j.core.functions.Either; import org.eclipse.tractusx.irs.SemanticModelNames; import org.eclipse.tractusx.irs.component.Shell; import org.eclipse.tractusx.irs.component.assetadministrationshell.AssetAdministrationShellDescriptor; @@ -78,11 +79,12 @@ void setUp() throws IOException { void shouldReturnSubmodelEndpointsWhenRequestingWithCatenaXId() throws RegistryServiceException { final String existingCatenaXId = "urn:uuid:5e1908ed-e176-4f57-9616-1415097d0fdf"; - final Collection aasShellDescriptor = digitalTwinRegistryService.fetchShells( + final Collection> aasShellDescriptor = digitalTwinRegistryService.fetchShells( List.of(new DigitalTwinRegistryKey(existingCatenaXId, ""))); final List shellEndpoints = aasShellDescriptor.stream() .findFirst() .get() + .getOrNull() .payload() .getSubmodelDescriptors(); @@ -121,7 +123,13 @@ void shouldReturnTombstoneWhenClientReturnsEmptyDescriptor() { LookupShellsResponse.builder().result(Collections.emptyList()).build()); final List submodelEndpoints = dtRegistryFacadeWithMock.fetchShells( - List.of(new DigitalTwinRegistryKey(catenaXId, ""))).stream().findFirst().get().payload().getSubmodelDescriptors(); + List.of(new DigitalTwinRegistryKey(catenaXId, ""))) + .stream() + .findFirst() + .get() + .getOrNull() + .payload() + .getSubmodelDescriptors(); assertThat(submodelEndpoints).isEmpty(); } @@ -157,6 +165,7 @@ void shouldReturnAssetAdministrationShellDescriptorForFoundIdentification() { .stream() .findFirst() .get() + .getOrNull() .payload() .getSubmodelDescriptors(); assertThat(submodelEndpoints).isEmpty(); @@ -181,6 +190,7 @@ void shouldReturnSubmodelEndpointsWhenFilteringByAspectType() throws RegistrySer .stream() .findFirst() .get() + .getOrNull() .payload() .getSubmodelDescriptors(); 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 8a64391986..d340c8e31b 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 @@ -40,6 +40,7 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import io.github.resilience4j.core.functions.Either; import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.eclipse.tractusx.irs.common.util.concurrent.ResultFinder; import org.eclipse.tractusx.irs.component.Shell; @@ -108,7 +109,10 @@ void shouldReturnExpectedShell() throws RegistryServiceException { expectedShell); // when - final var actualShell = sut.fetchShells(List.of(digitalTwinRegistryKey)).stream().map(Shell::payload); + final var actualShell = sut.fetchShells(List.of(digitalTwinRegistryKey)) + .stream() + .map(Either::getOrNull) + .map(Shell::payload); // then assertThat(actualShell).containsExactly(expectedShell); @@ -143,6 +147,7 @@ void whenInterruptedExceptionOccurs() throws ExecutionException, InterruptedExce // then assertThatThrownBy(call).isInstanceOf(ShellNotFoundException.class) .hasMessage("Unable to find any of the requested shells") + .hasSuppressedException(new InterruptedException("interrupted")) .satisfies(e -> assertThat( ((ShellNotFoundException) e).getCalledEndpoints()).containsExactlyInAnyOrder( "address1", "address2")); @@ -236,6 +241,7 @@ void shouldReturnTheExpectedGlobalAssetId() throws RegistryServiceException { String actualGlobalAssetId = assetAdministrationShellDescriptors.stream() .findFirst() + .map(Either::getOrNull) .map(Shell::payload) .map(AssetAdministrationShellDescriptor::getGlobalAssetId) .get(); 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 fb3164c045..915a384f8b 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 @@ -60,6 +60,7 @@ import com.github.tomakehurst.wiremock.junit5.WireMockRuntimeInfo; import com.github.tomakehurst.wiremock.junit5.WireMockTest; +import io.github.resilience4j.core.functions.Either; import org.eclipse.edc.spi.types.domain.edr.EndpointDataReference; import org.eclipse.tractusx.irs.component.Shell; import org.eclipse.tractusx.irs.edc.client.EdcConfiguration; @@ -115,12 +116,12 @@ void shouldDiscoverEDCAndRequestRegistry() throws RegistryServiceException, EdcR when(edcEndpointReferenceRetrieverMock.getEndpointReferencesForAsset(any(), any())).thenReturn(List.of(CompletableFuture.completedFuture(endpointDataReference))); // Act - final Collection shells = decentralDigitalTwinRegistryService.fetchShells( + final Collection> shells = decentralDigitalTwinRegistryService.fetchShells( List.of(new DigitalTwinRegistryKey("testId", TEST_BPN))); // Assert assertThat(shells).hasSize(1); - assertThat(shells.stream().findFirst().get().payload().getSubmodelDescriptors()).hasSize(3); + assertThat(shells.stream().findFirst().get().getOrNull().payload().getSubmodelDescriptors()).hasSize(3); verify(exactly(1), postRequestedFor(urlPathEqualTo(DISCOVERY_FINDER_PATH))); verify(exactly(1), postRequestedFor(urlPathEqualTo(EDC_DISCOVERY_PATH))); verify(exactly(1), getRequestedFor(urlPathEqualTo(LOOKUP_SHELLS_PATH))); diff --git a/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/DiscoveryServiceWiremockSupport.java b/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/DiscoveryServiceWiremockSupport.java index 0d11ffb12e..fdfa23ff5c 100644 --- a/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/DiscoveryServiceWiremockSupport.java +++ b/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/DiscoveryServiceWiremockSupport.java @@ -48,6 +48,10 @@ public static MappingBuilder postEdcDiscovery200() { return postEdcDiscovery200(TEST_BPN, List.of(CONTROLPLANE_PUBLIC_URL)); } + public static MappingBuilder postEdcDiscovery200Empty() { + return post(urlPathEqualTo(EDC_DISCOVERY_PATH)).willReturn(responseWithStatus(STATUS_CODE_OK).withBody("[]")); + } + public static MappingBuilder postEdcDiscoveryEmpty200() { return postEdcDiscovery200(TEST_BPN, List.of()); } diff --git a/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/SubmodelFacadeWiremockSupport.java b/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/SubmodelFacadeWiremockSupport.java index 17d1573002..a245cb29af 100644 --- a/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/SubmodelFacadeWiremockSupport.java +++ b/irs-testing/src/main/java/org/eclipse/tractusx/irs/testing/wiremock/SubmodelFacadeWiremockSupport.java @@ -57,6 +57,7 @@ public final class SubmodelFacadeWiremockSupport { public static final String CX_POLICY_USAGE_PURPOSE = "cx-policy:UsagePurpose"; public static final String CX_CORE_INDUSTRYCORE_1 = "cx.core.industrycore:1"; public static final String PERMISSION_TYPE = "use"; + public static final int STATUS_CODE_BAD_GATEWAY = 502; private SubmodelFacadeWiremockSupport() { } @@ -76,7 +77,8 @@ public static void prepareNegotiation(final String negotiationId, final String t .withBody(getCatalogResponse(edcAssetId, contractAgreementId, PERMISSION_TYPE, - EDC_PROVIDER_BPN)))); + EDC_PROVIDER_BPN, + createConstraints())))); stubFor(post(urlPathEqualTo(PATH_NEGOTIATE)).willReturn( WireMockConfig.responseWithStatus(STATUS_CODE_OK).withBody(startNegotiationResponse(negotiationId)))); @@ -107,6 +109,20 @@ public static void prepareNegotiation(final String negotiationId, final String t contractAgreementId)))); } + public static void prepareMissmatchPolicyCatalog(final String edcAssetId, final String contractAgreementId) { + stubFor(post(urlPathEqualTo(PATH_CATALOG)).willReturn(WireMockConfig.responseWithStatus(STATUS_CODE_OK) + .withBody(getCatalogResponse(edcAssetId, + contractAgreementId, + PERMISSION_TYPE, + EDC_PROVIDER_BPN, + createNotAcceptedConstraints())))); + } + + public static void prepareFailingCatalog() { + stubFor(post(urlPathEqualTo(PATH_CATALOG)).willReturn(WireMockConfig.responseWithStatus(STATUS_CODE_BAD_GATEWAY) + .withBody(""))); + } + private static String startTransferProcessResponse(final String transferProcessId) { return startNegotiationResponse(transferProcessId); } @@ -190,7 +206,7 @@ private static String getTransferConfirmedResponse(final String transferProcessI @SuppressWarnings("PMD.UseObjectForClearerAPI") // used only for testing public static String getCatalogResponse(final String edcAssetId, final String offerId, final String permissionType, - final String edcProviderBpn) { + final String edcProviderBpn, final String constraints) { return """ { "@id": "78ff625c-0c05-4014-965c-bd3d0a6a0de0", @@ -237,7 +253,7 @@ public static String getCatalogResponse(final String edcAssetId, final String of "dspace:participantId": "%s", "@context": %s } - """.formatted(edcAssetId, offerId, permissionType, createConstraints(), EDC_PROVIDER_DUMMY_URL, + """.formatted(edcAssetId, offerId, permissionType, constraints, EDC_PROVIDER_DUMMY_URL, edcAssetId, EDC_PROVIDER_DUMMY_URL, edcProviderBpn, edcProviderBpn, CONTEXT); } @@ -253,6 +269,17 @@ private static String createConstraints() { }""".formatted(String.join(",\n", atomitConstraints)); } + private static String createNotAcceptedConstraints() { + final List atomitConstraints = List.of( + createAtomicConstraint("test", "test")); + return """ + { + "odrl:and": [ + %s + ] + }""".formatted(String.join(",\n", atomitConstraints)); + } + private static String createAtomicConstraint(final String leftOperand, final String rightOperand) { return """ { diff --git a/pom.xml b/pom.xml index 1fb7f74a22..b79bc1fa23 100644 --- a/pom.xml +++ b/pom.xml @@ -75,10 +75,10 @@ - 2.1.4 + 2.1.5-SNAPSHOT - 3.1.11 + 3.1.12 2.2.0 1.11.4 1.9.0